Rotate a particle system - c++

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)

Related

Changing coordinate system causes clockwise rotations

The task
I need to convert the coordinate system to +X forward, +Y right and +Z up (left-handed, like the one in Unreal Engine). The crucial part is that I want my camera to face its forward axis (again, like in Unreal Engine). Here is how it works in Unreal:
The problem
I have managed to achieve both things: my camera now faces its forward direction and world coordinates are the same as in UE, HOWEVER, I've stumbled upon a big issue. For each object:
pitch rotation (around RightVector) is now clockwise
yaw rotation (around UpVector) is now clockwise
roll rotation (around ForwardVector) is counter-clockwise (as it was before)
I need these rotations to be all counter-clockwise (as per standard) and keep the camera facing the forward vector.
My current solution attempt
My current setup relies on rotating the projection and camera view matrices (model matrix in my code is called entity matrix):
#define GLM_FORCE_LEFT_HANDED // it's defined somewhere else but so you're aware
// Transform::VectorForward = (1, 0, 0) // these are used below
// Transform::VectorRight = (0, 1, 0)
// Transform::VectorUp = (0, 0, 1)
// The entity matrix update function which updates the model matrix for each object
virtual void UpdateEntityMatrix()
{
auto m = glm::translate(glm::mat4(1.f), m_Transform.Location);
m = glm::rotate(m, glm::radians(m_Transform.Rotation[2]), Transform::VectorUp); // yaw rotation
m = glm::rotate(m, glm::radians(m_Transform.Rotation[1]), Transform::VectorRight); // pitch rotation
m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), Transform::VectorForward); // roll rotation
m_EntityMatrix = glm::scale(m, m_Transform.Scale);
}
// The entity matrix update in my camera class (child of entity) which also updates the view matrix
void Camera::UpdateEntityMatrix()
{
SceneEntity::UpdateEntityMatrix();
auto m = glm::translate(glm::mat4(1.f), m_Transform.Location);
m = glm::rotate(m, glm::radians(180.f), GetRightVector()); // NOTE: I'm getting the current Forward/Right/Up vectors of the entity
m = glm::rotate(m, glm::radians(m_Transform.Rotation[2]), GetUpVector()); // yaw rotation
m = glm::rotate(m, glm::radians(m_Transform.Rotation[1]), GetRightVector()); // pitch rotation
m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), GetForwardVector()); // roll rotation
m = glm::scale(m, m_Transform.Scale);
m_ViewMatrix = glm::inverse(m);
m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}
void PerspectiveCamera::UpdateProjectionMatrix()
{
m_ProjectionMatrix = glm::perspective(glm::radians(m_FOV), m_Width / m_Height, m_NearClip, m_FarClip);
// we want the camera to face +x:
m_ProjectionMatrix = glm::rotate(m_ProjectionMatrix, glm::radians(-90.f), Transform::VectorUp);
m_ProjectionMatrix = glm::rotate(m_ProjectionMatrix, glm::radians(90.f), Transform::VectorRight);
}
This is my result so far (the camera visualization thing shows the rotation of currently used camera):
What else I tried
I tried modifying the model matrix (note the -):
virtual void UpdateEntityMatrix()
{
auto m = glm::translate(glm::mat4(1.f), m_Transform.Location);
m = glm::rotate(m, glm::radians(-m_Transform.Rotation[2]), Transform::VectorUp); // yaw rotation
m = glm::rotate(m, glm::radians(-m_Transform.Rotation[1]), Transform::VectorRight); // pitch rotation
m = glm::rotate(m, glm::radians(m_Transform.Rotation[0]), Transform::VectorForward); // roll rotation
m_EntityMatrix = glm::scale(m, m_Transform.Scale);
}
But it makes my camera not face forward anymore (the view is the camera's rotation but mirrored on the Y and Z axis):
Itried to fix it by applying the same change when calculating the camera view matrix but it didn't help (still mirrored or some other issues).
On top of that, I tried experimenting with the glm::lookAt functions to create the view matrix but never achieved anything.
Update: I've found a solution
I think my problem was actually defining a counter-clockwise rotation. It turns out Unreal's rotations are not consistently counter-clockwise. I think it's best to define a counter-clockwise rotation when looking in the direction pointed by the direction arrow - as if you were behind it. Here is my conclusion:
Conclusion
Unless somebody finds an errorin the system I defined, I'll stick to it. The code is contained in the My current solution attempt section. It seems I was correct from the get-go.
However, the answer provided by #paddy does solve my original issue - converting clockwise to counter-clockwise. Upon further attempts, I was able to correctly replicate Unreal's system while keeping my camera facing forward.

How to rotate a cube by its center

I am trying to rotate a "cube" full of little cubes using keyboard which works but not so great.
I am struggling with setting the pivot point of rotation to the very center of the big "cube" / world. As you can see on this video, center of front (initial) face of the big cube is the pivot point for my rotation right now, which is a bit confusing when I rotate the world a little bit.
To explain it better, it looks like I am moving initial face of the cube when using keys to rotate the cube. So the pivot point might be okay from this point of view, but what is wrong in my code? I don't understand why it is moving by front face, not the entire cube by its very center?
In case of generating all little cubes, I call a function in 3 for loops (x, y, z) and the function returns cubeMat so I have all cubes generated as you can see on the video.
cubeMat = scale(cubeMat, {0.1f, 0.1f, 0.1f});
cubeMat = translate(cubeMat, {positioning...);
For rotation itself, a short example of rotation to left looks like this:
mat4 total_rotation; //global variable - never resets
mat4 rotation; //local variable
if(keysPressed[GLFW_KEY_LEFT]){
timer -= delta;
rotation = rotate(mat4{}, -delta, {0, 1, 0});
}
... //rest of key controls
total_rotation *= rotation;
And inside of those 3 for cycles is also this:
program.setUniform("ModelMatrix", total_rotation * cubeMat);
cube.render();
I have read that I should use transformation to set the pivot point to the middle but in this case, how can I set the pivot point inside of little cube which is in center of world? That cube is obviously x=2, y=2, z=2 since in for cycles, I generate cubes starting at x=0.
You are accumulating the rotation matrices by right-multiplication. This way, all rotations are performed in the local coordinate systems that result from all previous transformations. And this is why your right-rotation results in a turn after an up-rotation (because it is a right-rotation in the local coordinate system).
But you want your rotations to be in the global coordinate system. Thus, simply revert the multiplication order:
total_rotation = rotation * total_rotation;

Rotating the LookAt vector of gluLookAt

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);

Quaternion-Based-Camera unwanted roll

I'm trying to implement a quaternion-based camera, but when moving around the X and Y axis, the camera produces an unwanted roll on the Z axis. I want to be able to look around freely on all axis.
I've read other topics about this problem (for example: http://www.flipcode.com/forums/thread/6525 ), but I'm not getting what is meant by "Fix this by continuously rebuilding the rotation matrix by rotating around the WORLD axis, i.e around <1,0,0>, <0,1,0>, <0,0,1>, not your local coordinates, whatever they might be."
//Camera.hpp
glm::quat rotation;
//Camera.cpp
void Camera::rotate(glm::vec3 vec)
{
glm::quat paramQuat = glm::quat(vec);
rotation = paramQuat * rotation;
}
I call the rotate function like this:
cam->rotate(glm::vec3(0, 0.5, 0));
This must have to do with local/world coordinates, right? I'm just not getting it, since I thought quaternions are always based on each other (thus a quaternion can't be in "world" or "local" space?).
Also, should i use more than one quaternion for a camera?
As far as I understand it, and from looking at the code you provided, what they mean is that you shouldn't store and apply the rotation incrementally by applying rotate on the rotation quat all the time, but instead keeping track of two quaternions for each axis (X and Y in world space) and calculating the rotation vector as the product of those.
[edit: some added (pseudo)code]
// Camera.cpp
void Camera::SetRotation(glm::quat value)
{
rotation = value;
}
// controller.cpp --> probably a place where you'd want to translate user input and store your rotational state
xAngle += deltaX;
yAngle += deltaY;
glm::quat rotationX = QuatAxisAngle(X_AXIS, xAngle);
glm::quat rotationY = QuatAxisAngle(Y_AXIS, yAngle);
camera.SetRotation(rotationX * rotationY);

