I started drawing hexagonal grid on canvas with Path object. I did all the calculations on how many hexagons go on a particular display, depending on the hexagon size.
I have all my hexagon coordinates calculated depending on canvas. But now, I have serious performance issues and have to port this to OpenGL.
Because the algorithm works in canvas, I'm trying to convert those "canvas" hexagon coordinates to OpenGL coordinate system with GLU.gluUnProject.
"for loop"
float near[] = { 0.0f, 0.0f, 0.0f, 0.0f };
GLU.gluUnProject(b.hexes[ii][jj].points[ii].x,
b.hexes[ii][jj].points[ii].y, 0, mg.mModelView, 0,
mg.mProjection, 0, viewport, 0, near, 0);
vertices[zz] = (float) ((near[0])/near[3]);
zz++;
vertices[zz] = (float) ((near[1])/near[3]);
zz++;
vertices[zz] = 0;
Because I lack opengl knowledge, I dont know how to set glViewport,gluPerspective,glTranslatef to 2D world that is "the same" as canvas.
So my question is:
How to set those three thing that my first hexagon (on canvas, the first one is top left) to be equal on openGL drawing surface world?
Update
Thank you all for you're interest of helping on my problem. But:
I now set my 18 float vertices array as follows:
[20.0, 0.0, 0.0, 60.0, 0.0, 0.0, 80.0, 34.641018, 0.0, 60.0, 69.282036, 0.0, 20.0, 69.282036, 0.0, 0.0, 34.641018, 0.0]
Z is always 0.
ByteBuffer vertexByteBuffer = ByteBuffer
.allocateDirect(vertices.length * 4);
vertexByteBuffer.order(ByteOrder.nativeOrder());
vertexBuffer = vertexByteBuffer.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
and draw:
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_FAN, 0, vertices.length/3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
Before draw I set:
onDrawFrame()
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f);
onSurfaceChanged()
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0, width, height, 0, -1, 1);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
You have no need to transform yourself the vertices coordinates. All you have to do is to provide the correct projection matrix to OpenGL.
Basically, this would be something along the lines of :
glViewport(0, 0, canvasWidth, canvasHeight);
glMatrixMode(GL_PROJECTION); // or some matrix uniform if using shaders
glLoadIdentity();
glOrtho(0, canvasWidth, canvasHeight, 0, -1, 1); // this will allow to pass vertices in 'canvas pixel' coordinates
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Depending on the order in which you're passing your vertices, you might want to make that culling is disabled.
Related
Hi I am working on a AR android app. I am using ARToolkit6. In this app I want to view my 3D object( A Cube) on left half of the screen. With this eventually I want to display 3 cubes on the screen each on 1/3 of the screen area.
I was able to scale the 3D object by tweaking ModelView Matrix. What I read so far, I think I need to tweak projection matrix to achieve my goal. I tried looking solutions online. But Couldn't get it to work. Can anyone direct me to right path?
for (int trackableUID : trackableUIDs) {
// If the marker is visible, apply its transformation, and render a cube
if (ARToolKit.getInstance().queryMarkerVisible(trackableUID)) {
float[] projectionMatrix = ARToolKit.getInstance().getProjectionMatrix();
float[] modelViewMatrix = ARToolKit.getInstance().queryMarkerTransformation(trackableUID);
float[] scalingMat = {1, 0, 0, 0, 0, 3.0f, 0, 0, 0, 0, 1.0f, 0, 0.0f, 0, 0, 1};
float[] newModelView = modelViewMatrix;
multiplyMM(newModelView, 0, modelViewMatrix, 0, scalingMat, 0);
cube.draw(projectionMatrix, newModelView);
}
I followed the this link Set origin to top-left corner of screen in OpenGL ES 2 and (OpenGL ES) Objects away from view centre are stretched. So I translated the modelView Matrix but it doesn't solve the problem, the 3D object appears at the center of the screen. Can you explain how should I approach this problem? Thanks
#Override
public void draw() {
super.draw();
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glFrontFace(GLES20.GL_CCW);
// Look for trackables, and draw on each found one.
for (int trackableUID : trackableUIDs) {
// If the marker is visible, apply its transformation, and render a cube
if (ARToolKit.getInstance().queryMarkerVisible(trackableUID)) {
float[] projectionMatrix = ARToolKit.getInstance().getProjectionMatrix();
float[] modelViewMatrix = ARToolKit.getInstance().queryMarkerTransformation(trackableUID);
float[] scalingMat = {1, 0, 0, 0, 0, 3.0f, 0, 0, 0, 0, 1.0f, 0, 0.0f, 0, 0, 1};
multiplyMM(modelViewMatrix, 0, scalingMat, 0, modelViewMatrix, 0);
float[] rightModelMatrix = new float[16];
Matrix.setIdentityM(rightModelMatrix, 0);
// Translate outer sphere by 5 in x.
Matrix.translateM(rightModelMatrix, 0, 5.0f, 0.0f, 0.0f);
Matrix.multiplyMM(modelViewMatrix, 0, rightModelMatrix, 0, modelViewMatrix, 0);
cube.draw(projectionMatrix, modelViewMatrix);
}
}
Also tried this but the object gets displayed at the center of the screen.
glMatrixMode(GL_PROJECTION);
glTranslatef(5f, 0f, 0f);
I am trying to rotate a Triangle along Z axis from centre of triangle. But here i am getting triangle rotation from centre of an edge of triangle and not from its centre.
Renderer code:
#Override
public void onDrawFrame(GL10 gl) {
float scratch[] = new float[16];
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
int time = (int) (SystemClock.uptimeMillis() % 4000l);
float angle = 0.090f * time;
Matrix.setRotateM(mRotationMatrix, 0, angle, 0.0f, 0.0f, -1.0f);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
triangle.draw(scratch);
}
The problem is more likely due to your vertices, which compose the triangle.
Solution 1: Before rotating the triangle, translate it so that its center aligns with the scene's center.
Solution 2: Provide vertices, that are around the center. For example:
glVertex(0,0,0);
glVertex(1,0,0);
glVertex(0,1,0); // will produce rotation around the first vertex
... so offset them with a half:
glVertex(0-0.5,0-0.5,0-0.5);
glVertex(1-0.5,0-0.5,0-0.5);
glVertex(0-0.5,1-0.5,0-0.5); // will produce rotation around the approximate center
Best way is to calculate the center and translate before rotation.
Good luck!
I have, a problem with the setLookAtM function. My goal is to create a cube within a cube something like this (yep, it's paint :P ):
So basically everything works... almoust... I have the smaller cube and I have the bigger one.
However, there is a problem. I created the bigger one with coords from -1 to 1 and now I want to upscale it. With scale 1.0f i have something like this (the inner cube is rotating):
And thats good, but now... when I try to scale the bigger cube (so that it looks like in the paint drawing) the image goes black or white (i guess it's because the "camera" looks at the white cube but still i dont know why does my inner cube disappear :/ I don't understand what I'm doing wrong. Here is my code:
public void onDrawFrame(GL10 unused) {
float[] scratch = new float[16];
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5.0f, 0f, 0f, -1.0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
mRoom.mScale = 1.0f;
Matrix.setIdentityM(mScaleMatrix, 0);
Matrix.scaleM(mScaleMatrix, 0, mRoom.mScale, mRoom.mScale, mRoom.mScale);
float[] scaleTempMatrix = new float[16];
Matrix.multiplyMM(scaleTempMatrix, 0, mMVPMatrix, 0, mScaleMatrix, 0);
mRoom.draw(scaleTempMatrix);
When I set for example:
mRoom.mScale = 3.0f;
And
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -2.0f, 0f, 0f, 0.0f, 1.0f, 1.0f, 0.0f);
My camera should be at (0, 0, -2) looking at (0,0, -1) and it should be inside the white cube (since scale is 3.0 so the coords should be from -3 to 3 right?) But all I get is a white screen without the smaller cube rotating inside :/
If your scale is 3x in this code, then your visible coordinate range is actually going to be [-1/3,1/3].
You are thinking about things backwards, it might help if you considered the order in which the scale operation is applied. Right now you are scaling the object-space coordinates, then applying the view matrix and then projection. It may not look that way, but that is how matrix multiplication in GL works; GL effectively flips the operands when it does matrix multiplication and matrix multiplication is not commutative.
I believe this is what you actually want:
public void onDrawFrame(GL10 unused) {
float[] scratch = new float[16];
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -5.0f, 0f, 0f, -1.0f, 0f, 1.0f, 0.0f);
mRoom.mScale = 3.0f;
Matrix.setIdentityM(mScaleMatrix, 0);
Matrix.scaleM(mScaleMatrix, 0, mRoom.mScale, mRoom.mScale, mRoom.mScale);
Matrix.multiplyMM(mMVPMatrix, 0, mScaleMatrix, 0, mProjectionMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mMVPMatrix, 0, mViewMatrix, 0);
mRoom.draw(mMVPMatrix);
I'm creating a curtain like animation triggered by onTouchEvent() where u can drag one end of a square to make it bigger or smaller.
My only problem is that instead of having a square on the entire screen, I get a small line on the top of the screen and i can expand and de-expand that line.
Why won't this code draw a square?
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION); // set matrix to projection mode
gl.glLoadIdentity(); // reset the matrix to its default state
gl.glOrthof(0, height, width, 0, -3, 8);
}
Vertices:
private float vertices[] = {
-1.0f, 1.0f, 0.0f, // 0, Top Left
-1.0f, -1.0f, 0.0f, // 1, Bottom Left
1.0f, -1.0f, 0.0f, // 2, Bottom Right
1.0f, 1.0f, 0.0f, // 3, Top Right
};
// The order we like to connect them.
private short[] indices = { 0, 1, 2, 0, 2, 3 };
And the draw method in Square:
public void draw(GL10 gl,float x,float y) {
// Counter-clockwise winding.
gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
//Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//Enable vertex buffer
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
//Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
You are missing this? after setting the projection mode.
gl.glMatrixMode(GL10.GL_MODELVIEW); // set modelview matrix to identity.
gl.glLoadIdentity();
I am developing a simple tile world game for Android 2.3. I am trying to set up an orthographic view in opengl but my 1x1 tiles show up oblong -- oriented to the direction of the screen -- if the screen is in vertical position then the square is stretched vertically, if horizontal then it is stretched horizontally. Here is what I have in my onSurfaceChanged method:
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0.0f, width, 0.0f, height, 1.0f, 100.0f);
In my onDrawFrame method I have:
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
GLU.gluLookAt(gl,
0.0f, 0.0f, 6.0f, // eye translation
0.0f, 0.0f, 0.0f, // eye center
0.0f, 1.0f, 0.0f // eye world up
);
// draw objects
From the object onDraw method:
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFloatVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glPushMatrix();
gl.glTranslatef(localTranslation.getX(), localTranslation.getY(), localTranslation.getZ());
gl.glScalef(localScale.getX(), localScale.getY(), localScale.getZ());
gl.glRotatef(mAngle, localRotation.getX(), localRotation.getY(), localRotation.getZ());
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glNormal3f(0.0f, 0.0f, -1.0f);
gl.glPopMatrix();
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
I have used the same onSurfaceCreated, onDrawFrame, and onDraw methods with perspective mode and it worked without any distortion to the objects being drawn. I have tried a few different things pulled from the net (like replacing the right/bottom of the ortho call with width/height aspect ratio) but nothing seemed to correct the problem.
Here is what the screen looks like:
Any ideas? What am I missing? All that I want to see are perfect 1x1 squares that I can throw textures on without distortion.
Try this
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0.0f, width, 0.0f, height, 1.0f, 100.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
Ok this setting is what i use for both iOS and Android but when the screen ratio differs then positions of objects change.
glViewport(0, 0, backingWidth, backingHeight);
glOrthof(-1.0, //LEFT
1.0, //RIGHT
-1.0 * backingHeight / backingWidth, //BOTTOM
1.0 * backingHeight / backingWidth, //TOP
-2.0, //NEAR
100.0); //FAR
NOTE: That this works for normalised coordinates, which is what i use for all of my models.