glsl(lwjgl)におけるフォンスペキュラ照明

私は現在、glslとPhongモデルを使って、球面上に鏡面照明を作ろうとしています。

これは、私のフラグメントシェーダのようです:

#version 120
uniform vec4 color;
uniform vec3 sunPosition;
uniform mat4 normalMatrix;
uniform mat4 modelViewMatrix;
uniform float shininess;
// uniform vec4 lightSpecular;
// uniform vec4 materialSpecular;

varying vec3 viewSpaceNormal;
varying vec3 viewSpacePosition;

vec4 calculateSpecular(vec3 l, vec3 n, vec3 v, vec4 specularLight, vec4 materialSpecular) {
    vec3 r = -l+2*(n*l)*n;
    return specularLight * materialSpecular * pow(max(0,dot(r, v)), shininess);
}

void main(){
    vec3 normal = normalize(viewSpaceNormal);
    vec3 viewSpacePosition = (modelViewMatrix * vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)).xyz;
    vec4 specular = calculateSpecular(sunPosition, normal, viewSpacePosition, vec4(0.3,0.3,0.3,0.3), vec4(0.3,0.3,0.3,0.3));
    gl_FragColor = color+specular;
}

sunPositionは動いておらず、値(2.0f、3.0f、-1.0f)に設定されています。

問題は、鏡面反射の計算が正しければ、画像が何もしていないように見えることです。

This is how it looks like: http://i.imgur.com/Na2C6.png

私がこのコードでambient// emissiv-/deffuse- lightingを持っていない理由は、最初に鏡面光の部分を取りたいからです。

何か助けてくれてありがとう!

編集: @ダーシーレイナー それは本当に正しいものであるために縫い目が強くなりました...

現在のコードは次のようになります:

頂点シェーダ:

viewSpacePosition = (modelViewMatrix*gl_Vertex).xyz;
viewSpaceSunPosition = (modelViewMatrix*vec4(sunPosition,1)).xyz;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
viewSpaceNormal = (normalMatrix * vec4(gl_Position.xyz, 0.0)).xyz;

フラグメントシェーダ:

vec4 calculateSpecular(vec3 l, vec3 n, vec3 v, vec4 specularLight, vec4 materialSpecular) {
    vec3 r = -l+2*(n*l)*n;
    return specularLight * materialSpecular * pow(max(0,dot(r, v)), shininess);
}

void main(){
    vec3 normal = normalize(viewSpaceNormal);
    vec3 viewSpacePosition = normalize(viewSpacePosition);
    vec3 viewSpaceSunPosition = normalize(viewSpaceSunPosition);
    vec4 specular = calculateSpecular(viewSpaceSunPosition, normal, viewSpacePosition,     vec4(0.7,0.7,0.7,1.0), vec4(0.6,0.6,0.6,1.0));
    gl_FragColor = color+specular;
}

球は次のようになります:

-->Picture-link<--

太陽の位置:sunPosition =新しいベクトル(12.0f、15.0f、-1.0f);

2

2 答え

gl_FragCoord は、フラグメントのウィンドウ相対座標(x、y、z、1/w)値を含む入力変数です。 ...この値は、頂点処理後にプリミティブを補間してフラグメントを生成する固定機能の結果です。

gl_FragCoordの最初の2つの値(x、y) には、フラグメントがレンダリングされるピクセルの中心座標が含まれます。例えば、800×600のフレームバッファ解像度では、左下隅にレンダリングされるフラグメントがピクセル位置(0.5,0.5)に落ちる。右上隅にレンダリングされたフラグメントは、座標(799.5,599.5)を持つことになります。第3の値(z)は、非線形範囲[0,1]にマッピングされたフラグメントの深さである。フラグメントの深さを[znear、zfar]から[0,1]にマップします。