opengl - Rotating around a sphere using vectors and NOT glulookat

I'm having an issue with drawing a model and rotating it using the mouse,
I'm pretty sure there's a problem with the mathematics but not sure .
The object just rotates in a weird way.
I want the object to start rotating each click from its current spot and not reset because of the
vectors are now changed and the calculation starts all over again.
void DrawHandler::drawModel(Model * model){
unsigned int l_index;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW); // Modeling transformation
glLoadIdentity();
Point tempCross;
crossProduct(tempCross,model->getBeginRotate(),model->getCurrRotate());
float tempInner= innerProduct(model->getBeginRotate(),model->getCurrRotate());
float tempNormA =normProduct(model->getBeginRotate());
float tempNormB=normProduct(model->getCurrRotate());
glTranslatef(0.0,0.0,-250.0);
glRotatef(acos (tempInner/(tempNormA*tempNormB)) * 180.0 / M_PI,tempCross.getX(),tempCross.getY(),tempCross.getZ());
glColor3d(1,1,1);
glBegin(GL_TRIANGLES);
for (l_index=0;l_index < model->getTrianglesDequeSize() ;l_index++)
{
Triangle t = model->getTriangleByPosition(l_index);
Vertex a1 = model->getVertexByPosition(t.getA());
Vertex a2 = model->getVertexByPosition(t.getB());
Vertex a3 = model->getVertexByPosition(t.getC());
glVertex3f( a1.getX(),a1.getY(),a1.getZ());
glVertex3f( a2.getX(),a2.getY(),a2.getZ());
glVertex3f( a3.getX(),a3.getY(),a3.getZ());
}
glEnd();
}
This is the mouse function which saves the beginning vector of the rotating formula
void Controller::mouse(int btn, int state, int x, int y)
{
x=x-WINSIZEX/2;
y=y-WINSIZEY/2;
if (btn==GLUT_LEFT_BUTTON){
switch(state){
case(GLUT_DOWN):
if(!_rotating){
_model->setBeginRotate(Point(float(x),float(y),
(-float(x)*x - y*y + SPHERERADIUS*SPHERERADIUS < 0)? 0:float(sqrt(-float(x)*x - y*y + SPHERERADIUS*SPHERERADIUS))));
_rotating=true;
}
break;
case(GLUT_UP):
_rotating=false;
break;
}
}
}
and finally the following function which holds the current vector.
(the beginning vector is where the mouse was clicked at
and the curr vector is where the mouse position at the moment )
void Controller::getMousePosition(int x,int y){
x=x-WINSIZEX/2;
y=y-WINSIZEY/2;
if(_rotating){
_model->setCurrRotate(Point(float(x),float(y),
(-float(x)*x - y*y + SPHERERADIUS*SPHERERADIUS < 0)? 0:float(sqrt(-float(x)*x - y*y + SPHERERADIUS*SPHERERADIUS))));
}
}
where sphereradius is the sphere radius O_O of 70 degress
is any calculation wrong ? cant seem to find the problem...
thanks
Why so complicated? Either you change the view matrix or you change the model matrix of your focused object. If you choose to change the model matrix and your object is centered in (0,0,0) of the world coordinate system, computing the rotation around a sphere illusion is trivial - you just rotate into the opposite direction. If you want to change the view matrix (which is actually done when you change the position of the camera) you have to approximate the surface points on the chosen sphere. Therefore, you could introduce two parameters specifying two angles. Everytime you click move your mouse, you update the params and compute the new locations on the sphere. There are some useful equations in [http://en.wikipedia.org/wiki/Sphere].
Without knowing what library (or libraries) you're using your code is rather difficult to read. It seems you're setting up your camera at (0, 0, -250), looking towards the origin, then rotating around the origin by the angle between two vectors, model->getCurrRotate() and model->getBeginRotate().
The problem seems to be that in "mouse down" events you explicitly set BeginRotate to the point on the sphere under the mouse, then in "mouse move" events you set CurrRotate to the point under the mouse, so every time you click somewhere else, you lose the previous state of rotation because BeginRotate and CurrRotate are simply overwritten.
Combining multiple rotations around arbitrary different axes is not a trivially simple task. The proper way to do it is to use quaternions. You may find this primer on quaternions and other 3D math concepts useful.
You might also want a more robust algorithm for converting screen coordinates to model coordinates on the sphere. The one you are using is assuming the sphere appears 70 pixels in radius on the screen and that the projection matrix is orthographic.