0

私は教育的追求のためのエンジンの始まりに取り組んでおり、理解していると思っていた OpenGL の概念に出くわしましたが、私が観察してきた動作を説明することはできません。問題は深度バッファにあります。また、問題を修正したことを理解してください。投稿の最後で、問題を修正した理由を説明しますが、私のソリューションで問題が修正された理由がわかりません。まず、GLUT と GLEW を初期化します。

//Initialize openGL
glutInit(&argc, argv);
//Set display mode and window attributes
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB);

//Size and position attributes can be found in constants.h
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutInitWindowPosition(WINDOW_XPOS, WINDOW_YPOS);
//Create window
glutCreateWindow("Gallagher");

// Initialize GLEW
glewExperimental = true;
glewInit();

//Initialize Graphics program
Initialize();

次に、プログラムを初期化します (読みやすさと関連性の欠如のためにセグメントを除外します)。

//Remove cursor
glutSetCursor(GLUT_CURSOR_NONE);

//Enable depth buffering
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LESS);
glDepthRange(0.0f, 1.0f)

//Set back color
glClearColor(0.0,0.0,0.0,1.0);

//Set scale and dimensions of orthographic viewport
//These values can be found in constants.h
//Program uses a right handed coordinate system.
glOrtho(X_LEFT, X_RIGHT, Y_DOWN, Y_UP, Z_NEAR, Z_FAR);

それ以降は、さまざまなエンジン コンポーネントの初期化、.obj ファイルの読み込み、ModularGameObject クラスのインスタンスの初期化、それらへのメッシュのアタッチが含まれます。ただし、先に進む前に、次の値を指定することが重要な場合があります。

X_LEFT = -1000;
X_RIGHT = 1000;
Y_DOWN = -1000;
Y_UP = 1000;
Z_NEAR = -0.1;
Z_FAR = -1000;

これにより、ビューポートは右手の座標系に従います。問題に関与していると思われるコードの最後の部分は、私の頂点シェーダーです。

#version 330 core
//Position of vertices in attribute 0
layout(location = 0) in vec4 _vertexPosition;
//Vertex Normals in attribute 1
layout(location = 1) in vec4 _vertexNormal;

//Model transformations
//Uniform location of model transformation matrix
uniform mat4 _modelTransformation;

//Uniform location of camera transformations
//Camera transformation matrix
uniform mat4 _cameraTransformation;
//Camera perspective matrix
uniform mat4 _cameraPerspective;

//Uniform location of inverse screen dimensions
//This is used because GLSL normalizes viewport from -1 to 1
//So any vector representing a position in screen space must be multiplied by this vector before display
uniform vec4 _inverseScreenDimensions;

//Output variables
//Indicates whether a vertex is valid or not, non valid vertices will not be drawn.
flat out int _valid;        // 0 = valid vertex
//Normal to be sent to fragment shader
smooth out vec4 _normal;

void main()
{
    //Initiate transformation pipeline

    //Transform to world space
    vec4 vertexInWorldSpace = vec4(_modelTransformation *_vertexPosition);

    //Transform to camera space
    vec4 vertexInCameraSpace = vec4(_cameraTransformation * vertexInWorldSpace);

    //Project to screen space
    vec4 vertexInScreenSpace = vec4(_cameraPerspective * vertexInCameraSpace);

    //Transform to device coordinates and store
    vec4 vertexInDeviceSpace = vec4(_inverseScreenDimensions * vertexInScreenSpace);
    //Store transformed vertex
    gl_Position = vertexInScreenSpace;

}

このコードにより、すべての変換と通常の計算 (含まれていない) が正しく実行されますが、モデルの各面は常に他の面よりも優れているように戦っています。問題がないのは、描画されている最初のモデルの内側に立っているときだけで、ちらつきはなく、スザンヌの頭の内側を本来のように見ることができます。

考えられることを何週間も試した後、最終的に、わずか2行のコードを変更/追加することで解決策にたどり着きました。まず、頂点シェーダーのメイン関数の最後に次の行を追加しました。

gl_Position.z = 0.0001+vertexInScreenSpace.z;

このコード行の追加により、Z ファイティングのすべてのビットがなくなりましたが、深度バッファーが完全に後方になり、遠くにある頂点が前方の頂点の上に確実に描画されていました。これが私の最初の質問です。なぜこのコード行がより信頼性の高い動作を引き起こすのでしょうか?

