0

コリジョンを使用してレイ ピッキングを実行しようとしています。つまり、画面上の 2D 位置がモデル空間の 3D 位置に変換されます。私の問題は、光線が常にモデルと交差して有効な 3D 位置になるとは限らないことです。

これが私がすることです:

後でフレームバッファに深度テクスチャを作成しますglReadPixels()

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

cv::Mat_<float> depthCV(screenHeight, screenWidth);
glReadPixels(0, 0, screenWidth, screenHeight, GL_DEPTH_COMPONENT, GL_FLOAT, depthCV.ptr());

その後、深度を線形化し、次の方法cv::Mat_<uchar>でエッジ検出用に保存しcv::Canny()ます:(画像を反転することを忘れないでください。)

cv::blur(gray, edge, cv::Size(3, 3));
cv::Canny(edge, edge, edgeThresh, edgeThresh * ratio, 3);

...そして輪郭を取得します

cv::findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_NONE, cv::Point(0, 0));

輪郭の 2D 座標 (x,y) は、次の方法で 3D モデル座標に変換されます。

GLint viewport[4];
GLfloat winX, winY, winZ;
glGetIntegerv(GL_VIEWPORT, viewport);
winX = (float)x;
winY = (float)viewport[3] - (float)(y);
glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
glm::vec4 viewportvec(viewport[0], viewport[1], viewport[2], viewport[3]);
glm::vec3 winCoords(winX, winY, winZ);

glm::vec3 modelCoords = glm::unProject(winCoords, view*model, proj, viewportvec);

これを実行して 3D ポイントを確認すると、一部の光線がモデルと交差していないことがわかります。光線の長さは遠平面の値に近いです。入力 (x,y) の周囲の 1 ピクセル近傍も見て、入力を広げようとしました。それでも一部の光線はモデルと交差しません。

これはなぜですか?またはそれを解決する方法は?以前のぼかしを使用したエッジ抽出が原因ですか?

ティーポット

分布がわかる画像を添付しました。青い点はモデルと交差していない点 (遠平面の値に近い光線の長さ) で、赤い点は交差しています。テストにはティーポット モデルを使用しました。

読みやすくするために、ここにコード全体を貼り付けたくありませんでした。何が問題なのかをよりよく理解するために、さらにコードや情報が必要な場合は、お知らせください。

4

1 に答える 1

0

以前のぼかしを使用したエッジ抽出が原因ですか?

はい、もちろんです。

エッジ検出後処理フィルターの代わりに、エッジ抽出ラスタライズ フラグメント シェーダーを実装することをお勧めします。実際には非常に簡単です:

顔の法線を画面座標に変換します (フラグメントごと)。abs(screenspace_normal.z) < threshold面が画面に対して垂直な場合は、エッジです。エッジではないすべてのフラグメントdiscardのフラグメント。残っているのは、エッジ (に近い) であり、さらに処理できるフラグメントです。

これにより、「隠れた」サーフェスのエッジも抽出されることに注意してください。したがって、深度テストへの「早期 Z」パスを実行してから、深度バッファに書き込みを行わず、エッジ フラグメントのみを出力する 2 番目のパスを実行する必要があります。

于 2016-07-18T17:12:11.003 に答える