Ios 如何在顶点/片段着色器(金属)中使用3x3 2D变换

Ios 如何在顶点/片段着色器(金属)中使用3x3 2D变换,ios,shader,texture-mapping,metal,Ios,Shader,Texture Mapping,Metal,我有一个假定的简单任务,但显然我仍然不明白投影在着色器中是如何工作的。我需要在纹理四边形(2个三角形)上进行2D透视变换,但在视觉上它看起来不正确(例如,梯形比CPU版本中的稍高或拉伸程度更大) 我有这个结构: struct VertexInOut { float4 position [[position]]; float3 warp0; float3 warp1; float3 warp2; float3 warp3; }; 在顶点着色器中

我有一个假定的简单任务,但显然我仍然不明白投影在着色器中是如何工作的。我需要在纹理四边形(2个三角形)上进行2D透视变换,但在视觉上它看起来不正确(例如,梯形比CPU版本中的稍高或拉伸程度更大)

我有这个结构:

struct VertexInOut  
{  
  float4 position [[position]];  
  float3 warp0;  
  float3 warp1;  
  float3 warp2;  
  float3 warp3;  
};  
在顶点着色器中,我做了如下操作(
texCoords
是四角的像素坐标,单应性是以像素坐标计算的):

然后在片段着色器中,如下所示:

return intensity.sample(s, inFrag.warp0.xy / inFrag.warp0.z);
float4 targetIntensity = intensityRight.sample(s, inFrag.warp.xy * (1.0 / inFrag.warp.z));
结果不是我所期望的。我花了好几个小时在这上面,但我想不出来。排气

更新:

这些是CPU的代码和结果(也称为“预期结果”):

这些是GPU的代码和结果(也称为错误结果):

//在缓冲区中传递的常量,映像大小为320x240
常量simd::float4四顶点[4]=
{
{-1.0f,-1.0f,0.0f,1.0f},
{+1.0f,-1.0f,0.0f,1.0f},
{-1.0f、+1.0f、0.0f、1.0f},
{+1.0f,+1.0f,0.0f,1.0f},
};
常量simd::float3纹理词[4]=
{
{0,图像高度,1.0f},
{图像宽度,图像高度,1.0f},
{0,0,1.0f},
{IMAGE_WIDTH,0,1.0f},
};
//顶点着色器
顶点顶点顶点同形顶点(uint vid[[vertex_id]],
恒定浮动4*位置[[缓冲区(0)]],
常量浮动3*texCoords[[缓冲区(1)],
常量simd::float3x3*同音字[[缓冲区(2)])
{
顶点v;
v、 位置=位置[vid];
//示例单应
simd::float3x3 h={
{1.03140473, 0.0778113901, 0.000169219566},
{0.0342947133, 1.06025684, 0.000459250761},
{-0.0364957005, -38.3375587, 0.818259298}
};
v、 翘曲=h*texCoords[vid];
返回v;
}
//片段着色器
片段int4同形片段(VertexInOut inFrag[[stage_in]],
纹理2D强度[[纹理(1)])
{
constexpr采样器s(坐标::像素,滤波器::线性,地址::钳位到零);
float4 TargetTensity=强度光线样本(s,inFrag.warp.xy/inFrag.warp.z);
返回目标性;
}

原始图像:

更新2:

与通常认为应该在片段着色器中进行透视分割的观点相反,如果在顶点着色器中进行分割(并且三角形之间没有扭曲或接缝),我会得到更相似的结果,但是为什么呢

更新3:

如果出现以下情况,我会得到相同(错误)的结果:

  • 我将透视分割移动到片段着色器
  • 我只是从代码中删除除法

非常奇怪,看起来分割没有发生。

好的,解决方案当然是一个非常小的细节:
simd::float3
分割的行为绝对疯狂。事实上,如果我在片段着色器中执行透视分割,如下所示:

return intensity.sample(s, inFrag.warp0.xy / inFrag.warp0.z);
float4 targetIntensity = intensityRight.sample(s, inFrag.warp.xy * (1.0 / inFrag.warp.z));
它起作用了


这让我发现,乘以预先除以的浮点数和除以浮点数是不同的。如果有人知道为什么我们可以解开这个谜团,我仍然不知道原因。

提出一个项目,我来看看。如果没有至少一个屏幕截图,我就不能给出建议。@Jessy我在这里提取了核心部分,但如果你需要,我可以创建一个完整的项目。我有一个自定义的客户机-服务器库,可以将图像测试结果上传到我的Mac电脑上,因此提取这部分代码的速度要快得多。我在思考这一点时睡着了,醒来时我决定,我需要全身心投入到这个项目中,这样才能及时有效地解决它。如果没有其他人能在你满意的时间范围内给你一个答案,那么是的,请找到一种方法来上传我们能做的最少的内容,我会抽出时间至少尝试帮助你。嘿@Jessy,你可以在这里找到一个示例应用程序:当你在A7+设备上运行应用程序时,你将能够看到红色的错误扭曲。正确的一个是绿色的,它叠加到错误的一个上。由于屏幕大小的原因,会有一些拉伸,但由于两者都受其影响,所以没有区别。谢谢你的帮助。刚刚发现除法的结果被破坏了。。。如果你现在试用该应用程序,你会看到图像是黄色的(所有红色像素都位于绿色像素之上)。这太可怕了!我对你的项目有着与你描述的相同的结果。我把浮标改成了半浮标,但这并没有改变行为。如果没有人能弄清楚为什么会发生这种情况,我可能会打开雷达。事实上,我们都感到惊讶,而且都认为这是错误的,这意味着它需要一个雷达场,不管这个错误是否与我们自己缺乏知识有关。我从未在OpenGL/ES中看到过类似的情况。
float4 targetIntensity = intensityRight.sample(s, inFrag.warp.xy * (1.0 / inFrag.warp.z));