原理
很好奇糖豆人这种软体效果是怎么实现的,于是查看了一些资料了解到可以通过改变mesh来使物体产生不一样的渲染效果。
主要通过类似弹簧的效果,点击物体后改变该物体的vertices,某个点离施力点越近则给它的初速度越大。初速度根据该点移动的距离慢慢减小,当减小为0后再次反弹至原点。
实现
外部接口为AddForce函数
using UnityEngine;
public class softBodyTest : MonoBehaviour {
Mesh mesh;
Vector3[] originalVertices;//原来的点
Vector3[] displacedVertices;//改变后的点
Vector3[] vertexVelocities;//每个点的当前速度
[Header("弹簧力")]
public float springForce = 20f;
[Header("弹簧阻尼")]
public float damping = 5;
// Use this for initialization
void Start() {
mesh = GetComponent<MeshFilter>().mesh;
originalVertices = mesh.vertices;
displacedVertices = new Vector3[originalVertices.Length];
for (int i = 0; i < displacedVertices.Length; i++)
{
displacedVertices[i] = originalVertices[i];
}
vertexVelocities = new Vector3[originalVertices.Length];
}
void Update () {
for (int i = 0; i < displacedVertices.Length; i++)
{
var velocity = vertexVelocities[i];
Vector3 displacement = displacedVertices[i] - originalVertices[i];
velocity -= displacement * springForce * Time.deltaTime;//减小的加速度与弹簧力有关 该点与原点的距离相当于弹簧的压缩量
velocity *= 1f - damping * Time.deltaTime;//防止弹簧反复横跳,增加阻尼
vertexVelocities[i] = velocity;
displacedVertices[i] += velocity * Time.deltaTime;
}
mesh.vertices = displacedVertices;
mesh.RecalculateNormals();
}
public void AddForce(Vector3 point, Vector3 direction, float force)
{
Debug.DrawLine(Camera.main.transform.position, point);
point = transform.InverseTransformPoint(point);
for (int i = 0; i < displacedVertices.Length; i++)
{
AddForceToVertex(i, point, direction, force);
}
}
private void AddForceToVertex(int i, Vector3 point,Vector3 direction, float force)
{
var pointToVertex = displacedVertices[i] - point;
float attenuateForce = force / (0.1f + pointToVertex.sqrMagnitude); //距离越近力越大
float velocity = attenuateForce * Time.deltaTime;
vertexVelocities[i] -= direction.normalized * velocity; //初速度
}
}
测试代码
if (Input.GetMouseButton(0))
{
Ray inputRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(inputRay, out hit))
{
var testScript = hit.collider.GetComponent<softBodyTest>();
if (testScript)
{
var point = hit.point;
testScript.AddForce(point, hit.normal, force);
}
}
}
最终效果