Issue
I'm trying to implement a ModelViewer that can visualize triangulated shapes with realistic lighting. Since realistic lighting doesn't seem possible with OpenGL ES 1.0 and I need a way to present depth for a single colored object, the project uses OpenGL ES 2.0 which is new to me. The object itself consists of triangles that are drawn using:
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
As for a test project, I've set up simple shaders that draw the object in consideration of the model-view-projection matrix. After that, my intention was to implement lighting but I cannot get past the first steps. When working with varying variables, the vertex attributes won't be found. Removing the varying attributes works, but i need to pass data. I've searched for days on how to implement vertex and fragment shaders that do more than present an object at a location.
// VERTEX SHADER CODE
attribute vec4 v_Position;
uniform mat4 u_MVPMatrix;
uniform vec4 u_Color;
varying vec4 v_Color;
void main() {
gl_Position = u_MVPMatrix * v_Position;
v_Color = u_Color;
};
// FRAGMENT SHADER CODE
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
The whole Class:
public class Object3D {
private FloatBuffer vertexBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
// static float triangleCoords[] = { // in counterclockwise order:
// 0.0f, 0.622008459f, 0.0f, // top
// -0.5f, -0.311004243f, 0.0f, // bottom left
// 0.5f, -0.311004243f, 0.0f // bottom right
// };
float[] triangleCoords;
// Set color with red, green, blue and alpha (opacity) values
float[] colors = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };
private final String vertexShaderCode =
"attribute vec4 v_Position;" +
"uniform float u_Color" +
"uniform mat4 u_MVPMatrix;" +
// outgoing
"varying vec4 v_Color" +
"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 = u_MVPMatrix * v_Position;" +
"v_Color = u_Color;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 v_Color;" +
"void main() {" +
"gl_FragColor = v_Color;" +
"}";
// Use to access and set the view transformation
private int mMVPMatrixHandle;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private final int vertexCount;
private final int vertexStride;
public Object3D(float[] triangleCoords) {
this.triangleCoords = triangleCoords;
vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
this.colors = new float[4*vertexCount];
for (int i = 0; i < colors.length; i+=4) {
colors[i] = 0.63671875f;
colors[i+1] = 0.76953125f;
colors[i+2] = 0.22265625f;
colors[i+3] = 1.0f;
}
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
// use the device hardware's native byte order
bb.order(ByteOrder.nativeOrder());
// create a floating point buffer from the ByteBuffer
vertexBuffer = bb.asFloatBuffer();
// add the coordinates to the FloatBuffer
vertexBuffer.put(triangleCoords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();
// add the vertex shader to program
GLES20.glAttachShader(mProgram, vertexShader);
// add the fragment shader to program
GLES20.glAttachShader(mProgram, fragmentShader);
GLES20.glBindAttribLocation(mProgram, 0, "v_Position");
// GLES20.glBindAttribLocation(mProgram, 1, "vColor");
// creates OpenGL ES program executables
GLES20.glLinkProgram(mProgram);
}
public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "v_Position");
// if (mPositionHandle == -1) {
// throw new RuntimeException(
// "Could not get attrib location for v_Position");
// }
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "v_Color");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, colors, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "u_MVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
// // get handle to shape's transformation matrix
// int mColorHandleU = GLES20.glGetUniformLocation(mProgram, "u_Color");
//
// // Apply the projection and view transformation
// GLES20.glUniform4fv(mColorHandleU, 1, new float[] {}, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
If I want to do some necessary color calculations, i need varying variables to pass information from the vertex to the fragment shader. However, I cannot seem to get this done.
The Error I keep getting is:
2019-05-14 21:54:25.122 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glEnableVertexAttribArray:892 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.123 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glVertexAttribPointer:604 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.124 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glDisableVertexAttribArray:901 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.237 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glEnableVertexAttribArray:892 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.237 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glVertexAttribPointer:604 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
2019-05-14 21:54:25.238 8281-8316/com.example.opengles20 E/emuglGLESv2_enc: device/generic/goldfish-opengl/system/GLESv2_enc/GL2Encoder.cpp:s_glDisableVertexAttribArray:901 GL error 0x501
Info: Invalid vertex attribute index. Wanted index: 4294967295. Max index: 16
Also, the following exception, when implemented, is thrown:
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "v_Position");
if (mPositionHandle == -1) {
throw new RuntimeException(
"Could not get attrib location for v_Position");
}
I know that for attributes, the instruction flow goes like this:
GLES20.glBindAttribLocation(...);
-- Link Shader Program --
attributeHandle = GLES20.glGetAttribLocation(programHandle, "a_AttributenName");
GLES20.glEnableVertexAttribArray(attributeHandle);
GLES20.glVertexAttribPointer(programHandle, ..., buffer);
The instruction sequence for uniforms go like this:
uniformHandle = GLES20.glGetUniformLocation(mProgram, "u_UniformName");
// do something with it, for example:
GLES20.glUniform4fv(uniformHandle, ...);
But what is there to do for varying variables?
Thanks in advance!
Solution
private final String vertexShaderCode =
"attribute vec4 v_Position;" +
"uniform float u_Color" +
"uniform mat4 u_MVPMatrix;" +
// outgoing
"varying vec4 v_Color" +
"void main() {" +
You're missing a semi-colon after u_Color and also v_Color. Presumably your vertex shader is not compiling and that's cascading down into the errors you're seeing.
It's a pain, but it really does save time in the long run to check for errors after every OpenGLES call (glGetError
). Getting detailed shader compile error logs is also fiddly but worth putting in place - see here (glGetShaderInfoLog
, GL_COMPILE_STATUS
).
Answered By - Columbo
Answer Checked By - David Marino (JavaFixing Volunteer)