На самом деле, матричные тени — дело простое. Тут нам и понадобится наш класс матриц из предыдущего урока. Остальной код (main.cpp. init.cpp, main.h) возьмите из урока инициализации.

Изменяем только файл main.cpp:

// В начале файла подключите хидер матричного класса:
#include «CMatrix.h»// Переменные, хранящие угол вращения источника света:
float xRotation = 0.0f;
float yRotation = 0.0f;// Эта матрица будет использоватся для хранения матрицы тени
CMatrix4x4 ShadowMatrix;// Следующие переменные очень важны для функционирования теней. Первая — позиция
// источника света, вторая — нормаль поверхности, на которую отбрасывается тень.
CVector4 lightPos(1.5f, 2.3f, 2.0f, 1.0f);
CVector4 planeNormal(0.0f, 1.0f, 0.0f, 0.0f);

/////////////////////////////////////////////////////////////////////
//
//      Функция, отрисовывающая куб
//
/////////////////////////////////////////////////////////////////////

void DrawCube()
{
// Передний полигон
glBegin(GL_QUADS);
glVertex3f(0.2f, 0.0f, 0.0f);
glVertex3f(0.2f, 0.5f, 0.0f);
glVertex3f(0.3f, 0.5f, 0.0f);
glVertex3f(0.3f, 0.0f, 0.0f);
glEnd();

// Задний полигон
glBegin(GL_QUADS);
glVertex3f(0.2f, 0.0f, 0.5f);
glVertex3f(0.2f, 0.5f, 0.5f);
glVertex3f(0.3f, 0.5f, 0.5f);
glVertex3f(0.3f, 0.0f, 0.5f);
glEnd();

// Левый полигон
glBegin(GL_QUADS);
glVertex3f(0.2f, 0.0f, 0.5f);
glVertex3f(0.2f, 0.5f, 0.5f);
glVertex3f(0.2f, 0.5f, 0.0f);
glVertex3f(0.2f, 0.0f, 0.0f);
glEnd();

// Правый полигон
glBegin(GL_QUADS);
glVertex3f(0.3f, 0.0f, 0.5f);
glVertex3f(0.3f, 0.5f, 0.5f);
glVertex3f(0.3f, 0.5f, 0.0f);
glVertex3f(0.3f, 0.0f, 0.0f);
glEnd();

// Верхний полигон
glBegin(GL_QUADS);
glVertex3f(0.2f, 0.5f, 0.0f);
glVertex3f(0.2f, 0.5f, 0.5f);
glVertex3f(0.3f, 0.5f, 0.5f);
glVertex3f(0.3f, 0.5f, 0.0f);
glEnd();

// Нижний полигон
glBegin(GL_QUADS);
glVertex3f(0.2f, 0.0f, 0.0f);
glVertex3f(0.2f, 0.0f, 0.5f);
glVertex3f(0.3f, 0.0f, 0.5f);
glVertex3f(0.3f, 0.0f, 0.0f);
glEnd();
}

///////////////////////////////////////////////////////////////
//
//  Теперь изменим нашу основную функцию:
//
///////////////////////////////////////////////////////////////

void RenderScene()
{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

glTranslatef(0.0f, 1.0f, 5.0f);
glRotatef(yRotation, 1.0f, 0.0f, 0.0f);
glRotatef(xRotation, 0.0f, 1.0f, 0.0f);

glColor3f(1.0f, 1.0f, 1.0f);

// Сначала мы отирсуем поверхность и забудем о ней. Затем я решил
// нарисовать тень. Чтобы сделать это, мы создадим матрицу тени, основываясь на
// позиции источника света и нормали поверхности. Создав эту матрицу, мы умножим её
// на текущую задействованную матрицу. Таким образом всё, что вы отрендерите далее,
// будет отрисовано плоским на поверхности, в точности как тень от обьекта. В принципе,
// ничего сложного, верно? Чтобы нарисовать что-то в качестве тени, вы должны закрасить
// обьект черным цветом и отключить текстуры. Я использовал glPush/PopMatrix, чтобы
// операции с тенью не затронули остальных обьектов сцены.

// Рисуем один большой обьект в качестве поверхности.
glColor3f(0.4f,0.8f,0.4f);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(15.0f, 0.01f, 15.0f);
glTexCoord2f(1.0, 0.0); glVertex3f(15.0f, 0.01f, 15.0f);
glTexCoord2f(1.0, 1.0); glVertex3f(15.0f, 0.01f, 15.0f);
glTexCoord2f(0.0, 1.0); glVertex3f(15.0f, 0.01f, 15.0f);
glEnd();

// Создадим матрицу тени на основе нормали поверхности и позиции источника света
ShadowMatrix.CreateShadowMatrix(planeNormal, lightPos);

// Теперь рисуем тень…
glDisable(GL_DEPTH_TEST);

glPushMatrix();

// Одно то, что мы создали матрицу тени, ещё ничего не значит. Теперь нужно
// умножить её на текущую матрицу:
glMultMatrixf(ShadowMatrix.matrix);
glColor3f(0.0f, 0.0f, 0.0f);

// Нарисуем куб как обычно. Новая матрица сделает его плоским.
DrawCube();
glPopMatrix();

glEnable(GL_DEPTH_TEST);

// Теперь мы можем нарисовать обычный куб.
glColor3f(0.8f, 0.5f, 0.5f);
DrawCube();

// Теперь нарисуем источник света
glColor3f(1.0f, 1.0f, 0.0f);
glTranslatef(lightPos.x, lightPos.y, lightPos.z);

GLUquadricObj *pObj = gluNewQuadric();
gluSphere(pObj, 0.05f, 6,6);

SwapBuffers(g_hDC);
}

//////////////////////////////////////////////////////////////////////
//
// И последнее, что осталось сделать — написать обработку клавиш:
//

case VK_UP:
lightPos.z -= 0.05f;
break;

case VK_DOWN:
lightPos.z += 0.05f;
break;

case VK_LEFT:
lightPos.x -= 0.05f;
break;

case VK_RIGHT:
lightPos.x += 0.05f;
break;

 

Вот и всё. У нас есть тень, которая следует всллед за движениями «солнца».
Чтобы создать тень с помощью этой техники, сначала создаётся матрица тени. Затем вы отрисовываете обьект дважды, один раз используя матрицу, второй раз нет. Но учитывайте и то, что при использовании этого способа значительно возрастает и нагрузка, так что для крупного проекта она может и не подойти.

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