2016-04-17 10 views
6

Nicht sicher, was ich hier vermisse. Versuchen, einen Planeten (d. H. Eine Kugel) zu drehen, indem der Benutzer auf eine Schaltfläche "Drehen" klickt, aber nicht scheint, es herauszufinden. Ich habe das folgende Segment, das die Kugel durch Interaktion mit dem Benutzer mit der Maus dreht:Erstellen einer Kugel Drehen 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; 
} 

Dies funktioniert gut, aber ich will auch den Planeten machen, drehe automatisch, nachdem der Benutzer auf die Schaltfläche klickt. Hier ist meine onLoad Funktion:

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

Meine Frage ist: Wie kann ich ‚Toggle‘ die Drehung, nachdem der Benutzer auf die Schaltfläche klickt? Bisher habe ich versucht, die onmousemove Funktion in einem Versuch zu ändern, um die Kugel ohne Benutzerinteraktion drehen zu lassen, aber das funktioniert nicht.

als Update, hier ist eine neue Funktion doRotate() ich hinzugefügt:

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

die derzeit nicht für mich arbeiten. Diese Funktion soll aufgerufen werden, wenn auf die Schaltfläche geklickt wird und die Drehung umgeschaltet wird.

Update:

Für eine ähnliche Demo finden Sie unter this page. Ich versuche, die Kugel automatisch drehen zu lassen, nachdem der Benutzer auf die entsprechende Schaltfläche geklickt hat. Dies ist natürlich nicht in der Demo verlinkt - das dient nur zur Verdeutlichung.

Update 2:

ich da bezifferten habe es aus. Bitte beachten Sie meine Antwort unten für Details.

+1

Ich bin nicht wirklich sicher, was Sie fragen. Wenn du es rotieren lassen willst, brauchst du eine Art Animationsschleife mit 'requestAnimationFrame' und jedesmal in der Schleife drehst du den Planeten ein bisschen. [Beispiel] (http://webglfundamentals.org/webgl/lessons/webgl-animation.html). – gman

+0

Ich versuche, die Kugel von selbst drehen zu lassen, nachdem der Benutzer auf die Schaltfläche klickt, ohne mit der Maus interagieren zu müssen. Ich weiß, dass dies requestAnimationFrame erfordert, aber ich war bisher nicht erfolgreich. –

+0

Interessante Frage. Es würde helfen, wenn Sie ein Beispiel zusammenstellen könnten, z. mit Codepen oder Jsfiddle. Sie können dann Ihr Problem besser demonstrieren und erhalten wahrscheinlich schneller eine Antwort. –

Antwort

3

dachte ich es aus auf meinem eigenen nach unzähligen Mengen von Versuch und Irrtum. Grundsätzlich, wie WaclawJapser angedeutet, ich habe die Szene nicht neu gezeichnet. Ich ignorierte auch die Uniformen überhaupt. Ich werde den gesamten Code nicht veröffentlichen, aber hier ist die entsprechende Funktion nach dem Update:

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

Dies funktioniert nun genau so, wie ich ursprünglich beabsichtigt hatte. Ich weiß nicht, ob es jemandem helfen wird, da es sich um ein ziemlich enges Problem handelt, aber ich denke, ich würde ein Status-Update veröffentlichen.

Danke an alle, die versucht haben zu helfen!

3

Ich denke, das Problem mit Ihrer doRotate ist, dass es nicht die Szene neu zeichnen. Sicher, Sie haben eine neue Rotationsmatrix berechnet, aber Sie haben die Informationen nicht an die GPU weitergegeben und auch nicht angewiesen, die Szene erneut zu zeichnen. Aber ohne zu wissen, wie Ihr Programm geschrieben ist, ist es schwer zu sagen, ob das tatsächlich das Problem ist.

Es ist in der Regel eine gute Idee, das Programm um eine mainLoop-Funktion zu strukturieren, die jeden Frame ausführt und alle notwendigen Updates behandelt und die Szene neu zeichnet. Wie 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); 
} 

Dann zum Beispiel *.doUpdate wie so implementiert werden kann:

*.doUpdate = function(dt){ 
    if (clickedOnSphere){ 
     rotationMatrix = doCalculations(dt); 
     // send or flag rotationMatrix to be sent to GPU; 
    } 
}