Opengl normal to vectors - math

I have quite a lot of triangles with coordinates such as below. I want to get the normals of each vertex so I can use it for calculating light.
I have the code for a cube normals and understand that but don't really know how to go about converting(calculating) these to normals. I would just like some direction on where to go from here.
//TRIANGLE 1
0.0f, -0.774f, 0.49f, //6
0.0f, -1.0f, 0.51f, //7
0.156f, -0.982f, 0.47f, //8

Calculating normals can be done using the Vector Cross Product. You take two vectors, and the cross product gives you a normal vector.
The two vectors can be obtained by taking the coordinates of your triangle, and subtracting one vertex coordinate from the other two vertices.
That is:
vec0 = vert2 - vert0
vec1 = vert1 - vert0
Which vertices you should subtract from one another depends on which direction the normal should point.
See the wikipedia article on how to compute the cross product. At the bottom of the section you'll see a matrix which shows how to calculate each component of the normal vector.

Related

OpenGL : equation of the line going through a point defined by a 4x4 matrix ? (camera for example)

I would like to know what is the set of 3 equations (in the world coordinates) of the line going through my camera (perpendicular to the camera screen). The position and rotation of my camera in the world coordinates being defined by a 4x4 matrix.
Any idea?
parametric line is simple just extract the Z axis direction vector and origin point O from the direct camera matrix (see the link below on how to do it). Then any point P on your line is defined as:
P(t) = O + t*Z
where t is your parameter. The camera view direction is usually -Z for OpenGL perspective in such case:
t = (-inf,0>
Depending on your projection you might want to use:
t = <-z_far,-z_near>
The problem is there are many combinations of conventions. So you need to know if you have row major or column major order of your matrix (so you know if the direction vectors and origins are in rows or columns). Also camera matrix in gfx is usually inverse one so you need to invert it first. For more info about this see:
Understanding 4x4 homogenous transform matrices

Normal Mapping on procedural sphere

I am a student in video games, and we are working on a raytracer in C++. We are using our teachers' library.
We create procedural objects (in our case a sphere), the Camera sends a ray for each pixel of the screen and the ray send back information on what it hit.
Some of us decided to integrate Normal Maps. So, at first, we sent ray on the object, looked at the value of the Normal map texel where we hit the sphere, converted it in a vector, normalized it and sent it back in place of the normal of the object. The result was pretty good, but of course, it didn't take the orientation of the "face" (it's procedural, so there is no face, but it gives the idea) into account anymore, so the render was flat.
We still don't really know how to "blend" the normal of the texture (in tangent space) and the normal of the object together. Here is our code:
// TGfxVec3 is part of our teachers library, and is a 3d vector like this:
// TGfxVec3( 12.7f, -13.4f, 52.0f )
// The sphere being at the origin and of radius 1, and tHit.m_tPosition being the
// exact position at the surface of the sphere where the ray hit, the normal of this
// point is the position hit by the ray.
TGfxVec3 tNormal = tHit.m_tPosition;
TGfxVec3 tTangent = Vec3CrossProduct( tNormal , m_tAxisZ );
TGfxVec3 tBiNormal = Vec3CrossProduct( tNormal , tTangent );
TGfxVec3 tTextureNorm = 2*(TGfxVec3( pNorm[0], pNorm[1], pNorm[2] )/255)-TGfxVec3( -1.0f, -1.0f, -1.0f );
// pNorm[0], pNorm[1], pNorm[2] are respectively the channels Red, Green,
// and Blue of the Normal Map texture.
// We put them in a 3D vector, divid them by 255 so their value go from 0 to 1,
// multiply them by 2, and then substract a vector, so their rang goes from -1 to +1.
tHit.m_tNorm = TGfxVec3( tTangente.x*tTextNorm.x + tCoTangente.x*tTextNorm.x +
tNorm.x*tTextNorm.x, tTangente.y*tTextNorm.y + tCoTangente.y*tTextNorm.y +
tNorm.y*tTextNorm.y, tTangente.z*tTextNorm.z + tCoTangente.z*tTextNorm.z +
tNorm.z*tTextNorm.z ).Normalize();
// Here, after some research, I came across this : http://www.txutxi.com/?p=316 ,
// that allow us to convert the normal map tangent space to the object space.
The results are still not good. My main concern are the Tangent and Binormals. The Axis taken in reference (here: m_tAxisZ, the Z Axis of the Sphere), is not right. But I don't know what to take, or even if what I am doing is really good. So I came here for help.
So, we finally did it. :D Ok, I will try to be clear. For this, two images :
(1) : http://i.imgur.com/cHwrR9A.png
(2) : http://i.imgur.com/mGPH1RW.png
(My drawing skill has no equal, I know).
So, the main problem was to find the Tangent "T" and the Bi-tangent "B". We already have the Normal "N". Our circle always being at the origin with a radius of 1, a point on its surface is equal to the Normal to that point (black and red vector on the first image). So, we have to find the tangent to that point (in green). For this, we just have to rotate the vector from PI/2 rad :
With N( x, y ) :
T = ( -N.y , N.x )
However, we are in 3D. So the point will not always be at the equator. We can easily solve this problem by ignoring the position in Y of our point and normalize the vector with only the two other component. So, on the second image, we have P (we set its Y value to 0), and we normalize the new vector to get P'.
With P( x, y, z ) :
P' = ( P.x, 0, P.z).Normalize();
Then, we go back to my first message to find the T. Finally, we get the B with a cross product between the N en the T. Finally, we calculate the normal to that point by taking the normal map into account.
With the variable "Map" containing the three channels (RGB) of the normal Map, each one clamped from -1 to 1, and T, N and B all being 3D vectors :
( Map.R*T + Map.G*B + Map.B*N ).Normalize();
And that's it, you have the normal to the point taking your normal map into account. :) Hope this will be usefull for others.
You are mostly right and completely wrong at the same time.
Tangent space normal mapping use a transformation matrix to convert the tangent space normal from the texture to another space, like object or world space, or transform the light in the tangent space to compute the lighting with everything in the same space.
Bi-normal is a common mistake and should be named bi-tangent.
It is sometime possible to compute the TBN at the fly on simple geometry, like on a height-map as it is easy to deduce the tangent and the bi-tangent on a regular grid. But on a sphere, the cross trick with a fixed axis will result to a singularity at the pole where the cross product give a zero length vector.
Last, even if we ignore the pole singularity, the TBN must be normalized before you apply the matrix to the tangent space normal. You may also miss a transpose, as a 3x3 orthonormal matrix inverse is the transpose, and what you need is the inverse of the original TBN matrix if you go from tangent to object.
Because of all this, we most often store the TBN as extra information in the geometry, computed from the texture coordinate ( the url you referenced link to that computation description ) and interpolate at runtime with the other values.
Rem : there is a rough simplification to use the geometry nornal as the TBN normal but there is no reason in the first place that they match.

