I need to rotate a triangle so that it lies on a plane given by a normal n and a constant d.
I have the normal n1 of the plane that the two triangles lie in. Now i need to rotate the right red triangle so that it results in the orange one.
The points of the triangles and the normals are stored as 3-dimensional vectors.
Until now, I did the following:
Get the normalized rotation quaternion (rotQuat) between n1 and n2.
Multiply every point of the triangle by the quaternion. Therefore I convert the point to a quaternion(point.x, point.y, point.z, 0) and do the multiplcation as follows: resultQuat = rotQuat * point * conjugate(rotQuat). I then apply x, y and z of the result to the point.
This is how i get the rotation between two vectors:
public static Quaternion getRotationBetweenTwoVector3f(Vector3f vec1, Vector3f vec2)
{
Vector3f cross = Vector3f.cross(vec1, vec2);
float w = (float) (java.lang.Math.sqrt(java.lang.Math.pow(vec1.getLength(), 2) * java.lang.Math.pow(vec2.getLength(), 2)) + Vector3f.dot(vec1, vec2));
Quaternion returnQuat = new Quaternion(cross.x, cross.y, cross.z, w);
returnQuat.normalize();
return returnQuat;
}
The problem is that the triangle has the correct orientation after the rotation, but the triangle also moves it's position. I need a rotation that rotates the triangle so that it's still connected to the two points of the left red triangle (like the orange one).
How is this possible?
Your problem is that rotation matrix/quaternions rotate points around an axis that passes through the origin. To rotate around different point than the origin, you need to translate the triangle points to the origin (just Substract the rotation point value from the triangle points), then multiply by the quaternion and then translate back.
So the algorithm becomes:
translatedPoints[i] = triPoints[i] - rotationPoint;
translatedPoints rotate using quaternion
translate translatedPoints back by adding the rotation point value.
Related
I searched and implemented things from this forum, it doesn't come out right.
What I'm trying to achieve is to calculate a spawnPoint for player bullets relative to his position and rotation.
The spawnPoint should be and his X + his width (the player is set to point to the right by default) and y + height/2 (to spawn from his center on the Y axis).
This is what I got from this forum:
this.bulletSpawn.x = (float)(this.position.x + this.width/2 + this.width * Math.cos(rotation));
this.bulletSpawn.y = (float)(this.position.y + this.height/2 + this.height/2 * Math.sin(rotation));
The rotation is in Radians. The this is the Player class.
Images showing what I expect to happen:
Original Position
Expected Behaviour
The red dot is the spawnPoint I'm trying to calculate knowing the player position and rotation.
The player Sprite is what rotates, and it rotates related to his center x and y, which is done with a lib, i do not have these variables. The entire arrow would be the player , the arrow direction is where the player is pointing at, and the red dot would be the bulletSpawn point (or the expected one)
Using the code I posted, the bullets seem to be spawning from somewhere else. Even at the beggining they have an offset and when I rotate the player the spawnPoint seems to be relative to a different origin than what I'm expecting.
This is the bullet position code:
position.x = holder.bulletSpawn.x - (float)(this.width/2 * holder.rotation);
position.y = holder.bulletSpawn.y - (float)(this.height/2 * holder.rotation);
This is inside the Bullet class. The position variable is a Vector2 of bullet, and holder is the player instance. This code is merely to give an offset for the bullet to spawn at the center of its own size
I added some fixes related to the comments, but the bullets still have a tiny offset that looks wrong at certain angles.
Basically the distance i want to get is the width of the player, and his center y which is height/2.
Let's initial position is X0, Y0, rotation is about center point CX, CY, and rotation angle is Theta. So new position after rotation is:
NX = CX + (X0-CX) * Cos(Theta) - (Y0-CY) * Sin(Theta)
NY = CY + (X0-CX) * Sin(Theta) + (Y0-CY) * Cos(Theta)
This equations describe affine transformation of rotation of arbitrary point about center point, and affine matrix is combination of translation, rotation, and back translation matrices.
About center CX, CY - you wrote
it rotates related to his x and y origin at his bottom left
About initial point coordinate - for bullet it seems to be
X + Width, Y + Height/2
Swift extension:
extension CGSize {
static func offsetFrom(angle:CGFloat, distance:CGFloat) -> CGSize {
let rad = angle * CGFloat.pi / 180
return CGSize(width: sin(rad) * distance, height: cos(rad) * distance)
}
}
I am trying to figure out how to implement the following method in java;
** Point rot90()** Query for a new Cartesian Point equivalent to this Cartesian point rotated by 90 degrees
I have no idea how to go about creating this method. However, I do believe that pulling the point (x,y) and outputting new point (y,x*-1) is equivalent to rotating 90 degrees. Basically the old y coordinate becomes the nee x coordinate and the new y coordinate is the old x coordinate multiplied by negative 1. Any thoughts on how to set up this method would be greatly appreciated. Thanks.
this is what I have so far
public Point rot90(){
Point rotated = new Point();
rotated.yCoord = xCoord*-1;
rotated.xCoord = yCoord;
return rotated;
}
I know this doesn't work as pointed out when I try to compile it. Any suggestions?
Your method needs an argument.
public Point rot90(Point p){
Point rotated = new Point();
rotated.yCoord = -p.xCoord;
rotated.xCoord = p.yCoord;
return rotated;
}
If your Point class has a constructor that can take coordinates then you can make it shorter.
public Point rot90(Point p){
return new Point(p.yCoord, -p.xCoord);
}
What exactly is the problem? Code not working or the result not as expected?
In the complex plane interpretation of Euclidean geometry, rotation (x,y) by 90° is, by definition of the complex unit, the multiplication of x+i·y by i. Since
i·(x+i·y)=-y+i·x,
the rotated point has the coordinates (-y,x), and your code implements the rotation by 270° =^= -90°.
In general, the rotation by an angle a amounts to the multiplication
(cos(a)+i*sin(a)) * (x+i*y)
Note that the screen coordinate system is the mirror image of the Cartesian plane, the y axis points down. Thus angle orientation is reversed.
Essentially, what is happening is there is some strange warping of the 3D cube being rendered by my raytracer, which continues to worsen as the camera moves up, even if the cube is in the same location on the screen.
The code is at http://pastebin.com/HucgjRtx
Here is a picture of the output:
http://postimg.org/image/5rnfrlkej/
EDIT: Problem resolved as being that I was just calculating the angles for vectors wrong. The best method I have found is creating a vector based on your FOV (Z) current pixel X, and current pixel Y, then normalizing that vector.
It looks like you're calculating rays to cast based on Euler angles instead of the usual projection.
Typically a "3D" camera is modeled such that the camera is at a point with rays projecting through a grid spaced some distance from it... which is, incidentally, exactly like looking at a monitor placed some distance from your face and projecting a ray through each pixel of the monitor.
The calculations are conceptually simple in fixed cases.. e.g.
double pixelSpacing = 0.005;
double screenDistance = 0.7;
for (int yIndex= -100; yIndex<= 100; yIndex++)
for (int xIndex= -100; xIndex<= 100; xIndex++) {
Vector3 ray = new Vector3(
xIndex * pixelSpacing,
yIndex * pixelSpacing,
screenDistance
);
ray = vec.normalize();
// And 'ray' is now a vector with our ray direction
}
You can use one of the usual techniques (e.g. 4x4 matrix multiplication) if you want to rotate this field of view.
I want to use the heading() function in the PVector class, but I am using P3D and have an x,y,and z for my PVector. How would I re-write this function to allow it to work for 3D space? My goal is to do something like:
size(100, 100, P3D);
PVector v = new PVector(.2, .11, .54);
rotate( v.heading() ); //set rotation from PVector named v
line(0, 0, 10, 0); //draw line that will be rotated in correct direction
The above code doesn't display the correct rotation in 3D space since v.heading() is only suited for 2D coordinate space. How can I achieve this using rotateX(), rotateY(), rotateZ()? I'd like to avoid using a quaternion if possible and use the rotate functions.
Thanks in advance!!
Using the heading() function in 2D is transforming 2D Cartesian coordinates (x,y) into 2D polar coordinates (radius, angle). A 3D version of polar coordinates is spherical coordinates:
The 3D point P can be represented as three linear coordinates (x,y,z) or one linear coordinate and two angles (rho, theta, phi). Rho is the length of the vector, theta is the angle in the x-y plane, and phi is the angle in the angle into the z plane. These equations describe the conversion:
rho = sqrt(x^2 + y^2 + z^2)
phi = arccos(z/rho)
theta = arctan(y/x)
You should be able to use the rotateX(), etc functions using these angles. Note that this uses the mathematics convention for the angle names theta and phi; in physics, these labels are reversed from what's shown above.
What kevinsa5 said, except use the inverse sine function to get the elevation. Use the atan2 function for the azimuth (or better, simply use the vector's 2D heading method). And use the vector's mag method for its magnitude.
rho = v.mag();
phi = asin(v.z/rho);
theta = atan2(v.y, v.x);
Working backwards, think "X - Y - Z" and try:
PVector p = new PVector(v.mag(), 0, 0); // X
rotateY3D(p, phi); // Y
rotateZ3D(p, theta); // Z
Then compare p with the original v.
I have a Ball in 3D space that has the following attributes:
location - a Vector3f representing where the ball is
rotation - a Vector3f representing the x, y, and z axis rotation angles
I want to roll the ball in a particular direction denoted by a Vector3f "direction". How would I calculate the appropriate axis rotation vector (see above) based on the direction I want the ball to roll towards?
I've tried the following:
set rotation.x to direction.z
set rotation.z to direction.x
Calculate the ball's transform matrix as:
private Matrix4f calculateEntityMatrix(EEntity entity)
{
Matrix4f matrix = new Matrix4f();
matrix.translate(new Vector3f(entity.getXLocation(), entity.getYLocation(), entity.getZLocation()));
if(entity.getXRotation()>0)
{
matrix = matrix.rotate(entity.getXRotation(), new Vector3f(1f, 0f, 0f));
}
if(entity.getYRotation()>0)
{
matrix = matrix.rotate(entity.getYRotation(), new Vector3f(0f, 1f, 0f));
}
if(entity.getZRotation()>0)
{
matrix = matrix.rotate(entity.getZRotation(), new Vector3f(0f, 0f, 1f));
}
if(entity.getXScale()!=1 || entity.getYScale()!=1 || entity.getZScale()!=1)
{
matrix = matrix.scale(new Vector3f(entity.getXScale(), entity.getYScale(), entity.getZScale()));
}
return matrix;
}
This works when rolling down either the x or z axis, but when I roll in a direction between the two axes the rotation appears incorrect. My assumption is that this is caused by the fact that the rotation is being calculated as follows:
the ball is rotated by rotation.x along the X axis
the ball is then rotation by rotation.z along "new" X axis created by step 1.
Any suggestions how this behaviour could be changed so that each rotation is calculated independently of each other?
Unless you want to implement slipping and/or backspin, I think you should approach this problem slightly different. You already have a Matrix.rotate() that supports rotation around an arbitrary axis, use it.
Attributes to store for the ball
position
rotation matrix
Note: in a matrix-oriented system / scene graph, bould would usually be stored in a single 4x4 transformation matrix. That might or might not be more convenience, depending on the rest of your current code base.
Algorithm for moving around
Given the ball direction and the standard up vector (0, 1, 0), calculate the rotation axis using the cross product. (i.e. it's perpendiciular to both direction and up axis)
Rotation is now simply a matrix.rotate( rotationSpeed, rotationAxis), applied to the existing rotation matrix.
If the ball is allowed to roll up/down surfaces, replace the standard up vector with the appropriate surface normal.