I want to render a simple cube in opengl es 3.0 on my android device but it doesn't render. This is my SurfaceView setup:
public GLContextView(Context context){
super(context);
setEGLContextClientVersion(3);
setRenderer(renderer);
}
Render Code:
public void onSurfaceCreated(javax.microedition.khronos.opengles.GL10 unused, javax.microedition.khronos.egl.EGLConfig p2){
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
GLES30.glEnable(GLES30.GL_BLEND);
GLES30.glEnable(GLES30.GL_CULL_FACE);
GLES30.glDepthFunc(GLES30.GL_LEQUAL);
GLES30.glCullFace(GLES30.GL_BACK);
GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
cubeProgram = RenderHelper.createShaderProgram(Shader.CubeVertexShader, Shader.CubeFragmentShader);
int[] array = new int[2];
GLES30.glGenVertexArrays(1, array, 0);
vaId = array[0];
GLES30.glBindVertexArray(vaId);
GLES30.glGenBuffers(2, array, 0);
vbId = array[0];
ibId = array[1];
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbId);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, RenderCube.vertices.length * 4, RenderCube.vBuffer, GLES30.GL_STATIC_DRAW);
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 0, 0);
GLES30.glEnableVertexAttribArray(positionHandle);
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, ibId);
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, RenderCube.indices.length * 4, RenderCube.iBuffer, GLES30.GL_STATIC_DRAW);
colorHandle = GLES30.glGetUniformLocation(cubeProgram, "in_color");
GLES30.glBindVertexArray(0);
}
public void onDrawFrame(GL10 p1){
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
GLES30.glUseProgram(cubeProgram);
GLES30.glBindVertexArray(vaId);
GLES30.glUniform4f(colorHandle, 1.0f, 1.0f, 1.0f, 1.0f);
GLES30.glDrawElements(GLES30.GL_TRIANGLES, RenderCube.indices.length, GLES30.GL_UNSIGNED_INT, 0);
}
public void onSurfaceChanged(GL10 p1, int p2, int p3){
GLES30.glViewport(0, 0, p2, p3);
}
RenderCube class with vertex and index data:
class RenderCube{
public static float[] vertices = {
0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
};
public static int[] indices = {
0, 3, 1, 0, 2, 3, //Bottom
4, 7, 5, 4, 6, 7, //Top
0, 5, 1, 0, 4, 5, //Back
2, 7, 3, 2, 6, 7, //Front
0, 6, 2, 0, 4, 6, //Left
1, 7, 3, 1, 5, 7 //Right
};
public static FloatBuffer vBuffer = RenderHelper.createFloatBuffer(vertices.length * 4, vertices);
public static IntBuffer iBuffer = RenderHelper.createIntBuffer(indices.length * 4, indices);
};
Shaders:
final class Shader{
public static final String CubeVertexShader =
"#version 300 es\n" +
"layout (location = 0) in vec3 pos;" +
"void main(){" +
" gl_Position = vec4(pos, 1.0f);" +
"}";
public static final String CubeFragmentShader =
"#version 300 es\n" +
"precision mediump float;" +
"uniform vec4 in_color;" +
"out vec4 color;" +
"void main(){" +
" color = in_color;" +
"}";
}
It compiles fine and no opengl errors are printed. What am I doing wrong?
I think you simply have no visible triangles.
The triangles of the bottom, top, left, and right faces are invisible because they're orthogonal to the viewing plane. So you're looking at them edge on, and they end up as degenerate triangles (i.e. triangles with zero area).
The way you defined them, the triangles of the back and front face all have clockwise winding order. Expanding the indices of those 4 triangles, and showing just the x and y coordinates of the corresponding vertices:
0, 5, 1 -> (0.0f, 0.0f), (1.0f, 1.0f), (1.0f, 0.0f)
0, 4, 5 -> (0.0f, 0.0f), (0.0f, 1.0f), (1.0f, 1.0f)
2, 7, 3 -> (0.0f, 0.0f), (1.0f, 1.0f), (1.0f, 0.0f)
2, 6, 7 -> (0.0f, 0.0f), (0.0f, 1.0f), (1.0f, 1.0f)
As you can see, these triangles are all clockwise. Since you chose to enable culling of back faces:
GLES30.glEnable(GLES30.GL_CULL_FACE);
GLES30.glCullFace(GLES30.GL_BACK);
and the default winding order for front faces is counter-clockwise, meaning that the winding of back faces is clockwise, all these triangles will be culled.
In addition, since the front face is at z = 1.0, it's also exactly on the front clip plane. The way I read the spec, geometry that is exactly on a clipping plane should still be visible. But it's probably safer to place it clearly inside the clip volume.
Related
I am trying to draw a simple, red triangle on screen. Without using an VBO the code works as intended. When trying to draw it by using an VBO (with or without shader), it simply has no effect.
My code:
//Works
glBegin(GL_TRIANGLES);
glVertex3f(0f, 0f, 0.0f);
glVertex3f(0.5f, 0f, 0.0f);
glVertex3f(0.5f, 0.5f, 0.0f);
glEnd();
//Does not work
int vertexArrayID = glGenVertexArrays();
glBindVertexArray(vertexArrayID);
float[] g_vertex_buffer_data = new float[]{
0f, 0f, 0.0f,
0.5f, 00f, 0.0f,
0.5f, 0.5f, 0.0f,
};
int vertexbuffer = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, FloatBuffer.wrap(g_vertex_buffer_data), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
false, // normalized?
0, // stride
0 // array buffer offset
);
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
glDisableVertexAttribArray(0);
glDeleteBuffers(vertexbuffer);
glDeleteVertexArrays(vertexArrayID);
System.out.println(glGetError());
glGetError() always returns 0.
I use a default, tutorial-copied shader to test my code (I link and bind the program before using above code):
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(){
gl_Position.xyz = vertexPosition_modelspace;
gl_Position.w = 1.0;
}
#version 330 core
// Ouput data
out vec3 color;
void main()
{
// Output color = red
color = vec3(1,0,0);
}
I’ve been developing a cube program that provides a number of cubes with desired qualities. However, whenever I try to light a textured cube, my cube becomes very dark. The lighting works well with a non-textured cube so I’m led to believe it’s done properly just as a simple textured cube without lighting works. There doesn’t seem to be significant documentation on how to solve this in OpenGL 2.0+ but there are a few things pertaining to older versions.
The following link offers information as to why my cube is behaving as it is, but I’m having trouble translating the solution to a newer version, especially within my shader code where I’m unsure if further changes should occur. I am using Android Studio 2.1.3 if that and its contained emulators would pose issues to the desired effect. If anyone could offer any advice, I’d greatly appreciate it. I have a separate (large) renderer that calls for the Cube to be drawn, let me know if that code would be beneficial as well in addition to my Cube. Below is my Cube:
public class TexturedLightCube {
/** Cube vertices */
private static final float VERTICES[] = {
-0.3f, -0.3f, -0.3f, //top front right
0.3f, -0.3f, -0.3f, //bottom front right
0.3f, 0.3f, -0.3f, //bottom front left
-0.3f, 0.3f, -0.3f, //top front left
-0.3f, -0.3f, 0.3f, //top back right
0.3f, -0.3f, 0.3f, //bottom back right
0.3f, 0.3f, 0.3f, //bottom back left
-0.3f, 0.3f, 0.3f // top back left
};
/** Vertex colors. */
private static final float COLORS[] = {
0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
0.0f, 1.0f, 1.0f, 1.0f,
};
/** Order to draw vertices as triangles. */
private static final byte INDICES[] = {
0, 1, 3, 3, 1, 2, // Front face.
0, 1, 4, 4, 5, 1, // Bottom face.
1, 2, 5, 5, 6, 2, // Right face.
2, 3, 6, 6, 7, 3, // Top face.
3, 7, 4, 4, 3, 0, // Left face.
4, 5, 7, 7, 6, 5, // Rear face.
};
private static final float TEXTURECOORDS[] =
{
0.0f, 1.0f, //left-bottom
0.0f, 0.0f, //right bottom
1.0f, 0.0f, //left top
1.0f, 1.0f, //right top
0.0f, 1.0f, //left-bottom
0.0f, 0.0f, //right bottom
1.0f, 0.0f, //left top
1.0f, 1.0f, //right top
};
private static final float NORMALS[] = {
//set all normals to all light for testing
1.0f, 1.0f, 1.0f, //top front right
1.0f, 0.0f, 1.0f, //bottom front right
0.0f, 0.0f, 1.0f, //bottom front left
0.0f, 1.0f, 1.0f, //top front left
1.0f, 1.0f, 0.0f, //top back right
1.0f, 0.0f, 0.0f, //bottom back right
0.0f, 0.0f, 0.0f, //bottom back left
0.0f, 1.0f, 0.0f //top back left
};
static final int COORDS_PER_VERTEX = 3;
private static final int VALUES_PER_COLOR = 4;
/** Vertex size in bytes. */
final int VERTEX_STRIDE = COORDS_PER_VERTEX * 4;
/** Color size in bytes. */
private final int COLOR_STRIDE = VALUES_PER_COLOR * 4;
/** Shader code for the vertex. */
private static final String VERTEX_SHADER_CODE =
"uniform mat4 uMVPMatrix;" +
"uniform mat4 uMVMatrix;" +
"uniform vec3 u_LightPos;" +
"attribute vec4 vPosition;" +
"attribute vec4 a_Color;" +
"attribute vec3 a_Normal;" +
"varying vec4 v_Color;" +
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"vec3 modelViewVertex = vec3(uMVMatrix * vPosition);"+
"vec3 modelViewNormal = vec3(uMVMatrix * vec4(a_Normal, 0.0));" +
"float distance = length(u_LightPos - modelViewVertex);" +
"vec3 lightVector = normalize(u_LightPos - modelViewVertex);" +
"float diffuse = max(dot(modelViewNormal, lightVector), 0.1);" +
"diffuse = diffuse * (1.0/(1.0 + (0.00000000000002 * distance * distance)));" + //attenuation factor
"v_Color = a_Color * a_Color * diffuse;" +
"gl_Position = uMVPMatrix * vPosition;" +
"v_TexCoordinate = a_TexCoordinate;" +
"}";
/** Shader code for the fragment. */
private static final String FRAGMENT_SHADER_CODE =
"precision mediump float;" +
"varying vec4 v_Color;" +
"uniform sampler2D u_Texture;"+ //The input texture
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_FragColor = v_Color * texture2D(u_Texture, v_TexCoordinate) ;" + //still works with just color
"}";
private int mTextureUniformHandle; //Pass in texture.
private int mTextureCoordinateHandle; //Pass in model texture coordinate information.
private final int mTextureCoordinateDataSize = 2; //Size of texture coordinate data in elements
public static int mTextureDataHandle; //Handle to texturedata;
private final FloatBuffer mTextureBuffer; //Store model data in float buffer.
private final FloatBuffer mVertexBuffer;
private final FloatBuffer mColorBuffer;
private final FloatBuffer mNormalBuffer;
private final ByteBuffer mIndexBuffer;
private final int mProgram;
private final int mPositionHandle;
private final int mColorHandle;
private final int mMVPMatrixHandle;
private final int mNormalHandle;
public static int mLightPosHandle;
public final int mMVMatrixHandle;
public static int loadTexture(final Context context, final int resourceId) {
//Get the texture from the Android resource directory
final int[] textureHandle = new int[1];
InputStream is = context.getResources().openRawResource(+ R.drawable.teneighty);
Bitmap bitmap = null;
try {
//BitmapFactory is an Android graphics utility for images
bitmap = BitmapFactory.decodeStream(is);
} finally {
//Always clear and close
try {
is.close();
is = null;
} catch (IOException e) {
}
}
//Generate one texture pointer...
GLES20.glGenTextures(1, textureHandle, 0);
//and bind it to our array.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
//Create Nearest Filtered Texture.
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
//Accounting for different texture parameters.
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
//Use the Android GLUtils to specify a two-dimensional texture image from our bitmap.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture");
}
return textureHandle[0];
}
public TexturedLightCube() {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(VERTICES.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mVertexBuffer = byteBuffer.asFloatBuffer();
mVertexBuffer.put(VERTICES);
mVertexBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(COLORS.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mColorBuffer = byteBuffer.asFloatBuffer();
mColorBuffer.put(COLORS);
mColorBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(NORMALS.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mNormalBuffer = byteBuffer.asFloatBuffer();
mNormalBuffer.put(NORMALS);
mNormalBuffer.position(0);
byteBuffer = ByteBuffer.allocateDirect(TEXTURECOORDS.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
mTextureBuffer = byteBuffer.asFloatBuffer();
mTextureBuffer.put(TEXTURECOORDS);
mTextureBuffer.position(0);
mIndexBuffer = ByteBuffer.allocateDirect(INDICES.length);
mIndexBuffer.put(INDICES);
mIndexBuffer.position(0);
mProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(mProgram, loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE));
GLES20.glAttachShader(mProgram, loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE));
GLES20.glLinkProgram(mProgram);
mTextureDataHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
mLightPosHandle = GLES20.glGetUniformLocation(mProgram, "u_LightPos");
mNormalHandle = GLES20.glGetAttribLocation(mProgram, "a_Normal");
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color");
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* #param mvpMatrix The Model View Project matrix in which to draw this shape
*/
public void draw(float[] mvpMatrix) {
// Add program to OpenGL environment.
GLES20.glUseProgram(mProgram);
//set active texture unit to texture unit 0.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
// Prepare the cube coordinate data.
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer);
// Prepare the cube color data.
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, COLOR_STRIDE, mColorBuffer);
//Will have the same size as Vertex as we are implementing per vertex lighting
GLES20.glEnableVertexAttribArray(mNormalHandle);
GLES20.glVertexAttribPointer(mNormalHandle, 3, GLES20.GL_FLOAT, false, VERTEX_STRIDE, mNormalBuffer);
// Prepare the cube texture data.
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
//Pass texture coordinate information.
GLES20.glVertexAttribPointer(mTextureCoordinateHandle,4, GLES20.GL_FLOAT, false, mTextureCoordinateDataSize, mTextureBuffer);
// Apply the projection and view transformation.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glUniform3f(LightCube.mLightPosHandle, MyGLRenderer.mLightPosInEyeSpace[0], MyGLRenderer.mLightPosInEyeSpace[1], MyGLRenderer.mLightPosInEyeSpace[2]);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glUniform1i(mTextureUniformHandle, 0);
// Draw the cube.
GLES20.glDrawElements(GLES20.GL_TRIANGLES, INDICES.length, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer); //-removed indices-
// Disable vertex arrays.
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glDisableVertexAttribArray(mColorHandle);
GLES20.glDisableVertexAttribArray(mNormalHandle);
}
/** Loads the provided shader in the program. */
private static int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
You're missing an ambient component to your lighting, which emulates second order (and higher) reflections you would get in real life, but can't get directly in a rasterizer.
Not sure why you are squaring a_Color in your fragment shader. This will definitely make things darker because all values are between 0 and 1; e.g. 0.1^2 == 0.01.
Remember that your dot product might be negative, so you want to clamp out negative diffuse components (e.g. no light intensity on surfaces which are facing away from the light).
I want to draw a quad over my game screen with a repeating scanline texture at a 1texel:1pixel ratio. This is a 2D game. This is what I have so far:
create()
quad = new Mesh(true, 4, 6,
new VertexAttribute(Usage.Position, 3, "a_position"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords"));
quad.setVertices(new float[] {
-1.0f, 0.0f, 0, 0.0f, 1.0f, //bottom left
1.0f, 0.0f, 0, 1.0f, 1.0f, //bottom right
1.0f, 1.0f, 0, 1.0f, 0.0f, //top right
-1.0f, 1.0f, 0, 0.0f, 0.0f }); //top left
quad.setIndices(new short[] { 0, 1, 2, 2, 3, 0});
Gdx.gl20.glEnable(GL20.GL_TEXTURE_2D);
Gdx.gl20.glEnable(GL20.GL_BLEND);
Gdx.gl20.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
texScanlines = new Texture(Gdx.files.internal("Scanlines.png"));
texScanlines.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
imgTextureRegion = new TextureRegion(texScanlines);
imgTextureRegion.setRegion(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
render()
Gdx.graphics.getGL20().glClearColor(0, 0, 0, 1);
Gdx.graphics.getGL20().glClear(GL20.GL_COLOR_BUFFER_BIT);
camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
// draw game stuff...
spriteBatch.end();
imgTextureRegion.getTexture().bind();
quad.render(SpriteBatch.createDefaultShader(), GL20.GL_TRIANGLES);
However, the quad isn't being rendered. Does anyone have any pointers?
I've been trying to make this piece of code work for a while now and I still can't figure it out what I did wrong. (LWJGL - Java)
I have tried to check on the web for other people's code, but I can't find any major difference. I actually learned to use OpenGL with C++ so my mind might be stuck on it and that might be why I can't find my errors.
Here is the init (called once)
FloatBuffer vertices = BufferUtils.createFloatBuffer(4 * 5);
vertices.put(new float[]{
// pos // Color
0.5f, 0.5f, 0.5f, 0.0f, 0.5f,
0.5f, -0.5f, 0.5f, 0.0f, 0.75f,
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.5f, 1.0f
});
vertices.flip();
ByteBuffer indices = BufferUtils.createByteBuffer(2 * 3);
indices.put(new byte[]{
0, 1, 3,
1, 2, 3
});
indices.flip();
// VAO
VAO = GL30.glGenVertexArrays();
GL30.glBindVertexArray(VAO);
// VBO
VBO = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
// EBO
EBO = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glEnableVertexAttribArray(0);
// v - position in layout (see shader)
// v - Nb of component per vertex (2 for 2D (x, y))
// v - Normalized ? (between 0 - 1)
// v - Offset between things (size of a line)
// v - Where to start ?
glVertexAttribPointer(0, 2, GL11.GL_FLOAT, false, 5 * Float.SIZE , 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL11.GL_FLOAT, false, 5 * Float.SIZE , 2 * Float.SIZE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// Unbinds the VAO
GL30.glBindVertexArray(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
And here is the render function :
shaderProgram.bind();
GL30.glBindVertexArray(VAO);
GL11.glDrawElements(GL11.GL_TRIANGLES, 6, GL11.GL_BYTE, 0);
GL30.glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
Shaders:
Vertex:
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec3 color;
out vec4 Color;
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
Color = vec4(color, 1.0);
}
Framgent :
#version 330 core
in vec4 Color;
out vec4 color;
void main()
{
color = Color;
}
In the the official Java documentation, Float.SIZE is defined as:
The number of bits used to represent a float value.
Since glVertexAttribPointer() expects the stride and offset arguments in bytes, you will have to divide this by 8, and use (Float.SIZE / 8) instead.
I drew a cube in openGL es 2.0.
Right now it has just two faces, for testing purposes(the front and the back). So basically there are two planes in space, both with the same color.
Now I want to apply a different color to each face. I tought that expanding the color array was sufficient, but the colors are not changing (there's just the original color).
Do I have to change the shader? Or pass a specific function to the draw method?
The class should explain better
public class Cube {
private FloatBuffer mVer;
private FloatBuffer colMem;
private ShortBuffer ordVer;
private float vertici[] = {
-0.2f, 0.2f, 0.2f, //p1 upper left front plane (0)
-0.2f, -0.2f, 0.2f, //p2 lower left front plane (1)
0.2f, -0.2f, 0.2f, //p3 lower right front plane (2)
0.2f, 0.2f, 0.2f, //p4 upper right front plane (3)
-0.2f, 0.2f, -0.2f, //p1 upper left front plane (4)
-0.2f, -0.2f, -0.2f, //p2 lower left front plane (5)
0.2f, -0.2f, -0.2f, //p3 lower right front plane (6)
0.2f, 0.2f, -0.2f, //p4 upper right front plane (7)
};
private short order[] = {
0, 1, 2, 0, 2, 3, //front face
7, 6, 5, 7, 5, 4, //back face
//3, 2, 6, 3, 6, 7, //right face
// 0, 1, 5, 0, 5, 4 //left face
};
private float color [] = {
0.8f, 0.8f, 0.1f, 1.0f,//color1
0.8f, 0.8f, 0.1f, 1.0f,
0.8f, 0.8f, 0.1f, 1.0f,
0.8f, 0.8f, 0.1f, 1.0f,
0.1f, 0.2f, 0.5f, 1.0f,//color2
0.1f, 0.2f, 0.5f, 1.0f,
0.1f, 0.2f, 0.5f, 1.0f,
0.1f, 0.2f, 0.5f, 1.0f
};
private final String vertCode =
"uniform mat4 uMVPMatrix;"+
"attribute vec4 vPosition;"+
"void main() {"+
"gl_Position = uMVPMatrix * vPosition;"+
"}";
private final String fragCode =
"precision mediump float;"+
"uniform vec4 vColor;"+
"void main() {"+
"gl_FragColor = vColor;"+
"}";
private int prog;
private int pos;
private int col;
private int mHandle;
public Cube () {
mVer = ByteBuffer.allocateDirect(vertici.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mVer.put(vertici).position(0);
ordVer = ByteBuffer.allocateDirect(order.length * 2).order(ByteOrder.nativeOrder()).asShortBuffer();
ordVer.put(order).position(0);
colMem = ByteBuffer.allocateDirect(color.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
colMem.put(color).position(0);
int vertexShader = Render.loadShader (GLES20.GL_VERTEX_SHADER, vertCode);
int fragmentShader = Render.loadShader (GLES20.GL_FRAGMENT_SHADER, fragCode);
prog = GLES20.glCreateProgram();
GLES20.glAttachShader(prog, vertexShader);
GLES20.glAttachShader(prog, fragmentShader);
GLES20.glLinkProgram(prog);
}
public void draw (float[] mVMatrix) {
GLES20.glUseProgram(prog);
pos = GLES20.glGetAttribLocation(prog, "vPosition");
GLES20.glEnableVertexAttribArray(pos);
GLES20.glVertexAttribPointer(pos, 3, GLES20.GL_FLOAT, false, 12, mVer);
col = GLES20.glGetUniformLocation(prog, "vColor");
GLES20.glUniform4fv(col, 1, color, 0);
mHandle = GLES20.glGetUniformLocation(prog, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mHandle, 1, false, mVMatrix, 0);
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, order.length, GLES20.GL_UNSIGNED_SHORT, ordVer);
GLES20.glDisableVertexAttribArray(pos);
}
}
You have a few options:
If you want to pass in the color as a uniform, which seems to be where you were headed, you need to draw each face with a separate draw call. You can't just pass in an array of colors for the uniform, and expect the colors to be applied to the triangles in order. You would call glUniform4v with the first color, call glDrawElements with just the indices f the first face, and then repeat these two calls for each face. This is fairly inefficient.
You make the colors an attribute instead of a uniform, very similar to what you do for the vertex positions. You have to be careful when using this approach because you need an OpenGL vertex for each combination of position and color. For a cube, you typically end up with 24 vertices. You should be able to find details if you search for older questions about similar topics.
There's another method called "instanced rendering" that could be applied, but that is only available in ES 3.0.