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;
Related
I am making a double pendulum simulator in Raylib and before I get into the deep physics behind how it works I wanted to finish creating the graphics for it.
So far I created a window, made a double pendulum, and can rotate the pendulums however I want, but as the last thing I need to do before working on the physics is trace its path and I went about it using textures using a RenderTexture2D variable.
However when doing so it does trace the path but only 1/4th of the entire window and I am not sure why.
Most likely it has to do with rltranslatef but I am not sure how to fix it. I have a pendulum.h & .cpp file but they are unrelated to making the graphics for this. Any help is appreciated.
pendulum.h:
#ifndef DOUBLE_PENDULUM_SIM_PENDULUM_H
#define DOUBLE_PENDULUM_SIM_PENDULUM_H
class pendulum {
public:
float pLength{};
float pMass{};
float x{};
float y{};
float pAngle{};
public:
[[nodiscard]] float getX() const ;
[[nodiscard]] float getY() const ;
[[nodiscard]] float getAngle() const ;
void setX(float length, float angle);
void setY(float length, float angle);
void setLength(float length);
void setMass(float mass);
void setAngle(float angle);
pendulum();
pendulum(float length, float mass, float angle) : pLength(length), pMass(mass), pAngle(angle) {}
~pendulum();
};
#endif //DOUBLE_PENDULUM_SIM_PENDULUM_H
pendulum.cpp:
#include "includes/pendulum.h"
#include <cmath>
#include <iostream>
#include <raylib.h>
void pendulum::setX(float length, float angle) {
x = length * sin(angle);
}
void pendulum::setY(float length, float angle) {
y = length * cos(angle);
}
float pendulum::getX() const {
return x;
}
float pendulum::getY() const {
return y;
}
void pendulum::setLength(float length) {
pLength = length;
}
void pendulum::setMass(float mass) {
pMass = mass;
}
float pendulum::getAngle() const {
return pAngle;
}
pendulum::~pendulum() {
std::cout << "\nPendulum destroyed" << std::endl;
}
void pendulum::setAngle(float angle) {
pAngle = angle * DEG2RAD;
}
//Default constructor
pendulum::pendulum() = default;
main.cpp in which the main graphics is drawn:
#include <iostream>
#include "raylib.h"
#include "includes/pendulum.h"
#include <rlgl.h>
#include <cmath>
void _testPendulum();
pendulum pen1;
pendulum pen2;
int main() {
//Prompt to make the initial values themselves
float uLength1, uLength2, uMass1, uMass2, uAngle1, uAngle2;
try {
std::cout << "Please choose the length of each pendulum, starting with Pendulum 1, then Pendulum 2. Each value provided can be up to 7 decimal digits, " << "\n" << "length MUST BE greater than 50 and less than 200" << "\n";
std::cin >> uLength1 >> uLength2;
std::cout << "Please choose the mass of each pendulum, starting with Pendulum 1, then Pendulum 2. Each value provided can be up to 7 decimal digits, " << "\n" << "mass MUST BE greater than 20 and less than 100" << "\n";
std::cin >> uMass1 >> uMass2;
std::cout << "Please choose the starting angle of each pendulum, starting with Pendulum 1, then Pendulum 2. Each value provided can be up to 7 decimal digits" << "\n";
std::cin >> uAngle1 >> uAngle2;
} catch (const std::exception & e) {
std::cout << e.what();
}
//Pendulum 1 settings
pen1.setMass(uMass1);
pen1.setLength(uLength1);
pen1.setAngle(uAngle1);
pen1.setX(pen1.pLength,pen1.getAngle());
pen1.setY(pen1.pLength, pen1.getAngle());
std::cout << "X coord: " << pen1.getX() << " Y coord: " << pen1.getY() << std::endl;
//Pendulum 2 settings
pen2.setMass(uMass2);
pen2.setLength(uLength2);
pen2.setAngle(uAngle2); //Can only set this once and cant anywhere else, why?
pen2.setX( pen2.pLength,pen2.getAngle());
pen2.setY( pen2.pLength,pen2.getAngle());
pen2.x = pen1.getX() + pen2.getX();
pen2.y = pen1.getY() + pen2.getY();
std::cout << "X coord: " << pen2.getX() << " Y coord: " << pen2.getY() << std::endl;
Vector2 origin{0,0};
const double screenWidth = 1440;
const double screenHeight = 1080;
InitWindow((int) screenWidth, (int) screenHeight, "Double-Pendulum-Sim");
int frameCounter = 0;
SetTargetFPS(60);
float px1 = pen1.getX();
float py1 = pen1.getY();
float px2 = pen2.getX();
float py2 = pen2.getY();
RenderTexture2D target = LoadRenderTexture((int) screenWidth, (int) screenHeight);
BeginTextureMode(target);
ClearBackground(RAYWHITE);
EndTextureMode();
while (!WindowShouldClose()) {
Vector2 rod1{px1,py1};
Vector2 rod2 {px2, py2};
/**------------------Update------------------*/
frameCounter++;
uAngle1 += 1.0f;
pen1.setAngle(uAngle1); //Can only set this once and cant anywhere else, why?
pen1.setX(pen1.pLength,pen1.getAngle());
pen1.setY(pen1.pLength, pen1.getAngle());
px1 = pen1.getX();
py1 = pen1.getY();
uAngle2 -= 1.0f;
pen2.setAngle(uAngle2); //Can only set this once and cant anywhere else, why?
pen2.setX( pen2.pLength,pen2.getAngle());
pen2.setY( pen2.pLength,pen2.getAngle());
pen2.x = pen1.getX() + pen2.getX();
pen2.y = pen1.getY() + pen2.getY();
px2 = pen2.getX();
py2 = pen2.getY();
std::cout << frameCounter << std::endl;
/**---------------------------------Draw-Pendulums & Path---------------------------------- */
//TODO: Get pathing to work
BeginDrawing();
BeginTextureMode(target);
DrawPixelV(rod2, RED);
EndTextureMode();
rlTranslatef((float) screenWidth/2,(float) screenHeight/4,0);
DrawTextureRec(target.texture, (Rectangle){0,0, (float) target.texture.width, (float) -target.texture.height}, (Vector2){0,0}, WHITE);
ClearBackground(RAYWHITE);
DrawFPS(-350, -200);
DrawLineEx(origin, rod1, 5.0f, BLACK);
DrawCircle( px1,py1,pen1.pMass,BLACK);
DrawLineEx(rod1, rod2, 5.0f, BLACK);
DrawCircle(px2,py2,pen2.pMass,BLACK);
std::cout << "Pendulum 1 X & Y: " << pen1.getX() << " " << pen1.getY() << std::endl;
std::cout << "Pendulum 2 X & Y: " << pen2.getX() << " " << pen2.getY() << std::endl;
EndDrawing();
}
CloseWindow();
return 0;
}
//Test function
void _testPendulum() {
try {
pen1.setMass(20.0f);
pen1.setLength(150.0f);
pen1.setAngle(0.0f);
pen1.setX(pen1.pLength,pen1.getAngle());
pen1.setY(pen1.pLength, pen1.getAngle());
std::cout << "X coord: " << pen1.getX() << " Y coord: " << pen1.getY() << std::endl;
pen2.setMass(50.0f);
pen2.setLength(150.0f);
pen2.setAngle(0.0f);
pen2.setX( pen2.pLength,pen2.getAngle());
pen2.setY( pen2.pLength,pen2.getAngle());
pen2.x = pen1.getX() + pen2.getX();
pen2.y = pen1.getY() + pen2.getY();
std::cout << "X coord: " << pen2.getX() << " Y coord: " << pen2.getY() << std::endl;
} catch (const std::exception & e) {
std::cout << e.what();
}
}
Your problem comes from DrawPixelV(rod2, RED); which is unable to write where position is negative (try without rlTranslatef to see the idea).
Solution:
Don't use rlTranslatef
Instead make origin, px1, py1, px2 and py2 centered on the screen center (not 0,0).
In main.cpp, I changed these lines and the problem disappeared
Vector2 origin{700,200}; // was origin{0,0};
...
float px1 = pen1.getX() + 700; // +700 was not here
float py1 = pen1.getY() + 200; // +200 was not here
float px2 = pen2.getX() + 700;
float py2 = pen2.getY() + 200;
...
px1 = pen1.getX() + 700;
py1 = pen1.getY() + 200;
...
px2 = pen2.getX() + 700;
py2 = pen2.getY() + 200;
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 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?
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 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