I am trying to display a single texture on a quad.
I had a working VertexObject, which drew a square(or any geometric object) fine. Now I tried expanding it to handle textures too, and the textures doesn't work. I only see the quad in one solid color.
The coordinate data is in an arrayList:
/*the vertices' coordinates*/
public int coordCount = 0;
/*float array of 3(x,y,z)*/
public ArrayList<Float> coordList = new ArrayList<Float>(coordCount);
/*the coordinates' indexes(if used)*/
/*maximum limit:32767*/
private int orderCount = 0;
private ArrayList<Short> orderList = new ArrayList<Short>(orderCount);
/*textures*/
public boolean textured;
private boolean textureIsReady;
private ArrayList<Float> textureList = new ArrayList<Float>(coordCount);
private Bitmap bitmap; //the image to be displayed
private int textures[]; //the textures' ids
The buffers are initialized in the following function:
/*Drawing is based on the buffers*/
public void refreshBuffers(){
/*Coordinates' List*/
float coords[] = new float[coordList.size()];
for(int i=0;i<coordList.size();i++){
coords[i]= coordList.get(i);
}
// initialize vertex byte buffer for shape coordinates
ByteBuffer bb = ByteBuffer.allocateDirect(
// (number of coordinate values * 4 bytes per float)
coords.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(coords);
// set the buffer to read the first coordinate
vertexBuffer.position(0);
/*Index List*/
short order[] = new short[(short)orderList.size()];
for(int i=0;i<order.length;i++){
order[i] = (short) orderList.get(i);
}
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(
// (# of coordinate values * 2 bytes per short)
order.length * 2);
dlb.order(ByteOrder.nativeOrder());
orderBuffer = dlb.asShortBuffer();
orderBuffer.put(order);
orderBuffer.position(0);
/*texture list*/
if(textured){
float textureCoords[] = new float[textureList.size()];
for(int i=0;i<textureList.size();i++){
textureCoords[i] = textureList.get(i);
}
ByteBuffer byteBuf = ByteBuffer.allocateDirect(textureCoords.length * 4);
byteBuf.order(ByteOrder.nativeOrder());
textureBuffer = byteBuf.asFloatBuffer();
textureBuffer.put(textureCoords);
textureBuffer.position(0);
}
}
I load the image into the object with the following code:
public void initTexture(GL10 gl, Bitmap inBitmap){
bitmap = inBitmap;
loadTexture(gl);
textureIsReady = true;
}
/*http://www.jayway.com/2010/12/30/opengl-es-tutorial-for-android-part-vi-textures/*/
public void loadTexture(GL10 gl){
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterx(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
/*bind bitmap to texture*/
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
}
And the drawing happens based on this code:
public void draw(GL10 gl){
if(textured && textureIsReady){
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//loadTexture(gl);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0,
textureBuffer);
}else{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glColor4f(color[0], color[1], color[2], color[3]);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0,
vertexBuffer);
}
if(!indexed)gl.glDrawArrays(drawMode, 0, coordCount);
else gl.glDrawElements(drawMode, orderCount, GL10.GL_UNSIGNED_SHORT, orderBuffer);
if(textured && textureIsReady){
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
}else{
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
The initialization is as follows:
pic = new VertexObject();
pic.indexed = true;
pic.textured = true;
pic.initTexture(gl,MainActivity.bp);
pic.color[0] = 0.0f;
pic.color[1] = 0.0f;
pic.color[2] = 0.0f;
float inputVertex[] = {2.0f,2.0f,0.0f};
float inputTexture[] = {0.0f,0.0f};
pic.addTexturedVertex(inputVertex,inputTexture);
inputVertex[0] = 2.0f;
inputVertex[1] = 8.0f;
inputTexture[0] = 0.0f;
inputTexture[0] = 1.0f;
pic.addTexturedVertex(inputVertex,inputTexture);
inputVertex[0] = 8.0f;
inputVertex[1] = 8.0f;
inputTexture[0] = 1.0f;
inputTexture[0] = 1.0f;
pic.addTexturedVertex(inputVertex,inputTexture);
inputVertex[0] = 8.0f;
inputVertex[1] = 2.0f;
inputTexture[0] = 1.0f;
inputTexture[0] = 0.0f;
pic.addTexturedVertex(inputVertex,inputTexture);
pic.addIndex((short)0);
pic.addIndex((short)1);
pic.addIndex((short)2);
pic.addIndex((short)0);
pic.addIndex((short)2);
pic.addIndex((short)3);
The coordinates are just simply added to the arrayList, and then I refresh the buffers.
The bitmap is valid, because it is showing up on an imageView.
The image is a png file with the size of 128x128 in the drawable folder.
For what I gathered the image is getting to the vertexObject, but something isn't right with the texture mapping. Any pointers on what am I doing wrong?
Okay, I got it!
I downloaded a working example from the internet and rewrote it, to resemble the object(presented above) step by step. I observed if it works on every step. Turns out, the problem isn't in the graphical part, because the object worked in another context with different coordinates.
Long story short:
I got the texture UV mapping wrong!
That's why I got the solid color, the texture was loaded, but the UV mapping wasn't correct.
Short story long:
At the lines
inputVertex[0] = 2.0f;
inputVertex[1] = 8.0f;
inputTexture[0] = 0.0f;
inputTexture[0] = 1.0f;
The indexing was wrong as only the first element of inputTexture was updated only. There might have been some additional errors regarding the sizes of the different array describing the vertex coordinates, but rewriting on the linked example fixed the problem, and it produced a mroe concise code.
Related
I'm currently developing an .obj file loader on Android. I have done the basics, and the 3d mesh is drawn correctly with OpenGl. Unfortunately I have a problem in binding the texture. Let me explain with more details:
The .obj file has the following structure:
v -0.751804 0.447968 -1.430558
v -0.751802 2.392585 -1.428428
... etc list with all the vertices ...
vt 0.033607 0.718905
vt 0.033607 0.718615
... etc list with all the texture coordinates ...
f 237/1 236/2 253/3 252/4
f 236/2 235/5 254/6 253/3
... etc list with all the faces ...
The f lines idicate the index where the appropriate vertex and texture coordinates are stored, like
f vertex_index/texture_coord_index
So my program
parses the vertices and stores them in a Vector<Float>,
parses the texture coordinates and stores them in a Vector<Float>
and finally parses the faces and stores every vertex index in a Vector<Short> and every texture coordinate index in a Vector<Short>
After all this code, I'm creating the appropriate buffers:
public void buildVertexBuffer(){
ByteBuffer vBuf = ByteBuffer.allocateDirect(vertices.size() * 4);
vBuf.order(ByteOrder.nativeOrder());
vertexBuffer = vBuf.asFloatBuffer();
vertexBuffer.put(toFloatArray(vertices));
vertexBuffer.position(0);
}
where vertices is the vector that stores the float vertices
public void buildFaceBuffer(){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(faces.size() * 2);
byteBuffer.order(ByteOrder.nativeOrder());
faceBuffer = byteBuffer.asShortBuffer();
faceBuffer.put(toShortArray(faces));
faceBuffer.position(0);
}
where faces is the vector that stores the indices and
public void buildTextureBuffer(Vector<Float> textures){
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(texturePointers.size() * 4 * 2);
byteBuffer.order(ByteOrder.nativeOrder());
textureBuffer = byteBuffer.asFloatBuffer();
for(int i=0; i<texturePointers.size(); i++){
float u = textures.get(texturePointers.get(i) * 2);
float v = textures.get(texturePointers.get(i) * 2 + 1);
textureBuffer.put(u);
textureBuffer.put(v);
}
textureBuffer.position(0);
}
where textures are the float texture coordinates and texturePointers point to the textures' values.
The binding happens here:
public int[] loadTexture(GL10 gl, Context context){
if(textureFile == null)
return null;
int resId = getResourceId(textureFile, R.drawable.class);
if(resId == -1){
Log.d("Bako", "Texture not found...");
return null;
}
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
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);
/*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_CLAMP_TO_EDGE);*/
/*int size = bitmap.getRowBytes() * bitmap.getHeight();
ByteBuffer buffer = ByteBuffer.allocateDirect(size);
bitmap.copyPixelsToBuffer(buffer);
gl.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_INT, buffer);*/
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
return textures;
}
Finally my draw() method of my mesh looks like this
public void draw(GL10 gl){
if(bindedTextures != null){
gl.glBindTexture(GL10.GL_TEXTURE_2D, bindedTextures[0]);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL10.GL_CW);
}
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
for(int i=0; i<parts.size(); i++){
ModelPart modelPart = parts.get(i);
Material material = modelPart.getMaterial();
if(material != null){
FloatBuffer a = material.getAmbientColorBuffer();
FloatBuffer d = material.getDiffuseColorBuffer();
FloatBuffer s = material.getSpecularColorBuffer();
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, a);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, s);
gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, d);
}
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, modelPart.getTextureBuffer()); // returns the texture buffer created with the buildTextureBuffer() method
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL10.GL_FLOAT, 0, modelPart.getNormalBuffer());
gl.glDrawElements(GL10.GL_TRIANGLES, modelPart.getFacesSize(), GL10.GL_UNSIGNED_SHORT, modelPart.getFaceBuffer());
//gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
//gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}
When i run this application the 3d model is drawn like a charm, but the texture is somehow streched. The image that contains the texture has a red background with the appropriate image in the center and this red background is drawn onto the whole 3d model.
Well my first question is if the textureBuffer built correctly. Do i have to change the code in buildTextureBuffer() ?
And the second one; is the the draw() method correct? Does my problem have to be with the faces buffer?
So, in OpenGL a vertex is whatever combination of information describes a particular point on the model. You're using the old fixed pipeline so a vertex is one or more of a location, some texture coordinates, a normal and a colour.
In OBJ a vt is only a location. The thing that maps to the OpenGL concept of a vertex is each unique combination of — in your case — location + texture coordinate pairs given after an f.
You need a mapping whereby if the f says 56/92 then you can lookup the 56/92 and find out that you consider that to be, say, vertex 23 and have communicated suitable arrays to OpenGL such that the location value in slot 23 was the 56th thing the OBJ gave as a v and the 92nd thing it gave as a vt.
Putting it another way, OBJ files have an extra level of indirection that OpenGL does not.
It looks to me like you're not resolving that difference. A common approach would be to use a HashMap from v/vt pair to output index, building your output arrays on demand as you parse the f.
I have small cubes that make up a grid to make 3D cube. On each small cube I use a bitmap to texture the surface, but I want to use more then one picture. I can build more textures within loadTextures and add them tofinal int[] textureHandle = new int[1]; and return them. How do I instantiate them to each small cube I'm drawing though?
#Override
public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
{
mLastRequestedCubeFactor = mActualCubeFactor = 3;
generateCubes(mActualCubeFactor, false, false);
// Set the background clear color to black.
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// Use culling to remove back faces.
GLES20.glEnable(GLES20.GL_CULL_FACE);
// Enable depth testing
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
// Position the eye in front of the origin.
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = -0.5f;
// We are looking toward the distance
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = -5.0f;
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera position.
// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
// view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
final String vertexShader = RawResourceReader.readTextFileFromRawResource(mLessonSevenActivity, R.raw.lesson_seven_vertex_shader);
final String fragmentShader = RawResourceReader.readTextFileFromRawResource(mLessonSevenActivity, R.raw.lesson_seven_fragment_shader);
final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
new String[] {"a_Position", "a_Normal", "a_TexCoordinate"});
// Load the texture
mAndroidDataHandle = TextureHelper.loadTexture(mLessonSevenActivity, R.drawable.usb_android);
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mAndroidDataHandle);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mAndroidDataHandle);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
// Initialize the accumulated rotation matrix
Matrix.setIdentityM(mAccumulatedRotation, 0);
}
public class TextureHelper
{
public static 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];
}
}
How do I instantiate them to each small cube I'm drawing though?
In short, you don't.
Even in desktop GL, where vertex instancing is a core feature, there is no way to change texture bindings without splitting the draw into multiple draw calls.
You could use a texture atlas, array texture or geometry shader to sample from a different (already bound) texture or a different part of a single texture. Alternatively, you could use bindless textures. Each one of those things I mentioned requires a newer version of GL than the last.
The only way to do this in ES is going to be either multiple draw calls, or a texture atlas/binding textures to multiple texture units. But since instancing is not a core feature, computing the texture coordinate / unit dynamically is a tremendous pain and will involve duplicating vertex data.
The bottom line is, what do you really mean by instantiated cube? Are you trying to draw 500 cubes in a single operation, or are you drawing them separately by calling some method in your cube class? Instancing has different meanings depending on the context.
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;
}
I want to create a electric lightning in OpenGl. For that I wrote this function:
public Blitz()
{
points = new float[STEPS * 3];
for(int i = 0; i < STEPS; i += 3)
{
points[i] = (float) (startX + i * (endX - startX) / STEPS);
points[i + 1] = (float) (startY + i * (endY - startY) / STEPS);
points[i + 2] = 0;
}
// ...
vertexBuffer.put(points);
vertexBuffer.position(0);
}
public void update()
{
for(int i = 0; i < STEPS; i += 3)
{
float rnd = random(); // creates rnd float
if(points[i] + rnd < startX + 5 && points[i] + rnd > startX - 5)
{
points[i] += rnd;
}
}
vertexBuffer.clear();
vertexBuffer.put(points);
vertexBuffer.position(0);
}
public void render()
{
texture.bind();
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glLineWidth(10);
gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, STEPS);
}
Here is my Texture Class that I use for my textures:
public class Texture
{
private GL10 gl;
FloatBuffer texCoords;
private int textureID;
public Texture(GL10 gl, Bitmap bmp)
{
this.gl = gl;
int[] TextureIDs = new int[1];
gl.glGenTextures(1, TextureIDs, 0);
textureID = TextureIDs[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA, bmp, 0);
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);
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_CLAMP_TO_EDGE);
ByteBuffer buffer = ByteBuffer.allocateDirect( 4 * 2 * 4 );
buffer.order(ByteOrder.nativeOrder());
texCoords = buffer.asFloatBuffer();
texCoords.put(0);
texCoords.put(0);
texCoords.put(0);
texCoords.put(1);
texCoords.put(1);
texCoords.put(1);
texCoords.put(1);
texCoords.put(0);
texCoords.rewind();
}
public void bind()
{
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_SRC_ALPHA);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texCoords);
}
public void dispose()
{
int[] textures = {textureID};
gl.glDeleteTextures(1, textures, 0);
textureID = 0;
}
}
With a normal color all works great but if I want to put this texture on the lines it comes to this result:
Do you have any ideas why? What is my mistake?
Your mistake is, that you assume, that a OpenGL line would be able to draw a texture with one coordinate varying perpendicular to the lines direction. OpenGL simply can't do that, because texture coordinates are vertex attributes and there are only two vertices to a line segment. Which means, that any texture coordinate variation is possible only along the line, not perpendicular to it.
The solution is not to draw a line, but a quad or a triangle strip with vertices being extruded to both sides of the line. This is most easily done using a shader operating in screen parallel space.
When i was applying color buffer and blending on a solid circle, the color in first 20 degrees does not display properly, I got some sort of color ribbon but that is not what it supposed to be, maybe I have done something wrong in my code?
public class Circle {
boolean circleChecked;
private int points=361;
private float vertices[]={0.0f,0.0f,0.0f};
private float[] fogcolor = {0.2f,0.4f,0.7f,0.9f};
private FloatBuffer vertBuff, textureBuffer;
private FloatBuffer colorBuffer; // Buffer for color-array (NEW)
float texData[] = null;
private float[] colors = { // Colors for the vertices (NEW)
0.7f,0.7f,0.7f,0.5f,
0.7f,0.7f,0.7f,0.5f,
0.7f,0.7f,0.7f,0.5f
};
float theta = 0;
int[] textures = new int[1];
int R=1;
float textCoordArray[] =
{
-R,
(float) (R * (Math.sqrt(2) + 1)),
-R,
-R,
(float) (R * (Math.sqrt(2) + 1)),
-R
};
public Circle(float size, float positionX, float positionY){
vertices = new float[(points)*3];
for(int i=0;i<3;i+=3){
vertices[i]=positionX * size;
vertices[i+1]=positionY *size;
vertices[i+2]=0.51f;
}
for(int i=3;i<(points)*3;i+=3)
{
vertices[i]=((float) ( Math.cos(theta))/3+positionX) * size;
vertices[i+1]=((float) (Math.sin(theta))/3+positionY) *size;
vertices[i+2]=0.5f;
theta += Math.PI / 90;
}
ByteBuffer bBuff=ByteBuffer.allocateDirect(vertices.length*4);
bBuff.order(ByteOrder.nativeOrder());
vertBuff=bBuff.asFloatBuffer();
vertBuff.put(vertices);
vertBuff.position(0);
// Setup color-array buffer. Colors in float. A float has 4 bytes (NEW)
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);
cbb.order(ByteOrder.nativeOrder()); // Use native byte order (NEW)
colorBuffer = cbb.asFloatBuffer(); // Convert byte buffer to float (NEW)
colorBuffer.put(colors); // Copy data into buffer (NEW)
colorBuffer.position(0); // Rewind (NEW)
ByteBuffer bBuff2=ByteBuffer.allocateDirect(textCoordArray.length * 4 * 360);
bBuff2.order(ByteOrder.nativeOrder());
textureBuffer=bBuff2.asFloatBuffer();
textureBuffer.put(textCoordArray);
textureBuffer.position(0);
}
public void draw(GL10 gl){
//gl.glDisable(GL10.GL_LIGHTING);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//gl.glColor4f(0.8f, 0.8f, 0.8f, 1);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertBuff);
gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
// if(circleChecked){
// gl.glColor4f(0.2f, 0.4f, 0.8f, 1);
//}
//gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_BLEND);
gl.glPushMatrix();
gl.glFogf(GL10.GL_FOG_MODE, GL10.GL_LINEAR);
gl.glFogf(GL10.GL_FOG_START, 3.0f);
gl.glFogf(GL10.GL_FOG_END, 5.0f);
float fogColor[] = {1f, 0.0f, 0.5f, 1.0f};
gl.glFogfv(GL10.GL_FOG_COLOR, fogColor, 0);
gl.glFogf(GL10.GL_FOG_DENSITY, 0.9f);
gl.glEnable(GL10.GL_FOG);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
//gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); //4
//gl.glTexCoordPointer(2, GL10.GL_FLOAT,0, textureBuffer); //5
// gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, points/2);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY); // Disable color-array (NEW)
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glPopMatrix();
//gl.glDisable(GL10.GL_FOG);
}
}
The problem is in your color array. glDrawArrays gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, points/2); will take values from each buffer you enable its client state "gl.glEnableClientState(GL10.GL_COLOR_ARRAY)". The number of those values equals to the last parameter and in your case points/2 but your color buffer has only 3 values. The result is that only first of your triangles has correct color mapping, all the rest is garbage and the results are unpredictable.
Although this might seem inefficient for your case, you will need to repeat those color parameters in your "for" loop where you set your vertex coordinates and the length of the buffer should be the same as "vertBuffer". And by length I mean number of values, not bytes, where 1 color value consists of 4 float values and 1 position value consists of 3 float values in your case.