I have a plane class that stores a plane as
Vector position;
Vector normal;
float d;
(Vector is just x,y,z in a helper class)
Been using it for years, serves almost all my purposes. However, I use it as a savant without really thinking much about how/why it works.
So... I need to convert it to to a float[4] format for a friend to use for some OpenGL rendering. What's the right way to convert point/normal/d to the plane equation in float[4]? Everything I try seems to be off a little bit.
[Edit]
This is the plane's Create() function, which assigns a value to d...
void Create(Vector thePoint, Vector theNormal)
{
theNormal.Normalize();
pos=thePoint;
normal=theNormal;
d=-theNormal.Dot(thePoint);
}
Using homogeneous coordinates points are
Point = [x,y,z,1]
To define the equation of a plane
you need the following 4 values for the coordinates of the plane
Plane = [n_x,n_y,n_z,-d]
Where (n_x,n_y,n_z) is the normal vector, and d the distance to the origin.
Now taking the dot product of the point and the plane yields the equation
[x,y,z,1] . [n_x,n_y,n_z,-d] = 0
x*n_x + y*n_y + z*n_z - d = 0
In C# code this is
public float[] GetCoord(Plane plane)
{
return new float[] { plane.normal.X, plane.normal.Y, plane.normal.Z, -plane.d };
}
Related
i am scratching my head for some time now how to do this.
I have two defined vectors in 3d space. Say vector X at (0,0,0) and vector Y at (3,3,3). I will get a random point on a line between those two vectors. And around this point i want to form a circle ( some amount of points ) perpendicular to the line between the X and Y at given radius.
Hopefuly its clear what i am looking for. I have looked through many similar questions, but just cant figure it out based on those. Thanks for any help.
Edit:
(Couldnt put everything into comment so adding it here)
#WillyWonka
Hi, thanks for your reply, i had some moderate success with implementing your solution, but has some trouble with it. It works most of the time, except for specific scenarios when Y point would be at positions like (20,20,20). If it sits directly on any axis its fine.
But as soon as it gets into diagonal the distance between perpendicular point and origin gets smaller for some reason and at very specific diagonal positions it kinda flips the perpendicular points.
IMAGE
Here is the code for you to look at
public Vector3 X = new Vector3(0,0,0);
public Vector3 Y = new Vector3(0,0,20);
Vector3 A;
Vector3 B;
List<Vector3> points = new List<Vector3>();
void FindPerpendicular(Vector3 x, Vector3 y)
{
Vector3 direction = (x-y);
Vector3 normalized = (x-y).normalized;
float dotProduct1 = Vector3.Dot(normalized, Vector3.left);
float dotProduct2 = Vector3.Dot(normalized, Vector3.forward);
float dotProduct3 = Vector3.Dot(normalized, Vector3.up);
Vector3 dotVector = ((1.0f - Mathf.Abs(dotProduct1)) * Vector3.right) +
((1.0f - Mathf.Abs(dotProduct2)) * Vector3.forward) +
((1.0f - Mathf.Abs(dotProduct3)) * Vector3.up);
A = Vector3.Cross(normalized, dotVector.normalized);
B = Vector3.Cross(A, normalized);
}
What you want to do first is to find the two orthogonal basis vectors of the plane perpendicular to the line XY, passing through the point you choose.
You first need to find a vector which is perpendicular to XY. To do this:
Normalize the vector XY first
Dot XY with the X-axis
If this is very small (for numerical stability let's say < 0.1) then it must be parallel/anti-parallel to the X-axis. We choose the Y axis.
If not then we choose the X-axis
For whichever chosen axis, cross it with XY to get one of the basis vectors; cross this with XY again to get the second vector.
Normalize them (not strictly necessary but very useful)
You now have two basis vectors to calculate your circle coordinates, call them A and B. Call the point you chose P.
Then any point on the circle can be parametrically calculated by
Q(r, t) = P + r * (A * cos(t) + B * sin(t))
where t is an angle (between 0 and 2π), and r is the circle's radius.
I have an irregular tetrahedron using 4 vertices.
I need to find out the altitude given that one specific vertex is the top and the others are the base.
Basically the height would be the shortest distance from the top to its base creating a 90 degrees angle. It should be a simple math question but I cannot find anything on Google.
I am looking for an optimized function that looks like this :
float GetPyramidAltitude (Vector3 top, Vector3 baseA, Vector3 baseB, Vector3 baseC) {
...
}
Thank you for your help.
This is equivalent to finding the distance between a point and a plane. The plane is defined by the three points comprising the base. There is a detailed explanation on determining a plane given three points and finding the minimal distance between a point and a plane.
Disclaimer: I don't know Unity3D, so I'm kind of making up the syntax below. If something's not clear, let me know; otherwise you're going to have to translate into something that will compile using the Unity3D API.
The first step is to determine the equation of the plane given three points. The plane normal is given by:
n = cross(baseB-baseA, baseC-baseA);
n = n / norm(n);
Where cross returns the cross product of the two arguments, and norm returns the l2 norm (vector magnitude). The offset term in the plane equation is given by:
d = -n.x*baseA.x - n.y*baseA.y - n.z*baseA.z;
This will result in the plane equation:
n.x*X + n.y*Y + n.z*Z + d = 0
To find the distance between the top and the plane is then given by
D = dot(n, top) + d;
where dot is the dot product of the unit vector normal of the plane n and top and d is defined earlier. When D > 0 top is "above" the plane defined by the three base points where the normal points "up". When D < 0 the top is below the plane. So, in your case, you may want to take the absolute value of D to get the distance.
Thanks, however I found a solution from a method in Unity.
Basically we only need 3 parameters : the top vertex, one vertex from the base and the base's face normal which I already had.
Here's my solution :
float GetPyramidAltitude (Vector3 top, Vector3 baseA, Vector3 baseNormal) {
Vector3 topToBase = Vector3.Project(baseA - top, baseNormal);
return topToBase.magnitude;
}
Solved
I'm making a 3D portal system in my engine (like Portal game). Each of the portals has its own orientation saved in a quaternion. To render the virtual scene in one of the portals I need to calculate the difference between the two quaternions, and the result use to rotate the virtual scene.
When creating the first portal on the left wall, and second one on the right wall, the rotation from one to another will take place in only one axis, but for example when the first portal will be created on the floor, and the second one on the right wall, the rotation from one to another could be in two axis, and that's the problem, because the rotation goes wrong.
I think the problem exists because the orientation for example X axis and Z axis are stored together in one quaternion and I need it separately to manualy multiply X * Z (or Z * X), but how to do it with only one quaternion, (the difference quaternion)? Or is there other way to correct rotate the scene?
EDIT:
Here on this picture are two portals P1 and P2, the arrows show how are they rotated. As I am looking into P1 I will see what sees P2. To find the rotation which I need to rotate the main scene to be like the virtual scene in this picture I'm doing following:
Getting difference from quaternion P2 to quaternion P1
Rotating result by 180 degrees in Y axis (portal's UP)
Using the result to rotate the virtual scene
This method above works only when the difference takes place in only one axis. When one portal will be on the floor, or on te ceiling, this will not work because the difference quaternion is build in more than one axis. As suggested I tried to multiply P1's quaternion to P2's quaternion, and inversely but this isn't working.
EDIT 2:
To find the difference from P2 to P1 I'm doing following:
Quat q1 = P1->getOrientation();
Quat q2 = P2->getOrientation();
Quat diff = Quat::diff(q2, q1); // q2 * diff = q1 //
Here's the Quat::diff function:
GE::Quat GE::Quat::diff(const Quat &a, const Quat &b)
{
Quat inv = a;
inv.inverse();
return inv * b;
}
Inverse:
void GE::Quat::inverse()
{
Quat q = (*this);
q.conjugate();
(*this) = q / Quat::dot((*this), (*this));
}
Conjugate:
void GE::Quat::conjugate()
{
Quat q;
q.x = -this->x;
q.y = -this->y;
q.z = -this->z;
q.w = this->w;
(*this) = q;
}
Dot product:
float GE::Quat::dot(const Quat &q1, const Quat &q2)
{
return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
}
Operator*:
const GE::Quat GE::Quat::operator* ( const Quat &q) const
{
Quat qu;
qu.x = this->w*q.x + this->x*q.w + this->y*q.z - this->z*q.y;
qu.y = this->w*q.y + this->y*q.w + this->z*q.x - this->x*q.z;
qu.z = this->w*q.z + this->z*q.w + this->x*q.y - this->y*q.x;
qu.w = this->w*q.w - this->x*q.x - this->y*q.y - this->z*q.z;
return qu;
}
Operator/:
const GE::Quat GE::Quat::operator/ (float s) const
{
Quat q = (*this);
return Quat(q.x / s, q.y / s, q.z / s, q.w / s);
}
All this stuff works, because I have tested it with GLM library
If you want to find a quaternion diff such that diff * q1 == q2, then you need to use the multiplicative inverse:
diff * q1 = q2 ---> diff = q2 * inverse(q1)
where: inverse(q1) = conjugate(q1) / abs(q1)
and: conjugate( quaternion(re, i, j, k) ) = quaternion(re, -i, -j, -k)
If your quaternions are rotation quaternions, they should all be unit quaternions. This makes finding the inverse easy: since abs(q1) = 1, your inverse(q1) = conjugate(q1) can be found by just negating the i, j, and k components.
However, for the kind of scene-based geometric configuration you describe, you probably don't actually want to do the above, because you also need to compute the translation correctly.
The most straightforward way to do everything correctly is to convert your quaternions into 4x4 rotation matrices, and multiply them in the appropriate order with 4x4 translation matrices, as described in most introductory computer graphics texts.
It is certainly possible to compose Euclidean transformations by hand, keeping your rotations in quaternion form while applying the quaternions incrementally to a separate translation vector. However, this method tends to be technically obscure and prone to coding error: there are good reasons why the 4x4 matrix form is conventional, and one of the big ones is that it appears to be easier to get it right that way.
I solved my problem. As it turned out I don't need any difference between two rotations. Just multiply one rotation by rotation in 180 degrees, and then multiply by inverse of second rotation that way (using matrices):
Matrix m1 = p1->getOrientation().toMatrix();
Matrix m2 = p2->getOrientation().toMatrix();
Matrix model = m1 * Matrix::rotation(180, Vector3(0,1,0)) * Matrix::inverse(m2);
and translation calculating this way:
Vector3 position = -p2->getPosition();
position = model * position + p1->getPosition();
model = Matrix::translation(position) * model;
No, you have to multiply two quaternions together to get the final quaternion you desire.
Let's say that your first rotation is q1 and the second is q2. You want to apply them in that order.
The resulting quaternion will be q2 * q1, which will represent your composite rotation (recall that quaternions use left-hand multiplication, so q2 is being applied to q1 by multiplying from the left)
Reference
For a brief tutorial on computing a single quaternion, refer to my previous stack overflow answer
Edit:
To clarify, you'd face a similar problem with rotation matrices and Euler angles. You define your transformations about X, Y, and Z, and then multiply them together to get the resulting transformation matrix (wiki). You have the same issue here. Rotation matrices and Quaternions are equivalent in most ways for representing rotations. Quaternions are preferred mostly because they're a bit easier to represent (and easier for addressing gimbal lock)
Quaternions work the following way: the local frame of reference is represented as the imaginary quaternion directions i,j,k. For instance, for an observer standing in the portal door 1 and looking in the direction of the arrow, direction i may represent the direction of the arrow, j is up and k=ij points to the right of the observer. In global coordinates represented by the quaternion q1, the axes in 3D coordinates are
q1*(i,j,k)*q1^-1=q1*(i,j,k)*q1',
where q' is the conjugate, and for unit quaternions, the conjugate is the inverse.
Now the task is to find a unit quaternion q so that directions q*(i,j,k)*q' in local frame 1 expressed in global coordinates coincide with the rotated directions of frame 2 in global coordinates. From the sketch that means forwards becomes backwards and left becomes right, that is
q1*q*(i,j,k)*q'*q1'=q2*(-i,j,-k)*q2'
=q2*j*(i,j,k)*j'*q2'
which is readily achieved by equating
q1*q=q2*j or q=q1'*q2*j.
But details may be different, mainly that another axis may represent the direction "up" instead of j.
If the global system of the sketch is from the bottom, so that global-i points forward in the vertical direction, global-j up and global-k to the right, then local1-(i,j,k) is global-(-i,j,-k), giving
q1=j.
local2-(i,j,k) is global-(-k,j,i) which can be realized by
q2=sqrt(0.5)*(1+j),
since
(1+j)*i*(1-j)=i*(1-j)^2=-2*i*j=-2*k and
(1+j)*k*(1-j)=(1+j)^2*k= 2*j*k= 2*i
Comparing this to the actual values in your implementation will indicate how the assignment of axes and quaternion directions has to be changed.
Check https://www.emis.de/proceedings/Varna/vol1/GEOM09.pdf
Imagine to get dQ from Q1 to Q2, I'll explain why dQ = Q1*·Q2, instead of Q2·Q1*
This rotates the frame, instead of an object. For any vector v in R3, the rotation action of operator
L(v) = Q*·v·Q
It's not Q·v·Q*, which is object rotation action.
If you rotates Q1 and then Q1* and then Q2, you can write
(Q1·Q1*·Q2)*·v·(Q1·Q1*·Q2) = (Q1*·Q2)*·Q1*·v·Q1·(Q1*·Q2) = dQ*·Q1*·v·Q1·dQ
So dQ = Q1*·Q2
I am presently trying to construct an OBB (Oriented Bounding Box) using the source and math contained in the book "Real Time Collision Detection".
One problem with the code contained in this book is that it does very little to explain what the parameters mean for the methods.
I am trying to figure out what I need to feed my setOBB() method (I wrote this one). It goes like this:
void PhysicalObject::setOBB( Ogre::Vector3 centrePoint, Ogre::Vector3 localAxes[3], Ogre::Vector3 positiveHalfwidthExtents )
{
// Ogre::Vector3 c; // OBB center point
// Ogre::Vector3 u[3]; // Local x-, y-, and z-axes (rotation matrix)
// Ogre::Vector3 e; // Positive halfwidth extents of OBB along each axis
m_obb.c = centrePoint;
m_obb.u[0] = localAxes[0];
m_obb.u[1] = localAxes[1];
m_obb.u[2] = localAxes[2];
m_obb.e = positiveHalfwidthExtents;
}
Looking at the parameters it wants above, the first and third parameters I believe I understand.
Pass in the centre position of the object.
This is my problem. I believe it wants a matrix represented using an array of 3 vectors? but how?
A Vector which contains magnitude for the distance between the centre point and the edge of the OBB in each x,y,z direction.
Here is what I'm doing currently:
// Build the OBB
Ogre::Vector3 rotation[3];
Ogre::Vector3 centrePoint = sphere->getPosition();
rotation[0] = ?
rotation[1] = ?
rotation[2] = ?
Ogre::Vector3 halfEdgeLengths = Ogre::Vector3( 1,1,1 );
myObject->setOBB( centrepoint, rotation, halfEdgeLengths );
How can i represent a matrix using three vectors (which I cannot avoid doing this way). Thanks.
A 3x3 matrix representing a rotation/scale in 3d space is nothing more than three vectors in row.
Each column vector is the rotated and scaled main axis. First column is the scaled and rotated x axis, second and third are y and z.
(Ogre uses column major matrices)
So, localAxes[3] simply is a rotation. And you can get it from a Quaternion.
Ogre::Vector3 rotation[3];
Ogre::Quaternion orientation = sphere->getOrientation();
orientation.ToAxes(rotation);
// Now rotation has the three axes representing the orientation of the sphere.
Ok. So another question is that this functionality requires it to be a matrix, right? I'm assuming so, or you'd just use the individual axes vectors in the places they are needed during the calculation.
That said, if you stuff these vectors into a matrix in a uniform way, then you'll either have them as the rows of the matrix or the columns of the matrix and, more or less, have a 50% chance to get it right depending on how the functions accepting the matrix expect the matrix to be formatted. So, set up the 2d array as the matrix and go forward with caution, I'd suggest. For example:
int matrix[3][3] = { { x1, x2, x3 },
{ y1, y2, y3 },
{ z1, z2, z3 }
};
Flip if you need to go column-major.
I have an input 3D vector, along with the pitch and yaw of the camera. Can anyone describe or provide a link to a resource that will help me understand and implement the required transformation and matrix mapping?
The world-to-camera transformation matrix is the inverse of the camera-to-world matrix. The camera-to-world matrix is the combination of a translation to the camera's position and a rotation to the camera's orientation. Thus, if M is the 3x3 rotation matrix corresponding to the camera's orientation and t is the camera's position, then the 4x4 camera-to-world matrix is:
M00 M01 M02 tx
M10 M11 M12 ty
M20 M21 M22 tz
0 0 0 1
Note that I've assumed that vectors are column vectors which are multiplied on the right to perform transformations. If you use the opposite convention, make sure to transpose the matrix.
To find M, you can use one of the formulas listed on Wikipedia, depending on your particular convention for roll, pitch, and yaw. Keep in mind that those formulas use the convention that vectors are row vectors which are multiplied on the left.
Instead of computing the camera-to-world matrix and inverting it, a more efficient (and numerically stable) alternative is to calculate the world-to-camera matrix directly. To do so, just invert the camera's position (by negating all 3 coordinates) and its orientation (by negating the roll, pitch, and yaw angles, and adjusting them to be in their proper ranges), and then compute the matrix using the same algorithm.
If we have a structure like this to describe a 4x4 matrix:
class Matrix4x4
{
public:
union
{
struct
{
Type Xx, Xy, Xz, Xw;
Type Yx, Yy, Yz, Yw;
Type Zx, Zy, Zz, Zw;
Type Wx, Wy, Wz, Ww;
};
struct
{
Vector3<Type> Right;
Type XW;
Vector3<Type> Up;
Type YW;
Vector3<Type> Look;
Type ZW;
Vector3<Type> Pos;
Type WW;
};
Type asDoubleArray[4][4];
Type asArray[16];
};
};
If all you have is Euler angles, that is an angles representing the yaw, pitch, and roll and a point in 3d space for the position, you can calculate the Right, Up, and Look vectors. Note that Right, Up, and Look are just the X,Y,Z Vectors, but since this is a camera, I find it easier to name it so. The simplest way to apply your roations to the camera matrix is to build a series of rotation matrices and multiply our camera matrix by each rotation matrix.
A good reference for that is here: http://www.euclideanspace.com
Once you have applied all the needed rotations, you can set the vector Pos to the camera's position in the world space.
Lastly, before you apply the camera's transformation, you need to take the camera's inverse of its matrix. This is what you are going to multiply your modelview matrix by before you start drawing polygons. For the matrix class above, the inverse is calculated like this:
template <typename Type>
Matrix4x4<Type> Matrix4x4<Type>::OrthoNormalInverse(void)
{
Matrix4x4<Type> OrthInv;
OrthInv = Transpose();
OrthInv.Xw = 0;
OrthInv.Yw = 0;
OrthInv.Zw = 0;
OrthInv.Wx = -(Right*Pos);
OrthInv.Wy = -(Up*Pos);
OrthInv.Wz = -(Look*Pos);
return OrthInv;
}
So finally, with all our matrix constuction out of the way, you would be doing something like this:
Matrix4x4<float> cameraMatrix, rollRotation, pitchRotation, yawRotation;
Vector4<float> cameraPosition;
cameraMatrix = cameraMatrix * rollRotation * pitchRotation * yawRotation;
Matrix4x4<float> invCameraMat;
invCameraMat = cameraMatrix.OrthoNormalInverse();
glMultMatrixf(invCameraMat.asArray);
Hope this helps.
What you are describing is called 'Perspective Projection' and there are reams of resources on the web that explain the matrix math and give the code necessary to do this. You could start with the wikipedia page