OpenGL particles, help controlling direction - c++

I am trying to modify this Digiben sample in order to get the effect of particles that generate from a spot (impact point) and float upwards kind of like the sparks of a fire. The sample has the particles rotating in a circle... I have tried removing the cosine/sine functions and replace them with a normal glTranslate with increasing Y value but I just can't get any real results... could anyone please point out roughly where I should add/modify the translation in this code to obtain that result?
void ParticleMgr::init(){
tex.Load("part.bmp");
GLfloat angle = 0; // A particle's angle
GLfloat speed = 0; // A particle's speed
// Create all the particles
for(int i = 0; i < P_MAX; i++)
{
speed = float(rand()%50 + 450); // Make a random speed
// Init the particle with a random speed
InitParticle(particle[i],speed,angle);
angle += 360 / (float)P_MAX; // Increment the angle so when all the particles are
// initialized they will be equally positioned in a
// circular fashion
}
}
void ParticleMgr::InitParticle(PARTICLE &particle, GLfloat sss, GLfloat aaa)
{
particle.speed = sss; // Set the particle's speed
particle.angle = aaa; // Set the particle's current angle of rotation
// Randomly set the particles color
particle.red = rand()%255;
particle.green = rand()%255;
particle.blue = rand()%255;
}
void ParticleMgr::DrawParticle(const PARTICLE &particle)
{
tex.Use();
// Calculate the current x any y positions of the particle based on the particle's
// current angle -- This will make the particles move in a "circular pattern"
GLfloat xPos = sinf(particle.angle);
GLfloat yPos = cosf(particle.angle);
// Translate to the x and y position and the #defined PDEPTH (particle depth)
glTranslatef(xPos,yPos,PDEPTH);
// Draw the first quad
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(-5, 5, 0);
glTexCoord2f(1,0);
glVertex3f(5, 5, 0);
glTexCoord2f(1,1);
glVertex3f(5, -5, 0);
glTexCoord2f(0,1);
glVertex3f(-5, -5, 0);
glEnd(); // Done drawing quad
// Draw the SECOND part of our particle
tex.Use();
glRotatef(particle.angle,0,0,1); // Rotate around the z-axis (depth axis)
//glTranslatef(0, particle.angle, 0);
// Draw the second quad
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3f(-4, 4, 0);
glTexCoord2f(1,0);
glVertex3f(4, 4, 0);
glTexCoord2f(1,1);
glVertex3f(4, -4, 0);
glTexCoord2f(0,1);
glVertex3f(-4, -4, 0);
glEnd(); // Done drawing quad
// Translate back to where we began
glTranslatef(-xPos,-yPos,-PDEPTH);
}
void ParticleMgr::run(){
for(int i = 0; i < P_MAX; i++)
{
DrawParticle(particle[i]);
// Increment the particle's angle
particle[i].angle += ANGLE_INC;
}
}
For now I am adding a glPushMatrix(), glTranslate(x, y, z) in the run() function above, right before the loop, with x,y,z as the position of the enemy for placing them on top of the enemy....is that the best place for that?
Thanks for any input!

Using glTranslate and glRotate that way will in fact decrease your program's performance. OpenGL is not a scene graph, so the matrix manipulation functions directly influence the drawing process, i.e. they don't set "object state". The issue you're running into is, that a 4×4 matrix-matrix multiplication involves 64 multiplications and 16 additions. So you're spending 96 times the computing power for moving a particle, than simply update the vertex position directly.
Now to your problem: Like I already told you, glTranslate operates on (a global) matrix state of one of 4 selectable matrices. And the effects accumulate, i.e. each glTranslate will start from the matrix the previous glTranslate left. OpenGL provides a matrix stack, where one can push a copy of the current matrix to work with, then pop to revert to the state before.
However: Matrix manipulation has been removed from OpenGL-3 core and later entirely. OpenGL matrix manipulation never was accelerated (except on one particular graphics workstation made by SGI around 1996). Today it is a anachronism, as every respectable program working with 3D geometry used much more sophisticated matrix manipulation by either own implementation or 3rd party library. OpenGL's matrix stack was just redundant. So I strongly suggest you forget about OpenGL's matrix manipulation functionality and roll your own.

