THREE.js-旋转旋转3D球

时间:2018-09-02 04:12:04

标签: javascript three.js 3d physics

我是THREE.js的新手,对物理学的了解很差-但是我正在尝试构建一个足球游戏引擎(从顶部观察),而现在我正为球的运动而苦苦挣扎。 / p>

当试图从一侧到另一侧移动球时,旋转总是面向一个方向,我不知道如何使球朝其移动方向旋转。

我添加了一个简单的代码来显示此问题。非常感谢您的帮助。

     /*
            *
            * SET UP MOTION PARAMS
            * 
            */

            var degrees = 10;
            var power = 1;
            var angleRad = degrees * Math.PI / 120;

            var velocityX = Math.cos(angleRad) * power;
            var velocityY = Math.sin(angleRad) * power;
            var velocityZ = 1;

            var friction = 1;
            var gravity = 0.2;
            var bounciness = 0.9;



            window.onload = function (params) {

                /*
                *
                * SET UP THE WORLD
                * 
                */
                
                
                
                //set up the ratio
                var gWidth = window.innerWidth;
                var gHeight = window.innerHeight;
                var ratio = gWidth / gHeight;
                var borders = [40, 24] //indicate where the ball needs to move in mirror position


                //set the scene
                scene = new THREE.Scene();
                scene.background = new THREE.Color(0xeaeaea);

                //set the camera
                var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
                camera.position.z = 120;   

                //set the light
                var light = new THREE.SpotLight(0xffffff, 1);
                light.position.set(100, 1, 0); 		
                light.castShadow = true;         
                light.position.set(0, 0, 100);
                scene.add(light);

                //  set the renderer 
                var renderer = new THREE.WebGLRenderer();

                //properties for casting shadow
                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFSoftShadowMap; 

                renderer.setSize(gWidth, gHeight);
                document.body.appendChild(renderer.domElement);



                
                /*
                *
                * ADD MESH TO SCENE
                * 
                */


                // create and add the ball
                var geometry = new THREE.SphereGeometry(5, 5, 5);
                var material = new THREE.MeshLambertMaterial({ color: 'gray' });
                var ball = new THREE.Mesh(geometry, material);

                ball.castShadow = true;
                ball.receiveShadow = false;
                scene.add(ball);


                
                // create and add the field
                var margin = 20;
                var fieldRatio = 105 / 68;

                var width = 90;
                var height = width / fieldRatio;

                var material = new THREE.MeshLambertMaterial({ color: 'green' });
                var geometry = new THREE.BoxGeometry(width, height, 1);
                var field = new THREE.Mesh(geometry, material);

                field.receiveShadow = true;
                field.position.z = -1;
                scene.add(field);




                /*
                * setting up rotation axis 
                */


                var rotation_matrix = null;

                var setQuaternions = function () {
                    setMatrix();
                    ball.rotation.set(Math.PI / 2, Math.PI / 4, Math.PI / 4); // Set initial rotation
                    ball.matrix.makeRotationFromEuler(ball.rotation); // Apply rotation to the object's matrix
                }

                var setMatrix = function () {
                    rotation_matrix = new THREE.Matrix4().makeRotationZ(angleRad); // Animated rotation will be in .01 radians along object's X axis
                }

                setQuaternions();


                /*
                *
                * ANIMATION STEP
                * 
                */

                var render = function (params) {

                    // add velocity to ball
                    ball.position.x += velocityX;
                    ball.position.z += velocityZ;
                    ball.position.y += velocityY;


                    //validate if ball is stop moving
                    if (Math.abs(velocityX) < 0.02 && Math.abs(velocityY) < 0.02) {
                        console.log("DONE!");
                        return;
                    }



                    // handle boucing effect
                    if (ball.position.z < 1) {
                        velocityZ *= -bounciness;
                        ball.position.z = 1
                    }


                    // Update the object's rotation & apply it
                    ball.matrix.multiply(rotation_matrix);
                    ball.rotation.setFromRotationMatrix(ball.matrix);


                    //reducing speed by friction
                    angleRad *= friction;
                    velocityX *= friction;
                    velocityY *= friction;
                    velocityZ *= friction;


                    //set up the matrix 
                    setMatrix();
                    


                    //validate ball is withing its borders otherwise go in the mirror direction
                    if (Math.abs(ball.position.x) > borders[0]) {
                        velocityX *= -1;
                        ball.position.x = (ball.position.x < 0) ? borders[0] * -1 : borders[0];
                    }

                    if (Math.abs(ball.position.y) > borders[1]) {
                        velocityY *= -1;
                        ball.position.y = (ball.position.y < 0) ? borders[1] * -1 : borders[1];
                    }


                    // reduce ball height with gravity
                    velocityZ -= gravity;

                    

                    //render the page
                    renderer.render(scene, camera);

                    requestAnimationFrame(render);
                }

                render();

            }
