私はおそらく単純な仕事をしていますが、シェーダーでの投影の仕組みをまだ理解していないようです。テクスチャ クワッド (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);
これらは、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:
次の場合、同じ(間違った)結果が得られます。
- パースペクティブ分割をフラグメントシェーダーに移動します
- コードから分割を削除するだけです
非常に奇妙なことに、分裂が起こっていないように見えます。