Libgdx decal rotation around custom axis - rotation

I'm working app that uses Libgdx engine and decals in 3d space.
Now I need to rotate decals around X,Y,Z axis, but around custom pivot point that stands somewhere in the 3d space.
I found that decals have transformationOffset field, which might work with some calculations, but is Vector2 only. It means that I can move pivot point only over X and Y axis.
And when rotating decals over Y axis, wherever the pivot is, the result is the same.
decal.transformationOffset = new Vector2(0, -5);
decal.rotateX(newValues[0]);
decal.rotateY(newValues[1]);
decal.rotateZ(newValues[2]);
I need to move pivot over Z axis, too.
Is there some workaround for this issue?
Tnx!
EDIT:
I have succeded to rotate decal over pivot point in 3d space, but only if pivot's and decals's Z position is the same. If they are not I don't get what I've expected.
This is the code that works for pivot with same Z value:
decal.transformationOffset = new Vector2(pivotPosition.x - decal.getPosition().x, pivotPosition.y - decal.getPosition().y);
Tween.to(decal, DecalTween.XYZ_ROTATION, 5f).target(0, 360, 0).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
And in tween I do this:
target.setRotationX(0);
target.setRotationY(0);
target.setRotationZ(0);
target.rotateX(newValues[0]);
target.rotateY(newValues[1]);
target.rotateZ(newValues[2]);
How to extend this to use and Z value for pivot. I'm trying to add and translation animation beside rotate to achive this, but the results is weird.
Tween.to(decal, DecalTween.MOVE_XYZ, 2.5f).target(decal.getPosition().x, decal.getPosition().y, pivotPosition.z - decal.getPosition().z).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
decal.transformationOffset = new Vector2(pivotPosition.x - decal.getPosition().x, pivotPosition.y - decal.getPosition().y);
Tween.to(decal, DecalTween.XYZ_ROTATION, 5f).target(0, 360, 0).repeatYoyo(Tween.INFINITY, 0f).start(tweenManager);
Any idea how to combine translate and rotate animatio to get decal rotation in circle path over the pivot point?

I will answer my own question I guess.
I have extended Decal class, changed transformationOffset to Vector3.
Then in transformVertices I have added tz value, like there already was tx and ty. And add tz in calculation for vertex position.
Simple as that.
If anyone knows why is this left out from native libgdx support, please let me know.
Cheers.

Related

Flip 3D object around point/line

