1

私はおそらく単純な仕事をしていますが、シェーダーでの投影の仕組みをまだ理解していないようです。テクスチャ クワッド (2 つの三角形) で 2D 透視変換を行う必要がありますが、視覚的には正しく見えません (たとえば、台形が CPU バージョンよりもわずかに高いか、伸びています)。

私はこの構造体を持っています:

struct VertexInOut  
{  
  float4 position [[position]];  
  float3 warp0;  
  float3 warp1;  
  float3 warp2;  
  float3 warp3;  
};  

そして、頂点シェーダーで次のようなことを行います(texCoordsクワッドコーナーのピクセル座標であり、ホモグラフィはピクセル座標で計算されます):

v.warp0 = texCoords[vid] * homographies[0]; 

次に、フラグメント シェーダーで次のようにします。

return intensity.sample(s, inFrag.warp0.xy / inFrag.warp0.z);

結果は私が期待するものではありません。これに何時間も費やしましたが、わかりません。ベント

アップデート:

これらは、CPU のコードと結果 (別名、期待される結果) です。

// _image contains the original image
cv::Matx33d h(1.03140473, 0.0778113901, 0.000169219566,
              0.0342947133, 1.06025684, 0.000459250761,
              -0.0364957005, -38.3375587, 0.818259298);
cv::Mat dest(_image.size(), CV_8UC4);
// h is transposed because OpenCV is col major and using backwarping because it is what is used on the GPU, so better for comparison
cv::warpPerspective(_image, dest, h.t(), _image.size(), cv::WARP_INVERSE_MAP | cv::INTER_LINEAR);  

cpuによってゆがむ

これらは、GPU のコードと結果です (別名、間違った結果):

// constants passed in buffers, image size 320x240
const simd::float4 quadVertices[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 },
};

const simd::float3 textureCoords[4] =
{
  { 0,  IMAGE_HEIGHT, 1.0f },
  { IMAGE_WIDTH, IMAGE_HEIGHT, 1.0f },
  { 0, 0, 1.0f },
  { IMAGE_WIDTH, 0, 1.0f },
};

// vertex shader
vertex VertexInOut homographyVertex(uint vid [[ vertex_id ]],
                                    constant float4 *positions [[ buffer(0) ]],
                                    constant float3 *texCoords [[ buffer(1) ]],
                                    constant simd::float3x3 *homographies [[ buffer(2) ]])
{
  VertexInOut v;
  v.position = positions[vid];

  // example homography
  simd::float3x3 h = {
    {1.03140473, 0.0778113901, 0.000169219566},
    {0.0342947133, 1.06025684, 0.000459250761},
    {-0.0364957005, -38.3375587, 0.818259298}
  };

  v.warp = h * texCoords[vid];

  return v;
}

// fragment shader
fragment int4 homographyFragment(VertexInOut inFrag [[stage_in]],
                                 texture2d<uint, access::sample> intensity [[ texture(1) ]])
{
  constexpr sampler s(coord::pixel, filter::linear, address::clamp_to_zero);
  float4 targetIntensity = intensityRight.sample(s, inFrag.warp.xy / inFrag.warp.z);
  return targetIntensity;
}

ここに画像の説明を入力

元の画像:

元の画像

更新 2:

パースペクティブ分割はフラグメント シェーダーで行うべきであるという一般的な考えに反して、頂点シェーダーで分割すると (三角形間の歪みや継ぎ目がない場合) 、はるかに似た結果が得られますが、なぜでしょうか?

ここに画像の説明を入力

更新 3:

次の場合、同じ(間違った)結果が得られます。

  • パースペクティブ分割をフラグメントシェーダーに移動します
  • コードから分割を削除するだけです

非常に奇妙なことに、分裂が起こっていないように見えます。

4

1 に答える 1

2

OK、解決策はもちろん非常に細かい部分でしsimd::float3。実際、フラグメント シェーダーでパースペクティブ ディバイドを行うと、次のようになります。

float4 targetIntensity = intensityRight.sample(s, inFrag.warp.xy * (1.0 / inFrag.warp.z));

できます!

これにより、事前に分割された浮動小数点数で乗算することは、浮動小数点数で除算することとは異なることがわかりました。この謎を解き明かすことができる理由を知っている人がいれば、その理由はまだわかりません。

于 2015-08-11T17:48:08.253 に答える