How to calculate vec4 cross product with glm? - math

Why this throws an compilation error: no matching function for call to ‘cross(glm::vec4&, glm::vec4&)’
glm::vec4 a;
glm::vec4 b;
glm::vec4 c = glm::cross(a, b);
but it works fine for vec3?

There is no such thing as a 4D vector cross-product; the operation is only defined for 3D vectors. Well, technically, there is a seven-dimensional vector cross-product, but somehow I don't think you're looking for that.
Since 4D vector cross-products aren't mathematically reasonable, GLM doesn't offer a function to compute it.

What do your vec4's represent? Like Nicol said, cross products are only for 3D vectors. The cross product operation is used to find a vector that is orthogonal to the two input vectors. So if your vec4's represent 3D homogeneous vectors in the form {x, y, z, w}, then the w-component doesn't matter to you; You could simply ignore it.
A workaround could go as follows:
vec4 crossVec4(vec4 _v1, vec4 _v2){
vec3 vec1 = vec3(_v1[0], _v1[1], _v1[2]);
vec3 vec2 = vec3(_v2[0], _v2[1], _v2[2]);
vec3 res = cross(vec1, vec2);
return vec4(res[0], res[1], res[2], 1);
}
Simply turn your vec4's into vec3's, perform the cross product, then add a w-component of 1 back into it.

The generalization of the cross product is the wedge product, and the wedge product of two vectors is a 2-form, also known as a bivector.
In 3-space, the 2-form kinda looks like a vector, but it behaves quite differently. Suppose we have two non-collinear vectors tangent to a surface (aka tangent vectors). By taking the cross product of these vectors, we have a 2-form that represents the tangent plane. We can also represent that tangent plane by the vector normal to that plane (aka the normal vector). But the tangent and normal vectors are transformed differently, i.e. the normal vector is transformed by the inverse transpose of the matrix used to transform the tangent vectors.
In 4-space, the 2-form resulting from the wedge product of two vectors also represents the plane that contains the two vectors (this is also true in N-space). Similarly to the case in 3-space, we can have an alternate interpretation of that plane, but in 4-space, the complement to a plane is not a 4-vector, but another plane, both of which are represented with 6 components, not 4.
c1 * e1^e2 + c2 * e1^e3 + c3 * e1^e4 + c4 * e2^e3 + c5 * e2^e4 + c6 * e3^e4
Since glm doesn't provide the API for wedge products, you will have to roll your own. You can easily work out the algebra for the wedge product with two simple rules:
(1) ei ^ ei = 0
(2) ei ^ ej = -ej ^ ei
where the ei and ej are the component vectors (bases) of the vector space, e.g.
[a b c d] --> a * e1 + b * e2 + c * e3 + d * e4
The 7-dimensional vector referred to in a previous post is the geometric product of two vectors, which uses ei^ei=1 instead of rule (1) above, and is like a meld of the dot and cross products (or complex multiplication), which is more than what you want.
For more information, https://en.wikipedia.org/wiki/Exterior_algebra or https://en.wikipedia.org/wiki/Geometric_algebra .

There is more shortcut way to calculate cross product using glm's GLM_SWIZZLE.
Just do #define GLM_SWIZZLE before inclusion of any glm file. It's also helpful for lots of other tricks.
glm::vec4 a;
glm::vec4 b;
glm::vec4 c = glm::vec4( glm::cross( glm::vec3( a.xyz ), glm::vec3( b.xyz ) ), 0 );

Related

How to use 4d rotors

