Is Binormal vector a cross product of normalized tangent vector and normalized normal vector or vice versa?
Binormal_vector = cross(normalize(tangent_vector), normalize(normal_vector))
or
Binormal_vector = cross(normalize(normal_vector), normalize(tangent_vector))
Many resources like this (http://mathonline.wikidot.com/method-for-calculating-unit-normal-and-unit-binormal-vectors) define Binormal vector as
B = T X N
But in most of the shader codes Binormal vector is defined as
Binormal_vector = cross(normalize(normal_vector), normalize(tangent_vector)) * handedness
i.e.
B = N X T
In an Right-Handed Coordinate System (see further Right-hand rule)
the Binormal Vector is calcualted by:
B = N x T
while in an Left-Handed Coordinate System
the Binormal Vector is calcualted by:
B = T x N
In OpenGL is commonly used a Right-Handed Coordinate System, but this depends on the specification and definitions which are chosen by the user.
Further if a system is mirrored it changes from one system to the other. This may occur if a texture is mirrored or looked at from the backface.
Note in your above code this is compensated by handedness, which is the "sign" of the binormal vector and either 1.0 or -1.0.
Binormal_vector = cross(normalize(normal_vector), normalize(tangent_vector)) * handedness
Related
I have seen the HouseHolder
equation which creates an matrix that reflects an point about an plane but the equation assumes the plane only has a normal vector v.
My plane has 3 components
The normal unit vector V
A point that lies on the plane P
Distance of the plane from origin D
All stored in seperate variables.
How would I extend the equation to take the point and distance into its calculation or do I need a different approach?
(I found out the solution anyway so here it is)
The aforementioned householder equation also suppose that your plan contains the origin. So we cannot directly apply to your solution.
However let consider P as the new origin, x coordinates in this system are now x - P and the plan goes by the origin, its normal remains the same so you can compute S the symetrie of x in this system thanks to the HouseHolder equation:
S' = (x-p) - 2v(v^h(x-p)).
and you can get its coordinate in the original system :
S(x) = (x-p) - 2v(v^h(x-p)) + p
I am not sure if a question like this was asked before but i searched and didn't found what i am looking for.
I know how to determine if a point is to the left or right of a 2D line. but suppose we have a vector in 3D. of course a 3D vector passes through infinite planes, but suppose we chose one plane of them in which we are interested, and we have a specific point on this plane which we want to know if it lies to the left or right or on our vector (with respect to the chosen plane). how to do this ?
You should explicitly define orientation of that plane - for example, define main (forward) normal N - like OZ axis is normal for OXY plane.
If you have A,B,C triangle and claim that it is oriented counterclockwise, you can calculate forward plane normal as N = AB x BC
For points A, B, D in given plane calculate mixed product (vector product of AB and AD, then scalar product of result and N)
mp = (AB x AD) . dot. N
Sign of this value is positive, if vectors AB, AD, N form right-handed triplet and D lies left to AB direction
An intuitive solution is to define a coordinate system for the plane as follows. Let's normalize the 3d vector in your question and call the resulting unit vector v, and let x be a point on your plane, whose unit normal we will denote as n. You can now chose a coordinate system centered at x, that is made by the three 3*1 unit vectors v, n and b=v.crossProduct(n).
The idea is that if you express a point in this coordinate system, then if its b coordinate is negative, you can says that it is, say, on the left. So, if its b coordinate is positive, it will be on the right.
Obviously, if you have a point q expressed in this coordinates system, you can write its expression q_w in world coordinates using
q_w=R*q+x
where the rotation matrix R is the matrix whose columns are the unit axes of the plane coordinate system:
R=[v n b]
So, if you have a point Q in world coordinates, using the inverse of the relation above, you compute transpose(R)*(Q-x), and look at whether the b coordinate is positive or negative.
I'd like to generate random points being located on the surface of an n-dimensional torus. I have found formulas for how to generate the points on the surface of a 3-dimensional torus:
x = (c + a * cos(v)) * cos(u)
y = (c + a * cos(v)) * sin(u)
z = a * sin(v)
u, v ∈ [0, 2 * pi); c, a > 0.
My question is now: how to extend this formulas to n dimensions. Any help on the matter would be much appreciated.
I guess that you can do this recursively. Start with a full orthonormal basis of your vector space, and let the current location be the origin. At each step, choose a point in the plane spanned by the first two coordinate vectors, i.e. take w1 = cos(t)*v1 + sin(t)*v2. Shift the other basis vectors, i.e. w2 = v3, w3 = v4, …. Also take a step from your current position in the direction w1, with the radius r1 chosen up front. When you only have a single basis vector remaining, then the current point is a point on the n-dimensional torus of the outermost recursive call.
Note that while the above may be used to choose points randomly, it won't choose them uniformly. That would likely be a much harder question, and you definitely should ask about the math of that on Math SE or perhaps on Cross Validated (Statistics SE) to get the math right before you worry about implementation.
An n-torus (n being the dimensionality of the surface of the torus; a bagel or doughnut is therefore a 2-torus, not a 3-torus) is a smooth mapping of an n-rectangle. One way to approach this is to generate points on the rectangle and then map them onto the torus. Aside from the problem of figuring out how to map a rectangle onto a torus (I don't know it off-hand), there is the problem that the resulting distribution of points on the torus is not uniform even if the distribution of points is uniform on the rectangle. But there must be a way to adjust the distribution on the rectangle to make it uniform on the torus.
Merely generating u and v uniformly will not necessarily sample uniformly from a torus surface. An additional step is needed.
J.F. Williamson, "Random selection of points distributed on curved surfaces", Physics in Medicine & Biology 32(10), 1987, describes a general method of choosing a uniformly random point on a parametric surface. It is an acceptance/rejection method that accepts or rejects each candidate point depending on its stretch factor (norm-of-gradient). To use this method for a parametric surface, several things have to be known about the surface, namely—
x(u, v), y(u, v) and z(u, v), which are functions that generate 3-dimensional coordinates from two dimensional coordinates u and v,
The ranges of u and v,
g(point), the norm of the gradient ("stretch factor") at each point on the surface, and
gmax, the maximum value of g for the entire surface.
For the 3-dimensional torus with the parameterization you give in your question, g and gmax are the following:
g(u, v) = a * (c + cos(v) * a).
gmax = a * (a + c).
The algorithm to generate a uniform random point on the surface of a 3-dimensional torus with torus radius c and tube radius a is then as follows (where RNDEXCRANGE(x,y) returns a number in [x,y) uniformly at random, and RNDRANGE(x,y) returns a number in [x,y] uniformly at random):
// Maximum stretch factor for torus
gmax = a * (a + c)
while true
u = RNDEXCRANGE(0, pi * 2)
v = RNDEXCRANGE(0, pi * 2)
x = cos(u)*(c+cos(v)*a)
y = sin(u)*(c+cos(v)*a)
z = sin(v)*a
// Norm of gradient (stretch factor)
g = a*abs(c+cos(v)*a)
if g >= RNDRANGE(0, gmax)
// Accept the point
return [x, y, z]
end
end
If you have n-dimensional torus generating formulas, a similar approach can be used to generate uniform random points on that torus (accept a candidate point if norm-of-gradient equals or exceeds a random number in [0, gmax), where gmax is the maximum norm-of-gradient).
I have a unit vector in 3D space whose direction I wish to perturb by some angle within the range 0 to theta, with the position of the vector remaining the same. What is a way I can accomplish this?
Thanks.
EDIT: After thinking about the way I posed the question, it seems to be a bit too general. I'll attempt to make it more specific: Assume that the vector originates from the surface of an object (i.e. sphere, circle, box, line, cylinder, cone). If there are different methods to finding the new direction for each of those objects, then providing help for the sphere one is fine.
EDIT 2: I was going to type this in a comment but it was too much.
So I have orig_vector, which I wish to perturb in some direction between 0 and theta. The theta can be thought of as forming a cone around my vector (with theta being the angle between the center and one side of the cone) and I wish to generate a new vector within that cone. I can generate a point lying on the plane that is tangent to my vector and thus creating a unit vector in the direction of the point, call it rand_vector. At this time, I orig_vector and trand_vector are two unit vectors perpendicular to each other.
I generate my first angle, angle1 between 0 and 2pi and I rotate rand_vector around orig_vector by angle1, forming rand_vector2. I looked up a resource online and it said that the second angle, angle2 should be between 0 and sin(theta) (where theta is the original "cone" angle). Then I rotate rand_vector2 by acos(angle2) around the vector defined by the cross product between rand_vector2 and orig_vector.
When I do this, I don't obtain the desired results. That is, when theta=0, I still get perturbed vectors, and I expect to get orig_vector. If anyone can explain the reason for the angles and why they are the way they are, I would greatly appreciate it.
EDIT 3: This is the final edit, I promise =). So I fixed my bug and everything that I described above works (it was an implementation bug, not a theory bug). However, my question about the angles (i.e. why is angle2 = sin(theta)*rand() and why is perturbed_vector = rand_vector2.Rotate(rand_vector2.Cross(orig_vector), acos(angle2)). Thanks so much!
Here's the algorithm that I've used for this kind of problem before. It was described in Ray Tracing News.
1) Make a third vector perpendicular to the other two to build an orthogonal basis:
cross_vector = unit( cross( orig_vector, rand_vector ) )
2) Pick two uniform random numbers in [0,1]:
s = rand( 0, 1 )
r = rand( 0, 1 )
3) Let h be the cosine of the cone's angle:
h = cos( theta )
4) Modify uniform sampling on a sphere to pick a random vector in the cone around +Z:
phi = 2 * pi * s
z = h + ( 1 - h ) * r
sinT = sqrt( 1 - z * z )
x = cos( phi ) * sinT
y = sin( phi ) * sinT
5) Change of basis to reorient it around the original angle:
perturbed = rand_vector * x + cross_vector * y + orig_vector * z
If you have another vector to represent an axis of rotation, there are libraries that will take the axis and the angle and give you a rotation matrix, which can then be multiplied by your starting vector to get the result you want.
However, the axis of rotation should be at right angles to your starting vector, to get the amount of rotation you expect. If the axis of rotation does not lie in the plane perpendicular to your vector, the result will be somewhat different than theta.
That being said, if you already have a vector at right angles to the one you want to perturb, and you're not picky about the direction of the perturbation, you can just as easily take a linear combination of your starting vector with the perpendicular one, adjust for magnitude as needed.
I.e., if P and Q are vectors having identical magnitude, and are perpendicular, and you want to rotate P in the direction of Q, then the vector R given by R = [Pcos(theta)+Qsin(theta)] will satisfy the constraints you've given. If P and Q have differing magnitude, then there will be some scaling involved.
You may be interested in 3D-coordinate transformations to change your vector angle.
I don't know how many directions you want to change your angle in, but transforming your Cartesian coordinates to spherical coordinates should allow you to make your angle change as you like.
Actually, it is very easy to do that. All you have to do is multiply your vector by the correct rotation matrix. The resulting vector will be your rotated vector. Now, how do you obtain such rotation matrix? That depends on the 3d framework/engine you are using. Any 3d framework must provide functions for obtaining rotation matrices, normally as static methods of the Matrix class.
Good luck.
Like said in other comments you can rotate your vector using a rotation matrix.
The rotation matrix has two angles you rotate your vector around. You can pick them with a random number generator, but just picking two from a flat generator is not correct. To ensure that your rotation vector is generated flat, you have to pick one random angle φ from a flat generator and the other one from a generator flat in cosθ ;this ensures that your solid angle element dcos(θ)dφ is defined correctly (φ and θ defined as usual for spherical coordinates).
Example: picking a random direction with no restriction on range, random() generates flat in [0,1]
angle1 = acos(random())
angle2 = 2*pi*random()
My code in unity - tested and working:
/*
* this is used to perturb given vector 'direction' by changing it by angle not more than 'angle' vector from
* base direction. Used to provide errors for player playing algorithms
*
*/
Vector3 perturbDirection( Vector3 direction, float angle ) {
// division by zero protection
if( Mathf.Approximately( direction.z, 0f )) {
direction.z = 0.0001f;
}
// 1 get some orthogonal vector to direction ( solve direction and orthogonal dot product = 0, assume x = 1, y = 1, then z = as below ))
Vector3 orthogonal = new Vector3( 1f, 1f, - ( direction.x + direction.y ) / direction.z );
// 2 get random vector from circle on flat orthogonal to direction vector. get full range to assume all cone space randomization (-180, 180 )
float orthoAngle = UnityEngine.Random.Range( -180f, 180f );
Quaternion rotateTowardsDirection = Quaternion.AngleAxis( orthoAngle, direction );
Vector3 randomOrtho = rotateTowardsDirection * orthogonal;
// 3 rotate direction towards random orthogonal vector by vector from our available range
float perturbAngle = UnityEngine.Random.Range( 0f, angle ); // range from (0, angle), full cone cover guarantees previous (-180,180) range
Quaternion rotateDirection = Quaternion.AngleAxis( perturbAngle, randomOrtho );
Vector3 perturbedDirection = rotateDirection * direction;
return perturbedDirection;
}
Let's say I have two points in 3D space (a and b) and a fixed axis/unit vector called n.
I want to create a rotation matrix that minimizes the euclidan distance between point a (unrotated) and the rotated point b.
E.g:
Q := matrix_from_axis_and_angle (n, alpha);
find the unknown alpha that minimizes sqrt(|a - b*Q|)
Btw - If a solution/algorithm can be easier expressed with unit-quaternions go ahead and use them. I just used matrices to formulate my question because they're more widely used.
Oh - I know there are some degenerated cases ( a or b lying exactly in line with n ect.) These can be ignored. I'm just looking for the case where a single solution can be calculated.
sounds fairly easy. Assume unit vector n implies rotation around a line parallel to n through point x0. If x0 != the origin, translate the coordinate system by -x0 to get points a' and b' relative to new coordinate system origin 0, and use those 2 points instead of a and b.
1) calculate vector ry = n x a
2) calculate unit vector uy = unit vector in direction ry
3) calculate unit vector ux = uy x n
You now have a triplet of mutually perpendicular unit vectors ux, uy, and n, which form a right-handed coordinate system. It can be shown that:
a = dot(a,n) * n + dot(a,ux) * ux
This is because unit vector uy is parallel to ry which is perpendicular to both a and n. (from step 1)
4) Calculate components of b along unit vectors ux, uy. a's components are (ax,0) where ax = dot(a,ux). b's components are (bx,by) where bx = dot(b,ux), by = dot(b,uy). Because of the right-handed coordinate system, ax is always positive so you don't actually need to calculate it.
5) Calculate theta = atan2(by, bx).
Your rotation matrix is the one which rotates by angle -theta relative to coordinate system (ux,uy,n) around the n-axis.
This yields degenerate answers if a is parallel to n (steps 1 and 2) or if b is parallel to n (steps 4, 5).
I think you can rephrase the question to:
what is the distance from a point to a 2d circle in 3d space.
the answer can be found here
so the steps needed are as following:
rotating the point b around a vector n gives you a 2d circle in 3d space
using the above, find the distance to that circle (and the point on the circle)
the point on the circle is the rotated point b you are looking for.
deduce the rotated angle
...or something ;^)
The distance will be minimized when the vector from a to the line along n lines up with the vector from b to the line along n.
Project a and b into the plane perpendicular to n and solve the problem in 2 dimensions. The rotation you get there is the rotation you need to minimize the distance.
Let P be the plane that is perpendicular to n.
We can find the projection of a into the P-plane, (and similarly for b):
a' = a - (dot(a,n)) n
b' = b - (dot(b,n)) n
where dot(a,n) is the dot-product of a and n
a' and b' lie in the P-plane.
We've now reduced the problem to 2 dimensions. Yay!
The angle (of rotation) between a' and b' equals the angle (of rotation) needed to swing b around the n-axis so as to be closest to a. (Think about the shadows b would cast on the P-plane).
The angle between a' and b' is easy to find:
dot(a',b') = |a'| * |b'| * cos(theta)
Solve for theta.
Now you can find the rotation matrix given theta and n here:
http://en.wikipedia.org/wiki/Rotation_matrix
Jason S rightly points out that once you know theta, you must still decide to rotate b clockwise or counterclockwise about the n-axis.
The quantity, dot((a x b),n), will be a positive quantity if (a x b) lies in the same direction as n, and negative if (a x b) lies in the opposite direction. (It is never zero as long as neither a nor b is collinear with n.)
If (a x b) lies in the same direction as n, then b has to be rotated clockwise by the angle theta about the n-axis.
If (a x b) lies in the opposite direction, then b has to be rotated clockwise by the angle -theta about the n-axis.