2

更新:このようなもののほとんどがなくなったようです。OpenGL ES 2.0 で適切にライティングを行う方法は、独自のシェーダーを作成し、任意の方法で法線を渡し、シェーダーでライティングを行うことだと思います。特に、OpenGL ES 2.0 のドキュメントによると、glMaterialFv、glLightFv などはもうありません (glNormalPointer とその友人は言うまでもありません)。ただし、ドロップインの代替品としてそのままでは機能しないようです。ただし、GLKit には、OpenGL ES 1.1 のライティング機能を模倣する標準シェーダーがいくつか用意されています。

誰かがさらに情報を持っていれば、私はそれを感謝しますが、それが答えだと思います.


私は OpenGL を初めて使用するので、事前に混乱をお詫びします。iOS で OpenGL ES 2.0 を使用しています。インターネットで見つけた例の多くは時代遅れのようです。たとえば、glBegin(GL_POLYGON) 方法論は廃止されたようです。そのため、古い例のほとんどがそうであるように、glNormal3f を使用できないと思います。

Ray Wenderlich の素敵なチュートリアルから始めて、作成中のゲームに統合し、いくつかの部屋の基本的なジオメトリを正常にレンダリングしました。今、私は照明を追加したいだけです。何が機能していないのかわかりませんが、法線に関係していると思われます。

私はGL_LIGHT0を有効にしようと混乱した試みをしまし.

//* Some attempts at lighting
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat mat_shininess[] = { 50.0 };
GLfloat light0_position[] = { 0.0, 0.0, 7.99, 0.0 };
GLfloat light0_ambience[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat light0_specular[] = { 1.0, 1.0, 1.0, 1.0 };

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambience);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glShadeModel(GL_SMOOTH);

glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
//*/
glEnable(GL_DEPTH_TEST);

VBOS を使用して、頂点の位置と色を単純なシェーダーのペアに渡しています。以下はチュートリアルからです。

_positionSlot = glGetAttribLocation(programHandle, "Position");
_colorSlot = glGetAttribLocation(programHandle, "SourceColor");

次に、render: メソッドで (位置と色の位置の間に法線を含めるように Vertex 構造を変更しました)。

glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE,
                      sizeof(Vertex), 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE,
                      sizeof(Vertex), (GLvoid*) (sizeof(float) * 6));

照明を除いて、これはすべて非常にうまく機能します。法線を計算して再計算しました。X 軸と Y 軸に平行な垂直の長方形の壁の場合、これは簡単なことです。これらは、GL_ARRAY_BUFFER にバインドされたバッファーの一部であり、位置と色の情報も含まれています。

glNormalPointer を使用するために繰り返し試みました。

glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), (GLvoid*)(sizeof(float)*3));

チュートリアルの頂点構造は次のようになります。

typedef struct {
    float Position[3];
    float Normal[3];
    float Color[4];
} Vertex;

上記の呼び出しは成功しますが、照明効果は表示されません。一部の情報源は、法線にも glVertexAttribPointer を使用する必要があることを示唆しています。このために、チュートリアルの頂点シェーダーを次のように変更しました。

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

varying vec4 DestinationColor;

uniform mat4 Projection;
uniform mat4 Modelview;

void main(void) {
    DestinationColor = SourceColor;
    gl_Position = Projection * Modelview * Position;
}

そして、そのNormal変数を使用できるようになると思った呼び出しを追加しました(OpenGLがそれをどうするかをどのように知っているかはわかりませんが):

// just before glLinkProgram()
glBindAttribLocation(programHandle, 1, "Normal");

GLuint _normalSlot = glGetAttribLocation(programHandle, "Normal");

glVertexAttribPointer(_normalSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(float)*3));

GLSL ファイルのどこに Normal 変数を配置しても、glBindAttribLocation はその属性に対して常に失敗し、glGetAttribLocation は常にその属性に対して -1 を返します。(glBindAttribLocation を使用して SourceColor 属性の場所を正常に変更できますが、Normal は受け入れられません。) 以前のバージョンの OpenGL/GLSL には gl_Normal 変数がありましたが、明らかにそれ以上はありません。

私は途方に暮れていて、私に起こることは何でも試し続けています. 私の次のステップは、glInterleavedArrays です。可動部分が多すぎて、問題を見つけるのが大変です。私の法線は最初から大丈夫だったのかもしれませんが、代わりにライトに問題があります。照明以外に、法線が正しいことを確認する方法はありますか? または、法線が間違っている場合、ライトから何かを見ることができるはずですか?

