当前位置: 首页 > news >正文

Three.js Shader实战:5步打造动态天空云层效果(附完整代码)

Three.js Shader实战:5步打造动态天空云层效果(附完整代码)

在三维场景开发中,天空效果往往是营造沉浸感的关键元素。传统的静态天空盒已经无法满足现代交互式应用的需求,而通过Shader实现的动态云层不仅能提升视觉真实度,还能根据场景需求实时变化。本文将带你从零开始,用Three.js的ShaderMaterial构建一个会"呼吸"的云层系统。

1. 环境准备与基础搭建

首先确保你的开发环境已经配置好Three.js基础库。我们推荐使用Vite作为构建工具,它能完美支持GLSL语法的代码高亮和模块化导入。

npm create vite@latest threejs-cloud --template vanilla cd threejs-cloud npm install three

创建一个基础的Three.js场景结构:

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 ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // 添加控制器 const controls = new OrbitControls(camera, renderer.domElement); camera.position.z = 5;

提示:在Shader开发阶段,OrbitControls可以帮助我们多角度观察效果,建议始终保留。

2. 理解云层生成的噪声原理

云层的自然感来源于噪声算法。我们将使用经典的Perlin噪声变体来生成有机的云朵形态。噪声函数的核心思想是通过多层(octaves)不同频率的简单噪声叠加,形成复杂的自然图案。

关键参数说明:

参数作用典型值
octaves噪声层数4-8
lacunarity频率倍增系数2.0
gain振幅衰减系数0.5
cloudScale整体云朵大小0.2-1.0

在GLSL中实现基础噪声函数:

float hash(float n) { return fract(sin(n)*43758.5453); } float noise(in vec3 x) { vec3 p = floor(x); vec3 f = fract(x); f = f*f*(3.0-2.0*f); float n = p.x + p.y*57.0 + 113.0*p.z; return mix( mix(mix(hash(n+0.0), hash(n+1.0),f.x), mix(hash(n+57.0), hash(n+58.0),f.x),f.y), mix(mix(hash(n+113.0), hash(n+114.0),f.x), mix(hash(n+170.0), hash(n+171.0),f.x),f.y), f.z); }

3. 构建ShaderMaterial核心结构

创建一个包裹整个场景的球体作为天空穹顶,并为其赋予ShaderMaterial:

const skyGeometry = new THREE.SphereGeometry(500, 60, 60); const skyMaterial = new THREE.ShaderMaterial({ vertexShader: ` varying vec3 vWorldPosition; void main() { vec4 worldPosition = modelMatrix * vec4(position, 1.0); vWorldPosition = worldPosition.xyz; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform vec3 skyColor; uniform vec3 cloudColor; uniform float time; varying vec3 vWorldPosition; // 这里插入之前定义的噪声函数 void main() { vec3 direction = normalize(vWorldPosition); // 云密度计算将在这里实现 gl_FragColor = vec4(mix(skyColor, cloudColor, cloudDensity), 1.0); } `, uniforms: { skyColor: { value: new THREE.Color(0x87CEEB) }, cloudColor: { value: new THREE.Color(0xFFFFFF) }, time: { value: 0 } }, side: THREE.BackSide }); const sky = new THREE.Mesh(skyGeometry, skyMaterial); scene.add(sky);

4. 实现动态云层效果

现在我们来完善片段着色器中的云密度计算。核心思路是将三维噪声应用于球面坐标,并添加时间变量实现动态效果。

