天空鸟群模拟,海底鱼群模拟效果


每个单独的鱼都会有独立的行为:
- 1.自由移动行为,
- 2.躲避前方范围物体的行为(包括鱼)
- 3.跟随鱼并保持距离的行为(形成鱼群)
- 4.随时跟随最近的鱼群(分离与对齐)
躲避行为算法效果图

核心代码:
(仅提供算法参考,无法使其单独运行)
public class Boid : MonoBehaviour {
BoidSettings settings;
// State
[HideInInspector]
public Vector3 position;
[HideInInspector]
public Vector3 forward;
Vector3 velocity;
// To update:
Vector3 acceleration;
[HideInInspector]
public Vector3 avgFlockHeading;
[HideInInspector]
public Vector3 avgAvoidanceHeading;
[HideInInspector]
public Vector3 centreOfFlockmates;
[HideInInspector]
public int numPerceivedFlockmates;
// Cached
Material material;
Transform cachedTransform;
Transform target;
void Awake () {
material = transform.GetComponentInChildren<MeshRenderer> ().material;
cachedTransform = transform;
}
public void Initialize (BoidSettings settings, Transform target) {
this.target = target;
this.settings = settings;
position = cachedTransform.position;
forward = cachedTransform.forward;
float startSpeed = (settings.minSpeed + settings.maxSpeed) / 2;
velocity = transform.forward * startSpeed;
}
public void SetColour (Color col) {
if (material != null) {
material.color = col;
}
}
public void UpdateBoid () {
Vector3 acceleration = Vector3.zero;
if (target != null) {
Vector3 offsetToTarget = (target.position - position);
acceleration = SteerTowards (offsetToTarget) * settings.targetWeight;
}
if (numPerceivedFlockmates != 0) {
centreOfFlockmates /= numPerceivedFlockmates;
Vector3 offsetToFlockmatesCentre = (centreOfFlockmates - position);
var alignmentForce = SteerTowards (avgFlockHeading) * settings.alignWeight;
var cohesionForce = SteerTowards (offsetToFlockmatesCentre) * settings.cohesionWeight;
var seperationForce = SteerTowards (avgAvoidanceHeading) * settings.seperateWeight;
acceleration += alignmentForce;
acceleration += cohesionForce;
acceleration += seperationForce;
}
if (IsHeadingForCollision ()) {
Vector3 collisionAvoidDir = ObstacleRays ();
Vector3 collisionAvoidForce = SteerTowards (collisionAvoidDir) * settings.avoidCollisionWeight;
acceleration += collisionAvoidForce;
}
velocity += acceleration * Time.deltaTime;
float speed = velocity.magnitude;
Vector3 dir = velocity / speed;
speed = Mathf.Clamp (speed, settings.minSpeed, settings.maxSpeed);
velocity = dir * speed;
cachedTransform.position += velocity * Time.deltaTime;
cachedTransform.forward = dir;
position = cachedTransform.position;
forward = dir;
}
bool IsHeadingForCollision () {
RaycastHit hit;
if (Physics.SphereCast (position, settings.boundsRadius, forward, out hit, settings.collisionAvoidDst, settings.obstacleMask)) {
return true;
} else { }
return false;
}
Vector3 ObstacleRays () {
Vector3[] rayDirections = BoidHelper.directions;
for (int i = 0; i < rayDirections.Length; i++) {
Vector3 dir = cachedTransform.TransformDirection (rayDirections[i]);
Ray ray = new Ray (position, dir);
if (!Physics.SphereCast (ray, settings.boundsRadius, settings.collisionAvoidDst, settings.obstacleMask)) {
return dir;
}
}
return forward;
}
Vector3 SteerTowards (Vector3 vector) {
Vector3 v = vector.normalized * settings.maxSpeed - velocity;
return Vector3.ClampMagnitude (v, settings.maxSteerForce);
}
}
public class BoidManager : MonoBehaviour {
const int threadGroupSize = 1024;
public BoidSettings settings;
public ComputeShader compute;
Boid[] boids;
void Start () {
boids = FindObjectsOfType<Boid> ();
foreach (Boid b in boids) {
b.Initialize (settings, null);
}
}
void Update () {
if (boids != null) {
int numBoids = boids.Length;
var boidData = new BoidData[numBoids];
for (int i = 0; i < boids.Length; i++) {
boidData[i].position = boids[i].position;
boidData[i].direction = boids[i].forward;
}
var boidBuffer = new ComputeBuffer (numBoids, BoidData.Size);
boidBuffer.SetData (boidData);
compute.SetBuffer (0, "boids", boidBuffer);
compute.SetInt ("numBoids", boids.Length);
compute.SetFloat ("viewRadius", settings.perceptionRadius);
compute.SetFloat ("avoidRadius", settings.avoidanceRadius);
int threadGroups = Mathf.CeilToInt (numBoids / (float) threadGroupSize);
compute.Dispatch (0, threadGroups, 1, 1);
boidBuffer.GetData (boidData);
for (int i = 0; i < boids.Length; i++) {
boids[i].avgFlockHeading = boidData[i].flockHeading;
boids[i].centreOfFlockmates = boidData[i].flockCentre;
boids[i].avgAvoidanceHeading = boidData[i].avoidanceHeading;
boids[i].numPerceivedFlockmates = boidData[i].numFlockmates;
boids[i].UpdateBoid ();
}
boidBuffer.Release ();
}
}
public struct BoidData {
public Vector3 position;
public Vector3 direction;
public Vector3 flockHeading;
public Vector3 flockCentre;
public Vector3 avoidanceHeading;
public int numFlockmates;
public static int Size {
get {
return sizeof (float) * 3 * 5 + sizeof (int);
}
}
}
}
public static class BoidHelper {
const int numViewDirections = 300;
public static readonly Vector3[] directions;
static BoidHelper () {
directions = new Vector3[BoidHelper.numViewDirections];
float goldenRatio = (1 + Mathf.Sqrt (5)) / 2;
float angleIncrement = Mathf.PI * 2 * goldenRatio;
for (int i = 0; i < numViewDirections; i++) {
float t = (float) i / numViewDirections;
float inclination = Mathf.Acos (1 - 2 * t);
float azimuth = angleIncrement * i;
float x = Mathf.Sin (inclination) * Mathf.Cos (azimuth);
float y = Mathf.Sin (inclination) * Mathf.Sin (azimuth);
float z = Mathf.Cos (inclination);
directions[i] = new Vector3 (x, y, z);
}
}
}
是不是感觉很复杂,代码我没有放全,因为实在有点多
点击👇下载Demo
Demo

本文介绍了一种基于Unity的鱼群模拟算法,通过实现躲避、跟随等行为使虚拟鱼群展现出逼真效果。核心代码涉及碰撞检测、方向调整及群体行为等关键技术。
2412

被折叠的 条评论
为什么被折叠?



