效果演示:
脚本如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace PhysicsLab
{public class RopeSolver : MonoBehaviour {public Transform ParticlePrefab;public int Count = 3;public int Space = 1;[Range(0, 1)]public float Damping = 0.1f;public Vector3 ExternForce = Vector3.zero;public int SolveCount = 1;[Header("Collider")]public RopeSphereCollider sphereCollider;private List<Transform> chain = new List<Transform>();private List<Particle> particleList = new List<Particle>();void Start(){for (int i=0; i<Count; i++){var obj = Instantiate(ParticlePrefab, transform, true);obj.Translate(0, -i * Space, 0);chain.Add(obj);// Construct Particlesvar particle = new Particle();particle.radius = 0.5f * Space;particle.pos = particle.prevPos = new Vector3(0, -i * Space, 0);particle.velocity = Vector3.zero;particleList.Add(particle);}}void FixedUpdate (){// Update Velocityfor (int i=0; i<Count; i++){var particle = particleList[i];// Verlet IntegrationVector3 vel = particle.velocity + ExternForce * Time.fixedDeltaTime * Time.fixedDeltaTime;particle.prevPos = particle.pos;particle.pos = particle.pos + (1-Damping) * vel;}// Resolve Constraints// 1. Attach Root Particle to base transformparticleList[0].pos = transform.position;// 2. Keep Length Constraint from top to bottomfor (int n=0; n<SolveCount; n++){for (int i=1; i<Count; i++){Vector3 offsetToParent = particleList[i].pos - particleList[i-1].pos;// Strategy 1: only move child particle//particleList[i].pos = particleList[i-1].pos + Space * offsetToParent.normalized;// Strategy 2: Position Based Dynamics, iterativelyoffsetToParent = Space * offsetToParent.normalized - offsetToParent;particleList[i-1].pos -= 0.5f * offsetToParent;particleList[i].pos += 0.5f * offsetToParent;}// Attach Root Particle to base transformparticleList[0].pos = transform.position;}// Collision Detection & Responseif (sphereCollider != null){for (int i=0; i<Count; i++){sphereCollider.UpdateCollision(particleList[i]);}}// Update velocityfor (int i=0; i<Count; i++){particleList[i].velocity = particleList[i].pos - particleList[i].prevPos;}// Apply Particle Data to Transformfor (int i=0; i<Count; i++){chain[i].position = particleList[i].pos;}}}public class Particle{public float radius;public Vector3 pos;public Vector3 prevPos;public Vector3 velocity;}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace PhysicsLab
{[RequireComponent(typeof(Transform))]public class RopeSphereCollider : MonoBehaviour {private Transform sphereTfm;void OnEnable(){sphereTfm = GetComponent<Transform>();}public void UpdateCollision(Particle particle){Vector3 colliderCenter = sphereTfm.position;float colliderR = sphereTfm.lossyScale.x * 0.5f;Vector3 offset = particle.pos - colliderCenter;if (offset.magnitude < colliderR + particle.radius) // Collision Detected{// Collision Responseparticle.pos = colliderCenter + offset.normalized * (colliderR + particle.radius);}}}
}
源码下载链接: https://download.csdn.net/download/qq_41603955/90086948