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.
Related
I am working on a project that displays a laser beam and it's path through reflections. When an entity is hit by a laser it calls the entities alterLaser(Laser r) method. In order to create a reflecting ray I must call Laser.createNew(x,y,angle counter clockwise of (+x)). My problem is that I can find the angle of reflection easily but I don't know how to find that angle relative to the x-axis.
I first tried finding the acute angle in between the two vectors laser and mirror but I do not know if there is a direct relationship between that and the x-axis. After searching the internet I found this formula:
r = i + 2s - 180
where r is the angle the reflected ray makes with the X-axis. i is the angle the initial ray makes with the x-axis and s is the angle the reflected ray makes with the x-axis;
I found this formula wasn't working, but in the cases I tried it was giving theta in a different quadrant than the intended quadrant. But that poses the new problem of finding which quadrant it is in.
here is a look at my current code:
#Override
protected void alterLaser(Laser r) {
Vec laser = new Vec(r.getStartX(),r.getStartY(),r.getEndX(),r.getEndY());
Vec mirror = new Vec(this.getStartX(),this.getStartY(),this.getEndX(),this.getEndY());
double theta,thetaq2,thetaq3,thetaq4;
theta = laser.angle() + (2 * mirror.absAngle()) - 180;
theta = Vec.absTheta(theta);
thetaq2 = 180-theta;
thetaq3 = theta+180;
thetaq4 = 360-theta;
Laser.createNew(r.getEndX(),r.getEndY(),theta,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq2,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq3,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq4,null,this);
}
}
The easiest way in Java to find the angle a vector makes counterclockwise with respect to positive x axis is to use the Math.atan2 function. https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#atan2(double,%20double)
This will put the value on the range -pi to pi so you don't have to worry about special casing the different quadrants.
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 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.
I'm trying to rotate a model by
(float) Math.atan2(-camX.getXf() * padX, -camDir.getZf() * padY)
Y
and
-MathUtils.HALF_PI
Z
But
model.setRotation(new Matrix3(1,0,0,
0,(float) Math.atan2(-camX.getXf() * padX, -camDir.getZf() * padY),0,
0,0,-MathUtils.HALF_PI));
It rotates on the y axis (Though it's sideways because it's a md2 model) but rotating the Z axis doesn't make it right side up. Any idea why?
Each variable is in it's respective area of the matrix.
EDIT: alright, now I'm using this code:
float x = 0;
float y = (float) Math.atan2(-camX.getXf() * padX, -camDir.getZf() * padY);
float z = (float) -MathUtils.HALF_PI;
float a = (float) Math.sin(x);
float A = (float) Math.cos(x);
float b = (float) Math.sin(y);
float B = (float) Math.cos(y);
float c = (float) Math.sin(z);
float C = (float) Math.cos(z);
Matrix3 m = new Matrix3(A*b, -(B*a),b,
(C*a)+(A*b*c), (A*C)-(a*b*c), -(B*c),
(a*c)-(A*C*b), (A*c)+(C*a*b), B*C);
But now none of the axis are rotating correctly.
This is how the matrix is set up:
xx, xy, xz,
yx, yy, yz,
zx, zy, zz
Rotation matrices don't work this way. Angles don't go into matrices! Instead I assume that Java handles a rotation matrix just like any other transformation matrix in cartesian coordinates. Since I think you don't want to input the rotation matrix by hand, you are probably better off starting with a new Matrix3 (I hope it is automatically initialized at the identity matrix), and then successively rotating it using rotateX(float x), rotateY(float y) and rotateZ(float z), where x, y, z are the angles you want to rotate about. (In case you are using com.threed.jpct.Matrix, at least.) Note that the result does depend on the succession of the three rotations.
Here is a typical tutorial on how to use rotation matrices http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm. The order of applying rotations round the three axes is critical. Alternatively you can rotate about an arbitrary axis. Also you may want to explore quaternions.
This is what a rotation matrix looks like in 2D; it rotates a point in (x,y) space about the z-axis in the counterclockwise direction.
http://en.wikipedia.org/wiki/Rotation_matrix
I have matrix. This matrix represents array x and y coordinates. For example
float[] src = {7,1,7,2,7,3,7,4};
I need to rotate this coordinates to 90 degrees.
I use android.graphics.Matrix like this:
float[] src = {7,1,7,2,7,3,7,4};
float[] dist = new float[8];
Matrix matrix = new Matrix();
matrix.preRotate(90.0f);
matrix.mapPoints(dist,src);
after operation rotate I have array with next values
-1.0 7.0 -2.0 7.0 -3.0 7.0 -4.0 7.0
Its is good for area with 360 degrees.
And how do rotate in area from 0 to 90? I need set up center of circle in this area but how ?
Thanks.
Use setRotate, not preRotate:
setRotate initializes the matrix as a rotation matrix.
preRotate multiplies the current matrix by a rotation matrix M' =
M x R
Since you called the default constructor your starting with the identity matrix.
Remember matrix multiplication is not commutative.
I'm not familiar with android, but if you translate after you rotate you can get a rotation around a specific point. Find where your center point would be rotated to, then translate it back to it's original position.
Use the Matrix preRotate(float degrees, float px, float py) method (preRotate documenation)
This preRoate(degrees) is equivalent to preRotate(degrees, 0, 0).