hiccLoghicc log by wccHipo日志

学习Three.js

toc

Intro

基于r95版本three.js。整理知识点,以及demo。

尝鲜

// create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x000000)); renderer.setSize(window.innerWidth, window.innerHeight); // show axes in the screen var axes = new THREE.AxesHelper(20); scene.add(axes); // create the ground plane var planeGeometry = new THREE.PlaneGeometry(60, 20); var planeMaterial = new THREE.MeshBasicMaterial({ color: 0xAAAAAA }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.set(15, 0, 0); // add the plane to the scene scene.add(plane); // create a cube var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xFF0000, wireframe: true }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); // position the cube cube.position.set(-4, 3, 0); // add the cube to the scene scene.add(cube); // create a sphere var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshBasicMaterial({ color: 0x7777FF, wireframe: true }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere sphere.position.set(20, 4, 2); // add the sphere to the scene scene.add(sphere); // position and point the camera to the center of the scene camera.position.set(-30, 40, 30); camera.lookAt(scene.position); // add the output of the renderer to the html element document.getElementById("webgl-output").appendChild(renderer.domElement); // render the scene renderer.render(scene, camera);
  • 渲染器renderer
  • 场景scene
    • axes
    • 平面几何体
      • 类型,PlaneGeometrySphereGeometry
      • 材质 MeshBasicMaterial
      • 组合Mesh对象
    • 摄影机camera 决定哪些对象被渲染

添加材质、光源和阴影效果

