Change origin of a Texture/TextureRegion when drawing in LibGDX? - animation

Is there a way to change the origin of a Texture/TextureRegion when using the draw call
public void draw (TextureRegion region, float width, float height, Affine2 transform)
in LibGDX?
I'm trying to load an animation which is exported from Adobe After Effects. Currently the transform is exported as an affine 2D matrix and it's just rotation so it's simple, but it may get more complex later so I don't want to just use this call
public void draw (TextureRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation)
What I've achieved so far is just this (the origin is fixed at 0, 0): http://postimg.org/image/9qxux0sfr/
instead of this (good origin): http://postimg.org/image/pd60zaa89/

Related

Monogame - Rotate Sprite around centre of screen and itself

I have a problem and although I serached everywhere I couldn't find a solution.
I have a stacked sprite and I'm rotating this sprite around the center of the screen. So I iterate over a list of sprites (stacked) and increase the y-coordinate by 2 every loop (rotation is increased step by step by 0.01f outside of the loop):
foreach(var s in stacked)
{
Vector2 origin = new Vector2(Basic.width / 2, Basic.height / 2);
Rectangle newPosition = new Rectangle(position.X, position.Y - y, position.Width, position.Height);
float angle = 0f;
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
Vector2 pos = new Vector2(newPosition.X, newPosition.Y);
pos = Vector2.Transform(pos, transform);
newPosition.X = (int)pos.X;
newPosition.Y = (int)pos.Y;
angle += rotation;
s.Draw(newPosition, origin, angle, Color.White);
y += 2;
}
This works fine. But now my problem. I want not only to rotate the sprite around the center of the screen but also around itself. How to achieve this? I can only set one origin and one rotation per Draw. I would like to rotate the sprite around the origin 'Basic.width / 2, Basic.height / 2' and while it rotates, around 'position.Width / 2, position.Height / 2'. With different rotation speed each. How is this possible?
Thank you in advance!
Just to be clear:
When using SpriteBatch.Draw() with origin and angle, there is only one rotation: the final angle of the sprite.
The other rotations are positional offsets.
The origin in the Draw() call is a translation, rotation, translate back. Your transform matrix shows this quite well:
Matrix transform = Matrix.CreateTranslation(-origin.X, -origin.Y, 0f) *
Matrix.CreateRotationZ(rotation) *
Matrix.CreateTranslation(origin.X, origin.Y, 0f);
//Class level variables:
float ScreenRotation, ScreenRotationSpeed;
float ObjectRotation, ObjectRotationSpeed;
Vector2 ScreenOrigin, SpriteOrigin;
// ...
// In constructor and resize events:
ScreenOrigin = new Vector2(Basic.width <<1, Basic.height <<1);
// shifts are faster for `int` type. If "Basic.width" is `float`:
//ScreenOrigin = new Vector2(Basic.width, Basic.height) * 0.5f;
// In Update():
ScreenRotation += ScreenRotationSpeed; // * gameTime.ElapsedGameTime.Seconds; // for FPS invariant speed where speed = 60 * single frame speed
ObjectRotation+= ObjectRotationSpeed;
//Calculate the screen center rotation once per step
Matrix baseTransform = Matrix.CreateTranslation(-ScreenOrigin.X, -ScreenOrigin.Y, 0f) *
Matrix.CreateRotationZ(ScreenRotation) *
Matrix.CreateTranslation(ScreenOrigin.X, ScreenOrigin.Y, 0f);
// In Draw() at the start of your code snippet posted:
// moved outside of the loop for a translationally invariant vertical y interpretation
// or move it inside the loop and apply -y to position.Y for an elliptical effect
Vector2 ObjectOrigin = new Vector2(position.X, position.Y);
Matrix transform = baseTransform *
Matrix.CreateTranslation(-ObjectOrigin.X, -ObjectOrigin.Y, 0f) *
Matrix.CreateRotationZ(ObjectRotation) *
Matrix.CreateTranslation(ObjectOrigin.X, ObjectOrigin.Y, 0f);
foreach(var s in stacked)
{
Vector2 pos = new Vector2(ObjectOrigin.X, ObjectOrigin.Y - y);
pos = Vector2.Transform(pos, transform);
float DrawAngle = ObjectRotation;
// or float DrawAngle = ScreenRotation;
// or float DrawAngle = ScreenRotation + ObjectRotation;
// or float DrawAngle = 0;
s.Draw(pos, SpriteOrigin, DrawAngle, Color.White);
}
I suggest moving the Draw() parameter away from destinationRectangle and use the Vector2 position directly with scaling. Rotations within square rectangles can differ up to SQRT(2) in aspect ratio, i.e. stretching/squashing. Using Vector2 incurs a cost of higher collision complexity.
I am sorry for the ors, but without complete knowledge of the problem...YMMV
In my 2D projects, I use the vector form of polar coordinates.
The Matrix class requires more calculations than the polar equivalents in 2D. Matrix operates in 3D, wasting cycles calculating Z components.
With normalized direction vectors (cos t,sin t) and a radius(vector length),in many cases I use Vector2.LengthSquared() to avoid the square root when possible.
The only time I have used Matrices in 2D is display projection matrix(entire SpriteBatch) and Mouse and TouchScreen input deprojection(times the inverse of the projection matrix)

Flip image with different size width smooth transition

