Ray-Sphere Intersection Derivation - math

I'm trying to write a function that returns true if a ray intersects a sphere and the code I'm referencing goes something like this:
// given Sphere and Ray as arguments
invert the Sphere matrix
make new Ray object
origin of this object = old Ray origin * inverted Sphere matrix
direction = old Ray direction * inverted Sphere matrix
a = |new direction| ^ 2
b = dot product of new origin and new direction
c = |new origin| ^ 2 - 1
det = b*b - a*c
if det > 0 there is an intersection
I'm stuck at understanding why we need to invert the Sphere matrix first and then multiply it to the Ray's origin and direction. Also I'm confused how to derive the quadratic equation variables a, b, and c and the end. I know I have to combine the parametric equations for a ray (p + td) and for a circle (x dot x - 1 = 0) but I can't figure out how to do so.

You need to invert the sphere matrix to have the ray in the sphere's coordinate frame, which, if the sphere is not scaled, is the same as simply setting new_origin = origin - sphere_center (and using the original direction)
The equation is formed from the formula:
|new_dir*t + new_origin|^2 = r^2 (presumably r is 1)
If you expand it, you get:
|new_dir|^2*t^2 + 2*(new_origin·new_dir)*t + |new_origin|^2-r^2 = 0

Related

Panning via normal vector and plane

I have got a camera and the direction it is looking at. Therefore I can create a plane out of this direction vector if I take it as a normal vector. So now I want to move my camera which should be on this plane along the plane. Everything's in 3D but I couldn't come up with an idea how to do so. How can I implement the navigational method of panning - so moving in this specific plane?
To pan your camera to the left and to the right you need to know not only lookAt direction, but also up direction for the camera. Then you can calculate cross product of lookAt and upAxis and this gives you direction to the right, negated vector gives you direction to the left.
Definition: A vector N that is orthogonal to every vector in a plane is called a normal vector to the plane.
An equation of the plane containing the point (x0, y0, z0) with normal vector N = (A, B, C), is A(x − x0) + B(y − y0) + C(z − z0) = 0.
Note: The equation of any plane can be expressed as Ax + By + Cz = D.
This is called the standard form of the equation of a plane. From the eqn you can get any other point you want on the plane.
Example: A plane passing through the point P = (1, 6, 4) and the normal vector, R = (2, - 3, - 1). Then the eqn is,
2(x-1) - 3(y-6) - (z-4) = 0
=> 2x - 3y - z = -20

Find a vector tangent to a circle

I need to move a point by vectors of fixed norm around a central circle.
So to do this, I need to calculate the circle tangent vector to apply to my point.
Here is a descriptive graph :
So I know p1 coordinates, circle radius and center, and the vector norm d. I need to find p2 (= finding the vector v orientation).
I put on the graph some ideas I got to find it : p1' is p1 projected on the circle. And t is the tangent vector to C in p1'.
That should be easy, but I'm too weak in maths to figure how to implement this. So I would like an idea of the implementation this (language agnostic is okay, javascript is cool).
Extra cool if you can also get me how to implement clockwise and counter clockwise movement with this.
Edit : Obtained this
let vx = cx - p1x,
vy = cy - p1y,
norm = Math.sqrt((vx * vx) + (vy * vy)),
p2x = p1x - (vy * d / norm),
p2y = p1y + (vx * d / norm);
But there is still a quirk : using this on time, the point is slowly getting away from the center of the circle, performing a spiral.
Obtain vector Center of circle - point P1. Let's call this vector
v1.
Tangent vector 't' is perpendicular to v1. If v1=(vx, vy) then
t=(-vy,vx) . Just swap values and a sign (I wrote -vy, it could also be -vx, but not both -vy,-vx).
Setting one direction or the order is just using t2= -t1= (vy, -vx), or (-vy, vx)
For movements you must use normalized (||v|| = 1) vectors.

3d orthogonal projection on a plane

I have a point in 3d P(x,y,z) and a plane of view Ax+By+Cz+d=0 . A point in plane is E.Now i want to project that 3d point to that plane and get 2d coordinates of the projected point relative to the point E.
P(x,y,z) = 3d point which i want to project on the plane.
Plane Ax + By + Cz + d = 0 , so normal n = (A,B,C)
E(ex,ey,ez) = A point in plane ( eye pos of camera )
What i am doing right now is to get nearest point in plane from point P.then i subtract that point to E.I suspect that this is right ???
please help me.Thanks.
The closest point is along the normal to the plane. So define a point Q that is offset from P along that normal.
Q = P - n*t
Then solve for t that puts Q in the plane:
dot(Q,n) + d = 0
dot(P-n*t,n) + d = 0
dot(P,n) - t*dot(n,n) = -d
t = (dot(P,n)+d)/dot(n,n)
Where dot((x1,y1,z1),(x2,y2,z2)) = x1*x2 + y1*y2 + z1*z2
You get a point on the plane as p0 = (0, 0, -d/C). I assume the normal has unit length.
The part of p in the same direction as n is dot(p-n0, n) * n + p0, so the projection is p - dot(p-p0,n)*n.
If you want some coordinates on the plane, you have to provide a basis/coordinate system. Eg two linear independent vectors which span the plane. The coordinates depend on these basis vectors.

