我使用freeglut在opengl中渲染,我创建了一个带有emmiter和forcefield的粒子系统,它们运行良好。
我要把火放在大学项目的旧火车上,我用纹理球来模拟它。
代码会很长,我很抱歉,但一切都很重要,这里是:
#include <GL/freeglut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <SOIL/SOIL.h>
#include <glm/glm.hpp>
#include <deque> using namespace std;
typedef glm::vec3 Vector3;
struct Force { private :
float strength;
Vector3 orentation; public :
Force(const Vector3 &v,const float &s)
:strength(s),orentation(v)
{
}
Force(const Force &f)
:strength(f.strength),orentation(f.orentation)
{
}
float getStrength() const
{
return strength;
}
Vector3 getOrentation() const
{
return orentation;
} };
class Particle { public :
Vector3 velocity,position;
const float mass;
float *deltatime;
float lifebegin;
Particle(const Vector3 &pos,const float &m,float *dt,const float &life)
:velocity(Vector3()),position(pos),mass(m),deltatime(dt),lifebegin(life)
{
}
void applyforce(const Force &f)
{
Vector3 force=f.getOrentation()*f.getStrength();
Vector3 accleration=force/mass;
velocity+=accleration*(*deltatime);
proceedintime();
}
void proceedintime()
{
position+=velocity*(*deltatime);
}
virtual void draw()const=0;
virtual bool collide(Particle *p)const=0;
virtual ~Particle()
{
} }; class TexturedParticle : public Particle { protected :
unsigned int textureid; public:
TexturedParticle(const Vector3 &pos,const float &m,float *dt,const float &life,const unsigned int &tex)
:Particle(pos,m,dt,life),textureid(tex)
{
}
virtual ~TexturedParticle()
{
}
}; class Emmiter; class ForceField;
class ParticleSystem {
friend class Emmiter;
friend class ForceField; private :
deque<Particle*> particles;
float elapsedtime;
float *deltatime;
float LifeOfParticles;
unsigned short particlesperframe; public :
ParticleSystem(const float &life,float *dt)
:elapsedtime(0),deltatime(dt),LifeOfParticles(life)
{
}
void deleteparticles()
{
float div=fmod(elapsedtime,LifeOfParticles);
if(div==0)
{
deque<Particle*>::const_iterator begin=particles.begin();
deque<Particle*>::const_iterator end=particles.end();
for(deque<Particle*>::const_iterator it=begin;it!=end;it++)
delete (*it);
particles.clear();
}
}
void drawparticl1es()
{
deque<Particle*>::const_iterator begin=particles.begin();
deque<Particle*>::const_iterator end=particles.end();
for(deque<Particle*>::const_iterator it=begin;it!=end;it++)
{
(*it)->proceedintime();
(*it)->draw();
}
elapsedtime+=(*deltatime);
} };
class Emmiter { public :
unsigned short ParticlesPerSecond;
Vector3 position;
ParticleSystem *ps;
unsigned char count;
float *deltatime;
Particle *(*emitfunc)(const Emmiter &em);
Emmiter(const unsigned short &parpersec,const Vector3 &pos,ParticleSystem *p,const unsigned char &c)
:ParticlesPerSecond(parpersec),position(pos),ps(p),count(c)
{
}
unsigned short particlesperframe()const
{
return ParticlesPerSecond*(*deltatime);
}
void emitparticles()const
{
unsigned short numpars=particlesperframe();
Particle *p=0;
for(unsigned char i=0;i<count;i++)
{
for(unsigned short j=0;j<numpars;j++)
{
p=emitfunc(*this);
p->lifebegin=ps->elapsedtime;
ps[i].particles.push_back(p);
}
}
} }; class ForceField { private :
Vector3 center;
float radius,MaxAcceleration;
unsigned char count;
ParticleSystem *pars; public:
ForceField(const Vector3 &cen,const float &r,const float &mf,ParticleSystem *ps,const unsigned char &c);
void applyforceonparticle(Particle *p)const;
void applyforceonsystems()const; };
ForceField::ForceField(const Vector3 &cen,const float &r,const float
&mf,ParticleSystem *ps,const unsigned char &c)
:center(cen),radius(r),MaxAcceleration(mf),count(c),pars(ps) {
}
void ForceField::applyforceonsystems() const {
for(unsigned char i=0;i<count;i++)
{
ParticleSystem p=pars[i];
for(deque<Particle*>::const_iterator it=p.particles.begin();it!=p.particles.end();it++)
{
applyforceonparticle(*it);
}
} }
void ForceField::applyforceonparticle(Particle *p) const {
Vector3 orentation=center-p->position;
float strength=1-orentation.length()/radius;
if(strength<=0)
return;
p->applyforce(Force(orentation,strength*MaxAcceleration*p->mass)); }
class BallParticle:public TexturedParticle { public :
float radius;
BallParticle(const Vector3 &pos,const float &r,const float &m,float *dt,const float &life,const unsigned int &tex)
:TexturedParticle(pos,m,dt,life,tex),radius(r)
{
}
void draw() const
{
glPushMatrix();
glBindTexture(GL_TEXTURE_2D,textureid);
glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius,10,10);
glPopMatrix();
}
bool collide(Particle *p) const
{
BallParticle *b=dynamic_cast<BallParticle*>(p);
return (b)&&((b->position-position).length()<=b->radius+radius);
} }; using namespace std;
float deltatime; float oldtime; float newtime; GLuint texture;
ParticleSystem pars(1,&deltatime); Emmiter
emmiter(100,Vector3(0,0,0),&pars,1); ForceField
f(Vector3(0,0.5f,0),0.5f,0.1f,&pars,1);
float myrand(const float &min,const float &max) {
return min+(max-min)*(float(rand())/float(RAND_MAX)); }
Particle *emitfunction(const Emmiter &em) {
float x=em.position.x,y=em.position.y;
BallParticle *b=new BallParticle(Vector3(myrand(x-1,x+1),myrand(y-1,y+1),em.position.z),1,2,&deltatime,0.0f,texture);
b->velocity=Vector3(0,1,0);
return b; }
GLuint GetTextId(const char *texture_name) {
return(SOIL_load_OGL_texture(
texture_name,
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_POWER_OF_TWO
));
}
/* GLUT callback Handlers */ void resize(int width, int height) {
glViewport(0, 0, width, height);
/*glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,(4/3.0f),2,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camera.LookAt();*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45,(float)width/(float)height,0.1f,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( 0, 0, 10, 0, 0, 0, 0, 1, 0 ); }
void display() {
glClear(GL_COLOR_BUFFER_BIT);
newtime=glutGet(GLUT_ELAPSED_TIME)/1000;
deltatime=newtime-oldtime;
oldtime=newtime;
pars.drawparticl1es();
glutSwapBuffers(); } void idle() {
emmiter.emitparticles();
f.applyforceonsystems();
pars.deleteparticles();
glutPostRedisplay(); }
void init() {
const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 0.0f };
const GLfloat light_diffuse[] = { 1, 0.5f, 0.0f, 1.0f };
const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat light_position[] = { 0.0f, 0.0f, 0.0f, 1.0f };
const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat high_shininess[] = { 100.0f };
const GLfloat mat_emissive[]={1,0.5f,0,1};
glClearColor(0, 0, 0, 0);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_TEXTURE_2D);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
glMaterialfv(GL_FRONT,GL_EMISSION,mat_emissive);
//glShadeModel(GL_SMOOTH);
//glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE); }
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(300,200);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("Fire");
glutReshapeFunc(resize);
glutDisplayFunc(display);
glutIdleFunc(idle);
init();
oldtime=glutGet(GLUT_ELAPSED_TIME)/1000;
emmiter.emitfunc=&emitfunction;
emmiter.deltatime=&deltatime;
texture=GetTextId("/home/abd/graphics/fire2.jpg");
glutMainLoop();
return EXIT_SUCCESS;
}
这是我使用的纹理:
火势看起来有点好,但我中间还有一个空洞,粒子也不能顺利移动。
我试过这些东西:
1 - 改变力场的强度和半径:没有效果。
2 - 增加每秒的粒子数量:没有工作,仍然看到了洞。
3 - 我让我的粒子变得更大:它使火看起来更好,洞几乎消失了(差不多,它有点过去了)但是我在火周围得到奇怪的曲线并且它仍然没有顺利移动。4 - 我有双缓冲,我在idle函数中调用了glutPostRedisplay,它们仍然没有顺利移动,我尝试删除了PERSPECTIVE NICEST和SMOOTH_SHADING_MODEL的提示,我使用了glutSolidSphere使用新的opengl功能,我有Nvidia GT9400和最新版本的更新驱动程序,但他们仍然没有顺利移动。
那么如何解决这两个问题?
因为这是一个大学项目,我不想要代码,&#34;哪里是错误&#34;已经足够了,我知道它就能解决它。
算法没问题但不是代码。
这是输出的屏幕截图:
正如你所看到的,中间有一个小洞,围着火焰弯曲。
答案 0 :(得分:0)
https://www.opengl.org/sdk/docs/man2/xhtml/glBlendFunc.xml
这是一个很好的观察者,了解这些参数的作用