threejs-场景中物体做动画

我上一篇文章说了一下怎么创建一个三维场景,这次说一下怎么让这个场景动起来

让你的场景动起来

    1. 首先需要解决如何在特定的时间间隔重新渲染场景,在H5没出现之前,是通过setInterval()方法实现的,比如通过setInterval()手动指定每500ms调用一次。这个方法的缺点:它不管浏览器当前在做什么(比如在浏览其他网页),它都会按照你设定的每隔500ms执行一次。显然setInterval这个方法并没有与屏幕的刷新同步,这将会导致较高的CPU使用率。
    1. 下面我们引入h5的方法requestAnimationFrame()方法,这个方法能为稳定而连续的渲染场景提供良好的解决方案。通过这个函数你可以向浏览器提供一个回调函数,跟setInterval()不同的是,你无需定义回调的间隔,浏览器会自行决定回调的最佳时机。需要做的就是在这个回调函数里完成一帧(一个静止画面)的绘制操作。然后将剩下的工作交给浏览器。它负责使场景绘制尽量高效和平顺的进行。
function renderScene() {
    requestAnimationFrame( renderScene);
    renderer.render( scene, camera );
}
  • 如上代码但我们改变了物体的位置,就必须重新调用render()函数,因为浏览器是不会自动刷新的,假如我们不断的改变物体的位置,就需要不断的重新绘制场景,最好的方式就是执行循环,不断的调用render()来重绘场景,renderScene()就是不断的执行render()函数,在render()函数中不断的绘制场景和不断的改变相机的位置并渲染他们。这里的参数scene不是指场景不断的在动,场景永远在原点(0,0,0),永远不会改变
    let scene = new THREE.Scene();
    let camera = new THREE.PerspectiveCamera(45, window.innerWidth / 
    window.innerHeight, 0.1, 1000);
    let renderer = new THREE.WebGLRenderer();

    renderer.setClearColor(new THREE.Color(0x000000));
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;

    // 创建地平面
    let planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1);
    let planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff });
    let plane = new THREE.Mesh(planeGeometry, planeMaterial);

    // 旋转定位地平面
    plane.rotation.x = -0.5 * Math.PI;
    plane.position.x = 15;
    plane.position.y = 0;
    plane.position.z = 0;

    // 将地平面添加到场景中
    scene.add(plane);

    // 创建立方体
    let cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
    let cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });
    let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
    cube.castShadow = true;

    // 定位立方体
    cube.position.x = -4;
    cube.position.y = 4;
    cube.position.z = 0;

    // 将立方体添加到场景当中
    scene.add(cube);

    // 创建球体
    let sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
    let sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff });
    let sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

    // 定位球体
    sphere.position.x = 20;
    sphere.position.y = 0;
    sphere.position.z = 2;
    sphere.castShadow = true;

    // 将球体添加到场景当中
    scene.add(sphere);

    camera.position.x = -30;
    camera.position.y = 40;
    camera.position.z = 30;
    camera.lookAt(scene.position);

    // 添加微妙的环境照明
    let ambienLight = new THREE.AmbientLight(0x353535);
    scene.add(ambienLight);

    // 为阴影添加聚光灯
    let spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(-10, 20, -5);
    spotLight.castShadow = true;
    scene.add(spotLight);

    // 将渲染器的输出添加到id为"webgl-output"元素
    document.getElementById("webgl-output").appendChild(renderer.domElement);

    // 调用渲染函数
    let step = 0;
    renderScene();
    function renderScene() {
      stats.update();

      // 围绕其轴旋转立方体
      cube.rotation.x += 0.02;
      cube.rotation.y += 0.02;
      cube.rotation.z += 0.02;

      // 上下反弹球体
      step += 0.04;
      sphere.position.x = 20 + (10 * (Math.cos(step)));
      sphere.position.y = 2 + (10 * Math.abs(Math.sin(step)));

      // 使用requestAnimationFrame渲染
      requestAnimationFrame(renderScene);
      renderer.render(scene, camera);
    }
  • 把代码运行起来会看到下图所示,至于视角的问题其实是固定相机的位置问题,场景、相机都是默认是世界坐标系,相机的默认坐标也是原点(0,0,0)位置。
image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。