Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

блендинг текстур по маске


Страницы:   1 2 3

korvin88 ©   (2006-07-19 19:30:00) 

Всем привет!

Вопрос практический - как совместить две текстуры на одном полигоне, имея битовую маску их совмещения? Т.е. там, где маска белая, должна быть одна текстура, а там, где черная - другая. API - OpenGL.


  (2007-03-21 20:25:00) [1]

Удалено модератором


  (2007-03-14 08:11:00) [2]

Удалено модератором


Trimp   (2006-07-25 19:16:00) [3]

Всё понял.  


> что маску легче сделать с альфой

Про это забыл написать.

Удачи! :))


korvin88   (2006-07-25 19:02:00) [4]

Trimp
Чья? Моя? В ДНК, надо полагать, раз так долго все это рожал :))). Но и ты тоже немного ошибся в последнем примере. Перепутал параметры - они должны относиться к маске, т.е. к первой текстуре, а не нулевой :). Это меня долго смущало. Плюс ко всему я никак не мог допереть, что маску легче сделать с альфой (возможно даже, без альфы - никак). Ну и баги по мелочи. Ну сейчас хоть работает :)). Если интересно, то вот правильная процедура (пока не оптимизировал - наверняка это все можно свести к более простой форме).


Procedure DrawMaskedPolygon(PMask,PTex1,PTex2 : GLUint; x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4 : GLfloat);
begin
 glPushAttrib(GL_ALL_ATTRIB_BITS);
   glActiveTextureARB(GL_TEXTURE0_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D,PTex2);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE ,GL_COMBINE_ARB    );
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB  ,GL_REPLACE        );
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_REPLACE        );

   glActiveTextureARB(GL_TEXTURE1_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D, PMask);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE ,GL_COMBINE_ARB    );
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB  ,GL_INTERPOLATE_ARB);
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_REPLACE        );

   glActiveTextureARB(GL_TEXTURE2_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D,PTex1);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE ,GL_COMBINE_ARB    );
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB  ,GL_INTERPOLATE_ARB);
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB,GL_REPLACE        );

   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB   ,GL_PREVIOUS_ARB);
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB  ,GL_SRC_COLOR   );

   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB   ,GL_TEXTURE     );
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB  ,GL_SRC_COLOR   );
   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_ALPHA_ARB ,GL_TEXTURE     );
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_ALPHA_ARB,GL_SRC_ALPHA   );

   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE2_RGB_ARB   ,GL_PREVIOUS_ARB);
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND2_RGB_ARB  ,GL_SRC_ALPHA   );

   glBegin(GL_TRIANGLE_STRIP);
     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,co,cz);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,co,cz);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,co,cz);
     glVertex3f          (x1,y1,z1);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,cz,cz);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,cz,cz);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,cz,cz);
     glVertex3f          (x2,y2,z2);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,co,co);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,co,co);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,co,co);
     glVertex3f          (x3,y3,z3);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,cz,co);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,cz,co);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,cz,co);
     glVertex3f          (x4,y4,z4);
   glEnd ;
 glPopAttrib ;
end ;


Еще раз, спасибо! :))


Trimp   (2006-07-25 18:21:00) [5]

В чём ошибка то была?


korvin88   (2006-07-25 18:10:00) [6]

Trimp
Мда... пришлось повозиться, но оно в итоге заработало, наконец, как надо :).

All
Спасибо большое, всем, кто потратил на меня свое время :))).


Trimp   (2006-07-25 15:31:00) [7]

Замечание

Вместо

//биндим маску
  glActiveTextureARB(GL_TEXTURE1_ARB    );
  glEnable          (GL_TEXTURE_2D      );
  glBindTexture     (GL_TEXTURE_2D,PMask);
  glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE       );

лучше

  glActiveTextureARB(GL_TEXTURE1_ARB    );
  glEnable          (GL_TEXTURE_2D      );
  glBindTexture     (GL_TEXTURE_2D, PMask);
  glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB    );
  glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB
,GL_REPLACE);

  glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_ALPHA_ARB
