网格变形效果——黏液效果

Posted CZandQZ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网格变形效果——黏液效果相关的知识,希望对你有一定的参考价值。

做的效果图如上,效果制作分为3个部分,一部分是挤压,一部分是拖拽,一部分是复原。

1 先说挤压吧,首先挤压有一个挤压区域,首先我们需要获取模型上所有的顶点并且模型的碰撞器会随着模型的变化而发生变化因为只有这样碰撞才会实时的发生反馈。定义挤压区域,判断所有的顶点是否在以鼠标位置为中心圆的挤压半径,如果在圆内那么它的y坐标向0插值。反之不会发生任何变化。

2 再说拖拽,拖拽也是需要判断拖拽区域,判断所有顶点是否在以鼠标位置为中心圆的拖拽半径,如果在园内的话,拖拽方向也是鼠标的当前坐标-鼠标上次坐标。

3 最后说复原,首先我们先记载最开始坐标,然后每帧当前坐标向起始坐标进行插值。

代码如下:首先先贴出挤压的代码

float dist = Vector2.Distance(new Vector2(_verts[i].x, _verts[i].z), new Vector2(point.x, point.z));
if (_isUsingPush)

    if (point.y > _minYpoint)
     
         if (dist < _pushRadius)
         
            _verts[i].y = Mathf.Lerp(_verts[i].y, 0,
                            Mathf.Pow(1 - Mathf.Pow(dist / _pushRadius, _pushFalloff * _pushMagnitude2), 2) *
                            _pushIntsity * _pushMagnitude);
         
      
 

dist是当前顶点和鼠标的点的2维距离(忽略y坐标),这里插值t的取值,如果在圆中心的这个值为1,反之值越小所以这个需要1-值,这里的值所有函数都是Mathf.Pow,当然这里也可以用其他的函数,线性函数也是可以的,这里用pow主要是为了平缓一些。

下面就是拖拽了,代码如下:

if (_isDrag)

   if (dist < _dragRadius)
   
         float distance2 = Mathf.Pow((1 - Vector3.Distance(_verts[i], point) / _dragRadius / 2), _dragFalloff);
         float drag = _dragIntensity * distance2 * DragStr * _speedMagnitude;
         _verts[i] -= _movePos[tochId] * drag;
    

同样这里的值也跟挤压一样,用的pow函数并且也需要1-值。

最后就是复原了,这里复原我们是放在FixedUpdate里面更新了。

代码如下:

private void FixedUpdate()

        if (_isRepair)
        
            for (int i = 0; i < _verts.Length; i++)
            
                Vector2 v1 = new Vector2(_verts[i].x, _verts[i].z);
                Vector2 v2 = new Vector2(_originVerts[i].x, _originVerts[i].z);
                float dist2 = 1 + Vector2.Distance(v1, v2) * _rubber;

                _verts[i] = Vector3.Lerp(_verts[i], _originVerts[i], _repairSpeed * Time.deltaTime * dist2);
            

            _mesh.vertices = _verts;
            _meshCollider.sharedMesh = _mesh;
            _meshFilter.mesh = _mesh;
            _meshFilter.mesh.RecalculateNormals();
        

这里dist2这里的值需要默认加上1,因为当距离为0的这里dist2如果不加1那么dist2为0那么就不会复原了。所以整个代码如下:

using UnityEngine;
using System.Collections;