I'm making a 3D monster maker. I recently added a feature to flip parts along the x and y axes, this works perfectly fine on its own, however, I also have a feature that allows users to combine parts (sets flags, doesn't combine mesh), this means that simply flipping the individual objects won't flip the "shape" of the combined object. I have had two ideas of how to do this which didn't work and I'll list them below. I have access to the origin of the objects and the centre of mass of all instances that are combined - the 0, 0, 0 point on a theoretical number plane
In these examples we're flipping across the y axis, the axis plane is X = width, Y = height, Z = depth
Attempt #1 - Simply flipping the individual object's X scale, getting the X distance from the centreMass and taking that from the centreMass for position, this works when the direction of the object is (0, 0, 1) and the right (1, 0, 0) or (-1, 0, 0), in any other direction X isn't the exact "left/right" of the object. Here's a video to clarify: https://youtu.be/QXdEF4ScP10
code:
modelInstance[i].scale.x *= -1;
modelInstance[i].basePosition.set(centre.x - modelInstance[i].distFromCentre.x, modelInstance[I].basePosition.y, modelInstance[I].basePosition.z);
modelInstance[i].transform.set(modelInstance[i].basePosition, modelInstance[i].baseRotation, modelInstance[i].scale);
Attempt #2 - Rotate the objects Y180° around the centreMass and then flip their z value. As far as I understand, this is a solution, but I don't think I can do this. The way to rotate an object around a point AFAIK involves transforming the matrix to the point, rotating it, and then translating it back which I can't use. Due to the ability to rotate, join, flip, and scale objects I keep the rotation, position, and scale completely separate because issues with scaling/rotating and movement occur. I have a Vector3 for the position, a matrix for the rotation, and a Vector3 for the scale, whenever I change any of these I use object.transform.set(position, matrix.getRotation(), scale); So when I attempt to do this method (translating rotation matrix to point etc) the objects individually flip but remain in the same place, translating the objects transform matrix has weird results and doesn't work. Video of both variations: https://youtu.be/5xzTAHA1vCU
code:
modelInstance[i].scale.z *= -1;
modelInstance[i].baseRotationMatrix.translate(modelInstance[i].distFromCentre).rotate(Vector3.Y, 180).translate( modelInstance[i].distFromCentre.scl(-1));
modelInstance[i].transform.set(modelInstance[i].basePosition, modelInstance[i].baseRotation, modelInstance[i].scale);
Ok, since no one else has helped I'll give you some code that you can either use directly or use to help you alter your code so that it is done in a similar way.
First of all, I tend to just deal with matrices and pass them to shaders as projection matrices, ie. I don't really know what modelInstance[i] is, is it an actor (I never use them), or some other libgdx class? Whatever it is, if you do use this code to generate your matrices, you should be able to overwrite your modelInstance[i] matrix at the end of it. If not, maybe it'll give you pointers on how to alter your code.
First, rotate or flip your object with out any translation. Don't translate or scale first, because when you rotate you'll also rotate the translation you've performed. I use this function to generate a rotation matrix, it rotates around the y axis first, which I think is way better then other rotation orders. Alternatively you could create an identity matrix and use the libgdx rotation functions on it to create a similar matrix.
public static void setYxzRotationMatrix(double xRotation, double yRotation, double zRotation, Matrix4 matrix)
{
// yxz - y rotation performed first
float c1=(float)Math.cos(yRotation);
float c2=(float)Math.cos(xRotation);
float c3=(float)Math.cos(zRotation);
float s1=(float)Math.sin(yRotation);
float s2=(float)Math.sin(xRotation);
float s3=(float)Math.sin(zRotation);
matrix.val[0]= -c1*c3 - s1*s2*s3; matrix.val[1]=c2*s3; matrix.val[2]=c1*s2*s3-c3*s1; matrix.val[3]=0;
matrix.val[4]= -c3*s1*s2 + c1*s3; matrix.val[5]=c2*c3; matrix.val[6]=c1*c3*s2+s1*s3; matrix.val[7]=0;
matrix.val[8]= -c2*s1; matrix.val[9]=-s2; matrix.val[10]=c1*c2; matrix.val[11]=0;
matrix.val[12]=0; matrix.val[13]=0; matrix.val[14]=0; matrix.val[15]=1.0f;
}
I use the above function to rotate my object to the correct orientation, I then translate it to the correct location, then multiply it by the cameras matrix and scale as the final operation. This will definitely work if you can do it that way, but I just pass my final matrix to the shader. I'm not sure how you use your matrices. If you want to flip the model using the scale, you should try it immediately after the rotation matrix has been created. I'd recommend getting it working without flipping with scale first, so you can test both matrix.scl() and matrix.scale() as the final step. Off hand, I'm not sure which scale function you'll need.
Matrix4 matrix1;
setYxzRotationMatrix(xRotationInRadians, yRotationInRadians, zRotationInRadians,matrix1);
//matrix1 will rotate your model to the correct orientation, around the origin.
//here is where you may wish to use matrix1.scl(-1,1,1) or matrix1.scale(-1,1,1).
//get anchor position here if required - see notes later
//now translate to the correct location, I alter the matrix directly so I know exactly
what is going on. I think matrix1.trn(x, y, z) would do the same.
matrix1.val[12]=x;
matrix1.val[13]=y;
matrix1.val[14]=z;
//Combine with your camera, this may be part of your stage or scene, but I don't use
//these, so can't help.
Matrix4 matrix2;
//set matrix2 to an identity matrix, multiply it by the cameras projection matrix, then
//finally with your rotation/flip/transform matrix1 you've created.
matrix2.idt().mul(yourCamera.combined).mul(matrix1);
matrix2.scale(-1,1,1); //flipping like this will work, but may screw up any anchor
//position if you calculated one earlier.
//matrix2 is the final projection matrix for your model. ie. you just pass that matrix
to a shader and it should be used to multiply with each vertex position vector to create
the fragment positions.
Hopefully you'll be able to adapt the above to your needs. I suggest trying one operation at a time and making sure your next operation doesn't screw up what you've already done.
The above code assumes you know where you want to translate the model to, that is you know where the center is going to be. If you have an anchor point, lets say -3 units in the x direction, you need to find out where that anchor point has been moved to after the rotation and maybe flip. You can do that by multiplying a vector with matrix1, I'd suggest before any translation to the correct location.
Vector3 anchor=new vector3(-3,0,0);
anchor.mul(matrix1); //after this operation anchor is now set to the correct location
//for the new rotation and flipping of the model. This offset should
//be applied to your translation if your anchor point is not at 0,0,0
//of the model.
This can all be a bit of a pain, particularly if you don't like matrices. It doesn't help that everything is done in a different way to what you've tried so far, but this is the method I use to display all the 3D models in my game and will work if you can adapt it to your code. Hopefully it'll help someone anyway.