body {
    padding: 0;
    margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<html>

<head>

</head>

<body>
</body>

</html>

2 个答案:

答案 0 :(得分:2)

如果我正确理解了您的情况,那么您将希望对球进行旋转,该旋转基于球的局部空间的“右轴”。

THREE.js在import time print("Hello. Please enter your name, then press 'enter' ") username = input() print("Hello " + username) time.sleep(2) def game_tutorial_input(): while True: tutorial_answer = input("Do you wish to see the tutorial?" "(y/n) ") if "y" in tutorial_answer: input("Great! Press enter after each instruction to move" "onto the next one.") input("To answer each question, type one of the given" "options depending on what you want to select," " then press enter.") input("Wow, that was short tutorial!") else: print("Alright!") continue return time.sleep(2) print("Welcome, " + username + ", to Indiana") 类上提供了许多辅助方法来简化此数学namely the makeRotationAxis() method

从概念上和实践上,对您的ball.rotation数学进行少量调整即可实现您想要的。请参见以下代码片段以了解如何完成此操作(或参见this working jsFiddle):

THREE.Matrix4
   /*
            *
            * SET UP MOTION PARAMS
            * 
            */
            
            var rotationAngle = 0;

            var degrees = 10;
            var power = 1;
            var angleRad = degrees * Math.PI / 120;

            var velocityX = Math.cos(angleRad) * power;
            var velocityY = Math.sin(angleRad) * power;
            var velocityZ = 1;

            var friction = 1;
            var gravity = 0.2;
            var bounciness = 0.9;



            window.onload = function (params) {

                /*
                *
                * SET UP THE WORLD
                * 
                */
                
                
                
                //set up the ratio
                var gWidth = window.innerWidth;
                var gHeight = window.innerHeight;
                var ratio = gWidth / gHeight;
                var borders = [40, 24] //indicate where the ball needs to move in mirror position


                //set the scene
                scene = new THREE.Scene();
                scene.background = new THREE.Color(0xeaeaea);

                //set the camera
                var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
                camera.position.z = 120;   

                //set the light
                var light = new THREE.SpotLight(0xffffff, 1);
                light.position.set(100, 1, 0); 		
                light.castShadow = true;         
                light.position.set(0, 0, 100);
                scene.add(light);

                //  set the renderer 
                var renderer = new THREE.WebGLRenderer();

                //properties for casting shadow
                renderer.shadowMap.enabled = true;
                renderer.shadowMap.type = THREE.PCFSoftShadowMap; 

                renderer.setSize(gWidth, gHeight);
                document.body.appendChild(renderer.domElement);



                
                /*
                *
                * ADD MESH TO SCENE
                * 
                */


                // create and add the ball
                var geometry = new THREE.SphereGeometry(5, 5, 5);
                var material = new THREE.MeshLambertMaterial({ color: 'gray' });
                var ball = new THREE.Mesh(geometry, material);

                ball.castShadow = true;
                ball.receiveShadow = false;
                scene.add(ball);


                
                // create and add the field
                var margin = 20;
                var fieldRatio = 105 / 68;

                var width = 90;
                var height = width / fieldRatio;

                var material = new THREE.MeshLambertMaterial({ color: 'green' });
                var geometry = new THREE.BoxGeometry(width, height, 1);
                var field = new THREE.Mesh(geometry, material);

                field.receiveShadow = true;
                field.position.z = -1;
                scene.add(field);




                /*
                * setting up rotation axis 
                */


                var rotation_matrix = null;

                var setQuaternions = function () {
                    setMatrix();
                    ball.rotation.set(Math.PI / 2, Math.PI / 4, Math.PI / 4); // Set initial rotation
                    ball.matrix.makeRotationFromEuler(ball.rotation); // Apply rotation to the object's matrix
                }

                var setMatrix = function () {
                    rotation_matrix = new THREE.Matrix4().makeRotationZ(angleRad); // Animated rotation will be in .01 radians along object's X axis
                }

                setQuaternions();


                /*
                *
                * ANIMATION STEP
                * 
                */

                var render = function (params) {

                    // add velocity to ball
                    ball.position.x += velocityX;
                    ball.position.z += velocityZ;
                    ball.position.y += velocityY;


                    //validate if ball is stop moving
                    if (Math.abs(velocityX) < 0.02 && Math.abs(velocityY) < 0.02) {
                        console.log("DONE!");
                        return;
                    }



                    // handle boucing effect
                    if (ball.position.z < 1) {
                        velocityZ *= -bounciness;
                        ball.position.z = 1
                    }


                    // Update the object's rotation & apply it
                  //                    ball.matrix.multiply(rotation_matrix);
                  // Compute the direction vector of the balls current forward direction of motion
                  var vectorDirection = new THREE.Vector3(velocityX, velocityY, velocityZ);

                  // Compute the vector about which the balls rotation is calculated. This is at a 
                  // right angle to the vectorDirection, and so we use the cross product to 
                  // calculate this
                  var axisOfRotation = new THREE.Vector3().crossVectors(vectorDirection, new THREE.Vector3(0,0,1) );

                  // Normalise the rotation axis to unit length
                  axisOfRotation.normalize();

                  // Build a rotation matrix around the rotation axis.
                  var rotation = new THREE.Matrix4();
                  rotation .makeRotationAxis(axisOfRotation, rotationAngle)
                  ball.rotation.setFromRotationMatrix(rotation );

                  // Decrement the rotation angle to achieve the rolling effect
                  rotationAngle -= 0.1;
                    
                   // ball.rotation.setFromRotationMatrix(ball.matrix);


                    //reducing speed by friction
                    angleRad *= friction;
                    velocityX *= friction;
                    velocityY *= friction;
                    velocityZ *= friction;


                    //set up the matrix 
                    setMatrix();
                    


                    //validate ball is withing its borders otherwise go in the mirror direction
                    if (Math.abs(ball.position.x) > borders[0]) {
                        velocityX *= -1;
                        ball.position.x = (ball.position.x < 0) ? borders[0] * -1 : borders[0];
                    }

                    if (Math.abs(ball.position.y) > borders[1]) {
                        velocityY *= -1;
                        ball.position.y = (ball.position.y < 0) ? borders[1] * -1 : borders[1];
                    }


                    // reduce ball height with gravity
                    velocityZ -= gravity;

                    

                    //render the page
                    renderer.render(scene, camera);

                    requestAnimationFrame(render);
                }

                render();

            }
body {
    padding: 0;
    margin: 0;
}

答案 1 :(得分:1)

如果要包括摩擦力和惯性等,这实际上是物理学的一种超现实的高级方法。但是您可以采取一些捷径来获得不错的视觉滚动效果...

如果沿球的运动方向获取向量,则可以通过获取运动向量与世界向上向量的叉积来获得垂直向量。

该向量是如果球与地面完全摩擦,则球绕其旋转的轴。有了该轴后,就可以将.rotateOnWorldAxis(轴:Vector3,角度:Float)与对象一起使用。

然后,您必须根据球的半径和行进的距离计算出旋转的角度。.所以它是运动矢量*(PI * 2)的长度(在我的代码中称为幅度) /球的圆周。

让我知道这是否有帮助...

p.s-您的“ angleRad”计算除以120而不是180。我已解决该问题。

/*
 *
 * SET UP MOTION PARAMS
 * 
 */

var degrees = 35;
var power = 0.45;
var angleRad = degrees * Math.PI / 180;

var velocityX = Math.cos(angleRad) * power;
var velocityY = Math.sin(angleRad) * power;
var velocityZ = 1;

var friction = 1;
var gravity = 0.2;
var bounciness = 0.9;

var ballRadius = 5;
var ballCircumference = Math.PI * ballRadius * 2;
var ballVelocity = new THREE.Vector3();
var ballRotationAxis = new THREE.Vector3(0, 1, 0);


window.onload = function(params) {

  /*
   *
   * SET UP THE WORLD
   * 
   */



  //set up the ratio
  var gWidth = window.innerWidth;
  var gHeight = window.innerHeight;
  var ratio = gWidth / gHeight;
  var borders = [40, 24] //indicate where the ball needs to move in mirror position


  //set the scene
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xeaeaea);

  //set the camera
  var camera = new THREE.PerspectiveCamera(35, ratio, 0.1, 1000);
  camera.position.z = 120;

  //set the light
  var light = new THREE.SpotLight(0xffffff, 1);
  light.position.set(100, 1, 0);
  light.castShadow = true;
  light.position.set(0, 0, 35);
  scene.add(light);

  //  set the renderer 
  var renderer = new THREE.WebGLRenderer();

  //properties for casting shadow
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  renderer.setSize(gWidth, gHeight);
  document.body.appendChild(renderer.domElement);




  /*
   *
   * ADD MESH TO SCENE
   * 
   */


  // create and add the ball
  var geometry = new THREE.SphereGeometry(ballRadius, 8, 8);

  //make a checkerboard texture for the ball...
  var canv = document.createElement('canvas')
  canv.width = canv.height = 256;
  var ctx = canv.getContext('2d')
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, 256, 256);
  ctx.fillStyle = 'black';
  
  for (var y = 0; y < 16; y++)
    for (var x = 0; x < 16; x++)
      if ((x & 1) != (y & 1)) ctx.fillRect(x * 16, y * 16, 16, 16);
  var ballTex = new THREE.Texture(canv);
  ballTex.needsUpdate = true;


  var material = new THREE.MeshLambertMaterial({
    map: ballTex
  });
  var ball = new THREE.Mesh(geometry, material);

  ball.castShadow = true;
  ball.receiveShadow = false;
  scene.add(ball);



  // create and add the field
  var margin = 20;
  var fieldRatio = 105 / 68;

  var width = 90;
  var height = width / fieldRatio;

  var material = new THREE.MeshLambertMaterial({
    color: 'green'
  });
  var geometry = new THREE.BoxGeometry(width, height, 1);
  var field = new THREE.Mesh(geometry, material);

  field.receiveShadow = true;
  field.position.z = -1;
  scene.add(field);




  /*
   * setting up rotation axis 
   */


  var rotation_matrix = null;

  var setQuaternions = function() {
    setMatrix();
    ball.rotation.set(Math.PI / 2, Math.PI / 4, Math.PI / 4); // Set initial rotation
    ball.matrix.makeRotationFromEuler(ball.rotation); // Apply rotation to the object's matrix
  }

  var setMatrix = function() {
    rotation_matrix = new THREE.Matrix4().makeRotationZ(angleRad); // Animated rotation will be in .01 radians along object's X axis
  }

  setQuaternions();


  /*
   *
   * ANIMATION STEP
   * 
   */

  var render = function(params) {

    // add velocity to ball
    ball.position.x += velocityX;
    ball.position.z += velocityZ;
    ball.position.y += velocityY;


    //validate if ball is stop moving
    if (Math.abs(velocityX) < 0.02 && Math.abs(velocityY) < 0.02) {
      console.log("DONE!");
      return;
    }



    // handle boucing effect
    if (ball.position.z < 1) {
      velocityZ *= -bounciness;
      ball.position.z = 1
    }


    // Update the object's rotation & apply it
    /*
                    ball.matrix.multiply(rotation_matrix);   ball.rotation.setFromRotationMatrix(ball.matrix);
    //set up the matrix 
    setMatrix();
*/

    // Figure out the rotation based on the velocity and radius of the ball...
    ballVelocity.set(velocityX, velocityY, velocityZ);
    ballRotationAxis.set(0, 0, 1).cross(ballVelocity).normalize();
    var velocityMag = ballVelocity.length();
    var rotationAmount = velocityMag * (Math.PI * 2) / ballCircumference;
    ball.rotateOnWorldAxis(ballRotationAxis, rotationAmount)


    //reducing speed by friction
    angleRad *= friction;
    velocityX *= friction;
    velocityY *= friction;
    velocityZ *= friction;





    //validate ball is withing its borders otherwise go in the mirror direction
    if (Math.abs(ball.position.x) > borders[0]) {
      velocityX *= -1;
      ball.position.x = (ball.position.x < 0) ? borders[0] * -1 : borders[0];
    }

    if (Math.abs(ball.position.y) > borders[1]) {
      velocityY *= -1;
      ball.position.y = (ball.position.y < 0) ? borders[1] * -1 : borders[1];
    }


    // reduce ball height with gravity
    velocityZ -= gravity;



    //render the page
    renderer.render(scene, camera);

    requestAnimationFrame(render);
  }

  render();

}
body {
  padding: 0;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/96/three.min.js"></script>
<html>

<head>

</head>

<body>
</body>

</html>