4

出発点として、MultiTargets と呼ばれる Vuforia (バージョン 4) サンプルを使用します。これは、カメラ フィードで 3D の物理的な「立方体」を追跡し、立方体のエッジに沿って黄色のグリッド ラインで補強します。私が達成したいのは、独自のライト位置を設定することにより、テクスチャを削除し、代わりにキューブ面に拡散照明を使用することです。

これをネイティブ Android で実行したいのですが、Unity は使用したくありません。

数日間の作業と学習の困難な旅でした。あらゆる種類の OpenGL を扱うのはこれが初めてで、OpenGL ES 2.0 は初心者にとって簡単なものではありません。

そのため、キューブの上面の少し上に光源を配置しました。モデル空間でランバート係数を計算すると、適切な拡散効果が得られることがわかりました。カメラに関係なく、すべてが所定の位置に留まり、上面だけが光を受けます。

しかし、アイ スペースを使用するようになると、おかしくなり、光がカメラを追いかけているように見えます。上面だけでなく他の面も明るくなります。それがなぜなのかわかりません。テストのために、フラグメントシェーダーでピクセルの明るさをレンダリングするために光源までの距離のみを使用して、ライトの位置が期待どおりであることを確認しました。したがって、私は自分の「lightDirectionEyespace」の正確さにかなりの自信を持っています。私の唯一の説明は、法線の何かが間違っているに違いないということです。しかし、正規行列を正しく作成するための説明に従ったと思います...

助けてください!

それからもちろん、これらの拡散計算を目の空間で実行する必要があるかどうかという問題がありますか? モデル空間だけでやっても何かデメリットはありますか?後でもっと多くのモデルとライトを使用し、鏡面反射光と透明度を追加すると、理由はまだわかりませんが、おそらく機能しなくなるのではないかと思います。

私の renderFrame メソッド: (一部の変数名にはまだ「ボトル」が含まれています。これは、立方体を正しく作成した後に次に照らしたいオブジェクトです)

