【问题标题】:how to rotate object around world axis with webgl and glMatrix如何使用 webgl 和 glMatrix 围绕世界轴旋转对象
【发布时间】:2019-03-06 02:06:39
【问题描述】:

我正在尝试旋转一个立方体,以便向下拖动总是围绕世界 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 transforming objects with multiple rotations of Different axis

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

非常感谢您的帮助。

【问题讨论】:

    标签: javascript rotation webgl


    【解决方案1】:

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

    如果您有一个mat4 model,其中所有先前的旋转操作都已收集,并且您希望将新的旋转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>

    【讨论】:

      猜你喜欢
      • 2015-07-23
      • 1970-01-01
      • 2016-09-02
      • 2019-10-18
      • 2016-02-29
      • 1970-01-01
      • 2014-04-18
      • 2015-04-11
      相关资源
      最近更新 更多