Создание 3D свободной камеры в WebGL - почему ни один из этих методов не работает?

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 вращения, и это будет моей следующей попыткой, однако, я думаю, мне нужно понять, почему эти два метода не работают...

5
задан Fridge 7 October 2011 в 12:49
поделиться