2

画面に立方体を照明で表示する簡単なプログラムを開発しています。AndroidデバイスでOpenGLES2.0を使用しています。ただし、立方体の底面のみが不透明です。他のサーフェスは透明に見えます(照明が原因だと思います。照明の使用をやめると、すべてのサーフェスが不透明に見えます)。そのため、背後のサーフェスを見ることができます。

これが私の立方体の頂点です:

    static float vertexs[] = { // in counterclockwise order:
    // front
    -0.5f, -0.5f, 0.5f,
     0.5f, -0.5f, 0.5f,
    -0.5f, 0.5f, 0.5f,
     0.5f, 0.5f, 0.5f,
    // back
    -0.5f, -0.5f, -0.5f,
     0.5f, -0.5f, -0.5f,
    -0.5f, 0.5f, -0.5f,
     0.5f, 0.5f, -0.5f,
    // left
    -0.5f, -0.5f, 0.5f,
    -0.5f, -0.5f, -0.5f,
    -0.5f, 0.5f, 0.5f,
    -0.5f, 0.5f, -0.5f,
    // right  
     0.5f, -0.5f, 0.5f,
     0.5f, -0.5f, -0.5f,
     0.5f, 0.5f, 0.5f,
     0.5f, 0.5f, -0.5f,  
    // up  
    -0.5f, 0.5f, 0.5f,
     0.5f, 0.5f, 0.5f,
    -0.5f, 0.5f, -0.5f,
     0.5f, 0.5f, -0.5f,
    // bottom  
    -0.5f, -0.5f, 0.5f,
     0.5f, -0.5f, 0.5f,
    -0.5f, -0.5f, -0.5f,
     0.5f, -0.5f, -0.5f
};

これが私が使用している法線です(問題はここにありますか?):

    static float normals[] = {
    // front
    -1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, 1.0f,
    -1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f,
    // back
    -1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, -1.0f,
    -1.0f, 1.0f, -1.0f,
     1.0f, 1.0f, -1.0f,
    // left
    -1.0f, -1.0f, 1.0f,
    -1.0f, -1.0f, -1.0f,
    -1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, -1.0f,
    // right  
     1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, -1.0f,
     1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, -1.0f,  
    // up  
    -1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f,
    -1.0f, 1.0f, -1.0f,
     1.0f, 1.0f, -1.0f,
    // bottom  
    -1.0f, -1.0f, 1.0f,
     1.0f, -1.0f, 1.0f,
    -1.0f, -1.0f, -1.0f,
     1.0f, -1.0f, -1.0f
};

シェーダーは以下のとおりです。

private final String vertexShaderCode =
        // Light
        "uniform vec4 u_LightAmbient;\n" + 
        "uniform vec4 u_LightDiffuse;\n" + 
        "uniform vec4 u_LightSpecular;\n" + 
        "uniform vec4 u_LightPos;\n" + 

        //Material
        "uniform vec4 u_MaterialAmbient;\n" + 
        "uniform vec4 u_MaterialDiffuse;\n" + 
        "uniform vec4 u_MaterialSpecular;\n" + 
        "uniform float u_MaterialShininess;\n" + 

        // Matrices
        "uniform mat4 u_ModelViewMatrix;\n" +
        "uniform mat4 u_ProjectionMatrix;\n" +
        "uniform mat4 u_NormalMatrix;\n" +

        // vertecies
        "attribute vec4 a_Position;\n" +
        "attribute vec3 a_Normal;\n" +

        "varying vec4 v_Color;\n" +

        "void main() {\n" +
            "vec4 ambient = u_LightAmbient * u_MaterialAmbient;\n" + 

            "vec3 P = vec3(u_ModelViewMatrix * a_Position);\n" + 
            "vec3 L = normalize(vec3(u_LightPos) - P);\n" + 
            "vec3 N = normalize(mat3(u_NormalMatrix) * a_Normal);\n" +
            "vec4 diffuseP = vec4(max(dot(L, N), 0.0));\n" + 
            "vec4 diffuse = diffuseP * u_LightDiffuse * u_MaterialDiffuse;\n" +

            "vec3 S = normalize(L + vec3(0.0, 0.0, 1.0));\n" + 
            "float specularP = pow(max(dot(N,S), 0.0), u_MaterialShininess);\n" +
            "vec4 specular = specularP * u_LightSpecular * u_MaterialSpecular;\n" + 

            //hyouji sareru iro
            "v_Color = ambient + specular + diffuse;\n" + 

            //position
            "gl_Position = u_ProjectionMatrix * u_ModelViewMatrix * a_Position;\n" +
        "}\n";

