В этом уроке мы добавим нашей карте высот немного реализма. Мы добавим детальную текстуру поверх основной текстуры поверхности. Чтобы отрендерить текстуры друг поверх друга мы будем использовать мультитекстурирование. Это значит, что ваше железо и драйвера должны поддерживать сответствующие расширения ARB. Исходный код взят из прошлого урока.

Сначала main.h.

// Вверху файла, после подключения хидеров, добавим:

// Дефайны для мультитекстурирования
#define GL_TEXTURE0_ARB                     0x84C0
#define GL_TEXTURE1_ARB                     0x84C1

#define GL_COMBINE_ARB          0x8570
#define GL_RGB_SCALE_ARB        0x8573

// Прототипы функций мультитекстурирования
typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum target, GLfloat s, GLfloat t);
typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum target);

// Обьявляем внешние указатели на функции мультитекстурирования
extern PFNGLMULTITEXCOORD2FARBPROC      glMultiTexCoord2fARB;
extern PFNGLACTIVETEXTUREARBPROC        glActiveTextureARB;

 

В файле terrain.h изменим прототим RenderHeightMap():

void RenderHeightMap(BYTE pHeightMap[], GLuint TID, GLuint TID2);

 

Теперь изменим terrain.cpp:

// В начале файла добавим две переменных:

extern bool g_bDetail; // Включение/выключение глобальных текстур

// Текущее значение тайлинга детальной текстуры
extern int g_DetailScale;

// Изменим функцию наложения текстур:
void SetTextureCoord(float x, float z)
{
float u =  (float)x / (float)MAP_SIZE;
float v = (float)z / (float)MAP_SIZE;

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// Вместо обычного наложения текстур мы будем использовать
// glMultiTexCoord2fARB(). Это позволит нам выбрать u/v координаты
// для каждой текстурной карты, так как мы используем мультитекстурирование.
// Посколько мы будем использовать текстурные матрицы для тайлинга
// детальной текстуры, просто применим те же u/v координаты
// для обоих текстур.

// Передадим координаты текстуры поверхности
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);

// Передадим координаты детальной текстуры
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
}

// Теперь изменим саму отрисовку:
void RenderHeightMap(BYTE pHeightMap[], GLuint TID, GLuint TID2)
{
int X = 0, Y = 0;
int x, y, z;
bool bSwitchSides = false;

if(!pHeightMap) return;

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// Теперь нам нужно скомбинировать текстуру поверхности с детальной
// текстурой. Чтобы красиво их обьединить, нам нужны некоторые дефайны
// ARB-расширений. Первое, GL_COMBINE_ARB, позволяет нам комбинировать
// параметры текстуры, второе, GL_RGB_SCALE_ARB, позволяет нам
// увеличивать гамму второй текстуры, чтобы она не затемняла первую.
// Это прекрасно работает для карт освещения и детальных текстур.
// GL_RGB_SCALE_ARB может принимать значения только 1, 2 или 4. 2 работает
// просто прекрасно, 4 уже слишком ярко.

// Чтобы сделать тайлинг детальной текстуры, задействуем текстурную
// матрицу. Когда мы входим в режим текстурных матриц, мы можем
// воздействовать на координаты выбранной текстуры. Это не обязательно,
// можно просто рассчитывать текстурные координаты и передавать
// их разными, но я решил показать вам этот функционал. Нажимая
// ПРОБЕЛ, вы можете переключатся между различными значениями
// GL_RGB_SCALE_ARB и посмотреть, какое вам больше нравится.

// Активируем первый ID текстуры и биндим её
glActiveTextureARB(GL_TEXTURE0_ARB);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, g_Texture[0]);

// Если включена детальная текстура, накладываем поверх вторую:
if(g_bDetail)
{
// Активируем и биндим второй ID текстуры
glActiveTextureARB(GL_TEXTURE1_ARB);
glEnable(GL_TEXTURE_2D);

// Включаем режим смешивания и увеличиваем гамму (значение «2»).
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);

// Биндим детальную текстуру
glBindTexture(GL_TEXTURE_2D, g_Texture[1]);