float cloudDensity(in vec3 pos) { // 基础云形状 vec3 samplePos = pos * 0.2; samplePos.y += time * 0.05; // 云层缓慢飘动 float f = 0.0; f += 0.5000 * noise(samplePos); samplePos *= 2.02; f += 0.2500 * noise(samplePos); samplePos *= 2.03; f += 0.1250 * noise(samplePos); samplePos *= 2.01; f += 0.0625 * noise(samplePos); // 调整密度曲线 f = smoothstep(0.3, 0.8, f); // 添加高度衰减(地平线附近云更厚) float horizon = 1.0 - abs(pos.y); return f * horizon * 2.0; }

在动画循环中更新time uniform:

function animate() { requestAnimationFrame(animate); skyMaterial.uniforms.time.value += 0.01; renderer.render(scene, camera); } animate();

5. 高级效果优化

基础云层完成后,我们可以通过以下技巧提升真实感:

光照计算- 添加简单的光照模型让云有体积感:

vec3 sunDir = normalize(vec3(-1.0, 0.5, -1.0)); float sun = max(0.0, dot(sunDir, direction)); // 云边缘光效 vec3 finalColor = mix(skyColor, cloudColor, density); finalColor += 0.3 * vec3(1.0, 0.9, 0.7) * pow(sun, 8.0) * density;

多重云层- 叠加不同高度的云层增加层次感:

float highClouds = cloudDensity(pos * 1.5 + vec3(0.0, time*0.03, 0.0)) * 0.5; float lowClouds = cloudDensity(pos * 0.8 + vec3(0.0, time*0.02, 0.0)); float totalDensity = max(highClouds, lowClouds * 0.7);

性能优化技巧

  • 降低球体分段数(32x32通常足够)
  • 减少噪声octaves数量(移动端建议3-4层)
  • 使用低精度浮点(mediump)

完整代码示例已上传至GitHub仓库,包含所有进阶效果实现。在实际项目中,你可以根据需要调整云层移动速度、密度阈值和颜色渐变等参数,打造独特的天空氛围。

http://www.cnnetsun.cn/news/1301301.html

相关文章:

  • 2026年03月15日 星期日 22:44:23 +0800
  • TurboDiffusion避坑指南:Wan2.1模型部署与生成常见问题解答
  • Step3-VL-10B-Base助力AIGC内容创作:自动化图文内容生成效果展示
  • 第七章 数据库的设计
  • OFA图像描述模型快速部署指南:10分钟开箱即用
  • YOLO12边缘AI部署:Nano版370万参数在树莓派+USB加速棒运行
  • 华为ENSP实战:如何用静态路由实现双路径负载均衡(附详细配置截图)
  • KKManager:重构Illusion游戏Mod管理体验的开源解决方案
  • DBSCAN实战:用Python+sklearn搞定电商用户分群(附完整代码)
  • WSL2实战:5分钟搞定Ubuntu环境搭建,告别虚拟机卡顿
  • 避坑指南:如何在macOS上正确下载和配置Oracle JDK(避免The operation couldn’t be completed错误)
  • 【MCP采样接口高阶实战指南】:20年架构师亲授Sampling调用流5大避坑点与3倍性能优化法
  • 告别直播错过烦恼:抖音直播24小时自动录制的高效解决方案
  • 如何用mytv-android让老旧安卓电视实现1080P直播的技术焕新?
  • Sunshine系统净化指南:从残留风险到彻底清理的诊疗方案
  • 揭秘哔哩哔哩Linux客户端:如何突破平台限制实现无缝体验
  • StructBERT在论文查重预检中的应用:快速定位潜在重复内容
  • 多格式音频支持!Speech Seaco Paraformer语音识别兼容性测试
  • Phi-3-vision-128k-instruct实战落地:制造业BOM表截图→结构化数据提取
  • SMUDebugTool完全指南:从入门到精通的12个实用技巧
  • 机器学习——PLC基础
  • Qwen3-14B多场景覆盖:支持长文本摘要(8K上下文)、代码补全、SQL生成、数学推理
  • Windows多用户并发远程会话管理:RDP Wrapper开源工具跨版本适配指南
  • ccmusic-database音乐分类系统LaTeX论文写作模板
  • Linux下PHP7.4源码编译安装全攻略(附常见错误解决方案)
  • QMCDecode:破解QQ音乐加密格式的开源音频转换工具
  • PADS Logic元件库管理全攻略:从创建到保存,避免踩坑的实用技巧
  • 用AI股票分析师daily_stock_analysis做投资预研:快速获取任意股票代码的虚构分析
  • 突破直播录制瓶颈:5大核心技术构建抖音24小时无人值守系统
  • GPU选购指南:如何根据GFLOPS选择最适合深度学习任务的显卡