4

私はOpenGLES2.0のチュートリアルに従い、 developer.apple.comの便利なユタティーポットを使用して、見つけたGLSL照明のチュートリアルと組み合わせています。

たくさんのいじりと実験の後、ティーポットを画面上に適度に正しく描画し、照明チュートリアルの「トゥーンシェーディング」を使用して3つの軸すべてを中心に回転させます。頂点リスト全体を三角ストリップとして描画するだけなので、ジオメトリにいくつかの不具合があります(teapot.hファイルを見ると、新しい三角ストリップを開始するはずの場所に「-1」が埋め込まれていますが、これはテストデータのみで、私の問題には関係ありません)。

私が本当に混乱しているのは、シーンにライトを配置する方法です。私のObjective-Cコードには、{0,1,0}を含むfloat 3ベクトルがあり、それをシェーダーに渡して、光の強度を計算します。

シーン内でもライトが動いているように見えるのはなぜですか?つまり、ライトは、ティーポットがどの方向を向いていても、常に同じ側を指している、見えないスティックによってティーポットに取り付けられているかのように機能します。

これは頂点シェーダーです

attribute vec4 Position;
attribute vec4 SourceColor;
attribute vec3 Normal;

uniform mat4 Projection;
uniform mat4 Modelview;

varying vec3 normal;

void main(void) {
    normal = Normal;
    gl_Position = Projection * Modelview * Position;
}

「Position」はObj-Cコードによって設定され、オブジェクトの頂点です。「Normal」は頂点配列(VBO)からの法線のリストであり、「Projection」と「Modelview」は次のように計算されます。

(CC3GLMatrixは、上記のリンク先のGLESチュートリアルで説明されているCocos3Dライブラリからのものです)

CC3GLMatrix *projection = [CC3GLMatrix matrix];
float h = 4.0f * self.frame.size.height / self.frame.size.width;
[projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:1 andFar:100];
glUniformMatrix4fv(_projectionUniform, 1, 0, projection.glMatrix);

CC3GLMatrix *modelView = [CC3GLMatrix matrix];
[modelView populateFromTranslation:CC3VectorMake(0, 0, -7)];
[modelView scaleBy:CC3VectorMake(30, 30, 30)];

_currentRotation += displayLink.duration * 90;
[modelView rotateBy:CC3VectorMake(_currentRotation, _currentRotation, _currentRotation)];

glUniformMatrix4fv(_modelViewUniform, 1, 0, modelView.glMatrix);

そして、私はシーンに光を当てます

float lightDir[] = {1,0,1};
glUniform3fv(_lightDirUniform, 1, lightDir);

フラグメントシェーダーは次のようになります

varying lowp vec4 DestinationColor; // 1
varying highp vec3 normal;
uniform highp vec3 LightDir;


void main(void) {
    highp float intensity;
    highp vec4 color;
    intensity = dot(LightDir,normal);
    if (intensity > 0.95)
        color = vec4(1.0,0.5,0.5,1.0);
    else if (intensity > 0.5)
        color = vec4(0.6,0.3,0.3,1.0);
    else if (intensity > 0.25)
        color = vec4(0.4,0.2,0.2,1.0);
    else
        color = vec4(0.2,0.1,0.1,1.0);

    gl_FragColor = color;
}

これを解決しようとしているときに、(GLESには存在しない)'gl_LightSource'と'gl_NormalMatrix'を参照するコードに出くわしましたが、コードからシェーダーに渡さなければならない同等のものに何を入れるべきかわかりません。「アイスペース」「カメラスペース」「ワールドスペース」などへの参照は混乱を招きます。おそらくそれらの間で物事を変換する必要があることはわかっていますが、コード内またはシェーダー内の理由や方法(および場所)がわかりません。 ?)

フレームごとに光源を変更する必要がありますか?それを設定するために私が持っているコードはあまりにも単純に見えます。私は実際にティーポットを動かしているのではありません。代わりに、シーン全体を動かしています。

4

1 に答える 1

5

まず第一に、いくつかの定義:

  • ワールドスペース:あなたの全世界が定義されているスペース。慣例により、それは決して動かない静的なスペースです。

  • ビュースペース/カメラスペース/アイスペース:カメラが定義されているスペース。通常、ワールドスペースに対する位置と回転です。

  • モデル空間:モデルが定義されている空間。カメラ空間と同様に、通常はワールド空間に対する位置と回転です。

  • ライトスペース:モデルスペースと同じ

簡単な例では(そしてあなたの例では)モデル空間と世界空間は同じです。さらに、OpenGL自体にはワールドスペースの概念がありません。つまり、ワールドスペースを使用できないという意味ではありません。シーン内で複数のオブジェクトを個別に移動させたい場合に便利です。

ここで、レンダリング前にオブジェクトで行っているのは、モデルの頂点をビュースペースに変換するマトリックス、つまり「modelViewMatrix」を作成することです。

この場合の光では、少し異なります。シェーダーでの光の計算はモデル空間で行われるため、フレームごとに光の位置をモデル空間に変換する必要があります。

これは、次のような計算によって行われます。

_lightDirUniform = inverseMatrix(model) * inverseMatrix(light) * lightPosition;

ライトポジションは、光から世界へ、そしてモデル空間へと変換されます。ワールドスペースがない場合は、モデルスペースの変換を省略すれば、問題はありません。

于 2011-08-25T18:26:12.110 に答える