これによると、 vec3 viewSpacePosition =(modelViewMatrix * vec4(gl_FragCoord.x、gl_FragCoord.y、gl_FragCoord.z、1.0))。xyz; は期待したことをしません。 gl_FragCoord は、頂点位置は、 gl_ModelViewProjectionMatrix によって変換され、三角形プリミティブ上のフラグメントの副中心座標によって補間され、ビューポートサイズでスケーリングされます。モデルビュー行列( modelView Matrix )によるさらなる変換は意味をなさない。

鏡面光を計算するには(3つのベクトルが必要です:フォン反射モデル

  1. The normal vector of the surface, which is normalize(viewSpaceNormal) in this case.
  2. The vector from the frgments position to the camera. The camera has the position (0, 0, 0) in view space. Thus follows, the view vector is normalize(vec3(0.0) - viewSpacePosition).
  3. The light vector, which is the vector from the frgment position to the light source. So the light vector is calculated by normalize(viewSpaceSunPosition - viewSpacePosition).
    Note, since the calculation is done in the view space (viewSpaceNormal and viewSpacePosition are in view space), the light vector, and thus also the position of the light source (viewSpaceSunPosition), has to be in the view space. This means that the position of the light source should be transformed by the view matrix before it is set to the uniform variable viewSpaceSunPosition.

ビュー行列とモデルビュー行列は等しくてはならないことに注意してください。モデルビュー行列は、モデル行列とビュー行列から構成されます。通常、モデル行列は、単一のオブジェクト(例えば、シーン内のオブジェクト上のアニメーション)に対する追加の変換を含む。

これとは別に、反射ベクトルの計算に間違いがあります。計算式は次のとおりです。

incidentVector - 2.0 * dot(incidentVector, normalVector) * normalVector;

GLSLには、 code> を実行してください。

頂点とフラグメントシェーダはどういうわけか、次のようになります。

頂点シェーダ

varying vec3 viewSpacePosition;
varying vec3 viewSpaceNormal;

void main()
{
    viewSpacePosition  = (modelViewMatrix*gl_Vertex).xyz;
    viewSpaceNormal    = (normalMatrix * vec4(gl_Position.xyz, 0.0)).xyz;
    gl_Position        = gl_ModelViewProjectionMatrix * gl_Vertex;
}

フラグメントシェーダ

varying vec3 viewSpacePosition;
varying vec3 viewSpaceNormal;

uniform vec3  viewSpaceSunPosition;
uniform float shininess;

vec4 calculateSpecular(vec3 L, vec3 N, vec3 V, vec4 specularLight, vec4 materialSpecular)
{
    vec3 R = -L - 2.0 * dot(N, -L) * N;
   //vec3 R = reflect( -L, N );
    return specularLight * materialSpecular * pow(max(0,dot(R, V)), shininess);
}

void main()
{
    vec3 N = normalize( viewSpaceNormal );
    vec3 V = normalize( -viewSpacePosition );
    vec3 L = normalize( viewSpaceSunPosition - viewSpacePosition );
    vec4 specular = calculateSpecular(L, N, V, vec4(0.7,0.7,0.7,1.0), vec4(0.6,0.6,0.6,1.0));
    gl_FragColor  = color+specular;
}

この質問の回答も参照してください。

0
追加された

gl_FragCoordを使用しないでください。画面座標に格納されています(modelViewMatrixで変換しても座標を表示することはできません)。最も簡単なことは、頂点シェーダのviewSpacePositionを次のように設定することです:

// Change gl_Vertex to whatever attribute you are using.
viewSpacePosition = (modelViewMatrix * gl_Vertex).xyz; 

これはビューの座標(すなわち、投影が適用される前)でviewSpacePositionを取得するはずです。その後、フラグメントシェーダでviewSpacePositionを正規化して正規化することができます。太陽のベクトルをワールド座標に格納するかどうかは不明ですが、それをビュー空間に変換して正規化することもできます。それを行って何が起こるか見てみましょう。これらは非常に誤りがちです。

0
追加された