So I was reading over something on this page (http://gamedeveloperjourney.blogspot.com/2009/04/point-plane-collision-detection.html)
The author mentioned
d = - D3DXVec3Dot(&vP1, &vNormal);
where vP1 is a point on the plane and vNormal is the normal to the plane. I'm curious as to how this gets you the distance from the world origin since the result will always be 0. In addition, just to be clear (since I'm still kind of hazy on the d part of a plane equation), is d in a plane equation the distance from a line through the world origin to the plane's origin?
In the generic case the distance between a point p and a plane can be computed by
<p - p0, normal>
where <a, b> is the dot product operation
<a, b> = ax*bx + ay*by + az*bz
and where p0 is a point on the plane.
When n is of unity length the dot product between a vector and it is the (signed) length of the projection of the vector on the normal
The formula you are reporting is just the special case when the point p is the origin. In this case
distance = <origin - p0, normal> = - <p0, normal>
This equality is formally wrong because the dot product is about vectors, not points... but still holds numerically. Writing down the explicit formula you get that
(0 - p0.x)*n.x + (0 - p0.y)*n.y + (0 - p0.z)*n.z
is the same as
- (p0.x*n.x + p0.y*n.y + p0.z*n.z)
Indeed a nice way to store a plane is to save the normal n and the value of k = <p0, n> where p0 is any point on the plane (the value of k is independent on which point you choose of the plane).
The result is not always zero. The result will only be zero if the plane goes through the origin. (Here let's assume the plane doesn't go through the origin.)
Basically, you are given a line from the origin to some point on the plane. (I.e. you have a vector from the origin to vP1). The problem with this vector is that most likely it's slanted and going to some far away place on the plane rather than to the closest point on the plane. So, if you simply took the length of vP1 you will get a distance that is too big.
What you need to do is get the projection of vP1 onto some vector that you know is perpendicular to the plane. That of course is vNormal. So take the dot product of vP1 and vNormal, and divide by the length of vNormal and you have the answer. (If they are kind enough to give you a vNormal that already is magnitude one, then no need to divide.)
You can work this out with Lagrange multipliers:
You know that the closest point on the plane must be of the form:
c = p + v
Where c is the closest point and v is a vector along the plane (which is thus orthogonal to n, the normal). You are trying for find the c with the smallest norm (or norm squared). So you are trying to minimized dot(c,c) subject to v being orthogonal to n (thus dot(v,n) = 0).
Thus, set up Lagrangian:
L = dot(c,c) + lambda * ( dot(v,n) )
L = dot(p+v,p+v) + lambda * ( dot(v,n) )
L = dot(p,p) + 2*dot(p,v) + dot(v,v) * lambda * ( dot(v,n) )
And take the derivative with respect to v (and set to 0) to get:
2 * p + 2 * v + lambda * n = 0
You can solve for lambda by in the equation above by dot producting both sides by n to get
2 * dot(p,n) + 2 * dot(v,n) + lambda * dot(n,n) = 0
2 * dot(p,n) + lambda = 0
lambda = - 2 * dot(p,n)
Note again that dot(n,n) = 1 and dot(v,n) = 0 (since v is in the plane and n is orthogonal to it). Then subtitute lambda back in to get:
2 * p + 2 * v - 2 * dot(p,n) * n = 0
and solve for v to get:
v = dot(p,n) * n - p
Then plug this back into c = p + v to get:
c = dot(p,n) * n
The length of this vector is |dot(p,n)| and the sign tells you whether the point is in the direction of the normal vector from the origin, or the reverse direction from the origin.
Related
I have a line AB. I would like to draw a line BC, perpendicular to AB. I know xyz of the points A and B, I also know the distance N between B and C. How can I find an arbitrary point C which fits into the given parameters? The calculations should be done in 3-D. Any point, perpendicular to AB can be the point C, if its distance to B equals N.
An almost identical question is given here, but I would like to know how the same thing is done in 3-D: How do you find a point at a given perpendicular distance from a line?
The calculation that works for me in 2-D was given in the link above:
dx = A.x-B.x
dy = A.y-B.y
dist = sqrt(dx*dx + dy*dy)
dx /= dist
dy /= dist
C.x = B.x + N*dy
C.y = B.y - N*dx
I tried adding Z axis to it like this:
dz = A.z - B.z
dist = sqrt(dx*dx + dy*dy + dz*dz)
dz /=dist
C.z = .... at this point it becomes a mystery to me
If I put something like "C.z - N*dz" into C.z, the distance is accurate only in some rotation angles, I would like to know the correct solution. I can imagine that in 3-D it is calculated in a completely different manner.
Clarification
Point C is not unique. It can be any point on a circle with its
centre at B and radius N. The circle is perpendicular to AB
If the desired point C can be any of the infinitely-many points fitting your requirements, here is one method.
Choose any vector that is not parallel or anti-parallel to vector AB. You could try the vector (1, 0, 0), and if that is parallel you could use (0, 1, 0) instead. Then take the cross-product of vector AB and the chosen vector. That cross-product is perpendicular to vector AB. Divide that cross-product by its length then multiply by the desired length N. Finally extend that vector from point B to find your desired point C.
Here is code in Python 3 that follows that algorithm. This code is somewhat non-pythonic to make it easier to convert to other languages. (If I really did this for myself I would use the numpy module to avoid coordinates completely and shorten this code.) But it does treat the points as tuples of 3 values: many languages will require you to handle each coordinate separately. Any real-life code would need to check for "near zero" rather than "zero" and to check that the sqrt calculation does not result in zero. I'll leave those additional steps to you. Ask if you have more questions.
from math import sqrt
def pt_at_given_distance_from_line_segment_and_endpoint(a, b, dist):
"""Return a point c such that line segment bc is perpendicular to
line segment ab and segment bc has length dist.
a and b are tuples of length 3, dist is a positive float.
"""
vec_ab = (b[0]-a[0], b[1]-a[1], b[2]-a[2])
# Find a vector not parallel or antiparallel to vector ab
if vec_ab[1] != 0 or vec_ab[2] != 0:
vec = (1, 0, 0)
else:
vec = (0, 1, 0)
# Find the cross product of the vectors
cross = (vec_ab[1] * vec[2] - vec_ab[2] * vec[1],
vec_ab[2] * vec[0] - vec_ab[0] * vec[2],
vec_ab[0] * vec[1] - vec_ab[1] * vec[0])
# Find the vector in the same direction with length dist
factor = dist / sqrt(cross[0]**2 + cross[1]**2 + cross[2]**2)
newvec = (factor * cross[0], factor * cross[1], factor * cross[2])
# Find point c such that vector bc is that vector
c = (b[0] + newvec[0], b[1] + newvec[1], b[2] + newvec[2])
# Done!
return c
The resulting output from the command
print(pt_at_given_distance_from_line_segment_and_endpoint((1, 2, 3), (4, 5, 6), 2))
is
(4.0, 6.414213562373095, 4.585786437626905)
I have a normalized direction vector (from a 3d position to a light position) and I would like this vector to be rotated by some angle so I can create a "cone".
Id like to simulate cone tracing by using the direction vector as the center of the cone and create an X number of samples to create more rays to sample from.
What I would like to know is basically the math behind:
https://docs.unrealengine.com/latest/INT/BlueprintAPI/Math/Random/RandomUnitVectorinCone/index.html
Which seems to do exactly what Im looking for.
1) Make arbitrary vector P, perpendicular to your direction vector D.
You can choose component with max magnitude, exchange it with middle-magnitude component, negate it, and make min magnitude component zero.
For example, if z- component is maximal and y-component is minimal, you may make such P:
D = (dx, dy, dz)
p = (-dz, 0, dx)
P = Normalize(p) //unit vector
2) Make vector Q perpendicular both D and P through vector product:
Q = D x P //unit vector
3) Generate random point in the PQ plane disk
RMax = Tan(Phi) //where Phi is cone angle
Theta = Random(0..2*Pi)
r = RMax * Sqrt(Random(0..1))
V = r * (P * Cos(Theta) + Q * Sin(Theta))
4) Normalize vector V
Note that distribution of vectors is slightly non-uniform on the sphere segment.(it is uniform on the plane disk). There are methods to generate uniform distribution on the sphere but some work needed to apply them to segment (my first attempt before edit was wrong).
Edit: Modification to make sphere-uniform distribution (not checked thoroughly)
RMax = Tan(Phi) //where Phi is cone angle
Theta = Random(0..2*Pi)
u = Random(Cos(Phi)..1)
r = RMax * Sqrt(1 - u^2)
V = r * (P * Cos(Theta) + Q * Sin(Theta))
The magnitude of the cross product describes the signed area of the parallelogram described by the two vectors (u, v) used to build the cross product, it has its uses. This same magnitude can be calculated as the magnitude of u times the magnitude of v times the sine of the angle between u and v:
||u||||v||sin(theta).
Now the dot product of u (normalized) and v (normalized) gives the cosine of the angle between u and v:
cos(theta)==dot(normalize(u), normalize(v))
I want to be able to get the signed sine value that is related to the cosine value. It is related because the sine and cosine waves are PI/2 out of sync. I know that the square root of 1 less the cosine value squared gives the unsigned sine value:
sin(theta)==sqrt(1 - (cos(theta) * cos(theta))
Where by cos(theta) I mean the dot product not the angle.
But the attendant sign calculation (+/-) requires theta as an angle:
(cos(theta + PI / 2)) > or == or < 0
If I have to perform an acos function I might as well just do the cross product and find the magnitude.
Is there a known ratio or step that can be added to a cosine value to get its related sine value?
For each possible cosine, both signs are possible for the sine if the corresponding angle is unrestricted.
If you know the angle is between [0,pi], then the sine must be positive or zero.
If you want to know the area of a parallelogram, always take the positive branch sin(x) = sqrt(1 - cos(x)^2). Negative area rarely makes sense (only to define orientation w.r.t. to a plane such as for backface culling)
If you have the two vectors, use a cross product or dot product directly, not the other one and convert.
Seems to me like a complicated way to get to atan2 identities:
d = 𝐚·𝐛 = |𝐚||𝐛|cosθ
c = |𝐚×𝐛| = |𝐚||𝐛|sinθ (with 0° < θ < 180°)
tanθ = 𝐚·𝐛 / |𝐚×𝐛|
θ = atan2(c·sgn(c|z), d) (= four quadrant)
where sgn(c|z) is the sign of the z-component in c (unless 𝐚 and 𝐛 both run exactly parallel with the xz or yz plane, then its the sign of the y-component and x-component, respectively).
Now, from basic trig identities,
r = √(x²+y²)
cos(atan2(y,x)) = x/r
sin(atan2(y,x)) = y/r
Therefore,
sinθ = c·sgn(c|z)/√(c²+d²)
cosθ = d/√(c²+d²)
I think I have found a solution.
cos(b) == sin(a)
v_parallel = dot(normalize(u), v) // the projection of v on u
v_perp = normalize(v) - v_parallel
cos(b) = dot(normalize(v), v_perp) // v_perp is already normalized
Therefore, the magnitude of
u cross v = magnitude(u) * magnitude(v) * cos(b)
I'm trying to generate some axis vectors from parameters commonly used to specify crystallographic unit cells. These parameters consist of the length of the three axes: a,b,c and the angles between them: alpha,beta,gamma. By convention alpha is the angle between the b and c axes, beta is between a and c, and gamma between a and b.
Now getting vector representations for the first two is easy. I can arbitrarily set the the a axis to the x axis, so a_axis = [a,0,0]. I then need to rotate b away from a by the angle gamma, so I can stay in the x-y plane to do so, and b_axis = [b*cos(gamma),b*sin(gamma),0].
The problem is the third vector. I can't figure out a nice clean way to determine it. I've figured out some different interpretations but none of them have panned out. One is imagining the there are two cones around the axes axis_a and axis_b whose sizes are specified by the angles alpha and beta. The intersection of these cones create two lines, the one in the positive z direction can be used as the direction for axis_c, of length c.
Does someone know how I should go about determining the axis_c?
Thanks.
The angle alpha between two vectors u,v of known length can be found from their inner (dot) product <u,v>:
cos(alpha) = <u,v>/(||u|| ||v||)
That is, the cosine of alpha is the inner product of the two vectors divided by the product of their lengths.
So the z-component of your third can be any nonzero value. Scaling any or all of the axis vectors after you get the angles right won't change the angles, so let's assume (say) Cz = 1.
Now the first two vectors might as well be A = (1,0,0) and B = (cos(gamma),sin(gamma),0). Both of these have length 1, so the two conditions to satisfy with choosing C are:
cos(alpha) = <B,C>/||C||
cos(beta) = <A,C>/||C||
Now we have only two unknowns, Cx and Cy, to solve for. To keep things simple I'm going to just refer to them as x and y, i.e. C = (x,y,1). Thus:
cos(alpha) = [cos(gamma)*x + sin(gamma)*y]/sqrt(x^2 + y^2 + 1)
cos(beta) = x/(sqrt(x^2 + y^2 + 1)
Dividing the first equation by the second (assuming beta not a right angle!), we get:
cos(alpha)/cos(beta) = cos(gamma) + sin(gamma)*(y/x)
which is a linear equation to solve for the ratio r = y/x. Once you have that, substituting y = rx in the second equation above and squaring gives a quadratic equation for x:
cos^2(beta)*((1+r^2)x^2 + 1) = x^2
cos^2(beta) = (1 - cos^2(beta)*(1 + r^2))x^2
x^2 = cos^2(beta)/[(1 - cos^2(beta)*(1 + r^2))]
By squaring the equation we introduced an artifact root, corresponding to choosing the sign of x. So check the solutions for x you get from this in the "original" second equation to make sure you get the right sign for cos(beta).
Added:
If beta is a right angle, things are simpler than the above. x = 0 is forced, and we have only to solve the first equation for y:
cos(alpha) = sin(gamma)*y/sqrt(y^2 + 1)
Squaring and multiplying away the denominator gives a quadratic for y, similar to what we did before. Remember to check your choice of a sign for y:
cos^2(alpha)*(y^2 + 1) = sin^2(gamma)*y^2
cos^2(alpha) = [sin^2(gamma) - cos^2(alpha)]*y^2
y^2 = cos^2(alpha)/[sin^2(gamma) - cos^2(alpha)]
Actually if one of the angles alpha, beta, gamma is a right angle, it might be best to label that angle gamma (between the first two vectors A,B) to simplify the computation.
Here is a way to find all Cx, Cy, Cz (first two are the same as in the other answer), given that A = (Ax,0,0), B = (Bx, By, 0), and assuming that |C| = 1
1) cos(beta) = AC/(|A||C|) = AxCx/|A| => Cx = |A|cos(beta)/Ax = cos(beta)
2) cos(alpha) = BC/(|B||C|) = (BxCx+ByCy)/|B| => Cy = (|B|cos(alpha)-Bx cos(beta))/By
3) To find Cz let O be the point at (0,0,0), T the point at (Cx,Cy,Cz), P be the projection of T on Oxy and Q be the projection of T on Ox. So P is the point at (Cx,Cy,0) and Q is the point at (Cx,0,0). Thus from the right angle triangle OQT we get
tan(beta) = |QT|/||OQ| = |QT|/Cx
and from the right triangle TPQ we get |TP|^2 + |PQ|^2 = |QT|^2. So
Cz = |TP| = sqrt(|QT|^2 - |PQ|^2) = sqrt( Cx^2 tan(beta)^2 - Cy^2 )
I'm not sure if this is correct but I might as well take a shot. Hopefully I won't get a billion down votes...
I'm too lazy to scale the vectors by the necessary amounts, so I'll assume they are all normalized to have a length of 1. You can make some simple modifications to the calculation to account for the varying sizes. Also, I'll use * to represent the dot product.
A = (1, 0, 0)
B = (cos(g), sin(g), 0)
C = (Cx, Cy, Cz)
A * C = cos(beta) //This is just a definition of the dot product. I'm assuming that the magnitudes are 1, so I can skip that portion, and you said that beta was the angle between A and C.
A * C = Cx //I did this by multiplying each corresponding value, and the Cy and Cz were ignored because they were being multiplied by 0
cos(beta) = Cx //Combine the previous two equations
B * C = cos(alpha)
B * C = Cx*cos(g) + Cy*sin(g) = cos(beta) * cos(g) + Cy*sin(g)
(cos(alpha) - cos(beta) * cos(g))/(sin(g)) = Cy
To be honest, I'm not sure how to get the z component of vector C, but I would expect it to be one more relatively easy step. If I can figure it out, I'll edit my post.
I have a 3D Plane defined by two 3D Vectors:
P = a Point which lies on the Plane
N = The Plane's surface Normal
And I want to calculate any vector that lies on the plane.
Take any vector, v, not parallel to N, its vector cross product with N ( w1 = v x N ) is a vector that is parallel to the plane.
You can also take w2 = v - N (v.N)/(N.N) which is the projection of v into plane.
A point in the plane can then be given by x = P + a w, In fact all points in the plane can be expressed as
x = P + a w2 + b ( w2 x N )
So long as the v from which w2 is "suitable".. cant remember the exact conditions and too lazy to work it out ;)
If you want to determine if a point lies in the plane rather than find a point in the plane, you can use
x.N = P.N
for all x in the plane.
If N = (xn, yn, zn) and P = (xp, yp, zp), then the plane's equation is given by:
(x-xp, y-yp, z-zp) * (xn, yn, zn) = 0
where (x, y, z) is any point of the plane and * denotes the inner product.
And I want to calculate any vector
that lies on the plane.
If I understand correctly You need to check if point belongs to the plane?
http://en.wikipedia.org/wiki/Plane_%28geometry%29
You mast check if this equation: nx(x − x0) + ny(y − y0) + nz(z − z0) = 0 is true for your point.
where: [nx,ny,nz] is normal vector,[x0,y0,z0] is given point, [x,y,z] is point you are checking.
//edit
Now I'm understand Your question. You need two linearly independent vectors that are the planes base. Sow You need to fallow Michael Anderson answerer but you must add second vector and use combination of that vectors. More: http://en.wikipedia.org/wiki/Basis_%28linear_algebra%29