Related

OpenGL capture 6 cube face images

How to move camera in OpenGL to capture 6 cube face images and save into files (like image below)?
What does "plugin" means?
I'm confused that you need how to calculate camera position&direction vectors for capture each side of dice or how to implement lookat&perspective functions.
for lookat&perspective functions, there are many resources to refer :
Can't understand gluLookAt arguments
gluPerspective parameters- what do they mean?
these functions are usually provided on many libraries, but if you need, then I will post my implementation.
Camera position and direction/up vector is calculated for viewing each side of dice squarely. to do this, you have to care about perspective FOV(field of view) with respect to distance between camera and dice.
If you read above posts carefully, you can determine arguments for these functions.
If once you see each side on screen, I think you need the method combining the result scene of each dice into one screen(or FBO) and save it.
If once you obtain 6 sets of arguments for lookat and perspective, you can use glViewPort.
// if pixel per each side : 10
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
//back side draw
glViewPort(0, 10, 10, 10);
//call glulookat & gluperspective or equivalent functions with arguments so that back side of dice drew on your Viewport fully
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//up side draw
glViewPort(10, 0, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
//left side draw
glViewPort(10, 10, 10, 10);
gluLookAt(...);
gluPerpective(...);
glDrawElements(...);
...
The above code draw 6 times in each selected viewport of your result FBO.
An example using PyQt5 for making an image of a plane with size X, Y in the z=0 plane.
Xt = X/2 #center of your camera in X
Yt = Y/2 #center of your camera in Y
dist = math.tan(math.radians(60))*Y/2 #Compute the distance of the campera from plane
#assuming a 60 degree projection
aspect = float(self.width)/float(self.height) #aspect ratio of display
center = QtGui.QVector3D(Xt, Yt, 0) #look at this point
eye = QtGui.QVector3D(Xt, Yt, dist) #Point of Camera in space
up = QtGui.QVector3D(0, 1, 0)
self.modelview = QtGui.QMatrix4x4()
self.modelview.lookAt(eye,center,up) #build modelview matrix with given parameters
self.projection = QtGui.QMatrix4x4()
self.projection.perspective(60.0, aspect, dist*0.0001, dist*10000.0) #build projection matrix
repeating this process for each side + adjusting the z distance to your cube should yield the desired result. The you can just write your results to a framebuffer and read that buffer into an array.

Drawing hour marks of a clock using OpenGL

here is my code:
void drawClock(void)
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0,0.0,0.0);
for(int i=0; i<12; i++){
glRotatef(30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
}
glFlush();
}
Here is my reshape function (without it I don't see anything, although I'm not sure how it really works)
void changeSize(int w, int h) {
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if(h == 0) h = 1;
float ratio = 1.0* w / h;
// Reset the coordinate system before modifying
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45,ratio,1,1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,0.0,70.0,
0.0,0.0,-1.0,
0.0f,1.0f,0.0f);
}
So I am trying to draw the hour marks of a clock using wire cubes of size 2.0, and each of these cubes must be 5.2 units away from the center. This is for an assignment, I know it is probably very simple but I just can't manage to make it work properly. My problem is that the cubes appear in 3D, but I want them to appear in 2D, as in I would only see one face. Also, the circle is not centered, I do not understand why. I know I am supposed to use pushMatrix and popMatrix but no matter how I use it it doesn't work.
3d Problem
gluPerspective makes a perspective projection. To accomplish what you need you should apply an orthographic projection instead.
The best way to do this with your current code is to us glOrtho to provide a left, right, bottom, top, far,near box within which everything will 'appear' 2D. Try the code below in place of gluPerspective.
glOrtho(10.0f,-10.0f,10.0f,-10.0f,10.0f,-10.0f,10.0f);
Position problem
I'm not so sure about the transformation as I've not used immediate mode for a while. Note the order of operations makes a difference.
As for the push/pop of matrices, it is basically a stack of 4x4 matrices detailing the transformations. I'm sure it works along the lines of
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslate(x,y,z);// Where x,y,z is the starting point of your clock
for(int i=0; i<12; i++){
glPushMatrix();
glRotatef(i * 30,0,0,1);
glTranslatef(5.2,0.0,0.0);
glutWireCube(2.0);
glPopMatrix();
}