In a TBN Matrix are the normal, tangent, and bitangent vectors always perpendicular?

This is related to a problem described in another question (images there):
Opengl shader problems - weird light reflection artifacts
I have a .obj importer that creates a data structure and calculates the tangents and bitangents. Here is the data for the first triangle in my object:
My understanding of tangent space is that the normal points outward from the vertex, the tangent is perpendicular (orthogonal?) to the normal vector and points in the direction of positive S in the texture, and the bitangent is perpendicular to both. I'm not sure what you call it but I thought that these 3 vectors formed what would look like a rotated or transformed x,y,z axis. They wouldn't be 3 randomly oriented vectors, right?
Also my understanding: The normals in a normal map provide a new normal vector. But in tangent space texture maps there is no built in orientation between the rgb encoded normal and the per vertex normal. So you use a TBN matrix to bridge the gap and get them in the same space (or get the lighting in the right space).
But then I saw the object data... My structure has 270 vertices and all of them have a 0 for the Tangent Y. Is that correct for tangent data? Are these tangents in like a vertex normal space or something? Or do they just look completely wrong? Or am I confused about how this works and my data is right?
To get closer to solving my problem in the other question I need to make sure my data is right and my understanding on how tangent space lighting math works.
The tangent and bitangent vectors point in the direction of the S and T components of the texture coordinate (U and V for people not used to OpenGL terms). So the tangent vector points along S and the bitangent points along T.
So yes, these do not have to be orthogonal to either the normal or each other. They follow the direction of the texture mapping. Indeed, that's their purpose: to allow you to transform normals from model space into the texture's space. They define a mapping from model space into the space of the texture.
The tangent and bitangent will only be orthogonal to each other if the S and T components at that vertex are orthogonal. That is, if the texture mapping has no sheering. And while most texture mapping algorithms will try to minimize sheering, they can't eliminate it. So if you want an accurate matrix, you need a non-orthogonal tangent and bitangent.

Intersection between two Arcs? (arc = distance between pair of angles)

