How can I compute normal on the surface of a cylinder? - math

I am working on a ray tracer and I got around to adding cylinders to the scene. The point I am stuck at is finding the surface normal vector in the point the ray hits. I need this to be able to do the diffuse lighting. What I have at this point is the 3d point where the camera ray hits the cylinder and the actual cylinder which is defined with a point on the central axis, the vector representing the direction of the axis and the radius. So to sum up my question, how do I find the normal vector in a point having the cylinder hit point, the radius, a point on its axis and the direction vector of the axis?

The cylinder normal vector starts at the centerline of the cylinder at the same z-height of the point where the ray intersects the cylinder, ends at the radial point of intersection. Normalize it and you have your unit normal vector.
If the cylinder centerline is not along the global z-direction of the scene you'll have to transform to cylinder coordinates, calculate the normal vector, and transform that back to global coordinates.

There are three possible situations:
the hit_pt is on the TOP CAP of the cylinder:
if (length(hit_pt - cy.top_center) < cy.radius)
surface_normal = cy.ori;
the hit_pt is on the BOTTOM CAP of the cylinder:
if (length(hit_pt - cy.bottom_center) < cy.radius)
surface_normal = -1 * cy.ori;
the hit_pt is on the SIDE of the cylinder. We can use dot product to find the point 'pt' on the center line of the cylinder, so that the vector (hit_pt - pt) is orthogonal to the cylinder's orientation.
t = dot((hit_pt - cy.bottom_center), cy.ori); // cy.ori should be normalized and so has the length of 1.
pt = cy.bottom_center + t * cy.ori;
surface_normal = normalize(hit_pt - pt)));

Related

How to determine if point is inside skewed conical frustum

I'm trying to work out whether a point is inside an ellipsoid cone formed between a point and a circle in 3D space. The cone is ellipsoid because the point is not perpendicular to the centre of the circle. See diagram below:
So I know:
The position of the point forming the apex of the cone: x
The location of the centre of the circle: c
The radius of the circle: r
The locations of various points I want to determine if they are inside the cone: y, z
Here is a top view of the same diagram:
I do not care about the base of the cone - I want points contained within the cone stretched effectively to infinity.
I've found formulae for working out whether a point is within an ellipsoid cone given the major/minor axis, but having difficulty working out how to do it when the ellipsoid cone is formed from a circle at an angle.
Thanks for any help!
With a conic you could probably determine distance from the axis and a semi major and minor and compute it directly.
Harder is some arbitrary shape.
If the cone has the point in the Z Axis direction, and you know a point in XYZ... then you should be able to draw an ellipse at that particular Z level. Maybe draw it with 360 segments.
Once you have your point and your ellipse, then you can test ellipse segment to see if there is an intersection in X & Y.
Imaging a circle at 0,0,0 with radius 1. And a point at 0,0,0 there are 2Y intersections at +/- 90 degrees and 2 X intersections happening at 0 and 180
If the point is at 2,0,0 you still have 2 intersections in X but they are to the left, and you want one to the left and one to the right.
Zero intersections mean. That you are outside the hoop.
Repeat across the 360 segments and determine how to handle points "on a line" and how close "on" is.

Translation coordinates for a circle under a certain angle

I have 2 circles that collide in a certain collision point and under a certain collision angle which I calculate using this formula :
C1(x1,y1) C2(x2,y2)
and the angle between the line uniting their centre and the x axis is
X = arctg (|y2 - y1| / |x2 - x1|)
and what I want is to translate the circle on top under the same angle that collided with the other circle. I mean with the angle X and I don't know what translation coordinates should I give for a proper and a straight translation!
For what I think you mean, here's how to do it cleanly.
Think in vectors.
Suppose the centre of the bottom circle has coordinates (x1,y1), and the centre of the top circle has coordinates (x2,y2). Then define two vectors
support = (x1,y1)
direction = (x2,y2) - (x1,y1)
now, the line between the two centres is fully described by the parametric representation
line = support + k*direction
with k any value in (-inf,+inf). At the initial time, substituting k=1 in the equation above indeed give the coordinates of the top circle. On some later time t, the value of k will have increased, and substituting that new value of k in the equation will give the new coordinates of the centre of the top circle.
How much k increases at value t is equal to the speed of the circle, and I leave that entirely up to you :)
Doing it this way, you never need to mess around with any angles and/or coordinate transformations etc. It even works in 3D (provided you add in z-coordinates everywhere).

