2011-11-12 14 views
1

OpenGLの照明システムを使用せずにすばらしい照明を実装するための探求を開始しました。 Phong拡散照明を正常に実装しました。スペキュラは私にトラブルを与えている。GLSL/OpenGL 2.1:ユニフォームを使用した鏡面照明

私は使用しているOpenGL定数が占有しているスペースが何であるかを知る必要があります。なぜなら、それらは誤って変換されているようであり、照明グリッチが発生するからです。

Phong拡散シェーダを正常に読み込んで実行すると、C++コードに問題はないことが確認されました。しかし、C++コードは無効なデータをシェーダに渡すことがありますが、これは私が心配していることの1つです。私はシェイダーにコメントを貼り付けるだけでなく、シェイダーに直接関連するすべてのC++コードを貼り付けます(問題はシェーダーに90%確実です)。

これらの画像では、光源は大きな点であり、軸が示されています。 ライトはicosphereの周りでy = 0で回転しています。あなたはモデルが何であるかのアイデア...私はピクセルごとまだ行っていない Note I haven't done per-pixel yet... 注意を...ソースに示すよう

はここで、フレネル照明のgetので

はここで、びまん性です。 .. 点灯面が光とカメラここ

の間ではないどこかに、光に直面しているかNote how the lit faces are facing the light, not somewhere between the light and the camera 注意が再び私は30で乗算しなければならなかったブリン・フォン、... Note again how the lit faces point towards the light source 注意ですか照明された面は光源の方を向いており、私はこの

バーテックスシェーダソース(「dirlight.vs」からロード)

const int MAXLIGHTS = 4; 

uniform bool justcolor = false; 

uniform int lightcount; 
uniform vec4 lightposs[MAXLIGHTS]; 
uniform vec4 lightdirs[MAXLIGHTS]; 
uniform vec4 lightdifs[MAXLIGHTS]; 
uniform vec4 lightambs[MAXLIGHTS]; 

//diffuse 
vec4 D; 
//specular, normaldotlight 
float S, NdotL[MAXLIGHTS]; 
//normal, eyevec, lightvecs, halfvecs 
vec3 N, E, L[MAXLIGHTS], H[MAXLIGHTS]; 

void main() { 
    //if(lightcount > MAXLIGHTS) lightcount = MAXLIGHTS; 
    D = vec4(0.0, 0.0, 0.0, 0.0); 
    S = 0.0; 

    N = gl_Normal; 
    E = normalize(vec3(-gl_Vertex)); 

    for(int i = 0; i < lightcount; i++) 
    { 
     //calculating direction to light source 
     L[i] = normalize(vec3(lightposs[i] - gl_Vertex)); 

     //normal dotted with direction to light source 
     NdotL[i] = max(dot(N, L[i]), 0.0); 

     //diffuse term, works just fine 
     D += gl_Color * lightdifs[i] * NdotL[i]; 

     if(NdotL[i] >= 0.0) 
     { 
      //halfvector = normalize(lightdir + eyedir) 
      H[i] = normalize(L[i] + E); 

      //Blinn-Phong, only lights up faces whose normals 
      //point directly to the light source for some reason... 
      //S += max(0.0, dot(H[i], N)); 

      //Fresnel, lights up more than Blinn-Phong 
      //but the faces still point directly to the light source, 
      //not somewhere between the lightsource and myself, like they should. 
      S += pow(max(0.0, dot(reflect(L[i], N), E)), 50.0); 
     } 
     else 
     { 
      H[i] = vec3(0.0, 0.0, 0.0); 
     } 
    } 

    //currently only showing specular. To show diffuse add D. 
    gl_FrontColor = justcolor ? gl_Color : vec4(S * 0.3, S * 0.3, S * 0.3, 1.0); 

    gl_Position = ftransform(); 
} 

フラグメントシェーダソース(dirlight」からロードを達成するために30で鏡面係数(S)を乗算しなければならなかったことも事実C++メインの初期化...

//class program manages shaders 
Program shaders = Program(); 
//attach a vertex shader, compiled from source in dirlight.vs 
shaders.addShaderFile(GL_VERTEX_SHADER, "dirlight.vs"); 
//attach a fragment shader compiled from source in dirlight.fs 
shaders.addShaderFile(GL_FRAGMENT_SHADER, "dirlight.fs"); 
//link program 
shaders.link(); 
//use program 
shaders.use(); 

//Program::getUniformLoc(const char* name) grabs the location 
//of the uniform specified 
GLint sTime = shaders.getUniformLoc("time"); 
GLint lightcount = shaders.getUniformLoc("lightcount"); 
GLint lightdir = shaders.getUniformLoc("lightdirs"); 
GLint lightdif = shaders.getUniformLoc("lightdifs"); 
GLint lightamb = shaders.getUniformLoc("lightambs"); 
GLint lightpos = shaders.getUniformLoc("lightposs"); 
GLint justcolor = shaders.getUniformLoc("justcolor"); 

glUniform1i(justcolor, 0); 
glUniform1i(lightcount, 2); 
//diffuse light colors 
GLfloat lightdifs[] = {1.f, 1.f, 1.f, 1.f, 
         1.f, 1.f, 1.f, 1.f}; 
glUniform4fv(lightdif, 2, lightdifs); 
glUniform4f(lightamb, 0.4f, 0.4f, 0.4f, 1.f); 

Excerから.fs ")

void main() 
{ 
    gl_FragColor = gl_Color; 
} 

抜粋C++メインループからのpt ...

//My lights rotate around the origin, where I have placed an icosphere 
GLfloat lightposs[] = {-4 * sinf(newTime), lighth, -4 * cosf(newTime), 0.0f, 
         -4 * sinf(newTime + M_PI), lighth, -4 * cosf(newTime + M_PI), 0.0f}; 
glUniform4fv(lightpos, 2, lightposs); 
+0

技術的には、頂点シェーダではなく、フラグメントシェーダでライティング計算を行う必要があります。それはフラグメントシェーダの重要な目的の1つです。フラグメントごとの照明モデルを実装します。 – datenwolf

+0

私は頂点シェーダで最初に実装しているので、同じ場所にすべてを持つことができます。私は後でピクセル単位に移行しています。私はそれらの間にエラーの余地があることを望んでいない、それが私が扱っている唯一のものでない限り。 – Miles

答えて

4

コードから欠落している重要なものはほとんどありません。まず、頂点の位置と法線を視点空間に変換する必要があります。照明の計算はそこで最も簡単です。モデルビュー行列を使用して頂点位置を変換すると、法線はモデルビューの転置された逆行列で変換されます。通常、ライトの位置はワールド座標系であるため、ワールド座標系からアイ座標系への行列を追加するのが理にかなっています。

+0

世界の空間で私が扱っているものは何ですか? (上の出所) – Miles

+1

@ MilesRufat-Latre:いいえ。これは、モデルのローカル空間(gl_Vertex、gl_Normal)、(lightpos、lightdir)、およびeye space(gl_Position = ftransform())のセマンティクスを提供していない、未定義の空間です。すでに述べたように、頂点シェーダを使用するだけで、物事を共通の空間、目の空間に持ち込むのはずっと簡単ですし、フラグメントシェーダでライティング計算を行います。 – datenwolf

+0

ローカルモデル空間を残してグローバルに移動するには、モデルローカル変数にgl_ModelViewの逆数を掛けますか?投影とモデルビューの行列はどのように関係していますか? – Miles

関連する問題