I'm trying to find a way to calculate the intersection between two arcs.
I need to use this to determine how much of an Arc is visually on the right half of a circle, and how much on the left.
I though about creating an arc of the right half, and intersect that with the actual arc.
But it takes me wayyy to much time to solve this, so I thought about asking here - someone must have done it before.
Edit:
I'm sorry the previous illustration was provided when my head was too heavy after crunching angles. I'll try to explain again:
In this link you can see that I cut the arc in the middle to two halves, the right part of the Arc contains 135 degrees, and the left part has 90.
This Arc starts at -180 and ends at 45. (or starts at 180 and ends at 405 if normalized).
I have managed to create this code in order to calculate the amount of arc degrees contained in the right part, and in the left part:
f1 = (angle2>270.0f?270.0f:angle2) - (angle1<90.0f?90.0f:angle1);
if (f1 < 0.0f) f1 = 0.0f;
f2 = (angle2>640.0f?640.0f:angle2) - (angle1<450.0f?450.0f:angle1);
if (f2 < 0.0f) f2 = 0.0f;
f3 = (angle2>90.0f?90.0f:angle2) - angle1;
if (f3<0.0f) f3=0.0f;
f4 = (angle2>450.0f?450.0f:angle2) - (angle1<270.0f?270.0f:angle1);
if (f4<0.0f) f4=0.0f;
It works great after normalizing the angles to be non-negative, but starting below 360 of course.
Then f1 + f2 gives me the sum of the left half, and f3 + f4 gives me the sum of the right half.
It also does not consider a case when the arc is defined as more than 360, which may be an "error" case.
BUT, this seems like more of a "workaround", and not a correct mathematical solution.
I'm looking for a more elegant solution, which should be based on "intersection" between two arc (because math has no "sides", its not visual";
Thanks!!
I think this works, but I haven't tested it thoroughly. You have 2 arcs and each arc has a start angle and a stop angle. I'll work this in degrees measured clockwise from north, as you have done, but it will be just as easy to work in radians measured anti-clockwise from east as the mathematicians do.
First 'normalise' your arcs, that is, reduce all the angles in them to lie in [0,360), so take out multiples of 360deg and make all the angles +ve. Make sure that the stop angle of each arc lies to clockwise of the start angle.
Next, choose the start angle of one of your arcs, it doesn't matter which. Sort all the angles you have (4 of them) into numerical order. If any of the angles are numerically smaller than the start angle you have chosen, add 360deg to them.
Re-sort the angles into increasing numerical order. Your chosen start angle will be the first element in the new list. From the start angle you already chose, what is the next angle in the list ?
1) If it is the stop angle of the same arc then either there is no overlap or this arc is entirely contained within the other arc. Make a note and find the next angle. If the next angle is the start angle of the other arc there is no overlap and you can stop; if it is the stop angle of the other arc then the overlap contains the whole of the first arc. Stop
2) If it is the start angle of the other arc, then the overlap begins at that angle. Make a note of this angle. The next angle your sweep encounters has to be a stop angle and the overlap ends there. Stop.
3) If it is the stop angle of the other arc then the overlap comprises the angle between the start angle of the first arc and this angle. Stop.
This isn't particularly elegant and relies on ifs rather more than I generally like but it should work and be relatively easy to translate into your favourite programming language.
And look, no trigonometry at all !
EDIT
Here's a more 'mathematical' approach since you seem to feel the need.
For an angle theta in (-pi,pi] the hyperbolic sine function (often called sinh) maps the angle to an interval on the real line in the interval (approximately) (-11.5,11.5]. Unlike arcsin and arccos the inverse of this function is also single-valued on the same interval. Follow these steps:
1) If an arc includes 0 break it into 2 arcs, (start,0) and (0,stop). You now have 2, 3 or 4 intervals on the real line.
2) Compute the intersection of those intervals and transform back from linear measurement into angular measurement. You now have the intersection of the two arcs.
This test can be resumed with a one-line test. Even if a good answer is already posted, let me present mine.
Let assume that the first arc is A:(a0,a1) and the second arc is B:(b0,b1). I assume that the angle values are unique, i.e. in the range [0°,360°[, [0,2*pi[ or ]-pi,pi] (the range itself is not important, we will see why). I will take the range ]-pi,pi] as the range of all angles.
To explain in details the approach, I first design a test for interval intersection in R. Thus, we have here a1>=a0 and b1>=b0. Following the same notations for real intervals, I compute the following quantity:
S = (b0-a1)*(b1-a0)
If S>0, the two segments are not overlapping, else their intersection is not empty. It is indeed easy to see why this formula works. If S>0, we have two cases:
b0>a1 implies that b1>a0, so there is no intersection: a0=<a1<b0=<b1.
b1<a0 implies that b0<b1, so there is no intersection: b0=<b1<a0=<a1.
So we have a single mathematical expression which performs well in R.
Now I expand it over the circular domain ]-pi,pi]. The hypotheses a0<a1 and b0<b1 are not true anymore: for example, an arc can go from pi/2 to -pi/2, it is the left hemicircle.
So I compute the following quantity:
S = (b0-a1)*(b1-a0)*H(a1-a0)*H(b1-b0)
where H is the step function defined by H(x)=-1 if x<0 else H(x)=1
Again, if S>0, there is no intersection between the arcs A and B. There are 16 cases to explore, and I will not do this here ... but it is easy to make them on a sheet :).
Remark: The value of S is not important, just the signs of the terms. The beauty of this formula is that it is independant from the range you have taken. Also, you can rewrite it as a logical test:
T := (b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0)
where ^ is logical XOR
EDIT
Alas, there is an obvious failure case in this formula ... So I correct it here. I realize that htere is a case where the intersection of the two arcs can be two arcs, for example when -pi<a0<b1<b0<a1<pi.
The solution to correct this is to introduce a second test: if the sum of the angles is above 2*pi, the arcs intersect for sure.
So the formula turns out to be:
T := (a1+b1-a0-b0+2*pi*((b1<b0)+(a1<a0))<2*pi) | ((b0>a1)^(b1>a0)^(a1>=a0)^(b1>=b0))
Ok, it is way less elegant than the previous one, but it is now correct.

