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.
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'm attempting to get a texture to show up on on a square made from a triangle fan, the texture is made from a Canvas.
The main color is just yellow and a smaller box is drawn inside of it, but the final texture is just solid yellow.
Yellow square with no texture (picture)
Fragment shadder:
public static final String fragmentShaderCode_TEXTURED =
"precision mediump float;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
//"gl_FragColor = vColor;"+
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
"}";
Texture generation:
public static int loadGLTexture(String s){
Rect r = new Rect();
ThreadDat.get().paint.getTextBounds(s, 0, 1, r); //get string dimensions, yeilds 8x9 pxls
Bitmap bitmap = Bitmap.createBitmap(bestSize(r.width()),bestSize(r.height()), Bitmap.Config.ARGB_8888);
//example size is 16x16pxls
Log.i("TextureSize", r.width() + " " + r.height());
Canvas c = new Canvas(bitmap);
//some temporary test code setting the background yellow
//Paint colors are stored per thread, only one right now
ThreadDat.get().paint.setARGB(255, 255, 255, 0);
c.drawRect(0, 0, c.getWidth(), c.getHeight(), ThreadDat.get().paint);
//type the letter, in this case "A" in blue
ThreadDat.get().paint.setARGB(255, 0, 0, 255);
ThreadDat.get().paint.setTypeface(Typeface.create("Consolas", Typeface.NORMAL));
c.drawText(s.charAt(0) + "", 0, 0, ThreadDat.get().paint);
//draw another square that is half width and height, should be Blue
c.drawRect(0, 0, c.getWidth() / 2, c.getHeight() / 2, ThreadDat.get().paint);
return loadTexture(bitmap);
}
Draw code:
#Override
public void draw() {
//clearing any error to check if program has an error
GLES20.glGetError();
//get the compiled shader for textured shapes
int prgm = MyGLRenderer.getSTRD_TXTR_SHDR();
GLES20.glUseProgram(prgm);
//check for new errors and log to logcat (nothing)
MyGLRenderer.logError();
//setup projection view matrix
float[] scratch = new float[16];
Matrix.setIdentityM(scratch, 0);
Matrix.multiplyMM(scratch, 0, MyGLRenderer.getmMVPMatrix(), 0, scratch, 0);
//apply translations to matrix
Matrix.translateM(scratch, 0, xOffset, yOffset, zOffset);
Matrix.setRotateEulerM(scratch, 0, yaw, pitch, roll);
//get vPosition variable handle from chosen shader
mPosHandle = GLES20.glGetAttribLocation(prgm, "vPosition");
GLES20.glEnableVertexAttribArray(mPosHandle);
GLES20.glVertexAttribPointer(mPosHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT,
false, VERTEX_STRIDE, vertexBuffer);
////pass color data (set to white)
//mColorHandle = GLES20.glGetUniformLocation(prgm, "vColor");
//GLES20.glUniform4fv(mColorHandle, 1, color, 0);
//use texture0
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//use texture from -> int textureID = MyGLRenderer.loadGLTexture("A");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
//get handel for "uniform sampler2D s_texture;" to set value
int txtureHandle = GLES20.glGetUniformLocation(prgm, "s_texture");
GLES20.glUniform1i(txtureHandle, 0); //set s_texture to use binded texture 0
//pass in texture coords (u,v / s,t)
int textureCoordHndl = GLES20.glGetAttribLocation(prgm, "a_texCoord");
GLES20.glVertexAttribPointer(textureCoordHndl, 2/*size, 2 points per vector*/,
GLES20.GL_FLOAT, false, 0, textureBuffer);
//pass in the model view projection matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(prgm, "uMVPMatrix");
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, scratch, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertex_count);
GLES20.glDisableVertexAttribArray(mPosHandle);
MyGLRenderer.logError();
}
I tried using the same coordinate set as used in this example:
Vertices for square:
{ 0, 0, 0, //bottom left
0, height, 0, //topLeft
width, 0, 0, // bottom Right
width, height, 0)}; //topRight
Texture coords:
0.0f, 1.0f, // top left (V2)
0.0f, 0.0f, // bottom left (V1)
1.0f, 1.0f, // top right (V4)
1.0f, 0.0f // bottom right (V3)
Similar Issue
This does sound like there is an issue with texture coordinates. Since the whole thing is yellow I would suspect that the v_texCoord is always (0,0) in your fragment shader so the first texture pixel is being repeated.
The texture itself seems to be ok since the color is being drawn. Without the texture you would most likely see a black rectangle.
Anyway to handle such issues you need to be a bit inventive in debugging, testing. For testing the coordinates use gl_FragColor = vec4( v_texCoord.x, v_texCoord.y, .0, 1.0 );. This should output a gradient rectangle where top left is black, top right is red, bottom left is green. If you do not see this result then your texture coordinates are incorrect. In this case first check if the varying is correctly connected from the vertex shader. You may use v_texCoord = vec2(1.0, 0.0) in the vertex shader and the result should be a red rectangle (assuming you still have the previous test in the fragment shader). If the rectangle is red then the issue is most likely in your handles and not in the shaders (otherwise the varying is incorrectly set. Maybe a mismatch in naming). Check what is the value of the handle textureCoordHndl. If this is a negative value then the handle was not connected. This is most likely due to a mismatch in the naming.
From further inspection:
You are missing the enabling of the attribute for texture coordinates GLES20.glEnableVertexAttribArray(textureCoordHndl);. Remember that each of the attributes must be enabled before you use them.
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.
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.