要求
本次作业基本要求是三选一
-
简单粒子制作
按参考资源要求,制作一个粒子系统,参考资源
使用 3.3 节介绍,用代码控制使之在不同场景下效果不一样
-
完善官方的“汽车尾气”模拟
使用官方资源资源 Vehicle 的 car, 使用 Smoke 粒子系统模拟启动发动、运行、故障等场景效果
-
参考 http://i-remember.fr/en 这类网站,使用粒子流编程控制制作一些效果, 如“粒子光环”
本次作业,我们选择第三个题目进行完成。
代码部分
- 我们要首先定义一个新的结构
CirclePosition
,用以记录每个粒子的当前半径、角度和时间,其中时间是做游离运动需要的
public class CirclePosition
{
public float radius = 0f, angle = 0f, time = 0f;
public CirclePosition(float radius, float angle, float time)
{
this.radius = radius;
this.angle = angle;
this.time = time;
}
}
- 然后我们需要预设粒子系统和粒子活动的一些系数,包括粒子的数量、大小、半径、旋转方向等等变量,并使用我们之前定义好的
CirclePosition
保存每个粒子对应的属性:
public int count = 10000; // number of particles
public bool clockwise = true; // towards
public float size = 0.03f; // size of particles
public float minRadius = 5.0f; // min radius
public float maxRadius = 12.0f; // max radius
public float speed = 2f; // speed
public float maxRadiusChange = 0.02f; // range
private NormalDistribution normalGenerator = new NormalDistribution(); // generator
public Color startColor = Color.blue; // color
- 执行初始化设置,粒子活动由编程控制,我们将粒子各个属性进行预设,包括初始速度设置成0,设置初始大小、最大粒子数量等等:
void Start()
{
particleArr = new ParticleSystem.Particle[count];
circle = new CirclePosition[count];
particleSys = this.GetComponent<ParticleSystem>();
var main = particleSys.main;
main.startSpeed = 0;
main.startSize = size;
main.loop = false;
main.maxParticles = count;
particleSys.Emit(count);
particleSys.GetParticles(particleArr);
RandomlySpread(); // init position
}
- 在
RandomlySpread
函数中,我们将所有的粒子随机分布在圆圈轨道上,这里要使用极坐标法生成符合高斯分布的伪随机数,所以我们先定义一个NormalDistribution
的类:
public class NormalDistribution
{
// The polar method
private bool _hasDeviate;
private double _storedDeviate;
private readonly Random _random;
public NormalDistribution(Random random = null)
{
_random = random ?? new Random();
}
public double NextGaussian(double mu = 0, double sigma = 1)
{
if (sigma <= 0)
throw new ArgumentOutOfRangeException("sigma", "Must be greater than zero.");
if (_hasDeviate)
{
_hasDeviate = false;
return _storedDeviate * sigma + mu;
}
double v1, v2, rSquared;
do
{
v1 = 2 * _random.NextDouble() - 1; // two random values between -1.0 and 1.0
v2 = 2 * _random.NextDouble() - 1;
rSquared = v1 * v1 + v2 * v2;
} while (rSquared >= 1 || rSquared == 0); // ensure within the unit circle
var polar = Math.Sqrt(-2 * Math.Log(rSquared) / rSquared); // calculate polar tranformation for each deviate
_storedDeviate = v2 * polar;
_hasDeviate = true;
return v1 * polar * sigma + mu;
}
}
- 使用刚才的类,利用高斯分布生成半径,均值为
midRadius
,标准差为0.7
float midRadius = (maxRadius + minRadius) / 2;
float radius = (float)normalGenerator.NextGaussian(midRadius, 0.7);
其他的参数我们也利用随机数的方式进行生成:
float angle = Random.Range(0.0f, 360.0f);
float theta = angle / 180 * Mathf.PI;
float time = Random.Range(0.0f, 360.0f);
float radiusChange = Random.Range(0.0f, maxRadiusChange);
材质和效果
设置好代码之后,我们还需要添加一些初始的颜色,形状等属性
-
粒子光圈的参数设置
主要是设置粒子多少、大小、初始颜色等刚才我们写成public的属性值:
-
然后针对粒子系统面板的属性进行设置:
粒子的发射设置:
粒子的形状设置:
粒子的渲染设置:
最后,我们还需要调整摄像机的属性,为了能够清楚地看到粒子效果,我们需要将摄影机模式改成Solid Color
并调整背景颜色为黑色,适当调整Y值和旋转之后,如下所示:
效果展示
最终我们看到的粒子效果如下所示: