当前位置: 首页 > 知识库问答 >
问题:

如何使用webgl和glMatrix绕世界轴旋转对象

阎成天
2023-03-14

我试图旋转一个立方体,这样向下拖动总是绕着世界X轴旋转对象,而向一侧拖动总是绕着世界Y轴旋转对象,无论对象如何旋转。我看到了这个例子,它实现了我想要的准确行为:https://jsfiddle.net/MadLittleMods/n6u6asza/

$(renderer.domElement).on('mousedown', function(e) {
    isDragging = true;
})
.on('mousemove', function(e) {
    //console.log(e);
    var deltaMove = {
        x: e.offsetX-previousMousePosition.x,
        y: e.offsetY-previousMousePosition.y
    };

    if(isDragging) {

        var deltaRotationQuaternion = new three.Quaternion()
            .setFromEuler(new three.Euler(
                toRadians(deltaMove.y * 1),
                toRadians(deltaMove.x * 1),
                0,
                'XYZ'
            ));

        cube.quaternion.multiplyQuaternions(deltaRotationQuaternion, cube.quaternion);
    }

    previousMousePosition = {
        x: e.offsetX,
        y: e.offsetY
    };
});

这是我遇到麻烦的jsFiddle代码:http://jsfiddle.net/9sqvp52u/

var eye = vec3.fromValues(0, 5, radius * 1.5);
var target = vec3.fromValues(0, 0, 0);
var up = vec3.fromValues(0, 1, 0);
var vm = mat4.create();
var pvm = mat4.create();
var q = quat.create();
var rot = mat4.create();

// 1. perspective matrix
mat4.perspective(pvm, fovy, aspect, near, far);
// 2. view matrix
mat4.lookAt(vm, eye, target, up);
mat4.multiply(pvm, pvm, vm);
// 3. model matrix
var degY = radToDeg(dY);
var degX = radToDeg(dX);
quat.fromEuler(q, degY, degX, 0);
mat4.fromQuat(rot, q);
mat4.multiply(pvm, pvm, rot);

我看到了这个stackoverflow答案:OpenGL通过不同轴的多次旋转转换对象

但我还是不明白我做错了什么。在我的代码中,我仍然在将旋转矩阵乘以对象矩阵的左侧,但是对象总是围绕其局部轴旋转。

我真的很感激你的帮助。

共有1个答案

空慈
2023-03-14

问题是,必须在应用以前的旋转之后,但在视图和投影矩阵之前,将新旋转应用于模型。

如果您有一个mat4模型,其中收集了所有以前的旋转操作,并且您希望对该模型应用一个新的旋转newrot,那么最终的转换计算如下:

projection * view * newrot * model

要解决您的问题,您必须创建一个模型矩阵:

var model = mat4.create();
var newrot = mat4.create();

将新旋转矩阵应用于模型矩阵,并计算最终矩阵:

var degY = radToDeg(dY);
var degX = radToDeg(dX);
quat.fromEuler(q, degY, degX, 0);
mat4.fromQuat(newrot, q);
mat4.multiply(model, newrot, model);

var final = mat4.create();
mat4.multiply(final, pvm, model);

gl.uniformMatrix4fv(u_matrix, false, final);

请参阅我已将更改应用于原始代码的示例:

function main(images) {

document.body.removeChild(document.querySelector('canvas'));

const canvas = document.createElement('canvas');
canvas.id = 'canvas';
document.body.appendChild(canvas);

const gl = canvas.getContext('webgl');
if (!gl) {
    return;
}

var AMORTIZATION = 0.95;
var drag = false;
var old_x, old_y;
var dX = 0, dY = 0;
var mouseDown = function (e) {
    drag = true;
    old_x = e.pageX;
    old_y = e.pageY;

    e.preventDefault();
    return false;
};

var mouseUp = function (e) {
    drag = false;
};

var mouseMove = function (e) {
    if (!drag) return false;
    dX = (e.pageX - old_x) * 2 * Math.PI / canvas.width;
    dY = (e.pageY - old_y) * 2 * Math.PI / canvas.height;
    THETA += dX;
    PHI += dY;
    old_x = e.pageX, old_y = e.pageY;

    e.preventDefault();
};

canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mouseout', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);


const vertexShaderSource = document.getElementById('2d-vertex-shader').text;
const fragmentShaderSource = document.getElementById('2d-fragment-shader').text;

const program = gl.createProgram();

const vShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vShader, vertexShaderSource);
gl.compileShader(vShader);

const fShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fShader, fragmentShaderSource);
gl.compileShader(fShader);

gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
gl.linkProgram(program);

gl.useProgram(program);

var color = gl.getAttribLocation(program, 'color');
var position = gl.getAttribLocation(program, 'position');
var u_matrix = gl.getUniformLocation(program, 'u_matrix');
gl.enableVertexAttribArray(color);
gl.enableVertexAttribArray(position);

var multiplier = 1;
const width = canvas.clientWidth * multiplier | 0;
const height = canvas.clientHeight * multiplier | 0;
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.CULL_FACE);
gl.enable(gl.DEPTH_TEST);

var vertexData = [
    // x,    y,    z
    // front face (z: +1)
    1.0, 1.0, 1.0, // top right
    -1.0, 1.0, 1.0, // top left
    -1.0, -1.0, 1.0, // bottom left
    1.0, -1.0, 1.0, // bottom right
    // right face (x: +1)
    1.0, 1.0, -1.0, // top right
    1.0, 1.0, 1.0, // top left
    1.0, -1.0, 1.0, // bottom left
    1.0, -1.0, -1.0, // bottom right
    // top face (y: +1)
    1.0, 1.0, -1.0, // top right
    -1.0, 1.0, -1.0, // top left
    -1.0, 1.0, 1.0, // bottom left
    1.0, 1.0, 1.0, // bottom right
    // left face (x: -1)
    -1.0, 1.0, 1.0, // top right
    -1.0, 1.0, -1.0, // top left
    -1.0, -1.0, -1.0, // bottom left
    -1.0, -1.0, 1.0, // bottom right
    // bottom face (y: -1)
    1.0, -1.0, 1.0, // top right
    -1.0, -1.0, 1.0, // top left
    -1.0, -1.0, -1.0, // bottom left
    1.0, -1.0, -1.0, // bottom right
    // back face (z: -1)
    -1.0, 1.0, -1.0, // top right
    1.0, 1.0, -1.0, // top left
    1.0, -1.0, -1.0, // bottom left
    -1.0, -1.0, -1.0  // bottom right
];

var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);

const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,
        1.0, 0.0, 0.0,

        1.0, 1.0, 0.0,
        1.0, 1.0, 0.0,
        1.0, 1.0, 0.0,
        1.0, 1.0, 0.0,

        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,
        0.0, 1.0, 0.0,

        1.0, 0.5, 0.5,
        1.0, 0.5, 0.5,
        1.0, 0.5, 0.5,
        1.0, 0.5, 0.5,

        1.0, 0.0, 1.0,
        1.0, 0.0, 1.0,
        1.0, 0.0, 1.0,
        1.0, 0.0, 1.0,

        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0,
        0.0, 0.0, 1.0
    ]),
    gl.STATIC_DRAW
);

var vertexIndexData = [
    0, 1, 2, 0, 2, 3,    // Front face
    4, 5, 6, 4, 6, 7,    // Back face
    8, 9, 10, 8, 10, 11,  // Top face
    12, 13, 14, 12, 14, 15, // Bottom face
    16, 17, 18, 16, 18, 19, // Right face
    20, 21, 22, 20, 22, 23  // Left face
];
var vertexIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(vertexIndexData), gl.STATIC_DRAW);


var fovy = degToRad(40);
var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
var near = 0.1;
var far = -10;
var radius = 10;
var up = [0, 1, 0];
var time_old = 0;
var THETA = 0;
var PHI = 0;

var eye = vec3.fromValues(0, 5, radius * 1.5);
var target = vec3.fromValues(0, 0, 0);
var up = vec3.fromValues(0, 1, 0);
var vm = mat4.create();
var pvm = mat4.create();
var q = quat.create();
var newrot = mat4.create();
var model = mat4.create();

// 1. perspective matrix
mat4.perspective(pvm, fovy, aspect, near, far);
// 2. view matrix
mat4.lookAt(vm, eye, target, up);
mat4.multiply(pvm, pvm, vm);

requestAnimationFrame(render);

// Draw the scene.
function render(time) {
    // var dt = time - time_old;
    if (!drag) {
        dX *= AMORTIZATION;
        dY *= AMORTIZATION;
    }

    gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    gl.enable(gl.CULL_FACE);
    gl.enable(gl.DEPTH_TEST);
    gl.clearColor(198/255, 222/255, 183/255, 1);

    var degY = radToDeg(dY);
    var degX = radToDeg(dX);
    quat.fromEuler(q, degY, degX, 0);
    mat4.fromQuat(newrot, q);
    mat4.multiply(model, newrot, model);

    var final = mat4.create();
    mat4.multiply(final, pvm, model);

    gl.uniformMatrix4fv(u_matrix, false, final);

    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.vertexAttribPointer(position, 3, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    gl.vertexAttribPointer(color, 3, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);

    gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);

    requestAnimationFrame(render);
}
}

