OpenGL ES 2.0 Android drawing textured triangles - android

I have the book "OpenGL ES 2 for Android A Quick-Start Guide" and it is going through a good tutorial on OpenGL and android. The issue I am having though is that it's examples don't use index buffers for the creation of their shapes.
I am trying to texture a square which I define the 4 verticies of the square (plus an S coordinate and T coordinate for the textures) and then render using the index buffer. However, I the color of the square is only the bottom left corner of the PNG texture file and it is not getting rendered correctly on my square.
This is my render function:
public void onDrawFrame(float[] matrixViewProjection)
{
super.onDrawFrame(matrixViewProjection);
GLES20.glUseProgram(this.shaderProgram);
int posHandle = GLES20.glGetAttribLocation(shaderProgram,"vPosition");
GLES20.glEnableVertexAttribArray(posHandle);
GLES20.glVertexAttribPointer(posHandle,coordsPerVertex,GLES20.GL_FLOAT,false,vertexStride,vertexBuffer);
int colHandle = GLES20.glGetUniformLocation(shaderProgram,"vColor");
GLES20.glUniform4fv(colHandle,1,color,0);
int mvpHandle = GLES20.glGetUniformLocation(shaderProgram,"uMVPMatrix");
GLES20.glUniformMatrix4fv(mvpHandle,1,false,matrixSum,0);
GLES20.glDrawElements(GLES20.GL_TRIANGLES,indexBufferCount,GLES20.GL_UNSIGNED_SHORT,drawListBuffer);
GLES20.glDisableVertexAttribArray(posHandle);
}
And this is my constructor for my square object:
public ShapeSquare(Context context, int program, float size)
{
float squareCoords[] = {
-(size/2.0f),-(size/2.0f),0f, 0f, 0f,
-(size/2.0f), (size/2.0f),0f, 0f, 1f,
(size/2.0f), (size/2.0f),0f, 1f, 1f,
(size/2.0f),-(size/2.0f),0f, 0f, 0f
};
short drawOrder[] = {0,1,3,1,2,3};
indexBufferCount = drawOrder.length;
ByteBuffer bb = ByteBuffer.allocateDirect(squareCoords.length*4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length*2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
shaderProgram = program;
shaderProgram = program;
textureID = TextureHelper.loadTexture(context, R.raw.texture1);
}
And these are some of the definitions I have, although I don't know if they are correct
protected static int coordsPerVertex = 3;
protected int vertexCount = 12/coordsPerVertex;
protected static final int vertexStride = coordsPerVertex*4+8;
Here is what is rendered...
And this is the texture I have. (Take note of the bottom left corner)

You have to specify 2 array of vertex attribute data (glVertexAttribPointer).
1 for the vertex coordinates and 1 for the texture coordinates:
int posHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");
int texHandle = GLES20.glGetAttribLocation(shaderProgram, ???);
GLES20.glEnableVertexAttribArray(posHandle);
GLES20.glEnableVertexAttribArray(texHandle );
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(posHandle, coordsPerVertex, GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
vertexBuffer.position(3);
GLES20.glVertexAttribPointer(texHandle, coordsPerVertex, GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
Note the vertexBuffer contains tuples of 5 elements (x, y, z, u, v). The stride in bytes is 5*4. The offset of the vertex coordinates is 0 and the offset of the texture coordinates is 3*4 respectively 3 elements in the float buffer.
Since you do not use Vertex Buffer Objects, you should prefer to create separate arrays (respectively float buffers) for the attributes.

Related

How to detect if I tapped on GL10 object

I'm drawing a simple Triangle that is displayed on screen using AndAR. Now I want to make a simple interaction. By that I mean that I want to display a Toast when the drawn object is tapped. I've already implemented onTouchEvent so I can get XY coordinates of the place where I tapped the screen. Now I need to check if this point is in area of my 2D triangle. How can I get coordinates of points of my triangle ? Triangle is "sticked" to the marker and it is drawn when marker is recognied, so the coordinates are changed in real time based on view angle. This is the biggest problem. Any idea ?
public class Triangle extends ARObject implements BasicShape {
private final FloatBuffer vertexBuffer;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float triangleCoords[] = {
// in counterclockwise order:
25.0f, 25.622008459f, 25.0f,// top
-25.5f, -25.311004243f, 25.0f,// bottom left
25.5f, -25.311004243f, 25.0f // bottom right
};
float color[] = { 1f, 0f, 0f, 0.0f };
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public Triangle(String name, String patternName, double markerWidth, double[] markerCenter) {
super(name, patternName, markerWidth, markerCenter);
// 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);
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* #param gl - The OpenGL ES context in which to draw this shape.
*/
#Override
public void draw(GL10 gl) {
super.draw(gl);
// Since this shape uses vertex arrays, enable them
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// draw the shape
gl.glColor4f( // set color:
color[0], color[1],
color[2], color[3]);
gl.glVertexPointer( // point to vertex data:
COORDS_PER_VERTEX,
GL10.GL_FLOAT, 0, vertexBuffer);
gl.glDrawArrays( // draw shape:
GL10.GL_TRIANGLES, 0,
triangleCoords.length / COORDS_PER_VERTEX);
gl.glTranslatef(0.0f, 0.0f, 12.5f);
// Disable vertex array drawing to avoid
// conflicts with shapes that don't use it
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
#Override
public void init(GL10 gl10) {
}
}

Android OpenGL ES rendering subdivided Mesh

I'm trying to render a subdivided mesh with a displacement texture on it and a color texture. To do so I go through every pixel, create a vertex for it, and move that vertex according to a black and white image I have. The problem is that when I render it, I get something that looks a bit like TV snow.
Here's the relevant code:
public Plane(Bitmap image, Bitmap depth)
{
this.image = image; //color image
this.depth = depth; //BW depth image
this.w = image.getWidth();
this.h = image.getHeight();
vertexCoords = vertexArray(); //places vertices in 3d
drawOrder = orderArray(); //sets the draw order
colorCoords = colorArray(); //sets color per vertex
ByteBuffer bb = ByteBuffer.allocateDirect(vertexCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vertexCoords);
vertexBuffer.position(0);
ByteBuffer dlb = ByteBuffer.allocateDirect(drawOrder.length * 4);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
ByteBuffer cbb = ByteBuffer.allocateDirect(colorCoords.length * 4);
cbb.order(ByteOrder.nativeOrder());
colorBuffer = cbb.asFloatBuffer();
colorBuffer.put(colorCoords);
colorBuffer.position(0);
}
public void draw(GL10 gl) {
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW);
// Enable face culling.
gl.glEnable(GL10.GL_CULL_FACE);
// What faces to remove with the face culling.
gl.glCullFace(GL10.GL_BACK);
// Enabled the vertices buffer for writing and to be used during
// rendering.
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// Specifies the location and data format of an array of vertex
// coordinates to use when rendering.
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// Enable the color array buffer to be used during rendering.
gl.glEnableClientState(GL10.GL_COLOR_ARRAY); // NEW LINE ADDED.
// Point out the where the color buffer is.
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer); // NEW LINE ADDED.
gl.glDrawElements(GL10.GL_TRIANGLES, drawOrder.length,
GL10.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable the vertices buffer.
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
// Disable face culling.
gl.glDisable(GL10.GL_CULL_FACE);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
}
What can I do to actually view the model, instead of this snow thing? The patterns change if I turn my screen on and off, and they sometimes change randomly. It seems that the colors present in the original bitmap are also present in the snow (the snow color changes with different pictures), so I know I'm doing something right, I just don't know what's wrong here.
EDIT: here's the code for vertexArray()
public float[] vertexArray()
{
int totalPoints = w*h;
float[] arr = new float[totalPoints*3];
int i = 0;
for(int y = 0; y<h; y++)
{
for(int x = 0; x<w; x++)
{
arr[i] = x * 0.01f;
arr[i+1] = y * 0.01f;
arr[i+2] = 1.0f;//getDepth(x,y);
i+=3;
}
}
return arr;
}

OpenGL 2.0 ES Android Draw Rectangle

I'm following Google's tutorial (http://developer.android.com/training/graphics/opengl/environment.html) and i think that i everything correctly done. But i have problem, Triangle and Rectangle is invisible and LogCat doesn't show any error.
This is my code for rectangle:
package com.example.gameengine;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import android.opengl.GLES20;
/**
* A two-dimensional square for use as a drawn object in OpenGL ES 2.0.
*/
public class GLObject {
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;" +
"attribute vec4 vPosition;" +
"void main() {" +
// The matrix must be included as a modifier of gl_Position.
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
" gl_Position = uMVPMatrix * vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
private final FloatBuffer vertexBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float squareCoords[] = {
-0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };
/**
* Sets up the drawing object data for use in an OpenGL ES context.
*/
public GLObject() {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = GLRenderer.loadShader(
GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = GLRenderer.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); // create OpenGL program executables
}
/**
* 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);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 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, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
GLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the square
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
And this is how i draw rectangle:
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
// Draw square
mSquare.draw(mMVPMatrix);
GLSurface is correctly implmenent(i can change background color)
EDIT: Since vertex buffer objects are not being used for drawing here, no need to use the ELEMENT_ARRAY_BUFFER. That being the case, have you tried just specifying an unit matrix for the mvp that will show the quad without any transformation ? That will rule out the possibility of the quad not getting drawn at all and hence being invisible.
Is this the full drawing code ? It looks like you are not binding the ELEMENT_ARRAY_BUFFER, that is needed for indexing the vertices using drawListBuffer.
Using the below, you can enable this for the default object (0).
glBindBuffer(GL_ARRAY_BUFFER, somebufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, someotherBufferID);

GLES20 Texture Not Working on Some Devices

I have tried to add a fairly simple extension on top of Android's example OpenGL 2.0 project in order to add texturing to basic shapes. This seems pretty straightforward, but on certain devices (Samsung Nexus S, LG Optimus 3D, Samsung Galaxy S) the texture just does not render.
This is actually a problem that I am having on a much larger project, but I was able to reproduce the issue with the simple project below in the hope that someone here has an idea of where my code presents issues, or how to specifically architect GL textures for these devices (maybe there are issues with the devices).
To give an idea of how this object is used: In the GLSurfaceView.Renderer's onSurfaceCreated method I am instantiating a Square() object and in the onDrawFrame method I am calling Square's draw() method. However, all of the relevant code to dealing with textures should appear in this Square class which is almost exactly identical to Google's own example.
Many thanks in advance to anyone who takes a crack at this.
class Square {
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;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
" gl_Position = vPosition * uMVPMatrix;" +
" v_TexCoordinate = a_TexCoordinate;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
" gl_FragColor = texture2D(u_Texture, v_TexCoordinate);" +
"}";
private final FloatBuffer vertexBuffer;
private final FloatBuffer textureBuffer;
private final ShortBuffer drawListBuffer;
private final int mProgram;
private int mPositionHandle;
private int mColorHandle;
private int mMVPMatrixHandle;
// number of coordinates per vertex in this array
static final int COORDS_PER_VERTEX = 3;
static float squareCoords[] = { -0.5f, 0.5f, 0.0f, // top left
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f, // bottom right
0.5f, 0.5f, 0.0f }; // top right
final float[] previewTextureCoordinateData =
{
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
private int textureDataHandle;
private int textureUniformHandle;
private int textureCoordinateHandle;
private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
// Set color with red, green, blue and alpha (opacity) values
float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };
private int loadTexture(final Context context, final int resourceId)
{
final int[] textureHandle = new int[1];
GLES20.glGenTextures(1, textureHandle, 0);
if (textureHandle[0] != 0)
{
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false; // No pre-scaling
// Read in the resource
final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
// Bind to the texture in OpenGL
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
// Set filtering
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_NEAREST);
// Load the bitmap into the bound texture.
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
// Recycle the bitmap, since its data has been loaded into OpenGL.
bitmap.recycle();
}
if (textureHandle[0] == 0)
{
throw new RuntimeException("Error loading texture.");
}
return textureHandle[0];
}
public Square(Context context) {
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
squareCoords.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(squareCoords);
vertexBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
drawOrder.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);
ByteBuffer texCoordinates = ByteBuffer.allocateDirect(previewTextureCoordinateData.length * 4);
texCoordinates.order(ByteOrder.nativeOrder());
textureBuffer = texCoordinates.asFloatBuffer();
textureBuffer.put(previewTextureCoordinateData);
textureBuffer.position(0);
// prepare shaders and OpenGL program
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
textureDataHandle = loadTexture(context, R.drawable.color_texture);
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); // create OpenGL program executables
}
public void draw(float[] mvpMatrix) {
// Add program to OpenGL environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 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);
textureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
GLES20.glVertexAttribPointer(textureCoordinateHandle, 2, GLES20.GL_FLOAT, false,
0, textureBuffer);
GLES20.glEnableVertexAttribArray(textureCoordinateHandle);
textureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
MyGLRenderer.checkGlError("glGetUniformLocation");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandle);
GLES20.glUniform1i(textureUniformHandle, 0);
// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
MyGLRenderer.checkGlError("glUniformMatrix4fv");
// Draw the square
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
}
I'll guess that this is a Power-of-two problem.
By default, the GL_TEXTURE_WRAP setting of glTexParameter is set to GL_REPEAT, and textures that use GL_REPEAT must be power-of-two sized:
Similarly, if the width or height of a texture image are not powers of two and either the
GL_TEXTURE_MIN_FILTER is set to one of the functions that requires mipmaps
or the GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T is not
set to GL_CLAMP_TO_EDGE, then the texture image unit will return
(R, G, B, A) = (0, 0, 0, 1).
You may start with a power-of-two texture, but when you use a BitmapFactory.decodeResource to generate a bitmap, it helpfully(?) scales this based on the density of a device. So for example if you load a 512*512 source texture from drawable folder on a HDPI device, I believe it scales it by 1.5x, so you're left with something that is not Po2.
This gives you the result that your textures don't work on a ton of devices, because those devices are all of a density that causes you to generate illegal texture sizes.
The solution in this case would be to place your (power of 2) source texture into the resource folder drawable-nodpi, which will prevent any density-based scaling. Either that or use CLAMP_TO_EDGE, which doesn't care about Po2.

writing .3ds or .obj loader in java

Iv'e exported a model in blender to a .obj file. Iv'e managed to create a very simple
class that loads vertices and indices to arrays. My problem is that i want the texture coordinates (vt) and normals (vn) as well. So for example, i would need 4 vertices * 6 faces for a simple cube to be able to use texture but i only get 8 in my .obj file, as well as i don't have a clue about how to handle the indices for vt since i can only have one array/buffer for indices but i get two different v/vt in .obj file.
Is there any loader out there that only returns arrays or similar for vertex, texture, normals, and one array of indices? Or examples of how to write one? Iv'e only found loaders in complete 3d engines so far and that is not what i want.
4 vertices * 6 faces is more than you need. Actually it will be not efficient. Exported vertices that you've got are optimized with indexes. Using Opengl-es you can point from where to get vertices(array) and then draw a vertices using their indexes in another array. In result you get 8 vertices versus possible 24 vertices, you need less memory to store. So efficience is 16/24 *100%. Imagine that you'll have a model with 1000 vertices.
Index of vertex means that in another array with a proper offset GPU will get a vertex (size_of_vertex(3 floats)*index) and a proper offset for UV coords (size_of_UVcoord(2 floats)*index)
this code for opengl ES 2.0 but you can get an idea:
GLES20.glUseProgram(programTextured);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
sqTex.getVertexBuffer().position(sqTex.VERT_OFFSET);
GLES20.glVertexAttribPointer(GLES20.glGetAttribLocation(programTextured, "aPosition") 3, GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer()); GLES20.glEnableVertexAttribArray(GLES20.glGetAttribLocation(programTextured, "aPosition"));
sqTex.getVertexBuffer().position(sqTex.TEXT_OFFSET);
GLES20.glVertexAttribPointer(
GLES20.glGetAttribLocation(programTextured, "aTextureCoord"), 2,
GLES20.GL_FLOAT, false, 5 * 4, sqTex.getVertexBuffer());
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, sqTex.getIndexBuffer());
and sqTEx is a instance of TexturedSquare:
public class TexturedSquare {
// private float[] vertices=new float[4];
float vertices[] = { -1.0f, -1.0f, 0.0f,0.0f,0.0f, // 0, Top Left //x,y,z,u,v
1.0f, -1.0f, 0.0f,0.0f,1.0f, // 1, Bottom Left
1.0f, 1.0f, 0.0f,1.0f,1.0f, // 2, Bottom Right
-1.0f, 1.0f, 0.0f,1.0f,0.0f, // 3, Top Right
};
public static int VERT_OFFSET=0;
public static int TEXT_OFFSET=3;
short[] indices = { 0, 1, 2, 2, 3, 0 };;
// Our vertex buffer.
private FloatBuffer vertexBuffer;
// Our index buffer.
private ShortBuffer indexBuffer;
public TexturedSquare()
{
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
// short is 2 bytes, therefore we multiply the number if
// vertices with 2.
ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuffer = ibb.asShortBuffer();
indexBuffer.put(indices);
indexBuffer.position(0);
}
FloatBuffer getVertexBuffer(){
return vertexBuffer;
}
ShortBuffer getIndexBuffer(){
return indexBuffer;
}
}
Look a jPCT (or jPCT-AE), it's an exellent 3D library for Java (and/or Android). It supports 3ds/obj loading out of the box.

Categories

Resources