3D rotation on 3 axis; Java - java

I'm working on a 3d game engine (LWJGL3) and I'm really stuck on rotation object around parent.
Here is some outline:
Each GameObject can have other GameObject as child.
Each GameObject has a Transform class:
public Vector3f translation;
public Quaternion rotation;
public Vector3f scale;
public Transform() {
this.translation = new Vector3f(0.0f);
this.rotation = new Quaternion();
this.scale = new Vector3f(1.0f);
}
The Quaternion class extends the Quaternionf from JOML lib with some extra methods, but you can consider it as a pure JOML class. When I add a GameObject to another, it updates its local transforms so it inherits parents translation, rotation and scale:
public void updateToParent(GameObject parent) {
this.translation.add(parent.getWorldTransform().translation);
rotateAroundParent(parent.getWorldTransform());
this.scale.mul(parent.getWorldTransform().scale);
}
private void rotateAroundParent(Transform transform) {
this.translation.sub(transform.translation);
this.translation.rotateZ(-transform.rotation.z);
this.translation.rotateY(-transform.rotation.y);
this.translation.rotateX(-transform.rotation.x);
this.translation.add(transform.translation);
this.rotation.add(transform.rotation);
}
And this part "works" OK. Parent rotated 45 in x,y and z axis with children:
.
"Magic" starts when I try to apply rotation:
public void rotateAroundPoint(float dx, float dy, float dz, Transform transform) {
this.translation.sub(transform.translation);
this.translation.rotateZ(-(float)Math.toRadians(dz));
this.translation.rotateY(-(float)Math.toRadians(dy));
this.translation.rotateX(-(float)Math.toRadians(dx));
this.translation.add(transform.translation);
this.rotation.add(dx, dy, dz);
}
(Please Note! This is my latest try to implement it and I know it's not working)
When Parent object, and therefore the children, has no rotation applied (at least on different axis than rotation) this rotation works but only on one axis at a time. When ever I try to apply rotation on 2 or 3 axis or on rotated object it fails hard:
I've tried implementing Quaternion rotation, changing order of rotation etc. etc. Basically everything I could find here and on uncle Google, yet still couldn't solve this issue. I know it has something with Gimbal Lock, "rotating the rotation" axis and so on.
I was also thinking it might be the problem with ModelViewMatrix, but after sitting on this issue with over a week I have no idea what is good and what isn't :P
public static Matrix4f getModelViewMatrix(Model model) {
Quaternion rotation = model.getTransform().rotation;
MODEL_VIEW_MATRIX.identity()
.translate(model.getTransform().translation)
.rotateX(-rotation.x)
.rotateY(-rotation.y)
.rotateZ(-rotation.z)
.scale(model.getTransform().scale);
viewCurrent.set(VIEW_MATRIX);
return viewCurrent.mul(MODEL_VIEW_MATRIX);
}
What I want to achieve is: When a GameObject rotates - each of his child rotates together with him as a one part.
I would appreciate every help you can guys give me :)

Related

How to prevent texture bleeding in a tilemap in LibGDX

