Смешивание текстур в LWJGL
| |
miker9 | Дата: Понедельник, 01 Октября 2012, 12:26 | Сообщение # 1 |
частый гость
Сейчас нет на сайте
| Допустим есть две текстуры(красная и коричневая) и плоскость из нескольких полигонов.Каким образом можно добиться такого эффекта?
|
|
| |
Archido | Дата: Понедельник, 01 Октября 2012, 14:31 | Сообщение # 2 |
Сэнсэй
Сейчас нет на сайте
| Как вариант - сделать у красной альфа канал. Хотя... т.е. коричневая тайлится, а красная просто поверх накладывается с неким рисунком? Тогда не очень вариант... Вообще такое легко делается по маске, когда есть шейдеры , но можно и блендингом по идее, в два прохода.
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
Сообщение отредактировал Archido - Понедельник, 01 Октября 2012, 14:35 |
|
| |
miker9 | Дата: Понедельник, 01 Октября 2012, 17:28 | Сообщение # 3 |
частый гость
Сейчас нет на сайте
| А насколько рационально будет создавать отдельную текстуру для группы полигонов, например 32х32, если учесть что слоев может быть много?
Quote т.е. коричневая тайлится, а красная просто поверх накладывается с неким рисунком? Не обязательно.
P.S Это нужно для террайна в RTS
Сообщение отредактировал miker9 - Понедельник, 01 Октября 2012, 17:28 |
|
| |
Archido | Дата: Понедельник, 01 Октября 2012, 18:04 | Сообщение # 4 |
Сэнсэй
Сейчас нет на сайте
| Шейдеров совсем нету да? Это печально в нынешние времена, т.к. с ними много вещей проще делается.
Если нужно делать ландшафт, то обычно его делают тайлингом нескольких различных текстур (слои, да) и смешиванием между ними, сплаттинг называется. Насколько понимаю - это и нужно. Чтобы смешать слои, нужно где-то брать для каждого коэффициент смешивания между ними (если точнее, то прозрачность конкретного слоя в каждой вершине ландшафта). Брать это можно либо из вершины, либо накладывать специальную дополнительную текстурку (маску)... Первое делается проще, второе сложнее (без шейдеров).
Конкретнее могу рассказать (завтра уже, правда), если будет известно, готово ли сейчас что-либо из ланшдшафта и как оно рисуется. Кодом.
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
Сообщение отредактировал Archido - Понедельник, 01 Октября 2012, 18:04 |
|
| |
miker9 | Дата: Понедельник, 01 Октября 2012, 23:11 | Сообщение # 5 |
частый гость
Сейчас нет на сайте
| Да, шейдеров нету.Посмотрел про сплаттинг на педевики, по картинкам это то что надо. Террайн разделен на чанки 32х32 полигонов(Некоторые чанки могут быть неполными).При инициализации каждый чанк строится из массива высот в дисплей-лист.
Code public void buildChunk(Chunk chunk) { GL11.glNewList(chunk.dList, GL11.GL_COMPILE); GL11.glBegin(GL11.GL_QUADS); for(int x=chunk.x; x<chunk.x+32 && x < heightMap.length-1; x++) { for(int y=chunk.y; y<chunk.y+32 &&y < heightMap[0].length-1; y++) {
GL11.glTexCoord2f(0, 1); if(x==0 || y == 0) { GL11.glColor3f(0, 0, 0); } GL11.glVertex3f(x*2, y*2, heightMap[x][y]); GL11.glColor3f(1, 1, 1); if(x==0 || y == getHeight()) { GL11.glColor3f(0, 0, 0); }
GL11.glTexCoord2f(0, 0); GL11.glVertex3f(x*2, y*2+2, heightMap[x][y+1]); GL11.glColor3f(1, 1, 1); if(x==getWidth() || y == getHeight()) { GL11.glColor3f(0, 0, 0); } GL11.glTexCoord2f(1, 0); GL11.glVertex3f(x*2+2, y*2+2, heightMap[x+1][y+1]); GL11.glColor3f(1, 1, 1); if(x==getWidth() || y == 0) { GL11.glColor3f(0, 0, 0); }
GL11.glTexCoord2f(1, 1); GL11.glVertex3f(x*2+2, y*2, heightMap[x+1][y]); GL11.glColor3f(1, 1, 1); }
} GL11.glEnd(); GL11.glEndList(); }
|
|
| |
Archido | Дата: Вторник, 02 Октября 2012, 05:23 | Сообщение # 6 |
Сэнсэй
Сейчас нет на сайте
| Мм, дисплей листы я бы посоветовал в процессе (или в близжайшем будущем) заменить на VBO (1, 2, 3) - оно быстрее и более гибко.
Допустим, нам нужно смешать два слоя. Для простоты (чтобы суть понять) - первым способом. Чтобы это сделать, нужно для второго слоя хранить информацию о том, в каких местах его видно, а в каких нет (прозрачность). Хранить будем в цвете вершины, для этого нужно каждому слою задавать свой glColor4f (1, 1, 1, Alpha), поэтому в данный момент придется клонировать дисплей листы (с информацией о вершинах и текс. координатах, они будут одинаковы для всех слоев) и в каждом задавать свой Color. Например, превратить член dList класcа Chunk в массив, где chunk.dList[N] номер слоя и в цикле для каждого такого слоя строить собственный дисплей лист. Альфу можно задавать любыми способами, для теста взять 0.5 например (для второго слоя, для первого она всегда равна 1), или лучше рандом даже.
Как примерно может выглядеть процесс отрисовки: Code //Сначало обычным способом рисуется первый слой ...
GL11.glBindTexture (...); //первая текстура GL11.glCallLists(chunk.dList[0]);
...
//теперь рисуем второй слой, тут нужно поколдовать с Blend и Depth
GL11.glDepthMask(GL11.GL_FALSE); //Отрубаем запись в Z-Buffer GL11.glDepthFunc(GL11.GL_LEQUAL); //Т.к. у нас уже глубина ландшафта записана при отрисовке первого слоя, то устанавливаем ф-цию сравнения этой глубины в EQUAL, чтобы тест всегда проходило. По идее, если ландшафт рисуется одним из первых, то можно вообще воткнуть glDepthFunc(GL_ALWAYS) и будет еще лучше.
GL11.glEnable(GL11.GL_BLEND); //Включаем смешивание GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); //это формула смешивания. Result = Texture1 * Layer2.Alpha + Texture2 * (1 - Layer2.Aplpha);
//рисуем второй слой GL11.glBindTexture (...); //вторая текстура GL11.glCallLists(chunk.dList[1]);
...
//и возвращаем все в изначальное положение
GL11.glDepthMask(GL11.GL_TRUE); GL11.glDepthFunc(GL11.GL_LESS);
GL11.glDisable(GL11.GL_BLEND);
Примерно так
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
|
|
| |
miker9 | Дата: Вторник, 02 Октября 2012, 22:10 | Сообщение # 7 |
частый гость
Сейчас нет на сайте
| Проблема в том что обе текстуры квадратные.
|
|
| |
Archido | Дата: Среда, 03 Октября 2012, 08:55 | Сообщение # 8 |
Сэнсэй
Сейчас нет на сайте
| Quote (miker9) Проблема в том что обе текстуры квадратные. А в чем тут проблема?
В данный момент, судя по коду, у тебя целая полноценная текстура кладется на патч (32х32)? Ее можно затайлить и класть, скажем, 8х8 текстур на патч или даже больше, указав нужное кол-во в glTexCoord2f (где там сейчас стоит 1, указать 8 например) и смешиванием всего этого дела в два слоя можно делать что-то вроде этого - 1 и 2
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
|
|
| |
miker9 | Дата: Среда, 03 Октября 2012, 23:04 | Сообщение # 9 |
частый гость
Сейчас нет на сайте
| Quote Мм, дисплей листы я бы посоветовал в процессе (или в близжайшем будущем) заменить на VBO Так как террайн 90% времени статичен я подумал что юзать д.листы будет быстрее(по фпс) Quote А в чем тут проблема? Если использовать вершины для прозрачности получается не очень гладко. А так спасибо за ответы
|
|
| |
Archido | Дата: Четверг, 04 Октября 2012, 12:12 | Сообщение # 10 |
Сэнсэй
Сейчас нет на сайте
| Quote (miker9) Если использовать вершины для прозрачности получается не очень гладко. Ну, если иметь в распоряжении несколько текстур разных видов поверхности (трава, песок, земля, etc) и хорошенько их затайлить (так, чтобы на одном патче в 32х32 полигонов оказалось 50 - 150 текстур), то смешивая разные текстуры - можно получить очень хорошие результаты . Я в прошлом посте две картинки приводил для примера, такой результат не устраивает?
Если на каждый патч используется одна большая текстура, то чтобы ее плавно смешать с такой же другой - нужно юзать у последней альфаканал. Но тогда получится, что на патч - будет свой уникальный альфаканал и соотвественно уникальная текстура (с уникальным рисунком)... Тогда что-то смешивать вообще смысла не имеет и можно заранее запечь все слои для N-го патча (фотошоп, редактор) в одну текстуру и ее использовать. Единственное, что на такое дело потребуется много памяти под текстуры, поэтому если ландшафт большой - то такое просто вообще не взлетит.
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
|
|
| |
miker9 | Дата: Четверг, 04 Октября 2012, 14:46 | Сообщение # 11 |
частый гость
Сейчас нет на сайте
| Quote две картинки приводил для примера, такой результат не устраивает? Не совсем, полигоны у меня не такие мелкие(Переходы получаются плавными но мелких деталей не нарисовать) P.S координаты текстур задаются вручную, в редакторе
|
|
| |
Archido | Дата: Четверг, 04 Октября 2012, 17:38 | Сообщение # 12 |
Сэнсэй
Сейчас нет на сайте
| Можно скрин ландшафта с текстурами + скрин его же во wireframe режиме, так чтобы все очевидно было. И что конкретно подразумевается под мелкими деталями (они точно нужны в RTS?) ? Ну а вообще, если разрешения сетки не хватает на такие вещи, то выход только один - использовать маски (либо альфаканал, но маски в разы гибче). Делаются они в OpenGL без шейдеров с помощью мультитекстурирования (вторые. текс. координаты для масок) и текстурных комбайнеров (это чтобы смешать основную текстуру и альфа маску), тут уже ограничений практически нет - маску можно брать любого разрешения (зависит от необходимой детализации) и можно размещать ее в любом месте и на любых полигонах (настраивается вторыми текс. координатами)... Могу, в принципе, подробнее рассказать. А смешать с помощью альфы вершин вообще получилось, да?
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
|
|
| |
miker9 | Дата: Четверг, 04 Октября 2012, 23:58 | Сообщение # 13 |
частый гость
Сейчас нет на сайте
| Quote А смешать с помощью альфы вершин вообще получилось, да? Да, но при таком варианте возникает проблемма гибкости т.к. я завишу от разположения точек. Quote Могу, в принципе, подробнее рассказать Буду благодарен
|
|
| |
Archido | Дата: Пятница, 05 Октября 2012, 09:43 | Сообщение # 14 |
Сэнсэй
Сейчас нет на сайте
| Окей. Первое, что нужно - это добавить мультитекстурные координаты туда, где создается Chunk: Code //Теперь вместо 'glTexCoord2f(x, y)' надо делать так:
glMultiTexCoord2f(GL_TEXTURE0, ...); //координаты для маски glMultiTexCoord2f(GL_TEXTURE1, ...); //координаты для текстуры, которая будет отрисовываться по данной маске (базовая т.е.) C координатами надо будет поиграться, каким-то полигонам можно поставить все в 0 (чтобы маски на них вообще небыло) и тому подобное.
Самый первый слой по-хорошему нужно рисовать без маски (или с полностью непрозрачной) чтобы сформировать собственно сам ландшафт (тут и в Z буфер надо писать). Как-нить так: Code glActiveTexture(GL_TEXTURE0); //маску отключаем glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, BaseTexture);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //отключаем текс. комбайнеры
GL11.glCallLists(chunk.dList[0]);
Теперь, собсна, рендер 2-го и последующих слоев: Code
// тут все точно также с Блендингом и отключением записи в Z буфер
...
//Далее колдунство с текстурными комбайнерами:
glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, AlphaMask); //указываем маску
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glActiveTexture(GL_TEXTURE1); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, BaseTex); //тут основную текстуру
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
GL11.glCallLists(chunk.dList[N]); //рисуем Выглядит все это довольно грустно и так уже почти никто не делает (ибо есть шейдеры).
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
Сообщение отредактировал Archido - Пятница, 05 Октября 2012, 09:43 |
|
| |
miker9 | Дата: Суббота, 06 Октября 2012, 21:31 | Сообщение # 15 |
частый гость
Сейчас нет на сайте
| Большое спасибо сейчас попробую )
Добавлено (06.10.2012, 21:31) --------------------------------------------- Мм, такой вопрос, а как должна выглядеть маска(чернобелая или альфа)?
Сообщение отредактировал miker9 - Суббота, 06 Октября 2012, 21:38 |
|
| |
Archido | Дата: Воскресенье, 07 Октября 2012, 13:44 | Сообщение # 16 |
Сэнсэй
Сейчас нет на сайте
| Если чернобелая - то нужно специально создавать однокомпонентную текстуру и в нее правильно грузить данные (и это наиболее правильный вариант). Для простоты - можно сделать обычную с альфаканалом (4 компоненты) - альфа канал и будет маской.
C++ - он особенный. С помощью него можно не только выстрелить себе в ногу, но и повеситься в пустой комнате:)
|
|
| |
miker9 | Дата: Понедельник, 08 Октября 2012, 22:43 | Сообщение # 17 |
частый гость
Сейчас нет на сайте
| Ок, большое спасибо за помощь.
|
|
| |
|