Three.js以速度和摩擦为动画

时间:2017-02-24 10:33:53

标签: three.js game-physics

我试图在three.js中制作3D旋转轮动画,其中我按一个键来加速滚轮,当我释放按键时,它会通过摩擦减速直到它停止。

我在这个网站上尝试过不同的例子,但我不能让它正常运行。我理解物理,但我很难在渲染循环中实现它。

同样在将来我想实施减速曲线。 有没有人知道如何制作这样的东西?

提前致谢

编辑:

终于得到了一些有点像我想要的东西!这是我的代码:`



var container, outputLeap;
var camera, scene, renderer;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var sceneRoot = new THREE.Group();
var wheelSpin = new THREE.Group();
var wheelMesh;

var clock = new THREE.Clock();

var speed = 0.1;
var decelRate = 100;

function onWindowResize() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

function onWindowResize() {
  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}


function init() {
  outputLeap = document.getElementById('output-leap');
  container = document.getElementById('container');


  camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 80);

  scene = new THREE.Scene();

  var geometryWheel = new THREE.CylinderGeometry(3, 3, 0.05, 32);
  var materialWheel = new THREE.MeshBasicMaterial({
    color: 0xffff00,
    wireframe: true
  });
  var wheelMesh = new THREE.Mesh(geometryWheel, materialWheel);
  scene.add(sceneRoot);

  sceneRoot.add(wheelSpin);
  wheelSpin.add(wheelMesh);

  renderer = new THREE.WebGLRenderer();
  renderer.setClearColor(0x000000);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);

  window.addEventListener('resize', onWindowResize, false);
}

function render() {

  var time = clock.getElapsedTime();
  var delta = clock.getDelta();

  camera.position.y = 15;

  if (speed > 0)
    speed = Math.max(0, speed - decelRate * delta);
  else
    speed = Math.min(0, speed + decelRate * delta);

  camera.lookAt(scene.position);
  wheelSpin.rotation.y -= speed;

  outputLeap.innerHTML = 'Rotation: ' + speed;

  renderer.render(scene, camera);
}


function animate() {
  requestAnimationFrame(animate); 
  render();
}


init();
animate();

<!DOCTYPE html>
<html lang="en">

<head>
  <title></title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>

<body>
  <div id="info-top">
    <div id="output"></div>
    <div id="output-leap"><br></div>
  </div>
  <div id="container"></div>
  <script src="http://threejs.org/build/three.min.js">
  </script>
  <script src='js/THREEx.KeyboardState.js'></script>
  <script>
  </script>
</body>

</html>
&#13;
&#13;
&#13;

似乎delta是使动画工作的关键。但现在我想知道为什么?我也想知道你如何将速度和减速变量转化为更多现实的&#34;值?

1 个答案:

答案 0 :(得分:1)

有许多方法可以模拟摩擦和相关的加速度。

这是一个简单的整合。

摩擦力(阻力)是与速度指数相关的力,该力作用于移动(旋转)物体的质量。

我们可以忽略这样一个事实:我们有一个旋转物体,因为摩擦的位置在中心。还有人希望轴在轴承或润滑轴上旋转,这在很大程度上可以描述为阻力。

如果我们从拖曳函数中删除所有系数,面积,粘度,滚动摩擦和blah blah(它们都是线性关系)并查看核心函数。 drag = 1/2 * v*v其中v是速度。乘以一些可调系数,我们得到了力量。

速度是车轮的一部分接触车轴的运动,我们从车轴的半径和旋转速度得到。

因此我们可以设置sim。

wheel = {
   mass : 100,  // mass
   axleRadius : 40,  // the lower the radius the less the drag
   deltaRot : 0.3,  // rate of turn per unit time.
   dragCoff : 0.1, //coefficients of drag
}

获得对轴的速度

var velocity = wheel.deltaRot * axleRadius;

从该速度中获取阻力

var drag = 0.5 * velocity * velocity * wheel.dragCoff;

将该拖动(作为力)施加在方向盘的质量f = ma

var accel = drag / wheel.mass;

将加速度转换回接触轴的表面上的速度

wheel.deltaRot -= accel / wheel.axleRadius;

你有一个很好的近似轮子转动轴。

车轴半径对阻力有很大影响。半径越大,阻力越大。 dragCoff是我们未包括的所有因素,如接触轴的表面积,轴承滚动阻力,润滑粘度。它们都是线性关系(我假设你不会在模拟过程中改变轴半径)与速度平方相比,所以可以捆绑成一个数字以满足你的需要(当然少于一个)

质量越大,质量越大,车轮旋转的时间越长。

作为一个简单的演示,该功能已经简化了一点

&#13;
&#13;
var wheel = {
   mass : 100,
   radius : 100,  // has no effect on the sim
   axleRadius : 30,
   deltaRot : 1.3,
   dragCoff : 0.2, //coefficients of drag
   rotation : 0,
}
function updateWheel(w){
    w.deltaRot -= ((0.5 * Math.pow(w.deltaRot * w.axleRadius,2) * w.dragCoff) / w.mass) / w.axleRadius;
    w.rotation += w.deltaRot;
}
function drawCircle(radius,x=0,y=0){
    ctx.beginPath();
    ctx.arc(0,0,radius,0,Math.PI * 2);
    ctx.fill();
}
function display() { 
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
    ctx.globalAlpha = 1; // reset alpha
    ctx.clearRect(0, 0, w, h);
    updateWheel(wheel);
    ctx.setTransform(1,0,0,1,cw,ch); // draw at center of canvas
    ctx.rotate(wheel.rotation);
    ctx.fillStyle = "black";
    drawCircle(wheel.radius);
    ctx.fillStyle = "red";
    drawCircle(wheel.radius-10);
    ctx.fillStyle = "black";
    ctx.fillRect(0,-10,wheel.radius-5,20);
    ctx.fillStyle = "white";
    drawCircle(wheel.axleRadius+2);
    ctx.fillStyle = "black";
    drawCircle(wheel.axleRadius);
}

var w, h, cw, ch, canvas, ctx, globalTime = 0, firstRun = true;
;(function(){
    var  createCanvas, resizeCanvas;
    createCanvas = function () {
        var c, cs;
        cs = (c = document.createElement("canvas")).style;
        cs.position = "absolute";
        cs.top = cs.left = "0px";
        cs.zIndex = 1000;
        document.body.appendChild(c);
        return c;
    }
    resizeCanvas = function () {
        if (canvas === undefined) {
            canvas = createCanvas();
        }
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        ctx = canvas.getContext("2d");
        cw = (w = canvas.width) / 2;
        ch = (h = canvas.height) / 2;
        wheel.deltaRot = 1.3;
    }
    function update() { // Main update loop
        display(); // call demo code
        requestAnimationFrame(update);
    }
    setTimeout(function(){
        resizeCanvas();
        window.addEventListener("resize", resizeCanvas);
        requestAnimationFrame(update);
    },0);
})();
&#13;
&#13;
&#13;