Calculate the rotation performed around a point

I have two points in 2D space, centred on origin (0,0). The first point represents the starting location and the second represents the end location. I need to calculate the angle of rotation between the two points, my problem being that the hypoteneuse from each point to (0,0) is not equal.
Could someone tell me how to work out the angle between the two points, bearing in mind that they could be anywhere relative to (0,0).
Many thanks,
Matt.
Let's say point 1 is (x1,y1) and point 2 is (x2,y2)
The tangent of the Angle from X axis to point 1, relative to (0,0) is y1/x1
The tangent of the Angle from X axis to point 2, relative to (0,0) is y2/x2
Take the arc tangent (is that the right term? Tan-1 on a calculator) to get the actual angle for each, then subtract to get the answer you're looking for
This is easily accomplished taking the arccosine of the normalized inner product of the two vectors. That is, given u = (ux, uy) and v = (vx, vy), the angle between the two is given by θ = acos(u·v/|u||v|), where u · v = uxvx + uyvy is the dot product of the two and the | | operator is the l2 normal given by |u| = sqrt(ux2 + uy2). This will result in the smallest rotation that can be applied to one of the vectors that will make them linear multiples of each other. Therefore, you may need to fiddle with the sign of θ to make sure you're going in the right direction if you have one you want to start from.

Calculate 3d Vector perpendicular to plane described by a Point and True North Heading