Is the binormal of a vertex the cross between its normal and tangent?

I'm trying to find out what a binormal is in the context of graphics programming but coming up short, I saw on a site that the binormal was being calculated as the cross product between the normal and tangent (i.e. cross(normal, tangent)), is this the correct way to calculate a binormal?
Just to point out that is TOTALLY not the definition of the binormal. Thats the definition of a Bi Tangent. A Binormal is something totally different relating to the "other" normal formed by a curved surface.
People need to learn not to re-iterate that mistake (Made by someone early on in the days of normal mapping).
According to mathworld, the binormal vector is defined as cross(tangent,normal) where tangent and normal are unit normal vectors.
Note that, strictly speaking, order matters when you take cross products. cross(tangent,normal) points in the opposite direction from cross(normal,tangent). That may or may not matter depending on your application. It really doesn't matter as long as your calculations are internally consistent.
Normal, tangent and binormal vectors form an orthonormal basis to represent tangent space.
Tangent space ( sometimes called texture space ) is used in per-pixel lighting with normal maps to simulate surface detail ( imagine a wall or a golf-ball ).
The tangent and binormal vectors represent the equivalent texture UVs i.e the vectors parallel to the surface normal.
So technically speaking - as they form an orthonormal basis then binormal = cross (tangent,normal ) however in practice, since binormals and tangents are generated from the UVs in the normal map and may be averaged over several vertices then they may not be strictly orthonormal.
For a couple of good articles on the subject read
http://www.3dkingdoms.com/weekly/weekly.php?a=37
and
http://www.blacksmith-studios.dk/projects/downloads/bumpmapping_using_cg.php
Actually, no, sometimes it isn't. In 3d graphics, at least.
If a texture was stretched, then it is possible that binormal will not be perpendicular to both normal and tangent (although it should be perpendicular).
Just use whatever your exporter has calculated. If the exporter provides both tangent and binormal, it is good. If there is only tangent, then calculate binormal as a perpendicular to tangent and normal.
Get a complex object with both tangent and binormal calculated, and compare lighting when you use binormal which was provided with the lighting that you get when binormal was calculated as cross-product. There will be a difference.
Anyway, I believe that a proper way is to get both tangent and binormal calculated in exporter, and just use what exporter has provided.
Yes the Binormal or Bitangent is the cross between the normal and the tangent of a vertex. If you have any 2 vectors out of these three you can calculate the other one.
For instance if you have a tangent and a binormal (or bitangent) you can calculate the normal.
Here is a sample that can create binormal and bitangents in GLSL having just the normal:
varying vec3 normal;
varying vec4 vpos;
varying vec3 T,B;
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
normal = normalize(gl_NormalMatrix*gl_Normal);
gl_Position =gl_ProjectionMatrix*gl_ModelViewMatrix*gl_Vertex;
vpos = gl_ProjectionMatrix*gl_ModelViewMatrix*gl_Vertex;
T = cross(normal,vec3(-1,0,0));
B = cross(T,normal);
}
While it might not get the desired restults sometimes it should get you where you want.

Resources