用于光线/网格相交的 DirectX 11 计算着色器

2023-12-29

我最近将使用 D3DXIntersect 查找光线/网格交点的 DirectX 9 应用程序转换为 DirectX 11。由于 D3DXIntersect 在 DX11 中不可用,我编写了自己的代码来查找交点,该代码仅循环网格中的所有三角形,并且测试它们,跟踪最接近原点的命中。这是在 CPU 端完成的,并且可以通过 GUI 进行拾取,但我的应用程序的另一部分是根据几个不同的视点从现有网格创建新网格,并且我需要检查每个三角形的视线在网格中多次。这变得相当慢。

使用 DX11 计算着色器来执行此操作是否有意义(即,在 CPU 上执行此操作会显着加快速度)吗?我在互联网上搜索但找不到现有的例子。

假设答案是肯定的,这是我正在考虑的方法:

  • 为网格中的每个三角形启动一个线程
  • 每个线程计算命中该三角形的距离,或者返回未命中的最大浮点数。每个线程在缓冲区中存储一个值。
  • 然后进行归约并返回最小值(非负)。

我希望我能够访问 DirectX 中的 CUDA Thrust 之类的东西,因为我认为编写这种减少的代码将是一件痛苦的事情。这就是我问的原因,所以我不会白做一堆工作!


这是完全可行的,这里有一些 HLSL 代码,可以执行该操作(并且还可以处理以相同距离击中 2 个三角形的情况)。

我假设您知道如何创建资源(结构化缓冲区)并将它们绑定到计算管道。

另外,我会考虑您的几何图形已索引。

第一步是收集通过测试的三角形。我们将使用追加缓冲区来仅推送通过测试的元素,而不是使用“Hit”标志。

首先创建 2 个结构化缓冲区(位置和三角形索引),并将模型数据复制到其中。

然后创建一个带有可追加无序视图的结构化缓冲区。

要执行命中检测,您可以使用以下计算代码:

struct rayHit
{
    uint triangleID;
    float distanceToTriangle;
};

cbuffer cbRaySettings : register(b0)
{
    float3 rayFrom;
    float3 rayDir;
    uint TriangleCount;
};

StructuredBuffer<float3> positionBuffer : register(t0);
StructuredBuffer<uint3> indexBuffer : register(t1);

AppendStructuredBuffer<rayHit> appendRayHitBuffer : register(u0);

void TestTriangle(float3 p1, float3 p2, float3 p3, out bool hit, out float d)
{
    //Perform ray/triangle intersection
    hit = false;
    d = 0.0f;
}

[numthreads(64,1,1)]
void CS_RayAppend(uint3 tid : SV_DispatchThreadID)
{
    if (tid.x >= TriangleCount)
        return;

    uint3 indices = indexBuffer[tid.x];
    float3 p1 = positionBuffer[indices.x];
    float3 p2 = positionBuffer[indices.y];
    float3 p3 = positionBuffer[indices.z];

    bool hit;
    float d;
    TestTriangle(p1,p2,p3,hit, d);

    if (hit)
    {
        rayHit hitData;
        hitData.triangleID = tid.x;
        hitData.distanceToTriangle = d;
        appendRayHitBuffer.Append(hitData);
    }
}

请注意,您需要为appendRayHitBuffer提供足够的大小(最坏的情况是三角形计数,例如:每个三角形都被射线击中)。

完成此操作后,缓冲区的开始部分将包含命中数据,并且无序视图计数器会计算通过测试的三角形的数量。

然后你需要创建一个参数缓冲区和一个小的字节地址缓冲区(大小为 16,因为我认为运行时不允许 12)

您还需要一个小型结构化缓冲区(一个元素就足够了),它将用于存储最小距离

Use 复制结构计数 https://msdn.microsoft.com/en-us/library/windows/desktop/ff476393(v=vs.85).aspx将 UnorderedView 计数器传递到这些缓冲区中(请注意,参数缓冲区的第二个和第三个元素需要均设置为 1,因为它们将成为使用调度的参数)。

