When I'm working on 3D graphics projects I often stumble across the problem of having to draw a cube. Thing is, I thus far have not found a better method to draw one other than specifying EVERY vertex, normal and occasionally texture coordinate. Given the regularity of a cube, I can't shake the feeling there has to be a better method.
So, is there an easier method than something like this:
putNormal(geometryBuffer, 0, 0, 1);
putVertex(geometryBuffer, x, y, 1);
putNormal(geometryBuffer, 0, 0, 1);
putVertex(geometryBuffer, x + 1, y, 1);
putNormal(geometryBuffer, 0, 0, 1);
putVertex(geometryBuffer, x + 1, y + 1, 1);
putNormal(geometryBuffer, 0, 0, 1);
putVertex(geometryBuffer, x, y + 1, 1);
putNormal(geometryBuffer, -1, 0, 0);
putVertex(geometryBuffer, x, y, 0);
putNormal(geometryBuffer, -1, 0, 0);
putVertex(geometryBuffer, x + 1, y, 0);
putNormal(geometryBuffer, -1, 0, 0);
putVertex(geometryBuffer, x + 1, y, 1);
putNormal(geometryBuffer, -1, 0, 0);
putVertex(geometryBuffer, x, y, 1);
//and so on..
The openGL Utility library (GLU) provides some utilities for more complex shapes like spheres, nurbs, quadrics (those aren't cubes), and so forth, but despite cubes being quick, programmers tend to lay out the faces differently and have different ideas about how many things to bind to each vertex, so it's not entirely as obvious as one would think.
More information is available at: http://www.glprogramming.com/red/chapter11.html
Use the method glutSolidCube from the class GLUT in the package com.jogamp.opengl.util.gl2, like this:
GLUT glut = new GLUT();
glut.glutSolidCube(size);
In an application, while trying to rotate an object using touch, I noticed drift in position of object after sometime (without any translation applied !!). The rotation is only about z-axis and works perfectly, but drift happens only after few rotations.
ds will be used for translation (using up-down button).
_uNozzleCentreMatrix and _ModelMatrixNozzle will use ds if I correct this.
private static final float[] _uNozzleCentre = new float[]{0.0f, 0.333605f, 0.0f, 1.0f};
protected static float[] _uNozzleCentreMatrix = new float[4];
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.setLookAtM(GLES20Renderer._ViewMatrix, 0, 0, 0, 7f, 0, 0, 0, 0, 1, 0);
Matrix.frustumM(GLES20Renderer._ProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 8);
Matrix.setIdentityM(GLES20Renderer._ModelMatrixNozzle, 0);
}
private static void updateModel(int upDown, float xAngle, float yAngle, float zAngle) {
//ds = GLES20Renderer._upDown - GLES20Renderer._lastUpDown;
ds = 0; // ds changes with button up-down, but now it is made 0, so button up-down will not affect it
Matrix.multiplyMV(GLES20Renderer._uNozzleCentreMatrix, 0, GLES20Renderer._ModelMatrixNozzle, 0, GLES20Renderer._uNozzleCentre, 0);
if(Math.abs(ds) > 0) {
} else {
if(GLES20Renderer._zAngle >= 360) {
GLES20Renderer._zAngle = GLES20Renderer._zAngle - 360;
}
if(GLES20Renderer._zAngle <= -360) {
GLES20Renderer._zAngle = GLES20Renderer._zAngle + 360;
}
Matrix.translateM(GLES20Renderer._ModelMatrixNozzle, 0, GLES20Renderer._uNozzleCentreMatrix[0], GLES20Renderer._uNozzleCentreMatrix[1], 0);
Matrix.rotateM(GLES20Renderer._ModelMatrixNozzle, 0, GLES20Renderer._zAngle, 0, 0, 1);
Matrix.rotateM(GLES20Renderer._ModelMatrixNozzle, 0, -GLES20Renderer._lastZAngle, 0, 0, 1);
Matrix.translateM(GLES20Renderer._ModelMatrixNozzle, 0, -GLES20Renderer._uNozzleCentreMatrix[0], -GLES20Renderer._uNozzleCentreMatrix[1], 0);
}
Matrix.multiplyMM(GLES20Renderer._MVPMatrixNozzle, 0, GLES20Renderer._ViewMatrix, 0, GLES20Renderer._ModelMatrixNozzle, 0);
Matrix.multiplyMM(GLES20Renderer._MVPMatrixNozzle, 0, GLES20Renderer._ProjectionMatrix, 0, GLES20Renderer._MVPMatrixNozzle, 0);
GLES20Renderer._lastZAngle = zAngle;
}
Apk for download:
http://www.pixdip.com/opengles/rotation/rotation.apk
(Try swiping a longer horizontal area from extreme left to right to observe drift early. Please be patient! Drift can take 20 seconds to occur)
For those whom it did not happen, here is the automated apk:
http://www.pixdip.com/opengles/rotation/automatic.apk
and the edited part of code:
Matrix.translateM(GLES20Renderer._ModelMatrixNozzle, 0, GLES20Renderer._uNozzleCentreMatrix[0], GLES20Renderer._uNozzleCentreMatrix[1], 0);
Matrix.rotateM(GLES20Renderer._ModelMatrixNozzle, 0, GLES20Renderer._zAngle, 0, 0, 1);
//Matrix.rotateM(GLES20Renderer._ModelMatrixNozzle, 0, -GLES20Renderer._lastZAngle, 0, 0, 1);
Matrix.translateM(GLES20Renderer._ModelMatrixNozzle, 0, -GLES20Renderer._uNozzleCentreMatrix[0], -GLES20Renderer._uNozzleCentreMatrix[1], 0);
Sometimes floating point errors get accumulated because of matrix stack.
This can be removed by using separate matrices for some critical transformations:
private static float[] _TMatrix = new float[16];
private static float[] _ModelMatrix = new float[16];
Matrix.setIdentity(Renderer._ModelMatrix);
Matrix.setIdentity(Renderer._TMatrix);
Matrix.translate(Renderer._ModelMatrix, xmov,ymov,0);
Matrix.translate(Renderer._TMatrix, -xmov,-ymov,0);
Matrix.multiply(Renderer._ModelMatrix, Renderer._TMatrix, Renderer._ModelMatrix);
// will result in an identity model matrix, without any floating point errors
Basically I'm trying to improve on the Ghosts in a Pacman game I'm making. In the orginal pacman when a Ghost is eaten when Pacman has picked up the Power the Ghosts eyes would navigate back to the home area and then spawn the ghost back in. I would like to do this to. It would also help me with implementing a Ghost AI to make them move smarter then just random.
So basically those eyes would have to navigate through this:
And the board is being drawn from the below 2D array:
//0's = Walls or location not allowed to go
//1's = Dot Spot
//2's = Clear Path nothing on it but safe to move
//3's = Power Dot
//-1's = only ghosts can go through
//5= Top entry spot
//6= bottom entry point
//7 = Cherry
//(Spots = row - 1 same with columns = - 1. First # is row. Second is col
public int board[][] =
{{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}, //1
{2, 0, 3, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 3, 0, 2}, //2
{2, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 2}, //3
{2,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2}, //4
{2,0,1,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,1,0,2}, //5
{2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,2}, //6
{2,0,0,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2}, //7
{2,2,2,2,0,1,0,1,1,1,1,1,1,1,0,1,0,2,2,2,2}, //8
{0,0,0,0,0,1,0,1,0,0,-1,0,0,1,0,1,0,0,0,0,0}, //9
{5,2,2,2,2,1,1,1,0,2,2,2,0, 1 ,1,1,2,2,2,2,6}, //10 - cherry
{0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,0}, //11
{2,2,2,2,0,1,0,1,1,1,2,1,1,1,0,1,0,2,2,2,2}, //12
{2,0,0,0,0,1,0,1,0,0,0,0,0,1,0,1,0,0,0,0,2}, //13
{2,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,2}, //14 - pacman on this row
{2,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,2}, //15
{2,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,2}, //16
{2,0,0,1,0,1,0,1,0,0,0,0,0,1,0,1,0,1,0,0,2}, //17
{2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,2}, //18
{2,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,2}, //19
{2,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,2}, //20
{2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}; //21
So my question is how should I go about making the eyes go to the centre home spot in the fastest way without going through walls?
Just use a precomputed inkblot. The "home" squares are labelled zero. Then, all unassigned neighbour squares of a square labelled n are assigned label n +1. Now all your "dead" ghosts have to do is move to a neighbouring square with a lower label. Eventually they will get home having taken the shortest path. Easy!
You can look into Lee's algorithm for shortest path inside a matrix with obstacles.
I have a simple plane Mesh that is 100x100. Following the libgdx tutorials I've successfully mapped a texture over the mesh. However, it looks odd right from the start, and even stranger when I zoom out. What I'm aiming for is a simple grid pattern.
Here's the plane zoomed in:
Now zoomed out:
The texture itself is a small 64x64 square, outlined.
My Grid class looks like this (Grid extends gdx.graphics.Mesh):
private final int HALFWIDTH = 50, HALFLENGTH = 50;
private Texture texture;
public Grid() {
super( true, 4, 4,
new VertexAttribute(Usage.Position, 3, "a_position"),
new VertexAttribute(Usage.ColorPacked, 4, "a_color"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoords")
);
setVertices(new float[] {
-HALFWIDTH, -HALFLENGTH, -2f, Color.toFloatBits(255, 0, 0, 255), -HALFWIDTH, HALFLENGTH,
HALFWIDTH, -HALFLENGTH, -2f, Color.toFloatBits(0, 255, 0, 255), HALFWIDTH, -HALFLENGTH,
-HALFWIDTH, HALFLENGTH, -2f, Color.toFloatBits(0, 0, 255, 255), -HALFWIDTH, HALFLENGTH,
HALFWIDTH, HALFLENGTH, -2f, Color.toFloatBits(0, 255, 255, 0), HALFWIDTH, HALFLENGTH
});
setIndices(new short[] { 0, 1, 2, 3 });
this.texture = new Texture( Gdx.files.internal("assets/grid.png") );
this.texture.setWrap( TextureWrap.Repeat, TextureWrap.Repeat );
this.texture.setFilter( TextureFilter.Linear, TextureFilter.Linear );
}
void draw() {
Gdx.graphics.getGL10().glEnable(GL10.GL_TEXTURE_2D);
this.texture.bind();
render(GL10.GL_TRIANGLE_STRIP, 0, 4);
}
I'm not 100% sure, but I have a strong suspicion this is because you're using Linear interpolation on your texture. When you zoom in and out on the texture, OpenGL has to choose how to display the texture at different resolutions. Using linear interpolation is well-known to cause the effect your screenshots show (sometimes called Zagging). It's due to the thin lines (high information density) in the texture you are using.
Try changing your texture mode to use Mip Maps.
this.texture.setFilter(TextureFilter.MipMap, TextureFilter.MipMap);
This will pre-compute scaled versions of your textures and avoid the zagging effect. Let me know if this works.
Not sure if this will help, but your HALFWIDTH is not the same as the first one.
-HALFWIDTH, **-HALFLENGTH**, -2f, Color.toFloatBits(255, 0, 0, 255), -HALFWIDTH, **HALFLENGTH**,
HALFWIDTH, -HALFLENGTH, -2f, Color.toFloatBits(0, 255, 0, 255), HALFWIDTH, -HALFLENGTH,
-HALFWIDTH, HALFLENGTH, -2f, Color.toFloatBits(0, 0, 255, 255), -HALFWIDTH, HALFLENGTH,
HALFWIDTH, HALFLENGTH, -2f, Color.toFloatBits(0, 255, 255, 0), HALFWIDTH, HALFLENGTH
Is not negative, like it is in the first coordinate. This may be throwing off the texturing calculation.
I'm trying to get a 3D array initialized for a game I'm working on, after multiple syntax changes I couldn't figure out how to get it to work! What I started with was:
public class AnimationView extends SurfaceView implements SurfaceHolder.Callback {//Create bitmaps.
Bitmap bitmapGoal = BitmapFactory.decodeResource(this.getResources(), R.drawable.goal);
Bitmap bitmapOrig = BitmapFactory.decodeResource(this.getResources(), R.drawable.ball);
Bitmap bitmap = Bitmap.createScaledBitmap(bitmapOrig, 150, 150, true);
//initialize the canvas.
private Canvas c;
private int score[] = {0, 0, 0, 0};
public int numBalls = 1;
//we support up to 4 balls. thus each array is 4 bit.
private int ballX[] = {0, 200, 400, 600};
private double ballY[] = {0, 0, 0, 0};
private double dirV[] = {0, 0, 0, 0};
private int dirH[] = {30, 30, 30, 30};
private static final int SCALE = 10;
private double elasticity = .6;
private int rotationNow[] = {5, 5, 5, 5};
private int rotationDraw[] = {0, 0, 0, 0};
class AnimationThread extends Thread {
//Are we running currently?
private boolean mRun;
//layer 1 is how many balls, 4 layers deep.
//layer 2 is which ball we're talking about, either 1, 2, 3, or 4 layers deep, depending on layer 1.
//layer 3 is the bounds of the ball, dependent on how many there are total.
//layer 3 is formatted x-min, x-max, y-min, y-max
int[][][] bounds = new int[][][] {
{ {0, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} },
//end first layer
{ {0, c.getWidth() / 2 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() / 2, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0}, {0, 0, 0, 0} },
//end second layer
{ {0, c.getWidth() / 3 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() / 3, c.getWidth() * 2 / 3 - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {c.getWidth() * 2 / 3, c.getWidth() - bitmap.getWidth(), 0, c.getHeight() - bitmap.getHeight()}, {0, 0, 0, 0} },
//end third layer
{ {0, c.getWidth() / 2, 0, c.getHeight() / 2}, {c.getWidth() / 2, c.getWidth(), 0, c.getHeight() / 2}, {0, c.getWidth() / 2, c.getHeight() / 2, c.getHeight()}, {c.getWidth() / 2, c.getWidth(), c.getHeight() / 2, c.getHeight()} }
//end fourth, and final layer!
};
Sorry about the weird formatting error. I know this doesn't help anything. There is a new line between ymax and int[][][].
You don't exactly need to look through it and understand, but this compiled and then errored out during execution. So then I tried to make a simple 3D array, I started with:
int[][][] bounds = new int[1][1][1];
bounds[0][0][0] = 0;
Eclipse had it's red squiggly under the semi-colon on the first line. Saying
'Syntax error on token ";", { expected after this token'
This is where it gets frustrating. Because that exact same code copy/pasted into a regular Java program works fine, but I can NOT get it to work inside an Android project. I then simplified some stuff, to this:
int[] bounds = new int[1];
bounds[0] = 0;
Exact same error, exact same place! Why Eclipse?? I also tried it with "int bounds[][][]" as opposed to "int[][][] bounds" but no difference, still same error.
I've rebooted my computer, cleaned my project multiple times, restarted Eclipse. I'm out of ideas. Do you have any??
Well, seems like the problem is not before, but after the code you pasted.
this assignment - bounds[0][0][0] = 0; is probably not in any method and this is illegal. When Eclipse sees an expression that need to be inside a method, it expects the line above to be the method declaration, so it expects '{' as a beginning of a method block, and not ';'
Ok, I feel ridiculous. After being very, very confused at why the variable couldn't initialize and why the very simple code then wouldn't compile. It turns out, though the canvas and bitmaps were available, it was infact them returning null values into the array.
So I got it working now.
Also, for my first question here, I was extremely impressed with the speediness of the solutions. Thanks a ton!
int[][][] bounds = new int[1][1][1];
bounds[0][0][0] = 0;
I copied these two lines and seem to be compiling fine.
I think you might have forgot to comment the earlier declaration of bounds . (or) you might be missing braces or something like that