Unity Rotation & Quaternions

I'm learning Unity and I have a question.
I dont understand why this line resets the rotation to 0,0,0. All I'm doing is re-assigning its euler values?
transform.rotation =
Quaternion.Euler(transform.rotation.x,
transform.rotation.y,
transform.rotation.z);
The reason I'm doing this is because I need to lock one axis and keep the others changing. So I thought I could do it like this after the changes in x and z axes occur:
transform.rotation = Quaternion.Euler(transform.rotation.x,
LOCKED ROTATION VALUE,
transform.rotation.z);
I'm sure its simple but I cant find out whats wrong.
Thanks in advance.
Here is some documentation with transform.Rotate(). I'd use this one for rotating.
// Here is an example if you want to just rotate the Z axis.
transform.Rotate(new Vector3(0, 0, 10f) * Time.deltaTime);
Also, here is some other documentation on Quaternion. You could use functions like RotateTowards.
If your game object has a rigidbody on it then you can lock the rotation of it in Unity. Click on the game object and under the Rigidbody component click Constraints and then click the axis under Freeze Rotation.
You are using transform.rotation as if it is exposing Euler angles (which it is not). If you want the Euler angles from your rotation, you have to do this:
transform.rotation =
Quaternion.Euler(transform.rotation.eulerAngles.x,
transform.rotation.eulerAngles.y,
transform.rotation.eulerAngles.z);

How to rotate Decal over more then one axis at moment

I'm working on Libdx app using Decals.
Decals are 2d sprites in 3d world.
I have problem that when I say:
decal.setRotationX(angle)
everything works fine, but when I say:
decal.setRotationX(angle);
decal.setRotationY(angle2);
The decal rotates over Y axis only.
How to manage that problem?
I have found that Decal in source code uses Quaternion for rotation, but currently I don't know how to customize that to face my requirements.
Tnx in advance!
EDIT:
I have managed to rotate decal around multiple axis with:
decal.getRotation().setEulerAngles(yaw,pitch,roll);
Now my question is how to animate this with TweenEngine?
In get values method I have:
returnValues[0] = target.getRotation().getYaw();
returnValues[1] = target.getRotation().getPitch();
returnValues[2] = target.getRotation().getRoll();
In set values method I have:
target.getRotation().setEulerAngles(newValues[0], newValues[1],
newValues[2]);
But decal is not moving or animating, it's stucked in one position (slightly rotated over XYZ axis).
Any idea, values in TweenEngine are correct but somehow decal is not refreshing and rotating.
If you want to do it only once, you can do it like this:
decal.rotateX(angleX);
decal.rotateY(angleY);
decal.rotateZ(angleZ);
This will "add" the given angle to the current one though.
An alternative way would be to use the rotation Quaternion of the Decal:
decal.getRotation().setEulerAngles(yaw, pitch, roll);
The following image shows what "yaw", "pitch" and "roll" means:
Roll, pitch, yaw http://i.msdn.microsoft.com/dynimg/IC79189.gif
EDIT: I've just seen the JavaDoc of Decal.getRotation() and it says that the returned quaternion should not be modified! I've also checked the code and every other method of Decal sets an internal update flag which will cause the decal to change the next time it's rendered. Decal.getRotation() does not set this flag and thus the changes to it won't get recognized.
It seems like currently there is no really clean and easy way to set the rotation on all three axes at the same time. A workaround might look like this:
decal.setRotationX(0);
decal.setRotationY(0);
decal.setRotationZ(0);
decal.rotateX(angleX);
decal.rotateY(angleY);
decal.rotateZ(angleZ);
It first resets all angles to 0 and then rotates on each axis while not overwriting any other axis.

