我最近开始用OpenGL ES 2.0编码,并遇到了一个(对我来说)相当具有挑战性的问题。这是我的第一次尝试,流式VBO缓冲对象动态(至少这是我认为我正在做的)。我的应用程序应该用特定的颜色画两个三角形,但它们只是黑色的。我想可能是我混淆了一些GL命令,但我找不到问题。
下面是GLRenderer类的一个片段:
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
/* Draw black background */
GLES20.glClearColor(0.8f, 0.6f, 0.4f, 1.0f);
{...}
viewMatrix = camera.getMatrix();
/* Create and compile shaders */
int vertexShaderHandle = loadShader(vertexShader, GLES20.GL_VERTEX_SHADER);
int fragmentShaderHandle = loadShader(fragmentShader, GLES20.GL_FRAGMENT_SHADER);
/* Create and link program */
programHandle = loadProgram(vertexShaderHandle, fragmentShaderHandle);
/* Set references for drawing input */
mVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "uMVPMatrix");
positionHandle = GLES20.glGetAttribLocation(programHandle, "vPosition");
colorHandle = GLES20.glGetUniformLocation(programHandle, "vColor");
checkGlError("glGetUniformLocation");
/* Create 2 Triangles for testing purposes. */
final float[] triangle1Vertex = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,};
final float[] triangle2Vertex = { -1.0f, 1.0f, 0.0f,
-1.0f, -0.5f, 0.0f,
-0.5f, 1.0f, 0.0f};
/* Color */
final float[] color = { 0.63671875f, 0.76953125f, 0.22265625f, 0.0f};
/* Init triangles */
Triangle triangle1 = new Triangle(triangle1Vertex, color);
Triangle triangle2 = new Triangle(triangle2Vertex, color);
/* Add triangles to be drawn */
TriangleCollection.add(triangle1);
TriangleCollection.add(triangle2);
/* Create buffer objects in GPU, 2 buffers are needed */
final int buffers[] = new int[2];
GLES20.glGenBuffers(2, buffers, 0); //Generate GPUSide Buffers
/* Allocate GPU memory space for vertices */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(
GLES20.GL_ARRAY_BUFFER,
TriangleCollection.MAX_NUMBER_OF_VERTICES * TriangleCollection.BYTES_PER_FLOAT,
TriangleCollection.publishVerticesBuffer(),
GLES20.GL_STREAM_DRAW);
checkGlError("glBufferData");
/* Allocate GPU memory space for color data */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(
GLES20.GL_ARRAY_BUFFER,
TriangleCollection.NUMBER_OF_COLOR_ELEMENTS * TriangleCollection.BYTES_PER_FLOAT,
TriangleCollection.publishColorBuffer(),
GLES20.GL_STREAM_DRAW);
checkGlError("glBufferData");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* Reference the GPU Buffers */
triangleVerticesIdx = buffers[0];
triangleColorsIdx = buffers[1];
GLES20.glFlush();
startTime = System.nanoTime();
}
@Override
public void onDrawFrame(GL10 unused) {
FloatBuffer vertices = TriangleCollection.publishVerticesBuffer();
FloatBuffer colors = TriangleCollection.publishColorBuffer();
/* Upload triangle data */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleVerticesIdx);
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, vertices.capacity() * Triangle.BYTES_PER_FLOAT, vertices);
checkGlError("glBufferSubData");
/* Upload color data */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleColorsIdx);
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, colors.capacity() * Triangle.BYTES_PER_FLOAT, colors);
checkGlError("glBufferSubData");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* Clear Screen */
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(programHandle);
/*Matrix calculations */
Matrix.setIdentityM(modelMatrix, 0);
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
GLES20.glUniformMatrix4fv(mVPMatrixHandle, 1, false, mvpMatrix, 0);
checkGlError("glUniformMatrix4fv");
/* Pass the position information */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleVerticesIdx);
checkGlError("glBindBuffer");
GLES20.glEnableVertexAttribArray(positionHandle);
checkGlError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(positionHandle, Triangle.COORDINATES_PER_VERTEX, GLES20.GL_FLOAT, false, 0, 0);
checkGlError("glVertexAttribPointer");
/* Pass the color information */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleColorsIdx);
checkGlError("glBindBuffer");
GLES20.glEnableVertexAttribArray(colorHandle);
checkGlError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(colorHandle, TriangleCollection.COLOR_SIZE_FLOAT, GLES20.GL_FLOAT, false, 0, 0);
checkGlError("glVertexAttribPointer");
/* Clear currently bound buffer */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
checkGlError("glBindBuffer");
//Draw
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, TriangleCollection.MAX_NUMBER_OF_VERTICES);
checkGlError("glDrawArrays");
}
这段代码运行没有错误,我已经在调试模式下检查了FloatBuffers。它们包含所需的信息。
我也很感谢任何关于我的绘画/渲染管道的一般概念的反馈。我不确定这是否是一个好的解决方案,但至少我在Nexus 5上获得了30 FPS @8000个三角形。
编辑1
经过一些测试,我得到了以下结果:
- 根据日志,我正在使用EGL 1.4。我现在不打算使用OpenGL ES 3.0(如果这是可能的)。
2。用一个常量替换碎片着色器的vColor元素是有效的。三角形为红色:
final String fragmentShader =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vec4(1.0,0.0,0.0,1.0);" +
"}";
当使用普通的非静态片段着色器时,删除这部分代码绝对不会改变:
/*传递颜色信息*/
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleColorsIdx); checkGlError("glBindBuffer"); GLES20.glEnableVertexAttribArray(colorHandle); checkGlError("glEnableVertexAttribArray"); GLES20.glVertexAttribPointer(colorHandle, TriangleCollection.COLOR_SIZE_FLOAT, GLES20.GL_FLOAT, false, 0, 0); checkGlError("glVertexAttribPointer");
移除colorHandle = GLES20。glGetUniformLocation (programHandle"vColor");from surfaceCreated()正常工作,不绘制三角形
编辑2
我仍然找不到我的错误。虽然使用glGetUniformLocation适用于一个三角形,但它不适用于许多三角形。我将项目简化为一个简单的测试应用程序,以便展示完整的代码:public class MainActivity extends Activity {
private MySurfaceView mySurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Create SurfaceView and add it to Activity */
MySurfaceView = new MySurfaceView(this);
setContentView(mySurfaceView);
}
@Override
protected void onPause() {
super.onPause();
MySurfaceView.onPause();
}
@Override
protected void onResume() {
super.onResume();
MySurfaceView.onResume();
}
}
public class MySurfaceView extends GLSurfaceView {
private final GLRenderer renderer;
/**
* Creates the SurfaceView
* @param context Application context
*/
public MySurfaceView(Context context) {
super(context);
setEGLConfigChooser(8, 8, 8, 8, 16, 0);
/* OpenGl Version GLES 2.0 min */
setEGLContextClientVersion(2);
/* Add Renderer for drawing */
renderer = new GLRenderer();
setRenderer(renderer);
}
}
public class GLRenderer implements GLSurfaceView.Renderer {
/* Frame Counter */
private int nbFrame = 0;
private long startTime;
/* Vertex Shader */
final String vertexShader =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
/* Fragment Shader*/
final String fragmentShader =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
/* Reference for the program */
private int programHandle;
/* References to pass data into shader */
private int mVPMatrixHandle, positionHandle, colorHandle;
/* Projection matrix, used for projection 3D scene to 2D viewport. */
private float[] projectionMatrix = new float[16];
/* Model matrix used for moving Models around */
private float[] modelMatrix = new float[16];
/* Combined Matrix */
private float[] mvpMatrix = new float[16];
/* Matrix of the camera position and perspective */
private float[] viewMatrix;
/* Reference to the buffer of the triangle vertices in the GPU DDR */
private int triangleVerticesIdx;
/* Reference to the buffer of the triangle colors in the GPU DDR */
private int triangleColorsIdx;
/**
* Load shader
*/
static int loadShader(final String shader, int type) {
int shaderHandle = GLES20.glCreateShader(type);
if (shaderHandle != 0) {
GLES20.glShaderSource(shaderHandle, shader);
checkGlError("glShaderSource");
GLES20.glCompileShader(shaderHandle);
checkGlError("glCompileShader");
final int[] compileStatus = new int[1];
GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
GLES20.glDeleteShader(shaderHandle);
shaderHandle = 0;
}
}
if (shaderHandle == 0) {
throw new RuntimeException("Error while creating shader");
}
return shaderHandle;
}
/**
* Loads a OpenGL ES 2.0 program with a vertex and a fragment shader.
* @param vertexShader
* @param fragmentShader
* @return
*/
public static int loadProgram(int vertexShader, int fragmentShader) {
int programHandle;
/* Load program */
programHandle = GLES20.glCreateProgram();
if (programHandle != 0) {
/* Bind shaders to program */
GLES20.glAttachShader(programHandle, vertexShader);
checkGlError("glAttachShader");
GLES20.glAttachShader(programHandle, fragmentShader);
checkGlError("glAttachShader");
/* Bind Attributes */
GLES20.glBindAttribLocation(programHandle, 0, "vPosition");
checkGlError("glBindAttribLocation");
GLES20.glBindAttribLocation(programHandle, 1, "vColor");
checkGlError("glBindAttribLocation");
/* Link shaders */
GLES20.glLinkProgram(programHandle);
/* Get link status... */
final int[] linkStatus = new int[1];
GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
GLES20.glDeleteProgram(programHandle);
programHandle = 0;
}
}
if (programHandle == 0) {
throw new RuntimeException("Error creating program.");
}
return programHandle;
}
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
/* Draw black background */
GLES20.glClearColor(0.8f, 0.6f, 0.4f, 1.0f);
/* Create Camera and define values -> calculate Matrix */
Camera camera = new Camera();
camera.setPosition(0.0f, 0.0f, 1.5f);
camera.setPerspective(0.0f, 0.0f, -5.0f);
camera.setUpVector(0.0f, 1.0f, 0.0f);
camera.setMatrix();
viewMatrix = camera.getMatrix();
/* Create and compile shaders */
int vertexShaderHandle = loadShader(vertexShader, GLES20.GL_VERTEX_SHADER);
int fragmentShaderHandle = loadShader(fragmentShader, GLES20.GL_FRAGMENT_SHADER);
/* Create and link program */
programHandle = loadProgram(vertexShaderHandle, fragmentShaderHandle);
/* Set references for drawing input */
mVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "uMVPMatrix");
positionHandle = GLES20.glGetAttribLocation(programHandle, "vPosition");
colorHandle = GLES20.glGetUniformLocation(programHandle, "vColor");
checkGlError("glGetUniformLocation");
/* Create 2 Triangles for testing purposes. */
final float[] triangle1Vertex = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,};
/* Color */
final float[] color = { 0.0f, 0.76953125f, 0.22265625f, 1.0f,
0.0f, 0.76953125f, 0.22265625f, 1.0f,
0.0f, 0.76953125f, 0.22265625f, 1.0f};
/* Create Vertex Buffer */
ByteBuffer bb = ByteBuffer.allocateDirect(triangle1Vertex.length*4);
bb.order(ByteOrder.nativeOrder());
FloatBuffer vert1 = bb.asFloatBuffer();
vert1.put(triangle1Vertex);
vert1.position(0);
/* Create Color Buffer */
ByteBuffer bb1 = ByteBuffer.allocateDirect(color.length*4);
bb1.order(ByteOrder.nativeOrder());
FloatBuffer color1 = bb1.asFloatBuffer();
color1.put(color);
color1.position(0);
/* Create buffer objects in GPU, 2 buffers are needed */
final int buffers[] = new int[2];
GLES20.glGenBuffers(2, buffers, 0); //Generate GPUSide Buffers
/* Allocate GPU memory space for vertices */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(
GLES20.GL_ARRAY_BUFFER,
1*9*4,// 9 floats for triangle and 4 bytes per float
vert1,
GLES20.GL_STATIC_DRAW);
checkGlError("glBufferData");
/* Upload FPU memory space for color data */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
GLES20.glBufferData(
GLES20.GL_ARRAY_BUFFER,
1*3*4*4,
color1,
GLES20.GL_STATIC_DRAW);
checkGlError("glBufferData");
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* Reference the GPU Buffers */
triangleVerticesIdx = buffers[0];
triangleColorsIdx = buffers[1];
GLES20.glFlush();
startTime = System.nanoTime();
}
/**
* Not needed. Device must be in landscape mode all the time.
*
* @param unused -
*/
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
/* Define Viewport */
GLES20.glViewport(0, 0, width, height);
/* Create perspective projection */
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 10.0f;
Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far);
}
@Override
public void onDrawFrame(GL10 unused) {
/* Measure FPS */
nbFrame++;
if(System.nanoTime()-startTime >= 1000000000) {
Log.d("FPS", Integer.toString(nbFrame));
nbFrame = 0;
startTime = System.nanoTime();
}
/* Clear Screen */
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(programHandle);
/*Matrix calculations */
Matrix.setIdentityM(modelMatrix, 0);
Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
GLES20.glUniformMatrix4fv(mVPMatrixHandle, 1, false, mvpMatrix, 0);
checkGlError("glUniformMatrix4fv");
/* Pass the position information */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleVerticesIdx);
checkGlError("glBindBuffer");
GLES20.glEnableVertexAttribArray(positionHandle);
checkGlError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 0, 0);
checkGlError("glVertexAttribPointer");
/* Pass the color information */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, triangleColorsIdx);
checkGlError("glBindBuffer");
GLES20.glEnableVertexAttribArray(colorHandle);
checkGlError("glEnableVertexAttribArray");
GLES20.glVertexAttribPointer(colorHandle, 4, GLES20.GL_FLOAT, false, 0, 0);
checkGlError("glVertexAttribPointer");
/* Clear currently bound buffer */
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
checkGlError("glBindBuffer");
//Draw
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 1*9);
checkGlError("glDrawArrays");
}
/**
* Utility method for debugging OpenGL calls. Provide the name of the call
* just after making it:
*
* <pre>
* mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
* MyGLRenderer.checkGlError("glGetUniformLocation");</pre>
*
* If the operation is not successful, the check throws an error.
*
* @param glOperation - Name of the OpenGL call to check.
*/
public static void checkGlError(String glOperation) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e("OPEN_GL", glOperation + ": glError " + error);
throw new RuntimeException(glOperation + ": glError " + error);
}
}
}
解决方案最后我能够解决这个问题(借助你的线索)。对于所有其他有类似问题的人,检查你的着色器,不要只是复制&像我一样粘贴它们。这也帮助了我很多。这里还有我现在工作的着色器:
final String vertexShader =
"uniform mat4 uMVPMatrix; n"
+ "attribute vec4 aPosition; n"
+ "attribute vec4 aColor; n"
+ "varying vec4 vColor; n"
+ "void main() n"
+ "{ n"
+ " vColor = aColor; n"
+ " gl_Position = uMVPMatrix * aPosition; n"
+ "} n";
/* Fragment Shader*/
final String fragmentShader =
"precision mediump float;" +
"varying vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
我必须看到你的片段着色器知道肯定,但从这里,它看起来像你设置alpha组件为0在你的颜色数组,这意味着你的颜色不会出现。设置alpha分量为1
你需要检查并确保你的片段着色器正确编译。根据GLSL_ES规范,着色器需要在开始处包含一行,指示您使用的是哪个版本。(第3.3节,第9页).除非你是为ESGL1.0(这似乎不太可能给你自由使用顶点缓冲对象),指令必须出现在任何有效的着色器代码。