private final String fragmentShaderCode =
        "precision mediump float;\n" +

        "varying vec4 v_Color;\n" +

        "void main() {\n" +
            "gl_FragColor = v_Color;\n" +
        "}\n";    

描画機能は以下のとおりです。

public Cube() {
    // initialize vertex byte buffer for shape coordinates
    ByteBuffer bb = ByteBuffer.allocateDirect(vertexs.length * 4);
    ByteBuffer nb = ByteBuffer.allocateDirect(normals.length * 4);

    // use the device hardware's native byte order
    bb.order(ByteOrder.nativeOrder());
    nb.order(ByteOrder.nativeOrder());

    // create a floating point buffer from the ByteBuffer
    vertexBuffer = bb.asFloatBuffer();
    normalBuffer = nb.asFloatBuffer();

    // add the coordinates to the FloatBuffer
    vertexBuffer.put(vertexs);
    float div = (float)Math.sqrt(3);
    for(int i = 0; i < normals.length; i++){
        normals[i] /= div;
    }
    normalBuffer.put(normals);

    // set the buffer to read the first coordinate
    vertexBuffer.position(0);
    normalBuffer.position(0);

    // prepare shaders and OpenGL program
    int vertexShader = MyRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = MyRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

    mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
    GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
    GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
    GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
}

public void draw(float[] mvMatrix, float[] pMatrix) {
    // Add program to OpenGL environment
    GLES20.glUseProgram(mProgram);

    // get handle to vertex shader's aPosition member
    positionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position");
    normalHandle = GLES20.glGetAttribLocation(mProgram,  "a_Normal");
    GLES20.glEnableVertexAttribArray(positionHandle);
    GLES20.glVertexAttribPointer(positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

    GLES20.glEnableVertexAttribArray(normalHandle);
    GLES20.glVertexAttribPointer(normalHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, normalBuffer);

    modelViewMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_ModelViewMatrix");
    GLES20.glUniformMatrix4fv(modelViewMatrixHandle, 1, false, mvMatrix, 0);        

    projectionMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_ProjectionMatrix");
    GLES20.glUniformMatrix4fv(projectionMatrixHandle, 1, false, pMatrix, 0);

    normalMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_NormalMatrix");
    float[] tmp = new float[16];
    float[] normalMatrix = new float[16];
    Matrix.invertM(tmp, 0, mvMatrix, 0);
    Matrix.transposeM(normalMatrix, 0, tmp, 0);
    GLES20.glUniformMatrix4fv(normalMatrixHandle, 1, false, normalMatrix, 0);

    lightAmbientHandle = GLES20.glGetUniformLocation(mProgram, "u_LightAmbient");
    GLES20.glUniform4f(lightAmbientHandle, 0.2f, 0.2f, 0.2f, 1.0f);
    lightDiffuseHandle = GLES20.glGetUniformLocation(mProgram, "u_LightDiffuse");
    GLES20.glUniform4f(lightDiffuseHandle, 0.5f, 0.5f, 0.5f, 1.0f);
    lightSpecularHandle = GLES20.glGetUniformLocation(mProgram, "u_LightSpecular");
    GLES20.glUniform4f(lightSpecularHandle, 0.0f, 0.0f, 0.0f, 1.0f);
    lightPosHandle = GLES20.glGetUniformLocation(mProgram, "u_LightPos");

    materialAmbientHandle = GLES20.glGetUniformLocation(mProgram, "u_MaterialAmbient");
    materialDiffuseHandle = GLES20.glGetUniformLocation(mProgram, "u_MaterialDiffuse");
    materialSpecularHandle = GLES20.glGetUniformLocation(mProgram, "u_MaterialSpecular");
    materialShininessHandle = GLES20.glGetUniformLocation(mProgram, "u_MaterialShininess");

    // Front
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

    // Back
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 4, 4);

    // Left
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 8, 4);

    // Right
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 12, 4);

    // Top
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 16, 4);

    // Bottom
    setMaterial(0.0f, 1.0f, 0.0f, 1.0f);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 20, 4);

    // Disable vertex array
    GLES20.glDisableVertexAttribArray(positionHandle);
}    

