Строим икосаэдр
Чтобы нивелировать зависимость цвета вершины от амплитуды нормали, обычно вектор нормали масштабируют (или нормируют), то есть делают его длину равной единице, оставляя неизменным направление. С учетом сказанного создадим две вспомогательные функции. Первая масштабирует, а вторая вычисляет нормаль к плоскости треугольника. Алгоритм вычисления использует координаты двух сторон, прилегающих к текущей вершине треугольника:
//==== Нормирование вектора нормали (или любого другого)
void Scale(double v[3])
{
double d = sqrt(v[0]*v[0]+v[l]*v[l]+v[2]*v[2]);
if (d == 0.)
{
MessageBox(0,"Zero length vector","Error",MB_OK);
return;
}
void getNorm(double vl[3], double v2[3], double out[3])
{
//===== Вычисляем координаты вектора нормали
//====== по формулам векторного произведения
out[0] = vl[l]*v2[2] – vl[2]*v2[l];
out[l] = vl[2]*v2(0] – vl[0]*v2[2];
out[2] =vl[0]*v2[l] – vl[l]*v2[0];
Scale(out);
}
Замените функцию DrawScene. В новом варианте мы аккуратно вычисляем и масштабируем нормали в каждом из двадцати треугольников поверхности икосаэдра:
void DrawScene()
{
static double
angle -3. * atanfl.)/2.5, V = cos(angle), W = sin(angle),
v[12] [3] = {
{-V,0.,W}, {V,0.,W}, {-V,0.,-W},
{V,0.,-W}, {0.,W,V}, {0.,W,-V},
{0.,-W,V}, {0.,-W,-V}, {W,V, 0.},
{-W,V,0.}, {W,-V,0.}, {-W,-V,0.}
};
static GLuint id[20][3] = {
(0.1, 4), {0.4, 9}, (9.4, 5), (4.8, 5}, (4.1.8),
(8.1.10), (8.10.3), (5.8, 3), (5.3, 2), (2.3.7),
(7.3.10), (7.10.6), (7.6.11), (11.6.0), (0.6.1),
(6.10.1), (9.11.0), (9.2.11), (9.5, 2), (7.11.2) 1;
glNewList(l,GL_COMPILE); glColorSd (1., 0.4, 1.);
glBegin(GLJTRIANGLES);
for (int i = 0; i < 20; i++)
{
double dl[3], d2[3], norm[3];
for (int j = 0; j < 3; j++)
{
dl[j] =v[id[i][0]] [j] – v[id[i][l]J [j];
d2[j] =v[id[i][l]] [j] – v[id[i][2J] [j];
}
//====== Вычисление и масштабирование нормали
getNorm(dl, d2, norm);
glNormal3dv(norm);
glVertexSdv(v [ id[i] [1]]);
glVertex3dv(v[id[i] [1] ] glVertex3dv(v[id[i] [2] ]
glEnd();
}
glEndList ();
}
Примечание
Функцию нормировки всех нормалей можно возложить на автомат OpenGL, если включить состояние GL_NORMALIZE, но обычно это ведет к замедлению перерисовки и, как следствие, выполнения приложения, если изображение достаточно сложное. В нашем случае оно просто, и поэтому вы можете проверить действие настройки, если вставите вызов glEnable (GL_NORMALIZE); в функцию Init (до вызова OrawScene) и временно выключите вызов Scale(out); производимый в функции getNorm. Затем вернитесь к исходному состоянию.