OpenGL glTranslatef not working as it should

So I decided to make a 3D Stars kinda thing in C++ with SDL and OpenGL. I created a Point class which holds x, y, and z values. I create an array of Points and fill it with random coordinates. This seems to work but when I do glTranslatef(0,0,0.1f) or something similar, the stars don't come close, they just disappear.
//OpenGL Initialization Code
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0f,640.0/480.0,0.3f,500.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_DEPTH_TEST);
//Random point generation
for(int i = 0; i < 200000; i++)
{
float randomX = (float)rand()/((float)RAND_MAX/100.0f) - 50.0f;
float randomY = (float)rand()/((float)RAND_MAX/20) - 10.0f;
float randomZ = (float)rand()/((float)RAND_MAX/20) - 20.0f;
points[i] = Point(randomX, randomY,randomZ);
}
//Render
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POINTS);
for(int i = 0; i < 200000; i++)
{
glVertex3f(points[i]._x, points[i]._y, points[i]._z);
}
glEnd();
glTranslatef(0,0,0.1f);
SDL_GL_SwapBuffers();
SDL_Flip(screen);
What am I doing wrong?
Is that code your render function?
If it is, then you should move the point generation elsewhere so that they get generated only once.
If it is not, then you should move the initialization code to the beginning of the render function. The matrices should be cleared every frame.
If that doesn't work:
Try temporarily disabling depth testing. If they don't disappear and you see lines, you need to adjust your view frustum. Try using gluLookAt
Also, try translating them in the negative z axis. If I remember correctly, in opengl, object-space coordinates are farther away as z decreases. (0 is closer than -1)
I'm not sure why they'ld be disappearing, but in your sample code it should be inert. You load a new Identity matrix at the top for the MODELVIEW matrix, and then translate it after you've rendered. Try moving the glTranslate to right before your glBegin.
I moved the OpenGL initialization code after the code where I init SDL SetVideoMode, it works as it should now.

OpenGL gluLookAt() not working as intended