使用 UINT_MAXVALUE 清除小型 StructuredBuffer 缓冲区,并使用参数缓冲区间接调度 https://msdn.microsoft.com/en-us/library/windows/desktop/ff476406(v=vs.85).aspx

我假设您不会有很多点击,因此对于下一部分,numthreads 将设置为 1,1,1(如果您想使用更大的组,您将需要运行另一个计算着色器来构建参数缓冲区)。

然后求最小距离:

StructuredBuffer<rayHit> rayHitbuffer : register(t0);
ByteAddressBuffer rayHitCount : register(t1);

RWStructuredBuffer<uint> rwMinBuffer : register(u0);

[numthreads(1,1,1)]
void CS_CalcMin(uint3 tid : SV_DispatchThreadID)
{
    uint count = rayHitCount.Load(0);
    if (tid.x >= count)
        return;

    rayHit hit = rayHitbuffer[tid.x];

    uint dummy;
    InterlockedMin(rwMinBuffer[0],asuint(hit.distanceToTriangle), dummy);   
} 

由于我们预计命中距离将大于零,因此我们可以在这种情况下使用 asuint 和 InterlockedMin。另外,由于我们使用 DispatchIndirect,因此这部分现在仅应用于之前通过测试的元素。

现在,您的单个元素缓冲区包含最小距离,但不包含索引。

最后一部分,我们需要最终提取位于最小命中距离的三角形索引。

您再次需要一个带有 UnorderedView 的新 StructuredBuffer 来存储最小索引。

使用与之前相同的调度参数(间接),并执行以下操作:

ByteAddressBuffer rayHitCount : register(t1);
StructuredBuffer<uint> MinDistanceBuffer : register(t2);
AppendStructuredBuffer<uint> appendMinHitIndexBuffer : register(u0);

[numthreads(1,1,1)]
void CS_AppendMin(uint3 tid : SV_DispatchThreadID)
{
    uint count = rayHitCount.Load(0);
    if (tid.x >= count)
        return;

    rayHit hit = rayHitbuffer[tid.x];

    uint minDist = MinDistanceBuffer[0];

    uint d = asuint(hit.distanceToTriangle);

    if (d == minDist)
    {
        appendMinHitIndexBuffer.Append(hit.triangleID);
    }
}

现在,appendMinHitIndexBuffer 包含最接近的三角形索引(如果有这种情况,则包含多个),您可以使用暂存资源将其复制回来并映射资源以供读取。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

用于光线/网格相交的 DirectX 11 计算着色器 的相关文章

