高级技术与特效 Three.js 高级技术与特效 后期处理 (Post-processing) 后期处理是在场景渲染完成后,对渲染结果进行额外的处理,以添加各种视觉效果,例如景深、Bloom、颜色校正等。 原理: 后期处理通过渲染到纹理 (Render Targets) 实现。首先将场景渲染到纹理,然后将该纹理作为输入,应用各种后期处理特效,最后将处理后的纹理显示到屏幕上。 代码示例: 代码解释: 引入必要的模块: 、 、 。 创建 实例,传入渲染器。 添加 ,用于渲染原始场景。 添加 ,实现 Bloom 特效。可以调整 、 、 等参数来控制 Bloom 的效果。 在渲染循环中使用 代替 。 流程图: 阴影 (Shadows) 阴影可以增强场景的真实感和立体感。Three.
后期处理是在场景渲染完成后,对渲染结果进行额外的处理,以添加各种视觉效果,例如景深、Bloom、颜色校正等。
原理:
后期处理通过渲染到纹理 (Render Targets) 实现。首先将场景渲染到纹理,然后将该纹理作为输入,应用各种后期处理特效,最后将处理后的纹理显示到屏幕上。
代码示例:
import * as THREE from 'three'; import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'; import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'; import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'; // 1. 创建场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 添加一些几何体到场景 const geometry = new THREE.SphereGeometry(1, 32, 32); const material = new THREE.MeshBasicMaterial({ color: 0xffff00 }); const sphere = new THREE.Mesh(geometry, material); scene.add(sphere); camera.position.z = 5; // 2. 创建 EffectComposer const composer = new EffectComposer(renderer); // 3. 添加 RenderPass const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); // 4. 添加 UnrealBloomPass (Bloom特效) const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85); bloomPass.threshold = 0.1; bloomPass.strength = 0.8; bloomPass.radius = 0.2; composer.addPass(bloomPass); // 5. 渲染循环 function animate() { requestAnimationFrame(animate); sphere.rotation.x += 0.01; sphere.rotation.y += 0.01; composer.render(); // 使用 composer 渲染 //renderer.render(scene, camera); // 注释掉默认渲染 } animate();
代码解释:
引入必要的模块:EffectComposer、RenderPass、UnrealBloomPass。
创建 EffectComposer 实例,传入渲染器。
添加 RenderPass,用于渲染原始场景。
添加 UnrealBloomPass,实现 Bloom 特效。可以调整 threshold、strength、radius 等参数来控制 Bloom 的效果。
在渲染循环中使用 composer.render() 代替 renderer.render()。
流程图:
阴影可以增强场景的真实感和立体感。Three.js 支持多种阴影类型。
代码示例:
import * as THREE from 'three'; // 1. 创建场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({antialias: true}); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 启用阴影支持 renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 可选的阴影类型 // 2. 创建物体 const planeGeometry = new THREE.PlaneGeometry(10, 10); const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x808080, side: THREE.DoubleSide }); const plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.rotation.x = -Math.PI / 2; plane.receiveShadow = true; // 允许接收阴影 scene.add(plane); const sphereGeometry = new THREE.SphereGeometry(1, 32, 32); const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 }); const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); sphere.castShadow = true; // 允许投射阴影 sphere.position.y = 1; scene.add(sphere); // 3. 创建光源 const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(5, 5, 5); light.castShadow = true; // 允许投射阴影 light.shadow.mapSize.width = 1024; // 阴影贴图大小 light.shadow.mapSize.height = 1024; light.shadow.camera.near = 0.5; light.shadow.camera.far = 500; scene.add(light); // 添加环境光 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); camera.position.z = 5; // 4. 渲染循环 function animate() { requestAnimationFrame(animate); sphere.rotation.x += 0.01; sphere.rotation.y += 0.01; renderer.render(scene, camera); } animate();
代码解释:
启用阴影支持:renderer.shadowMap.enabled = true;,并选择阴影类型。
物体:设置 castShadow = true 允许物体投射阴影,receiveShadow = true 允许物体接收阴影。
光源:设置 light.castShadow = true 允许光源投射阴影,并配置阴影贴图的大小和相机参数,以获得更好的阴影效果。
材质:使用 MeshStandardMaterial 或 MeshPhysicalMaterial 等支持阴影的材质。
注意事项:
阴影的性能开销较大,应根据需要调整阴影贴图的大小。
使用 DirectionalLight 或 SpotLight 可以投射阴影。
AmbientLight 不会投射阴影,但可以照亮场景。
自定义着色器允许你完全控制物体的渲染方式,实现各种高级视觉效果。
原理:
Three.js 使用 WebGL 着色器语言 (GLSL) 编写着色器。你需要编写顶点着色器 (Vertex Shader) 和片元着色器 (Fragment Shader),分别控制顶点的位置和像素的颜色。
代码示例:
import * as THREE from 'three'; // 1. 创建场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 2. 定义着色器代码 const vertexShader = ` varying vec3 vNormal; void main() { vNormal = normal; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `; const fragmentShader = ` varying vec3 vNormal; void main() { vec3 normal = normalize(vNormal); float intensity = dot(normal, vec3(0.5, 0.7, 1.0)); vec3 color = vec3(0.8, 0.0, 0.0) * intensity; gl_FragColor = vec4(color, 1.0); } `; // 3. 创建材质 const material = new THREE.ShaderMaterial({ vertexShader: vertexShader, fragmentShader: fragmentShader }); // 4. 创建物体 const geometry = new THREE.SphereGeometry(1, 32, 32); const sphere = new THREE.Mesh(geometry, material); scene.add(sphere); camera.position.z = 5; // 5. 渲染循环 function animate() { requestAnimationFrame(animate); sphere.rotation.x += 0.01; sphere.rotation.y += 0.01; renderer.render(scene, camera); } animate();
代码解释:
定义顶点着色器和片元着色器的 GLSL 代码。
创建 THREE.ShaderMaterial 实例,传入着色器代码。
创建物体,并使用自定义材质。
GLSL 代码解释:
顶点着色器:
varying vec3 vNormal;:声明一个 varying 变量,用于将法线传递给片元着色器。
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);:计算顶点在裁剪空间中的位置。
片元着色器:
varying vec3 vNormal;:接收从顶点着色器传递过来的法线。
vec3 normal = normalize(vNormal);:归一化法线。
float intensity = dot(normal, vec3(0.5, 0.7, 1.0));:计算光照强度,使用法线和光照方向的点积。
vec3 color = vec3(0.8, 0.0, 0.0) * intensity;:根据光照强度计算颜色。
gl_FragColor = vec4(color, 1.0);:设置像素的颜色。
用途:
自定义着色器可以用于实现各种特殊效果,例如:
卡通渲染 (Toon Shading)
水面效果
火焰效果
程序化纹理
粒子系统用于模拟大量的微小物体,例如烟雾、火焰、雪花等。
代码示例:
import * as THREE from 'three'; // 1. 创建场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 2. 创建粒子几何体 const particleCount = 1000; const positions = new Float32Array(particleCount * 3); const colors = new Float32Array(particleCount * 3); for (let i = 0; i < particleCount; i++) { positions[i * 3] = (Math.random() - 0.5) * 10; positions[i * 3 + 1] = (Math.random() - 0.5) * 10; positions[i * 3 + 2] = (Math.random() - 0.5) * 10; colors[i * 3] = Math.random(); colors[i * 3 + 1] = Math.random(); colors[i * 3 + 2] = Math.random(); } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); // 3. 创建粒子材质 const material = new THREE.PointsMaterial({ size: 0.1, vertexColors: true, transparent: true, opacity: 0.8 }); // 4. 创建粒子系统 const particles = new THREE.Points(geometry, material); scene.add(particles); camera.position.z = 5; // 5. 渲染循环 function animate() { requestAnimationFrame(animate); particles.rotation.x += 0.001; particles.rotation.y += 0.002; renderer.render(scene, camera); } animate();
代码解释:
创建 THREE.BufferGeometry,用于存储粒子的位置和颜色等属性。
创建 THREE.PointsMaterial,用于定义粒子的外观。
创建 THREE.Points 实例,表示粒子系统。
关键概念:
BufferGeometry: 高效地存储大量顶点数据。
PointsMaterial: 用于渲染粒子,可以设置粒子的大小、颜色、透明度等属性。
Points: 用于将几何体渲染为点。
高级用法:
使用纹理作为粒子贴图。
使用自定义着色器控制粒子的行为。
使用力场 (Force Fields) 影响粒子的运动。
Three.js 支持加载各种 3D 模型格式,例如 glTF, FBX, OBJ 等,并播放模型动画。
代码示例 (glTF):
import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; // 1. 创建场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 2. 创建 GLTFLoader const loader = new GLTFLoader(); // 3. 加载模型 loader.load( 'path/to/your/model.gltf', function (gltf) { scene.add(gltf.scene); // 获取动画剪辑 const animations = gltf.animations; // 创建动画混合器 (AnimationMixer) const mixer = new THREE.AnimationMixer(gltf.scene); // 创建动画动作 (AnimationAction) const clip = THREE.AnimationClip.findByName(animations, 'ArmatureAction'); // 替换为你的动画名称 const action = mixer.clipAction(clip); // 播放动画 action.play(); // 将 mixer 保存到全局变量,以便在渲染循环中使用 window.mixer = mixer; }, function (xhr) { console.log((xhr.loaded / xhr.total * 100) + '% loaded'); }, function (error) { console.log('An error happened'); } ); camera.position.z = 5; // 4. 渲染循环 function animate() { requestAnimationFrame(animate); // 更新动画混合器 if (window.mixer) { window.mixer.update(0.01); // delta time } renderer.render(scene, camera); } animate();
代码解释:
引入 GLTFLoader。
创建 GLTFLoader 实例。
使用 loader.load() 加载模型,并在回调函数中将模型添加到场景中。
创建 THREE.AnimationMixer,用于控制动画的播放。
创建 THREE.AnimationAction,指定要播放的动画剪辑。
在渲染循环中使用 mixer.update() 更新动画。
其他模型格式:
可以使用 FBXLoader、OBJLoader 等加载其他模型格式。
本文介绍了 Three.js 中的几种高级技术和特效,包括后期处理、阴影、自定义着色器、粒子系统和模型加载与动画。掌握这些技术可以让你创建更具吸引力和互动性的 3D 应用程序。通过实践这些代码示例,你将能够更深入地理解这些概念,并将其应用到你自己的项目中。