Нормали вращаются неправильно, когда объект вращается
Я делаю простой тор в WebGL. Вращение вершин отлично работает, но у меня проблема с нормалями. При вращении вокруг одной оси они сохраняют правильное направление, но когда вращение вокруг второй оси возрастает, нормали начинают вращать неправильный путь до тех пор, пока один из вращений не станет на 180 °, тогда нормали вращаются в полной противоположности тому, что им следует.
Я предполагаю, что проблема кроется в кватернионе, используемом для вращения, но я не смог определить, что не так.
Вот (слегка измененный, но он все еще показывает проблему) jsfiddle моего проекта: https://jsfiddle.net/dt509x8h/1/
В html-части скрипта есть div, содержащий все данные из obj файла, который я читаю, для генерации тора (хотя и более низкого разрешения).
vertex shader:
attribute vec4 aVertexPosition;
attribute vec3 aNormalDirection;
uniform mat4 uMVPMatrix;
uniform mat3 uNMatrix;
varying vec3 nrm;
void main(void) {
gl_Position = uMVPMatrix * aVertexPosition;
nrm = aNormalDirection * uNMatrix;
}
фрагмент шейдера:
varying vec3 nrm;
void main(void) {
gl_FragColor = vec4(nrm, 1.0);
}
Обновление матриц (запуск при вводе):
mat4.perspective(pMatrix, Math.PI*0.25, width/height, clipNear, clipFar); //This is actually not run on input, it is just here to show the creation of the perspective matrix
mat4.fromRotationTranslation(mvMatrix, rotation, position);
mat3.normalFromMat4(nMatrix, mvMatrix);
mat4.multiply(mvpMatrix, pMatrix, mvMatrix);
var uMVPMatrix = gl.getUniformLocation(shaderProgram, "uMVPMatrix");
var uNMatrix = gl.getUniformLocation(shaderProgram, "uNMatrix");
gl.uniformMatrix4fv(uMVPMatrix, false, mvpMatrix);
gl.uniformMatrix3fv(uNMatrix, false, nMatrix);
Создание поворотного кватерниона (называемого при перемещении мыши):
var d = vec3.fromValues(lastmousex-mousex, mousey-lastmousey, 0.0);
var l = vec3.length(d);
vec3.normalize(d,d);
var axis = vec3.cross(vec3.create(), d, [0,0,1]);
vec3.normalize(axis, axis);
var q = quat.setAxisAngle(quat.create(), a, l*scale);
quat.multiply(rotation, q, rotation);
Вращение тора только вокруг оси Y, нормальная точка в правых направлениях:
Вращение тора вокруг двух осей. Нормали указывают на все места:
![Вращение вокруг двух осей]()
Я использую glMatrix v2.3.2 для всех операций с матрицами и кватернионами.
Обновление:
Кажется, что вращение только вокруг оси Z (путем установки входной оси для quat.setAxisAngle
явно на [0,0,1]
или с помощью quat.rotateZ
) также приводит к вращению нормалей в противоположном направлении.
Обнуление z-компонента axis
не помогает.
Update2:
Поворот на quat.rotateX(q, q, l*scale); quat.rotateY(q, q, l*scale); quat.multiply(rotation, q, rotation);
Кажется правильным, но как только вращается вокруг Z, z нормали начинает двигаться.
Использование разницы в значениях x или y мыши вместо l
приводит к перемещению всех нормалей, а также использование в основном разных значений scale
для x и y.
Update3: изменение порядка умножения в шейдере на uNMatrix * aNormalDirection
приводит к тому, что нормали всегда вращаются неправильно.
Ответы
Ответ 1
В моем случае проблема заключалась в том, как я загрузил данные из .obj файла. Я перевернул z-позицию всех вершин, но нормали были созданы из неперевернутых вершин.
Использование неинвертированных z-позиций и переворачивание умножения на нормальную матрицу фиксировали проблемы.