参考资料
- 第一个3D案例—透视投影相机
- 第一个3D案例—渲染器
- …
- Canvas画布布局和全屏
知识点
- 透视投影相机PerspectiveCamera
- WebGL渲染器WebGLRenderer
- 辅助观察坐标系AxesHelper
- 漫反射网格材质MeshLambertMaterial
- 点光源PointLight
- 点光源辅助观察PointLightHelper
- 环境光AmbientLight
- 平行光DirectionalLight
- 平行光辅助观察DirectionalLightHelper
- 相机控件OrbitControls
- 请求动画帧window.requestAnimationFrame
- canvas画布宽高度动态变化
- 性能监控Stats
代码实现
-
相机、渲染器、光
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Three.js</title> </head><body></body><!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 --><script type="importmap">{"imports": {"three": "./js/three.module.js","three/addons/": "../three.js/examples/jsm/"}}</script><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';const width = 800const height = 500// 场景const scene = new THREE.Scene();// 几何体const geometry = new THREE.BoxGeometry(100, 100, 100);// 材质 // MeshBasicMaterial:不受光// MeshLambertMaterial:受光const material = new THREE.MeshLambertMaterial({color:0x0000ff,});// 网格模型:物体const mesh = new THREE.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);// 坐标系const axes = new THREE.AxesHelper(200);scene.add(axes);// // 点光源// const pointLight = new THREE.PointLight( 0xffffff, 1.0, 0, 0);// pointLight.position.set(-200, 200, 200 );// scene.add( pointLight );// // 辅助点光源// const pointLightHelper = new THREE.PointLightHelper( pointLight, 10 );// scene.add( pointLightHelper );// 环境光const ambientLight = new THREE.AmbientLight( 0xffffff, 0.2);scene.add( ambientLight );// 平行光const directionalLight = new THREE.DirectionalLight( 0xffffff, 1, 0, 0);// directionalLight.position.set(100, 0, 0);// directionalLight.position.set(0, 100, 0);// directionalLight.position.set(100, 100, 100);directionalLight.position.set(100, 60, 50);directionalLight.target = mesh;scene.add( directionalLight );// 辅助平行光const directionalLightHelper = new THREE.DirectionalLightHelper( directionalLight, 10 );scene.add( directionalLightHelper );// 相机const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);camera.position.set(200, 200, 200);camera.lookAt(scene.position);// 渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);renderer.render(scene, camera);document.body.appendChild(renderer.domElement);// 控制器const controls = new OrbitControls(camera, renderer.domElement);controls.addEventListener('change', () => {renderer.render(scene, camera);});</script> </html>
-
动画
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Three.js</title> </head><body></body><!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 --><script type="importmap">{"imports": {"three": "./js/three.module.js","three/addons/": "../three.js/examples/jsm/"}}</script><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';const width = 800const height = 500// 场景const scene = new THREE.Scene();// 几何体const geometry = new THREE.BoxGeometry(100, 100, 100);// 材质const material = new THREE.MeshBasicMaterial({color: 0x00ff00,transparent: true,opacity: 0.5});// 网格模型:物体const mesh = new THREE.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);// 坐标系const axes = new THREE.AxesHelper(200);scene.add(axes);// 相机const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);camera.position.set(200, 200, 200);camera.lookAt(scene.position);// 渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);renderer.render(scene, camera);document.body.appendChild(renderer.domElement);// 动画渲染// 跟踪时间var clock = new THREE.Clock();function render() {const spt = clock.getDelta() * 1000;console.log('🚀 ~ file: animation.html:59 ~ render ~ spt:', spt)requestAnimationFrame(render);mesh.rotation.y += 0.01;renderer.render(scene, camera);}render();// 控制器const controls = new OrbitControls(camera, renderer.domElement);controls.addEventListener('change', () => {// 因为动画渲染了,所以这里可以省略// renderer.render(scene, camera);});</script> </html>
-
画布动态变化
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Three.js</title><style>body {margin: 0;overflow: hidden;}</style> </head><body></body><!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 --><script type="importmap">{"imports": {"three": "./js/three.module.js"}}</script><script type="module">import * as THREE from 'three';let width = window.innerWidth;let height = window.innerHeight;// 场景const scene = new THREE.Scene();// 几何体const geometry = new THREE.BoxGeometry(100, 100, 100);// 材质const material = new THREE.MeshBasicMaterial({color: 0x00ff00,transparent: true,opacity: 0.5});// 网格模型:物体const mesh = new THREE.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);// 坐标系const axes = new THREE.AxesHelper(200);scene.add(axes);// 相机const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);camera.position.set(200, 200, 200);camera.lookAt(scene.position);// 渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);renderer.render(scene, camera);document.body.appendChild(renderer.domElement);// 填满浏览器window.onresize = function () {width = window.innerWidth;height = window.innerHeight;renderer.setSize(width, height);camera.aspect = width / height;camera.updateProjectionMatrix();}</script> </html>
-
性能监控
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Three.js</title> </head><body></body><!-- 具体路径配置,你根据自己文件目录设置,我的是课件中源码形式 --><script type="importmap">{"imports": {"three": "./js/three.module.js","three/addons/": "../three.js/examples/jsm/"}}</script><script type="module">import * as THREE from 'three';import { OrbitControls } from 'three/addons/controls/OrbitControls.js';import Stats from 'three/addons/libs/stats.module.js';const width = 800const height = 500// 场景const scene = new THREE.Scene();// 几何体const geometry = new THREE.BoxGeometry(100, 100, 100);// 材质const material = new THREE.MeshBasicMaterial({color: 0x00ff00,transparent: true,opacity: 0.5});// 网格模型:物体const mesh = new THREE.Mesh(geometry, material);mesh.position.set(0, 0, 0);scene.add(mesh);for (let i = 0; i < 1000; i++) {// 几何体const geometry = new THREE.BoxGeometry(5, 5, 5);// 材质const material = new THREE.MeshBasicMaterial({color: 0x00ff00,transparent: true,opacity: 0.5});// 网格模型:物体const mesh = new THREE.Mesh(geometry, material);mesh.position.set((Math.random() - 0.5) * 200, (Math.random() - 0.5) * 200, (Math.random() - 0.5) * 200);scene.add(mesh);}// 坐标系const axes = new THREE.AxesHelper(200);scene.add(axes);// 相机const camera = new THREE.PerspectiveCamera(75, width/height, 0.1, 1000);camera.position.set(200, 200, 200);camera.lookAt(scene.position);// 渲染器const renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);renderer.render(scene, camera);document.body.appendChild(renderer.domElement);// 性能监控const stats = new Stats()document.body.appendChild(stats.domElement);// 动画渲染// 跟踪时间var clock = new THREE.Clock();function render() {stats.update()const spt = clock.getDelta() * 1000;requestAnimationFrame(render);mesh.rotation.y += 0.01;renderer.render(scene, camera);}render();</script> </html>