水面天空效果
🎯 提示词
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
使用 Three.js 实现水面天空效果,具体要求:
**【核心特效】**
- 动态波浪效果,使用多层正弦波叠加
- 光线步进(Raymarching)渲染水面
- 大气散射天空着色
- 菲涅尔反射效果
**【场景与光照】**
- 蓝色天空渐变背景
- 太阳高光效果
- ACES色调映射
**【交互与控制】**
- OrbitControls 轨道控制
- 鼠标控制视角旋转
**【技术要求】**
- Three.js 版本
- 自定义 ShaderMaterial
- 全屏平面几何体
📖 效果拆解
| 层次 |
视觉效果 |
技术实现 |
| 基础 |
全屏水面+天空背景 |
PlaneGeometry + 自定义着色器 |
| 核心特效 |
动态波浪模拟 |
多层正弦波叠加(wavedx函数) |
| 光线追踪 |
水面光线步进 |
raymarchwater 函数迭代318次 |
| 大气效果 |
天空渐变+太阳 |
extra_cheap_atmosphere + sun函数 |
| 反射 |
菲涅尔水面反射 |
fresnel 反射计算 |
🔧 核心技术点
1. 多层波浪叠加
使用多层正弦波叠加模拟真实水面效果,通过调整频率、相位、速度参数实现自然波动。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
vec2 wavedx(vec2 position, vec2 direction, float speed, float frequency, float timeshift) {
float x = dot(direction, position) * frequency + timeshift * speed;
float wave = exp(sin(x) - 1.0);
float dx = wave * cos(x);
return vec2(wave, -dx);
}
float getwaves(vec2 position, int iterations){
float iter = 0.0;
float phase = 6.0;
float speed = 2.0;
float weight = 1.0;
for(int i=0;i<iterations;i++){
vec2 p = vec2(sin(iter), cos(iter));
vec2 res = wavedx(position, p, speed, phase, Time);
position += p * res.y * weight * DRAG_MULT;
w += res.x * weight;
iter += 12.0;
weight = mix(weight, 0.0, 0.2);
phase *= 1.18;
speed *= 1.07;
}
return w / ws;
}
2. 光线步进水面渲染
通过光线步进算法计算相机到水面的交点,实现水面深度效果。
float raymarchwater(vec3 camera, vec3 start, vec3 end, float depth){
vec3 pos = start;
float h = 0.0;
vec3 dir = normalize(end - start);
for(int i=0;i<318;i++){
h = getwaves(pos.xz * 0.1, ITERATIONS_RAYMARCH) * depth - depth;
if(h + 0.01 > pos.y) {
return distance(pos, camera);
}
pos += dir * (pos.y - h);
}
return -1.0;
}
3. 大气散射天空着色
简化的大气散射模型实现天空渐变效果,支持太阳高光。
vec3 extra_cheap_atmosphere(vec3 raydir, vec3 sundir){
sundir.y = max(sundir.y, -0.07);
float special_trick = 1.0 / (raydir.y * 1.0 + 0.1);
float special_trick2 = 1.0 / (sundir.y * 11.0 + 1.0);
float raysundt = pow(abs(dot(sundir, raydir)), 2.0);
float sundt = pow(max(0.0, dot(sundir, raydir)), 8.0);
float mymie = sundt * special_trick * 0.2;
vec3 suncolor = mix(vec3(1.0), max(vec3(0.0), vec3(1.0) - vec3(5.5, 13.0, 22.4) / 22.4), special_trick2);
vec3 bluesky= vec3(5.5, 13.0, 22.4) / 22.4 * suncolor;
return bluesky2 * (1.0 + 1.0 * pow(1.0 - raydir.y, 3.0)) + mymie * suncolor;
}
4. 菲涅尔反射
计算水面菲涅尔反射强度,实现真实的水面反射效果。
float fresnel = (0.04 + (1.0-0.04)*(pow(1.0 - max(0.0, dot(-N, ray)), 5.0)));
vec3 C = fresnel * getatm(R) * 2.0 + fresnel * sun(R) + vec3(0.0293, 0.0698, 0.1717);
💡 调试与优化
| 问题类型 |
表现形式 |
解决方案 |
| 性能问题 |
帧率低,水面闪烁 |
减少ITERATIONS_RAYMARCH和ITERATIONS_NORMAL迭代次数 |
| 天空与水面过渡生硬 |
地平线处接缝明显 |
调整intersectPlane的depth参数 |
| 反射效果不明显 |
水面颜色过深 |
增加fresnel系数或调整天空颜色强度 |
🚀 扩展思路
| 变体效果 |
核心改动 |
难度 |
| 夜间星空效果 |
修改大气散射参数,添加星星采样 |
⭐⭐ |
| 不同水域风格 |
修改波浪参数(相位/速度/频率) |
⭐ |
| 添加云层 |
在天空着色器中添加云朵噪声 |
⭐⭐ |
| 水面倒影物体 |
添加水下物体raymarch或简单平面反射 |
⭐⭐⭐ |
©️ 版权声明
本文档由 ThreeLab 编辑整理,如需转载,请注明出处。
💬 评论区
评论功能即将上线,敬请期待!