[英]Making a Sphere Rotate in WebGL
不知道我在這里缺少什么。 嘗試通過讓用戶點擊“旋轉”按鈕來使行星(即球體)旋轉,但似乎無法弄明白。 我確實有以下段通過用戶與鼠標的交互來旋轉球體:
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();
}
我的問題是:用戶點擊按鈕后如何“切換”旋轉? 到目前為止,我所嘗試的是修改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);
}
哪個目前不適合我。 單擊按鈕時,應調用此函數,切換旋轉。
更新:
有關類似的演示,請參閱此頁面 。 我要做的是在用戶點擊相關按鈕后自動旋轉球體。 這顯然不在演示鏈接中 - 這只是為了澄清目的。
更新2:
我已經弄清楚了。 有關詳細信息,請參閱下面的答案。
我認為你的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所暗示的那樣,我並沒有重新繪制場景。 我也完全無視制服。 我不會發布整個代碼,但這里是修復后的相關函數:
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);
}
}
這現在完全按照我原先的意圖行事。 我不知道它是否會對任何人有所幫助,因為它似乎是一個非常狹窄的問題,但我想我會發布狀態更新。
感謝所有試圖幫助的人!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.