Three.js 新手教程5步搞定逼真天空云彩效果第一次接触Three.js时看到那些令人惊叹的3D场景总让人心生向往。特别是天空中飘动的云彩效果既能为场景增添真实感又不会过于复杂到让初学者望而却步。本文将带你从零开始用最简单的Shader代码实现一个动态的云彩天空效果。1. 环境准备与基础设置在开始编写云彩效果之前我们需要搭建一个基本的Three.js环境。这包括场景(Scene)、相机(Camera)和渲染器(Renderer)三大核心组件。import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js; // 初始化场景 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); // 添加轨道控制器方便查看 const controls new OrbitControls(camera, renderer.domElement); camera.position.set(0, 0, 5); controls.update();注意确保你的项目已经安装了three.js库可以通过npm或直接CDN引入。2. 创建天空球体云彩效果需要一个载体通常我们会使用一个巨大的球体作为天空穹顶// 创建天空球体 const skyGeometry new THREE.SphereGeometry(500, 60, 60); const skyMaterial new THREE.MeshBasicMaterial({ color: 0x87CEEB, side: THREE.BackSide }); const skySphere new THREE.Mesh(skyGeometry, skyMaterial); scene.add(skySphere);这里有几个关键点需要注意球体半径要足够大(如500单位)确保相机在移动时不会穿帮材质设置side: THREE.BackSide因为我们是从球体内部观察初始颜色设置为天蓝色(0x87CEEB)后续Shader会覆盖这个颜色3. 理解Shader基础Shader是GPU上运行的小程序分为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。对于云彩效果我们主要关注片元着色器。顶点着色器基础代码varying vec2 vUv; void main() { vUv uv; gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0); }片元着色器核心概念uniform从JavaScript传入的全局变量varying从顶点着色器传递到片元着色器的变量gl_FragColor最终输出的像素颜色4. 实现云彩Shader效果现在进入核心部分——编写云彩效果的片元着色器。我们将使用噪声函数模拟云的随机形态。const cloudShader { uniforms: { time: { value: 0 }, resolution: { value: new THREE.Vector2() } }, vertexShader: ..., // 使用上面的顶点着色器代码 fragmentShader: uniform float time; uniform vec2 resolution; // 噪声函数 float noise(vec3 p) { vec3 i floor(p); vec4 a dot(i, vec3(1., 57., 21.)) vec4(0., 57., 21., 78.); vec3 f cos((p-i)*acos(-1.))*(-.5).5; a mix(sin(cos(a)*a),sin(cos(1.a)*(1.a)), f.x); a.xy mix(a.xz, a.yw, f.y); return mix(a.x, a.y, f.z); } void main() { vec2 uv gl_FragCoord.xy / resolution.xy; vec3 pos vec3(uv*2.-1., time*0.1); // 多层噪声叠加 float cloud noise(pos*3.) * 0.5; cloud noise(pos*6.) * 0.25; cloud noise(pos*12.) * 0.125; // 云的颜色和透明度 vec3 color mix(vec3(1.), vec3(0.5,0.6,0.7), cloud); gl_FragColor vec4(color, 1.0); } };5. 整合与优化效果现在我们将Shader应用到天空球体上并添加动画效果// 更新材质 skyMaterial.dispose(); // 释放原有材质 const cloudMaterial new THREE.ShaderMaterial({ ...cloudShader, side: THREE.BackSide, transparent: true }); skySphere.material cloudMaterial; // 设置分辨率 cloudMaterial.uniforms.resolution.value.set( window.innerWidth, window.innerHeight ); // 动画循环 function animate() { requestAnimationFrame(animate); cloudMaterial.uniforms.time.value 0.01; renderer.render(scene, camera); } animate();效果优化技巧调整噪声函数的缩放因子可以改变云的密度和大小增加更多层的噪声可以丰富云的细节通过mix函数调整云的颜色渐变控制time变量的增量可以改变云移动的速度6. 进阶技巧与常见问题当基本效果实现后你可能还想进一步优化阳光效果增强// 在片元着色器中添加阳光效果 vec3 sunDir normalize(vec3(-1.0, 0.5, -1.0)); float sun pow(max(0.0, dot(normalize(pos), sunDir)), 8.0); color vec3(1.0, 0.8, 0.6) * sun * 0.3;常见问题解决云彩不显示检查球体是否足够大确认材质设置了side: THREE.BackSide确保Shader编译没有错误查看浏览器控制台性能优化降低球体的分段数(如从60降到32)简化Shader中的噪声计算考虑使用WebGL2以获得更好的性能移动端适配// 响应式调整 window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); cloudMaterial.uniforms.resolution.value.set( window.innerWidth, window.innerHeight ); });在实际项目中我发现云彩效果最关键的参数是噪声函数的缩放比例和时间增量。过大的缩放会让云显得破碎而过小则会使云层过于均匀。通常需要多次调试才能找到最适合场景的参数组合。
Three.js 新手教程:5步搞定逼真天空云彩效果
Three.js 新手教程5步搞定逼真天空云彩效果第一次接触Three.js时看到那些令人惊叹的3D场景总让人心生向往。特别是天空中飘动的云彩效果既能为场景增添真实感又不会过于复杂到让初学者望而却步。本文将带你从零开始用最简单的Shader代码实现一个动态的云彩天空效果。1. 环境准备与基础设置在开始编写云彩效果之前我们需要搭建一个基本的Three.js环境。这包括场景(Scene)、相机(Camera)和渲染器(Renderer)三大核心组件。import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js; // 初始化场景 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); // 添加轨道控制器方便查看 const controls new OrbitControls(camera, renderer.domElement); camera.position.set(0, 0, 5); controls.update();注意确保你的项目已经安装了three.js库可以通过npm或直接CDN引入。2. 创建天空球体云彩效果需要一个载体通常我们会使用一个巨大的球体作为天空穹顶// 创建天空球体 const skyGeometry new THREE.SphereGeometry(500, 60, 60); const skyMaterial new THREE.MeshBasicMaterial({ color: 0x87CEEB, side: THREE.BackSide }); const skySphere new THREE.Mesh(skyGeometry, skyMaterial); scene.add(skySphere);这里有几个关键点需要注意球体半径要足够大(如500单位)确保相机在移动时不会穿帮材质设置side: THREE.BackSide因为我们是从球体内部观察初始颜色设置为天蓝色(0x87CEEB)后续Shader会覆盖这个颜色3. 理解Shader基础Shader是GPU上运行的小程序分为顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)。对于云彩效果我们主要关注片元着色器。顶点着色器基础代码varying vec2 vUv; void main() { vUv uv; gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0); }片元着色器核心概念uniform从JavaScript传入的全局变量varying从顶点着色器传递到片元着色器的变量gl_FragColor最终输出的像素颜色4. 实现云彩Shader效果现在进入核心部分——编写云彩效果的片元着色器。我们将使用噪声函数模拟云的随机形态。const cloudShader { uniforms: { time: { value: 0 }, resolution: { value: new THREE.Vector2() } }, vertexShader: ..., // 使用上面的顶点着色器代码 fragmentShader: uniform float time; uniform vec2 resolution; // 噪声函数 float noise(vec3 p) { vec3 i floor(p); vec4 a dot(i, vec3(1., 57., 21.)) vec4(0., 57., 21., 78.); vec3 f cos((p-i)*acos(-1.))*(-.5).5; a mix(sin(cos(a)*a),sin(cos(1.a)*(1.a)), f.x); a.xy mix(a.xz, a.yw, f.y); return mix(a.x, a.y, f.z); } void main() { vec2 uv gl_FragCoord.xy / resolution.xy; vec3 pos vec3(uv*2.-1., time*0.1); // 多层噪声叠加 float cloud noise(pos*3.) * 0.5; cloud noise(pos*6.) * 0.25; cloud noise(pos*12.) * 0.125; // 云的颜色和透明度 vec3 color mix(vec3(1.), vec3(0.5,0.6,0.7), cloud); gl_FragColor vec4(color, 1.0); } };5. 整合与优化效果现在我们将Shader应用到天空球体上并添加动画效果// 更新材质 skyMaterial.dispose(); // 释放原有材质 const cloudMaterial new THREE.ShaderMaterial({ ...cloudShader, side: THREE.BackSide, transparent: true }); skySphere.material cloudMaterial; // 设置分辨率 cloudMaterial.uniforms.resolution.value.set( window.innerWidth, window.innerHeight ); // 动画循环 function animate() { requestAnimationFrame(animate); cloudMaterial.uniforms.time.value 0.01; renderer.render(scene, camera); } animate();效果优化技巧调整噪声函数的缩放因子可以改变云的密度和大小增加更多层的噪声可以丰富云的细节通过mix函数调整云的颜色渐变控制time变量的增量可以改变云移动的速度6. 进阶技巧与常见问题当基本效果实现后你可能还想进一步优化阳光效果增强// 在片元着色器中添加阳光效果 vec3 sunDir normalize(vec3(-1.0, 0.5, -1.0)); float sun pow(max(0.0, dot(normalize(pos), sunDir)), 8.0); color vec3(1.0, 0.8, 0.6) * sun * 0.3;常见问题解决云彩不显示检查球体是否足够大确认材质设置了side: THREE.BackSide确保Shader编译没有错误查看浏览器控制台性能优化降低球体的分段数(如从60降到32)简化Shader中的噪声计算考虑使用WebGL2以获得更好的性能移动端适配// 响应式调整 window.addEventListener(resize, () { camera.aspect window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); cloudMaterial.uniforms.resolution.value.set( window.innerWidth, window.innerHeight ); });在实际项目中我发现云彩效果最关键的参数是噪声函数的缩放比例和时间增量。过大的缩放会让云显得破碎而过小则会使云层过于均匀。通常需要多次调试才能找到最适合场景的参数组合。