随机推荐

  • 无模式 JDialog 不显示内容

    Java SE 6 我正在尝试创建一个弹出对话框 在我的程序执行一些耗时的工作时显示 请稍候 消息 为此 我选择使用无模式 JDialog 以便程序在 JDialog 可见时继续运行并正常工作 如果您使用模态 JDialog 则程序将暂停
  • Windows 上的 PHP 诅咒

    PHP 中是否有与 ncurses 相当的 Windows 版本 我创建了一个 CLI 脚本 希望以一种很好的方式显示各种统计信息 当前处理的记录 完成百分比等 而不向 cmd exe 窗口输出负载和大量文本 ncurses 扩展不适用于
  • 计算整数的持久数

    我正在尝试编写一个执行以下操作的代码 将整数的数字相乘并继续该过程给出 乘积序列总是得出令人惊讶的结果 一位数 例如 715 gt 35 gt 15 gt 5 88 gt 64 gt 24 gt 8 27 gt 14 gt 4 达到个位数所
  • 使用 map() 估计多个“lm”模型并在一个表中返回输出

    我需要在同一数据集上估计多个线性模型 并将回归结果全部放入一张表中 对于可重现的示例 这里是使用的简化mtcars formula 1 mpg disp formula 2 mpg log disp formula 3 mpg disp h
  • 我可以使用 System.Linq.Expressions 动态生成异步方法吗?

    我知道编译器无法将异步 lambda 表达式转换为表达式树 但是是否可以手动生成表达式树 var expr Expression Lambda
  • 模拟实体框架模型?

    是否可以模拟 EF 模型 以便我可以测试使用模型类的代码 而无需删除散布在我的项目中的 LINQ to Entities 代码 或者是否需要建立一个测试数据库来让模型命中 您可以将 LINQ 代码包装在数据访问对象 http en wiki
  • 如何在批处理脚本中生成日期前四天的日期? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想在批处理脚本中生成日期前四天的日期 我检查了可用的解决方案 但它们看起来很复杂 任何帮助将不胜感激 我强烈同意 JosefZ 日期
  • 从函数返回 JSX

    我有一个组件需要检查多个选项并根据这些选项返回 因此 我创建了一个外部函数 在我的组件返回语句中调用该函数来确定将返回的格式 render const policy this props let deployment policy Depl
  • 如何更改 silverlight 5 中只读文本框的背景颜色?

    我想更改只读文本框的颜色 可以将默认颜色更改为白色 颜色 和文本框为
  • 如何正确通知 MediaScanner 有关文件夹的信息,即使在 Nexus/Kitkat 设备上也是如此?

    背景 我正在制作一个应用程序 将一些图像从互联网下载到定义为的特定文件夹中 final String pathToPutFiles Environment getExternalStoragePublicDirectory Environm
  • 字符串不匹配时的 Ansible 条件

    我正在尝试编写一个 Ansible 剧本 仅在 Nginx 尚未存在且当前版本不存在时才编译 Nginx 然而它每次都会编译 这是不可取的 这就是我所拥有的 shell usr local nginx sbin nginx v 2 gt 1
  • mediaelement.js - 如何隐藏音频控件?

    我正在尝试将 Mediaelement js 实现到视频和音频网站中 视频运行良好 但我需要做的是隐藏音频元素 这样它根本不会显示在页面上 并且 MEJS 音频控件酒吧不可见 音频的播放将通过根据需要播放 暂停音频的函数来处理 我尝试更改
  • Spring Batch:动态块大小

    我有步骤读取多个资源 我需要根据每个文件的行数更改块大小 Spring Batch是否可以具有动态块大小 或者有其他方法可以做到这一点 你可以做Spring Batch 步骤分区 对步骤进行分区 以便该步骤具有多个线程 每个线程并行处理一块
  • TextInputLayout:未聚焦时提示标签的颜色不同

    我想做的事 当使用嵌入 TextInputLayout 中的 EditText 时 我想 当标签失焦并漂浮在 EditText 上方时 将标签的颜色设置为绿色 因为用户已经输入了一些值 当标签失焦并位于 EditText 内时 将标签的颜色
  • 如何在Scala中使用优先级队列?

    我正在尝试在 Scala 版本 2 10 中实现 A 搜索 但我遇到了障碍 我不知道如何使用 Scala 的优先级队列 我有一组正方形 表示为 Int Int s 我需要插入它们的优先级由Ints 在 Python 中 您只有一个键 值对列
  • Ruby on Rails 绘制 gem 图形? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • svn 非 LF 行结束问题 svn:ignore on dump load

    我正在尝试使用转储文件将运行 svn 版本 1 2 3 的系统上的存储库 历史记录完整 迁移到运行 1 7 1 的系统 由于原始存储库是一个早期版本 因此使用svnrdump直接不是一个选择 我用了svnadmin dump然后将 8 GB
  • 在 Google appengine 中禁用版本特定的网址

    Google App Engine 支持版本特定的请求路由 如文档所示 here https cloud google com appengine docs standard python how requests are routed例如
  • 如何使用 Python、Pandas 创建 Decile 和 Quintile 列以根据大小对另一个变量进行排名?

    我有一个数据框 其中一列包含Investment代表交易者投资的金额 我想在数据框中创建 2 个新列 一个给出十分位数排名 另一个给出五分位数排名Investment尺寸 我希望 1 代表投资额最大的十分位数 10 代表投资额最小的十分位数
  • 用于光线/网格相交的 DirectX 11 计算着色器

    我最近将使用 D3DXIntersect 查找光线 网格交点的 DirectX 9 应用程序转换为 DirectX 11 由于 D3DXIntersect 在 DX11 中不可用 我编写了自己的代码来查找交点 该代码仅循环网格中的所有三角形