4

以前に発生して投稿した問題と多少似ているため、GLSLアプリで法線を正しく表示しようとしています。説明のために、RenderMonkeyで提供されているninjaHead.objモデルをテスト目的で使用しています(ここで取得できます)。これで、RenderMonkeyのプレビューウィンドウでは、すべてが見栄えが良く RenderMonkey なります。生成される頂点コードとフラグメントコードはそれぞれ次のとおりです。

バーテックス:

uniform vec4 view_position;

varying vec3 vNormal;
varying vec3 vViewVec;

void main(void)
{
  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

  // World-space lighting
  vNormal = gl_Normal;
  vViewVec = view_position.xyz - gl_Vertex.xyz;
}

断片:

uniform vec4 color;

varying vec3 vNormal;
varying vec3 vViewVec;

void main(void)
{
   float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
   gl_FragColor =  v* color;
}

私はこれに基づいてGLSLコードを作成しましたが、期待した結果が得られていません...

私の頂点シェーダーコード:

uniform mat4 P;
uniform mat4 modelRotationMatrix;
uniform mat4 modelScaleMatrix;
uniform mat4 modelTranslationMatrix;
uniform vec3 cameraPosition;

varying vec4 vNormal;
varying vec4 vViewVec;

void main()
{
vec4 pos = gl_ProjectionMatrix * P * modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertex;

gl_Position = pos;

gl_TexCoord[0] = gl_MultiTexCoord0;

gl_FrontColor = gl_Color;   

vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);     

// World-space lighting
   vNormal = normal4*modelRotationMatrix;
   vec4 tempCameraPos = vec4(cameraPosition.x,cameraPosition.y,cameraPosition.z,0);     
   //vViewVec = cameraPosition.xyz - pos.xyz;
   vViewVec = tempCameraPos - pos;
}

私のフラグメントシェーダーコード:

varying vec4 vNormal;
varying vec4 vViewVec;

void main()
{
  //gl_FragColor = gl_Color;
  float v = 0.5 * (1.0 + dot(normalize(vViewVec), vNormal));
gl_FragColor =  v * gl_Color;
}

しかし、私のレンダリングはこれを生成します... openGLレンダリング

何がこれを引き起こしているのか、そして/またはそれを機能させる方法を誰かが知っていますか?

編集 kvarkのコメントに応えて、レンダリングされているすべての三角形を表示するために、通常/照明の計算なしでレンダリングされたモデルがあります。 フラットシェーディングをレンダリングする

これが、色に使用される法線を使用したモデルのシェーディングです。問題が見つかったと思います!その理由は、なぜこのようにレンダリングされているのか、そしてそれをどのように解決するのかということです。提案は大歓迎です! 通常のシェーディング

解決策 さて、誰もが問題を解決しました!プログラミングの練習に間違いなく役立った彼の有益な洞察に感謝しますが、答えは私が大規模な乳首であることから来るのではないかと思います...コードのdisplay()関数にエラーがあり、glNormalPointerオフセットを設定しましたランダムな値に。以前はこれでした:

gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, getNormalsBufferObject());

しかし、これである必要があります:

gl.glEnableClientState(GL.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, getNormalsBufferObject());
gl.glNormalPointer(GL.GL_FLOAT, 0, 0);

ですから、これは教訓だと思います。金曜日の午後の時間を節約するために、Ctrl+CおよびCtrl+Vコードを無意識に使用しないでください。そして...あなたが見ているコードの部分が正しいと確信している場合、問題はおそらくどこか別の場所にあります。

4

2 に答える 2

1
  1. あなたのPマトリックスは何ですか?(私はそれが世界->カメラビュー変換だと思います)。

  2. vNormal = normal4*modelRotationMatrix;なぜ引数の順序を変更したのですか?法線に逆回転を掛けていることを行うと、本当に必要ないことです。代わりに標準の順序を使用してください(modelRotationMatrix * normal4)

  3. vViewVec = tempCameraPos - pos。これは完全に正しくありません。posは、世界空間にある間、同種のクリップ空間にある頂点ですtempCameraPos(私は推測します)。法線と同じ空間(ワールド空間)で結果を得る必要があるため、modelTranslationMatrix * modelRotationMatrix * modelScaleMatrix * gl_Vertexこの方程式にはワールド空間の頂点位置()を使用します。

于 2011-04-20T19:25:27.643 に答える
0

GLバージョンを少し混ぜているようですか?ユニフォームを介して手動で行列を渡していますが、固定関数を使用して頂点属性を渡します。うーん。ともかく...


私はあなたがあなたの法線に対してしていることを本当に好きではありません。見てください:

vec4 normal4 = vec4(gl_Normal.x,gl_Normal.y,gl_Normal.z,0);     

vNormal = normal4*modelRotationMatrix;

法線は方向データのみを保存します。なぜそれを使用するのvec4ですか? just を使用する方がエレガントだと思いますvec3。さらに、次に何が起こるか見てみましょう。法線に 4x4 モデルの回転行列を掛けます...さらに、法線の 4 番目の座標は 0 に等しいため、同次座標では正しいベクトルではありません。それがここでの主な問題かどうかはわかりませんが、その乗算がゴミになるとしても驚かないでしょう。

vec3法線を変換する標準的な方法は、モデル ビュー マトリックスの 3x3 サブマトリックスでa を乗算することです (変換ではなく方向のみに関心があるため)。正確には、「最も正しい」アプローチは、その 3x3 サブマトリックスの逆転置を使用することです (これは、スケーリングがある場合に重要になります)。古い OpenGL バージョンでは、 として事前に計算されていましたgl_NormalMatrix

したがって、上記の代わりに、次のようなものを使用する必要があります

// (...)
varying vec3 vNormal;
// (...)

mat3 normalMatrix = transpose(inverse(mat3(modelRotationMatrix)));
// or if you don't need scaling, this one should work too-
mat3 normalMatrix = mat3(modelRotationMatrix);

vNormal = gl_Normal*normalMatrix;

それは確かにあなたのコードで修正すべきことの 1 つです。問題が解決することを願っています。

于 2011-04-23T12:57:40.887 に答える