OpenGL C++ 中的粒子闪烁

Flickering with Particles in OpenGL C++

我在使用这段代码时遇到问题。我想让它发射在静态背景前爆炸和落下的烟花。现在烟花和背景一起工作,但它们一起会造成闪烁,烟花不会以正常的速度下降。我如何防止这种闪烁并实现正常的烟花坠落率?

#include <GL/freeglut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include "Header.h"
using namespace std;

#define M_PI (3.1415926535897932384626433832795)

GLfloat randomNum()
{
    return (rand() % 10000) / 10000.0;
}

GLfloat nx = 0;
GLfloat ny = .8;



#define MAX_POINTS 750
GLfloat numPoints;
GLfloat curx, cury;
GLfloat x[MAX_POINTS], y[MAX_POINTS];
GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
GLfloat red, green, blue;
int step; int length;

GLfloat newRed = 0;
GLfloat newGreen = 0;
GLfloat newBlue = 0;

GLint   totPor = 0;
GLint   strontiumPor = 0;
GLfloat bariumPor = 0;
GLfloat copperPor = 0;
GLfloat sodiumPor = 0;
GLfloat phosPor = 0;

GLfloat red2;
GLfloat green2;
GLfloat green3;
GLfloat blue2;

void initialize()
{
    int j; double temp, temp2;

    numPoints = randomNum()*(MAX_POINTS - 1);
    curx = nx;
    cury = ny;

    //Color Mixing



    if (totPor != 0)
    {
        red = newRed   *  strontiumPor / (totPor - strontiumPor);            //s   red
        green = newGreen *  bariumPor / (totPor - bariumPor);            //b   green
        blue = newBlue  *  copperPor / (totPor - copperPor);             //c  blue
        red2 = newRed * sodiumPor / (totPor - sodiumPor);       //d   yellow
        green2 = newGreen * sodiumPor / (totPor - sodiumPor);
        green3 = newGreen * phosPor / (totPor - phosPor);           //p    blue green
        blue2 = newBlue  * phosPor / (totPor - phosPor);

        red = red + red2;
        green = green + green2 + green3;
        blue = blue + blue2;
    }
    else
    {
        red = newRed;
        green = newGreen;
        blue = newBlue;
    }


    glPointSize(1.7);
    step = 0;
    length = 500 + 300 * randomNum();


    /* initialize the blast */
    for (j = 0; j<numPoints; j++) {
        x[j] = curx;
        y[j] = cury;
        temp = randomNum();
        temp2 = randomNum()*2.0*M_PI;
        xacc[j] = (cos(temp2) * temp) / length;
        yacc[j] = (sin(temp2) * temp) / length;
    }

}


void draw_fireworks(void)
{
    int i;
    double glow = (length - (step)) / (double)length;
    glColor3f(red*glow, green*glow, blue*glow);  //glow
    glBegin(GL_POINTS);
    for (i = 0; i<numPoints; i++) {
        x[i] += xacc[i];
        y[i] += yacc[i];
        glVertex2f(x[i], y[i]);
    }
    glEnd();
    glFlush();
    glutSwapBuffers();
}

void display(void)
{

    int i;
    glClear(GL_COLOR_BUFFER_BIT);

        if (step < 0.9*length) {
        for (i = 0; i<numPoints; i++)
            yacc[i] -= 0.02 / length; // gravity
        draw_fireworks();
    }
    step++;
    if (step > length) initialize();

    DrawScene();
    glutSwapBuffers();

}



int t = 0;

void idle(void)
{


    if (t == 45000)
    {
        glutPostRedisplay();
        t = 0;
    }
    t++;
}


void SpecialKey(int key, int x, int y)
{
    switch (key) {
    case GLUT_KEY_LEFT:
        /* Move fireworks left or right, up or down */
        nx = nx + -.025;
        break;
    case GLUT_KEY_RIGHT:
        nx = nx + .025;
        break;
    case GLUT_KEY_UP:
        ny = ny + .025;
        break;
    case GLUT_KEY_DOWN:
        ny = ny + -.025;
        break;
    }
    glutPostRedisplay();
}



