ОСВЕЩЕНИЕ
5.2. Расчет нормали к объекту
Во всех формулах для освещенности у нас так или иначе будет фигурировать
вектор N - нормаль к объекту в точке P. Сразу возникает вопрос, а как же
этот вектор считать.
Обычно придерживаются такой логики. Модель у нас состоит из плоских граней,
но эта сетка плоских граней приближает какой-то искривленный объект. Нормаль
к этому искривленному объекту меняется в каждой точке, а для плоских граней
она постоянна для всех точек грани, и резко меняется при переходе на другую
грань. Поэтому нормаль к объекту обычно приближают следующим образом: считают
нормали в вершинах, а нормаль в какой-то точке грани линейно интерполируют
между вершинами; то есть линейно интерполируют по грани все три координаты
нормали.
Нормаль в вершине рассчитываются как сумма приведенных к длине 1 нормалей ко
всем граням, к которым принадлежит эта вершина. То есть. Сначала считаем
нормали ко всем граням и приводим их к длине 1. Далее, для каждой вершины
надо перебрать все грани, и если очередная грань содержит эту вершину, то
к нормали в вершине прибавляется нормаль к этой грани. Первоначально все
нормали к вершинам полагаются равными нулю. Для больших моделей этот процесс
может быть довольно долгим, но достаточно провести его заранее один раз и
сохранить все посчитанные нормали к вершинам.
Для вящей понятности приведу кусок кода:
// ...
for (i = 0; i < numberOfVertics; i++) {
vertexNormal[i].x = 0;
vertexNormal[i].y = 0;
vertexNormal[i].z = 0;
}
for (i = 0; i < numberOfVertics; i++) {
for (j = 0; j < numberOfFaces; j++) {
if (face[j].vertex0 == i ||
face[j].vertex1 == i ||
face[j].vertex2 == i)
{
vertexNormal[i].x += faceNormal[j].x;
vertexNormal[i].y += faceNormal[j].y;
vertexNormal[i].z += faceNormal[j].z;
}
}
}
// ...
Но это метод даже слишком лобовой, и поэтому медленный. Можно сделать все
проще и быстрее: перебираем все грани, и к нормалям всех принадлежащих грани
вершин добавляем нормаль грани. После этого приводим все нормали к длине 1,
причем эта фаза даже не обязательна, а лишь удобна для дальнейших расчетов.
Соответствующий кусочек кода:
// ...
for (i = 0; i < numberOfVertics; i++) {
vertexNormal[i].x = 0;
vertexNormal[i].y = 0;
vertexNormal[i].z = 0;
}
for (i = 0; i < numberOfFaces; i++) {
vertexNormal[face[i].vertex0].x += faceNormal[j].x;
vertexNormal[face[i].vertex1].y += faceNormal[j].y;
vertexNormal[face[i].vertex2].z += faceNormal[j].z;
}
// ...