EDIT
OK, я попробовал камеру, использующую кватернионы:
qyaw = [Math.cos(rot[0]/2), 0, Math.sin(rot[0]/2), 0];
qpitch = [Math.cos(rot[1]/2), 0, 0, Math.sin(rot[1]/2)];
rotQuat = quat4.multiply (qpitch, qyaw);
camRot = quat4.toMat4(rotQuat);
camMat = mat4.multiply(camMat,camRot);
и получил точно такую же проблему. Так что я предполагаю, что это не блокировка кардана. Я пробовал менять порядок умножения матриц, но получается матрица камеры * матрица вида модели, затем матрица объекта * вид модели. Это правильно, не так ли?
Я пытаюсь создать 3d камеру в webGL, которая может перемещаться по миру и вращаться вокруг осей x и y (вправо и вверх).
Я получаю знакомую проблему (возможно, gimbal lock?), что когда одна из осей повернута, вращение вокруг другой испорчено; например, когда вы вращаетесь вокруг оси Y на 90 градусов, вращение вокруг x становится вращением вокруг z.
Я понимаю, что это распространенная проблема, и есть множество руководств по созданию камеры, которые позволяют избежать этой проблемы, но, насколько я могу судить, я реализовал два разных решения и все равно получаю ту же проблему. Честно говоря, это не дает мне покоя...
Одно из решений, которое я использую, следующее (адаптировано из http://www.toymaker.info/Games/html/camera.html):
function updateCam(){
yAx = [0,1,0];
xAx = [1,0,0];
zAx = [0,0,1];
mat4.identity(camMat);
xRotMat = mat4.create();
mat4.identity(xRotMat)
mat4.rotate(xRotMat,rot[0],xAx);
mat4.multiplyVec3(xRotMat,zAx);
mat4.multiplyVec3(xRotMat,yAx);
yRotMat = mat4.create();
mat4.identity(yRotMat)
mat4.rotate(yRotMat,rot[1],yAx);
mat4.multiplyVec3(yRotMat,zAx);
mat4.multiplyVec3(yRotMat,xAx);
zRotMat = mat4.create();
mat4.identity(zRotMat)
mat4.rotate(zRotMat,rot[2],zAx);
mat4.multiplyVec3(zRotMat,yAx);
mat4.multiplyVec3(zRotMat,xAx);
camMat[0] = xAx[0];
camMat[1] = yAx[0];
camMat[2] = zAx[0];
//camMat[3] =
camMat[4] = xAx[1]
camMat[5] = yAx[1];
camMat[6] = zAx[1];
//camMat[7] =
camMat[8] = xAx[2]
camMat[9] = yAx[2];
camMat[10]= zAx[2];
//camMat[11]=
camMat[12]= -1* vec3.dot(camPos, xAx);
camMat[13]= -1* vec3.dot(camPos, yAx);
camMat[14]= -1* vec3.dot(camPos, zAx);
//camMat[15]=
var movSpeed = 1.5 * forward;
var movVec= vec3.create(zAx);
vec3.scale(movVec, movSpeed);
vec3.add(camPos, movVec);
movVec= vec3.create(xAx);
movSpeed = 1.5 * strafe;
vec3.scale(movVec, movSpeed);
vec3.add(camPos, movVec);
}
Я также попробовал использовать этот метод, используя
mat4.rotate(camMat, rot[1], yAx);
вместо явного построения матрицы камеры - тот же результат.
Мой второй (на самом деле первый...) метод выглядит так (rot - массив, содержащий текущие вращения вокруг x, y и z (z всегда нулевой)):
function updateCam(){
mat4.identity(camRot);
mat4.identity(camMat);
camRot = fullRotate(rot);
mat4.set(camRot,camMat);
mat4.translate(camMat, camPos);
}
function fullRotate(angles){
var cosX = Math.cos(angles[0]);
var sinX = Math.sin(angles[0]);
var cosY = Math.cos(angles[1]);
var sinY = Math.sin(angles[1]);
var cosZ = Math.cos(angles[2]);
var sinZ = Math.sin(angles[2]);
rotMatrix = mat4.create([cosZ*cosY, -1*sinZ*cosX + cosZ*sinY*sinX, sinZ*sinX+cosZ*sinY*cosX, 0,
sinZ*cosY, cosZ*cosX + sinZ*sinY*sinX, -1*cosZ*sinX + sinZ*sinY*cosX, 0,
-1*sinY, cosY*sinX, cosY*cosX, 0,
0,0,0,1 ] );
mat4.transpose(rotMatrix);
return (rotMatrix);
}
Код (я убрал большинство шаблонов освещения gl и т.д. и оставил только трансформации) для фактического рисования сцены выглядит так:
function drawScene() {
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 2000.0, pMatrix);
mat4.identity(mvMatrix);
for(var i=0; i
Однако, большинство трансформаций можно игнорировать, тот же эффект можно увидеть, просто отобразив сферу на мировых координатах 0,0,0.
Я думал, что два моих метода - либо вращение осей по одной за раз по мере продвижения, либо построение матрицы вращения за один раз - позволяют избежать проблемы выполнения двух вращений одно за другим. Есть идеи, где я ошибаюсь?
PS - я все еще очень сильно начинаю изучать WebGL и 3d математику, так что будьте мягче и говорите со мной как с человеком, который не слышал о матрице всего пару месяцев назад... Также, я знаю, что кватернионы являются хорошим решением для 3d вращения, и это будет моей следующей попыткой, однако, я думаю, мне нужно понять, почему эти два метода не работают...