主题:粒子系统
woshihanjin
[专家分:2510] 发布于 2004-04-29 23:52:00
由粒子系统(5000个粒子)实现的黄金火焰十字架。
平台DOS + Watcom C
[img]http://www.wodutom.com/coolwindows/10z.PNG[/img]
这个是50000个粒子形成的粒子星云
[img]http://www.wodutom.com/coolwindows/star.PNG[/img]
#include <i86.h>
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include "x\xsvga.hpp"
#include "x\xtimer.hpp"
#include "x\xkey.hpp"
#include "x\xpsystem.hpp"
#include "x\xmath.hpp"
cMath *pmath;
int angle=0;
/*坐标更新*/
cParticleF2D& drop(cParticleF2D& x,cParameterQueue& paras)
{
float t;
paras.Peek(&t);
x.vx+=x.ax*t;
x.vy+=x.ay*t;
x.x+=x.vx*t;
x.y+=x.vy*t;
return x;
}
/*坐标转换并显示*/
cParticleF2D& draw(cParticleF2D& x,cParameterQueue& paras)
{
cBitmap *bmp;
paras.Peek(&bmp);
char *p;
long dx,dy;
dx=(x.x-400)*pmath->fcos(angle)-(300-x.y)*pmath->fsin(angle)+400;
dy=(x.x-400)*pmath->fsin(angle)+(300-x.y)*pmath->fcos(angle)+300;
if(dx>0&&dx<799&&dy>0&&dy<599)
{
p=(char *)bmp->GetBuffer(dx,600-dy);
bmp->Set(p,&x.C);
}
if(dx<0||dx>=800) x.vx=-x.vx;
if(dy<0||dy>=600) x.vy=-x.vy;
return x;
}
void main()
{
long i;
float t=0.01;
cTimer timer;
cSVGA* svga=cSVGA::Instance();
float RGB[256][3];
cBitmap bmp;
pmath=cMath::Instance();
cParticleF2D particle;
cParticleGroup<cParticleF2D> pg(50000,2); /*第一个例子是5000*/
memset(&particle,0,sizeof(particle));
particle.y=300;
particle.x=400;
particle.C=255;
for(i=0;i<50000;i++)
{
particle.ax=rand()%10191/1000.0-5; /*水平随机加速度*/
particle.ay=rand()%8191/1000.0-4; /*垂直随机加速度*/
pg.Add(particle);
}
pg.AddTransFunc(drop); /*绑定函数*/
pg.AddTransPara(&t); /*绑定参数*/
svga->SetMode(800,600,8,cSVGA::_c_linear);
bmp.Create(svga->GetDirectBuffer(),800,600,8);
cPALETTE pal;
for(i=0;i<256;i++) RGB[i][0]=sqrt(i)/16.0;
for(i=0;i<256;i++) RGB[i][1]=pow(i,0.7)/48.5;
for(i=0;i<256;i++) RGB[i][2]=(float)(i*i)/65536.0;
for(i=0;i<256;i++) pal[i].R=RGB[i][0]*256;
for(i=0;i<256;i++) pal[i].G=RGB[i][1]*256;
for(i=0;i<256;i++) pal[i].B=RGB[i][2]*256;
svga->SetPal(&pal);
pg.AddTransFunc(draw);
pg.AddTransPointPara(&bmp);
char *p,*q;
while(cKey::Asc()!=27)
{
/*自动对pg里面的每一个粒子调用绑定的函数*/
pg.Refresh();
/*全屏 Blur*/
for(p=(char *)bmp.GetBuffer(1,1),q=(char *)bmp.GetBuffer(bmp.Width()-2,bmp.Height()-2);p<q;p++)
*p=*(p-1)+*(p+1)+*(p-bmp.Width())+*(p+bmp.Width())>>2;
/*全屏 FadeOut*/
for(p=(char *)bmp.GetBuffer(0,0),q=(char *)bmp.GetBuffer(bmp.Width()-1,bmp.Height()-1);p<q;p++) if(*p>0) (*p)--;
angle++; /*第一个例子是angle+=0;*/
}
delete pmath;
delete svga;
}
回复列表 (共15个回复)
沙发
不游泳的鱼 [专家分:620] 发布于 2004-04-29 12:43:00
什么意思?[em10]
板凳
woshihanjin [专家分:2510] 发布于 2004-04-29 12:52:00
DOS下纯C++写的图像程序啊!
3 楼
woshihanjin [专家分:2510] 发布于 2004-04-29 13:03:00
可以为每一个粒子组独立绑定无限数量的坐标运算(vertex shader)或颜色运算(pixel shader)函数(可惜都是由CPU完成的,而且现在还不支持动态参数,用到只好用全局变量了(上面例子中的pmath->fcos(angle)就是一个动态参数,因为angle随时在变,如果做在参数表里就会因为不断刷新参数表冲击渲染流水线,严重降低效率,目前还没想到好的解决办法),要用显卡做还是只有OpenGL和DX,:)。由粒子组对象Refresh时统一调用。
4 楼
woshihanjin [专家分:2510] 发布于 2004-04-29 14:05:00
粒子系统主要可以用来实现物理模拟,比如自由落体、双(多)星系统、爆炸等,或某些自然效果,比如烟雨、瀑布等。
5 楼
guwei4250 [专家分:60] 发布于 2004-04-29 14:16:00
如果要编写这样的程序,至少要具备什么知识,你的这个程序激起了对这方面强列的兴趣
6 楼
woshihanjin [专家分:2510] 发布于 2004-04-29 14:22:00
至少要具备比较扎实的语言功底,能够很清楚自己在什么地方操作什么数据(指指针)
7 楼
不游泳的鱼 [专家分:620] 发布于 2004-04-29 16:48:00
TC3.0好象不能运行!![em8][em4]
8 楼
woshihanjin [专家分:2510] 发布于 2004-04-29 21:11:00
当然,里面缺很多函数没给出来,这个只是主程序
#include "x\xsvga.hpp"
#include "x\xtimer.hpp"
#include "x\xkey.hpp"
#include "x\xpsystem.hpp"
#include "x\xmath.hpp"
这些是自己写的.而且TC3.0是16位的,要32位的编译器才可以.
9 楼
woshihanjin [专家分:2510] 发布于 2004-04-30 11:09:00
/*可以在TC下运行的简化版,最好不要在XP/2000下运行,否则速度很慢*/
[img]http://www.wodutom.com/coolwindows/startc.png[/img]
#include<math.h>
#include<mem.h>
#include<dos.h>
#include<stdlib.h>
#define p_num 2000
struct _Particle
{
float vx,vy,ax,ay,x,y;
unsigned char c;
};
void SetColor(int c,int r,int g,int b)
{
outportb(0x3c6,255);
outportb(0x3c8,c);
outportb(0x3c9,r>>2);
outportb(0x3c9,g>>2);
outportb(0x3c9,b>>2);
}
char far *GetBuffer(long x,long y)
{
return (char far *)(0xa0000000L+x+y*320);
}
void blur()
{
unsigned char far *p, far *q;
for(p=GetBuffer(1,1),q=GetBuffer(318,198);p<q;p++) *p=*(p-1)+*(p+1)+*(p-320)+*(p+320)>>2;
}
void main()
{
struct _Particle pg[p_num];
float fcos,fsin,t=0.01,angle=0.0;
float RGB[256][3];
int i;
int dx,dy;
memset(pg,0,p_num*sizeof(struct _Particle));
for(i=0;i<p_num;i++)
{
pg[i].x=160;
pg[i].y=100;
pg[i].c=255;
pg[i].ax=rand()%10191/1000.0-5;
pg[i].ay=rand()%8191/1000.0-4;
}
for(i=0;i<256;i++) RGB[i][0]=sqrt(i)/16.0;
for(i=0;i<256;i++) RGB[i][1]=pow(i,0.7)/48.5;
for(i=0;i<256;i++) RGB[i][2]=(i*i)/65536.0;
_AX=0x13;
asm int 0x10;
for(i=0;i<256;i++) SetColor(i,RGB[i][0]*256,RGB[i][1]*256,RGB[i][2]*256);
while(inportb(0x60)!=1)
{
fcos=cos(angle);
fsin=sin(angle);
for(i=0;i<p_num;i++)
{
pg[i].vx+=pg[i].ax*t;
pg[i].vy+=pg[i].ay*t;
pg[i].x+=pg[i].vx*t;
pg[i].y+=pg[i].vy*t;
dx=(pg[i].x-160)*fcos-(100-pg[i].y)*fsin+160;
dy=(pg[i].x-160)*fsin+(100-pg[i].y)*fcos+100;
if(dx>0&&dx<319&&dy>0&&dy<199) *GetBuffer(dx,dy)=pg[i].c;
if(dx<0||dx>=320) pg[i].vx=-pg[i].vx;
if(dy<0||dy>=200) pg[i].vy=-pg[i].vy;
}
blur();
angle+=0.01;
}
_AX=0x03;
asm int 0x10;
}
10 楼
woshihanjin [专家分:2510] 发布于 2004-04-30 11:45:00
把粒子组初始化为直立椭圆,并在坐标系统中加入一些小幅度的随机运动分子,就可以做出如蜡烛火焰一样的动态效果。改变颜色基调,新建三个粒子组,让其一以不同的水平速度做抛物运动,到地面时回归原位,第二个组在地面做圆形振动,第三个组做爆炸效果,和起来就可以做成一个瀑布的效果。
我来回复