I created a simple dynamic body from a PolygonShape and rendering it as a PolygonSprite rendered by a PolygonSpriteBatch. The rendering works fine, but the physics is not. The translation due to velocity works well, but when I set angular velocity or apply torque the body "orbits" around a point while rotating on its origin too. The problem isn't the origin, as while debugging I noticed that the body's position is also changing. The only rotation shouldn't make the body translate, right?
Here's how it rotates. I've only set angular velocity.
The linear velocity is always equal to 0 as I checked during debugging, but the position changes (which doesn't make any sense), so it should not be a rendering problem caused by a wrong rotation origin.
Here's where I create the body with the polygon.
public DrawableBody createFullBody(float[] vertices, Body body, Texture tex, Vector2 coord){
//in our example: vertices = new float[]{0.0f, 0.0f, 0.0f, 1f, 1f, 1f, 1f, 0.0f};
DrawableBody out = new DrawableBody(); //a class that contains Body and PolygonSprite
ShortArray indices = triangulate(vertices); //uses EarClippingTriangulator
PolygonShape shape = new PolygonShape();
shape.set(vertices);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
fixtureDef.restitution = 0.9f;
Fixture fixture = body.createFixture(fixtureDef);
shape.dispose(); //this is useless now, so we can dispose it.
PolygonRegion region = new PolygonRegion(new TextureRegion(tex), vertices, indices.toArray());
PolygonSprite sprite = new PolygonSprite(region);
body.setTransform(coord, 0);
sprite.setPosition(coord.x, coord.y);
out.body = body;
out.poly = sprite;
return out;
}
And that's how I render the square:
public void render(PolygonSpriteBatch batch, float delta){
Vector2 pos = body.getPosition(); //this changes even if velocity is zero?!?
Vector2 size = model.robotSize; //this is Vector2(0.1f, 0.1f)
float angle = body.getAngle();
d_body.poly.setPosition(pos.x - size.x / 2.0f, pos.y - size.y / 2.0f);
d_body.poly.setSize(size.x, size.y);
d_body.poly.setOrigin(size.x / 2.0f, size.y / 2.0f);
d_body.poly.setRotation(angle);
batch.draw(d_body.poly.getRegion(),
d_body.poly.getX(), d_body.poly.getY(),
d_body.poly.getOriginX(), d_body.poly.getOriginY(),
d_body.poly.getWidth(), d_body.poly.getHeight(),
1.0f, 1.0f,
d_body.poly.getRotation());
}
I'm struggling with this issue for two days now, so any help would really be appreciated.
Related
The problem is that when rotating my 3D cube on more than one axes, it distorts weirdly roughly halfway through. I am using the JOML math library for matrices.
// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.identity();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.5f, 1.0f, 0.0f), model);
// Other matrices for coordinate system
Matrix4f view = new Matrix4f();
view.identity();
view.translate(new Vector3f(0.0f, 0.0f, -3.0f), view);
Matrix4f projection = new Matrix4f();
projection.identity();
projection.perspective((float)Math.toRadians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); // FOV is 45
This is a gif of the distortion:
The main problem is that your rotation axis (0.5f, 1.0f, 0.0f) is not unit/normalized, (as is also required by its JavaDoc)
Parameters:
axis - the rotation axis (needs to be normalized)
To solve the problem and still use a matrix, you simply need to normalize the rotation axis.
Also (but this is irrelevant to the error):
JOML matrices are identity by default after instantiation - you do not need to call identity() on them)
you can omit supplying model as the argument to the dest parameter of rotate()
So:
// This is the model matrix for the rotation of a textured cube
Matrix4f model = new Matrix4f();
model.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)),
new Vector3f(0.5f, 1.0f, 0.0f).normalize());
There are 2 mistakes in your code:
First: you try to update 2 axis at once.
Doing this will cause the model to scale as it rotates.
Second: you don't use 1.0f when defining what axis you want to rotate. This aswell causes the model to scale.
The way Matrix4f.rotate(float angleInRadiants, Vector3f(x, y, z)) works is it will rotate the axis specified in the the vector by the specified angleInRadians.
This is the correct way to rotate both axis:
model
.rotate((float)(glfwGetTime() * Math.toRadians(50.0f)), new Vector3f(0.0f, 1.0f, 0.0f), model)
.rotate(((float)(glfwGetTime() * Math.toRadians(50.0f)) / 2), new Vector3f(0.1f, 0.0f, 0.0f), model);
A better way to do rotation is quaternions.
You can create a new Quaternionf object, set it's angles and rotate the model matrix using it.
float someAngleInRads = (float) Math.toRadians(20f * glfwGetTime());
Quaternionf quaternionf = new Quaternionf()
.rotateAxis(someAngleInRads, new Vector3f(0, 1, 0))
.rotateAxis(someAngleInRads / 2, new Vector3f(1, 0, 0));
model.rotate(quaternionf);
You could also set the angles for the quaternion this way:
Quaternionf quaternionf = new Quaternionf().rotateXYZ(Math.toRadians(someAngleInRads / 2), Math.toRadians(someAngleInRads), Math.toRadians(0f));
I have a simple triangular shape (obstacle) in my game and i would like to fill it with a texture repeatedly. I have looked at the other 2 topics but couldn't find a working solution. How can i fill this triangle with a small image (assume that its called "brickTexture.png" repeatedly?
Here is the code for creating the box2dbody of the obstacle in Obstacle.java
BodyDef bdef = new BodyDef();
bdef.position.set(obstaclePosition);
bdef.type = BodyDef.BodyType.StaticBody;
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
PolygonShape triangle = new PolygonShape();
float vertices1[] ={-50 / PPM, 100 / PPM,
50 / PPM, 100 / PPM,
0 / PPM, 0 / PPM};
triangle.set(vertices1);
fdef.shape = triangle;
b2body.createFixture(fdef);
And this is the triangle
This can easily be achieved by using the classes PolygonRegion and PolygonSpriteBatch and will work for any polygonal shape (not just triangles).
Create the polygon region:
// this will calculate the triangles given your vertices
short triangles[] = new EarClippingTriangulator().computeTriangles(vertices1).toArray();
// use your texture region
PolygonRegion polygonRegion = new PolygonRegion(textureRegion, vertices1, triangles);
Then you need to use the PolygonSpriteBatch to render at the desired position (I presume body position):
polygonSpriteBatch.draw(polygonRegion, x, y);
Make sure you load your texture with Repeat wrap so it can tile:
texture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
Class docs: PolygonRegion, EarClippingTriangulator, PolygonSpriteBatch
I want to know how to prevent an object in crossing another. I have a ball and a square which I can move whith my mouse. When my ball is on my square I move it (in top for example) if I go very slowly the ball remains on the square if not it crosses it.
if both of your 2 object have a fixture defined they will not be able to crossing one another this is an exmple of how a dynamic object who will be affected by physics in the BOX2D world must be created , and also this object can't tunneling through a sensor :
public Ball (World world){
this.world = world;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DYNAMIC;
bodyDef.position.set(0.0f/RATE, 0.0f/RATE);
Ballbody = world.createBody(bodyDef);
CircleShape circle = new CircleShape();
radius = (int) (Math.random()*30+15); // you can set a non randum raduis
circle.m_radius = radius/RATE;
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.restitution = 0.8f;
fixtureDef.density = 2.0f;
fixtureDef.friction = 0.3f;
fixtureDef.filter.groupIndex = -1;
Ballbody.createFixture(fixtureDef);
Ballbody.getFixtureList().setUserData("Ballounaton"); // optional
Vec2 ballVec = new Vec2((float) (Math.random()*8+2),0.0f);
Ballbody.setLinearVelocity(ballVec);
}
make sure to define a fixture to your box2d dynamic or static object to avoid tunneling through a sensor like in this exmple :
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.restitution = 0.8f;
fixtureDef.density = 2.0f;
fixtureDef.friction = 0.3f;
fixtureDef.filter.groupIndex = -1;
Ballbody.createFixture(fixtureDef);
according to BOX2D official documentation :
Recall that shapes don’t know about bodies and may be used
independently of the physics simulation. Therefore Box2D provides the
b2Fixture class to attach shapes to bodies. Fixtures hold the
following:
a single shape
broad-phase proxies
density, friction, and restitution
collision filtering flags
back pointer to the parent body
user data
sensor flag
I am attempting to have a 2D HUD which has icons that track the location on the screen of 3D objects behind the HUD in a 3D environment.
Reasoning: Sometimes you cannot see a 3D object (too far away or off screen) but you still want to know where it is.
Issue: 3D scene is using a perspective matrix to transform it, giving it depth (z-axis), the HUD is strictly 2D (xy-plane). Because of the depth, the 2D HUD cannot properly track objects when they are farther/closer away.
What I want: A way to get a 2D Vector [(x,y) pos] of where to put an icon so that it is centered where the 3D object in the background would be.
Example of all objects in an xy-plane (z=0):
You can see that as the objects get farther away from the center, the Icon (circle thing in white) is more off center.
Example of objects with increasing depths (farther from center == deeper):
You can see that the HUD thinks 3D objects are in the same plane still.
Pseudo-Code:
.getPos() gets the Vector (x,y,z)
lookAtObj = Object.getPos() - camera.getPos() // lookAt vector from camera to the object
icon.pos = Orthogonal Component of lookAtObj on camera.get_lookAt()
My Perspective Matrix:
// Function call in the OpenGL draw() method
FloatMatrix proj = FloatMatrix.getPerspectiveMatrix( this.fov, this.width, this.height, 0.1f, 200.0f );
// Function
public static FloatMatrix getPerspectiveMatrix( Double fov, float w, float h, float near, float far ){
float asp = w/h;
float fov_cos = (float) Math.cos( fov / 2.0d );
float fov_sin = (float) Math.sin( fov / 2.0d );
float fov_cot = fov_cos/fov_sin;
float a_0 = fov_cot/asp;
float a_3 = (far + near)/(near-far);
float a_43 = (2.0f * far * near)/(near-far);
float[] an = {
a_0, 0.0f, 0.0f, 0.0f,
0.0f, fov_cot, 0.0f, 0.0f,
0.0f, 0.0f, a_3, -1.0f,
0.0f, 0.0f, a_43, 0.0f,
};
return new FloatMatrix( an, 4, 4 );
}
This is pretty straightforward. You can use gluProject. It will take a given modelview, projection, and viewport transform, and a 3D point, and apply the inverse and spit out a 2D point in window coordinates for you (apologies for minor typos, just typing this here):
double myX = ..., myY = ..., myZ = ...; // your object's 3d coordinates
double[] my2DPoint = new double[2]; // will contain 2d window coords when done
double[] modelview = new double[16];
double[] projection = new double[16];
int[] viewport = new int[4];
gl.glGetDoublev(GL2.GL_MODELVIEW_MATRIX, modelview, 0);
gl.glGetDoublev(GL2.GL_PROJECTION_MATRIX, projection, 0);
gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
glu.gluProject(myX, myY, myZ, modelview, 0, projection, 0,
viewport, 0, my2DPoint, 0);
// now my2DPoint[0] is window x, and my2DPoint[1] is window y
After you do this, you'll have your 3D point in 2D window coordinates. Then simply switch your projection over to a 2D orthogonal projection, in window pixels, and draw your HUD in 2D space.
For performance, if you have multiple HUD items to draw per frame; just get the modelview/projection/viewport once per frame (or, even better, invalidate your cached ones if you change them and re-query only as needed) and reuse them in subsequent calls to gluProject.
I have a rectangle that I would like to move fast but for what ever reason the faster velocity I use still seems slow. What am I doing wrong? I have also dropped a circle from above onto a surface and even tough I play with gravity it comes down like a ballon...
Some declarations
float velocity = 10000000f;
static final float BOX_STEP=1/60f;
static final int BOX_VELOCITY_ITERATIONS=6;
static final int BOX_POSITION_ITERATIONS=2;
Gravity, tried everything and they all seem to suck
world = new World(new Vector2(0, -50), true);
The ground my object is moving onto
//ground
BodyDef groundBodyDef =new BodyDef();
groundBodyDef.position.set(new Vector2(0, camera.viewportHeight * .08f));
Body groundBody = world.createBody(groundBodyDef);
PolygonShape groundBox = new PolygonShape();
groundBox.setAsBox((camera.viewportWidth) * 2, camera.viewportHeight * .08f);
groundBody.createFixture(groundBox, 0.0f);
And then here are my objects:
//ball
bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.set(new Vector2(camera.viewportWidth * .2f, camera.viewportHeight * .75f));
body = world.createBody(bodyDef);
CircleShape dynamicCircle = new CircleShape();
dynamicCircle.setRadius(camera.viewportWidth * .035f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = dynamicCircle;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.5f;
fixtureDef.restitution = 0.8f;
body.createFixture(fixtureDef);
body.setLinearVelocity(0,-100);
//slime boy
BodyDef bodyBoxDef = new BodyDef();
bodyBoxDef.type = BodyType.DynamicBody;
bodyBoxDef.position.set(new Vector2(camera.viewportWidth * .08f,camera.viewportHeight * .191f));
bodyBox = world.createBody(bodyBoxDef);
PolygonShape slimeBox = new PolygonShape();
slimeBox.setAsBox(camera.viewportWidth * .04f, camera.viewportHeight * .03f);
FixtureDef fixtureSlimeDef = new FixtureDef();
fixtureSlimeDef.shape = slimeBox;
fixtureSlimeDef.density = 1.0f;
fixtureSlimeDef.friction = 0.0f;
fixtureSlimeDef.restitution = 0.0f;
bodyBox.createFixture(fixtureSlimeDef);
debugRenderer = new Box2DDebugRenderer();
body.applyTorque(1000000000);
bodyBox.setFixedRotation(true);
bodyBox.setBullet(true);
Any one have suggestions to speed up all movement in this?
I have been using a screen 1280 by 720 but I saw from other sources smaller is better so I scaled down to 640 by 260 but still not the preformance I want. How small should I really go?
From the Box2d Manual (Section 2.2):
Box2D is tuned for meters, kilograms, and seconds. So you can consider
the extents to be in meters. Box2D generally works best when objects
are the size of typical real world objects. For example, a barrel is
about 1 meter tall. Due to the limitations of floating point
arithmetic, using Box2D to model the movement of glaciers or dust
particles is not a good idea.
See https://stackoverflow.com/a/4556714/960524