2012-03-06 15 views
4

GLSLで書かれた単純な頂点シェーダがあり、サーフェスの法線を計算する際に誰かが私を助けてくれるのだろうかと思いました。私は現在の光のモデルが見える...平らな面をアップグレードしています...奇妙です。私の現在のコードは以下の通りです:GLSL - Surface Normalを計算します。

varying vec4 oColor; 
varying vec3 oEyeNormal; 
varying vec4 oEyePosition; 

uniform float Amplitude;  // Amplitude of sine wave 
uniform float Phase;   // Phase of sine wave 
uniform float Frequency;  // Frequency of sine wave 

varying float sinValue; 

void main() 
{ 
    vec4 thisPos = gl_Vertex; 

    thisPos.z = sin((thisPos.x + Phase) * Frequency) * Amplitude; 

    // Transform normal and position to eye space (for fragment shader) 
    oEyeNormal = normalize(vec3(gl_NormalMatrix * gl_Normal)); 
    oEyePosition = gl_ModelViewMatrix * thisPos;  

    // Transform vertex to clip space for fragment shader 
    gl_Position = gl_ModelViewProjectionMatrix * thisPos; 

    sinValue = thisPos.z; 
} 

誰にでもアイデアはありますか?

答えて

6

ここで、微分ジオメトリの観点から考えてみましょう。だから、最初の我々の2つのパラメータの後に偏微分され、この表面の接線を計算

X(s,t) = (s, t, A*sin((s+P)*F)) 

:あなたは、パラメータsとtとのパラメトリック曲面を持っ

Xs(s,t) = (1, 0, A*F*cos((s+P)*F)) 
Xt(s,t) = (0, 1, 0) 

その後、我々はただ計算する必要がありますこれらの外積は、通常のを取得する:

N = Xs x Xt = (-A*F*cos((s+P)*F), 0, 1) 

をだからあなたの通常の完全な分析計算することができ、あなたが実際にgl_Normal属性は必要ありません。

float angle = (thisPos.x + Phase) * Frequency; 
thisPos.z = sin(angle) * Amplitude; 
vec3 normal = normalize(vec3(-Amplitude*Frequency*cos(angle), 0.0, 1.0)); 

// Transform normal and position to eye space (for fragment shader) 
oEyeNormal = normalize(gl_NormalMatrix * normal); 

normalの正規化は、(私たちはとにかく変換​​し、通常の正常化以来)neccessaryではないかもしれませんが、適切なタイミングで私は、正規化されていない通常の不均一なスケーリングの存在下で正しく動作するかどうかわかりません。もちろん、法線を負のz方向に向けるには、それを否定する必要があります。


まあ、宇宙の表面上の道は必要ではなかったでしょう。 zだけがxに依存するので、法線のy部分がゼロであるので、x-z平面内の正弦曲線で考えることもできます。だから、傾きがzの微分であり、xzベクトルが(1, A*F*cos((x+P)*F))である曲線z=A*sin((x+P)*F)の接線をとると、これに対する法線はちょうど(-A*F*cos((x+P)*F), 1)(スイッチ座標とネゲート1)であり、(正規化されていない)normal。 3Dベクトルと偏微分はありませんが、結果は同じです。

+0

ありがとうございました! Win7のパーティションを起動すると、すぐにこれを試してみます。私は照明とGLSLで時間を過ごしています! – Josh

-1

さらに、あなたのパフォーマンスを微調整する必要があります

oEyeNormal = normalize(vec3(gl_NormalMatrix * gl_Normal)); 
  1. gl_NormalMatrixは、3×3の行列であるため、vec3にキャストする必要はありません。
  2. 頂点シェーダで長さに基づく計算を行わないため、入力頂点を正規化する必要はありません。いくつかの情報源は、着信する法線は、アプリケーションによって常に正規化されるべきであるため、頂点シェーダ内にそれをまったく必要としないと言います。しかし、それはシェーダの開発者の手にないので、私は頂点ベースのライティング(gouraud)を計算するときにそれらを正規化します。
+0

1. - キャストは不要ですが、vec3からvec3へのキャストはノーオペレーションでなければなりません(GLSLコンパイラはここでコピーするのは愚かではありません) 。しかし、それはまったく不必要なことです。 –

+1

2 - それは間違っている。彼は入ってくる法線を正規化しません(実際には良い考えではありません)。しかし、彼は変形された法線を正規化し( 'gl_NormalMatrix'を乗じた後に)、**スケーリングとせん断変換を説明するために**必要です。もちろん、非正規化された法線をサーフェス全体に補間すると、フラグメントごとの法線が正しくないことがわかります。最終的にここで微調整するパフォーマンスはあまりありません。 –

+0

そして最終的にそれは実際の質問に答えることはなく、コメントとしてもっと適しているかもしれません。 –

関連する問題