function radToDeg(r) {
return r * 180 / Math.PI;
}

function degToRad(d) {
return d * Math.PI / 180;
}

main();
#canvas { width: 900px; height: 600px; }
<canvas id="canvas"></canvas>
<div id="uiContainer">
    <div id="ui">
        <div id="cameraAngle"></div>
    </div>
</div>

<script id="2d-vertex-shader" type="notjs">
    attribute vec4 position;
    attribute vec4 color;

    uniform mat4 u_matrix;

    varying vec4 vColor;

    void main(void) {
        gl_Position = u_matrix * position;
        vColor = color;
    }
</script>
<script id="2d-fragment-shader" type="notjs">
    precision mediump float;

    varying vec4 vColor;

    void main(void) {
        gl_FragColor = vColor;
    }
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.7.1/gl-matrix-min.js"></script>
 类似资料:
  • 我目前正在尝试绕世界x轴旋转一个位置向量(0,0,1),然后将其旋转回其原始位置(只是尝试使其工作)。我阅读了旋转矩阵,并使它工作(排序),但我现在相当卡住了。 如图和代码所示,我在起点(0,0,1)处创建了一个立方体,并将其向下旋转30度。但顺时针旋转时,它的旋转角度似乎超过30度。但是,当我逆时针(30度)旋转它时,它确实旋转了适当的量。这导致它没有在它应该(0,0,1)的起点处结束。 我想知

  • 我正在创建一个外部欧拉角旋转的可视化,我想要一个立方体根据用户输入绕世界轴旋转的动画。我有一个dat。具有x、y和z旋转角度控件的GUI控件。看到这个截图。 到目前为止,我已经能够实现内部旋转,只需使用(和,)并设置多维数据集旋转。我的GUI代码看起来像这样: 当用户移动x旋转控件时,立方体将围绕其局部x轴旋转指定角度。然后,当用户移动y旋转控件时,已旋转的立方体将围绕其局部y轴旋转。 然而,我在

  • 我尝试绕全局y轴旋转对象(基本上,无论当前方向如何,都围绕0,1,0偏航)。我想给你看一张照片,但是声誉。。。我想绕全局轴而不是对象的局部轴旋转偏航。例如,如果我通过俯仰稍微倾斜一个长方体,然后尝试旋转偏航,它将以倾斜的角度而不是直线旋转长方体,就好像长方体根本没有倾斜一样。 每个对象将其位置和旋转存储在矩阵中,每个更新调用都会更新该矩阵。旋转的代码看起来是这样的: 其中,位置是每次更新都会平移和

  • 我想知道如何围绕它的Y轴旋转一个物体。 例如,我想旋转谷歌示例应用程序hello\u ar\u java的droid机器人https://github.com/google-ar/arcore-android-sdk/tree/master/samples/hello_ar_java围绕其Y轴,角度为alpha。

  • 我的屏幕上有一个旋转和平移的对象,但是我有两个关于z轴旋转的问题。解释起来有点棘手,所以我上传了两个视频来描述每个问题。 1) 反向旋转:在绕x轴旋转对象后,z轴旋转将被反向,并且应该如此。 2)错误的Z轴旋转:同样,在围绕x轴旋转物体后,我试图围绕z轴旋转物体,旋转导致不同的轴旋转。 我相信视频很好地描述了这些问题。 编辑:更新#1 好的,我想我找到了解决方案,就是只绕Z轴旋转相机,然后对模型本

  • 我是XNA的新手。我只是陷入了某种困境——我必须在游戏中倾斜/翻转角色,这意味着围绕X轴和Z轴旋转(不是同时旋转!)我可以做旋转-这意味着绕Y轴旋转。我有旋转矩阵,角色的当前位置向量(也是可以从旋转矩阵中获得的朝向/方向向量)我通过将朝向向量围绕Y轴旋转R弧度来实现旋转,即围绕Y轴旋转。比如说,如果我现在绕X轴旋转,那么方法是什么?例如,从站立姿势改为“超人飞行”姿势需要角色倾斜。。。y旋转不涉及