OpenGL C++中的粒子闪烁

Flickering with Particles in OpenGL C++

本文关键字:粒子 闪烁 C++ OpenGL      更新时间:2023-10-16

我在使用此代码时遇到问题。我希望它能发射烟花,在静止的背景前爆炸并落下。现在,烟火和背景都起作用,但它们一起会引起闪烁,而且烟火不会以正常的速度落下。我该如何防止这种闪烁并实现正常的烟花掉落速度?

#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,不要把时间浪费在这个传统的固定函数管道上。改为使用着色器。