簡體   English   中英

使球體在WebGL中旋轉

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM