在光线追踪中避免自相交的方法

这篇具有很好参考价值的文章主要介绍了在光线追踪中避免自相交的方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这是我阅读 Ray Tracing Gem 的一篇笔记,《避免自相交的快速可靠的方法》是 Ray Tracing Gem 的第六章。这篇博客文章主要是为了记录和解释原文末尾给出的魔法一般的代码。

浮点误差

数学上给出了很多不同的求解光线与几何体相交的方法,它们都是等价的,但对于计算机而言并不一定。由于浮点数带来的浮点误差,不同方法带来的结果可能天差地别。

通常来讲,浮点数越大,其相对应的误差也就越大,这不难理解。IEEE754 单精度浮点数由 1 位符号位、8 位阶码以及 23 位尾数组成。浮点数的数量级主要是由阶码决定的,因为阶码的增减会以指数级别影响浮点数的大小。所以,如果一个浮点数的数量级越大,其阶码就越大,那么尾数的舍入的影响也就越大。

避免自相交的方法

图元 ID 排除法

可以使用ID显式地标记已经相交过的图元。

优点:

  • 不需要任何参数;
  • 满足缩放不变性;
  • 不会略过临近的几何体。

缺点:

  • 若交点落在两个图元的交线处,或者出射光纤与平面夹角很小,则仍然会导致自相交;
  • 无法处理重复或者重叠的几何体;
  • 仅可用于处理平面图元,因为非平面图元可能产生有效自相交。

限制光线区间

可以限制光线的有效相交区间。这样,当光线距离相交平面过近时,相交会被排除。

优点:

  • 几乎没有额外开销

缺点:

  • 非常不可靠,对于不同的场景会有不同的结果;
  • 可能导致小夹角下的自相交;
  • 可能导致略过相邻平面;

沿几何法向量进行自适应偏移

这是本文要介绍的重点,来自NVIDIA的魔法。

前面在浮点误差处提到过,交点的误差与光源到交点的距离有关,所以自适应偏移的距离也应当与这个距离有关。使用固定偏移量\(\epsilon\)显然无法自动适应距离的变化。因此,他们统计了光源到交点的距离与误差的关系:

在光线追踪中避免自相交的方法

容易发现,当相交点与光源的距离足够大时,距离和误差的数量级之间基本上呈现线性关系。当相交点与光源的距离过小时,则使用固定的距离进行偏移。Ray Tracing Gem给出的代码实现如下:

constexpr float origin() { return 1.0f / 32.0f; } // 距离界限
constexpr float float_scale() { return 1.0f / 65536.0f; } // 用于固定偏移
constexpr float int_scale() { return 256.0f; } // 数量级差距

float3 offset_ray(const float3 p, const float3 n)
{
    int3 of_i(int_scale() * n.x, int_scale() * n.y, int_scale() * n.z);

    float3 p_i(
        int_as_float(float_as_int(p.x) + ((p.x < 0) ? -of_i.x : of_i.x)),
        int_as_float(float_as_int(p.y) + ((p.y < 0) ? -of_i.y : of_i.y)),
        int_as_float(float_as_int(p.z) + ((p.z < 0) ? -of_i.z : of_i.z)));

    return float3(fabsf(p.x) < origin() ? p.x + float_scale() * n.x : p_i.x,
                  fabsf(p.y) < origin() ? p.y + float_scale() * n.y : p_i.y,
                  fabsf(p.z) < origin() ? p.z + float_scale() * n.z : p_i.z);
}

这里面用了魔法般的int_as_floatfloat_as_int,导致这段代码非常令人迷惑。int_as_float用于按照float的格式解析这段int数据,相当于*reinterpret_cast<float *>(&int_value)float_as_int同理。

为了理解上面的代码,我们对其进行一定的简化——我们将向量换成float,暂且去掉最后一部分,假设n是normalized vector,且为正数:

static constexpr float origin      = 1.0f / 32.0f;
static constexpr float float_scale = 1.0f / 65536.f;
static constexpr float int_scale   = 256.0f;

static int float_as_int(float value) {
    union {
        float f;
        int   i;
    } v;
    v.f = value;
    return v.i;
}

static float int_as_float(int value) {
    union {
        float f;
        int   i;
    } v;
    v.i = value;
    return v.f;
}

float offset_ray(const float point, const float normal) {
    int   off_i = static_cast<int>(int_scale * normal);
    float p_i   = int_as_float(float_as_int(point) + off_i);
    return p_i;
}

首先,normal是正则化后的向量,因此off_i一定不会超过256,也就是说off_i一定不超过0x0000 0100

然后,我们考虑第二行的float_as_int(point) + off_i。在IEEE754单精度浮点数中,低23位表示尾数。因此,float_as_int(point) + off_i等价于point的尾数加off_i(因为off_i只有低12位有效,其他部分全是0)。而浮点数的表示为\((-1)^S \times 2^{T - 127} \times M\),其中\(S\)表示符号位,\(T\)表示阶码,\(M\)表示尾数。因此,直接对尾数进行加减法会自动放大至\(2^{T-127}\)倍,也就是说会按照原来浮点数的数量级进行缩放。而上面的代码就是利用浮点数的这一特性来正确处理偏移量与距离的线性关系的。

至于最后一段代码:

return float3(fabsf(p.x) < origin() ? p.x + float_scale() * n.x : p_i.x,
              fabsf(p.y) < origin() ? p.y + float_scale() * n.y : p_i.y,
              fabsf(p.z) < origin() ? p.z + float_scale() * n.z : p_i.z);

则是特殊判断交点到光源的距离是否过近,如果过近则直接应用常数偏移,没有什么特殊的地方,不再详述。

存在的问题

这个方法仍然不能完美处理交点沿着几何法向量偏移后跳过三角面的情况,我们仍然能够构造特殊的情况使之失效。不过,在实际应用中,这个方法出现失效的情况相比前面几种方法要小得多。文章来源地址https://www.toymoban.com/news/detail-710460.html

到了这里,关于在光线追踪中避免自相交的方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 进阶篇丨链路追踪(Tracing)很简单:常见问题排查

    经过前面多篇内容的学习,想必大部分同学都已经熟练掌握分布式链路追踪的基础用法,比如回溯链路请求轨迹,定位耗时瓶颈点;配置核心接口黄金三指标告警,第一时间发现流量异常;大促前梳理应用上下游关键依赖,联系相关方协同备战等等。随着深入使用链路追踪技

    2024年02月02日
    浏览(41)
  • 【计算机图形学】OpenGL递归实现光线追踪

    计算机图形学课程设计:基于面向对象的光线跟踪算法设计与实现 目录 一、前言 二、项目实现与说明 1. 数据结构设计 1.1 光线 Ray 1.2 材质 Material 1.3 光照 Light 1.4 相机 Camera 1.5 球体Sphere 1.6 场景Scene 2. 算法实现 2.1 光线追踪算法原理与步骤 2.2 计算观察光线 2.3 光线与物体(球

    2024年02月08日
    浏览(32)
  • 使用篇丨链路追踪(Tracing)很简单:链路实时分析、监控与告警

    在前面文章里面,我们介绍了单链路的筛选与轨迹回溯,是从单次请求的视角来分析问题,类似查询某个快递订单的物流轨迹。但单次请求无法直观反映应用或接口整体服务状态,经常会由于网络抖动、宿主机 GC 等原因出现偶发性、不可控的随机离群点。当一个问题发生时,

    2024年02月04日
    浏览(30)
  • 2023知识追踪最新综述来自顶刊!!!——《Knowledge Tracing:A Survey》

    论文在2023年2月收录于ACM Computing Surveys(IF好像有14) https://dl.acm.org/doi/pdf/10.1145/3569576 后文里,我用技能一词 来 代替原文中的KC - knowledge component = 其他文献的知识点 教学是促进知识转移的重要活动 新冠促进 教育系统的数字化转型 目前的挑战 每个题目可能对应多个技能 技能

    2024年02月16日
    浏览(26)
  • 【GAMES101】作业5 简单光线追踪与代码流程理解

    在这部分的课程中,我们将专注于使用光线追踪来渲染图像。在光线追踪中最重要的操作之一就是找到光线与物体的交点。一旦找到光线与物体的交点,就可以执行着色并返回像素颜色。在这次作业中,我们需要实现两个部分:光线的生成和光线与三角的相交。本次代码框架

    2024年02月06日
    浏览(26)
  • LabVIEW开发光线追踪可视化分段反射器测试台

    LabVIEW开发光线追踪可视化分段反射器测试台 为了满足美国国家航空航天局(NASA)对未来望远镜的要求,新的红外空间天文台将在哈勃太空望远镜使用寿命结束后取代其。作为HST的继任者,詹姆斯韦伯太空望远镜(JWST),以前被称为下一代太空望远镜(NGST),需要一个更大

    2024年02月09日
    浏览(41)
  • games101-1 光栅化与光线追踪中的空间变换

    在学习了一些games101的课程之后,我还是有点困惑,尤其是对于课程讨论的空间的变换,幸而最*在做games101的第五次作业时,查询资料找到了scratchpixel这个网站,看了一些文章,终于把脑子里的一团乱麻组织起来了,也就有了这篇关于图形学的第一篇博客。 想要更好的理解这

    2024年02月06日
    浏览(28)
  • 发光太阳聚光器的蒙特卡洛光线追踪研究(Matlab代码实现)

     💥💥💞💞 欢迎来到本博客 ❤️❤️💥💥 🏆博主优势: 🌞🌞🌞 博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️ 座右铭: 行百里者,半于九十。 📋📋📋 本文目录如下: 🎁🎁🎁 目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码及文章 蒙特

    2024年02月10日
    浏览(37)
  • 分布式链路追踪——Dapper, a Large-Scale Distributed Systems Tracing Infrastructure

    要解决的问题 如何记录请求经过多个分布式服务的信息,以便分析问题所在? 如何保证这些信息得到完整的追踪? 如何尽可能不影响服务性能? 当用户请求到达前端A,将会发送rpc请求给中间层B、C;B可以立刻作出反应,但是C需要后端服务D、E的配合才能应答 一个简单有用

    2024年02月12日
    浏览(25)
  • 判断平面中两射线是否相交的高效方法

    最近在工作中遇到判断平面内两射线是否相交的问题。 对于这个问题的解决,常规的方法是将两条射线拓展为直线,计算直线的交点,而后判断交点是否在射线上。 这种方法,在思路上较为直观,也易于理解。然后,该方法在计算量上相对较大。对于少量射线间的交点计算

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包