void Keyboard(unsigned char key, int x, int y)
{

    //Select Chemicals
    switch (key)
    {
    case 's':
        newRed = 1;
        strontiumPor = strontiumPor + 1;
        totPor = totPor + 1;
        break;
    case 'b':
        newGreen = 1;
        bariumPor = bariumPor + 1;
        totPor = totPor + 1;
        break;
    case 'c':
        newBlue = 1;
        copperPor = copperPor + 1;
        totPor = totPor + 1;
        break;
    case 'd':
        newRed = 1;
        newGreen = 1;
        sodiumPor = sodiumPor + 1;
        totPor = totPor + 1;
        break;
    case 'p':
        newBlue = 1;
        newGreen = 1;
        phosPor = phosPor + 1;
        totPor = totPor + 1;
        break;


    case 'R':   newRed = newRed + .1;
        break;
    case 'G':   newGreen = newGreen + .1;
        break;
    case 'B':   newBlue = newBlue + .1;
        break;
    case ' ':                                            //Space bar is Reset or start
        newRed = 1;
        newGreen = 1;
        newBlue = 1;
        totPor = 0;
        strontiumPor = 0;
        bariumPor = 0;
        copperPor = 0;
        sodiumPor = 0;
        phosPor = 0;
        break;
    case 'm':   nx = 0; ny = 0.8;                       //M resets target to default
        break;
    case 'q':   exit(0);                                 //Q is quit
    }
    glutPostRedisplay();
}




void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    if (w <= h)
        glOrtho(-1.0, 1.0,
        -1.0*(GLfloat)h / (GLfloat)w, 1.0*(GLfloat)h / (GLfloat)w,
        -1.0, 1.0);
    else
        glOrtho(-1.0*(GLfloat)w / (GLfloat)h, 1.0*(GLfloat)w / (GLfloat)h,
        -1.0, 1.0,
        -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
}



int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(700, 700);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Fireworks Display");

    glClearColor(0.0, 0.0, 0.0, 0.0);
    initialize(); 
    initText();
    glutDisplayFunc(display);

    glutReshapeFunc(reshape);
    glutIdleFunc(idle);
    glutKeyboardFunc(Keyboard);
    glutSpecialFunc(SpecialKey);

    glutMainLoop();

    return 0;
}

然后还有这个:

#include <GL/freeglut.h>
#include "Soil.h"



GLuint tex_ID;




void LoadTextureMap()
{

    int width, height, channels;
    unsigned char* image = SOIL_load_image("washington.png", &width, &height, &channels, SOIL_LOAD_AUTO);

    glGenTextures(1, &tex_ID);
    glBindTexture(GL_TEXTURE_2D, tex_ID);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
        GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
        GL_NEAREST);

    glTexImage2D(GL_TEXTURE_2D, 0, channels, width, height, 0,
        GL_RGBA, GL_UNSIGNED_BYTE, image);

    SOIL_free_image_data(image);
}


void Tree(GLfloat x, GLfloat y, GLfloat z)
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, tex_ID);
    glPushMatrix();
    glRotatef(180, 0.0f, 0.0f, 1.0f);
    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);
    glTexCoord2f(0.0, 0.0); glVertex3f(-1.0 + x, -1.0 + y, 1.0 + z);
    glTexCoord2f(0.0, 1.0); glVertex3f(-1.0 + x, 1.0 + y, 1.0 + z);
    glTexCoord2f(1.0, 1.0); glVertex3f(1 + x, 1.0 + y, 1.0 + z);
    glTexCoord2f(1.0, 0.0); glVertex3f(1 + x, -1.0 + y, 1.0 + z);
    glEnd();
    glPopMatrix();
    glDisable(GL_TEXTURE_2D);
}

void DrawScene()
{

    Tree(0, 0, 0);

}




void initText()
{

    LoadTextureMap();
}

您在 draw_fireworks() 和 display() 中调用了 glutSwapBuffers()。你应该每帧只调用一次。

顺便说一句,如果您想学习 OpenGL,请不要将时间浪费在这些遗留的固定功能管道上。改用着色器。