I am trying to calculate the tangent line (needed for bump mapping) for every vertex in my mesh. The v1, v2 and v3 are the vertices in the triangle and the t1, t2 and t3 are the respective texture coords. From what i understand this should output the tangent line for the three vertices of the triangle.
Vec3f va = Vec3f{vertexData[a * 3 + 0], vertexData[a * 3 + 1], vertexData[a * 3 + 2]};
Vec3f vb = Vec3f{vertexData[b * 3 + 0], vertexData[b * 3 + 1], vertexData[b * 3 + 2]};
Vec3f vc = Vec3f{vertexData[c * 3 + 0], vertexData[c * 3 + 1], vertexData[c * 3 + 2]};
Vec2f ta = (Vec2f){texcoordData[a * 2 + 0],texcoordData[a * 2 + 1]};
Vec2f tb = (Vec2f){texcoordData[b * 2 + 0],texcoordData[b * 2 + 1]};
Vec2f tc = (Vec2f){texcoordData[c * 2 + 0],texcoordData[c * 2 + 1]};
Vec3f v1 = subtractVec3f(vb, va);
Vec3f v2 = subtractVec3f(vc, va);
Vec2f t1 = subtractVec2f(tb, ta);
Vec2f t2 = subtractVec2f(tc, ta);
float coef = 1/(t1.u * t2.v - t1.v * t2.u);
Vec3f tangent = Vec3fMake((t2.v * v1.x - t1.v * v2.x) * coef,
(t2.v * v1.y - t1.v * v2.y) * coef,
(t2.v * v1.z - t1.v * v2.z) * coef);
My problem is that the coef variable is sometimes the nan (not a number) value causing the multiplication to be off. My mesh is not super complex, a simple cylinder, but i would like a universal formula to calculate the tangent line to enable bump mapping on all of my meshes.
coef becomming a NaN indicates some numerical problem with your input data, like degenerate triangles or texture coordinates. Make sure that the expression (t1.u * t2.v - t1.v * t2.u) doesn't (nearly) vanish, i.e. its absolute value is larger than some reasonable threshold value.
A good sanity check is |vb-va|>0 ^ |vc-va|>0, |tb-ta|>0 ^ |tc-ta|>0, |normalized(vb-va) . normalized(vc-va)| < 1 and |normalized(tb-ta) . normalized(tc-ta)| < 1.
Related
I have a point on a half circle that needs a line connecting it to the black half circle. The line goes through the origin of the orange circle (perpendicular). When moving along the upper circle, the length of the line changes. Is there a way to calculate a position for the arrow, so the green line has a length of a given value? None of the circles are necessarily at the origin.
No need to check if the green line does intersect the black circle, I already made sure that's the case.
For the length s of the line from the orange centre to the black circle you get the formula:
s^2 = (x + r * cos(a))^2 + (y + r * sin(a))^2
where x is the absolute value of the x-component of the centre of the black circle and y the corresponding y-component. r is the radius of the black circle. a is the angle of the intersection point on the black circle (normally there will be two solutions).
Expanding the given formula leads to:
s^2 = x * x + r * r * cos(a)^2 + 2* r * x * cos(a)
+ y * y + r * r * sin(a)^2 +2 *r * y * sin(a)
As
r * r * cos(a)^2 + r * r * sin(a)^2 = r * r
we have
s^2 - x^2 - y^2 - r^2 = 2 *r * (x * cos(a) + y * sin(a)) (1)
Dividing by 2*r and renaming the left side of the equation p (p contains known values only) results in
p = x * cos(a) + y * sin(a) = SQRT(x * x + y * y) * sin(a + atan(x / y))
==>
a = asin(p /SQRT(x*x + y*y)) + atan(x / y) (2)
Let's have an example with approximate values taken from your drawing:
x = 5
y = -8
r = 4
s = 12
Then (1) will be
144 = 25 + 16 + 64 + 8 * (5 * cos(a) - 8 * sin(a)) ==>
39 / 8 = 5 * cos(a) - 8 * sin(a) =
SQRT(25 + 64) * sin(a + atan(5 / -8)) ==>
0.5167 = sin(a + atan(5 / -8))
asin(0.5167) = a - 212°
asin(0.5167) has two values, the first one is 31.11°, the second one is 148.89°. This leads to the two solutions for a:
a1 = 243.11°
a2 = 360.89° or taking this value modulo 360° ==> 0.89°
I just found a much simpler solution using the Law of cosines:
c * c = a * a + b * b - 2ab * cos(gamma)
You got a triangle defined by three points: the centre points of both circles and the point of intersection on the black circle. The lengths of all three sides are known.
So we get:
cos(gamma) = (a * a + b * b - c * c) / 2ab
If we choose the angle at centre of orange circle to be gamma we get
a = sqrt(89) = 9.434 (distance between the centres of both circles)
b = 12 (distance between centre of orange circle and point if intersection
c = 4 (radius of black circle)
Using this values we get:
cos(gamma) = (89 + 144 - 16) / (2 * sqrt(89) * 12) = 0.9584
gamma = acos(0.9584) = +/- 16.581°
´
How would I find the maximum possible angle (a) which a rectangle of width (W) can be at within a slot of width (w) and depth (h) - see my crude drawing below
Considering w = hh + WW at the picture:
we can write equation
h * tan(a) + W / cos(a) = w
Then, using formulas for half-angles and t = tan(a/2) substitution
h * 2 * t / (1 - t^2) + W * (1 + t^2) / (1 - t^2) = w
h * 2 * t + W * (1 + t^2) = (1 - t^2) * w
t^2 * (W + w) + t * (2*h) + (W - w) = 0
We have quadratic equation, solve it for unknown t, then get critical angle as
a = 2 * atan(t)
Quick check: Python example for picture above gives correct angle value 18.3 degrees
import math
h = 2
W = 4.12
w = 5
t = (math.sqrt(h*h-W*W+w*w) - h) / (W + w)
a = math.degrees(2 * math.atan(t))
print(a)
Just to elaborate on the above answer as it is not necessarly obvious, this is why why you can write equation:
h * tan(a) + W / cos(a) = w
PS: I suppose that the justification for "why a is the maximum angle" is obvious
I'm trying to implement a simple water simulation, with theory from GPU Gems 1 chapter 1.
if you imagine a 3D plane (flat in the xz plane, with y denoting height at any point), the height field function is given as:
where:
Wavelength (w): the crest-to-crest distance between waves in world space.
Amplitude (A): the height from the water plane to the wave crest.
Speed (S): the distance the crest moves forward per second.
Direction (D): the horizontal vector perpendicular to the wave front along which the
crest travels.
This is straightforward to implement.
Please note the article in GPUGems uses the z direction for height, but this isn't standard for graphics (normally, x is width, y is height, z is depth). So I'll refer to the xz direction meaning the flat/horizontal plane directions.
So, having computed the height (y) value at any given point, I need to compute the bitangent and tangent vectors to that point, in order that I can compute a normal vector, which I need for lighting equations.
The bitangent and tangent vectors are partial derivatives in the x and z directions (y is the heightfield value).
So my question is, how can I take a partial derivative in the x and then the z directions for the height field function?
The article says that the partial derivative for the x direction is given by
I understand the concept of taking a partial derivative from this video:, but I don't know how to take the partial derivative of my heightfield function.
Can someone explain it (like I'm 5) - My grasp of maths isn't great!
You want to derive the following equation:
W(x) = A * sin(w * (D.x * x + D.y * z) + t * phi)
= A * sin(w * D.x * x + w * D.y * z + t * phi)
which is the above formula with the expanded dot product. Because we want to find the derivative with respect to x, all other variables (except x) are considered constant. So we can substitute the constants:
c1 = A
c2 = w * D.x
c3 = w * D.y * z + t * phi
W(x) = c1 * sin(c2 * x + c3)
The derivative is:
W'(x) = c1 * c2 * cos(c2 * x + c3)
Reverting the substitution we get:
W'(x) = A * w * D.x * cos(w * D.x * x + w * D.y * z + t * phi)
which describes the y-component of the tangent at a given position.
Similarly, the bitangent (derivative with respect to z) can be described by
W'(z) = A * w * D.y * cos(w * D.y * z + w * D.x * x + t * phi)
Therefore:
tangent = (1, W'(x), 0)
= (1, A * w * D.x * cos(w * D.x * x + w * D.y * z + t * phi), 0)
bitangent = (0, W'(z), 1)
= (0, A * w * D.y * cos(w * D.y * z + w * D.x * x + t * phi), 1)
I’ve written the below python script. The idea is to calculate the new location of point C after you rotate the globe from point A to point B. I first calculate point P, which is the rotation pole. With calculating point P already something goes wrong. With the following input f.e. I would assume point P to be having latitude 90 or –90.
I asked this question before here: Rotate a sphere from coord1 to coord2, where will coord3 be?
But I figured it's better to ask again with the script included ;)
# GreatCircle can be downloaded from: http://www.koders.com/python/fid0A930D7924AE856342437CA1F5A9A3EC0CAEACE2.aspx?s=coastline
from GreatCircle import *
from math import *
# Points A and B defining the rotation:
LonA = radians(0)
LatA = radians(1)
LonB = radians(45)
LatB = radians(1)
# Point C which will be translated:
LonC = radians(90)
LatC = radians(1)
# The following equation is described here: http://articles.adsabs.harvard.edu//full/1953Metic...1...39L/0000040.000.html
# It calculates the rotation pole at point P of the Great Circle defined by point A and B.
# According to http://www.tutorialspoint.com/python/number_atan2.htm
# atan2(x, y) = atan(y / x)
LonP = atan2(((sin(LonB) * tan(LatA)) - (sin(LonA) * tan(LatB))), ((cos(LonA) * tan(LatB)) - (cos(LonB) * tan(LatA))))
LatP = atan2(-tan(LatA),(cos(LonP - LonA)))
print degrees(LonP), degrees(LatP)
# The equations to calculate the translated point C location were found here: http://www.uwgb.edu/dutchs/mathalgo/sphere0.htm
# The Rotation Angle in radians:
gcAP = GreatCircle(1,1,degrees(LonA),degrees(LatA),degrees(LonP),degrees(LatP))
gcBP = GreatCircle(1,1,degrees(LonB),degrees(LatB),degrees(LonP),degrees(LatP))
RotAngle = abs(gcAP.azimuth12 - gcBP.azimuth12)
# The rotation pole P in Cartesian coordinates:
Px = cos(LatP) * cos(LonP)
Py = cos(LatP) * sin(LonP)
Pz = sin(LatP)
# Point C in Cartesian coordinates:
Cx = cos(radians(LatC)) * cos(radians(LonC))
Cy = cos(radians(LatC)) * sin(radians(LonC))
Cz = sin(radians(LatC))
# The translated point P in Cartesian coordinates:
NewCx = (Cx * cos(RotAngle)) + (1 - cos(RotAngle)) * (Px * Px * Cx + Px * Py * Cy + Px * Pz * Cz) + (Py * Cz - Pz * Cy) * sin(RotAngle)
NewCy = (Cy * cos(RotAngle)) + (1 - cos(RotAngle)) * (Py * Px * Cx + Py * Py * Cy + Py * Pz * Cz) + (Pz * Cx - Px * Cz) * sin(RotAngle)
NewCz = (Cz * cos(RotAngle)) + (1 - cos(RotAngle)) * (Pz * Px * Cx + Pz * Py * Cy + Pz * Pz * Cz) + (Px * Cy - Py * Cx) * sin(RotAngle)
# The following equation I got from http://rbrundritt.wordpress.com/2008/10/14/conversion-between-spherical-and-cartesian-coordinates-systems/
# The translated point P in lat/long:
Cr = sqrt((NewCx*NewCx) + (NewCy*NewCy) + (NewCz*NewCz))
NewCLat = degrees(asin(NewCz/Cr))
NewCLon = degrees(atan2(NewCy, NewCx))
# Output:
print str(NewCLon) + "," + str(NewCLat)
I have two points in space, L1 and L2 that defines two points on a line.
I have three points in space, P1, P2 and P3 that 3 points on a plane.
So given these inputs, at what point does the line intersect the plane?
Fx. the plane equation A*x+B*y+C*z+D=0 is:
A = p1.Y * (p2.Z - p3.Z) + p2.Y * (p3.Z - p1.Z) + p3.Y * (p1.Z - p2.Z)
B = p1.Z * (p2.X - p3.X) + p2.Z * (p3.X - p1.X) + p3.Z * (p1.X - p2.X)
C = p1.X * (p2.Y - p3.Y) + p2.X * (p3.Y - p1.Y) + p3.X * (p1.Y - p2.Y)
D = -(p1.X * (p2.Y * p3.Z - p3.Y * p2.Z) + p2.X * (p3.Y * p1.Z - p1.Y * p3.Z) + p3.X * (p1.Y * p2.Z - p2.Y * p1.Z))
But what about the rest?
The simplest (and very generalizable) way to solve this is to say that
L1 + x*(L2 - L1) = (P1 + y*(P2 - P1)) + (P1 + z*(P3 - P1))
which gives you 3 equations in 3 variables. Solve for x, y and z, and then substitute back into either of the original equations to get your answer. This can be generalized to do complex things like find the point that is the intersection of two planes in 4 dimensions.
For an alternate approach, the cross product N of (P2-P1) and (P3-P1) is a vector that is at right angles to the plane. This means that the plane can be defined as the set of points P such that the dot product of P and N is the dot product of P1 and N. Solving for x such that (L1 + x*(L2 - L1)) dot N is this constant gives you one equation in one variable that is easy to solve. If you're going to be intersecting a lot of lines with this plane, this approach is definitely worthwhile.
Written out explicitly this gives:
N = cross(P2-P1, P3 - P1)
Answer = L1 + (dot(N, P1 - L1) / dot(N, L2 - L1)) * (L2 - L1)
where
cross([x, y, z], [u, v, w]) = x*u + y*w + z*u - x*w - y*u - z*v
dot([x, y, z], [u, v, w]) = x*u + y*v + z*w
Note that that cross product trick only works in 3 dimensions, and only for your specific problem of a plane and a line.
This is how I ended up doing it in come code. Luckily one code library (XNA) had half of what I needed, and the rest was easy.
var lv = L2-L1;
var ray = new Microsoft.Xna.Framework.Ray(L1,lv);
var plane = new Microsoft.Xna.Framework.Plane(P1, P2, P3);
var t = ray.Intersects(plane); //Distance along line from L1
///Result:
var x = L1.X + t * lv.X;
var y = L1.Y + t * lv.Y;
var z = L1.Z + t * lv.Z;
Of course I would prefer having just the simple equations that takes place under the covers of XNA.