I'm trying to flip some animations in LibGDX, but because they are of different width, the animation plays weird. Here's the problem:
(the red dot marks the X/Y coordinate {0,0})
As you can see, when the animation plays "left" when you punch, the feet starts way behind than were it was, but when you punch right, the animations plays fine because the origin of both animations is the left corner, so the transition is smooth.
The only way I think of achieving what I want is to see what animation is playing and adjust the coordinates accordingly.
This is the code:
public static float draw(Batch batch, Animation animation, float animationState,
float delta,
int posX, int posY, boolean flip) {
animationState += delta;
TextureRegion r = animation.getKeyFrame(animationState, true);
float width = r.getRegionWidth() * SCALE;
float height = r.getRegionHeight() * SCALE;
if (flip) {
batch.draw(r, posX + width, posY, -width, height);
} else {
batch.draw(r, posX, posY, width, height);
}
return animationState;
}
Any suggestion is welcome as how to approach this.
Use some other batch.draw option (with other parameters). You can set "origin" parameters. It's like a hot spot...center of the image... So if you i.e. rotate, rotation will be done around that hot spot.
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Batch.html
I didn't use it for flipping, but it should work the same way. But if it doesn't then you have to adjust coordinates on your own, make some list with X offset for every frame and add it for flipped images.
Other solution would be to have wider frame images and keep center of the character always match the center of the image. That way your images will be wider then they have to - you'll have some empty space, but for sane number of frame it's acceptable.

LibGDX Rotating a sprite at each iteration

I'm using the function
SpriteBatch.draw(region, x, y, originX, originY, width, height, scaleX, scaleY, rotation);
And I call it as, being screen a SpriteBatch and img as Sprite, the variable dir is in radians:
screen.draw(img, x, y, 0, 0, img.getWidth(), img.getHeight(), 0.8f, 0.8f, dir*180/((float) Math.PI));
What I'm getting is a rotation around a pivot and not the center of the image nor the coordinates x,y which holds that said center.
I have already tried to use the sprite functions, centerOrigin and setCenter and neither of them changes to what I Want.
Set all the scaling and position and rotation on the sprite img and then call img.draw(spriteBatch); instead of spriteBatch.draw(...). The spriteBatch.draw(...) method that you are calling is not aware of any parameters that you set on the sprite, such as calling setCenter on it, so you have to draw it from the sprite.
The X and Y co-ordinates which represent the centre of the object should be given as originX and originY if you want the image to rotate around its centre.
screen.draw(img, x, y, img.getWidth() / 2, img.getHeight() / 2, img.getWidth(), img.getHeight(), 0.8f, 0.8f, dir*180/((float) Math.PI));

OpenGL ortho, perspective and frustum projections

45I am trying to understand OpenGL projections on a single point. I am using QGLWidget for rendering context and QMatrix4x4 for projection matrix. Here is the draw function
attribute vec4 vPosition;
uniform mat4 projection;
uniform mat4 modelView;
void main()
{
gl_Position = projection* vPosition;
}
void OpenGLView::Draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUseProgram(programObject);
glViewport(0, 0, width(), height());
qreal aspect = (qreal)800 / ((qreal)600);
const qreal zNear = 3.0f, zFar = 7.0f, fov = 45.0f;
QMatrix4x4 projection;
projection.setToIdentity();
projection.ortho(-1.0f,1.0f,-1.0f,1.0f,-20.0f,20.0f);
// projection.frustum(-1.0f,1.0f,-1.0f,1.0f,-20.0f,20.0f);
// projection.perspective(fov,aspect,zNear, zFar);
position.setToIdentity();
position.translate(0.0f, 0.0f, -5.0f);
position.rotate(0,0,0, 0);
QMatrix4x4 mvpMatrix = projection * position;
for (int r=0; r<4; r++)
for (int c=0; c<4; c++)
tempMat[r][c] = mvpMatrix.constData()[ r*4 + c ];
glUniformMatrix4fv(projection, 1, GL_FALSE, (float*)&tempMat[0][0]);
//Draw point at 0,0
GLfloat f_RefPoint[2];
glUniform4f(color,1, 0,1,1);
glPointSize(15);
f_RefPoint[0] = 0;
f_RefPoint[1] = 0;
glEnableVertexAttribArray(vertexLoc);
glVertexAttribPointer(vertexLoc, 2, GL_FLOAT, 0, 0, f_RefPoint);
glDrawArrays (GL_POINTS, 0, 1);
}
Observations:
1) projection.ortho: the point rendered on the window and translating the point with different z-axis value has no effect
2) projection.frustum: the point is drawn on the windown only the point is translated as translate(0.0f, 0.0f, -20.0f)
3) projection.perspective: the point is never rendered on the screen.
Could someone help me understand this behaviour?
The ortho projection works this way. I suggest you search for some images or some videos about the differences between different projections.
I don't know how you see a point translation in Z coordinate but if you would have a square it would become smaller by translating it further away (with ortho it would stay the same). There is an issue here as you use -20.0f for zNear while this value should be positive. The values inserted into this method should in most cases be generated with field of view, aspect ratio... Anyway you will not be able to see anything closer then zNear and anything further then zFar.
This is the same as frustum but already takes parameters as field of view, aspect ratio. The reason you do not see anything is your zNear is at 3.0f and the point is .0f length away. By translating the point you will be able to see it but try translating it by anything from 3.0f to 7.0f (3.0f is your zNear and 7.0f is your zFar). Alternatives are increasing zFar or translating the projection matrix backwards. Or mostly in your case I suggest adding some "look at" system on the projection matrix as it will give you some easy-to-use tools to manipulate your "camera", in most cases you can set a point you are looking from, a point you are looking at and up vector.

How to set the OpenGL project matrix to get projection as described below?

I just want to mimic a perspective projection without using z coordinate (ie: Only using 2d environment).
The x axis must shrink as y axis increases towards the top.
I have following code as ready,
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, size.width, 0, size.height, -1024 * CC_CONTENT_SCALE_FACTOR(), 1024 * CC_CONTENT_SCALE_FACTOR());
GLfloat proj[16] = { ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,? };
glMultMatrixf(proj)

Resources