private void renderFrame()
{
  ShaderFactory.checkGLError("Check gl errors prior render Frame");

  // Clear color and depth buffer
  GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

  // Get the state from Vuforia and mark the beginning of a rendering section
  final State state=Renderer.getInstance().begin();

  // Explicitly render the Video Background
  Renderer.getInstance().drawVideoBackground();

  GLES20.glEnable(GLES20.GL_DEPTH_TEST);
  GLES20.glEnable(GLES20.GL_BLEND);
  GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

  // Did we find any trackables this frame?
  if(0 != state.getNumTrackableResults())
  {
    // Get the trackable:
    TrackableResult result=null;
    final int numResults=state.getNumTrackableResults();

    // Browse results searching for the MultiTarget
    for(int j=0; j < numResults; j++)
    {
      result=state.getTrackableResult(j);
      if(result.isOfType(MultiTargetResult.getClassType()))
        break;

      result=null;
    }

    // If it was not found exit
    if(null == result)
    {
      // Clean up and leave
      GLES20.glDisable(GLES20.GL_BLEND);
      GLES20.glDisable(GLES20.GL_DEPTH_TEST);

      Renderer.getInstance().end();
      return;
    }

    final Matrix44F modelViewMatrix_Vuforia=Tool.convertPose2GLMatrix(result.getPose());
    final float[] modelViewMatrix=modelViewMatrix_Vuforia.getData();

    final float[] modelViewProjection=new float[16];
    Matrix.scaleM(modelViewMatrix, 0, CUBE_SCALE_X, CUBE_SCALE_Y, CUBE_SCALE_Z); 
    Matrix.multiplyMM(modelViewProjection, 0, vuforiaAppSession
      .getProjectionMatrix().getData(), 0, modelViewMatrix, 0);

    GLES20.glUseProgram(bottleShaderProgramID);

    // Draw the cube:
    GLES20.glEnable(GLES20.GL_CULL_FACE);
    GLES20.glCullFace(GLES20.GL_BACK);

    GLES20.glVertexAttribPointer(vertexHandleBottle, 3, GLES20.GL_FLOAT, false, 0, cubeObject.getVertices());
    GLES20.glVertexAttribPointer(normalHandleBottle, 3, GLES20.GL_FLOAT, false, 0, cubeObject.getNormals());

    GLES20.glEnableVertexAttribArray(vertexHandleBottle);
    GLES20.glEnableVertexAttribArray(normalHandleBottle);

    // add light position and color
    final float[] lightPositionInModelSpace=new float[] {0.0f, 1.1f, 0.0f, 1.0f};
    GLES20.glUniform4f(lightPositionHandleBottle, lightPositionInModelSpace[0], lightPositionInModelSpace[1],
      lightPositionInModelSpace[2], lightPositionInModelSpace[3]);
    GLES20.glUniform3f(lightColorHandleBottle, 0.9f, 0.9f, 0.9f);

    // create the normalMatrix for lighting calculations
    final float[] normalMatrix=new float[16];
    Matrix.invertM(normalMatrix, 0, modelViewMatrix, 0);
    Matrix.transposeM(normalMatrix, 0, normalMatrix, 0);
    // pass the normalMatrix to the shader
    GLES20.glUniformMatrix4fv(normalMatrixHandleBottle, 1, false, normalMatrix, 0);

    // extract the camera position for lighting calculations (last column of matrix)
    // GLES20.glUniform3f(cameraPositionHandleBottle, normalMatrix[12], normalMatrix[13], normalMatrix[14]);

    // set material properties
    GLES20.glUniform3f(matAmbientHandleBottle, 0.0f, 0.0f, 0.0f);
    GLES20.glUniform3f(matDiffuseHandleBottle, 0.1f, 0.9f, 0.1f);

    // pass the model view matrix to the shader 
    GLES20.glUniformMatrix4fv(modelViewMatrixHandleBottle, 1, false, modelViewMatrix, 0);

    // pass the model view projection matrix to the shader
    // the "transpose" parameter must be "false" according to the spec, anything else is an error
    GLES20.glUniformMatrix4fv(mvpMatrixHandleBottle, 1, false, modelViewProjection, 0);

    GLES20.glDrawElements(GLES20.GL_TRIANGLES,
      cubeObject.getNumObjectIndex(), GLES20.GL_UNSIGNED_SHORT, cubeObject.getIndices());

    GLES20.glDisable(GLES20.GL_CULL_FACE);

    // disable the enabled arrays after everything has been rendered
    GLES20.glDisableVertexAttribArray(vertexHandleBottle);
    GLES20.glDisableVertexAttribArray(normalHandleBottle);

    ShaderFactory.checkGLError("MultiTargets renderFrame");
  }

  GLES20.glDisable(GLES20.GL_BLEND);
  GLES20.glDisable(GLES20.GL_DEPTH_TEST);

  Renderer.getInstance().end();
}

私の頂点シェーダー:

attribute vec4 vertexPosition;
attribute vec3 vertexNormal;

uniform mat4 modelViewProjectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 normalMatrix;

// lighting
uniform vec4 uLightPosition;
uniform vec3 uLightColor;

// material
uniform vec3 uMatAmbient;
uniform vec3 uMatDiffuse;

// pass to fragment shader
varying vec3 vNormalEyespace;
varying vec3 vVertexEyespace;
varying vec4 vLightPositionEyespace;
varying vec3 vNormal;
varying vec4 vVertex;

void main()
{
  // we can just take vec3() of a vec4 and it will take the first 3 entries
  vNormalEyespace = vec3(normalMatrix * vec4(vertexNormal, 1.0));
  vNormal = vertexNormal;
  vVertexEyespace = vec3(modelViewMatrix * vertexPosition);
  vVertex = vertexPosition;

  // light position
  vLightPositionEyespace = modelViewMatrix * uLightPosition;

  gl_Position = modelViewProjectionMatrix * vertexPosition;
}

