3D 蘑菇 SDF 渲染

🎯 提示词

PROMPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
使用 Three.js 实现【3D 蘑菇 SDF 渲染】,具体要求:

【核心特效】
- SDF (Signed Distance Field) 3D 建模
- 射线步进 (Ray Marching) 渲染
- 动态弯曲动画效果

【场景与光照】
- 程序化生成蘑菇形状
- 条纹装饰效果
- 地面平面

【交互与控制】
- OrbitControls 视角控制
- 鼠标位置响应

【技术要求】
- Three.js 版本
- 自定义 ShaderMaterial
- SDF 距离场函数

📖 效果拆解

层次 视觉效果 技术实现
基础 盒子几何体作为渲染载体 BoxGeometry
核心特效 SDF 蘑菇建模 带切口球体 + 圆锥体
增强细节 条纹装饰 嵌套空心球
动画效果 弯曲变形 时间驱动的旋转矩阵

🔧 核心技术点

1. SDF 带切口球体

定义带切口的球体距离场:

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
// 带切口的球体距离场函数
vec4 sdCutSphere(vec3 p, float r, float h, vec3 color) {
    float w = sqrt(r*r - h*h);
    vec2 q = vec2(length(p.xz), p.y);
    
    float s = max((h - r)*q.x*q.x + w*w*(h + r - 2.0*q.y), h*q.x - w*q.y);
    float d = (s < 0.0) ? length(q) - r :
              (q.x < w) ? h - q.y :
              length(q - vec2(w, h));
              
    return vec4(d, color);
}

2. 带帽圆锥体

定义带帽圆锥体距离场:

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 带帽圆锥体距离场函数
vec4 sdCappedCone(vec3 p, vec3 a, vec3 b, float ra, float rb, vec3 color) {
    float rba = rb - ra;
    float baba = dot(b - a, b - a);
    float papa = dot(p - a, p - a);
    float paba = dot(p - a, b - a) / baba;
    float x = sqrt(papa - paba*paba*baba);
    
    float cax = max(0.0, x - ((paba < 0.5) ? ra : rb));
    float cay = abs(paba - 0.5) - 0.5;
    float k = rba*rba + baba;
    float f = clamp((rba*(x - ra) + paba*baba)/k, 0.0, 1.0);
    float cbx = x - ra - f*rba;
    float cby = paba - f;
    
    float s = (cbx < 0.0 && cay < 0.0) ? -1.0 : 1.0;
    return vec4(s*sqrt(min(cax*cax + cay*cay*baba,
                           cbx*cbx + cby*cby*baba)), color);
}

3. 射线步进渲染

实现完整的射线步进算法:

GLSL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void main() {
    vec3 ro = vec3(0.0, 0.0, -8.0);       // 射线起点
    vec3 rd = normalize(vec3(vUv - 0.5, 1.0));  // 射线方向
    
    // 随时间旋转射线
    ro.xz *= rot2D(-Time);
    rd.xz *= rot2D(-Time);
    
    ro.y -= 4.0;
    rd.y += 0.5;
    
    float t = 0.0;
    vec4 color = vec4(0.0);
    
    // 射线步进循环
    for(int i = 0; i < 80; i++) {
        vec3 p = ro + rd * t;
        vec4 d = map(p) / 1.8;
        
        t += d.x;
        
        if(t > 100.0 || d.x < 0.001) {
            break;
        }
        
        color = vec4(t * d.yzw * 0.13, 1.0);
    }
    
    gl_FragColor = color;
}

💡 调试与优化

问题类型 表现形式 解决方案
渲染异常 形状不显示 检查 SDF 函数符号和距离计算
性能问题 帧率低 减少步进次数或使用 LOD
边缘锯齿 轮廓粗糙 增加步进精度或使用抗锯齿
弯曲异常 变形不自然 调整弯曲系数和时间参数

🚀 扩展思路

变体效果 核心改动 难度
多种蘑菇 添加不同形状的 SDF ⭐⭐
纹理映射 添加纹理坐标到 SDF ⭐⭐⭐
光照效果 添加法线计算和光照 ⭐⭐⭐
场景组合 添加多个蘑菇和环境 ⭐⭐⭐

本文档由 ThreeLab 编辑整理,如需转载,请注明出处。