I am making a rollercoaster inside of a skybox in OpenGL, and without much background on it's functions or computer graphics it is proving to be very difficult. I drew a rollercoaster using Catmull-Rom spline interpolation, and drew each point with glVertex3f. Now I want to call an update() function every 50ms to move the camera around the track. gluLookAt() is producing weird results, either removing the track from the screen, producing a black screen, etc. I think I need to move some of the matrix functions around but I am not sure where to put each one. Here is my code so far:
int main(int argc, char** argc)
{
// ... load track, etc ...
// Init currpos, nextpos, iter, up
currpos = Vec3f(0, 0, 0);
nextpos = currpos;
iter = 0;
up = Vec3f(0, 1, 0);
deque<Vec3f> points;
Vec3f newpt;
// Loop through the points and interpolate
for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++)
{
Vec3f curr(*pv); // Initialize the current point and a new point (to be drawn)
points.push_back(curr); // Push the current point onto the stack
allpoints.push_back(curr); // Add current point to the total stack
if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate
{
for (float u = 0.0f; u < 1.0f; u += 0.01f)
{
newpt = interpolate(points[0], points[1], points[2], points[3], u);
glColor3f(1, 1, 1);
glVertex3f(newpt.x(), newpt.y(), newpt.z());
allpoints.push_back(newpt);
}
points.pop_front();
}
}
// glutInit, InitGL(), etc...
}
void InitGL(GLvoid)
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(100.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, .0001, 999999);
glMatrixMode(GL_MODELVIEW);
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
}
void display (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z());
glPushMatrix();
glEnable(GL_TEXTURE_2D); // Enable texturing from now on
/* draw skybox, this was from previous assignment and renders correctly */
glPopMatrix();
// now draw rollercoaster ...
glPushMatrix();
glBegin(GL_LINE_STRIP);
deque<Vec3f> points;
Vec3f newpt;
for each (Vec3f pt in allpoints)
{
glColor3f(1, 1, 1);
glVertex3f(pt.x(), pt.y(), pt.z());
}
glutTimerFunc(50, update, 1);
glEnd();
glPopMatrix();
// Swap buffers, so one we just drew is displayed
glutSwapBuffers();
}
void update(int a)
{
if (iter < allpoints.size())
{
currpos = allpoints[iter];
nextpos = allpoints[iter + 1];
gaze = nextpos - currpos;
gaze.Normalize();
Vec3f::Cross3(binorm, gaze, up);
binorm.Normalize();
Vec3f::Cross3(up, binorm, gaze);
up.Normalize();
glutPostRedisplay();
}
iter++;
}
The idea is that I am keeping a global deque allpoints that includes the control points of the spline and the interpolated points. Once that is complete, I call update() every 50ms, and move the camera along each point in allpoints. In a previous version of the project, I could see that the rollercoaster was being drawn correctly. It is gluLookAt() that doesn't seem to work how I want it to. With the code above, the program starts with the camera looking at one side of the skybox with a part of the rollercoaster, and then when update() is called, the rollercoaster disappears but the camera does not move. I have been messing around with where I am putting the OpenGL matrix functions, and depending on where they are sometimes update() will cause a blank screen as well.
Besides the absence of glPopMatrix (which user971377 already spotted), you call glLoadIdentity in your drawing routine, which of course overwrites any changes you did on the modelview matrix in the update method (using gluLookAt).
Always keep in mind: gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate, and all other matrix and transformation functions always work on the top element (changed by glPush/PopMatrix) of the currently selected matrix stack (changed by glMatrixMode). And they always multiply the current matrix, istead of replacing it. So like for gluPerspective, you should call glLoadIdentity before calling gluLookAt. And the whole camera change should be done in the rendering routine, istead of the update routine.
Instead of doing any GL transformations in update you should rather change the variables on which the camera depends and set the camera (gluLookAt on the modelview matrix) in the display method. To demonstrate the standard use of these functions, your code should be something like:
void display()
{
<general state setup (glClear, ...)>
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glLookAt(camera); //view transformation (camera)
//object 1
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object 1>
glPopMatrix();
...
//object n
glPushMatrix(); //save modelview
glTranslate/glRotate/glScale; //local model transformations
<draw object n>
glPopMatrix();
gluSwapBuffers();
}
void update()
{
camera = ...;
}
}
Noticed in your code glPushMatrix(); is called with no glPopMatrix();
Just a thought, this might have something to do with you issue.
gluLookAt always applies its result to current matrix, which in your case is GL_MODEL_VIEW. But when you render your roller coaster, you load identity in that matrix, which erase the value you put using gluLookAt.
In this case, you don't need to touch the model view. In fact, GL_MODEL_VIEW stands for model matrix multiply by view matrix. In this case, you can glPushMatrix() followed by glMulMatrix( myModelMatrix ) and after rendering glPopMatrix(). With this, you can keep your view matrix inside the GL_MODEL_VIEW and still use a different model matrix for each object
I also suggest you only change projection matrix once a frame, and not each frame.
It's been a long time since I touched OpenGL, but here are a few things to consider:
With each call to display(), you are drawing the skybox with the current matrix then loading the identity matrix to draw the roller coaster. Perhaps load the identity within the push/pop so that the skybox is constant, but your prevailing tranformations on the roller coaster are applied.
Do you need to call gluPerspective and glMatrixMode with every call to display()?
Repeatedly calculating binorm from up and then up from binorm will probably give you unexpected results in terms of rotation of the camera around the screen's z axis.
The call to gluLookAt appears to have nextpos and currpos reversed, pointing the camera in the opposite direction.
(Opinion only) It may still look wierd with a completely stationary skybox. Matching camera rotation (but not translation) when drawing the skybox and roller coaster may look better.

