Эта запись является краткой историей про то как я выполнял тектурирование ландшафта в своем движке.
16 июля 2011
Эта запись является краткой историей про то как я выполнял тектурирование ландшафта в своем движке.
16 июля 2011
Эта запись является краткой историей про то как я выполнял тектурирование ландшафта в своем движке.
Все началось несколько месяцев назад, когда я писал игру на конкурс стратегий: нужно было отрисовывать ландшафт.
Тогда я удовлетворился очень простым решением, а именно:
никакого куллинга (а зачем если весь ландшафт 128х128 квадов? )
простое смешивание 2х текстур в шейдере.
Смотрится оно просто:
Однако, где-то неделю назад захотелось сделать лучше.
Что мы хотим?
поддержку большого количества текстур, например 32 текстуры.
процедурное смешивание.
Что имеем?
openGL 2.1 + GLSL 1.0
SM3
GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS = 4 (что-бы запускалось, и на домашнем ПК, и на ноутбуке)
Что делать?
На таком GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS развернуться довольно сложно, но можно:
1. Рисуем ладшафт в отдельный фрейм-буффер: во фрагмент пишем: ( RG = texCoord, B - освещенность, A - не используется )
результат:
2. Включаем аддитивный бленд и для каждой задействованой текстурки рисуем FSQ(full screen quad):
В шейдер передаем:
1 - текстура подученная на этапе №1.
2 - дуффузная текстура ( трава/песок/eth ).
3 - маска, в которой находится вклад текстуры(2) в каждый из тайлов.
4 - текстура с 2d шумом.
В шейдере:
читаем из текстуры №1 uv координаты.
к uv прибавляем значение полученное из текстуры с шумом.
вычисляем по uv координатам номер тайла + используя uv координаты, делаем выборку из диффузной текстуры.
вычисляем освещение( я вычислял по Ламберту )
Результат
- я доволен.
PS
1. лучше рисовать треугольник, вместо квадрата.
Дело в том, что в связи в особенностями реализации функции texture2D может появиться диагональная полоса посередине экрана, при использовании квадрата.
2. Шейдер: http://pastebin.com/wqCmN2HU
3. Хороший результат получается, если вместо текстуры шума использовать карту нормалей.
4. На новеньком железе такие приключения совсем не обязательны.
5. Фрагментный шейдер очень тяжелый - стараемся экономить на фрагментах.
6. Надеюсь, что не сильно накосячил с орфографией :-)
7 янв 2011
Вы вероятно уже знаете что такое расширения OpenGL.
Если это не так, то можете ознакомится с ними прочитав эту статью.
Обычно код инициализации расширения выглядит примерно так:
bool Init_GL_ARB_multitexture() { // Проверяем наличие расширения if( !IsExtEnable( "GL_ARB_multitexture")) return false; // Получить адрес функции и присвоить его глобальному указателю glActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress( "glActiveTextureARB"); glClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC) wglGetProcAddress( "glClientActiveTextureARB"); glMultiTexCoord2fARB = ( PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress( "glMultiTexCoord2fARB"); return true; }
Однако очень быстро надоедает прописывать 'магические комбинации букв', такие как (PFNGLACTIVETEXTUREARBPROC).
Также не очень приятно писать дважды имя нужной функции.
Хочу рассказать вам о том как я сейчас избавляюсь от этих неудобств:
Начнем с (PFNGLWHATIWANTARBPROC):
template< class T > bool initGlExtensionFuncPtr(T &func, const char * name){ func = ( T)getProcAddress( name); //wglGetProcAddress( name ) или glXGetProcAddress( name ) или handMadeGetProcAddress( name ); return ( func!=0); }
Теперь наш код будет выглядеть примерно так:
initGlExtensionFuncPtr(glActiveTextureARB, "glActiveTextureARB"); initGlExtensionFuncPtr( glClientActiveTextureARB, "glClientActiveTextureARB"); initGlExtensionFuncPtr( glMultiTexCoord2fARB, "glMultiTexCoord2fARB");
С помощью макросов его можно сделать еще короче:
#define init(X) initGlExtensionFuncPtr( X, #X) init( glActiveTextureARB); init( glClientActiveTextureARB); init( glMultiTexCoord2fARB); #undef init
Также многие рекомендуют проверять все функции на ноль, 'на всякий случай'; добавим эту проверку в наш код и посмотрим что получилось:
#define init(X) initGlExtensionFuncPtr( X, #X) bool Init_GL_ARB_multitexture( ) { return // Проверяем наличие расширения IsExtEnable( "GL_ARB_multitexture") && // Получить адрес функции и присвоить его глобальному указателю init( glActiveTextureARB) && init( glClientActiveTextureARB) && init( glMultiTexCoord2fARB); } #undef init
PS
http://www.gamedev.ru/code/articles/?id=4267
http://www.opengl.org/registry/
http://www.opengl.org/documentation/
Ссылка | Комментарии [5]
26 ноя 2010
Вот. Запилил редактор. Делает вид что работает)

Хм. Надо бы начать делать систему заклинаний.
И героев добавить.
И узнать как дела у art-отдела
И скелетку реализовать
И поесть
И поспать
...
Ссылка | Комментарии [1]