I know there are quite some questions (and answers) on this topic, but they all have different solutions, and none of them seems to be working in my case.
I'm developing a small test project with libGDX, in which I tried to add a simple tilemap. I created the tilemap using Tiled, which seems to be working quite good, except for the texture bleeding, that causes black lines (the background color) to appear between the tiles sometimes.
What I've tried so far:
I read several SO-questions, tutorials and forum posts, and tried almost all of the solutions, but I just don't seem to get this working. Most of the answers said that I would need a padding between the tiles, but this doesn't seem to fix it. I also tried loading the tilemap with different parameters (e.g. to use the Nearest filter when loading them) or rounding the camera's position to prevent rounding problems, but this did even make it worse.
My current setup:
You can find the whole project on GitHub. The branch is called 'tile_map_scaling'
At the moment I'm using a tileset that is made of this tile-picture:
It has two pixels of space between every tile, to use as padding and margin.
My Tiled tileset settings look like this:
I use two pixels of margin and spacing, to (try to) prevent the bleeding here.
Most of the time it is rendered just fine, but still sometimes there are these lines between the tiles like in this picture (sometimes they seem to appear only on a part of the map):
I'm currently loading the tile map into the asset manager without any parameters:
public void load() {
AssetManager manager = new AssetManager();
manager.setLoader(TiledMap.class, new TmxMapLoader(new InternalFileHandleResolver()));
manager.setErrorListener(this);
manager.load("map/map.tmx", TiledMap.class, new AssetLoaderParameters());
}
... and use it like this:
public class GameScreen {
public static final float WORLD_TO_SCREEN = 4.0f;
public static final float SCENE_WIDTH = 1280f;
public static final float SCENE_HEIGHT = 720f;
//...
private Viewport viewport;
private OrthographicCamera camera;
private TiledMap map;
private OrthogonalTiledMapRenderer renderer;
public GameScreen() {
camera = new OrthographicCamera();
viewport = new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, camera);
map = assetManager.get("map/map.tmx");
renderer = new OrthogonalTiledMapRenderer(map);
}
#Override
public void render(float delta) {
//clear the screen (with a black screen)
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
moveCamera(delta);
renderer.setView(camera);
renderer.render();
//... draw the player, some debug graphics, a hud, ...
moveCameraToPlayer();
}
private void moveCamera(float delta) {
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
camera.position.x -= CAMERA_SPEED * delta;
}
else if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
camera.position.x += CAMERA_SPEED * delta;
}
// ...
//update the camera to re-calculate the matrices
camera.update();
}
private void moveCameraToPlayer() {
Vector2 dwarfPosition = dwarf.getPosition();
//movement in positive X and Y direction
float deltaX = camera.position.x - dwarfPosition.x;
float deltaY = camera.position.y - dwarfPosition.y;
float movementXPos = deltaX - MOVEMENT_RANGE_X;
float movementYPos = deltaY - MOVEMENT_RANGE_Y;
//movement in negative X and Y direction
deltaX = dwarfPosition.x - camera.position.x;
deltaY = dwarfPosition.y - camera.position.y;
float movementXNeg = deltaX - MOVEMENT_RANGE_X;
float movementYNeg = deltaY - MOVEMENT_RANGE_Y;
camera.position.x -= Math.max(movementXPos, 0);
camera.position.y -= Math.max(movementYPos, 0);
camera.position.x += Math.max(movementXNeg, 0);
camera.position.y += Math.max(movementYNeg, 0);
camera.update();
}
// ... some other methods ...
}
The question:
I am using padding on the tilemap and also tried different loading parameters and rounding the camera position, but still I have this texture bleeding problem in my tilemap.
What am I missing? Or what am I doing wrong?
Any help on this would be great.
You need to pad the edges of your tiles in you tilesheet.
It looks like you've tried to do this but the padding is transparent, it needs to be of the color of the pixel it is padding.
So if you have an image like this (where each letter is a pixel and the tile size is one):
AB
CB
then padding it should look something like this
A B
AAABBB
A B
C C
CCCCCC
C C
The pixel being padded must be padded with a pixel of the same color.
(I'll try try create a pull request with a fix for your git-repo as well.)
As a little addition to bornander's answer, I created some python scripts, that do all the work to generate a tileset texture, that has the correct edge padding (that bornander explained in his answer) from a texture, that has no padding yet.
Just in case anyone can make use of it, it can be found on GitHub:
https://github.com/tfassbender/libGdxImageTools
There is also a npm package that can extrude the tiles. It was built for the Phaser JS game library, but you could still use it. https://github.com/sporadic-labs/tile-extruder

OpenGl\JOML: Preventing unwanted translation when scaling a matrix

I am attempting to put 3D objects on the HUD using LWJGL 3 and JOML. I just have a small problem where when I scale the object, it moves. I want to prevent that from happening.
In this image my object is set to a position of (0,0) (Z is always set to 0), and a scale of 100 (All scales are divided by 100 so the actual value of the scale is 1 when applied to the matrix. The code that does this can be seen below).
https://i.imgur.com/f8wH7cm.png
Then when I change the scale to 50 (0.5 when applied to the matrix) this is what is shown:
https://i.imgur.com/SXWM8nE.png
I want the object to still be at the top left corner of the screen.
Here is my code that comes up with the true scale and position (The screen size is 1080 x 720)
public Vector3f getTruePos(){
return new Vector3f(((position.x/1080) - 0.5), ((position.y/720) + (0.5)), 0);
}
public float getTrueScale(){
return scale/100;
}
Here is my code that does the rendering of the object.
public void renderHUD(List<UIObject> objects){
hudShaderProgram.bind();
for(UIObject object : objects){
Mesh mesh = object.getMesh();
hudShaderProgram.setUniform("projection", transformation.getOrthoProjectionMatrix());
hudShaderProgram.setUniform("model", transformation.buildModelViewMatrixUI(object));
mesh.render();
}
hudShaderProgram.unbind();
}
Then here is the code that handles the transformations of the object:
public Matrix4f buildModelViewMatrixUI(UIObject gameItem) {
Quaternionf rotation = gameItem.getRotation();
Matrix4f modelMatrix = new Matrix4f();
modelMatrix.translationRotateScale(gameItem.getTruePos().x, gameItem.getTruePos().y, 0, rotation.x, rotation.y, rotation.z, rotation.w, gameItem.getTrueScale(),
gameItem.getTrueScale(), gameItem.getTrueScale());
return modelMatrix;
}
Then getOrthoProjectionMatrix() returns the value that is set by this:
transformation.updateProjectionMatrix(FOV, window.getWidth(), window.getHeight(), Z_NEAR, Z_FAR);
public Matrix4f updateOrthoProjectionMatrix(float left, float right, float bottom, float top, float zNear, float zFar) {
orthoProjMatrix.identity();
orthoProjMatrix.setOrtho(left, right, bottom, top, zNear, zFar);
return orthoProjMatrix;
}
I am not sure what I need to do to achieve what I desire. Any help would be appreciated.
The full code for the snippets above can be found here:
The UIObject class
The Rendering Class
The Transformation class
If this is not enough information please let me know, I will be happy to supply more.
I managed to solve this issue. I only really needed to update my ortho projectin matrix.
public Matrix4f buildOrtho(float left, float right, float bottom, float top){
Matrix4f orthoProjMatrix = new Matrix4f();
orthoProjMatrix.setOrtho(left, right, bottom, top, -100, 1000);
return orthoProjMatrix;
}
I then just changed my render method to this:
public void renderHUD(Window window, List<UIObject> objects){
hudShaderProgram.bind();
Matrix4f orthoProjection = transformation.buildOrtho(0, window.getWidth(), window.getHeight(), 0);
for(UIObject object : objects){
Mesh mesh = object.getMesh();
hudShaderProgram.setUniform("ortho", orthoProjection);
hudShaderProgram.setUniform("model", transformation.buildModelViewMatrixUI(object));
mesh.render();
}
hudShaderProgram.unbind();
}
Also since I am now using the correct ortho projection I no longer need the getTrueScale() and getTruePositon() methods.

How to make LibGDX Actions moveTo() animate from one point to another in a curved line?

I am working on a project in LibGDX, and I am using Scene2D actors for some of my sprites. In this regard, I have a sprite, which is spawning somewhere on the screen and needs to move to another position on the screen. To do this I am using the moveTo(xPos, yPos, duration, interpolation) method in the Actions, to make the move animation.
However, when I use this approach, the actor moves like I told it to, but it only moves in a straight line, from point A to B. I have tried several Interpolation options, like Circle interpolation and such, but it seems only to impact the speed of the animation line.
So now my question: How do I make my animation make a smooth curved line (See picture), from A to B?
I am currently using this code to make the Actions animation:
adultCustomerPointActor.addAction(Actions.sequence(
Actions.moveTo(300, 200, 2f, Interpolation.circle)
));
Thanks in advance for your help :)
It's a geometry problem. Using vectors, find the point halfway between the two points:
vec1.set(bx, by).sub(ax, ay).scl(0.5f).add(ax, ay);
Get another vector that is 90 or 270 to from the vector between the points:
vec2.set(bx, by).sub(ax, ay).rotate90().add(vec1);
This vec2 can be scaled to adjust how extreme curvature of the arc is. If you leave it alone, you'll have a quarter circle. You can also scale it negative to reverse the curvature.
Then add the second vector to the first to find the center point of your arc, which we can call point C.
vec1.set(bx, by).sub(vec2); // CB
vec3.set(ax, ay).sub(vec2); // CA
float angle = vec1.angle(vec3);
Now you need a vector that points from point C to point A. You will rotate this vector until it reaches point B. So you need the angle between CA and CB.
So here's a very simplistic class that implements this. It doesn't account yet for deciding if you want the arc to go up or down and if you want to scale how extreme it looks. You could add those as additional parameters with getters/setters. I haven't tested it, so it may need some debugging.
public class ArcToAction extends MoveToAction {
private float angle;
private final Vector2 vec1 = new Vector2(), vec2 = new Vector2(), vec3 = new Vector2();
#Override
protected void begin () {
super.begin();
float ax = target.getX(getAlignment()); // have to recalculate these because private in parent
float ay = target.getY(getAlignment());
vec1.set(getX(), getY()).sub(ax, ay);
vec2.set(vec1).rotate90();
vec1.scl(0.5f).add(ax, ay);
vec2.add(vec1);
vec1.set(bx, by).sub(vec2); // CB
vec3.set(ax, ay).sub(vec2); // CA
angle = vec1.angle(vec3);
}
protected void update (float percent) {
if (percent >= 1){
target.setPosition(getX(), getY(), getAlignment());
return;
}
vec1.set(vec3).rotate(percent * angle);
target.setPosition(vec1.x, vec1.y, getAlignment());
}
}
If you want to support automatic pooling, you can add a method like this:
static public ArcToAction arcTo (float x, float y, float duration, Interpolation interpolation) {
ArcToAction action = Actions.action(ArcToAction .class);
action.setPosition(x, y);
action.setDuration(duration);
action.setInterpolation(interpolation);
return action;
}

