Related
I got a problem where using a ColorMatrixColorFilter gives different outputs.
I got this picture:
It has white, red, and transparent parts.
I have a view, overriding the onDraw(Canvas) method, where i draw this picture.
#Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(r, 0, 0, null);
canvas.drawBitmap(r, r.getWidth(), 0, blank);
canvas.drawBitmap(r, r.getWidth() * 2, 0, identity);//darker why?
canvas.drawBitmap(identityfiltered, r.getWidth() * 3, 0, null);
canvas.drawBitmap(identityfiltered, r.getWidth() * 4, 0, blank);
canvas.drawBitmap(identityfiltered, r.getWidth() * 5, 0, identity);//darker why?
}
The other variables explained:
Paint blank = new Paint(); //blank paint
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new float[] {
1, 0f, 0f, 0f, 0f, // red
0, 1f, 0f, 0f, 0f, // green
0, 0f, 1f, 0f, 0f, // blue
0, 0f, 0f, 1f, 0f, // alpha
});
Paint identity = new Paint();
identity.setColorFilter(filter); //the paint with identity filter
Bitmap r = BitmapFactory.decodeResource(getResources(), R.drawable.my_drawable);// my drawable
Bitmap identityfiltered = Bitmap.createBitmap(r.getWidth(), r.getHeight(), Config.ARGB_8888); //new bitmap with the same width height as my drawable, Bitmap r is drawn on this with the identity filter
Canvas c = new Canvas(identityfiltered);
c.drawBitmap(r, 0, 0, identity);
And the given output is:
As you can see the 3rd and 6th drawn bitmap is darker, that is when I directly draw to then View's canvas with the colorfilter. The question is why? Shouldn't it be the same, since the same filter is applied?
Update: I've been testing around, seems like it has something to do with semi-transparent images. I tried to copy fully opaque images and that went fine in all 6 cases.
But back to my image, I even tried with the identity matrix given by the API.
The new ColorMatrix() constructor comes with identity matrix initialized.
But had the same result.
In my GLSurfaceView.Renderer, I'm drawing my scene in two parts. The first group is offset and rotated, while the second is aligned to the "camera", so I apply a glRotate and glTranslate, then apply the exact opposite glTranslate and glRotate. On some devices, this works fine, but on others, the entire scene slowly rotates off "center".
Images: At start and After ~5 mins
Here's the onDraw() function:
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// rotate card table
gl.glRotatef(-20f, 1f, 0f, 0f);
gl.glRotatef( 5f, 0f, 1f, 0f);
gl.glRotatef(-10f, 0f, 0f, 1f);
gl.glTranslatef( 1f, 3f, 0f);
mDeck.draw(gl);
// undo rotate for buttons/overlays
gl.glTranslatef(-1f, -3f, 0f);
gl.glRotatef( 10f, 0f, 0f, 1f);
gl.glRotatef( -5f, 0f, 1f, 0f);
gl.glRotatef( 20f, 1f, 0f, 0f);
mOverlayBtns.draw(gl);
mPass.draw(gl);
}
The full source can be found on GitHub, here.
Is there something obvious I'm missing? Is there a better way to handle rotating, then rotating back?
So far, I've noticed this problem on:
Nexus 4
HTC Sensation
Another LG phone whose name I can't remember
These devices do not show the problem:
Galaxy Nexus
Nexus 7
Xoom
Your code was applying a set of affine transformations each frame, the problem is that each transformation is accumulative, so you were applying the transformation over and over. You either need to reset the current loaded MODELVIEW matrix using glLoadIdentity (http://www.khronos.org/opengles/sdk/1.1/docs/man/glLoadIdentity.xml) or push the current matrix, load your new matrix, draw and then pop the matrix back (as you were doing in your fix response).
I would put a glLoadIdentity at the beginning of each frame draw. Also, with your fix, I would also do this:
gl.glPushMatrix();
gl.glLoadIdentity(); // Be sure we start clean
// rotate card table
gl.glRotatef(-20f, 1f, 0f, 0f);
gl.glRotatef( 5f, 0f, 1f, 0f);
gl.glRotatef(-10f, 0f, 0f, 1f);
gl.glTranslatef( 1f, 3f, 0f);
mDeck.draw(gl);
gl.glPopMatrix();
Hope that helps.
I've found a fix for the issue, but I'm still hoping someone will be able to explain the problem I'm seeing above.
Instead of rotating the scene, then rotating back, I can use glPushMatrix and glPopMatrix to isolate the two groups. That way, the group of glTranslate and glRotate to move the scene back are unnecessary.
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glPushMatrix();
// rotate card table
gl.glRotatef(-20f, 1f, 0f, 0f);
gl.glRotatef( 5f, 0f, 1f, 0f);
gl.glRotatef(-10f, 0f, 0f, 1f);
gl.glTranslatef( 1f, 3f, 0f);
mDeck.draw(gl);
gl.glPopMatrix();
gl.glPushMatrix();
// undo rotate for buttons/overlays
// gl.glTranslatef(-1f, -3f, 0f);
// gl.glRotatef( 10f, 0f, 0f, 1f);
// gl.glRotatef( -5f, 0f, 1f, 0f);
// gl.glRotatef( 20f, 1f, 0f, 0f);
mOverlayBtns.draw(gl);
mPass.draw(gl);
gl.glPopMatrix();
}
EDIT 2: Take a look on the Triangle2d sample of this GitHub project for a complete, working sample.
EDIT: See the accepted answer for a link with a good explanation on how the ortographic matrix works. In the end, I tweaked the provided code a little:
float[] mvp = {
2f/width, 0f, 0f, 0f,
0f, -2f/height, 0f, 0f,
0f, 0f, 0f, 0f,
-1f, 1f, 0f, 1f
};
Please note that my z is fixed in 0 and w fixed in 1. This matrix make the origin (0,0) at the bottom-left of the screen; if you want the origin at top-left, try:
float[] mvp = {
2f/width, 0f, 0f, 0f,
0f, 2f/height, 0f, 0f,
0f, 0f, 0f, 0f,
-1f, -1f, 0f, 1f
};
Another problem was the call to GLES20.glUniformMatrix4fv which I changed to:
FloatBuffer b = ByteBuffer.allocateDirect(mvp.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
b.put(mvp).position(0);
GLES20.glUniformMatrix4fv(uMvpPos, b.limit() / mvp.length, false, b);
If you want to mess with this a bit, try this online calculator. Just remember that the rows in your sorce file will be columns in the calculator.
Original Problem:
I'm trying to draw a 2d triangle using OpenGLES 2.0 on android, but so far, not much success. These are my shaders:
(Vertex shader)
uniform mat4 uMvp;
attribute vec3 aPosition;
attribute vec3 aColor;
varying vec4 vColor;
void main() {
vColor = vec4(aColor.xyz, 1.0);
vec4 position = vec4(aPosition.xyz, 1.0);
gl_Position = uMvp * position;
};
(Fragment shader)
precision mediump float;
varying vec4 vColor;
void main(void)
{
gl_FragColor = vColor;
};
Then, in the onSurfaceChanged method of GLSurfaceView.Renderer, I put the following:
public void onSurfaceChanged(GL10 gl, int width, int height)
{
// here I load and compile the shaders and link the program.
// in the end, I use GLES20.glUseProgram(programHandle);
// (code omitted)
// create the matrix for the uniform
int uMvpPos = GLES20.glGetUniformLocation(programHandle, "uMvp");
float[] mvp = {width, 0f, 0f, 0f,
0f, -height, 0f, 0f,
0f, 0f, -2f, 0f,
-1f, 1, -1f, 1};
GLES20.glUniformMatrix4fv(uMvpPos, mvp.length * 4, false, mvp, 0);
// set viewport and clear color to white
GLES20.glViewport(0, 0, width, height);
GLES20.glClearColor(1f, 1f, 1f,1.0f);
}
I used the values of the matrix showed on this question. My intent here is to work with coordinates in the same way as a canvas works: (0,0) on top-left of screen and (width, height) on bottom-right.
And last but not least, this is the code of onDrawFrame:
public void onDrawFrame(GL10 gl)
{
int aPos = GLES20.glGetAttribLocation(programHandle,"aPosition");
int aColor = GLES20.glGetAttribLocation(programHandle,"aColor");
// assuming I correctly set up my coordinate system,
// these are the triangle coordinates and color
float[] data =
{
// XYZ, RGB
100f, 100f, 0f,
1f, 0f, 0f,
50f, 50f, 0f,
1f, 0f, 0f,
150f, 50f, 0f,
1f, 0f, 0f,
};
// put all my data into a float buffer
// the '* 4' is because a float has 4 bytes
FloatBuffer dataVertex = ByteBuffer.allocateDirect(data.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
dataVertex.put(data).position(0);
// set the POSITION values
// attribute, dataSize(number of elements), data type, normalized?, size(bytes), data
GLES20.glEnableVertexAttribArray(aPos);
GLES20.glVertexAttribPointer(aPos, 3, GLES20.GL_FLOAT, false, 6 * 4, dataVertex);
// set the COLOR values
dataVertex.position(3); // offset
GLES20.glEnableVertexAttribArray(aColor);
GLES20.glVertexAttribPointer(aColor, 3, GLES20.GL_FLOAT, false, 6 * 4, dataVertex);
// put a white background
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// and finally draw the triangle!
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
The end result is... a boring white screen, without the triangle. I guess I'm committing a very simple mistake, but I just can't spot it. Any thoughts?
Your orthographic projection matrix is wrong.
Orthographic projection is defined as (in column major order):
2/(r-l), 0, 0, 0,
0, 2/(t-b), 0, 0,
0, 0, 2/(f-n), 0,
(r+l)/(l-r), (t+b)/(b-t), (f+n)/(n-f), 1
In your case r=0, l=width, t=height, b=0, f=1, n=0 and you get:
-2/width, 0, 0, 0,
0, 2/height, 0, 0,
0, 0, 2, 0,
1, -1, -1, 1
I am having problems with my simple 2D OpenGL game.
Its really weird, I get textures to display correctly etc. but when I wanted to create particle effect with simple changing colors, for some reason it displays wrong colors from the buffer. I am using Android's OpenGL ES 1.1 but its the same with any version of OpenGL that uses VBO's.
I initialize the screen etc. and red triangle is displayed, but according to my color buffer it should be white, whats wrong?
GL11 gl11 = (GL11) gl;
gl11.glLoadIdentity();
gl11.glClear(GL_COLOR_BUFFER_BIT);
GLU.gluLookAt(gl, 0f, 0f, -container.getCamera().getScale(), 0f, 0f, 0f, 0f, -1f, 0f);
gl11.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl11.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl11.glTranslatef(container.getCamera().getX(), container.getCamera().getY(), 0.0f);
container.addParticle(new ColouredParticle(-container.getCamera().getX(), -container.getCamera().getY(), (float)Math.random(), (float)Math.random(), 0f, 5000));
particleColorBufferPointer = createFloatBuffer(gl11, GL11.GL_ARRAY_BUFFER, new float[] {
1f, 1f, 1f, 1f,
1f, 1f, 1f, 1f,
1f, 1f, 1f, 1f,
});
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, particleColorBufferPointer);
gl11.glColorPointer(4, GL10.GL_FLOAT, 0, 0);
particleVertexBufferPointer = createFloatBuffer(gl11, GL11.GL_ARRAY_BUFFER, new float[]{
-0.1f, -0.05f,
0.1f, -0.05f,
0.0f, 0.05f
});
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, particleVertexBufferPointer);
gl11.glVertexPointer(2, GL10.GL_FLOAT, 0, 0);
gl11.glDrawArrays(GL11.GL_TRIANGLES, 0, 3);
gl11.glDeleteBuffers(2, new int[]{particleVertexBufferPointer, particleColorBufferPointer}, 0);
gl11.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl11.glDisableClientState(GL10.GL_COLOR_ARRAY);
int error = gl11.glGetError();
if(error != GL11.GL_NO_ERROR) {
Log.v(TAG, "error " + Integer.toHexString(error));
}
Its just simple hardcoded float array containing the triangle vertices and colors, but for some reason the colors are wrong as I said before, what can possibly go wrong with such small amount of code? the color doesn't change to anything but black, like it only reads the red value from the buffer. Also it gives absolutely no error at all!
createFloatBuffer method:
private int createFloatBuffer(GL11 gl, int type, float[] data) {
int[] bufferPointerBuffer = new int[1];
gl.glGenBuffers(1, bufferPointerBuffer, 0);
int bufferPointer = bufferPointerBuffer[0];
gl.glBindBuffer(type, bufferPointer);
FloatBuffer dataBuffer = createFloatBuffer(data);
gl.glBufferData(type, data.length * FLOAT_SIZE, dataBuffer, GL_STATIC_DRAW);
gl.glBindBuffer(type, -1);
return bufferPointer;
}
Wow.. It all was because I had texture bound and it for some reason tried to draw it even if I had texture coords disabled, I wish i could have just listened when I got told to disable any state thats not needed anymore.. Thanks guys! Problem solved!
I am having a problem adapting and or I guess understanding the vertices/indices/faces in an OBJ file. I want to eventually parse a OBJ file programmatically but first I need to understand how to do it manually. I am using an adaptation of the example from GLWallpaperService(provided by a dev on the web) to do this.
The problem I am having is it seems to work fine with the code he provided to produce a generic cube with different colored faces which he had to implement and draw individually. My adjusted code below trying to draw just a basic cube from the coords I exported from blender and plugged in values.
public class GLCube {
private final int _nrOfVertices = 8;
private FloatBuffer _vertexBuffer;
private FloatBuffer _normalBuffer;
private ShortBuffer _indiceBuffer;
public GLCube() {
this.init();
}
private void init() {
// 3 is the number of coordinates to each vertex.
_vertexBuffer = BufferFactory.createFloatBuffer(_nrOfVertices * 3);
_normalBuffer = BufferFactory.createFloatBuffer(18);
_indiceBuffer = BufferFactory.createShortBuffer(72);
// Coordinates for the vertexes of the cube.
float[] vertexCoords = {
/*
1f, 1f, 0f,
0f, 1f, 0f,
0f, 0f, 0f,
1f, 0f, 0f,
1f, 0f, -1f,
1f, 1f, -1f,
0f, 1f, -1f,
0f, 0f, -1f,
*/
2.195671f, -0.176713f, -1.292541f,
2.195671f, -0.176713f, 0.707459f,
0.195671f, -0.176713f, 0.707459f,
0.195672f, -0.176713f, -1.292542f,
2.195672f, 1.823287f, -1.292541f,
2.195671f, 1.823287f, 0.707460f,
0.195671f, 1.823287f, 0.707459f,
0.195671f, 1.823287f, -1.292541f
};
short[] indicesArray = {/*
0, 1, 2, 0, 2, 3,
3, 4, 0, 4, 5, 0,
7, 2, 6, 6, 2, 1,
4, 7, 5, 7, 6, 5,
1, 0, 6, 6, 0, 5,
2, 7, 3, 7, 4, 3
*/
1,1,2, 1,3,1,
1,1,3, 1,4,1,
5,2,8, 2,7,2,
5,2,7, 2,6,2,
1,3,5, 3,6,3,
1,3,6, 3,2,3,
2,4,6, 4,7,4,
2,4,7, 4,3,4,
3,5,7, 5,8,5,
3,5,8, 5,4,5,
5,6,1, 6,4,6,
5,6,4, 6,8,6
};
//Coordinates for Normal Vector. Used for Lighting calculations
float[] normalCoords = {/*
0f, 0f, 1f, 0f, 0f, 1f,
0f, 0f, 1f, 0f, 0f, 1f,
0f, 0f, 1f, 0f, 0f, 1f,
1f, 0f, 0f, 1f, 0f, 0f,
1f, 0f, 0f, 1f, 0f, 0f,
1f, 0f, 0f, 1f, 0f, 0f,
-1f, 0f, 0f, -1f, 0f, 0f,
-1f, 0f, 0f, -1f, 0f, 0f,
-1f, 0f, 0f, -1f, 0f, 0f,
0f, 0f,-1f, 0f, 0f,-1f,
0f, 0f,-1f, 0f, 0f,-1f,
0f, 0f,-1f, 0f, 0f,-1f,
0f, 1f, 0f, 0f, 1f, 0f,
0f, 1f, 0f, 0f, 1f, 0f,
0f, 1f, 0f, 0f, 1f, 0f,
0f,-1f, 0f, 0f,-1f, 0f,
0f,-1f, 0f, 0f,-1f, 0f,
0f,-1f, 0f, 0f,-1f, 0f
*/
0f, -1f, 0f,
0f, 1f, 0f,
1f, -0f, 0f,
-0f, -0f, 1f,
-1f, -0f, -0f,
0f, 0f, -1f
};
_vertexBuffer.put(vertexCoords);
_normalBuffer.put(normalCoords);
_indiceBuffer.put(indicesArray);
_indiceBuffer.position(0);
_vertexBuffer.position(0);
_normalBuffer.position(0);
}
public void draw(GL10 gl) {
// 3 coordinates in each vertex
// 0 is the space between each vertex. They are densely packed in the array, so the value is 0
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, _vertexBuffer);
// 0 is the space between each vertex. They are densely packed in the array, so the value is 0
gl.glNormalPointer(GL10.GL_FLOAT, 0, _normalBuffer);
gl.glColor4f(1.0f, 0f, 0f, 1f); //Red
gl.glDrawElements(GL10.GL_TRIANGLES, 72, GL10.GL_UNSIGNED_SHORT, _indiceBuffer);
}
}
This is the Obj file and maybe I'm just not putting the values in the correct arrays but I have been trying to figure this out for awhile and honestly just don't have any background working with OpenGL so this is my first project trying to work with it.
# Blender v2.58 (sub 1) OBJ File: ''
# www.blender.org
v 2.195671 -0.176713 -1.292541
v 2.195671 -0.176713 0.707459
v 0.195671 -0.176713 0.707459
v 0.195672 -0.176713 -1.292542
v 2.195672 1.823287 -1.292541
v 2.195671 1.823287 0.707460
v 0.195671 1.823287 0.707459
v 0.195671 1.823287 -1.292541
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 -0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl (null)
s off
f 1//1 2//1 3//1
f 1//1 3//1 4//1
f 5//2 8//2 7//2
f 5//2 7//2 6//2
f 1//3 5//3 6//3
f 1//3 6//3 2//3
f 2//4 6//4 7//4
f 2//4 7//4 3//4
f 3//5 7//5 8//5
f 3//5 8//5 4//5
f 5//6 1//6 4//6
f 5//6 4//6 8//6
Any help with this would be so greatly appreciated. I left his values commented in so you could see what works. The image I see on my screen is a completely distorted set of triangles and it appears its trying to make my cube but is just not quite getting there.
An answer containing what to change would be awesome. -=)
I think you're interpreting the .obj format in the wrong way. Have a look at this document.
Basically the indices for your faces into the vertexCoords should be the first ints.
Each face is defined by indices in a format like this:
f v1/t1/n1 v2/t2/n2 v3/t3/n3
Where the v's are vertex indices, the t's are texture coordinate indices and the n's are normal indices.
So for this line (which defines a single face/triangle)
f 1//1 2//1 3//1
the vertex indices would be 1,2,3and the normal indices 1,1,1.
You have no texture coordinates, so no indices there and hence the double slash.
Keep in mind that the indices for the vertices that make up a face and the indices of the associated normals are different. So you will have to create two sets of indices. (See my edit below about glDrawElements though)
Another minor detail is to keep in mind that .obj files start counting with indices at 1, although that might be (an probably is) the 0th value in your array. So you'll have to account for that (i.e. subtract 1 from all index values).
Edit:
Looking at your code I see you're using glDrawElements. From what I know (but correct me if I'm wrong) this doesn't allow you to have multiple (different) sets of indices for vertices, texcoords and normals. So you will have to change your normal data to match the same indices as you have for your vertices.