光线步进中坐标钳制导致奇怪拉伸伪影问题排查
Raymarching网格渲染拉伸伪影问题解决
我尝试用Raymarching渲染球体网格,编写的SDF代码如下:
float sq_layer(vec3 p, vec3 bounding_box_min, vec3 bounding_box_max) { float cell_size = 4.0 / 16.0; vec3 p0 = clamp(p.xyz, bounding_box_min, bounding_box_max); p0 = mod(p0, cell_size) - cell_size * 0.5f; float d_pt = sphereSDF(vec3(p0.x, p0.y, p0.z), 0.05f) return d_pt; }
渲染结果出现拉伸伪影:
为排查问题,我将球体替换为盒子,修改后的代码如下:
float sq_layer(vec3 p, vec3 bounding_box_min, vec3 bounding_box_max) { vec3 cell_size = (bounding_box_max - bounding_box_min) / 4.0; vec3 p0 = clamp(p.xyz, bounding_box_min, bounding_box_max); p0 = mod(p0, cell_size) - cell_size * 0.5f; float d_pt = boxSDF(p0, cell_size * 0.35); return d_pt; }
仍出现类似拉伸伪影:
问题根源
错误出在先clamp再mod的顺序:clamp会把超出bounding box的点强行拉到盒子边界上,比如所有x坐标大于bounding_box_max.x的点,都会被设为bounding_box_max.x。对这个固定值做mod运算时,所有超出边界的点在对应维度的mod结果完全相同,最终导致渲染时出现拉伸变形。
修正方案
正确的处理顺序是:先将世界坐标转换到bounding box的局部空间,再做mod运算得到单元格内的位置,最后再限制SDF仅在bounding box内部生效。
球体网格修正代码
float sq_layer(vec3 p, vec3 bounding_box_min, vec3 bounding_box_max) { float cell_size = 4.0 / 16.0; // 转换到bounding box的局部空间(原点对齐盒子最小角) vec3 local_p = p - bounding_box_min; // 计算单元格内的相对位置,偏移到单元格中心 local_p = mod(local_p, cell_size) - cell_size * 0.5; // 球体SDF float d_sphere = sphereSDF(local_p, 0.05); // 确保仅在bounding box内部生效,外部返回极大距离 float d_bound = length(p - clamp(p, bounding_box_min, bounding_box_max)); return max(d_sphere, d_bound); }
盒子网格修正代码
float sq_layer(vec3 p, vec3 bounding_box_min, vec3 bounding_box_max) { vec3 cell_size = (bounding_box_max - bounding_box_min) / 4.0; // 转换到bounding box的局部空间 vec3 local_p = p - bounding_box_min; // 计算单元格内的相对位置,偏移到单元格中心 local_p = mod(local_p, cell_size) - cell_size * 0.5; // 盒子SDF float d_box = boxSDF(local_p, cell_size * 0.35); // 限制在bounding box内部 float d_bound = length(p - clamp(p, bounding_box_min, bounding_box_max)); return max(d_box, d_bound); }
补充说明
d_bound的作用是让bounding box外部的点返回一个极大的距离,避免Raymarching错误地在盒子外部渲染网格。- 如果你的bounding box不是轴对齐的,还需要额外做坐标旋转处理,但当前案例假设是轴对齐盒子。
内容的提问来源于stack exchange,提问作者Jaysmito Mukherjee
相关产品推荐
相关产品推荐