したがって、この投稿の長さと混乱をお詫びしますが、この状況で法線がどのように指定されているかについての詳細な説明は大歓迎です。OpenGL ES 2.0 では状況が異なるという意見に繰り返し出くわしますが、詳細な例はありません。前もって感謝します。

4

1 に答える 1

7

それを投稿して以来、私は多くのことを学び、それが本当に適切に答えられたことがないことに気付きました. 更新は正しいですが、非常に適切な説明をまだどこにも見たことがないので、もう少し説明する価値があります。これは簡潔であり、詳細で具体的な例が役立つ可能性がありますが、うまくいけば主要なポイントに到達します。

通常は、法線ベクトルを VBO の頂点属性のトリプレットとして送信します。テクスチャを操作している場合は、頂点の 3 つの空間座標 (xyz)、頂点での法線ベクトルの 3 つのコンポーネント、4 つの色コンポーネント (rgba) とテクスチャ座標の 2 つのコンポーネントがそこにあります。照明モデルによっては、ハードウェアの制限に応じて、GL_MAX_VERTEX_ATTRIBS まで、独自の定義のより多くの属性を使用できます。

すべての照明計算を行うのはあなたなので、構造体をどのようにレイアウトするかはあなた次第です。これらは OpenGL ES 2.0 にとっては何の意味もありません。各ピクセルの色を計算する GLSL 頂点およびフラグメント シェーダー プログラムをビルドする必要があります。定義する属性ベクトルごとに glVertexAttribPointer を 1 回呼び出すと、指定した名前の頂点シェーダーに属性ベクトルが渡されます。変数を使用して、頂点シェーダーからフラグメント シェーダーに渡すことができます。フラグメント シェーダーの属性値は、線形補間によって決定されます。

通常、追加のライティング パラメータを含む多数のユニフォームも渡します。ライトの位置や強度、または光沢などのマテリアル プロパティなど、頂点ごとに変化しないものにはユニフォームを使用します。モデル内で変化するものには頂点属性を使用します。

魔法のほとんどは、フラグメント シェーダーで発生するはずです。法線ベクトルを使用する最も単純な照明効果は拡散照明で、これは次のようなフラグメント シェーダーで生成できます。

varying lowp vec4 FragmentPosition;
varying lowp vec3 FragmentNormal;
varying lowp vec4 FragmentColor;

uniform lowp vec3 LightPosition;
uniform lowp float LightIntensity;

void main() {
  // .xyz makes a vec3 out of a vec4
  lowp vec3 inLightFrame = FragmentPosition.xyz - LightPosition;
  lowp float distance = length(inLightFrame);
  // inverse square dependence of intensity
  gl_FragColor = max(0.0, -dot(inLightFrame, normalize(FragmentNormal))) 
    / distance / distance * LightIntensity * FragmentColor;
}

これは、LightPosition 均一ベクトルがソフトウェアと次のような頂点シェーダーで設定されていることを前提としています。

attribute vec4 Position;
attribute vec3 Normal;
attribute vec4 Color;

varying vec4 FragmentPosition;
varying vec4 FragmentNormal;
varying vec4 FragmentColor;

void main() {
    FragmentPosition = Position;
    FragmentNormal = normalize(Normal);
    FragmentColor = Color;
}

さらに、次のように、位置、法線、および色を定義する glVertexAttribPointer への呼び出しがいくつかあります。

glVertexAttribPointer(glGetAttribLocation(programHandle, "Position"), 3, GL_FLOAT, 
  GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*0));
glVertexAttribPointer(glGetAttribLocation(programHandle, "Normal"), 3, GL_FLOAT, 
  GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*3));
glVertexAttribPointer(glGetAttribLocation(programHandle, "Color"), 4, GL_FLOAT, 
  GL_FALSE, sizeof(Vertex), (GLvoid*(sizeof(float)*6));

これは、次のような構造体を想定しています

typedef struct {
  float Position[3];
  float Normal[3];
  GLubyte Color[4];
} Vertex;

この簡単な例では、単位強度の白色光を想定しています。より多くのライトが必要になる場合があり、それぞれに赤、緑、青の強度を指定したいと思うでしょう。この例では、マテリアル プロパティ、アンビエント ライティング、スペキュラー ライティング、およびシャドウを無視しています。しかし、これは OpenGL ES 2.0 で法線ベクトルを処理する方法です。

于 2014-02-26T15:03:00.877 に答える