I'm now implementing opengl camera class and faced with the problem: how to properly convert coordinate axes to angles?
I've searched on the internet a lot, but found no working solutions and unfortunately math is black magic for me, so I cannot do it myself.
I have method in the camera class:
void Camera::LookAtTarget(const glm::vec3& targetPosition, const glm::vec3& upDirection)
{
m_directionForward = glm::normalize(targetPosition - m_position);
m_directionRight = -glm::normalize(
glm::cross(upDirection, m_directionForward));
m_directionUp = glm::normalize(
glm::cross(m_directionForward, m_directionRight));
// HOW TO GET ANGLES FROM THESE AXES?
}
Please help with some working code.
Related
I need to find the world position/orientation of a VR headset (both Oculus and HTC) and then set an actor to be at the same location. Getting the camera's position seems to not work well in VR, so I thought this code was the proper way to do this:
FQuat DeviceRotation;
FVector DevicePosition;
GEngine->XRSystem->GetCurrentPose(0, OUT DeviceRotation, OUT DevicePosition);
myActor->SetActorLocation(DevicePosition);
myActor->SetActorRotation(DeviceRotation);
However, the resulting coordinates are too low on the Z axis and the orientation doesn't properly match.
So what is the proper way to do this in C++? Do I need to factor in the player controller somehow?
UPDATE:
Looking more into this, it seems you have to add the HMD position rotated by the player pawn rotation:
FQuat DeviceRotation;
FVector DevicePosition;
FVector FinalPosition;
GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, DeviceRotation, DevicePosition);
APlayerController *PlayerController = UGameplayStatics::GetPlayerController(GetWorld(), 0);
FinalPosition = PlayerController->GetPawn()->GetActorRotation().RotateVector(DevicePosition) + PlayerController->PlayerCameraManager->GetCameraLocation();
myActor->SetActorLocation(FinalPosition);
myActor->SetActorRotation(DeviceRotation);
However, the results are still not correct, as there seems to be a rotation offset. I have the camera set to lock on to the HMD, so I'm not sure what else I'm missing here.
Figured it out. GetCurrentPose only gives an offset position for the HMD, so it needs to be added to the player pawn's transform like so:
FQuat hmdRotation;
FVector hmdLocationOffset;
GEngine->XRSystem->GetCurrentPose(IXRTrackingSystem::HMDDeviceId, hmdRotation, hmdLocationOffset);
APawn * playerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
myActor->SetActorLocation(playerPawn->GetTransform().TransformPosition(hmdLocationOffset));
myActor->SetActorRotation(hmdRotation);
I'm building a game with Cocos2d-x version 3.13.1 and I've decided to go with the built-in physics engine (Chipmunk 2D) to accomplish animations and collision detection. I have a simple projectile called BulletUnit that inherits from cocos2d::Node. It has a child sprite that displays artwork, and a rectangular physics body with the same dimensions as the artwork.
The BulletUnit has a method called fireAtPoint, which determines the angle between itself and the point specified, then sets the initial velocity based on the angle. On each update cycle, acceleration is applied to the projectile. This is done by applying impulses to the body based on an acceleration variable and the angle calculated in fireAtPoint. Here's the code:
bool BulletUnit::init() {
if (!Unit::init()) return false;
displaySprite_ = Sprite::createWithSpriteFrameName(frameName_);
this->addChild(displaySprite_);
auto physicsBody = PhysicsBody::createBox(displaySprite_->getContentSize());
physicsBody->setCollisionBitmask(0);
this->setPhysicsBody(physicsBody);
return true;
}
void BulletUnit::update(float dt) {
auto mass = this->getPhysicsBody()->getMass();
this->getPhysicsBody()->applyImpulse({
acceleration_ * mass * cosf(angle_),
acceleration_ * mass * sinf(angle_)
});
}
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This works exactly as I want it to. You can see in the image below, my bullets are accelerating as planned and traveling directly towards my mouse clicks.
But, there's one obvious flaw: the bullet is remaining flat instead of rotating to "point" towards the target. So, I adjust fireAtPoint to apply a rotation to the node. Here's the updated method:
void BulletUnit::fireAtPoint(const Point &point) {
angle_ = Trig::angleBetweenPoints(this->getPosition(), point);
// This rotates the node to make it point towards the target
this->setRotation(angle_ * -180.0f/M_PI);
auto physicsBody = this->getPhysicsBody();
physicsBody->setVelocityLimit(maxSpeed_);
physicsBody->setVelocity({
startingSpeed_ * cosf(angle_),
startingSpeed_ * sinf(angle_)
});
}
This almost works. The bullet is pointing in the right direction, but the trajectory is now way off and seems to be arcing away from the target as a result of the rotation: the more drastic the rotation, the more drastic the arcing. The following image illustrates what's happening:
So, it seems that setting the rotation is causing the physics engine to behave in a way I hadn't originally expected. I've been racking my brain on ways to correct the flight path, but so far, no luck! Any suggestions would be greatly apprecitated. Thanks!
I'm a student new to opengl. Currently, I'm doing a project that creates a scene.
Right now, my team is using gluLookAt() for my camera. What I want to accomplish is to try and rotate the LookAt vector around a certain point, namely where the camera is looking at.
This accomplishes a sort of "swaying in a circle". I need this because I am making a dart game for the scene, and my camera stay still, but I need it to move in a circle, but still allow the user's mouse to influence it. I also need it to create a drunken movement. That is why I am not considering rotating the Up or Eye vectors.
Currently, my look at code is like this.
int deltax = x - mouse.mX;
int deltay = y - mouse.mY;
cameradart.mYaw -= ((deltax/360.0) * 3.142) * 0.5;
cameradart.mPitch -= deltay * 0.02;
mouse.mX = x;
mouse.mY = y;
cameradart.lookAt.x = sin (cameradart.mYaw);
cameradart.lookAt.y = cameradart.mPitch ;
cameradart.lookAt.z = cos (cameradart.mYaw);
gluLookAt (cameradart.eye.x, cameradart.eye.y, cameradart.eye.z,
cameradart.eye.x + cameradart.lookAt.x, cameradart.eye.y + cameradart.lookAt.y,
cameradart.eye.z + cameradart.lookAt.z,
cameradart.up.x, cameradart.up.y, cameradart.up.z);
I know that it could be done easier using a different camera, but I really don't want to mess with my team's code by not using gluLookAt().
There's a couple of solutions in my mind, I'll tell you the easiest to understand/implement as a new graphics student
Assuming at first you're looking at (0,0,1) -store that vector-:
Think of a point that's drawing a circle and you're looking at it,
-Do it first to turn right and left (2D on X & Z)
-Let HDiff be the horizontal difference between old mouse position and the new one
-Update the x = cos(HDiff)
-Update the z = sin(HDiff)
*I didn't try it but it should work :)
If you want to be able to manipulate the camera, using a camera matrix is a much more effective mechanism than working with gluLookat. GLM is a good library for matrix and vector math and includes a lookat mechanism you can use to initialize the matrix, or you can just initialize it with a series of operations. However, remember that lookat produces a view matrix, and the view matrix is the inverse of the camera matrix.
This piece of code has a demonstration of what I'm talking about. Specifically look at the player member variable and how it's manipulated
glm::mat4 player;
...
glm::vec3 playerPosition(0, eyeHeight, ipd * 4.0f);
player = glm::inverse(glm::lookAt(playerPosition, glm::vec3(0, eyeHeight, 0), GlUtils::Y_AXIS));
This approach lets you apply changes like rotation and translation directly to the player matrix
// Rotate on the Y axis
player = glm::rotate(player, angle, glm::vec3(0, 1, 0));
This is much more intuitive than manipulating the view matrix, since changes to the view matrix always have to be the inverse of what you'd do to the player matrix.
When you're ready to render you need to convert the player matrix to a view matrix by taking it's inverse. In my example it's done like this:
gl::Stacks::modelview().top() = riftOrientation * glm::inverse(player);
This is because I'm using an application based modelview matrix stack that gets applied to the Shader programs I'm running.
For an OpenGL 1.x program, you'd instead use LoadMatrix
glMatrixMode(GL_MODELVIEW);
glm::mat4 modelview = glm::inverse(player);
glLoadMatrixf(&modelview);
I would like to draw a human skeleton (pose estimation project) in OpenGL, using whichever toolkit might be helpful.
I already have something simple working, drawing the joints with
glvertex3d // and/or
glutWireSphere
and the bones with
glBbegin(GL_Lines)
glvertex3d // coordinates of starting point
glvertex3d // coordinates of ending point
glEnd()
This looks like very similar to the next picture, however this bone depiction doesn't give any intuition about bone rotation.
I would like to have something looking more similar to the following picture, with bones drawn as elongated pyramids.
Glut doesn't seem to help on this.
glutWireCone // better than simple line, but still no intuition about rotation
glutWireTetrahedron // not really useful / parametrizable
Is there any tool available or should this be a custom solution?
GLUT objects will be drawn using the current OpenGL modelview matrix. This can be used to control the position, rotation, or even the scaling of the rendered object. With a cone, you would first translate (using glTranslate()) to the position of one end point, and then rotate (using glRotate() or glMultMatrix()) so that your cone was pointed towards the other endpoint. Finally you call your glutWireCone() method so that the height is equal to the distance from one endpoint to the other.
The tricky bit is finding the glRotate() parameters. GLUT will draw the cone by default along the Z axis, so your rotation needs to be whatever rotation would be required to rotate the Z axis to the axis defined by your end point minus your start point. The GLM math library can be really useful for this kind of thing. It even has a function for it
quat rotation(vec3 const & orig, vec3 const & dest)
So you could do something like this:
// these are filled in with your start and end points
glm::vec3 start, end;
glm::vec3 direction = end - start;
glm::quat rotation = rotation(glm::vec3(0, 0, 1), direction);
glm::mat4 rotationMatrix = glm::mat4_cast(rotation);
glMultMatrixf(&rotationMatrix);
You can get the tetrahedron effect by specifying 3 for the number of slices in your glut cone. In fact I wouldn't be very surprised if glutWireTetrahedron wasn't implemented in terms of glutWireCone
As mentioned in the comment above, Jherico's answer really helped me solve this problem.
This answer builts uppon his post, just to make things a bit more complete, for future reference.
Please find the GLM library here, it's a header only library, so you don't need to build this, just link to it and include the necessary header files. It has some great tools, as can be seen below.
#define GLM_FORCE_RADIANS // for compatibility between GLM and OpenGL API legacy functions
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp> // for glm::mat4_cast // casting quaternion->mat4
#include <glm/gtx/quaternion.hpp> // for glm::rotation
#include <glm/gtx/string_cast.hpp> // for glm::to_string
...
...
...
// _startBoneVec3 used below is Eigen::Vector3d
// _endddBoneVec3 used below is Eigen::Vector3d
...
...
...
//
// for JOINTS
//
glPushMatrix();
glTranslated( _startBoneVec3(0),_startBoneVec3(1),_startBoneVec3(2) );
glutWireSphere(1.0,30,30);
glPopMatrix();
...
...
//
// for BONES
//
glPushMatrix();
float boneLength = ( _endddBoneVec3 - _startBoneVec3 ).norm();
glTranslated( _startBoneVec3(0),_startBoneVec3(1),_startBoneVec3(2) );
glm::vec3 _glmStart( _startBoneVec3(0),_startBoneVec3(1),_startBoneVec3(2) );
glm::vec3 _glmEnddd( _endddBoneVec3(0),_endddBoneVec3(1),_endddBoneVec3(2) );
glm::vec3 _glmDirrr = glm::normalize( _glmEnddd - _glmStart ); // super important to normalize!!!
glm::quat _glmRotQuat = glm::rotation( glm::vec3(0,0,1),_glmDirrr); // calculates rotation quaternion between 2 normalized vectors
//glm::mat4 _glmRotMat = glm::mat4_cast(_glmRotQuat); // quaternion -> mat4
glm::mat4 _glmRotMat = glm::toMat4 (_glmRotQuat); // quaternion -> mat4
//std::cout << glm::to_string(_glmDirrr) << std::endl;
glMultMatrixf(glm::value_ptr(_glmRotMat));
glutWireCone(4.2,boneLength,4,20); // cone with 4 slices = pyramid-like
glPopMatrix();
Result:
Languages / Libraries in use: C++, OpenGL, GLUT
Okay, here's the deal.
I've got a particle system which shoots out alpha blended textures to produce a flame.
The system only keeps track of very basic things such as, time alive, life, xyz and spread.
The direction in which the flames are currently moving in is purely based on other things which are going on in my code ( I assume ).
My goal however, is to attach the flame to the camera (DONE) and have the flame pointing in the direction my camera is facing (NOT WORKING).
I've tried glRotate for both x,y,z and I can't get it to work properly.
I'm currently using gluLookAt to move the camera, and get the flame to follow the XYZ of the camera by calling glTranslatef(camX, camY - offset, camZ);
Any suggestions on how I can rotate the direction of the flame with the camera would be greatly appreciated.
Although most irrelevant, here is an image (incase)
You need to know the orientation of the camera to work out how to change the orientation of the flame particles. You need to basically inverse the camera's rotation matrix. If I was doing this, I would keep a copy of the transformations locally so that I could quickly access the cameras rotation. The alternative is to read the transformation matrix and to calculate the inverse rotation from the matrix.
static void inverseRotMatrix(const GLfloat in[4][4], GLfloat out[4][4])
{
out[0][0] = in[0][0];
out[0][1] = in[1][0];
out[0][2] = in[2][0];
out[0][3] = 0.0f;
out[1][0] = in[0][1];
out[1][1] = in[1][1];
out[1][2] = in[2][1];
out[1][3] = 0.0f;
out[2][0] = in[0][2];
out[2][1] = in[1][2];
out[2][2] = in[2][2];
out[2][3] = 0.0f;
out[3][0] = 0.0f;
out[3][1] = 0.0f;
out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
void RenderFlame()
{
GLfloat matrix[4][4];
GLfloat invMatrix[4][4];
glGetFloatv(GL_MODELVIEW_MATRIX, matrix[0]);
inverseRotMatrix(matrix, invMatrix);
glPushMatrix();
// glMultMatrixf(invMatrix[0]); If you want to rotate the entire body of particles
for ... each particle
...
glTranslatef(particleX, particleY, particleZ);
glMultMatrixf(invMatrix[0]);
DrawParticle();
...
glPopMatrix();
}
This may or may not work for you though depending on what you are doing. If the particles spread out in all directions it should be fine, but if the flame is essentially flat you will have other issues. All this does is rotate each particle so that it is facing the the screen. If you are just rotating the camera it will work fine. If you move the camera you have to rotate all of the points as well about the center point of the flame. But this does give you the rotation you need by inversing the rotation matrix, it's merely a question of how many times you apply the transformation. (I added a comment where you would apply another rotation to rotate the whole body of particles)