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,请不要将时间浪费在这些遗留的固定功能管道上。改用着色器。
我在使用这段代码时遇到问题。我想让它发射在静态背景前爆炸和落下的烟花。现在烟花和背景一起工作,但它们一起会造成闪烁,烟花不会以正常的速度下降。我如何防止这种闪烁并实现正常的烟花坠落率?
#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,请不要将时间浪费在这些遗留的固定功能管道上。改用着色器。