Writing a Raytracer, and perspective viewing system not displaying properly?

In a ray tracer I'm writing I've just tried to implement a proper perspective viewing system, however something seems to be wrong with it and I can't seem to figure out what is happening.
For example with a scene with three spheres, green, red and blue at (-150.0,0.0,0.0), (0.0,0.0,0.0) and (150.0,0.0,0.0) respectively and a camera at (0.0,0.0,-600.0), pointed at the centre sphere I get this image:
Which seems about right.
If I move the camera to (0.0, 600.0,-600.0), still pointed at the centre sphere, I would expect to get a similar image since I haven't moved left or right. However this is what is rendered:
Which doesn't make any sense to me.
This is my perspective porjector class:
public class PerspectiveProjector extends Projector{
public Point3D camera;
public Point3D sceneLocation;
public double distance;
public Vector3D u, v, w;
public PerspectiveProjector(Point3D camera, Point3D sceneLocation, double FOV){
this.camera = new Point3D(camera);
this.sceneLocation = new Point3D(sceneLocation);
this.distance = RayTracer.world.viewPlane.height/2/Math.tan(Math.toRadians(FOV));
uvw();
}
private void uvw() {
w = camera.subtractVector(sceneLocation);
w.normalise();
//prob
u = new Vector3D(0.00424,1.0,0.00764).cross(w);
u.normalise();
v = w.cross(u);
v.normalise();
}
public Ray createRay(Point2D point) {
Ray ray = new Ray(new Point3D(camera), u.multiply(point.x).add(v.multiply(point.y).subtract(w.multiply(distance))));
ray.direction.normalise();
return ray;
}
}
If you would like to see any more of my code please let me know.
I don't really understand what you're doing to get your u value, so here's how I would solve that problem.
In order to make the X coordinate of the image be horizontal, the u vector needs to lie in the XY plane, so the z coordinate must be zero. To keep the X coordinate perpendicular to the direction the camera direction, which, in your code, is w, their dot product must be zero. A vector like this must have the coordinates:
u = Vector3D(w.y,-w.x,0) or
u = Vector3D(-w.y,w.x,0)
This works because the dot product of the two vectors must algebraically be zero.
(x,y,z)*(y,-x,0) = xy + -yx + 0z = xy - xy + 0 = 0; therefore, (y,-x,0) must be a point on the xy plane perpendicular to (x,y,z).
Replace that one line and tell me if it works

How to apply an impulse to an object WITHOUT box2d libgdx

I have a game that is almost done but I forgot about gravity and impulse, i did not want to implement box2d and i got the gravity to work, but can some body explain how to apply an impulse without box2d?
You can simulate an impulse just by adding a velocity to the objects velocity. Like that:
class GameObject {
private Vector2 velocity = new Vector2();
public void applyImpulse(Vector2 impulse) {
velocity.add(impulse);
}
public void update(float deltaTime) {
float dampingPerSecond = 0.5f;
float dampingFactor = Math.max(0f, 1 - deltaTime*dampingPerSecond);
velocity.scl(dampingFactor);
}
}
Now you might use it like this: object.applyImpulse(new Vector2(3, 2));. In case you update all your GameObjects in every frame, your object will slow down after an impulse was given. Which is what you would expect to happen, if no further impulses hit your object. Doing this in a realistic way though is difficult and might only be achieved by using box2d. You might however tweak that and hope that it will work in your game. Remember to always apply your gravity after that though.

Categories