我正在开发一个简单的程序,它在屏幕上显示一个带有照明的立方体。我在 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);
}
}
结果图如下
最佳答案
--- 对你的图片的额外回答---
既然您发布了图片,它看起来不像是 alpha 值。 它看起来更像背面剔除。所以您肯定为顶点设置了错误的顺序。 你知道剔除吗? 请试试这个:
GLES20.glDisable(GLES20.GL_CULL_FACE);
它看起来比吗?
我认为问题是,你的脸被绘制在“背面”,而 Culling 是一种避免在“看不见”时绘制人脸的机制,所以如果它们的顺序错误,GL 不会渲染它们。
这可能不是网上最好的解释,但请看这里:
http://www.altdevblogaday.com/2011/08/03/backface-culling-101/
你脸上顶点的“顺序”很重要。如果你使它们顺时针或逆时针旋转,则确定 OpenGL 认为它是在渲染背面还是正面。 (参见 glFrontFace(GLenum 模式);)
我从上述网站获得了该图片。
如果您的着色器认为它正在渲染背面,则该面会简单地跳到您通常不需要的安全渲染资源。所以你可以看穿立方体。
你的解决方案是
- 禁用 backFaceCulling 所以每张脸都会被渲染 - 即使 这让一切变得更慢。
- 用 glFrontFace(GLenum 模式) 反转剔除算法(你 可以设置 Gl 应该渲染正面还是背面)。但 如果你有正面和背面,这可能会导致同样的问题 立方体的侧面,所以最好的解决方案是:
- 检查每个面的顶点顺序。 我提到的网站,顶点的顺序需要相同。所以 检查它们并确定订单。
我认为最后一个最有效,但也是最有前途的。但如果您不确定这可能是问题所在,请先尝试禁用 BackfaceCulling。如果一切看起来都很好,您仍然可以修复它。
希望对您有所帮助。
---我原来的答案---
嗯, 通过说
gl_FragColor = v_Color;
在 fragment 着色器中和之前在顶点着色器中定义:
v_Color = ambient + specular + diffuse;
这意味着,您为 fragment/像素赋予光的值。包括阿尔法值。 所以当你用它做一些计算时,比如
vec4 diffuseP = vec4(max(dot(L, N), 0.0));
这个因子可能变得小于 1.0(向量的点积) 因为你把这个乘以你的光,每个值都可能变得小于 1.0 最后,您的光的 Alpha 值 -> 颜色变成了 1.0 到 0.0 之间的值,就像光反射本身一样。 这可能会导致透明度。
所以如果你想尝试这样的事情:
gl_FragColor = v_Color.xyz, 1.0;
或者后面纹理的alpha值,一切都会好的。
关于android - 为什么立方体的表面呈现为透明的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11864636/