水面天空效果

🎯 提示词

PROMPT
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. 多层波浪叠加

使用多层正弦波叠加模拟真实水面效果,通过调整频率、相位、速度参数实现自然波动。

JAVASCRIPT
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. 光线步进水面渲染

通过光线步进算法计算相机到水面的交点,实现水面深度效果。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
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. 大气散射天空着色

简化的大气散射模型实现天空渐变效果,支持太阳高光。

JAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
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. 菲涅尔反射

计算水面菲涅尔反射强度,实现真实的水面反射效果。

JAVASCRIPT
1
2
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 编辑整理,如需转载,请注明出处。