我正在开发一个简单的程序,在屏幕上显示带有光照的立方体。我在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);
}
}
结果图片位于
之下
答案 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模式); )
我从上述网站获得了该图片。
如果你的Shader认为它正在渲染背面,那么这个面就会被简单地跳过,以安全渲染你通常不需要的资源。所以你可以透过立方体看到。
您的解决方案
我认为最后一项工作最多,但最有希望。但如果您不确定这可能是问题,请尝试首先禁用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)