- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我目前正在研究 Path Tracer,我正在寻找优化光线-三角形相交的方法。我目前使用 Moller-Trumbore 算法的以下 sse4 实现:
bool Ray::intersectTriangle(const Triangle tri, float& result) const
{
__m128 q = _mm_cross_ps(m_directionM128, tri.e2);
float a = _mm_dp_ps(tri.e1, q, dotProductMask).m128_f32[0];
if (a > negativeEpsilon && a < positiveEpsilon)
return false;
float f = 1.0f / a;
__m128 s = _mm_sub_ps(m_originM128, tri.v0);
float u = f * _mm_dp_ps(s, q, dotProductMask).m128_f32[0];
if (u < 0.0f)
return false;
__m128 r = _mm_cross_ps(s, tri.e1);
float v = f * _mm_dp_ps(m_directionM128, r, dotProductMask).m128_f32[0];
if (v < 0.0f || (u + v > 1.0f))
return false;
float t = f * _mm_dp_ps(tri.e2, r, dotProductMask).m128_f32[0];
if (t < 0.0f || t > m_length)
return false;
result = t;
return true;
}
(如果有人看到优化它的方法,请告诉我)。然后我读到可以使用 SIMD 指令同时对 4 个三角形执行相交测试。但是怎么做呢?我看不出如何以比我的顺序方式更有效的方式来实现它。
Here与我的渲染器有关的小代码。
最佳答案
AVX512 最多可以做 16 个三角形,AVX2 最多可以做 8 个,SSE 最多可以做 4 个。不过,诀窍在于确保数据采用 SOA 格式。另一个技巧是在任何时候都不要“返回错误”(只需在最后过滤结果)。所以你的三角形输入看起来像:
struct Tri {
__m256 e1[3];
__m256 e2[3];
__m256 v0[3];
};
你的射线看起来像:
struct Ray {
__m256 dir[3];
__m256 pos[3];
};
然后数学代码开始看起来更漂亮(请注意 _mm_dp_ps 不是有史以来最快的函数 - 还要注意访问 __m128/__m256/__m512 类型的内部实现是不可移植的)。
#define or8f _mm256_or_ps
#define mul _mm256_mul_ps
#define fmsub _mm256_fmsub_ps
#define fmadd _mm256_fmadd_ps
void cross(__m256 result[3], const __m256 a[3], const __m256 b[3])
{
result[0] = fmsub(a[1], b[2], mul(b[1], a[2]));
result[1] = fmsub(a[2], b[0], mul(b[2], a[0]));
result[2] = fmsub(a[0], b[1], mul(b[0], a[1]));
}
__m256 dot(const __m256 a[3], const __m256 b[3])
{
return fmadd(a[2], b[2], fmadd(a[1], b[1], mul(a[0], b[0])));
}
方法中基本上有 4 个条件:
if (a > negativeEpsilon && a < positiveEpsilon)
if (u < 0.0f)
if (v < 0.0f || (u + v > 1.0f))
if (t < 0.0f || t > m_length)
如果这些条件中的任何一个为真,则不存在交集。这基本上需要一点重构(伪代码)
__m256 condition0 = (a > negativeEpsilon && a < positiveEpsilon);
__m256 condition1 = (u < 0.0f)
__m256 condition2 = (v < 0.0f || (u + v > 1.0f))
__m256 condition3 = (t < 0.0f || t > m_length)
// combine all conditions that can cause failure.
__m256 failed = or8f(or8f(condition0, condition1), or8f(condition2, condition3));
所以最后,如果发生交集,结果将是 t。如果交集没有发生,那么我们需要将结果设置为错误的东西(在这种情况下负数可能是一个不错的选择!)
// if(failed) return -1;
// else return t;
return _mm256_blendv_ps(t, _mm256_set1_ps(-1.0f), failed);
虽然最终代码可能看起来有点糟糕,但它最终会比您的方法快得多。细节决定成败......
这种方法的一个主要问题是,您可以选择是针对 8 个三角形测试 1 条射线,还是针对 1 个三角形测试 8 条射线。对于主要射线,这可能不是什么大问题。对于习惯于向不同方向散射的二次射线),事情会开始变得有点烦人。大多数光线追踪代码很有可能最终会遵循以下模式:测试 -> 排序 -> 批处理 -> 测试 -> 排序 -> 批处理
如果您不遵循该模式,您几乎永远无法充分利用 vector 单元。 (谢天谢地,AVX512 中的压缩/扩展指令对此有很大帮助!)
关于c++ - 快速 SSE 射线 - 4 个三角形相交,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45599766/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!