I'm trying to create a 4D environment, similar to Miegakure's.
I'm having trouble understanding how to represent rotations. The creator of Miegakure wrote this small article explaining he made a class for 4d rotors.
http://marctenbosch.com/news/2011/05/4d-rotations-and-the-4d-equivalent-of-quaternions/
How can I implement the functions of this class ? In particular the functions to rotate vectors and other rotors, and getting the inverse ?
I would appreciate some pseudocode examples.
Thanks a lot to anyone who bothers answering.
The most common way to represent goemetric algebra multivectors (including rotors) in a computer is via an array of coefficients, one for each canonical form algebra basis element (canonical basis blade) ie. for a 4D basis space you will have a 2^4 dimensional algebra and have 2^4 dimensional array of coefficients. An alternate but probably faster way to represent them is with a dynamically resizing list with each element containing an index to a blade and the coefficient of the associated blade. In this case the multiplication of two multivectors will only use non zero basis blades and so should be algorithmically cheaper and lighter on memory usage.
In terms of practical usage I found the easiest place to get started with playing around with geometric algebra is probably in python with https://github.com/pygae/clifford . Full disclaimer I use this library daily and contribute to it extensively. This library uses the flat array of coefficients approach. With this python library you can apply 4D rotors via the sandwich product and do reversion (inversion of a rotor) via the tilde operator:
# Create a 4D geometric algebra with euclidean metric
from clifford.g4 import *
# Create a rotor
R = layout.randomRotor()
# Create a vector to rotate
V = layout.randomV()
# Apply the rotor to the vector
V2 = R*V*~R
The specific definition of the geometric product and reverse for multivectors from an N-dimensional geometric algebra can be found in Chapter 4 of Geometric algebra for Physicists by Chris Doran and Anthony Lasenby.
A good C++ GA reference implementation for N-dimensional GAs using the list of elements approach can be found in Leo Dorst's book Geometric Algebra for Physicists or on his website:
http://www.geometricalgebra.net/code.html . In general this is a great resource for GA, especially the conformal model and numerical implementations and concerns.
I was able to use Rotors after learning more on the subject thanks to this youtube series about Geometric Algebra : https://www.youtube.com/watch?v=PNlgMPzj-7Q&list=PLpzmRsG7u_gqaTo_vEseQ7U8KFvtiJY4K
It's really well explained and I recommend it to whoever wants use geometric algebra.
If you already know about Quaternions multiplication, Rotor multiplication won't be any different, and the i, j, k units of quaternions are analog to the basis bivectors of Geometric Algebra : e12, e13, e23 (or e01, e02, e12)
So a Rotor in 4D will be (A + B*e12 + C*e13 + D*e14 + E*e23 + F*e24 + G*e34 + H*e1234).
A table showing how to multiply those units can be found on this page :
http://www.euclideanspace.com/maths/algebra/clifford/d4/arithmetic/index.htm
To get the gist of it, consider the 2D Rotors.
They're of the form: R = A + B*e12
Now, if we compute product between 2 arbitrary rotors R_1 and R_2, we get:
R_1*R_2 = (
R_1.a * R_2.a
+ R_1.a * R_2.b*e12
+ R_1.b*e12 * R_2.a
+ R_1.b*e12 * R_2.b*e12 )
// but: e12*e12 = e1e2e1e2 = -e1e2e2e1= -e1e1 = -1
// this is confirmed by the computation rules I linked above
=
( (R_1.a * R_1.a - R_2.b * R_2.b)
+ (R_1.a * R_2.b + R_1.b * R_2.a) * e12 )
So in code, you would do something like :
R_3.a = R_1.a * R_2.a - R_1.b * R_2.b
R_3.b = R_1.a * R_2.b + R_1.b * R_2.a
Now it's only a matter of doing the same with those big 4D rotors, applying the multiplication rules for dimension 4 as linked above.
Here is the resulting code (using e0, e1, e2, e3 as basis vectors):
e: self.e*other.e - self.e01*other.e01 - self.e02*other.e02 - self.e03*other.e03 - self.e12*other.e12 - self.e13*other.e13 - self.e23*other.e23 + self.e0123*other.e0123,
e01: self.e*other.e01 + self.e01*other.e - self.e02*other.e12 - self.e03*other.e13 + self.e12*other.e02 + self.e13*other.e03 - self.e23*other.e0123 - self.e0123*other.e23,
e02: self.e*other.e02 + self.e01*other.e12 + self.e02*other.e - self.e03*other.e23 - self.e12*other.e01 + self.e13*other.e0123 + self.e23*other.e03 + self.e0123*other.e13,
e03: self.e*other.e03 + self.e01*other.e13 + self.e02*other.e23 + self.e03*other.e - self.e12*other.e0123 - self.e13*other.e01 - self.e23*other.e02 - self.e0123*other.e12,
e12: self.e*other.e12 - self.e01*other.e02 + self.e02*other.e01 - self.e03*other.e0123 + self.e12*other.e - self.e13*other.e23 + self.e23*other.e13 - self.e0123*other.e03,
e13: self.e*other.e13 - self.e01*other.e03 + self.e02*other.e0123 + self.e03*other.e01 + self.e12*other.e23 + self.e13*other.e - self.e23*other.e12 + self.e0123*other.e02,
e23: self.e*other.e23 - self.e01*other.e0123 - self.e02*other.e03 + self.e03*other.e02 - self.e12*other.e13 + self.e13*other.e12 + self.e23*other.e - self.e0123*other.e01,
e0123: self.e*other.e0123 + self.e01*other.e23 - self.e02*other.e13 + self.e03*other.e12 + self.e12*other.e03 - self.e13*other.e02 + self.e23*other.e01 + self.e0123*other.e,
Solving rotation around arbitrary vector will make you insane in 4D. Yes there are equations for that out there like The Euler–Rodrigues formula for 3D rotations expansion to 4D but all of them need to solve system of equations and its use is really not intuitive for us in 4D.
I am using rotation parallel to planes instead (similar to rotations around main axises in 3D) In 4D there are 6 of them XY,YZ,ZX,XW,YW,ZW so just create rotation matrices (similar to 3D). I am using 5x5 homogenuous transform matrices for 4D so the rotations looks like this:
xy:
( c , s ,0.0,0.0,0.0)
(-s , c ,0.0,0.0,0.0)
(0.0,0.0,1.0,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
yz:
(1.0,0.0,0.0,0.0,0.0)
(0.0, c , s ,0.0,0.0)
(0.0,-s , c ,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
zx:
( c ,0.0,-s ,0.0,0.0)
(0.0,1.0,0.0,0.0,0.0)
( s ,0.0, c ,0.0,0.0)
(0.0,0.0,0.0,1.0,0.0)
(0.0,0.0,0.0,0.0,1.0)
xw:
( c ,0.0,0.0, s ,0.0)
(0.0,1.0,0.0,0.0,0.0)
(0.0,0.0,1.0,0.0,0.0)
(-s ,0.0,0.0, c ,0.0)
(0.0,0.0,0.0,0.0,1.0)
yw:
(1.0,0.0,0.0,0.0,0.0)
(0.0, c ,0.0,-s ,0.0)
(0.0,0.0,1.0,0.0,0.0)
(0.0, s ,0.0, c ,0.0)
(0.0,0.0,0.0,0.0,1.0)
zw:
(1.0,0.0,0.0,0.0,0.0)
(0.0,1.0,0.0,0.0,0.0)
(0.0,0.0, c ,-s ,0.0)
(0.0,0.0, s , c ,0.0)
(0.0,0.0,0.0,0.0,1.0)
Where c=cos(a),s=sin(a) and a is angle of rotation. The rotation axis goes through coordinate system origin (0,0,0,0). For more info take a look at these:
Understanding 4x4 homogenous transform matrices mine 3D math
4D rendering techniques mine C++ 4D render
Visualising 4D objects in OpenGL older QAs
4D to 3D perspective projection older QAs
Four-Space Visualization of 4D Objects this is the most comprehensive stuff on the topic I found read it !!!

How to calculate an orthogonal plane from a vector

I have a position in space called X1. X1 has a velocity called V1. I need to construct an orthogonal plane perpendicular to the velocity vector. The origin of the plane is X1.
I need to turn the two edges from the plane into two vectors, E1 and E2. The edges connect at the origin. So the three vectors form an axis.
I'm using the GLM library for the vector mathematics.
One way to create a frame from a vector is to use Householder transformations. This may seem complicated but the code is in quite short, at least as efficient as using cross products, and less prone to rounding error. Moreover exactly the same idea works in any number of dimensions.
The ideas is, given a vector v, find a Householder transformation that maps v to a multiple of (1,0,0), and then apply the inverse of this to (0,1,0) and (0,0,1) to get the other frame vectors. Since a Householder transformation is it's own inverse, and since they are simple to apply, the resulting code is fairly efficient. Below is C code that I use:
static void make_frame( const double* v, double* f)
{
double lv = hypot( hypot( v[0], v[1]), v[2]); // length of v
double s = v[0] > 0.0 ? -1.0 : 1.0;
double h[3] = { v[0] - s*lv, v[1], v[2]}; // householder vector for Q
double a = 1.0/(lv*(lv + fabs( v[0]))); // == 2/(h'*h)
double b;
// first frame vector is v normalised
b = 1.0/lv;
f[3*0+0] = b*v[0]; f[3*0+1] = b*v[1]; f[3*0+2] = b*v[2];
// compute other frame vectors by applying Q to (0,1,0) and (0,0,1)
b = -v[1]*a;
f[3*1+0] = b*h[0]; f[3*1+1] = 1.0 + b*h[1]; f[3*1+2] = b*h[2];
b = -v[2]*a;
f[3*2+0] = h[0]*b; f[3*2+1] = b*h[1]; f[3*2+2] = 1.0 + b*h[2];
}
In general you can define a plane in 3D using four numbers, e.g., Ax+By+Cz=D. You can think of the triple of numbers (A,B,C) as a vector that sticks out perpendicularly to the plane (called the normal vector).
The normal vector n = (A,B,C) only defines the orientation of the plane, so depending on the choice of the constant D you get planes at different distance from the origin.
If I understand your question correctly, the plane you're looking for has normal vector (A,B,C) = V1 and the constant D is obtained using the dot product: D = (A,B,C) . X1, i.e., D = AX1.x + BX1.y + C*X1.z.
Note you can also obtain the same result using the geometric equation of a plane n . ((x,y,z) - p0) = 0, where p0 is some point on the plane, which in your case is V1 . ( (x,y,z) - X1) = 0.

How to get the "anti-clockwise" angle between two 2D vectors?

I have two vectors and I want to get the angle between those vectors, I am currently doing it with this formula :
acos(dot(v1.unitVector, v2.unitVector))
Here is what I get with it :
I would want the green angle rather than the red angle, but I don't know what formula I should use...
Thank you.
EDIT : So, hen the vectors are still in a certain position (like the first two pairs of vectors, it's ok, but whenever it is in a configuration like in the third pair, it doesn't give me the right angle anymore)
With the dot product you get always an angle that is independent of the order of the vectors and the smaller of the two possibilities.
For what you want, you need the argument function of complex numbers that is realized by the atan2 function. The angle from a=ax+i*ay to b=bx+i*by is the argument of the conjugate of a times b (rotating b backwards by the angle of a, scale not considered), which in coordinates is
(ax-i*ay) * (bx+i*by) = ax*bx+ay*by + i*(ax*by-ay*bx)
so the angle is
atan2( ax*by-ay*bx, ax*bx+ay*by ).
Adding to the accepted answer, the problem with atan2 is that, if you imagine vector a being static and vector b rotating in anti-clockwise direction, you will see the return value ranging from 0 to π, but then it suddenly turns negative and proceeds from -π to 0, which is not exactly good if you're interested in an angle increasing from 0 to 2π.
To tackle that problem, the function below conveniently maps the result from atan2 and returns a value between 0 and 2π as one would expect:
const TAU = Math.PI * 2;
/**
* Gives the angle in radians from vector a to vector b in anticlockwise direction,
* ranging from 0 to 2π.
*
* #param {Vector} a
* #param {Vector} b
* #returns {Number}
*/
static angle(a, b) {
let angle = Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
if (angle < 0) {
angle += TAU;
}
return angle;
}
It is written in JavaScript, but it's easily portable to other languages.
Lutz already answered this correctly but let me add that I highly recommend basing modern vector math code on Geometric Algebra which raises the abstraction level dramatically.
Using GA, you can simply multiply the two vectors U and V to get a rotor. The rotor internally looks like A + Bxy where A = U dot V = |U|V|cos(angle) and Bxy = U wedge V = |U||V|sin(angle)xy (this is isomorphic to the complex numbers). Then you can return the rotor's signed CCW angle which is atan2( B, A ).
So with operator overloading, you can just type (u * v).Angle. The final calculations end up the same, but the abstraction level you think and work in is much higher.
Maybe this one is more fit:
atan2( ax*by-ay*bx, ax*bx+ay*by ) % (PI*2)
the calculation which could get the full anti-clockwise radian.

Local interpolation of surfaces using normal vectors

I need to interpolate a 3D surface given it's points and normal vectors.
Given a point on it's surface, I need to find where that point would be in space once the interpolation has been accounted for. I need to be able to do this for each triangle in isolation.
Here's what I'm trying to describe. I need the position of the point once the curve / surface has been interpolated.
If I was working in 2D:
3D:
I've come across this paper "Simple local interpolation of surfaces using normal vectors - Takashi Nagata" which I think demonstrates exactly what I'm looking for (section 2.2. Interpolation of a patch using normals), but the math is just beyond me.
What I'm trying to extract from it is a set of equations where the position and normals of the points comprising the triangle go in, as well as the point on the triangle, and the adjusted point comes out (like magic).
The paper looks like its trying to fit a quadratic surface so that it matches the points and normals you have. The resulting surface is given by
p(s,t) = c00 + c10 s + c01 t + c11 s t + c20 s^2 + c02 t^2
where s,t are the two variables, c00 etc are all vectors with three coordinates. s,t are chosen so at s=0,t=0 its your first point, s=1, t=0 is your second point and s=1,t=1 is your third point. Assuming we can find the various c00's you can pick some values of s,t in the triangle to give a middle point, s=2/3, t=1/3 might be a find candidate.
Find c00 etc will take some work. You probably need to implement eqn 15, which gives a curvature, as a function
vec3 c(vec3 D,vec3 n0,vec3 n1) {
vec3 v = (n0 + n1)/2; // 12a
vec3 dv = (n0 - n1)/2; // 12b
double d = D.dot(v); // 13a
double dd = D.dot(dv); // 13b
double c = n0.dot(n0 - 2*dv); // 14a
double dc = n0.dot(dv); // 14b
vec3 res;
if( c == -1 || c==1 )
res = vec3.zeroVector;
else
res = dd / (1-dc) * v + d / dc * dv;
return res;
}
assuming you have a vec3 class which can do basic vector operators.
With that defined, use 35, 36 to define the starting vectors and normals. Use 39 to define differences between pairs of points d1, d2, d3 and curvatures c1, c2, c3. The use eq 44
x(η, ζ ) = x00(1 − η) + x10(η − ζ ) + x11ζ
− c1(1 − η)(η − ζ ) − c2(η − ζ )ζ − c3(1 − η)ζ
and your done.
For the records, and because I wanted to have this information somewhere on the web.
This is the 2d interpolation using the paper posted by the OP.
Where 1a and 1b are the boundary conditions, and the equations 4a and 4b are the x and y components of the vector c needed for the interpolation.

How to determine if a vector is between two other vectors?

I am looking for a fast and effective way to determine if vector B is Between the small angle of vector A and vector C. Normally I would use the perpendicular dot product to determine which sides of each line B lies on but in this case is not so simple because of the following:
None of the vectors can be assumed to be normalized and normalizing them is an extra step I would prefer to avoid.
I have no clear notion as to which side is the smallest angle so it is hard to say which side of the line is good or not.
It is possible for A and B to be co-linear or exactly 180 degrees apart in which case I want to return false.
While I am working in a 3D enviroment it is easy for me to simplify this to 2D if that makes things easier and more importantly faster. This test will be used in an algorithm that needs to run as fast as possible.
If there is some easy and efficient method to determine which direction my perpendicular vectors should both point I could use the two dot products for my test.
Another approach I have been considering without much success so far is using a matrix. In theory from what I understand of matrix transforms I should be able to use A and C as basis vectors. Then multiplying B by the matrix I should be able to test what quadrant B then lies in by whether X and Y are both positive. If I could get this approach to work it would likely be the best since one matrix multiplication should be faster than two dot products and I should not have to worry about which side has the smallest angle on it.
The problem is from my tests I cannot simply use A and C as bases and multiply it normally and get correct behavior. I am really not sure what i am doing wrong here. I have run across the term "Vector spaces" a few times which as near as I can figure seems to be a very similar concept to matrix transforms without any requirements for orthogonal bases or orthonormal bases. Is it the same thing as matrix? If not, might there be a better approach and how would I use that?
Just to give a more visual explanation of what I am talking about:
#Aki Suihkonen
I can't seem to get it working. Coded up a mock case I could run through and see if I can't figure somthing out
For this case using
Ax 2.9579773 Ay 3.315979
Cx 2.5879822 Cy 5.1630249
For B I rotated around the four quadrants the vectors divide the space up into.
The signs I got:
- For Q1 --
- For Q2 +-
- For Q3 +-
- For Q4 --
Assuming I rotated around in the enviroment the same direction as the image I am fairly sure I did.
I think Aki's solution is close, but there are cases where it doesn't work:
From his solution:
return (ay * bx - ax * by) * (ay * cx - ax * cy) < 0;
This is equivalent to checking whether the cross product between B and A has the same sign as the cross product between C and A.
The sign of the cross product (U x V) tells you whether V lies on one side of U or the other (out of the board, into the board). In most coordinate systems, if U needs to rotate counter-clockwise (out of the board), then the sign will be positive.
So Aki's solution checks to see if B needs to rotate in one direction to get to A, while C needs to rotate in the other direction. If this is the case, B is not within A and C. This solution doesn't work when you don't know the 'order' of A and C, as follows:
To know for certain whether B is within A and C you need to check both ways. That is, the rotation direction from A to B should be the same as from A to C, and the rotation direction from C to B should be the same as from C to A.
This reduces to:
if (AxB * AxC >= 0 && CxB * CxA >= 0)
// then B is definitely inside A and C
One method to think about this is to regard all these vectors A, B, C as complex numbers.
Multiplying A, C all with B*, which is the complex conjugate of B, both the resulting vectors will be rotated in complex plane so that the reference axis (B*Conj(B)) is now the real axis (or y = 0) -- and that axis doesn't need to be calculated. In this case one only has to check if the sign of 'y' or imaginary component differ. Also in this case both resulting vectors have been scaled by the same length |B|.
`return sign(Imag(A * Conj(B))) != sign(Imag(C * Conj(B)));`
A = ax + i * ay; B = bx + i * by; C = cx + i * cy;
Conj(B) = bx - i * by;
A * B = (ax * bx - ay * by) + i * (ax * by + ay * bx);
I think this equation leads to even better performance, as only the Imaginary component of the multiplication is needed.
As a full solution, this converts to:
return (ay * bx - ax * by) * (ay * cx - ax * cy) < 0;
The middle multiplication is a short cut for:
return Sign(ay * bx - ax * by) != Sign(ay * cx - ax * cy);
Without complex numbers, the problem can be also seen as vector B being
{ Rcos beta, Rsin beta }, which can be represented as a rotation matrix.
R*[ cb -sb ] [ bx -by ], cb = cos(beta), sb = sin(beta)
[ sb cb ] = [ by bx ] cos(-beta) = cos(beta), sin(-beta) = -sin(beta)
Multiplying [ax,ay], [cx,cy] with the transpose of the scaled matrix [bx by, -by bx] affects the lengths of [ax, ay] * rotMatrix(-beta), [cx, cy] * rotMatrix(-beta) in exactly the same way.
In polar coordinates, you would just be asking if θA < θB < θC. So transform to polar first:
a_theta = ax ? atan(ay / ax) : sign(ay) * pi

Resources