GLSL/GL2.1照明:アイスペースへの変換

それで、照明の計算を行う前に、すべてを目の空間に変換するのに役立ちますか?私は変換部分に問題があります。私は法線を正しく変換しましたが、翻訳を適用すると(オブジェクトがワールド座標系の中心にない場合)、照明はまったく同じままです。

C ++コードに問題はないことを確認しました。 私はシェイダーをペーストします…

質問:私が正しいものを変えていないこと、そしてそれをどう変えるべきかを知りたい。

頂点シェーダ…

const int MAXLIGHTS = 4;

uniform int lightcount;
uniform vec4 lPositions[MAXLIGHTS];

//V = transformed vertex
//N = transformed normal
//E = eye vector
//L = vector from vertex to light
varying vec3 V, N, E, L[MAXLIGHTS];

void main()
{
    int lcount = lightcount > MAXLIGHTS ? MAXLIGHTS : lightcount;

    V = vec3(gl_ModelViewMatrix * gl_Vertex);

    N = gl_NormalMatrix * gl_Normal;

    E = normalize(-V);

    for(int i = 0; i < lcount; i++)
    {
        L[i] = gl_NormalMatrix * normalize(vec3(lPositions[i] - gl_Vertex));
    }

    gl_FrontColor = gl_Color;
    gl_Position = ftransform();
}

フラグメントシェーダ…

const int MAXLIGHTS = 4;

uniform int lightcount;
uniform vec4 lDiffuses[MAXLIGHTS];
uniform vec4 lAmbients[MAXLIGHTS];

varying vec3 V, N, E, L[MAXLIGHTS];
uniform bool justcolor;

void main()
{
    if(justcolor)
    {
        gl_FragColor = gl_Color;
        return;
    }
    int lcount = lightcount > MAXLIGHTS ? MAXLIGHTS : lightcount;

    vec4 ambient;
    vec4 diffuse;
    vec4 specular = vec4(0.0, 0.0, 0.0, 0.0);
    vec4 color = vec4(0.0, 0.0, 0.0, 1.0);

    vec3 H;
    float NL;
    float NH;

    for(int i = 0; i < lcount; i++)
    {
        specular = vec4(0.0, 0.0, 0.0, 0.0);

        ambient = lAmbients[i];

        NL = dot(N, L[i]);
        diffuse = lDiffuses[i] * max(NL, 0.0);

        if(NL > 0.0)
        {
            H = normalize(E + L[i]);
            NH = max(0.0, dot(N, H));
            specular = pow(NH, 40.0) * vec4(0.3, 0.3, 0.3, 1.0);
        }

        color += gl_Color * (diffuse + ambient) + specular;
    }

    gl_FragColor = color;
}
ベストアンサー

目の空間は、シーンが投影行列を通過する直前に変換される空間です。これは、モデル空間から視空間(modelview変換)からクリップ空間(投影変換)までの完全な経路を意味する
ftransform()が便利にラップするものです。

modelviewマトリックスには、オブジェクトのローカルからアイスペースへの完全な変換が含まれています。しかし、あなたのライトは(それぞれの)オブジェクトのローカル空間にはなく、ワールド空間にあります。ここでは2つの異なる変換を扱っています:

  • Worldローカルのオブジェクト – これはmodelviewの model 部分です
  • 世界から目 – これは表示の一部です

したがって、分解されたmodelviewをモデルとして提供し、均一なマトリックス入力を表示することによって、頂点シェーダのライトとオブジェクトの頂点の両方を変換することが技術的に可能でした。次に、ライトパーツをビューパーツだけでなく、オブジェクトの頂点をモデル別に変換し、パーツを表示します。しかし、私はそうしないことをお勧めします。シェーダユニットの計算資源は、各頂点入力に対して異なる結果を有する計算に予約されるべきである。軽い位置の変換はこれを行いません。

代わりに、シェーダ(ユニフォーム)に渡す前に、光の位置を目の空間に事前変換する必要があります。これを行う方法。まずは、OpenGLの行列操作関数(glRotate、glTranslate、glScale、…、gluPerspectiveなどのGLUヘルパー)を取り除くことを強くお勧めします。それらがなくても簡単になり、さらに後のOpenGLバージョンから削除されました。

だからそれをどうやるのか。
GLMのような行列ライブラリがあるとしますが、他のライブラリも使えます。あなたのシーンをレンダリングするには、そのスキーム(Pythonのような擬似コード)

render_scene:
    projection_matrix = Matrix.Perspective(…)
    view_matrix = Matrix.LookAt(…)

    light_positions = []
    for i, light in enumerate(scene.lights):
        if i > MAX_LIGHTS:
             break
        light_positions.append( view_matrix * light.position )

    glUniform3fv(glGetUniformLocation("lPositions"), light_positions)

    for object in scene.objects:
        obj_modelview = view_matrix * object.transform
        # This is using deprecated functionality
        glMatrixMode(GL_MODELVIEW); glLoadMatrix(obj_modelview)
        object.draw()

ご覧のように、ライトはview_matrixを使用して視覚空間に「手動で」変換されますが、オブジェクトの頂点はGPUではなく、描画用に設定されたシェーダのパラメータに触れられます。

コメントする

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です