private void setMaterial(float r, float g, float b, float a){
    GLES20.glUniform4f(materialAmbientHandle, r, g, b, a);

    GLES20.glUniform4f(materialDiffuseHandle, r, g, b, a);

    GLES20.glUniform4f(materialSpecularHandle, r, g, b, a);

    GLES20.glUniform4f(materialShininessHandle, r, g, b, a);
}
}

結果の画像は以下のとおりです

ここに画像の説明を入力してください

4

2 に答える 2

19

---あなたの写真への追加の回答---

写真を投稿したので、アルファ値のようには見えません。これは、Backface Cullingに非常によく似ています。したがって、頂点の順序を間違えたことは確かです。カリングについて知っていますか?これを試してください:

GLES20.glDisable(GLES20.GL_CULL_FACE); 

見た目はもっと良いですか?

問題は、顔が「裏側」に描画され、カリングは「見えない」ときに顔が描画されないようにするメカニズムであるため、順序が間違っているとGLがレンダリングしないことだと思います。

それはおそらくネット上で最良の説明ではありませんが、ここを見てください:

http://www.altdevblogaday.com/2011/08/03/backface-culling-101/

顔の頂点の「順序」は重要です。それらを時計回りまたは反時計回りに作成した場合、OpenGLが裏側または表側のどちらをレンダリングしていると考えるかを決定します。(glFrontFace(GLenumモード);を参照

ここに画像の説明を入力してください

その画像は、前述のWebサイトから入手しました。

シェーダーが背面をレンダリングしていると判断した場合、この面はスキップされて、通常は必要のない安全なレンダリングリソースになります。だからあなたは立方体を通して見ることができます。

あなたの解決策は

  1. backFaceCullingを無効にするにはすべての面がレンダリングされますが、すべてが遅くなります。
  2. glFrontFace(GLenumモード)を使用してTheCullingアルゴリズムを反転するには(Glが前面または背面のどちらをレンダリングするかを設定できます)。ただし、立方体に前面と背面がある場合、これは同じ問題につながる可能性があるため、最善の解決策は次のとおりです。
  3. 面ごとの頂点の順序を確認します。前述のWebサイトで大まかに見られるように、頂点の順序は同じである必要があります。したがって、それらを確認して順序を修正してください。

最後のものが最も効果的ですが、最も有望だと思います。ただし、これが問題であるかどうかわからない場合は、最初にBackfaceCullingを無効にしてみてください。すべてが正常であると思われる場合でも、修正できます。

お役に立てば幸いです。

---私の最初の答え---

さて、言うことによって

gl_FragColor = v_Color;

フラグメントシェーダーで、頂点シェーダーで以前に定義しました。

v_Color = ambient + specular + diffuse;

つまり、フラグメント/ピクセルにライトの値を指定します。アルファ値を含みます。だからあなたがそれでいくつかの計算をしているとき

vec4 diffuseP = vec4(max(dot(L, N), 0.0));

この係数は1.0(ベクトルの内積)未満になる可能性があります。これに光を掛けた後、すべての値が1.0未満になる可能性があります。最終的に、光のアルファ値->色は次のようになります。光の反射自体と同様に、1.0〜0.0の値。これにより、透明性が生じる可能性があります。

したがって、次のようなことを試してみると、次のようになります。

gl_FragColor = v_Color.xyz, 1.0;

または後のテクスチャのアルファ値、すべてがうまくいくでしょう。

于 2012-08-08T20:57:05.160 に答える
0

glEnable(GL_DEPTH_TEST)を追加してみてください

于 2021-07-06T20:36:07.537 に答える