我上一篇文章说了一下怎么创建一个三维场景,这次说一下怎么让这个场景动起来
让你的场景动起来
- 首先需要解决如何在特定的时间间隔重新渲染场景,在H5没出现之前,是通过setInterval()方法实现的,比如通过setInterval()手动指定每500ms调用一次。这个方法的缺点:它不管浏览器当前在做什么(比如在浏览其他网页),它都会按照你设定的每隔500ms执行一次。显然setInterval这个方法并没有与屏幕的刷新同步,这将会导致较高的CPU使用率。
- 下面我们引入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