РЕДАКТИРОВАТЬ
ОК, я пробовал камеру с кватернионами:
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);
, и я получаю точнота же проблема.Так что я предполагаю, что это не карданный замок.Я попытался изменить порядок, которым я умножаю свои матрицы, но это просто матрица камеры * матрица вида модели, затем матрица объекта * вид модели.Это верно, не так ли?
Я пытаюсь создать в webGL 3d-камеру, которая может перемещаться по миру и вращаться вокруг осей x и y (вправо и вверх).
У меня возникает знакомая проблема (возможно, карданная блокировка?), Что как только одна из осей вращается, вращение вокруг другой облажается;например, когда вы поворачиваете вокруг оси 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);
}
Код (я вынул большую часть стандартного освещения и т. д. и только что оставил преобразования), чтобы фактически нарисовать сцену:
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<planets.length; i++){
if (planets[i].type =="sun"){
currentProgram = perVertexSunProgram;
} else {
currentProgram = perVertexNormalProgram;
}
alpha = planets[i].alphaFlag;
mat4.identity(planets[i].rotMat);
mvPushMatrix();
//all the following puts planets in orbit around a central sun, but it's not really relevant to my current problem
var rot = [0,rotCount*planets[i].orbitSpeed,0];
var planetMat;
planetMat = mat4.create(fullRotate(rot));
mat4.multiply(planets[i].rotMat, planetMat);
mat4.translate(planets[i].rotMat, planets[i].position);
if (planets[i].type == "moon"){
var rot = [0,rotCount*planets[i].moonOrbitSpeed,0];
moonMat = mat4.create(fullRotate(rot));
mat4.multiply(planets[i].rotMat, moonMat);
mat4.translate(planets[i].rotMat, planets[i].moonPosition);
mat4.multiply(planets[i].rotMat, mat4.inverse(moonMat));
}
mat4.multiply(planets[i].rotMat, mat4.inverse(planetMat));
mat4.rotate(planets[i].rotMat, rotCount*planets[i].spinSpd, [0, 1, 0]);
//this bit does the work - multiplying the model view by the camera matrix, then by the matrix of the object we want to render
mat4.multiply(mvMatrix, camMat);
mat4.multiply(mvMatrix, planets[i].rotMat);
gl.useProgram(currentProgram);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, planets[i].VertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
mvPopMatrix();
}
}
Однако большинство преобразований можно игнорировать, тот же эффект можно увидеть, просто отображая сферу с мировыми координатами 0,0,0.
Я думал, что два моих метода - либо вращениепо одной оси за раз, или когда вы строите матрицу вращения за один раз, вы избежали проблемы двух вращений одна за другой. Есть идеи, где я ошибаюсь?
PS - Я 'Я все еще очень начинаю изучать WebGLd 3d математика, так что будьте нежны и говорите со мной, как кто-то, кто не слышал о матрице пару месяцев назад ... Кроме того, я знаю, что кватернионы являются хорошим решением для 3d-вращения, и это будет моей следующей попыткойТем не менее, я думаю, что мне нужно понять, почему эти два метода не работают в первую очередь ...