Transform 3D points to 2D

I have a set of points (x1, x2,..xn) that lie on the plane define by Ax+ By+Cz+d=0.
I would like to find the transformation matrix to translate and rotate to XY plane. So, the new point coordinate will be x1'=(xnew, ynew,0).
A lot of answer give quaternion, dot or cross product matrix. I am not sure which one is the correct way.
Thank you
First of all, unless in your plane equation, d=0, there is no linear transformation you can apply. You need to instead perform an affine transformation.
One way to do this is to determine an angle and vector about which to rotate to make your pointset lie in a plane parallel to the XY plane (ie. the Z component of your transformed pointset to all have the same values). Then you simply drop the Z component.
For this, let V be the normalized plane normal for the plane containing your points. For convenience define from your plane equation above Ax+By+Cz+d=0:
V = (A, B, C)
V' = V / ||V|| = (A', B', C')
Z = (0, 0, 1)
where
A' = A / ||V||
B' = B / ||V||
C' = C / ||V||
||V|| = (A2+B2+C2)1/2
The angle will simply be:
θ = cos-1(Z∙V / ||V||)
= cos-1(Z∙V')
= cos-1(C')
The axis R about which to rotate is just the cross product of the normalized plane normal V' and Z. That is
R = V'×Z
= (B', -A', 0)
You can now use this angle / axis pair to build the quaternion rotation needed to rotate all of the points in your dataset to a plane parallel to the XY plane. Then, a I said earlier, just drop the Z component to perform an orthogonal projection onto the XY plane.
Update: antonakos makes a good point about normalizing the R before using an API taking axis / angle pairs.

How can I turn a ray-plane intersection point into barycentric coordinates?

My problem:
How can I take two 3D points and lock them to a single axis? For instance, so that both their z-axes are 0.
What I'm trying to do:
I have a set of 3D coordinates in a scene, representing a a box with a pyramid on it. I also have a camera, represented by another 3D coordinate. I subtract the camera coordinate from the scene coordinate and normalize it, returning a vector that points to the camera. I then do ray-plane intersection with a plane that is behind the camera point.
O + tD
Where O (origin) is the camera position, D is the direction from the scene point to the camera and t is time it takes for the ray to intersect the plane from the camera point.
If that doesn't make sense, here's a crude drawing:
I've searched far and wide, and as far as I can tell, this is called using a "pinhole camera".
The problem is not my camera rotation, I've eliminated that. The trouble is in translating the intersection point to barycentric (uv) coordinates.
The translation on the x-axis looks like this:
uaxis.x = -a_PlaneNormal.y;
uaxis.y = a_PlaneNormal.x;
uaxis.z = a_PlaneNormal.z;
point vaxis = uaxis.CopyCrossProduct(a_PlaneNormal);
point2d.x = intersection.DotProduct(uaxis);
point2d.y = intersection.DotProduct(vaxis);
return point2d;
While the translation on the z-axis looks like this:
uaxis.x = -a_PlaneNormal.z;
uaxis.y = a_PlaneNormal.y;
uaxis.z = a_PlaneNormal.x;
point vaxis = uaxis.CopyCrossProduct(a_PlaneNormal);
point2d.x = intersection.DotProduct(uaxis);
point2d.y = intersection.DotProduct(vaxis);
return point2d;
My question is: how can I turn a ray plane intersection point to barycentric coordinates on both the x and the z axis?
The usual formula for points (p) on a line, starting at (p0) with vector direction (v) is:
p = p0 + t*v
The criterion for a point (p) on a plane containing (p1) and with normal (n) is:
(p - p1).n = 0
So, plug&chug:
(p0 + t*v - p1).n = (p0-p1).n + t*(v.n) = 0
-> t = (p1-p0).n / v.n
-> p = p0 + ((p1-p0).n / v.n)*v
To check:
(p - p1).n = (p0-p1).n + ((p1-p0).n / v.n)*(v.n)
= (p0-p1).n + (p1-p0).n
= 0
If you want to fix the Z coordinate at a particular value, you need to choose a normal along the Z axis (which will define a plane parallel to XY plane).
Then, you have:
n = (0,0,1)
-> p = p0 + ((p1.z-p0.z)/v.z) * v
-> x and y offsets from p0 = ((p1.z-p0.z)/v.z) * (v.x,v.y)
Finally, if you're trying to build a virtual "camera" for 3D computer graphics, the standard way to do this kind of thing is homogeneous coordinates. Ultimately, working with homogeneous coordinates is simpler (and usually faster) than the kind of ad hoc 3D vector algebra I have written above.

Resources