Raymarching的核心是有符号距离函数(SDF),它输入空间中一点,输出该点到最近几何表面的带符号距离(正为外部、负为内部、零为表面),渲染器据此沿光线逐步推进并自适应步长,直至逼近表面。

Raymarching 的核心是距离函数,不是顶点和光栅化
Raymarching 渲染 Mandelbulb 不依赖 glDrawArrays 或网格数据,而是靠一个能返回「当前点到几何体表面最近距离」的函数——即有符号距离函数(SDF)。你写的不是模型,是数学定义;渲染器沿着光线一步步“试探”这个距离,直到足够接近(比如 dist )或超出最大步数。
常见错误是试图把 Mandelbulb 当成 OBJ 导入,或者在 fragment shader 里漏掉迭代终止条件,导致无限循环或黑屏。Mandelbulb 的 SDF 没有解析解,必须用迭代估算:
float mandelbulbDE(vec3 z) {
vec3 c = z;
float dr = 1.0;
float r = 0.0;
for (int i = 0; i < 8; i++) {
r = length(z);
if (r > 2.0) break;
// 球极映射 + 幂运算(p=8 是经典 Mandelbulb)
float theta = acos(z.z / r);
float phi = atan(z.y, z.x);
dr = pow(r, 7.0) * dr + 1.0; // 近似导数,用于步长缩放
float zr = pow(r, 8.0);
z = zr * vec3(sin(theta*8.0)*cos(phi*8.0),
sin(theta*8.0)*sin(phi*8.0),
cos(theta*8.0)) + c;
}
return 0.5 * log(r) * r / dr;
}
GLSL 中必须手动实现 raymarch 循环,不能依赖内置管线
OpenGL / WebGL 没有“自动 Raymarch”模式。你得在 fragment shader 的 main() 里手写 while 循环,从摄像机原点沿视线方向推进。GPU 对动态循环长度敏感,所以通常用固定上限(如 MAX_STEPS = 100)加提前退出。
容易踩的坑包括:
立即学习“C++免费学习笔记(深入)”;
-
stepSize直接用dist而不乘安全系数(建议0.9 * dist),导致跳过表面 - 没做
if (dist MAX_DIST)双重终止,显卡超时或着色器被系统 kill - 摄像机位置
ro和视线方向rd没归一化,造成畸变或缩放异常 - 未将屏幕坐标转为 NDC 后再构造
rd,结果整个画面偏移或拉伸
Mandelbulb 的光照和法线必须数值差分,不能用 normalMatrix
因为没有顶点法线缓存,表面法线只能通过距离函数在邻近点采样估算:normal = normalize(vec3( f(p + eps.xyy) - f(p - eps.xyy), f(p + eps.yxy) - f(p - eps.yxy), f(p + eps.yyx) - f(p - eps.yyx) ))。eps 太大会模糊细节,太小则浮点误差主导——1e-4 是较稳妥起点。
光照计算本身仍是 Phong 或 Blinn-Phong,但注意:
- 光源位置需与 Mandelbulb 坐标系对齐(例如统一以世界原点为中心)
- 硬阴影要用另一轮 raymarch 到光源路径上查障碍,否则全是环境光
- 反射/折射需递归调用 raymarch 主循环,但 WebGL 通常禁用递归,得展开成循环+栈模拟
性能瓶颈几乎全在 fragment shader 迭代次数,别碰 CPU 端预计算
Mandelbulb 的每次 DE 计算含多个 pow、acos、atan,GPU 上代价远高于普通纹理采样。降低 MAX_STEPS 到 60–80 是最直接优化,配合自适应步长(如 t += 0.5 * dist)比固定步进更稳。
真正拖慢的还有:
- 在
for循环内做分支(如if (r > 2.0))破坏 GPU warp 执行一致性 - 用
float高精度常量(如8.0写成8.0f更安全) - 未启用
#extension GL_OES_standard_derivatives : enable就调dFdx类函数 - 在 WebGL 1 中误用
double或高维向量(vec4用满才划算,别只用.xyz)
最易被忽略的是:Mandelbulb 的“空旷区域”其实可以跳过大量迭代,但标准 raymarch 循环不会主动跳——你得自己加包围盒(AABB)或距离场层次(distance field mip)来裁剪无效区域,否则 1080p 下每帧轻松破百万次 DE 调用。


















