You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

光线步进中坐标钳制导致奇怪拉伸伪影问题排查

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 02:12:27