I have a Point on the surface of the earth which I am converting to a Vector from Earth Center.
I have a True North Heading in degrees describing the path the point will travel on the surface of the earth.
I need to calculate a Vector which is perpendicular to the plane created by the path of this point along the earths surface.
I have tried calculating an arbitrary point along the path using the method described here
and then taking the cross product of the two vectors however it does not seem to be quite accurate enough and seems like more overhead than is necessary.
This is related to my other post ray-polygon-intersection-point-on-the-surface-of-a-sphere.
I'm assuming you're trying to compute a vector lying in the plane of the path, not perpendicular to it (since you've already got one - namely the vector from the origin to your point).
You first need to compute vectors lying in that plane that point due north and due east. To do this, let's call P your point, O the origin, and N = (0, 0, R) is the point at the top of your sphere. Then
e = cross(N - P, P - O)
is a vector that points due east, and is tangent to the sphere because it's perpendicular to P - O, a radius of the sphere.
For similar reasons
n = cross(e, P - O)
will point due north, and will be tangent to the sphere.
Now normalize n and e, and you've got an orthonormal basis for the tangent space at your point. To find a vector in a direction theta (say, counterclockwise from the positive east axis, to simplify the math), just take a little of e and a little of n:
v = cos(theta) * e + sin(theta) * n
Here's my understanding of your problem:
You have a point on the Earth's surface, specified as latitude/longitude coordinates
The direction "true north" is the direction that a person at that point would travel to reach the (geographic) North Pole by the most direct possible route. That is, the "true north vector" is tangent to the Earth's surface at your chosen point and points directly north, parallel to a line of longitude.
The direction of the point's motion will be (initially) tangent to the Earth's surface at your chosen point.
You have an angle in degrees from true north which specifies the heading at which this point is going to move.
This angle is the angle between the "true north vector" and the direction of motion of the point.
You want to calculate a vector that is tangent to the Earth's surface at that point but perpendicular to the direction of motion of the point.
If I've understood all that correctly, you can do it as follows:
The "true north vector" at latitude lat, longitude lng is given by [-sin(lat) * cos(lng), -sin(lat) * sin(lng), cos(lat)]
A vector perpendicular to the "true north vector" which points along a line of latitude (to the east) is given by [-sin(lng), cos(lng), 0]
Since these two vectors identify the plane tangent to the Earth's surface, and the vector specifying the direction of motion of your point is also in that plane, your motion vector is a linear combination of the previous two: [
-(sin(lat) * cos(lng) * cos(th) + sin(lng) * sin(th))
-(sin(lat) * sin(lng) * cos(th) - cos(lng) * sin(th))
cos(lat) * cos(th)
] where th is your heading angle.
To find a vector perpendicular to that motion vector, you can just take the cross product of the radius vector (that is, the vector pointing from the center of the Earth to your point,[cos(lat) * cos(lng), cos(lat) * sin(lng), sin(lat)] with the motion vector. (That math would be messy, best to let the computer handle it)
You already have 2 vectors:
N = (0,0,1) points straight up from the origin.
P = (a,b,c) points from the origin to your point.
Calculate the unit vector to your point
U = P/|P|
Calculate a unit vector perpendicular to U and N
E = U X N
Calculate a unit vector perpendicular to U and E (this will be tangent to the sphere)
T = U X E
T could be pointing either North or South, so
if T.z < 0, multiply T by -1.
T now points due north, and is parallel to the plane tangent to the sphere at P.
You now have enough information to construct a rotation matrix (R), so you can rotate T around U. You can find how to make a matrix for rotation around any axis on wikipedia:
Using R, you can calculate a vector pointing in the direction of travel.
A = RT
A is the answer you are looking for.

Triangle mathematics for game development

I'm trying to make a triangle (isosceles triangle) to move around the screen and at the same time slightly rotate it when a user presses a directional key (like right or left).
I would like the nose (top point) of the triangle to lead the triangle at all times. (Like that old asteroids game).
My problem is with the maths behind this. At every X time interval, I want the triangle to move in "some direction", I need help finding this direction (x and y increments/decrements).
I can find the center point (Centroid) of the triangle, and I have the top most x an y points, so I have a line vector to work with, but not a clue as to "how" to work with it.
I think it has something to do with the old Sin and Cos methods and the amount (angle) that the triangle has been rotated, but I'm a bit rusty on that stuff.
Any help is greatly appreciated.
The arctangent (inverse tangent) of vy/vx, where vx and vy are the components of your (centroid->tip) vector, gives you the angle the vector is facing.
The classical arctangent gives you an angle normalized to -90° < r < +90° degrees, however, so you have to add or subtract 90 degrees from the result depending on the sign of the result and the sign of vx.
Luckily, your standard library should proive an atan2() function that takes vx and vy seperately as parameters, and returns you an angle between 0° and 360°, or -180° and +180° degrees. It will also deal with the special case where vx=0, which would result in a division by zero if you were not careful.
See http://www.arctangent.net/atan.html or just search for "arctangent".
Edit: I've used degrees in my post for clarity, but Java and many other languages/libraries work in radians where 180° = π.
You can also just add vx and vy to the triangle's points to make it move in the "forward" direction, but make sure that the vector is normalized (vx² + vy² = 1), else the speed will depend on your triangle's size.
#Mark:
I've tried writing a primer on vectors, coordinates, points and angles in this answer box twice, but changed my mind on both occasions because it would take too long and I'm sure there are many tutorials out there explaining stuff better than I ever can.
Your centroid and "tip" coordinates are not vectors; that is to say, there is nothing to be gained from thinking of them as vectors.
The vector you want, vForward = pTip - pCentroid, can be calculated by subtracting the coordinates of the "tip" corner from the centroid point. The atan2() of this vector, i.e. atan2(tipY-centY, tipX-centX), gives you the angle your triangle is "facing".
As for what it's relative to, it doesn't matter. Your library will probably use the convention that the increasing X axis (---> the right/east direction on presumably all the 2D graphs you've seen) is 0° or 0π. The increasing Y (top, north) direction will correspond to 90° or (1/2)π.
It seems to me that you need to store the rotation angle of the triangle and possibly it's current speed.
x' = x + speed * cos(angle)
y' = y + speed * sin(angle)
Note that angle is in radians, not degrees!
Radians = Degrees * RadiansInACircle / DegreesInACircle
RadiansInACircle = 2 * Pi
DegressInACircle = 360
For the locations of the vertices, each is located at a certain distance and angle from the center. Add the current rotation angle before doing this calculation. It's the same math as for figuring the movement.
Here's some more:
Vectors represent displacement. Displacement, translation, movement or whatever you want to call it, is meaningless without a starting point, that's why I referred to the "forward" vector above as "from the centroid," and that's why the "centroid vector," the vector with the x/y components of the centroid point doesn't make sense. Those components give you the displacement of the centroid point from the origin. In other words, pOrigin + vCentroid = pCentroid. If you start from the 0 point, then add a vector representing the centroid point's displacement, you get the centroid point.
Note that:
vector + vector = vector
(addition of two displacements gives you a third, different displacement)
point + vector = point
(moving/displacing a point gives you another point)
point + point = ???
(adding two points doesn't make sense; however:)
point - point = vector
(the difference of two points is the displacement between them)
Now, these displacements can be thought of in (at least) two different ways. The one you're already familiar with is the rectangular (x, y) system, where the two components of a vector represent the displacement in the x and y directions, respectively. However, you can also use polar coordinates, (r, Θ). Here, Θ represents the direction of the displacement (in angles relative to an arbitary zero angle) and r, the distance.
Take the (1, 1) vector, for example. It represents a movement one unit to the right and one unit upwards in the coordinate system we're all used to seeing. The polar equivalent of this vector would be (1.414, 45°); the same movement, but represented as a "displacement of 1.414 units in the 45°-angle direction. (Again, using a convenient polar coordinate system where the East direction is 0° and angles increase counter-clockwise.)
The relationship between polar and rectangular coordinates are:
Θ = atan2(y, x)
r = sqrt(x²+y²) (now do you see where the right triangle comes in?)
and conversely,
x = r * cos(Θ)
y = r * sin(Θ)
Now, since a line segment drawn from your triangle's centroid to the "tip" corner would represent the direction your triangle is "facing," if we were to obtain a vector parallel to that line (e.g. vForward = pTip - pCentroid), that vector's Θ-coordinate would correspond to the angle that your triangle is facing.
Take the (1, 1) vector again. If this was vForward, then that would have meant that your "tip" point's x and y coordinates were both 1 more than those of your centroid. Let's say the centroid is on (10, 10). That puts the "tip" corner over at (11, 11). (Remember, pTip = pCentroid + vForward by adding "+ pCentroid" to both sides of the previous equation.) Now in which direction is this triangle facing? 45°, right? That's the Θ-coordinate of our (1, 1) vector!
keep the centroid at the origin. use the vector from the centroid to the nose as the direction vector. http://en.wikipedia.org/wiki/Coordinate_rotation#Two_dimensions will rotate this vector. construct the other two points from this vector. translate the three points to where they are on the screen and draw.
double v; // velocity
double theta; // direction of travel (angle)
double dt; // time elapsed
// To compute increments
double dx = v*dt*cos(theta);
double dy = v*dt*sin(theta);
// To compute position of the top of the triangle
double size; // distance between centroid and top
double top_x = x + size*cos(theta);
double top_y = y + size*sin(theta);
I can see that I need to apply the common 2d rotation formulas to my triangle to get my result, Im just having a little bit of trouble with the relationships between the different components here.
aib, stated that:
The arctangent (inverse tangent) of
vy/vx, where vx and vy are the
components of your (centroid->tip)
vector, gives you the angle the vector
is facing.
Is vx and vy the x and y coords of the centriod or the tip? I think Im getting confused as to the terminology of a "vector" here. I was under the impression that a Vector was just a point in 2d (in this case) space that represented direction.
So in this case, how is the vector of the centroid->tip calculated? Is it just the centriod?
meyahoocomlorenpechtel stated:
It seems to me that you need to store
the rotation angle of the triangle and
possibly it's current speed.
What is the rotation angle relative to? The origin of the triangle, or the game window itself? Also, for future rotations, is the angle the angle from the last rotation or the original position of the triangle?
Thanks all for the help so far, I really appreciate it!
you will want the topmost vertex to be the centroid in order to achieve the desired effect.
First, I would start with the centroid rather than calculate it. You know the position of the centroid and the angle of rotation of the triangle, I would use this to calculate the locations of the verticies. (I apologize in advance for any syntax errors, I have just started to dabble in Java.)
//starting point
double tip_x = 10;
double tip_y = 10;
should be
double center_x = 10;
double center_y = 10;
//triangle details
int width = 6; //base
int height = 9;
should be an array of 3 angle, distance pairs.
angle = rotation_angle + vertex[1].angle;
dist = vertex[1].distance;
p1_x = center_x + math.cos(angle) * dist;
p1_y = center_y - math.sin(angle) * dist;
// and the same for the other two points
Note that I am subtracting the Y distance. You're being tripped up by the fact that screen space is inverted. In our minds Y increases as you go up--but screen coordinates don't work that way.
The math is a lot simpler if you track things as position and rotation angle rather than deriving the rotation angle.
Also, in your final piece of code you're modifying the location by the rotation angle. The result will be that your ship turns by the rotation angle every update cycle. I think the objective is something like Asteroids, not a cat chasing it's tail!

Resources