I am trying to calculate the Tangent and Bitangent vectors for my terrain. I followed this tutorial to figure out how to calculate these 2 vectors and from what I understand, Tangent Bitangent and Normal vectors should all be orthogonal to each other right? I am checking that and it seems like I am doing something wrong since they are not orthogonal. Can someone please explain to me what I am doing wrong here? Here is my code.
for (int i = 0; i < indices.size(); i += 3) {
glm::vec3 v0 = vertices.at(indices.at(i)).position;
glm::vec3 v1 = vertices.at(indices.at(i + 1)).position;
glm::vec3 v2 = vertices.at(indices.at(i + 2)).position;
std::cout << "v0 " << glm::to_string(v0) << std::endl;
std::cout << "v1 " << glm::to_string(v1) << std::endl;
std::cout << "v2 " << glm::to_string(v2) << std::endl;
glm::vec2 uv0 = vertices.at(indices.at(i)).texcoord;
glm::vec2 uv1 = vertices.at(indices.at(i + 1)).texcoord;
glm::vec2 uv2 = vertices.at(indices.at(i + 2)).texcoord;
std::cout << "uv0 " << glm::to_string(uv0) << std::endl;
std::cout << "uv1 " << glm::to_string(uv1) << std::endl;
std::cout << "uv2 " << glm::to_string(uv2) << std::endl;
glm::vec3 deltaPos1 = v1 - v0;
glm::vec3 deltaPos2 = v2 - v0;
std::cout << "e1 " << glm::to_string(deltaPos1) << std::endl;
std::cout << "e2 " << glm::to_string(deltaPos2) << std::endl;
glm::vec2 deltaUV1 = uv1 - uv0;
glm::vec2 deltaUV2 = uv2 - uv0;
std::cout << "deltaUV1 " << glm::to_string(deltaUV1) << std::endl;
std::cout << "deltaUV2 " << glm::to_string(deltaUV2) << std::endl;
GLfloat r = (GLfloat) (1.f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x));
std::cout << "r is: " << r << std::endl;
glm::vec3 tangent = glm::normalize((deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r);
glm::vec3 bitangent = glm::normalize((deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r);
std::cout << "normal 1 " << glm::to_string(vertices.at(indices.at(0)).normal) << std::endl;
std::cout << "normal 2 " << glm::to_string(vertices.at(indices.at(1)).normal) << std::endl;
std::cout << "normal 3 " << glm::to_string(vertices.at(indices.at(2)).normal) << std::endl;
std::cout << "tangent " << glm::to_string(tangent) << std::endl;
std::cout << "bitangent " << glm::to_string(bitangent) << std::endl;
glm::vec3 normal1 = vertices.at(indices.at(i)).normal;
glm::vec3 normal2 = vertices.at(indices.at(i + 1)).normal;
glm::vec3 normal3 = vertices.at(indices.at(i + 2)).normal;
for (int j = 0; j < 3; j++) {
glm::vec3 norm;
if (j == 0) {
norm = normal1;
} else if (j == 1) {
norm = normal2;
} else {
norm = normal3;
}
GLfloat tangentDot = glm::dot(norm, tangent);
GLfloat bitangentDot = glm::dot(norm, bitangent);
if (tangentDot != 0 || bitangentDot != 0) {
std::cerr << "ERROR::Terrain::Tangent or bitangent were not orthogonal" << std::endl;
std::cerr << tangentDot << " " << bitangentDot << std::endl;
}
}
vertices.at(indices.at(i)).tangents = tangent;
vertices.at(indices.at(i)).bitangents = bitangent;
vertices.at(indices.at(i + 1)).tangents = tangent;
vertices.at(indices.at(i + 1)).bitangents = bitangent;
vertices.at(indices.at(i + 2)).tangents = tangent;
vertices.at(indices.at(i + 2)).bitangents = bitangent;
}
And here are the debug outputs that I get for the first iteration as an example.
v0 vec3(0.000000, 0.078430, 0.000000)
v1 vec3(0.000000, 0.078430, 3.137255)
v2 vec3(3.137255, 0.078430, 0.000000)
uv0 vec2(0.000000, 0.000000)
uv1 vec2(0.000000, 0.003922)
uv2 vec2(0.003922, 0.000000)
e1 vec3(0.000000, 0.000000, 3.137255)
e2 vec3(3.137255, 0.000000, 0.000000)
deltaUV1 vec2(0.000000, 0.003922)
deltaUV2 vec2(0.003922, 0.000000)
r is: -65025
normal 1 vec3(-0.039155, 0.998466, -0.039155)
normal 2 vec3(-0.039185, 0.999232, 0.000000)
normal 3 vec3(0.000000, 0.999232, -0.039185)
tangent vec3(1.000000, -0.000000, -0.000000)
bitangent vec3(-0.000000, -0.000000, 1.000000)
ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.0391549 -0.0391549
ERROR::Terrain::Tangent or bitangent were not orthogonal
-0.039185 0
ERROR::Terrain::Tangent or bitangent were not orthogonal
0 -0.039185
The dot product of Tangent and Normal is pretty small for the first iteration but it gets much bigger for some of them. Am I understanding the concept correctly? Do these 3 vectors have to be orthogonal? I checked the same dot product for vectors from imported meshes that I import with ASSIMP and they are all orthogonal.
-- Edit: Here is how I calculate my normals.
glm::vec3 Terrain::calculateNormal(int x, int z, unsigned char *textureData, int imageWidth, int imageHeight, int imageChannels) {
// TODO: Not optimal since we are calculating the same vertice height multiple times
// TODO: We also do the same calls above, maybe it will be smarter to just create a lookup table?
float heightL = getHeight(x - 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightR = getHeight(x + 1, z, textureData,imageWidth, imageHeight, imageChannels);
float heightD = getHeight(x, z - 1, textureData,imageWidth, imageHeight, imageChannels);
float heightU = getHeight(x, z + 1, textureData,imageWidth, imageHeight, imageChannels);
glm::vec3 normal = glm::vec3{heightL - heightR, 2.f, heightD - heightU};
normal = glm::normalize(normal);
return normal;
}
As pointed out in the comments, each of the vertices has it`s own normal and they may vary from one another. How would I handle the tangent and bitangent calculation in this case?
Related
I have a mid-term assignment in which we conduct 3 sets of unit tests with documentation etc for a program from our course. The program I chose is a physics simulation.
Within this program, there are two classes, Thing and World. I am able to independently create these objects. I tried adding the Thing object to the World object by creating a std::vector<Thing> things, and then creating a function to add the Thing to the vector of things. However, when I do that, it seems as though the World object creates its own copy of the Thing, because when I change the Things position, the version of the Thing in the things vector remains the same.
Please provide some guidance on the matter, I feel my problem might be with how I use pointers in this situation.
void testBoundaryBounce()
{
//Create the world
World world{10.0f, 10.0f, 1.0f};
//Thing, 2 units away from boundary
Thing thing{8.0f, 5.0f, 1.0f};
//Add thing to world (adding it the the things vector)
world.addThing(&thing);
//Apply force that should trigger bounce back to x = 7
thing.applyForce(1.0f, 0.0f);
//Updating thing so that movement takes effect
thing.update();
//Running world update to account for collisions, bounces etc
world.update();
std::cout << "thing x : " << thing.getX() << std::endl;
CPPUNIT_ASSERT(thing.getX() == 7);
}
Thing::Thing(float x, float y, float radius)
: x{x}, y{y}, dX{0}, dY{0}, radius{radius}
{
}
World::World(float width, float height, float gravity)
: width{width}, height{height}, gravity{gravity}
{
std::vector<Thing> things;
}
void World::addThing(Thing* thing)
{
float thingX = thing->getX();
float thingY = thing->getY();
float thingRad = thing->getRad();
std::cout << "Radius : " << thingRad << std::endl;
if (thingX + thingRad > width || thingX - thingRad <= 0 || thingY + thingRad >
height|| thingY - thingRad <= 0)
{
std::cout << "Thing is out of bounds or is too large" << std::endl;
}
else {
std::cout << "Thing is good" << std::endl;
things.push_back(*thing);
}
}
void World::update()
{
for (Thing& thing : things)
{
thing.update();
float thingX = thing.getX();
float thingY = thing.getY();
float thingRad = thing.getRad();
float worldGrav = this->gravity;
std::cout << "thing x: " << thingX << std::endl;
std::cout << "thing rad: " << thingRad << std::endl;
//World Boundary Bounces
if (thingX + thingRad >= width)
{
std::cout << "Bounce left" << std::endl;
thing.applyForce(-2.0f, 0.0f);
thing.update();
}
if (thingX + thingRad <= 0)
{
thing.applyForce(2.0f, 0.0f);
thing.update();
std::cout << "Bounce right" << std::endl;
}
if (thingY + thingRad >= height)
{
thing.applyForce(0.0f, -2.0f);
thing.update();
std::cout << "Bounce up" << std::endl;
}
if (thingY - thingRad <= 0)
{
thing.applyForce(0.0f, 2.0f);
thing.update();
std::cout << "Bounce down" << std::endl;
}
//Thing Collision Bounces
for (Thing& otherthing : things)
{
float thing2X = otherthing.getX();
float thing2Y = otherthing.getY();
float thing2Rad = otherthing.getRad();
if (thingX + thingRad == thing2X + thing2Rad && thingY + thingRad ==
thing2Y + thing2Rad)
{
thing.applyForce(-2.0f, -2.0f);
thing.update();
otherthing.applyForce(2.0f, 2.0f);
otherthing.update();
}
}
//Gravitational Pull
thing.applyForce(0.0f, worldGrav);
}
}
Its right in the definition of void push_back (const value_type& val);...
Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.
so when you call things.push_back(*thing);, you are adding a new element to the 'things' vector which is a copy of the value pointed to by the thing pointer.
You want to change your vector to hold pointers to Thing types instead:
std::vector<Thing *> things;
and add the pointers instead of copies:
things.push_back(thing);
Note you will later have to access fields via -> instead of ., or you can create a reference to it such as:
for (Thing* pt: things)
{
Thing& thing = *pt;
thing.update();
//etc...
Instead of constructing a Thing and copying it into world, you could have World construct the Things that it owns
void testBoundaryBounce()
{
//Create the world
World world{10.0f, 10.0f, 1.0f};
//Thing, 2 units away from boundary
Thing * thing = world.addThing(8.0f, 5.0f, 1.0f);
//Apply force that should trigger bounce back to x = 7
thing->applyForce(1.0f, 0.0f);
//Running world update to account for collisions, bounces etc
//Implies updating all the things
world.update();
std::cout << "thing x : " << thing.getX() << std::endl;
CPPUNIT_ASSERT(thing.getX() == 7);
}
Thing::Thing(float x, float y, float radius)
: x{x}, y{y}, dX{0}, dY{0}, radius{radius}
{
}
World::World(float width, float height, float gravity)
: width{width}, height{height}, gravity{gravity}
{
std::vector<Thing> things;
}
Thing * World::addThing(float x, float y, float radius)
{
std::cout << "Radius : " << radius << std::endl;
if ((x + radius > width) || (x - radius <= 0) || (y + radius >
height) || (y - radius <= 0))
{
std::cout << "Thing is out of bounds or is too large" << std::endl;
return nullptr;
}
else
{
std::cout << "Thing is good" << std::endl;
return &things.emplace_back(x, y, radius);
}
}
void World::update()
{
for (Thing& thing : things)
{
thing.update();
float thingX = thing.getX();
float thingY = thing.getY();
float thingRad = thing.getRad();
float worldGrav = this->gravity;
std::cout << "thing x: " << thingX << std::endl;
std::cout << "thing rad: " << thingRad << std::endl;
//World Boundary Bounces
if (thingX + thingRad >= width)
{
std::cout << "Bounce left" << std::endl;
thing.applyForce(-2.0f, 0.0f);
thing.update();
}
if (thingX + thingRad <= 0)
{
thing.applyForce(2.0f, 0.0f);
thing.update();
std::cout << "Bounce right" << std::endl;
}
if (thingY + thingRad >= height)
{
thing.applyForce(0.0f, -2.0f);
thing.update();
std::cout << "Bounce up" << std::endl;
}
if (thingY - thingRad <= 0)
{
thing.applyForce(0.0f, 2.0f);
thing.update();
std::cout << "Bounce down" << std::endl;
}
//Thing Collision Bounces
for (Thing& otherthing : things)
{
float thing2X = otherthing.getX();
float thing2Y = otherthing.getY();
float thing2Rad = otherthing.getRad();
if (thingX + thingRad == thing2X + thing2Rad && thingY + thingRad ==
thing2Y + thing2Rad)
{
thing.applyForce(-2.0f, -2.0f);
thing.update();
otherthing.applyForce(2.0f, 2.0f);
otherthing.update();
}
}
//Gravitational Pull
thing.applyForce(0.0f, worldGrav);
}
}
As an aside, everything bounces off of itself every update
I'm writing a static function that uses GLM's rotate() function to rotate a vector about an arbitrary axis.
I wrote a simple test to check my work, and I found that the rotations occur in the opposite direction than what I expected.
I rotate a unit vector (0,0,1) about the X axis (1,0,0) in steps of pi/4. I expected that since OpenGL (and GLM?) use a right-handed coordinate system, the rotations would occur in a counter-clockwise direction about the X axis. Instead, they're occurring in clockwise direction.
vec3& RotateVector(vec3& targetVector, float const& radians, vec3 const &axis)
{
mat4 rotation = glm::rotate(mat4(1.0f), radians, axis);
targetVector = (vec4(targetVector, 0.0f) * rotation).xyz();
return targetVector;
}
vec3 test(0, 0, 1);
cout << "test initial vals: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14f / 4.0f, vec3(1, 0, 0) );
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 /4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
RotateVector(test, 3.14 / 4.0f, vec3(1, 0, 0));
cout << "Rotated test: " << test.x << " " << test.y << " " << test.z << "\n";
When I run the code above, I get the following output:
test initial vals: 0 0 1
Rotated test: 0 0.706825 0.707388
Rotated test: 0 1 0.000796229
Rotated test: 0 0.707951 -0.706262
Rotated test: 0 0.00159246 -0.999999
The output shows that the rotation is moving clockwise about the X axis.
Why is that? I'd expect that OpenGL's right handed coordinate system would adhere to the right hand rule? Am I missing something, or am I just confused?
You're using the matrices transposed, and since rotation matrices are orthogonal matrices, this has the effect of using the inverse of those matrices: R^-1 = R^T.
glm mimics classic GL conventions with mat4 * vec4 multiplication order, where vec4 is a column vector.
When you write vec4 * mat4, vec4 is interpreted as row vector, and since (A*B)^T = B^T * A^T, you get the same result as transpose(mat4) * vec4.
I'm trying to create a minimal test case for another question about Box2d, but I am unable to cause the member functions of my custom drawer to be called:
#include <iostream>
#include "Box2D/Box2D.h"
class DebugDrawer : public b2Draw
{
public:
DebugDrawer() {
AppendFlags(b2Draw::e_shapeBit);
AppendFlags(b2Draw::e_jointBit);
AppendFlags(b2Draw::e_aabbBit);
AppendFlags(b2Draw::e_pairBit);
AppendFlags(b2Draw::e_centerOfMassBit);
}
void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color&)
{
for (int vertex = 0; vertex < vertexCount; ++vertex) {
b2Vec2 vec = vertices[vertex];
std::cout << "DrawPolygon" << "vertex" << vertex << "x" << vec.x << "y" << vec.y;
}
}
void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color&)
{
for (int vertex = 0; vertex < vertexCount; ++vertex) {
b2Vec2 vec = vertices[vertex];
std::cout << "DrawSolidPolygon" << "vertex" << vertex << "x" << vec.x << "y" << vec.y;
}
}
void DrawCircle(const b2Vec2& center, float32 radius, const b2Color&)
{
std::cout << "DrawCircle" << "x" << center.x << "y" << center.y << "radius" << radius;
}
void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2&, const b2Color&) {
std::cout << "DrawSolidCircle" << "x" << center.x << "y" << center.y << "radius" << radius;
}
void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color&) {
std::cout << "DrawSegment" << "p1.x" << p1.x << "p1.y" << p1.y << "p2.x" << p2.x << "p2.y" << p2.y;
}
void DrawTransform(const b2Transform& xf) {
std::cout << "DrawTransform" << "x" << xf.p.x << "y" << xf.p.y << "angle" << xf.q.GetAngle();
}
};
int main(int argc, char** argv)
{
b2World world(b2Vec2(0.0f, 0.0f));
DebugDrawer debugDrawer;
world.SetDebugDraw(&debugDrawer);
// body
b2BodyDef bd;
bd.type = b2_dynamicBody;
bd.position = b2Vec2(0, 0);
b2Body *body = world.CreateBody(&bd);
// shape
b2CircleShape shape;
shape.m_radius = 1.0f;
// fixture
b2FixtureDef fd;
fd.shape = &shape;
fd.density = 1.0f;
body->CreateFixture(&fd);
world.Step(1.0f / 120.0f, 8, 3);
return 0;
}
I've tried calling Step() several times, forcing bodies to stay awake, etc. What am I missing?
I think you explicitly need to call world.DrawDebugData().
Also, did you know you can call SetFlags(a | b | c); instead of AppendFlags(a); AppendFlags(b); AppendFlags(c);?
I am trying to learn 3d programming, and right now I am trying to understand how to use quaternions to rotate a vector around an axis.
As far as I understand, to rotate a vector v around an axis a, after converting both vectors to quaternions, we multiply v by a, then the product by the conjugate of a.
I want to rotate v(0,1,0) around a(1,0,0) by 90 degrees, and I should get a resulting vector v(0,0,1) (or 0,0,-1, depending on the direction of the rotation).
I am not getting the output I am expecting.
Here is the code:
int main()
{
//I want to rotate this vector about the x axis by PI/2 radians:
Quaternion v(0, 1, 0, 0);
v.normalize();
float angle = PI / 2.0f;
float cos = math::cos(angle / 2.0f);
float sin = math::sin(angle / 2.0f);
Quaternion q(1.0f*sin, 0.0f*sin, 0.0f*sin, cos);
std::cout << "q not normalized = " <<"\t"<< q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
q.normalize();
std::cout << "q normalized = " <<"\t\t"<< q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
std::cout << std::endl;
Quaternion r;
//I multiply the vector v by the quaternion v, then I multiply by the conjugate.
r = q * v;
//do I need to normalize here?
r = r * q.conjugate();
//and here?
//shouldn't the resulting vector be 0,0,1?
std::cout << "r not normalized = " << "\t" << r.x << " " << r.y << " " << r.z << " " << r.w << std::endl;
r.normalize();
std::cout << "r normalized = " << "\t\t" << r.x << " " << r.y << " " << r.z << " " << r.w << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
and here is the output:
q not normalized, which is same as q normalized:
x = 0.707107, y = 0, z = 0, w = 0.707107
r not normalized:
x = 0.707107, y = 0, z = 1, w = -2.12132
r normalized:
x = 0.288675, y = 0, z = 0.408248, w = -0.866025
what am I doing wrong?
did I even understand anything from this process?
Basically to rotate an vector along x axis (1,0,0) with angle 90 deg, use below method, this works for both Euler and quaternion
| 1 0 0 | | 0 | | 0 |
| 0 cos90 -sin90 | * | 1 | = | 0 |
| 0 sin90 cos90 | | 0 | | 1 |
Read about rotation matrices http://en.wikipedia.org/wiki/Rotation_matrix
I have the following function code:
D3DXVECTOR3 Mouse::GetClickDirection(D3DXMATRIX projMatrix, D3DXMATRIX viewMatrix, D3DXVECTOR3 cameraPosition)
{
POINT mousePoint;
GetCursorPos(&mousePoint);
ScreenToClient(hwnd, &mousePoint);
float x = ((mousePoint.x * 2.0f) / (float)backBufferWidth) - 1.0f;
float y = ((mousePoint.y * -2.0f) / (float)backBufferHeight) + 1.0f;
D3DXVECTOR3 mouseClip = D3DXVECTOR3(x, y, 1.0f);
D3DXMATRIX invViewMatrix;
D3DXMatrixInverse(&invViewMatrix, 0, &viewMatrix);
D3DXMATRIX invProjMatrix;
D3DXMatrixInverse(&invProjMatrix, 0, &projMatrix);
D3DXMATRIX inversedMatrix = invViewMatrix * invProjMatrix;
D3DXVECTOR3 mouseWorldSpace;
D3DXVec3TransformCoord(&mouseWorldSpace, &mouseClip, &inversedMatrix);
D3DXVECTOR3 direction = mouseWorldSpace - cameraPosition;
D3DXVec3Normalize(&direction, &direction);
system("CLS");
std::cout << "sX: " << x << std::endl;
std::cout << "sY: " << y << std::endl;
std::cout << "X: " << direction.x << std::endl;
std::cout << "Y: " << direction.y << std::endl;
std::cout << "Z: " << direction.z << std::endl;
return direction;
}
I'm trying to calculate and create a directional ray based on the x and y screen point that the user has clicked on in my DirectX 3D app. So far, the printed results seems to indicate that my calculations are wrong as the Z value is always around 0.9 and I have no idea why. What exactly am I doing wrong here? Please help. Thanks
I think your inverse matrix calculation is backwards.
D3DXMATRIX inversedMatrix = invProjMatrix * invViewMatrix;