信頼できる動作が得られ、深度ファイティングがなくなったので、描画順序を逆にするだけで済みました。そのため、glDepthRange への呼び出しを次のように変更しました。

glDepthRange(1.0f, 0.0f);

私は、glDepthRange(0.0f, 1.0f) が Z_NEAR (-0.1) に近いオブジェクトを 0 に近づけ、Z_FAR(-1000) に近いオブジェクトを 1 に近づけると仮定していました。 Depth Test を GL_LESS に設定することは完全に理にかなっています。実際のところ、私の Z_NEAR と Z_FAR が何であるかに関係なく、glDepthRange が値をマップする方法が間違っていなければ、これは当てはまります。

ただし、この行の変更は、私に近いオブジェクトが深度バッファーに 1 に近い値を格納し、さらにオブジェクトが後方描画順序をレンダリングする 0 の値を持つことを意味するため、間違っているに違いありませんが、確かにそれは魅力。

誰かが私の仮定が間違っている理由と、gsl と深度バッファリングの理解を考慮に入れていない可能性があることの方向性を教えてくれれば。エンジンの基礎の機能を完全に理解するまで、エンジンの進歩に進みたくありません。

編集: 私の _cameraPerspective マトリックスの内容は次のとおりです: 透視マトリックス図

AspectX     0           0               0
0           AspectY     0               0
0           0           1               0
0           0         1/focalLength         0

AspectX は 16、AspectY は 9 です。焦点距離のデフォルトは 70 ですが、実行時にこれを変更するためのコントロールが追加されました。

derhass によって指摘されましたが、これは glOrtho() に渡された情報がシェーダーによってどのように考慮されるかを説明していません。標準のパイプラインとマトリックス スタックを使用していないため、ビューポートのサイズは _inverseScreenDimensions で考慮されます。これは [1/X_RIGHT, 1/Y_UP, 1/Z_Far, 1] を含む vec4 です。または、変数名がない場合は、[1/1000、1/1000、-1/1000、1]。

頂点シェーダーでこれをスクリーン座標ベクトルに掛けると、X 値は -1 から 1 の間、Y 値は -1 から 1 の間、Z 値は 0 から 1 の間になります (オブジェクトがカメラの前にあった場合、最初は負の z 座標)、W は 1 です。

私が間違っていなければ、これが「デバイス座標」に到達するための最後のステップであり、続いてメッシュを描画します。

元の質問を心に留めておいてください: 私はこれが合理化されていないことを知っています.GLMやこれに最もよく使用されるすべてのライブラリを使用していないことは知っています. 私の質問は、私が行った変更によってこれが修正されたのはなぜですか?

4

2 に答える 2

0

Near と Far は、見ている方向の近平面と遠平面の距離であるため、通常はどちらも正の数になります。負の数を指定すると、クリッピング プレーンがビューの原点の後ろに配置されますが、これはおそらく希望どおりではありません。

于 2014-05-27T19:38:33.063 に答える
0

次の行列を射影行列として使用します。

AspectX     0           0               0
0           AspectY     0               0
0           0           1               0
0           0         1/focalLength     0

深度値を完全に破壊します。

これを vector に適用すると、 とがクリップ スペース コンポーネントとして(x,y,z,w)^T取得 z'=zされます。パースペクティブ分割の後、目の空間の z 値とは完全に独立w'=z/focalLengthた NDC z コンポーネントになります。したがって、すべてを同じ深さに投影し、見た行動を完全に説明します。z'/w'focaldepth

このページでは、射影行列が通常どのように構築されるかを説明し、特に z 値がどのようにマッピングされるかについて多くの詳細を提供します。

gl_Position.z = 0.0001+vertexInScreenSpace.z; それ以来、実際にある種の「機能する」深さを得る線を使用すると、NDC Z 座標(0.0001+z')/w'focalLenght * (1+ 0.0001/z)、最終的には少なくとも目の空間 z の関数になります。マッピングが実際に生成するものnearfar値を計算することはできますが、その計算を実行しても、この答えにはまったく意味がありません。コンピュータ グラフィックス射影、特に線形代数と射影空間の数学に慣れておく必要があります。

深度テストが反転される理由は、射影行列が z 座標を否定するという事実によるものです。通常、ビュー マトリックスは、視線方向が-zで、射影マトリックスが(0 0 -1 0)最後の行になるように構築されますが(0 0 1/focalLength 0)、基本的に z に -1 を掛けます。

于 2014-05-27T21:41:54.473 に答える