public class MeshDeformate : MonoBehaviour


    [SerializeField] private bool _isUsingPush;
    [SerializeField] private bool _isRepair;
    [SerializeField] private bool _isDrag;

    [Header("Push")]
    [SerializeField] private float _minYpoint = 0;
    [SerializeField] private float _pushRadius = 0.1f;
    [SerializeField] private float _pushIntsity = 0.2f;
    [SerializeField] private float _pushFalloff = 2f;

    [Header("Drag")]
    [SerializeField] private float _dragRadius = 0.5f;
    [SerializeField] private float _dragIntensity = 0.2f;
    [SerializeField] private float _dragFalloff = 5f;
    [SerializeField] private float DragStr = 0.1f;


    [SerializeField] private float _repairSpeed= 0.4f;
    [SerializeField] private float _rubber = 6f;
    [SerializeField] private float maxMagnitude = 0.2f;


    private Vector3[] _verts;
    private Vector3[] _originVerts;
    private Vector3[] _oldhPos = new Vector3[5];
    private Vector3[] _movePos = new Vector3[5];

    private float _pushMagnitude;
    private float _pushMagnitude2;
    private float _speedMagnitude;

    private Mesh _mesh;
    private MeshFilter _meshFilter;
    private MeshCollider _meshCollider;
    private bool _firstPush;

    private void Awake()
    
        _meshCollider = transform.GetComponent<MeshCollider>();
        _meshFilter = transform.GetComponent<MeshFilter>();
        _mesh = _meshFilter.mesh;

        _verts = _mesh.vertices;
        _originVerts = _mesh.vertices;
    

    private void Update()
    
        if (Input.GetMouseButtonDown(0))
        
            _firstPush = true;
        
        if (Input.GetMouseButton(0))
        
            var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit))
            
                if (hit.collider)
                
                    ModifyMesh(hit, 0);
                
            
        
    

    private void FixedUpdate()
    
        if (_isRepair)
        
            for (int i = 0; i < _verts.Length; i++)
            
                Vector2 v1 = new Vector2(_verts[i].x, _verts[i].z);
                Vector2 v2 = new Vector2(_originVerts[i].x, _originVerts[i].z);
                float dist2 = 1 + Vector2.Distance(v1, v2) * _rubber;

                _verts[i] = Vector3.Lerp(_verts[i], _originVerts[i], _repairSpeed * Time.deltaTime * dist2);
            

            _mesh.vertices = _verts;
            _meshCollider.sharedMesh = _mesh;
            _meshFilter.mesh = _mesh;
            _meshFilter.mesh.RecalculateNormals();
        
    


    private void ModifyMesh(RaycastHit hit, int tochId)
    
        if (_firstPush)
        
            _oldhPos[tochId] = hit.point;
            _firstPush = false;
        

        _movePos[tochId] = _oldhPos[tochId] - hit.point;

        var point = transform.InverseTransformPoint(hit.point);
        _movePos[tochId].y = 0;
        _speedMagnitude = 0;
        if (_movePos[tochId].magnitude < maxMagnitude)
        
            _speedMagnitude = maxMagnitude - _movePos[tochId].magnitude;
            _pushMagnitude = 1 + _movePos[tochId].magnitude * 2;
            _pushMagnitude2 = 1 + _movePos[tochId].magnitude * 2;
        

        Debug.LogError(_movePos[tochId]);

        for (int i = 0; i < _verts.Length; i++)
        
            float dist = Vector2.Distance(new Vector2(_verts[i].x, _verts[i].z), new Vector2(point.x, point.z));

            if (_isUsingPush)
            
                if (point.y > _minYpoint)
                
                    if (dist < _pushRadius)
                    
                        _verts[i].y = Mathf.Lerp(_verts[i].y, 0,
                            Mathf.Pow(1 - Mathf.Pow(dist / _pushRadius, _pushFalloff * _pushMagnitude2), 2) *
                            _pushIntsity * _pushMagnitude);
                    
                
            

            if (_isDrag)
            
                if (dist < _dragRadius)
                
                    float distance2 = Mathf.Pow((1 - Vector3.Distance(_verts[i], point) / _dragRadius / 2), _dragFalloff);
                    float drag = _dragIntensity * distance2 * DragStr * _speedMagnitude;
                    _verts[i] -= _movePos[tochId] * drag;
                
            

        

        _oldhPos[tochId] = hit.point;
      
        _mesh.vertices = _verts;
        _meshCollider.sharedMesh = _mesh;
        _meshFilter.mesh = _mesh;
        _meshFilter.mesh.RecalculateNormals();
    




整个代码就讲完了,最后贴出项目源码百度网盘 请输入提取码

提取码:mxp9

以上是关于网格变形效果——黏液效果的主要内容,如果未能解决你的问题,请参考以下文章

网格变形动画

Unity如何制作小球挤捏变形效果并回弹

Unity网格变形开源库测评

Unity网格变形开源库测评

第九章

使用vue学习three.js之创建动画-变形动画-使用MorphAnimMesh制作奔跑的小马动画