,GL_REPLACE);

  glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB ,GL_PREVIOUS_ARB);
  glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR   );

  glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_ALPHA_ARB ,GL_TEXTURE);
  glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_ALPHA_ARB,GL_SRC_ALPHA   );

P.S. Ознакомься получше со статьёй.


Trimp   (2006-07-25 15:20:00) [8]

//самое тонкое место... может, ошибка здесь???
Здесь

glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB ,GL_PREVIOUS_ARB);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR   );

glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB ,GL_TEXTURE     );
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR   );

glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE2_RGB_ARB ,GL_PREVIOUS_ARB);
glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND2_RGB_ARB,GL_SRC_ALPHA   );


korvin88   (2006-07-25 14:13:00) [9]

Блииин, опять ничего не выходит :((((. Вроде разобрался по статье, что с чем интерполировать. Прикинул также по примеру DeadMeat'а, как нужно делать. Сделал. И нифига не работает - результат такой-же, какого я всегда добивался при обычном блендинге! Т.е. вторая текстура банально влияет на уже наложенную :((. Вот код:


Procedure DrawMaskedPolygon(PMask,PTex1,PTex2 : GLUint; x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4 : GLfloat);
begin
 glPushAttrib(GL_ALL_ATTRIB_BITS);
   //биндим текстуру травы (для белого цвета)
   glActiveTextureARB(GL_TEXTURE0_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D,PTex1);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE        );

   //биндим маску
   glActiveTextureARB(GL_TEXTURE1_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D,PMask);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE       );

   //биндим текстуру земли (для черного цвета)
   glActiveTextureARB(GL_TEXTURE2_ARB    );
   glEnable          (GL_TEXTURE_2D      );
   glBindTexture     (GL_TEXTURE_2D,PTex2);
   glTexEnvi         (GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_ARB    );
   glTexEnvi         (GL_TEXTURE_ENV,GL_COMBINE_RGB_ARB ,GL_INTERPOLATE_ARB);

   //устанавливаем по порядку Arg0, Arg1 и Arg2 для формулы интерполяции Arg0*Arg2+Arg1*(1-Arg2)
   //самое тонкое место... может, ошибка здесь???
   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE0_RGB_ARB ,GL_PREVIOUS_ARB);
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND0_RGB_ARB,GL_SRC_COLOR   );

   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE1_RGB_ARB ,GL_TEXTURE     );
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND1_RGB_ARB,GL_SRC_COLOR   );

   glTexEnvi (GL_TEXTURE_ENV,GL_SOURCE2_RGB_ARB ,GL_PREVIOUS_ARB);
   glTexEnvi (GL_TEXTURE_ENV,GL_OPERAND2_RGB_ARB,GL_SRC_COLOR   );

   //собственно, выводим сам квад
   glBegin(GL_TRIANGLE_STRIP);
     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,co,cz);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,co,cz);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,co,cz);
     glVertex3f          (x1,y1,z1);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,cz,cz);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,cz,cz);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,cz,cz);
     glVertex3f          (x2,y2,z2);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,co,co);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,co,co);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,co,co);
     glVertex3f          (x3,y3,z3);

     glNormal3f          (0,1,0   );
     glMultiTexCoord2fARB(GL_TEXTURE0_ARB,cz,co);
     glMultiTexCoord2fARB(GL_TEXTURE1_ARB,cz,co);
     glMultiTexCoord2fARB(GL_TEXTURE2_ARB,cz,co);
     glVertex3f          (x4,y4,z4);
   glEnd ;
 glPopAttrib ;
end ;


Может, я опять неправильно понял, как это дело использовать? Помогите, пожалуйста, разобраться.


DeadMeat   (2006-07-24 16:36:00) [10]

korvin88
Собсна пжалста..


> Первый пример тоже рабочий (именно по нему я ответ писал),
>  просто текстуры нужно было свои в папку кинуть :). Так
> даже удобнее :)).

Ну в этом можно кликом загружать свои. Поэтому решил перезалить.
Там в подсказке записан формат команд. Но это так... для примера. Просто удобная обертка над комбайнером в виде "шейдера".


korvin88   (2006-07-24 16:34:00) [11]

