gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 20:09:09 26 4
gpt4 key购买 nike

我正在尝试旋转一个立方体,以便向下拖动始终使对象围绕世界 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

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

非常感谢您的帮助。

最佳答案

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

如果您有一个 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>

关于javascript - 如何使用 webgl 和 glMatrix 围绕世界轴旋转对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52583057/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com