I've got some code that's supposed to render text to a texture so that I don't have to render each character each draw step, and can instead use the rendered texture. However, my code does not as it's supposed to, and the texture is left blank. After a few hours of trying different things, I cannot figure it out, and so I bring the question to you.
I'm fairly certain the problem is somewhere in this code chunk below, but if you think it's not, I'll gladly post whatever other samples of code you would like. I just really want to get this done already. The exact problem is that the created texture is blank, and never is rendered to (it seems like). I've tried just drawing one massive quad on it, and that didn't seem to work either.
Edit: After flipping the buffer, I can get some color to be rendered to the texture, but it's all just one color (which makes me think it's only sampling one pixel), and I can't figure out how to get the actual image I want to render to show on it.
public Text(String text, int x, int y, Font font, float size, GUIComponent parent, Binding binding) {
super(null, x, y, font.getStringWidth(size, text), font.getStringHeight(size), parent, binding, false);
this.text = text;
this.font = font;
this.width = font.getStringWidth(size, text);
this.height = font.getStringHeight(size);
int fbo = glGenFramebuffers();
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
int tex = glGenTextures();
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0);
IntBuffer intBuffer = BufferUtils.createIntBuffer(1);
intBuffer.put(GL_COLOR_ATTACHMENT0);
intBuffer.flip();
glDrawBuffers(intBuffer);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
throw new RuntimeException("Something really bad happened");
}
//RENDER
RenderUtil.recalibrate(width, height, 1.0f); //Does glViewport(width, height), and some matrix stuff
Camera.updateShader("textshader", "projection", false); //Update projection matrix
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
int width = 0;
float f = this.width / 1.0f;
int charWidth = 0;
for (char c : text.toCharArray()) {
font.bind(0, c % 256); // calls glBindTexture, this works, have tested
//ResourceManager.getTexture("grassroadedger1").bind(0, 0);
charWidth = font.getCharWidth(size, c);
//float[] verts = new float[] { -1f, 1f, 1f, 1f, 1f, -1f, -1f, -1f };
float[] verts = new float[] { -1.0f + (width / f), 1.0f, 1.0f + ((width + charWidth) / f), 1.0f, 1.0f + ((width + charWidth) / f), -1.0f, -1.0f + (width / f), -1.0f };
width += charWidth;
glBindBuffer(GL_ARRAY_BUFFER, vertexPointer);
glBufferSubData(GL_ARRAY_BUFFER, 0, RenderUtil.createBuffer(verts));
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, RenderUtil.getIndicesPointer());
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
//END
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
RenderUtil.recalibrate(Window.getWidth(), Window.getHeight(), LuminaEngine.getGlobalImageScale());
this.setTexture(new Texture(tex, "text_"+size+"_"+text));
}
FragmentShader
#version 330 core
in vec2 uv;
layout(location = 0) out vec4 color;
uniform sampler2D sampler;
void main(){
color = texture2D( sampler, uv );
}
Vertex Shader
#version 330 core
layout(location = 0) in vec3 vertices;
layout(location = 1) in vec2 textures;
out vec2 uv;
uniform mat4 projection;
void main(){
gl_Position = projection * vec4(vertices,1);
uv = textures;
}
Edit: After flipping the intBuffer for drawBuffers, I can get some things to appear, mostly just a big blue square. Progress nonetheless
You never defined an array of generic vertex attribute data for the texture coordinates (in vec2 textures;).
Add something like this to your code:
int texCoordBuffer;
glGenBuffers(1, texCoordBuffer);
float[] texCoord = new float[] { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, RenderUtil.createBuffer(texCoord), GL_STATIC_DRAW);
int tax_attr_i = 1; // layout(location = 1) in vec2 textures;
glVertexAttribPointer(tax_attr_i, 2, GL_FLOAT, false, 0, 0);
Related
I am relatively new to OpenGL, so this question might seem a bit trivial. I have this code in my Main.java, which is supposed to output a rectangle with the texture of the image on it:
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
int VBO = glGenBuffers(), VAO = glGenVertexArrays(), EBO = glGenBuffers();
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, false, 8, 0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, false, 8, 2);
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, false, 8, 5);
glEnableVertexAttribArray(2);
Texture texture = null;
try {
log.info("Loading texture");
texture = Texture.loadTexture("texture.png");
} catch (IOException e) {
log.severe("Texture loading failed due to IOException: " + e.getMessage());
e.printStackTrace();
}
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
if(mainProgram != null) {
mainProgram.use();
}
glBindTexture(GL_TEXTURE_2D, texture.getId());
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//...
}
My shaders are the following:
Vertex Shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTexCoord;
out vec3 vertexColor;
out vec2 texCoord;
void main()
{
gl_Position = vec4(aPos , 1.0);
vertexColor = aColor;
texCoord = aTexCoord;
}
Fragment Shader:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 TexCoord;
// texture sampler
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
The Texture class referenced above is the following:
public class Texture {
public static Texture loadTexture(String fileName) throws IOException{
//load png file
PNGDecoder decoder = new PNGDecoder(new java.io.FileInputStream(new File("C:/Users/Using/Absolute/Paths/For/Demonstration/texture.png")));
//create a byte buffer big enough to store RGBA values
ByteBuffer buffer = BufferUtils.createByteBuffer(4 * decoder.getWidth() * decoder.getHeight());
//decode
decoder.decode(buffer, decoder.getWidth() * 4, PNGDecoder.Format.RGBA);
//flip the buffer so its ready to read
buffer.flip();
//create a texture
int id = glGenTextures();
//bind the texture
glBindTexture(GL_TEXTURE_2D, id);
//tell opengl how to unpack bytes
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//set the texture parameters, can be GL_LINEAR or GL_NEAREST
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//upload texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, decoder.getWidth(), decoder.getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// Generate Mip Map
glGenerateMipmap(GL_TEXTURE_2D);
return new Texture(id);
}
private int id;
public Texture(int id){
this.id = id;
}
public int getId(){
return id;
}
}
Note that the path of the texture image is not the problem, as the code works without any Exceptions or Compiler errors. The PNGDecoder i used can be found here.
The stride and offset argument must be set in bytes when specifying the array of generic vertex attribute data by glVertexAttribPointer.
Furthermore, the uv coordinates are the 7th and 8th element in the attribute tuple:
glVertexAttribPointer(0, 3, GL_FLOAT, false, 8, 0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 8*4, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 8, 2);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 8*4, 3*4);
glVertexAttribPointer(2, 2, GL_FLOAT, false, 8, 5);
glVertexAttribPointer(2, 2, GL_FLOAT, false, 8*4, 6*4);
I have been trying to follow the code as specified in this tutorial on OpenGL3+ textures, but my result ends up black instead of the texture.
I am using stbimage to load the image the texture uses into a direct ByteBuffer and can guarantee the RGB data in the buffer is, at least, not uniform - so it can't be that.
I usually do not like to dump code, but I don't see much else I can do at this point. Here's my java code and shaders:
GL is an interface pointing to all the GL## functionality in LWJGL31.
ShaderProgram wraps all the shader specific stuff into a nice blackbox that generates a shaderprogram from the attached shaders on the first call of use(GL) and subsequently reuses that program. This works just fine for rendering a coloured triangle, so I rule out any errors in there.
Util.checkError(GL, boolean); does check for any OpenGL errors that have accumulated since its last execution and throws a runtime exception if the boolean is not set (silently writes to the log instead, if set).
The rendering code, update(GL, long) is run once every frame
private static final ResourceAPI res = API.get(ResourceAPI.class);
Image lwjgl32;
ShaderProgram prog = new ShaderProgram();
int vbo, vao, ebo;
int texture;
#Override
public void init(GL gl) {
try {
prog.attach(res.get("shaders/texDemo.vert", ShaderSource.class));
prog.attach(res.get("shaders/texDemo.frag", ShaderSource.class));
lwjgl32 = res.get("textures/lwjgl32.png", Image.class);
} catch(ResourceException e) {
throw new RuntimeException(e);
}
float[] vertices = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
int[] indices = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
vao = gl.glGenVertexArrays();
vbo = gl.glGenBuffers();
ebo = gl.glGenBuffers();
gl.glBindVertexArray(vao);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo);
gl.glBufferData(GL.GL_ARRAY_BUFFER, vertices, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ebo);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indices, GL.GL_STATIC_DRAW);
gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 0);
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(1, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 3 * Float.BYTES);
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(2, 2, GL.GL_FLOAT, false, 8 * Float.BYTES, 6 * Float.BYTES);
gl.glEnableVertexAttribArray(0);
texture = gl.glGenTextures();
gl.glBindTexture(GL.GL_TEXTURE_2D, texture);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB8, lwjgl32.getWidth(), lwjgl32.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, lwjgl32.getImageData());
gl.glGenerateMipmap(GL.GL_TEXTURE_2D);
prog.use(gl);
gl.glUniform1i(gl.glGetUniformLocation(prog.getId(gl), "texture"), 0);
Util.checkError(gl, false);
}
#Override
protected void update(GL gl, long deltaFrame) {
gl.glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glActiveTexture(GL.GL_TEXTURE0);
gl.glBindTexture(GL.GL_TEXTURE_2D, texture);
prog.use(gl);
gl.glBindVertexArray(vao);
gl.glDrawElements(GL.GL_TRIANGLES, 6, GL.GL_UNSIGNED_INT, 0);
}
#Override
public void clean(GL gl) {
gl.glDeleteVertexArrays(vao);
gl.glDeleteBuffers(vbo);
gl.glDeleteBuffers(ebo);
ShaderProgram.clearUse(gl);
prog.dispose(gl);
}
Vertex shader
#version 330 core
layout (location = 0) in vec3 in_position;
layout (location = 1) in vec3 in_color;
layout (location = 2) in vec2 in_texCoord;
out vec3 color;
out vec2 texCoord;
void main() {
gl_Position = vec4(in_position, 1.0);
color = in_color;
texCoord = vec2(in_texCoord.x, in_texCoord.y);
}
Fragment shader
#version 330 core
out vec4 frag_colour;
in vec3 color;
in vec2 texCoord;
uniform sampler2D texture;
void main() {
frag_colour = texture(texture, texCoord) * vec4(color, 1.0);
}
1I wrapped LWJGL3's GL## static classes into a single interface and implementation so I can have a bunch of stateful methods that do things such as identifying the context that is being rendered to, etc. I also did my best to remove non-core functionality from the interface so I don't even get tempted to use deprecated stuff
You only enable the vertex attribute with index 0, but this 3 times.
Adapt your code like this:
gl.glVertexAttribPointer(0, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 0);
gl.glEnableVertexAttribArray(0);
gl.glVertexAttribPointer(1, 3, GL.GL_FLOAT, false, 8 * Float.BYTES, 3 * Float.BYTES);
gl.glEnableVertexAttribArray(1); // <-------
gl.glVertexAttribPointer(2, 2, GL.GL_FLOAT, false, 8 * Float.BYTES, 6 * Float.BYTES);
gl.glEnableVertexAttribArray(2); // <------
It's hard to tell from just looking at the code but a black quad means that this row in your fragment shader:
frag_colour = texture(texture, texCoord) * vec4(color, 1.0);
evaluates to 0. Which means either the texture is'nt read/bound properly, your texture coordinates are off or color is a zero vector. Make sure your texture image is properly loaded (file exists, has a width and height etc) and has the correct format. What I usually do to debug the shader is to set each parameter as a color to give a hint if it has the correct value:
frag_colour = vec4(color, 1.0); //Makes sure the color is right
or
frag_colour = texture(texture, texCoord); //Makes sure the texture is loaded and bound
And if that doesn't give enough information, even more detail:
frag_colour = vec4(color.x, color.x, color.x, 1.0);
or
frag_colour = vec4(texCoord.x, texCoord.x, texCoord.x, 1.0);
I am beginner in openGL.
i am created a prism ( each face is equilateral triangle ) in android using openGL library and i am able to rotate the prism successfully.
but my requirment is to put three different images in each face of the prism and i am not able to put the images. when i am putting the image it is scaling and mapping to all faces.
MyRenderer Class
public class MyRenderer implements Renderer {
/** Cube instance */
/* Rotation values for all axis */
private float xrot; //X Rotation ( NEW )
private float yrot; //Y Rotation ( NEW )
private float zrot; //Z Rotation ( NEW )
/** The Activity Context ( NEW ) */
private Context context;
private Pyramid pyramid;
/**
* Instance the Cube object and set
* the Activity Context handed over
*/
public MyRenderer(Context context) {
this.context = context;
pyramid = new Pyramid(this.context);
}
/**
* The Surface is created/init()
*/
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//Load the texture for the cube once during Surface creation
gl.glEnable(GL10.GL_TEXTURE_2D); //Enable Texture Mapping ( NEW )
gl.glShadeModel(GL10.GL_SMOOTH); //Enable Smooth Shading
gl.glClearColor(1.0f, 1.0f, 1.0f, 0.5f); //Black Background
gl.glClearDepthf(1.0f); //Depth Buffer Setup
gl.glEnable(GL10.GL_DEPTH_TEST); //Enables Depth Testing
gl.glDepthFunc(GL10.GL_LEQUAL); //The Type Of Depth Testing To Do
//Really Nice Perspective Calculations
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
/**
* Here we do our drawing
*/
public void onDrawFrame(GL10 gl) {
//Clear Screen And Depth Buffer
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity(); //Reset The Current Modelview Matrix
//Drawing
gl.glTranslatef(0.0f, -1.0f, -5.0f); //Move 5 units into the screen
gl.glScalef(1.0f, 1.0f, 1.0f); //Scale the Cube to 80 percent, otherwise it would be too large for the screen
//Rotate around the axis based on the rotation matrix (rotation, x, y, z)
gl.glRotatef(yrot, 0.0f, 1.65f, 0.0f); //X
pyramid.draw(gl, context);
yrot += 1.0f;
}
/**
* If the surface changes, reset the view
*/
public void onSurfaceChanged(GL10 gl, int width, int height) {
if(height == 0) { //Prevent A Divide By Zero By
height = 1; //Making Height Equal One
}
gl.glViewport(0, 0, width, height); //Reset The Current Viewport
gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Projection Matrix
gl.glLoadIdentity(); //Reset The Projection Matrix
//Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW); //Select The Modelview Matrix
gl.glLoadIdentity(); //Reset The Modelview Matrix
}
}
MyPyramid class
public class Pyramid {
/** The buffer holding the vertices */
private FloatBuffer vertexBuffer;
/** The buffer holding the color values */
private FloatBuffer colorBuffer;
private ByteBuffer indexBuffer;
private FloatBuffer textureBuffer;
private int noOfFaces = 3;
private int[] texturesID = new int[3];
private float PyramidVertices [] = {
0.0f, 1.65f, 0.0f,
-1.3f, 0.0f, 1.0f,
1.3f, 0.0f, 1.0f,
0.0f, 0.0f, -1.65f,
};
private float textures[] = {
//Mapping coordinates for the vertices
0.0f, 1.65f,
0.0f, 1.65f,
-1.3f, 0.0f,
1.3f, 0.0f,
};
private float colors[] = {
1.0f, 0.0f, 0.0f, 1.0f, //Red
0.0f, 1.0f, 0.0f, 1.0f, //Green
0.0f, 0.0f, 1.0f, 1.0f, //Blue
1.0f, 0.0f, 0.0f, 1.0f, //Red
};
private byte indices [] = { 0, 2, 1,
0, 2, 3,
0, 1, 3,
};
/**
* The Pyramid constructor.
*
* Initiate the buffers.
*/
public Pyramid( Context context) {
//
ByteBuffer byteBuf = ByteBuffer.allocateDirect(PyramidVertices.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
vertexBuffer = byteBuf.asFloatBuffer();
vertexBuffer.put(PyramidVertices);
vertexBuffer.position(0);
byteBuf = ByteBuffer.allocateDirect(colors.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
colorBuffer = byteBuf.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
indexBuffer = ByteBuffer.allocateDirect(indices.length);
indexBuffer.put(indices);
indexBuffer.position(0);
byteBuf = ByteBuffer.allocateDirect(textures.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(textures);
textureBuffer.position(0);
}
/**
* The object own drawing function.
* Called from the renderer to redraw this instance
* with possible changes in values.
*
* #param gl - The GL Context
*/
public void draw(GL10 gl, Context context) {
//Set the face rotation
// gl.glFrontFace(GL10.GL_CW);
gl.glCullFace(GL10.GL_CCW);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
loadTexture(gl, context);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
// Enable the texture state
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Point to our buffers
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
public void loadTexture(GL10 gl, Context context) {
Bitmap bitmap;
gl.glGenTextures(3, texturesID, 0); // Generate texture-ID array for 6 IDs
gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesID[2]);
InputStream is = context.getResources().openRawResource(R.drawable.forward);
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 OpenGL texture images
// Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
// Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
// Build Texture from loaded bitmap for the currently-bind texture ID
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
}
and i took the help from
http://www3.ntu.edu.sg/home/ehchua/programming/android/Android_3D.html
http://nehe.gamedev.net/
How to give different images on each face?
There are few ways of doing this but here are the simplest two for you to try:
Modify object to your needs
It's quite tricky to use few textures at a time and select them per-face, but the simple solution is to divide your pyramid into few objects. Then, you can assign different texture for each of your objects as you like.
Modify texture to your needs
You can use a technique known as Texture Atlas. In this solution you can take few textures and stitch them together into one, bigger bitmap. Then you use this bitmap as your main texture. You also need to modify your vertices UVs, so one of your triangles uses some part of your bigger texture, while another triangle uses different part of your texture. Using this technique you can get an appearance that different triangles use totally different images as their texture (even that there's just one real texture during rendering).
Let us know if you need more details about it.
Thanks for response.
I found the solution for my problem. I created a equilateral triangle and then by giving the proper rotation angle i am able to rotate it as well as i put the different texture in each face.
MyPyramid class
public class PyramidNew {
int []texturesID = new int[3];
Bitmap []bitmap = new Bitmap[3];
private FloatBuffer textureBuffer;
private FloatBuffer vertexBuffer; // Buffer for vertex-array
private float[][] colors = { // Colors of the 6 faces
{1.0f, 0.5f, 0.0f, 1.0f}, // 0. orange
{1.0f, 0.0f, 1.0f, 1.0f}, // 1. violet
{0.0f, 1.0f, 0.0f, 1.0f}, // 2. green
{0.0f, 0.0f, 1.0f, 1.0f}, // 3. blue
{1.0f, 0.0f, 0.0f, 1.0f}, // 4. red
{1.0f, 1.0f, 0.0f, 1.0f} // 5. yellow
};
/* private float[] vertices = { // Vertices for the front face
-1.5f, 0.0f, 0.86f, // 0. left-bottom-front
1.5f, 0.0f, 0.86f, // 1. right-bottom-front
0.0f, 1.86f, 0.0f, // 2. left-top-front
// 3. right-top-front
};*/
private float[] vertices = { // Vertices for the front face
-1.0f, 0.0f, 0.86f, // 0. left-bottom-front
1.0f, 0.0f, 0.86f, // 1. right-bottom-front
0.0f, 1.86f, 0.0f, // 2. left-top-front
// 3. right-top-front
};
private float textures[] = {
//Mapping coordinates for the vertices
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
// Constructor - Set up the buffers
public PyramidNew( Context context) {
// Setup vertex-array buffer. Vertices in float. An float has 4 bytes
System.out.println("calling Pyramid:::::::::");
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // Use native byte order
vertexBuffer = vbb.asFloatBuffer(); // Convert from byte to float
vertexBuffer.put(vertices); // Copy data into buffer
vertexBuffer.position(0); // Rewind
ByteBuffer byteBuf = ByteBuffer.allocateDirect(textures.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(textures);
textureBuffer.position(0);
InputStream stream1 = context.getResources().openRawResource(R.drawable.splash_screen);
InputStream stream2 = context.getResources().openRawResource(R.drawable.bg);
InputStream stream3 = context.getResources().openRawResource(R.drawable.bg1);
try {
//BitmapFactory is an Android graphics utility for images
bitmap[0] = BitmapFactory.decodeStream(stream1);
bitmap[1] = BitmapFactory.decodeStream(stream2);
bitmap[2] = BitmapFactory.decodeStream(stream3);
} finally {
//Always clear and close
try {
stream1.close();
stream2.close();
stream3.close();
stream1 = stream2 = stream3 = null;
} catch (IOException e) {
}
}
}
// Draw the color cube
public void draw(GL10 gl, Context context) {
gl.glFrontFace(GL10.GL_CCW); // Front face in counter-clockwise orientation
gl.glEnable(GL10.GL_CULL_FACE); // Enable cull face
gl.glCullFace(GL10.GL_BACK); // Cull the back face (don't display)
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//loading the first texture in first face
loadTexture(gl, context, 0);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
// rotating the face and puting the second texture in face
gl.glRotatef(120.0f, 0.0f, 1.0f, 0.0f);
//gl.glColor4f(colors[1][0], colors[1][1], colors[1][2], colors[1][3]);
loadTexture(gl, context, 1);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
// Back - Rotate another 120 degree about y-axis and then put different texture
gl.glRotatef(120.0f, 0.0f, 1.0f, 0.0f);
//gl.glColor4f(colors[2][0], colors[2][1], colors[2][2], colors[2][3]);
loadTexture(gl, context, 2);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
}
public void loadTexture(GL10 gl, Context context, int currentImage) {
// Bitmap []bitmap = new Bitmap[3];
gl.glGenTextures(3, texturesID, 0); // Generate texture-ID array for 6 IDs
gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesID[currentImage]);
// Generate OpenGL texture images
// Create Nearest Filtered Texture
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
// Different possible texture parameters, e.g. GL10.GL_CLAMP_TO_EDGE
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
// Build Texture from loaded bitmap for the currently-bind texture ID
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[currentImage], 0);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
// Enable the texture state
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Point to our buffers
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
}
}
This is the content of my Texture class:
public int id;
public Texture(InputStream inputStream) {
ByteBuffer buf = null;
int tWidth = 0;
int tHeight = 0;
try {
PNGDecoder decoder = new PNGDecoder(inputStream);
buf = ByteBuffer.allocateDirect(4*decoder.getWidth()*decoder.getHeight());
decoder.decode(buf, decoder.getWidth()*4, PNGDecoder.TextureFormat.RGBA);
buf.rewind();
inputStream.close();
} catch (IOException exception) {
ErrorHandler.handleError("Failed to load image", exception);
}
id = glGenTextures();
glActiveTexture(id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tWidth, tHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
glBindTexture(GL_TEXTURE_2D, 0);
}
This is how i render:
glActiveTexture(background.id);
glBindTexture(GL_TEXTURE_2D, background.id);
glBindBuffer(GL_ARRAY_BUFFER, vboVertexHandle);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 4*18);
glDrawArrays(GL_TRIANGLES, 0, 6);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glBindTexture(GL_TEXTURE_2D, 0);
and this is the fragment shader:
#version 330
in vec2 textureCoordinate;
out vec4 outputColor;
uniform sampler2D texture_diffuse;
void main() {
outputColor.rgb = vec3(1.0f, 1.0f, 1.0f);
outputColor += texture2D(texture_diffuse, textureCoordinate);
}
What do i do wrong? The texture coordinates passed to the shader program are 100% correct (i checked). But i still get a white quad.
Note: i use this png decoder.
EDIT:
I printed out floats for every 4 bytes to the console, and i got 0.00.00.00.0.... Doest that mean that the texture is loaded incorectly, or the informations is stored to the buffer in a different format?
Your fragment shader looks wrong - you set a white colour and add the value from the texture, so it will clamp to white. Just do something more like this
void main() {
outputColor.a = 1.0f;
outputColor.rgb = texture2D(texture_diffuse, textureCoordinate);
}
I've been following the tutorial at http://developer.android.com/resources/tutorials/opengl/opengl-es20.html for OpenGL ES on android. I've gotten to the, "Apply Projection and Camera View" section however I always seem to get a blank screen with no triangle, the previous section worked perfectly fine. I also tried just copy pasting the entire tutorial into my code but got the same result. Changing the line:
gl_Position = uMVPMatrix * vPosition;
to:
gl_Position = vPosition;
puts the application back to the first section (triangle stretches depending on screen orientation). Any idea what the problem is? Here's the code I have so far just in case I missed something:
public class GLTest20Renderer implements Renderer {
private final String vertexShaderCode =
// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix; \n" +
"attribute vec4 vPosition; \n" +
"void main(){ \n" +
// the matrix must be included as a modifier of gl_Position
" gl_Position = uMVPMatrix * vPosition; \n" +
"} \n";
private final String fragmentShaderCode =
"precision mediump float; \n" +
"void main(){ \n" +
" gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n" +
"} \n";
private FloatBuffer triangleVB;
private int mProgram;
private int maPositionHandle;
private int muMVPMatrixHandle;
private float[] mMVPMatrix = new float[16];
private float[] mMMatrix = new float[16];
private float[] mVMatrix = new float[16];
private float[] mProjMatrix = new float[16];
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
initShapes();
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = 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); // creates OpenGL program executables
// get handle to the vertex shader's vPosition member
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
}
public void onDrawFrame(GL10 unused) {
GLES20.glClear( GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT );
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// Prepare the triangle data
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 12, triangleVB);
GLES20.glEnableVertexAttribArray(maPositionHandle);
// Apply a ModelView Projection transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
}
private void initShapes() {
float triangleCoords[] = {
// X, Y, Z
-0.5f, -0.25f, 0,
0.5f, -0.25f, 0,
0.0f, 0.559016994f, 0
};
// initialize vertex Buffer for triangle
ByteBuffer vbb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
vbb.order(ByteOrder.nativeOrder());// use the device hardware's native byte order
triangleVB = vbb.asFloatBuffer(); // create a floating point buffer from the ByteBuffer
triangleVB.put(triangleCoords); // add the coordinates to the FloatBuffer
triangleVB.position(0); // set the buffer to read the first coordinate
}
private int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
}
I'm running all this on a Samsung Galaxy S2.
Fixed, just changed the near point in the lookat to be under 3:
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 2, 7);