DeadMeat
Ты прав, признаю. Комбайнеры мне помогут. Спасибо :). Действительно, в этом примере, если Tex0 - первая текстура, Tex2 - вторая, а Tex1 - битовая маска, а код комбайнера


Tex0:=Tex0;
Tex1:=Tex1;
Tex2:=Tex2;
Tex2:=Interpolate (Tex0, Tex2, Tex1);


то получается именно то, что надо (теперь хоть ясно, что с чем интерполировать :)).

Дело за малым - сделать такое самому :))). Но вот в этом мне поможет скорее не твой пример про ландшафт (там тоже комбайнеры, но принцип, я все же считаю, немного другой), а статья, которуй мне посоветовал Trimp.

Еще раз, спасибо.

P.S.
DeadMeat
Первый пример тоже рабочий (именно по нему я ответ писал), просто текстуры нужно было свои в папку кинуть :). Так даже удобнее :)).

antonn
Нет, нет. Это простой блендинг вручную. Мне нужен был аппартный, средствами OpenGL.


antonn   (2006-07-24 16:07:00) [12]

korvin88   (23.07.06 4:27) [23]
Нет, мне нужен именно OpenGL. Если antonn что-нибудь знает, то пусть отпишется :).

по ОГЛ ниче не знаю :)
для битмапов(есть простор для оптимизации):
procedure CopyTransparentMask(_B_in,_B_out,_B_mask:Tbitmap; _x,_y:integer);
const  MaxPixelCount = MaxInt div SizeOf(TRGBTriple);
type  PRGBArray = ^TRGBArray;
     TRGBArray = array[0..MaxPixelCount-1] of TRGBTriple;
var x, y: Integer; RowOut,RowIn,RowMask: PRGBArray;
   _r,_b,_g:integer;
begin
if (_x+_B_in.Width)>_B_out.Width then exit; if _x<0 then exit;
if (_y+_B_in.Height)>_B_out.Height then exit; if _y<0 then exit;
 _B_in.PixelFormat:=pf24bit; //!!
 _B_out.PixelFormat:=pf24bit; //!!
 _B_mask.PixelFormat:=pf24bit; //!!
 for y:=0 to _B_in.Height-1 do begin
    RowOut:= _B_out.ScanLine[y+_y];
    RowIn:= _B_in.ScanLine[y];
    RowMask:= _B_mask.ScanLine[y];
   for x:=0 to _B_in.Width-1 do
    if not((RowIn[x].rgbtRed=rc1)and(RowIn[x].rgbtGreen=gc1)and(RowIn[x].rgbtBlue=bc1))  then begin
         _r:= trunc(RowOut[x+_x].rgbtRed+((((RowIn[x].rgbtRed)-RowOut[x+_x].rgbtRed)/100)*(RowMask[x].rgbtRed*100/255)));
        if _r>255 then _r:=255 else if _r<0 then _r:=0;
         _g:= trunc(RowOut[x+_x].rgbtGreen+(((RowIn[x].rgbtGreen-RowOut[x+_x].rgbtGreen)/100)*(RowMask[x].rgbtGreen*100/255)));
        if _g>255 then _g:=255 else if _g<0 then _g:=0;
         _b:= trunc(RowOut[x+_x].rgbtBlue+(((RowIn[x].rgbtBlue-RowOut[x+_x].rgbtBlue)/100)*(RowMask[x].rgbtBlue*100/255)));
        if _b>255 then _b:=255 else if _b<0 then _b:=0;
         RowOut[x+_x].rgbtRed:=_r;
         RowOut[x+_x].rgbtGreen:=_g;
         RowOut[x+_x].rgbtBlue:=_b;
   end;
 end
end;


DeadMeat   (2006-07-24 15:53:00) [13]

Дико извиняюсь... Не то закачал.
Вот:
http://slil.ru/22949983


DeadMeat   (2006-07-24 15:47:00) [14]


> повесить з а тупость


DeadMeat   (2006-07-24 15:46:00) [15]

Можете меня повесить на тупость, но так я и не понял, в чем разница.
Щас времени нету это дело поднимать на чистом OGL (давно это было), поэтому простой пример на GLScene, использующий те же комбайнеры:
http://slil.ru/22949959
312 kb

