Расчет нормалей.
Для того чтобы использовать освещение нам нужно вычислить нормаль для каждой вершины сетки. Напомню, что вектор нормали - это вектор единичной длины, перпендикулярный к поверхности в данной точке этой поверхности и направленный от обратной стороны поверхности к лицевой стороне. Чтобы нарисовать поверхность, нам потребуется ее разбить на множество треугольников. Лицевой стороной треугольника является сторона, которая при рисовании обходится по вершинам против часовой стрелки:
Нормаль к плоскости может быть вычислена как векторное произведение двух векторов A и B, лежащих в данной плоскости:
Как видно из рисунка направление нормали определяется по правилу правого винта при переходе от вектора A к вектору B. При переходе против часовой стрелки нормаль направлена вверх, при переходе по часовой стрелке - вниз. Направление "вверх" у нас совпадает с направление оси Y. В математическом виде компоненты векторного произведения записываются так: normalX=ay*bz-by*az normalY=bx*az-ax*bz normalZ=ax*by-bx*ay где ax, ay, az - координаты вектора A bx, by, bz - координаты вектора B Чтобы вычислить нормаль для конкретной вершины сетки, нам нужно определить для нее векторы A и B. Возьмем вершину с индексами [j] [i] и достроим от нее два вектора - вниз на один шаг - вектор A и вправо один шаг - вектор B:
Зададим для хранения координат векторов нормалей три массива: float [] normalX=new float[jmax+1][imax+1]; Теперь мы можем вычислить нормаль для вершины [j] [i]: ax = 0 normalX [j] [i] = ay*bz-by*az = - by*az = - (y [j] [i+1] - y [j] [i]) * dz
По этим формулам мы можем вычислить нормали в диапазоне номеров i от 0 до (imax-1) и j от 0 до (jmax-1). Отдельно нужно рассчитать нормали для крайнего правого столбца (i=imax) и крайней нижней строки (j=jmax), а также для правого нижнего угла (i=imax, j=jmax). Для расчета нормалей нужно правильно подобрать векторы A и B:
Расчет вектора нормали для вершин с индексами [ j ] [ imax ] в крайнем правом столбце: ax = x [ imax -1] - x [imax] = - dx normalX [j] [imax] = ay*bz-by*az = ay*bz = (y [ j ] [ imax -1] - y [ j ] [ imax]) * dz Расчет вектора нормали для вершин с индексами [ jmax ] [ i ] в крайней нижней строке: ay = y [ jmax ] [ i+1 ] - y [ jmax ] [ i ] normalX [jmax] [ i ] = ay*bz-by*az = ay*bz = - (y [ jmax ] [ i+1 ] - y [ jmax ] [ i ]) * dz Расчет вектора нормали для правого нижнего угла [ jmax ] [ imax ]: ay = y [ jmax-1 ] [ imax ] - y [ jmax ] [ imax ] normalX [jmax] [ imax ]=ay*bz-by*az =-by*az =(y [ jmax] [ imax-1] - y [ jmax] [imax]) * dz По аналогии с координатами вершин мы должны переписать координаты нормалей последовательно в одномерный массив и отправить его в байтовый буфер: ByteBuffer nb = ByteBuffer.allocateDirect((jmax+1)*(imax+1)*3*4); int k=0; Итак, мы научились по координатам вершин в сетки вычислять вектор нормали для каждой вершины. Оформим расчет нормалей в виде метода: normalX [j] [i] = - (y [j] [i+1] - y [j] [i]) * dz; normalY [j] [i] = dx * dz; normalZ [j] [i] = - dx * (y [j+1] [i] - y [j] [i]); } } normalY [j] [imax] = dx * dz; normalZ [j] [imax] = - dx * (y [ j+1 ] [ imax] - y [ j ] [ imax ]); } normalY [jmax] [ i ] = dx * dz; normalZ [jmax] [ i ] = dx * (y [ jmax-1 ] [ i ] - y [ jmax ] [ i ]); } //переписываем координаты вектора нормали в одномерный массив normal int k=0; Мы не будем нормализовать нормали на CPU, поручим нормализацию шейдерам.
|