如何将粒子系统角度扩展扩展到 3 个维度
How to expand particle system angle spread to 3 dimensions
我想了解如何为 3D 粒子系统实现角度扩展,以实现类似于喷泉的效果。我可以让它为 2D 系统工作,但不能为 3D 系统工作。我真的很感激任何帮助,因为我已经尝试了几乎所有的方法。
这是我正在做的事情:
计算一个介于 -180 到 +180 之间的初始随机角度。 spreadAmount 是一个从 0.0 到 1.0 的浮点数,用于控制传播程度。
float velangrnd = spreadAmount * ((((double)(rand() % RAND_MAX) / (RAND_MAX)) - 0.5) * 360.0 * 3.14159265359 / 180.0);
计算角度:
float vsin_anglex_dir = -SIN(velangrnd);
float vcos_anglex_dir = -COS(velangrnd);
最后,计算角度扩展。 Vel是速度从0-1:
// XY Spread
float px0 = (vel * vsin_anglex_dir);
float py0 = (vel * vcos_anglex_dir);
float pz0 = 0;
之后,我简单地计算屏幕位置。 x, y, z 是发射器坐标:
px0 = x + px0 * time;
py0 = y + py0 * time;
pz0 = z + pz0 * time;
当 spreadAmount 为 1.0 时,这会在 XY 轴上创建一个完美的粒子圆。换句话说,粒子将根据速度 (vel) 以 360 度射出。在较低的值下,它将创建一个 2D 喷泉效果。
但是,无论我怎么尝试,我都无法将其扩展到第二个轴。我正在尝试创建一个 3D 喷泉。因此,一个轴向外射出粒子,另一个轴在一个方向上增加随机扩散角,第三个轴在另一个方向上增加随机扩散角。因此,一个喷泉。
在我拔掉剩余的头发之前,是否有关于如何执行此操作的任何建议?
谢谢!
在 3D 中你需要主方向单位向量 t
和你的角度 a
从中你创建 2 个基本向量 u,v
垂直于每个和 t
然后你构建你的随机方向......像这样(如果我没有犯任何愚蠢的错误):
float a=?,b,r;
vec3 u,v,t=vec3(?,?,?),d;
// create u,v from t
u=vec3(1,0,0); // u is any non zero vector
if (fabs(dot(u,t))>0.75) u=vec3(0,1,0); // but not (anti)parallel to t
u=normalize(cross(u,t)); // make it perpendicular and unit
v=normalize(cross(u,t)); // make it perpendicular and unit
// compute random direction d
b=2.0*M_PI*Random(); // random angle
r=tan(0.5*a)*Random(); // random radius
d=normalize((r*u*cos(b))+(r*v*sin(b))+t);
所以基本上它的随机向量在圆锥内,其中 t
是中心轴,圆锥角是 a
。我使用了我的 GLSL_math.h 但是你可以使用任何向量数学,比如 GLM ...
[Edit1] 无库和组件智能版本
#include <math.h>
void normalize(float &x,float &y,float &z)
{
float l=sqrt((x*x)+(y*y)+(z*z));
if (l>1e-6) l=1.0/l; else l=0.0;
x*=l; y*=l; z*=l;
}
void cross(float &x,float &y,float &z, float ax,float ay,float az, float bx,float by,float bz)
{
x=(ay*bz)-(az*by);
y=(az*bx)-(ax*bz);
z=(ax*by)-(ay*bx);
}
void cone(float &dx,float &dy,float &dz, float tx,float ty,float tz, float a)
{
// (dx,dy,dz) <- random direction inside cone
// (tx,ty,tz) -> cone axis direction
// a -> cone angle in [rad]
float b,c,s,r;
float ux,uy,uz;
float vx,vy,vz;
// create u,v from t
ux=1.0; uy=0.0; uz=0.0; // u is any non zero vector
if (fabs((ux*tx)+(uy*ty)+(uz*tz))>0.75) // but not (anti)parallel to t
{ ux=0.0; uy=1.0; uz=0.0; }
cross(ux,uy,uz, ux,uy,uz, tx,ty,tz); // make it perpendicular
normalize(ux,uy,uz); // make it unit
cross(vx,vy,vz, ux,uy,uz, tx,ty,tz); // make it perpendicular
normalize(vx,vy,vz); // make it unit
// compute random direction d
b=2.0*M_PI*Random(); // random angle
r=tan(0.5*a)*Random(); // random radius
c=r*cos(b); s=r*sin(b);
dx=(ux*c)+(vx*s)+tx; // random direction inside cone
dy=(uy*c)+(vy*s)+ty;
dz=(uz*c)+(vz*s)+tz;
normalize(dx,dy,dz); // make it unit
}
如果您对矢量数学方程式(甚至数组版本的实现)感兴趣,请点击此处(底部附近的 Edit2):
使用数组甚至 类 更方便(与以前的版本相比,数量更少,代码更清晰)。
[Edit2] 更好的版本使用球坐标允许传播 <0 , 2*PI> [rad]
具有“均匀”分布
我正在考虑将我的圆锥方法与球坐标系合并以避免矩形圆锥帽......结果如下:
vec3 rnd_dir(vec3 t,float spread)
{
vec3 b,n;
float a,r,x,y,z;
static const float pih=0.5*M_PI;
static const float _pih=2.0/M_PI;
// (x,y,z) = unit spread where +x is main direction (central axis)
x=Random(); // random angle within spread scaled to <0,1>
a=x*spread*0.5; // random angle within spread [rad]
if (a>pih) // linearize the point distribution (avoid high density on poles)
{
a=M_PI-a;
a=sqrt(a*_pih)*pih; // sqrt looks good probably because surface area is scaled with ^2
a=M_PI-a;
}
else{
a=sqrt(a*_pih)*pih; // sqrt looks good probably because surface area is scaled with ^2
}
x=cos(a); // convert angle to main axis coordinate
r=sqrt(1.0-(x*x)); // max radius of cone cap still inside unit sphere
a=Random()*2.0*M_PI; // random polar angle inside the cone cap [rad]
y=r*cos(a);
z=r*sin(a);
// create normal n, binormal b from tangent t ... TBN matrix
// t=normalize(t); // t should be unit if it is not uncomment this line
n=vec3(1,0,0); // n is any non zero vector
if (fabs(dot(n,t))>0.75) n=vec3(0,1,0); // but not (anti)parallel to t
n=normalize(cross(n,t)); // make it perpendicular and unit
b=normalize(cross(n,t)); // make it perpendicular and unit
// convert (x,y,z) so t is main direction
return (t*x)+(b*y)+(n*z);
}
它再次使用 vec3
(我懒得在 x,y,z
中编写代码)但是轴对齐展开生成本身根本不使用向量,因此您可以直接使用它并使用转换到 t,b,n
从以前的版本 (t,u,v)
相同...
此处预览所有步长为 5 度的价差(1000 点):
在 OpenGL 中渲染如下:
void gl_draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.5);
static float a=0.0; a+=5.5; if (a>360.0) a-=360.0;
a=-75.0;
glRotatef(a,0.0,1.0,0.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
int i;
vec3 d,t=normalize(vec3(1.0,0.5,-0.2));
Randomize();
RandSeed=0x1234567;
glPointSize(1);
glBegin(GL_POINTS);
glColor3f(0.1,0.8,1.0);
for (i=0;i<1000;i++)
{
d=rnd_dir(t,spread);
glVertex3fv(d.dat);
}
glEnd();
glPointSize(1);
glFlush();
SwapBuffers(hdc);
}
其中float spread=M_PI;
是用鼠标滚轮改变的全局变量...
我想了解如何为 3D 粒子系统实现角度扩展,以实现类似于喷泉的效果。我可以让它为 2D 系统工作,但不能为 3D 系统工作。我真的很感激任何帮助,因为我已经尝试了几乎所有的方法。
这是我正在做的事情:
计算一个介于 -180 到 +180 之间的初始随机角度。 spreadAmount 是一个从 0.0 到 1.0 的浮点数,用于控制传播程度。
float velangrnd = spreadAmount * ((((double)(rand() % RAND_MAX) / (RAND_MAX)) - 0.5) * 360.0 * 3.14159265359 / 180.0);
计算角度:
float vsin_anglex_dir = -SIN(velangrnd);
float vcos_anglex_dir = -COS(velangrnd);
最后,计算角度扩展。 Vel是速度从0-1:
// XY Spread
float px0 = (vel * vsin_anglex_dir);
float py0 = (vel * vcos_anglex_dir);
float pz0 = 0;
之后,我简单地计算屏幕位置。 x, y, z 是发射器坐标:
px0 = x + px0 * time;
py0 = y + py0 * time;
pz0 = z + pz0 * time;
当 spreadAmount 为 1.0 时,这会在 XY 轴上创建一个完美的粒子圆。换句话说,粒子将根据速度 (vel) 以 360 度射出。在较低的值下,它将创建一个 2D 喷泉效果。
但是,无论我怎么尝试,我都无法将其扩展到第二个轴。我正在尝试创建一个 3D 喷泉。因此,一个轴向外射出粒子,另一个轴在一个方向上增加随机扩散角,第三个轴在另一个方向上增加随机扩散角。因此,一个喷泉。
在我拔掉剩余的头发之前,是否有关于如何执行此操作的任何建议?
谢谢!
在 3D 中你需要主方向单位向量 t
和你的角度 a
从中你创建 2 个基本向量 u,v
垂直于每个和 t
然后你构建你的随机方向......像这样(如果我没有犯任何愚蠢的错误):
float a=?,b,r;
vec3 u,v,t=vec3(?,?,?),d;
// create u,v from t
u=vec3(1,0,0); // u is any non zero vector
if (fabs(dot(u,t))>0.75) u=vec3(0,1,0); // but not (anti)parallel to t
u=normalize(cross(u,t)); // make it perpendicular and unit
v=normalize(cross(u,t)); // make it perpendicular and unit
// compute random direction d
b=2.0*M_PI*Random(); // random angle
r=tan(0.5*a)*Random(); // random radius
d=normalize((r*u*cos(b))+(r*v*sin(b))+t);
所以基本上它的随机向量在圆锥内,其中 t
是中心轴,圆锥角是 a
。我使用了我的 GLSL_math.h 但是你可以使用任何向量数学,比如 GLM ...
[Edit1] 无库和组件智能版本
#include <math.h>
void normalize(float &x,float &y,float &z)
{
float l=sqrt((x*x)+(y*y)+(z*z));
if (l>1e-6) l=1.0/l; else l=0.0;
x*=l; y*=l; z*=l;
}
void cross(float &x,float &y,float &z, float ax,float ay,float az, float bx,float by,float bz)
{
x=(ay*bz)-(az*by);
y=(az*bx)-(ax*bz);
z=(ax*by)-(ay*bx);
}
void cone(float &dx,float &dy,float &dz, float tx,float ty,float tz, float a)
{
// (dx,dy,dz) <- random direction inside cone
// (tx,ty,tz) -> cone axis direction
// a -> cone angle in [rad]
float b,c,s,r;
float ux,uy,uz;
float vx,vy,vz;
// create u,v from t
ux=1.0; uy=0.0; uz=0.0; // u is any non zero vector
if (fabs((ux*tx)+(uy*ty)+(uz*tz))>0.75) // but not (anti)parallel to t
{ ux=0.0; uy=1.0; uz=0.0; }
cross(ux,uy,uz, ux,uy,uz, tx,ty,tz); // make it perpendicular
normalize(ux,uy,uz); // make it unit
cross(vx,vy,vz, ux,uy,uz, tx,ty,tz); // make it perpendicular
normalize(vx,vy,vz); // make it unit
// compute random direction d
b=2.0*M_PI*Random(); // random angle
r=tan(0.5*a)*Random(); // random radius
c=r*cos(b); s=r*sin(b);
dx=(ux*c)+(vx*s)+tx; // random direction inside cone
dy=(uy*c)+(vy*s)+ty;
dz=(uz*c)+(vz*s)+tz;
normalize(dx,dy,dz); // make it unit
}
如果您对矢量数学方程式(甚至数组版本的实现)感兴趣,请点击此处(底部附近的 Edit2):
使用数组甚至 类 更方便(与以前的版本相比,数量更少,代码更清晰)。
[Edit2] 更好的版本使用球坐标允许传播 <0 , 2*PI> [rad]
具有“均匀”分布
我正在考虑将我的圆锥方法与球坐标系合并以避免矩形圆锥帽......结果如下:
vec3 rnd_dir(vec3 t,float spread)
{
vec3 b,n;
float a,r,x,y,z;
static const float pih=0.5*M_PI;
static const float _pih=2.0/M_PI;
// (x,y,z) = unit spread where +x is main direction (central axis)
x=Random(); // random angle within spread scaled to <0,1>
a=x*spread*0.5; // random angle within spread [rad]
if (a>pih) // linearize the point distribution (avoid high density on poles)
{
a=M_PI-a;
a=sqrt(a*_pih)*pih; // sqrt looks good probably because surface area is scaled with ^2
a=M_PI-a;
}
else{
a=sqrt(a*_pih)*pih; // sqrt looks good probably because surface area is scaled with ^2
}
x=cos(a); // convert angle to main axis coordinate
r=sqrt(1.0-(x*x)); // max radius of cone cap still inside unit sphere
a=Random()*2.0*M_PI; // random polar angle inside the cone cap [rad]
y=r*cos(a);
z=r*sin(a);
// create normal n, binormal b from tangent t ... TBN matrix
// t=normalize(t); // t should be unit if it is not uncomment this line
n=vec3(1,0,0); // n is any non zero vector
if (fabs(dot(n,t))>0.75) n=vec3(0,1,0); // but not (anti)parallel to t
n=normalize(cross(n,t)); // make it perpendicular and unit
b=normalize(cross(n,t)); // make it perpendicular and unit
// convert (x,y,z) so t is main direction
return (t*x)+(b*y)+(n*z);
}
它再次使用 vec3
(我懒得在 x,y,z
中编写代码)但是轴对齐展开生成本身根本不使用向量,因此您可以直接使用它并使用转换到 t,b,n
从以前的版本 (t,u,v)
相同...
此处预览所有步长为 5 度的价差(1000 点):
在 OpenGL 中渲染如下:
void gl_draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.5);
static float a=0.0; a+=5.5; if (a>360.0) a-=360.0;
a=-75.0;
glRotatef(a,0.0,1.0,0.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
int i;
vec3 d,t=normalize(vec3(1.0,0.5,-0.2));
Randomize();
RandSeed=0x1234567;
glPointSize(1);
glBegin(GL_POINTS);
glColor3f(0.1,0.8,1.0);
for (i=0;i<1000;i++)
{
d=rnd_dir(t,spread);
glVertex3fv(d.dat);
}
glEnd();
glPointSize(1);
glFlush();
SwapBuffers(hdc);
}
其中float spread=M_PI;
是用鼠标滚轮改变的全局变量...