Это не то?


korvin88   (2006-07-24 15:19:00) [16]

Правка:
Пардон, в примере 2 очепятка :)). Черному цвету соответствует текстура №1 (песок), а белому - №2 (снег).


korvin88   (2006-07-24 15:07:00) [17]

DeadMeat
Нет, не так, блин :). По видимому, тут без иллюстраций не обойтись. Маска у меня кладется на [b]каждый[/b] тайл. [b]Совместно[/b] с двумя текстурами. И цвет маски определяет прозрачность текселей (так, кажется, это называется) на этих текстурах, а не прозрачность самих текстур.

Короче, вот:

[b]Пример №1[/b] (как тут по человечески заливать изображения и давать ссылки я не знаю, так что сорри :))
У нас есть:
маска смешивания - http://www.gamedev.ru/images/?id=13117
текстура №1 (для белого цвета) - http://www.gamedev.ru/images/?id=13118
текстура №2 (для черного цвета) - http://www.gamedev.ru/images/?id=13119
После смешивания мы должны наложить на квад - http://www.gamedev.ru/images/?id=13120

Для полного понимания идем дальше :)))
[b]Пример №2[/b]
У нас есть:
маска смешивания - http://www.gamedev.ru/images/?id=13121
текстура №1 (для белого цвета) - http://www.gamedev.ru/images/?id=13122
текстура №2 (для черного цвета) - http://www.gamedev.ru/images/?id=13123
И какую текстуру мы должны получить в итоге??? Правильно - http://www.gamedev.ru/images/?id=13124

Надеюсь, теперь все понятно? :)) Таким образом мы для каждого квада создаем по мере надобности текстуру прямо в процессе рендеринга (на основе базовых текстур и масок). Если ты мне подскажешь, как на комбайнерах из статьи сделать такой эффект, буду тебе очень благодарен.

XProger
Я и не ворочу, просто он дал мне теорию (с которой я полностью согласен), а у меня проблемы именно с практической реализацией. За шейдер спасибо. Изучать я собирался GLSL, так что твой пример мне как раз кстати :).


XProger   (2006-07-24 00:10:00) [18]

GLSL fragment program
uniform sampler2D mask;
uniform sampler2D tex1;
uniform sampler2D tex2;

void main(void)
{
  vec2 tc = gl_TexCoord[0].st;
  gl_FragColor = mix(texture2D(tex1, tc), texture2D(tex2, tc), texture2D(mask, tc));
}


tButton дал верное решение твоей задачи, советую не воротить носом...


DeadMeat   (2006-07-23 22:26:00) [19]

Я чего сказать та хочу... Блендинг по маске мона сделать комбайнером без проблем. Хоть какой. Просто главное его правильно применить. В примере как раз это и показано. Просто вчитаться надо.
Там на всю поверхность кладется одна текстура, потом по маске, кладется другая. И получается, что маска это Coverage factor, которая показывает, где трава, а где земля. В маске это черные и белые участки. Можно еще и альфа канал подключить. Тогда одной маской можно сразу три текстуры сблендить. Но на самом деле это и есть нужный Вам (как я понял) бленд текстур по маске. Разве не так?


korvin88   (2006-07-23 13:52:00) [20]

DeadMeat
Все верно - это один из вариантов затайлить ландшафт. Но я делаю по другому. У меня маска определена для каждого тайла, а не вертекса.

Раскажу, пожалуй, зачем я это все придумал:

Какой самый простой и тупой способ красиво затайлить ландшафт? Правильно - подготовить заранее все текстуры тайлов со всеми переходами и рисовать их по мере надобности. Но вот проблема - а что если у нас 5 базовых текстур (трава, земля, снег, песок и дорога)? Тогда, как я уже говорил несколькими постами выше, нам нужно порядка 400 текстур с переходами (трава-земля 16 видов, трава-снег 16 видов и т.д.). Тут я и подумал - почему бы это дело не оптимизировать и хранить только базовые текстуры и 16 черно-белых масок переходов, а остальные блендить на основе этих масок в realtime. Такая вот была исходная мысль.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо