Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ glsl(GPU)矩阵/向量计算产生与CPU不同的结果_C++_Opengl_Glsl_Matrix Multiplication - Fatal编程技术网

C++ glsl(GPU)矩阵/向量计算产生与CPU不同的结果

C++ glsl(GPU)矩阵/向量计算产生与CPU不同的结果,c++,opengl,glsl,matrix-multiplication,C++,Opengl,Glsl,Matrix Multiplication,我找不到任何关于不同行为的文档,所以这只是一个理智的检查,以确保我没有做错任何事情 我在GLSL中创建了一些辅助函数,以将float/vec/mat比较输出为颜色: 注意:非常确定这里没有任何错误,只是包括它,以便您确切地知道我在做什么 需要注意的一点是,CPU上的view_mat_t*proj_mat_t与GPU上的proj_mat*view_mat匹配。有人知道为什么吗?我已经在CPU上对矩阵进行了测试,并将它们与在线矩阵乘法器的结果进行了比较,它们似乎是正确的 我知道GPU在vert sh

我找不到任何关于不同行为的文档,所以这只是一个理智的检查,以确保我没有做错任何事情

我在GLSL中创建了一些辅助函数,以将float/vec/mat比较输出为颜色:

注意:非常确定这里没有任何错误,只是包括它,以便您确切地知道我在做什么

需要注意的一点是,CPU上的view_mat_t*proj_mat_t与GPU上的proj_mat*view_mat匹配。有人知道为什么吗?我已经在CPU上对矩阵进行了测试,并将它们与在线矩阵乘法器的结果进行了比较,它们似乎是正确的

我知道GPU在vert shader和frag shader之间做了一些事情,我想是这样的,将gl_位置除以gl_位置?。。。在这里,是否有其他我没有考虑到的东西,仅在vert着色器中?有什么东西在某种程度上自动换位了吗?

< P>您可能希望考虑CPU侧矩阵实例化和计算。这将有助于减少可能的错误源

其次,GPU和CPU不执行相同的计算。IEEE 754浮点数计算标准对如何执行这些计算以及计算的准确度有着相对严格的标准,但是:

根据所使用的特定操作/功能,数字在最低有效位和更高有效位上仍然可能出现差异 一些GPU供应商选择不确保严格遵守IEEE,因为Nvidia过去一直认为速度优先于严格遵守IEEE 最后我要指出的是,CPU端的计算为舍入误差留下了很大的空间,这些误差可能会累加起来。对于这类问题,通常的建议是在代码中包含对少量偏差的容忍度。通常,检查两个浮点数是否“相等”的代码假定absx-y<0.000001表示x和y基本相等。当然,具体的数字必须根据您的个人用途进行校准


当然,您需要检查以确保所有矩阵/制服都正确传递。

好。我找到了答案。单个着色器中的矩阵操作没有什么特别之处。但是,有几件事你应该注意:

:1:OpenGL GLSL使用列主矩阵。因此,要构造在数学上下文中可视表示的矩阵,如下所示:

 1  2  3  4
 5  6  7  8
 9 10 11 12
13 14 15 16
您可以从GLSL内部使用:

mat4 m = mat4(
  vec4( 1, 5, 9,13),
  vec4( 2, 6,10,14),
  vec4( 3, 7,11,15),
  vec4( 4, 8,12,16),
);
:2:如果改为在CPU上使用行主矩阵,请确保在将矩阵上传到着色器时将转置标志设置为true,如果使用列主矩阵,请确保将其设置为false

只要你意识到这两件事,你就应该做好准备

我的特殊问题是,在CPU实现中,我正处于从行专业转换为Calor专业的过程中,并没有确保在所有的CPU矩阵操作中都考虑到实现。

具体来说,这里是我现在正确的mat4乘法实现,假设col主矩阵:

同样,上面的实现是针对列主矩阵的。这意味着a.x是矩阵的第一列,而不是行

需要注意的一个关键点是,视图在CPU上 匹配GPU上的proj_mat*view_mat。有人知道为什么吗

这是因为对于两个矩阵A,B:A*B=B'*A,其中'表示转置操作。正如您自己已经指出的,您的数学代码以及流行的数学库(如GLM)使用矩阵的行主表示法,而OpenGL默认使用列主表示法。这意味着矩阵A

    (a b c)
A = (d e f)
    (g h i)
在CPU中,数学库在内存中存储为[a、b、c、d、e、f、g、h、i],而在GLSL着色器中定义的数学库则存储为[a、d、g、b、e、h、c、f、i]。因此,如果您上传GLM矩阵的数据[a,b,c,d,e,f,g,h,i],带有GluniformMatrix x3Fv,转置参数设置为GL_FALSE,那么您将在GLSL中看到的矩阵是

     (a d g)
A' = (b e h)
     (c f i)

这是转置后的原始矩阵。认识到在行主键和列主键之间更改矩阵数据的解释会导致原始矩阵的转置版本,现在可以解释为什么矩阵乘法突然以相反的方式工作。CPU上的视图和项目在GLSL着色器中被解释为视图和项目,因此,将预先计算的视图材质*投影材质上传到着色器将导致与分别上传两个矩阵,然后计算投影材质*视图材质相同的结果。

它们有多大不同?好问题-在gpu上很难分辨,我发现获取信息的唯一方法是输出各种颜色。。。。一个很大的区别是我
我在GPU上的proj view=my view_transpose*CPU上的proj_transpose…如上所述,我所有的相等性测试都是通过feq运行的,它在0.1公差范围内测试相等性,这是一个巨大的公差,因为我以后可以处理fp精度中的不一致性。。。我甚至没有得到相同的大概答案哦,而且,被测试的数字远低于100.0,所以不需要0.1公差在某些尺度上不是很大,如果有人这么想的话;好的,我删掉了那一段。我将强调第一段:我不知道您正在使用什么库来生成矩阵,但您需要验证其有效性,或者切换到一个经过验证的库,如GLM。对于您的第一段,我宁愿不使用GLM。这在一定程度上是我的一次教育经历。在手工操作的过程中,我已经学到了很多关于OpenGLAPI中各种gotchas的知识。我利用这个bug作为一个机会,希望能发现另一个bug。在接下来的段落中,我们已经讨论了fp精度。在你的最后一段,我已经通过了验证,确认输入是相同的。
mat4 m = mat4(
  vec4( 1, 5, 9,13),
  vec4( 2, 6,10,14),
  vec4( 3, 7,11,15),
  vec4( 4, 8,12,16),
);
fm4 mulfm4(fm4 a, fm4 b)
{
  return fm4
    { { a.x[0]*b.x[0] + a.y[0]*b.x[1] + a.z[0]*b.x[2] + a.w[0]*b.x[3], a.x[1]*b.x[0] + a.y[1]*b.x[1] + a.z[1]*b.x[2] + a.w[1]*b.x[3], a.x[2]*b.x[0] + a.y[2]*b.x[1] + a.z[2]*b.x[2] + a.w[2]*b.x[3], a.x[3]*b.x[0] + a.y[3]*b.x[1] + a.z[3]*b.x[2] + a.w[3]*b.x[3] },
      { a.x[0]*b.y[0] + a.y[0]*b.y[1] + a.z[0]*b.y[2] + a.w[0]*b.y[3], a.x[1]*b.y[0] + a.y[1]*b.y[1] + a.z[1]*b.y[2] + a.w[1]*b.y[3], a.x[2]*b.y[0] + a.y[2]*b.y[1] + a.z[2]*b.y[2] + a.w[2]*b.y[3], a.x[3]*b.y[0] + a.y[3]*b.y[1] + a.z[3]*b.y[2] + a.w[3]*b.y[3] },
      { a.x[0]*b.z[0] + a.y[0]*b.z[1] + a.z[0]*b.z[2] + a.w[0]*b.z[3], a.x[1]*b.z[0] + a.y[1]*b.z[1] + a.z[1]*b.z[2] + a.w[1]*b.z[3], a.x[2]*b.z[0] + a.y[2]*b.z[1] + a.z[2]*b.z[2] + a.w[2]*b.z[3], a.x[3]*b.z[0] + a.y[3]*b.z[1] + a.z[3]*b.z[2] + a.w[3]*b.z[3] },
      { a.x[0]*b.w[0] + a.y[0]*b.w[1] + a.z[0]*b.w[2] + a.w[0]*b.w[3], a.x[1]*b.w[0] + a.y[1]*b.w[1] + a.z[1]*b.w[2] + a.w[1]*b.w[3], a.x[2]*b.w[0] + a.y[2]*b.w[1] + a.z[2]*b.w[2] + a.w[2]*b.w[3], a.x[3]*b.w[0] + a.y[3]*b.w[1] + a.z[3]*b.w[2] + a.w[3]*b.w[3] } };
}
    (a b c)
A = (d e f)
    (g h i)
     (a d g)
A' = (b e h)
     (c f i)