how to draw a spiral using opengl

I want to know how to draw a spiral.
I wrote this code:
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);
GLfloat x,y,z = -50,angle;
glBegin(GL_POINTS);
for(angle = 0; angle < 360; angle += 1)
{
x = 50 * cos(angle);
y = 50 * sin(angle);
glVertex3f(x,y,z);
z+=1;
}
glEnd();
glutSwapBuffers();
}
If I don't include the z terms I get a perfect circle but when I include z, then I get 3 dots that's it. What might have happened?
I set the viewport using glviewport(0,0,w,h)
To include z should i do anything to set viewport in z direction?
You see points because you are drawing points with glBegin(GL_POINTS).
Try replacing it by glBegin(GL_LINE_STRIP).
NOTE: when you saw the circle you also drew only points, but drawn close enough to appear as a connected circle.
Also, you may have not setup the depth buffer to accept values in the range z = [-50, 310] that you use. These arguments should be provided as zNear and zFar clipping planes in your gluPerspective, glOrtho() or glFrustum() call.
NOTE: this would explain why with z value you only see a few points: the other points are clipped because they are outside the z-buffer range.
UPDATE AFTER YOU HAVE SHOWN YOUR CODE:
glOrtho(-100*aspectratio,100*aspectratio,-100,100,1,-1); would only allow z-values in the [-1, 1] range, which is why only the three points with z = -1, z = 0 and z = 1 will be drawn (thus 3 points).
Finally, you're probably viewing the spiral from the top, looking directly in the direction of the rotation axis. If you are not using a perspective projection (but an isometric one), the spiral will still show up as a circle. You might want to change your view with gluLookAt().
EXAMPLE OF SETTING UP PERSPECTIVE
The following code is taken from the excellent OpenGL tutorials by NeHe:
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
Then, in your draw loop would look something like this:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glLoadIdentity();
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0
glBegin(GL_TRIANGLES); // Drawing Using Triangles
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd();
Of course, you should alter this example code your needs.
catchmeifyoutry provides a perfectly capable method, but will not draw a spatially accurate 3D spiral, as any render call using a GL_LINE primitive type will rasterize to fixed pixel width. This means that as you change your perspective / view, the lines will not change width. In order to accomplish this, use a geometry shader in combination with GL_LINE_STRIP_ADJACENCY to create 3D geometry that can be rasterized like any other 3D geometry. (This does require that you use the post fixed-function pipeline however)
I recommended you to try catchmeifyoutry's method first as it will be much simpler. If you are not satisfied, try the method I described. You can use the following post as guidance:
http://prideout.net/blog/?tag=opengl-tron
Here is my Spiral function in C. The points are saved into a list which can be easily drawn by OpenGL (e.g. connect adjacent points in list with GL_LINES).
cx,cy ... spiral centre x and y coordinates
r ... max spiral radius
num_segments ... number of segments the spiral will have
SOME_LIST* UniformSpiralPoints(float cx, float cy, float r, int num_segments)
{
SOME_LIST *sl = newSomeList();
int i;
for(i = 0; i < num_segments; i++)
{
float theta = 2.0f * 3.1415926f * i / num_segments; //the current angle
float x = (r/num_segments)*i * cosf(theta); //the x component
float y = (r/num_segments)*i * sinf(theta); //the y component
//add (x + cx, y + cy) to list sl
}
return sl;
}
An example image with r = 1, num_segments = 1024:
P.S. There is difference in using cos(double) and cosf(float).
You use a float variable for a double function cos.