![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
блендинг текстур по маске
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. Такая вот была исходная мысль.