Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a Sphere Rotate in WebGL

Not sure what I'm missing here. Trying to make a planet (i.e. sphere) rotate by having the user click on a 'Rotate' button, but can't seem to figure it out. I do have the following segment which rotates the sphere by way of user interaction with the mouse:

    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;
}

This one works fine, but I also want to make the planet rotate automatically after the user clicks the button. Here is my onLoad function:

    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(); 
}

My question is: How can I 'toggle' the rotation after the user clicks the button? So far what I've tried is modify the onmousemove function in an attempt to make the sphere rotate without user interaction, but that's not working.

As an update, here is a new doRotate() function I added:

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);
}

Which is currently not working for me. This function is supposed to be called when the button is clicked, toggling the rotation.

Update:

For a similar demo, please see this page. What I'm trying to do is make the sphere rotate automatically after the user clicks the relevant button. This is obviously not in the demo linked--that's only for clarification purposes.

Update 2:

I've since figured it out. Please see my answer below for details.

like image 428
Fiery Phoenix Avatar asked Apr 17 '16 03:04

Fiery Phoenix


Video Answer


1 Answers

I think the problem with your doRotate is that it doesnt re-draw the scene. Sure, you calculated a new rotation matrix but you have not pass the information to the gpu nor tell it to draw the scene again. But without knowing how your program is written it is hard to say if that is actually the problem.

It is usually a good idea to structure the program around a mainLoop function that runs every frame and handles all the necessary updates and redraw the scene. Like so:

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);
}

Then, for example, *.doUpdate may be implemented like such:

*.doUpdate = function(dt){
    if (clickedOnSphere){
        rotationMatrix = doCalculations(dt);
        // send or flag rotationMatrix to be sent to GPU; 
    }
}
like image 79
WacławJasper Avatar answered Oct 15 '22 16:10

WacławJasper