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.
Related
Im trying to rotate object in OpenGL ES around its center. When i use Matrix.translateM() on the same axis what Matrix.setRotatem() it changing my object center to 0 on this axis.
When i trying operation below:
Matrix.translateM(rotationMatrix, OFFSET, 0, 1, 0);
Matrix.setRotateM(rotationMatrix, OFFSET, 90, 0, 1, 0);
Matrix.translateM(rotationMatrix, OFFSET, 0, -1, 0);
Then effect is:
But when i do something like this:
Matrix.translateM(rotationMatrix, OFFSET, 0, 0, 0);
Matrix.setRotateM(rotationMatrix, OFFSET, 90, 0, 1, 0);
Matrix.translateM(rotationMatrix, OFFSET, 0, 0, 0);
Effect is:
The second picture it's a correct look. So, my question is: Why translating on y axis, creates this mess.
If you want to rotate an object around a pivot then you've to:
Translate the object in that way that way, that the pivot is on the origin (0, 0, 0).
Since your object is located at (0, 1, 0) this means the object has to be translated by (0, -1, 0).
Rotate the object. If the object has to be rotated in the projection plane to the screen, then the rotation axis has to be the z axis (0, 0, 1). If the object hast to be rotated around an vertical axis, then the rotation axis has to be the z axis (0, 1, 0). For a rotation around a horizontal axis, the object has to be rotated around the x axis (0, 1, 0).
Translate the rectangle in that way that the pivot is back at its original position.
This means the object has to be translated by (0, 1, 0).
rotationMatrix = translate(0, 1, 0) * rotate * translate(0, -1, 0)
You've to use the Matrix operations Matrix.translateM respectively Matrix.rotateM, which create a new matrix and multiply the input matrix by the new matrix:
private float[] rotationMatrix = new float[16];
Matrix.setIdentityM(rotationMatrix, 0);
Matrix.translateM(rotationMatrix, 0, 0, 1, 0);
Matrix.rotateM(rotationMatrix, 0, 90, 0, 0, 1);
Matrix.translateM(rotationMatrix, 0, 0, -1, 0);
Note, the rotation axis are the last 3 parameters of Matrix.rotateM. You've to set them for your needs.
I have a png image with transparency. I am trying to create a filled polygon on the image over the transparent area. I'm setting the color but the actual color in the final image is different than expected. Here is my code:
Graphics2D g = wifiImage.createGraphics();
int [] x = {0, 200, 0};
int [] y = {0, 0, 200};
g.setColor(new Color(255, 0, 0)); //Red color
g.drawPolygon(x, y, 3);
g.fillPolygon(x, y, 3);
g.dispose();
ImageIO.write(wifiImage, "png", new File("./output/finalImage.png"));
In the final image, I expect the Red color triangle. But it is some brownish color instead.
As a workaround, in my origImage, I replaced transparency with white color. In that case, it works.
Can anybody tell how to set the correct color on the transparent region of the png?
The PNG image is probably a palletted image where 'brownish' is the palette color closest to (255, 0, 0).
Try this:
BufferedImage copy = new BufferedImage(wifiImage.getWidth(), wifiImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
g = copy.createGraphics();
copy.drawImage(wifiImage, 0, 0, null);
int [] x = {0, 200, 0};
int [] y = {0, 0, 200};
g.setColor(new Color(255, 0, 0)); //Red color
g.drawPolygon(x, y, 3);
g.fillPolygon(x, y, 3);
g.dispose();
ImageIO.write(copy, "png", new File("./output/finalImage.png"));
I'm trying to display a simple textured trapezoid (a road in perspective). For this I'm using SpriteBatch.draw with vertexes array as a parameter. But the result is unexpected.
What I expected:
What I got:
What exactly gone wrong? Or maybe I'm using the wrong method?
Here is the code:
#Override
public void create () {
texture = new Texture("road.jpg");
spriteBatch = new SpriteBatch();
float color = Color.toFloatBits(255, 255, 255, 255);
verts = new float[]{
0, 0, color, 0, 0,
Gdx.graphics.getWidth()/2-100, 300, color, 0, 1,
Gdx.graphics.getWidth()/2+100, 300, color, 1, 1,
Gdx.graphics.getWidth(), 0, color, 1, 0,
};
shapeRenderer = new ShapeRenderer();
}
#Override
public void render () {
Gdx.gl.glClearColor(0, 0.5f, 1f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
shapeRenderer.rect(0, 0, 640, 300);
shapeRenderer.end();
spriteBatch.begin();
spriteBatch.draw(texture, verts, 0, verts.length);
spriteBatch.end();
}
From documentation
draw(Texture texture, float[] spriteVertices, int offset, int count)
Draws a rectangle using the given vertices.
LibGDX draws these rectangles as two triangles, so it splits the texture. The problem is that these triangles in rectangle are the same size, but in trapezoid they are not, so they become distorted.
Solution would be to use projection or mesh.
When I just draw texture on SpriteBatch and set TextureWrap.Repeat everything is OK. But now I have 3D scene and I want have ground and texture must be repeated on model/mesh and this just don' t work.
public static StillModel createPlainMesh(float xs, float zs, Texture texture) {
final Mesh mesh = new Mesh(true, 4, 6, new VertexAttribute(
Usage.Position, 3, "a_position"), new VertexAttribute(
Usage.TextureCoordinates, 2, "a_texCoords"));
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 1,
-xs, 0f, zs, 1, 0,
-xs, 0f, -zs , 1,1
});
mesh.setIndices(new short[] { 0, 1, 2, 1, 2, 3 });
final StillModel model = new StillModel(new StillSubMesh(
"ground", mesh, GL10.GL_TRIANGLES, new Material()));
texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
model.setMaterial(new Material("material", new TextureAttribute(texture, 0, "s_tex")));
return model;
}
I have this code. I use setWrap(TextureWrap.Repeat, TextureWrap.Repeat), but textures are still streched. I don't know why, but it looks terrible.
I solved it. If you want repeat texture on model, You must modify this:
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 1,
-xs, 0f, zs, 1, 0,
-xs, 0f, -zs , 1,1
});
Modify Texture Coords - change to for example 20 if You want repeat it 20times
Example:
mesh.setVertices(new float[]
{ xs, 0f, zs, 0, 0,
xs, 0f, -zs, 0, 20,
-xs, 0f, zs, 20, 0,
-xs, 0f, -zs , 20,20
});
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