// Теперь входим в текстурную матрицу. Это позволит нам изменять
// тайлинг детальной текстуры.
glMatrixMode(GL_TEXTURE);

// Сбрасываем матрицу и применяем текущее значение scale
glLoadIdentity();
glScalef((float)g_DetailScale, (float)g_DetailScale, 1);

// Выходим из текстурной матрицы
glMatrixMode(GL_MODELVIEW);
}

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

glBegin( GL_TRIANGLE_STRIP );

for ( X = 0; X <= MAP_SIZE; X += STEP_SIZE )
{
if(bSwitchSides)
{
for ( Y = MAP_SIZE; Y >= 0; Y -= STEP_SIZE )
{
x = X;
y = Height(pHeightMap, X, Y );
z = Y;

SetTextureCoord( (float)x, (float)z );
glVertex3i(x, y, z);

x = X + STEP_SIZE;
y = Height(pHeightMap, X + STEP_SIZE, Y );
z = Y;

SetTextureCoord( (float)x, (float)z );
glVertex3i(x, y, z);
}
}
else
{
for ( Y = 0; Y <= MAP_SIZE; Y += STEP_SIZE )
{
x = X + STEP_SIZE;
y = Height(pHeightMap, X + STEP_SIZE, Y );
z = Y;

SetTextureCoord( (float)x, (float)z );
glVertex3i(x, y, z);

x = X;
y = Height(pHeightMap, X, Y );
z = Y;

SetTextureCoord( (float)x, (float)z );
glVertex3i(x, y, z);
}
}

bSwitchSides = !bSwitchSides;
}

glEnd();

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

// Теперь отключим мультитекстурирование, чтобы оно ничего более не затронуло

glActiveTextureARB(GL_TEXTURE1_ARB);
glDisable(GL_TEXTURE_2D);

glActiveTextureARB(GL_TEXTURE0_ARB);
glDisable(GL_TEXTURE_2D);

/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *

}

 

Файл main.cpp:

// В начале файла включим мультитекстурирование; добавим прототипы нужных
// функций и некоторые переменные
PFNGLMULTITEXCOORD2FARBPROC     glMultiTexCoord2fARB     = NULL;
PFNGLACTIVETEXTUREARBPROC       glActiveTextureARB       = NULL;// Вкл/выкл детальную текстуру
bool g_bDetail = true;// Текущее scale-значение для текстурной матрицы
int g_DetailScale = 16;// Добавим ещё один ID текстуры:
#define DETAIL 10           // ID детальной текстуры

/////////////////////////////////////////////////////////////////////////////////////
//
// В функцию Init() добавим мультитекстурирование и загрузку доп. текстуры:
//

glActiveTextureARB=
(PFNGLACTIVETEXTUREARBPROC) wglGetProcAddress(«glActiveTextureARB»);
glMultiTexCoord2fARB
= (PFNGLMULTITEXCOORD2FARBPROC) wglGetProcAddress(«glMultiTexCoord2fARB»);

// Нужно убедится, что текущая версия OpenGL на машине поддерживает мультитекстурирование:
if(!glActiveTextureARB || !glMultiTexCoord2fARB)
{
// Выводим ошибку и выходим
MessageBox(g_hWnd, «Your current setups does not support multitexturing», «Error», MB_OK);
PostQuitMessage(0);
}

Texture->LoadTexture(IL_BMP,«Detail.bmp», &textures[DETAIL]);

/////////////////////////////////////////////////////////////////////////////////////
//
// Добавим обработку пробела:

case VK_SPACE:

// Изменяем значение scale.
// Умножаем текущее значение на 2, пока оно не достигнет 128.
g_DetailScale = (g_DetailScale * 2) % 128;

// Если значение=0, делаем его 1
if(g_DetailScale == 0)
g_DetailScale = 1;

break;

/////////////////////////////////////////////////////////////////////////////////////
//
// И в RenderScene() просто изменим вызов отрисовки поверхности:

RenderHeightMap(g_HeightMap, textures[TERRAIN].texID, textures[DETAIL].texID);

Исходные коды к уроку