在 WebGL 中制作球体旋转
Making a Sphere Rotate in WebGL
不确定我在这里遗漏了什么。试图通过让用户单击 'Rotate' 按钮来使行星(即球体)旋转,但似乎无法弄清楚。我确实有以下部分通过用户与鼠标的交互来旋转球体:
document.onmousemove = function() {
if (!mouseDown) {
return;
}
var newX = event.clientX;
var newY = event.clientY;
var deltaX = newX - lastMouseX
var newRotationMatrix = mat4.create();
mat4.identity(newRotationMatrix);
mat4.rotate(newRotationMatrix, degToRad(deltaX / 10), [0, 1, 0]);
var deltaY = newY - lastMouseY;
mat4.rotate(newRotationMatrix, degToRad(deltaY / 10), [1, 0, 0]);
mat4.multiply(newRotationMatrix, planetRotationMatrix, planetRotationMatrix);
lastMouseX = newX
lastMouseY = newY;
}
这个很好用,但我还想让地球在用户点击按钮后自动旋转。这是我的 onLoad
函数:
window.onload = function onLoad() {
canvas = document.getElementById("gl-canvas");
initGL(canvas);
initShaders();
initBuffers();
initTexture();
initEvtHandlers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
var newRotationMatrix = mat4.create();
mat4.identity(newRotationMatrix);
document.getElementById("rotate").onclick = function () {
// rotation code goes here?
}
render();
}
我的问题是:如何'toggle'用户点击按钮后的旋转?到目前为止,我尝试的是修改 onmousemove
函数,试图让球体在没有用户交互的情况下旋转,但这是行不通的。
作为更新,这是我添加的新 doRotate()
函数:
var myRotationMatrix = mat4.create();
mat4.identity(myRotationMatrix);
doRotate = function () {
var dx = 1;
var newMatrix = mat4.create();
mat4.identity(newMatrix);
mat4.rotate(newMatrix, degToRad(dx / 10), [0, 1, 0]);
mat4.multiply(newMatrix, myRotationMatrix);
requestAnimFrame(doRotate);
}
目前对我不起作用。单击按钮时应该调用此函数,切换旋转。
更新:
类似的演示,请参见this page。我想要做的是在用户点击相关按钮后让球体自动旋转。这显然不在演示链接中——这只是为了澄清目的。
更新二:
我已经弄明白了。有关详细信息,请参阅下面的答案。
我认为您的 doRotate
的问题在于它没有重新绘制场景。当然,你计算了一个新的旋转矩阵,但你没有将信息传递给 gpu,也没有告诉它重新绘制场景。但是不知道你的程序是如何编写的,很难说这是否真的是问题所在。
围绕 mainLoop
函数构建程序通常是个好主意,该函数运行每一帧并处理所有必要的更新和重绘场景。像这样:
var lastTimeStamp = 0;
function mainLoop(timeStamp){
var dt = timeStamp - lastTimeStamp;
lastTimeStamp = timeStamp;
everythingThatNeedsUpdate.doUpdate(dt); // this should calculate the new rotationMatrix for your sphere and send it to GPU
gl.drawEverything();
requestAnimationFrame(mainLoop);
}
然后,例如,*.doUpdate
可以这样实现:
*.doUpdate = function(dt){
if (clickedOnSphere){
rotationMatrix = doCalculations(dt);
// send or flag rotationMatrix to be sent to GPU;
}
}
经过无数次的反复试验,我自己弄明白了。基本上,正如 WaclawJapser 暗示的那样,我没有重绘场景。我也完全无视制服。我不会 post 整个代码,但这里是修复后的相关函数:
requestAnimationFrame(rotatePlanet);
function rotatePlanet(now) {
if (flag == false) {
return; // do nothing if unchecked
} else {
// Start by clearing the current buffers to avoid an overlap.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Subtract the previous time from the current time.
now *= 0.001;
var deltaTime = now - then;
// Cache the current time to remember it for the next frame.
then = now;
// Every frame increases the rotation a little.
rotation[0] += rotationSpeed * deltaTime;
// Perform the necessary transformations.
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -6]);
mat4.rotate(mvMatrix, rotation[0], [0, 1, 0]); // rotates around y
mat4.rotate(mvMatrix, rotation[1], [1, 0, 0]); // rotates around x
// Set the matrix.
setMatrixUniforms();
// Draw the geometry.
gl.drawElements(gl.TRIANGLES, planetVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(rotatePlanet);
}
}
现在这完全符合我最初的预期。我不知道它是否会对任何人有所帮助,因为它看起来是一个相当狭窄的问题,但我想我会 post 状态更新。
感谢所有试图提供帮助的人!
不确定我在这里遗漏了什么。试图通过让用户单击 'Rotate' 按钮来使行星(即球体)旋转,但似乎无法弄清楚。我确实有以下部分通过用户与鼠标的交互来旋转球体:
document.onmousemove = function() {
if (!mouseDown) {
return;
}
var newX = event.clientX;
var newY = event.clientY;
var deltaX = newX - lastMouseX
var newRotationMatrix = mat4.create();
mat4.identity(newRotationMatrix);
mat4.rotate(newRotationMatrix, degToRad(deltaX / 10), [0, 1, 0]);
var deltaY = newY - lastMouseY;
mat4.rotate(newRotationMatrix, degToRad(deltaY / 10), [1, 0, 0]);
mat4.multiply(newRotationMatrix, planetRotationMatrix, planetRotationMatrix);
lastMouseX = newX
lastMouseY = newY;
}
这个很好用,但我还想让地球在用户点击按钮后自动旋转。这是我的 onLoad
函数:
window.onload = function onLoad() {
canvas = document.getElementById("gl-canvas");
initGL(canvas);
initShaders();
initBuffers();
initTexture();
initEvtHandlers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
var newRotationMatrix = mat4.create();
mat4.identity(newRotationMatrix);
document.getElementById("rotate").onclick = function () {
// rotation code goes here?
}
render();
}
我的问题是:如何'toggle'用户点击按钮后的旋转?到目前为止,我尝试的是修改 onmousemove
函数,试图让球体在没有用户交互的情况下旋转,但这是行不通的。
作为更新,这是我添加的新 doRotate()
函数:
var myRotationMatrix = mat4.create();
mat4.identity(myRotationMatrix);
doRotate = function () {
var dx = 1;
var newMatrix = mat4.create();
mat4.identity(newMatrix);
mat4.rotate(newMatrix, degToRad(dx / 10), [0, 1, 0]);
mat4.multiply(newMatrix, myRotationMatrix);
requestAnimFrame(doRotate);
}
目前对我不起作用。单击按钮时应该调用此函数,切换旋转。
更新:
类似的演示,请参见this page。我想要做的是在用户点击相关按钮后让球体自动旋转。这显然不在演示链接中——这只是为了澄清目的。
更新二:
我已经弄明白了。有关详细信息,请参阅下面的答案。
我认为您的 doRotate
的问题在于它没有重新绘制场景。当然,你计算了一个新的旋转矩阵,但你没有将信息传递给 gpu,也没有告诉它重新绘制场景。但是不知道你的程序是如何编写的,很难说这是否真的是问题所在。
围绕 mainLoop
函数构建程序通常是个好主意,该函数运行每一帧并处理所有必要的更新和重绘场景。像这样:
var lastTimeStamp = 0;
function mainLoop(timeStamp){
var dt = timeStamp - lastTimeStamp;
lastTimeStamp = timeStamp;
everythingThatNeedsUpdate.doUpdate(dt); // this should calculate the new rotationMatrix for your sphere and send it to GPU
gl.drawEverything();
requestAnimationFrame(mainLoop);
}
然后,例如,*.doUpdate
可以这样实现:
*.doUpdate = function(dt){
if (clickedOnSphere){
rotationMatrix = doCalculations(dt);
// send or flag rotationMatrix to be sent to GPU;
}
}
经过无数次的反复试验,我自己弄明白了。基本上,正如 WaclawJapser 暗示的那样,我没有重绘场景。我也完全无视制服。我不会 post 整个代码,但这里是修复后的相关函数:
requestAnimationFrame(rotatePlanet);
function rotatePlanet(now) {
if (flag == false) {
return; // do nothing if unchecked
} else {
// Start by clearing the current buffers to avoid an overlap.
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Subtract the previous time from the current time.
now *= 0.001;
var deltaTime = now - then;
// Cache the current time to remember it for the next frame.
then = now;
// Every frame increases the rotation a little.
rotation[0] += rotationSpeed * deltaTime;
// Perform the necessary transformations.
mat4.identity(mvMatrix);
mat4.translate(mvMatrix, [0, 0, -6]);
mat4.rotate(mvMatrix, rotation[0], [0, 1, 0]); // rotates around y
mat4.rotate(mvMatrix, rotation[1], [1, 0, 0]); // rotates around x
// Set the matrix.
setMatrixUniforms();
// Draw the geometry.
gl.drawElements(gl.TRIANGLES, planetVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
requestAnimationFrame(rotatePlanet);
}
}
现在这完全符合我最初的预期。我不知道它是否会对任何人有所帮助,因为它看起来是一个相当狭窄的问题,但我想我会 post 状态更新。
感谢所有试图提供帮助的人!