そして私のフラグメントシェーダー:

precision highp float; //apparently necessary to force same precision as in vertex shader

//lighting
uniform vec4 uLightPosition;
uniform vec3 uLightColor;

//material
uniform vec3 uMatAmbient;
uniform vec3 uMatDiffuse;

//from vertex shader
varying vec3 vNormalEyespace;
varying vec3 vVertexEyespace;
varying vec4 vLightPositionEyespace;
varying vec3 vNormal;
varying vec4 vVertex;

void main()
{
 vec3 normalModel = normalize(vNormal);
 vec3 normalEyespace = normalize(vNormalEyespace);
 vec3 lightDirectionModel = normalize(uLightPosition.xyz - vVertex.xyz);
 vec3 lightDirectionEyespace = normalize(vLightPositionEyespace.xyz - vVertexEyespace.xyz);

 vec3 ambientTerm = uMatAmbient;
 vec3 diffuseTerm = uMatDiffuse * uLightColor;
 // calculate the lambert factor via cosine law
 float diffuseLambert = max(dot(normalEyespace, lightDirectionEyespace), 0.0);
 // Attenuate the light based on distance.
 float distance = length(vLightPositionEyespace.xyz - vVertexEyespace.xyz);
 float diffuseLambertAttenuated = diffuseLambert * (1.0 / (1.0 + (0.01 * distance * distance)));

 diffuseTerm = diffuseLambertAttenuated * diffuseTerm;

 gl_FragColor = vec4(ambientTerm + diffuseTerm, 1.0);
}
4

2 に答える 2

2

私は最終的にすべての問題を解決しました。将来の読者にとって興味深いかもしれない 2 つの問題がありました。

  1. 公式サンプル (現在の Vuforia バージョン 4) の Vuforia CubeObject クラスの法線が正しくありません。それらはすべて頂点定義の順序に対応しているわけではありません。サンプルの CubeObject を使用している場合は、法線の定義が面に正しく対応していることを確認してください。ヴフォリア失敗…

  2. 疑わしいように、私の normalMatrix は間違って構築されました。4x4 modelViewMatrix を単に逆転置することはできません。最初にそこから左上の 3x3 サブマトリックスを抽出してから、それを逆転置する必要があります。

これが私のために働くコードです:

  final Mat3 normalMatrixCube=new Mat3();
  normalMatrixCube.SetFrom4X4(modelViewMatrix);
  normalMatrixCube.invert();
  normalMatrixCube.transpose();

Android も Vuforia も 3x3 行列を反転/転置できる行列クラスを提供していないように見えるため、この男からランダムにインポートしたカスタム クラス Mat3 に依存しているため、このコード自体はそれほど有用ではありません。これは本当に私の正気を疑います。そのような基本的な問題に対して機能する唯一のコードは、カスタム マトリックス クラスに依存する必要がありますか? やり方が間違っているだけかもしれませんが・・・わかりません。

于 2015-04-09T08:31:54.567 に答える
0

これで固定機能を使用しないことに賛成です!あなたの例は、光を目の空間の位置に変換する必要があることを理解するのに非常に役立ちます. 私が見つけたすべての質問は、glLightの使用を推奨しています。

これは静的光源を使用して解決するのに役立ちましたが、光源を静的に保ちながらモデルを変換したい場合 (オブジェクトを回転させるなど)、コードに欠けているものは、元のものを追跡することです。ビューが変更されるまで、または別のモデルを持つ別のオブジェクトを描画するまで、modelview マトリックス。次のようなものです:

vLightPositionEyespace = fixedModelView * uLightPosition;

fixedModelViewrenderFrame() メソッドでどこを更新できますか。

OpenGLディスカッションボードのこのスレッドが役立ちました:)

于 2015-11-14T22:45:14.347 に答える