Getting coordinates of the mouse in relation to 3D space in THREE.js

I have struggled for the past 3 weeks trying to figure this out. If anyone could help me I would appreciate it so much.
I'm developing a game similar to Geometry Wars in where I have a triangle in the middle of the screen which you can move around.
The problem is I need the triangle to rotate and face toward the direction of the mouse curser. I don't need to worry about the z-axis per-say as I always have the camera in a fixed position (z=500) and I am treating the scene as a "2D scene" - all the action occurs on the z=0 plane.
Calculating the angle between the triangle and the mouse is elementary:
targetAngle = Math.atan2(mouseCoord.y-this.position.y, mouseCoord.x-this.position.x)
where this is the mesh.
The problem is that the mouseCoords are in standed Dom window format whilst the position of the triangle is in Three.js format.
Q) How would I convert the mouse coords to represent the coords on the z=0 plane where the triangle is?
I have tryed so many ways including ray intersection but nothing works ;(
Thank you all for your help and thank you so much for an amazing framework!!!!
I don't actually see the problem. use the THREE.vector3 with the z coord in 0. then use something like triangle.rotate(THREE.vector3(targetAngle,0,0) or something
I suspect your intersection isn't working because of a CSS offset by your canvas within the DOM.
If you need the triangle to look at something specific, you should simply be able to use the "lookAt" method of the triangle.
To have it look at the camera for example:
triangleMesh.lookAt(camera.position);

Java3D: rotating object in world coordinates?

I've been searching all evening but can't find the information I'm looking for, or even if it's possible, which is quite distressing ;)
I'm using Java3D and can't figure out how to rotate the camera in world space.
My left/right, and up/down rotation both happen on local space.
Meaning that if I move left and right, everything looks fine.
However if I look 90 degrees down, then look 90 degrees right, everything appears to be on its side.
Currently, I'm doing the following. This will result in the above effects:
TransformGroup cam = universe.getViewingPlatform().getViewPlatformTransform();
Transform3D trfcam = new Transform3D();
cam.getTransform(trfcam);
trfcam.mul(Camera.GetT3D()); //Gets a Transform3D containing how far to rotate left/right and how far to move left/right/forward/back
trfcam.mul(Camera.GetRot()); //Gets a t3d containing how far to rotate up/down
cam.setTransform(trfcam);
Alternatively, one thing I tried was rotating the root, but that rotates around 0, so if I ever move the camera away from 0, it goes bad.
Is there something available on the web that would talk me through how to achieve this kind of thing?
I've tried a lot of different things but just can't seem to get my head around it at all.
I'm familiar with the concept, as I've achieved it in Ogre3D, just not familiar with the law of the land in J3D.
Thanks in advance for replies :)
Store the ammound you have rotated around each axis (x and y), and when you try to rotate around the x axis for example, reverse the the rotation around y, do the rotate around x, then redo the rotation around y.
I'm not sure I understand your second question correctly. Since viewer and model transformations are dual, you can simulate camera moves by transforming the world itself. If you dont want to translate the x and y axis you are rotating around, just add another TransformGroup to the main TransformGroup you are using, and do the transforms in the new one.
Edit: The first solution is quite slow, so you can make a Transform3D out of the 3 transform you have to do:
Say you have rotated around the x axis (Translate3D xrot), and now you need to rotate around y:
Translate3D yrot = new Translate3D();
yrot.rotY(angle);
Translate3D temp = xot;
xrot.mul(yrot); // Dont forget the reverse order. xrot is the previous translate
xrot.mul(yrot); // xrot = xrot * yrot * xrot^-1
temp.transpose(); // Get the reverse transform of the old transform
xrot.mul(temp);
yrot = xrot; // Store it for future rotation around x axis
cam.setTransform(yrot);
It works similar for many transformations you make: reverse the previous done, do the transform, redo the old one. I hope it helps.

Resources