为什么立方体的表面呈现为透明?

时间:2012-08-08 12:34:50

标签: android opengl-es opengl-es-2.0 transparent lighting

我正在开发一个简单的程序,在屏幕上显示带有光照的立方体。我在Android设备上使用OpenGL ES 2.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);
}
}

结果图片位于

之下

enter image description here

2 个答案:

答案 0 :(得分:18)

---您图片的附加答案---

现在您发布了图片,它看起来不像alpha值。 它看起来更像是 Backface Culling 。因此,您确实为顶点做了错误的顺序。 你知道Culling吗? 请试试这个:

GLES20.glDisable(GLES20.GL_CULL_FACE); 

看起来好不好?

我认为问题在于,你的面部被“背面”绘制,而剔除是一种避免在“未被看见”时绘制面部的机制,所以如果它们的顺序错误,GL就不会渲染它们。

这可能不是网上最好的解释,但请看一下:

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

脸部顶点的“顺序”非常重要。如果顺时针或逆时针制作它们,则确定OpenGL是否认为它是渲染背面还是正面。 (参见glFrontFace(GLenum模式);

enter image description here

我从上述网站获得了该图片。

如果你的Shader认为它正在渲染背面,那么这个面就会被简单地跳过,以安全渲染你通常不需要的资源。所以你可以透过立方体看到。

您的解决方案

  1. 禁用backFaceCulling因此,每个人脸都会被渲染 - 尽管如此 这让一切变得更慢。
  2. glFrontFace(GLenum模式)来反转TheCulling algorighm(你 如果G1应该渲染正面或背面,则可以设置。但 这可能会导致同样的问题,如果你有正面和背面 您的多维数据集中的侧面,因此最佳解决方案是:
  3. 检查每个面的顶点顺序。正如大致看到的那样 我提到的网站,顶点的顺序需要相同。所以 检查它们并修理订单。
  4. 我认为最后一项工作最多,但最有希望。但如果您不确定这可能是问题,请尝试首先禁用BackfaceCulling。如果一切似乎都很好,你仍然可以解决它。

    我希望有所帮助。

    ---我的原始答案---

    那么, 通过说

    gl_FragColor = v_Color;
    
    片段着色器中的

    并在Vertex Shader中定义:

    v_Color = ambient + specular + diffuse;
    

    这意味着,您可以为片段/像素提供光照的值。包括Alpha值。 所以当你用它做一些计算时,如

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

    此因子可能会小于1.0(向量的点积) 而且,由于你将光线与光线相乘后,每个值都可能会小于1.0 最后你的光的Alpha值 - &gt;颜色变为1.0和0.0之间的值,就像光反射本身一样。 这可能会导致透明度。

    所以,如果你尝试类似的东西:

    gl_FragColor = v_Color.xyz, 1.0;
    

    或后期纹理的alpha值,一切都会好的。

答案 1 :(得分:0)

尝试添加 glEnable(GL_DEPTH_TEST)