(function init() { // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 ); // create a render and configure it with shadows var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x000000)); renderer.setSize(window.innerWidth, window.innerHeight); // renderer.shadowMap.enabled = true; // createTree(scene); // createHouse(scene); // createGroundPlane(scene); // createBoundingWall(scene); // create a cube var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000, }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; // position the cube cube.position.x = -4; cube.position.y = 2; cube.position.z = 0; // add the cube to the scene var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff, }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere sphere.position.x = 20; sphere.position.y = 4; sphere.position.z = 2; sphere.castShadow = true; // create the ground plane var planeGeometry = new THREE.PlaneGeometry(60, 20); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xaaaaaa, }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.set(15, 0, 0); plane.receiveShadow = true; // add the objects scene.add(cube); scene.add(sphere); scene.add(plane); // position and point the camera to the center of the scene camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); // add spotlight for the shadows var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-40, 40, -15); spotLight.castShadow = true; spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024); spotLight.shadow.camera.far = 130; spotLight.shadow.camera.near = 40; // If you want a more detailled shadow you can increase the // mapSize used to draw the shadows. // spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024); scene.add(spotLight); var ambienLight = new THREE.AmbientLight(0x353535); scene.add(ambienLight); // add the output of the renderer to the html element document.getElementById("webgl-output").appendChild(renderer.domElement); // call the render function renderer.render(scene, camera); })(); function createBoundingWall(scene) { var wallLeft = new THREE.CubeGeometry(70, 2, 2); var wallRight = new THREE.CubeGeometry(70, 2, 2); var wallTop = new THREE.CubeGeometry(2, 2, 50); var wallBottom = new THREE.CubeGeometry(2, 2, 50); var wallMaterial = new THREE.MeshLambertMaterial({ color: 0xa0522d, }); var wallLeftMesh = new THREE.Mesh(wallLeft, wallMaterial); var wallRightMesh = new THREE.Mesh(wallRight, wallMaterial); var wallTopMesh = new THREE.Mesh(wallTop, wallMaterial); var wallBottomMesh = new THREE.Mesh(wallBottom, wallMaterial); wallLeftMesh.position.set(15, 1, -25); wallRightMesh.position.set(15, 1, 25); wallTopMesh.position.set(-19, 1, 0); wallBottomMesh.position.set(49, 1, 0); scene.add(wallLeftMesh); scene.add(wallRightMesh); scene.add(wallBottomMesh); scene.add(wallTopMesh); } function createGroundPlane(scene) { // create the ground plane var planeGeometry = new THREE.PlaneGeometry(70, 50); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0x9acd32, }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; scene.add(plane); } function createHouse(scene) { var roof = new THREE.ConeGeometry(5, 4); var base = new THREE.CylinderGeometry(5, 5, 6); // create the mesh var roofMesh = new THREE.Mesh( roof, new THREE.MeshLambertMaterial({ color: 0x8b7213, }) ); var baseMesh = new THREE.Mesh( base, new THREE.MeshLambertMaterial({ color: 0xffe4c4, }) ); roofMesh.position.set(25, 8, 0); baseMesh.position.set(25, 3, 0); roofMesh.receiveShadow = true; baseMesh.receiveShadow = true; roofMesh.castShadow = true; baseMesh.castShadow = true; scene.add(roofMesh); scene.add(baseMesh); } /** * Add the tree to the scene * @param scene The scene to add the tree to */ function createTree(scene) { var trunk = new THREE.CubeGeometry(1, 8, 1); var leaves = new THREE.SphereGeometry(4); // create the mesh var trunkMesh = new THREE.Mesh( trunk, new THREE.MeshLambertMaterial({ color: 0x8b4513, }) ); var leavesMesh = new THREE.Mesh( leaves, new THREE.MeshLambertMaterial({ color: 0x00ff00, }) ); // position the trunk. Set y to half of height of trunk trunkMesh.position.set(-10, 4, 0); leavesMesh.position.set(-10, 12, 0); trunkMesh.castShadow = true; trunkMesh.receiveShadow = true; leavesMesh.castShadow = true; leavesMesh.receiveShadow = true; scene.add(trunkMesh); scene.add(leavesMesh); }

让场景动起来

function init() { // 帧率统计 var stats = initStats(); // default setup var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x000000)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; // create the ground plane var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; // add the plane to the scene scene.add(plane); // create a cube var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; // position the cube cube.position.x = -4; cube.position.y = 4; cube.position.z = 0; // add the cube to the scene scene.add(cube); var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere sphere.position.x = 20; sphere.position.y = 0; sphere.position.z = 2; sphere.castShadow = true; // add the sphere to the scene scene.add(sphere); // position and point the camera to the center of the scene camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); // add subtle ambient lighting var ambienLight = new THREE.AmbientLight(0x353535); scene.add(ambienLight); // add spotlight for the shadows var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-10, 20, -5); spotLight.castShadow = true; scene.add(spotLight); // add the output of the renderer to the html element document.getElementById("webgl-output").appendChild(renderer.domElement); // call the render function var step = 0; renderScene(); function renderScene() { stats.update(); // rotate the cube around its axes cube.rotation.x += 0.02; cube.rotation.y += 0.02; cube.rotation.z += 0.02; // bounce the sphere up and down step += 0.04; sphere.position.x = 20 + (10 * (Math.cos(step))); sphere.position.y = 2 + (10 * Math.abs(Math.sin(step))); // render using requestAnimationFrame requestAnimationFrame(renderScene); renderer.render(scene, camera); } }

动画建议使用requestAnimationFrame

  • 旋转 rotation
  • 弹跳 Math.cos() Math.sin()

加上控制面板

使用简单的表单控制库 dat.GUI

function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x000000)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; // create the ground plane var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; // add the plane to the scene scene.add(plane); // create a cube var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; // position the cube cube.position.x = -4; cube.position.y = 3; cube.position.z = 0; // add the cube to the scene scene.add(cube); var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere sphere.position.x = 20; sphere.position.y = 0; sphere.position.z = 2; sphere.castShadow = true; // add the sphere to the scene scene.add(sphere); // position and point the camera to the center of the scene camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); // add subtle ambient lighting var ambienLight = new THREE.AmbientLight(0x353535); scene.add(ambienLight); // add spotlight for the shadows var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-10, 20, -5); spotLight.castShadow = true; scene.add(spotLight); // add the output of the renderer to the html element document.getElementById("webgl-output").appendChild(renderer.domElement); // call the render function var step = 0; var controls = new function () { this.rotationSpeed = 0.02; this.bouncingSpeed = 0.03; }; var gui = new dat.GUI(); gui.add(controls, 'rotationSpeed', 0, 0.5); gui.add(controls, 'bouncingSpeed', 0, 0.5); // attach them here, since appendChild needs to be called first var trackballControls = initTrackballControls(camera, renderer); var clock = new THREE.Clock(); render(); function render() { // update the stats and the controls trackballControls.update(clock.getDelta()); stats.update(); // rotate the cube around its axes cube.rotation.x += controls.rotationSpeed; cube.rotation.y += controls.rotationSpeed; cube.rotation.z += controls.rotationSpeed; // bounce the sphere up and down step += controls.bouncingSpeed; sphere.position.x = 20 + (10 * (Math.cos(step))); sphere.position.y = 2 + (10 * Math.abs(Math.sin(step))); // render using requestAnimationFrame requestAnimationFrame(render); renderer.render(scene, camera); } }

场景对浏览器自适应

function init() { // listen to the resize events window.addEventListener('resize', onResize, false); var camera; var scene; var renderer; // initialize stats var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. scene = new THREE.Scene(); // create a camera, which defines where we're looking at. camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size renderer = new THREE.WebGLRenderer(); renderer.setClearColor(new THREE.Color(0x000000)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; // initialize the trackball controls and the clock which is needed var trackballControls = initTrackballControls(camera, renderer); var clock = new THREE.Clock(); // create the ground plane var planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1); var planeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff }); var plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.receiveShadow = true; // rotate and position the plane plane.rotation.x = -0.5 * Math.PI; plane.position.x = 15; plane.position.y = 0; plane.position.z = 0; // add the plane to the scene scene.add(plane); // create a cube var cubeGeometry = new THREE.BoxGeometry(4, 4, 4); var cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 }); var cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.castShadow = true; // position the cube cube.position.x = -4; cube.position.y = 3; cube.position.z = 0; // add the cube to the scene scene.add(cube); var sphereGeometry = new THREE.SphereGeometry(4, 20, 20); var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0x7777ff }); var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere sphere.position.x = 20; sphere.position.y = 0; sphere.position.z = 2; sphere.castShadow = true; // add the sphere to the scene scene.add(sphere); // position and point the camera to the center of the scene camera.position.x = -30; camera.position.y = 40; camera.position.z = 30; camera.lookAt(scene.position); // add subtle ambient lighting var ambienLight = new THREE.AmbientLight(0x353535); scene.add(ambienLight); // add spotlight for the shadows var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-10, 20, -5); spotLight.castShadow = true; scene.add(spotLight); // add the output of the renderer to the html element document.getElementById("webgl-output").appendChild(renderer.domElement); // call the render function var step = 0; var controls = new function () { this.rotationSpeed = 0.02; this.bouncingSpeed = 0.03; }; var gui = new dat.GUI(); gui.add(controls, 'rotationSpeed', 0, 0.5); gui.add(controls, 'bouncingSpeed', 0, 0.5); render(); function render() { // update the stats and the controls trackballControls.update(clock.getDelta()); stats.update(); // rotate the cube around its axes cube.rotation.x += controls.rotationSpeed; cube.rotation.y += controls.rotationSpeed; cube.rotation.z += controls.rotationSpeed; // bounce the sphere up and down step += controls.bouncingSpeed; sphere.position.x = 20 + (10 * (Math.cos(step))); sphere.position.y = 2 + (10 * Math.abs(Math.sin(step))); // render using requestAnimationFrame requestAnimationFrame(render); renderer.render(scene, camera); } function onResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); } }

window resize 需要设置camera的aspect 属性,设置renderer的尺寸

function onResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }