Unity考虑做个zbrush效果 mesh 鼠标挤压变形效果,compute shader

发表于2018-03-07
评论0 3.1k浏览
想用Unity引擎做一个zbrush效果,类似mesh 鼠标挤压变形效果。

代码,用ComputeShader来运算,虽然不用遍历运算了,但是还要遍历赋值。感觉没讨到多少便宜。
using UnityEngine;  
public class MeshDeformerInputByCS : MonoBehaviour  
{  
    float force = 1f;  
    float forceOffset = 0.1f;//用于产生力的角度  
    void Update()  
    {  
        if (Input.GetMouseButton(0))  
        {  
            HandleInInput();  
        }  
        if (Input.GetMouseButtonUp(0) )  
        {  
            HandleEndPression();  
        }  
    }  
    void HandleInInput()  
    {  
        Ray inputRay = Camera.main.ScreenPointToRay(Input.mousePosition);  
        RaycastHit hit;  
        if (Physics.Raycast(inputRay, out hit))  
        {  
            MeshDeformerByCS deformer = hit.collider.GetComponent<MeshDeformerByCS>();  
            if (deformer)  
            {  
                Vector3 point = hit.point;//World space  
                point += hit.normal * forceOffset;//world space 用于计算受力的方向  
                deformer.AddInDeformingForce(point, force);  
            }  
        }  
    }  
    void HandleEndPression()  
    {  
        Ray inputRay = Camera.main.ScreenPointToRay(Input.mousePosition);  
        RaycastHit hit;  
        if (Physics.Raycast(inputRay, out hit))  
        {  
            MeshDeformerByCS deformer = hit.collider.GetComponent<MeshDeformerByCS>();  
            if (deformer)  
            {  
                deformer.ClearVertexVelocities();  
            }  
        }  
    }  
}  
using UnityEngine;  
struct DBuffer  
{  
    public Vector3 vertexPos;//作用的mesh顶点  
}  
[RequireComponent(typeof(MeshFilter))]  
public class MeshDeformerByCS : MonoBehaviour  
{  
    public ComputeShader shader;  
    private ComputeBuffer buffer;  
    int bufferArrayLength;  
    private Mesh deformingMesh;  
    Vector3[] originalVertices, displacedVertices;  
    Vector3[] vertexVelocities;  
    new MeshCollider collider;  
    public float AlphaOfVertexes = 0.5f;  
    Vector3 lastPoint = Vector3.zero;  
    float uniformScale = 1f;  
    #region public  
    public void AddInDeformingForce(Vector3 point, float force)  
    {  
        point = transform.InverseTransformPoint(point);  
        if (lastPoint == Vector3.zero)  
            lastPoint = point;  
        else if (lastPoint != Vector3.zero && lastPoint != point)  
        {  
            lastPoint = point;  
            ClearVertexVelocities();  
        }  
        Dispatch(force, point);  
        //根据Shader返回的buffer数据更新物体信息  
        DBuffer[] values = new DBuffer[bufferArrayLength];  
        buffer.GetData(values);  
        for (int i = 0; i < bufferArrayLength; i++)  
        {  
            displacedVertices[i] = values[i].vertexPos;  
        }  
        deformingMesh.vertices = displacedVertices;  
        deformingMesh.RecalculateNormals();  
        collider.sharedMesh = deformingMesh;  
    }  
    public void ReCover()  
    {  
        vertexVelocities = new Vector3[originalVertices.Length];  
        deformingMesh.vertices = originalVertices;  
        deformingMesh.RecalculateNormals();  
    }  
    public void ClearVertexVelocities()  
    {  
        vertexVelocities = new Vector3[originalVertices.Length];  
    }  
    #endregion  
    #region unity  
    void Start()  
    {  
        deformingMesh = transform.GetComponent<MeshFilter>().mesh;  
        bufferArrayLength = deformingMesh.vertexCount;  
        originalVertices = deformingMesh.vertices;  
        displacedVertices = new Vector3[originalVertices.Length];  
        for (int i = 0; i < originalVertices.Length; i++)  
        {  
            displacedVertices[i] = originalVertices[i];  
        }  
        vertexVelocities = new Vector3[originalVertices.Length];  
        collider = GetComponent<MeshCollider>();  
        CreateBuffer();  
    }  
    #endregion  
    void CreateBuffer()  
    {  
        //count数组的长度(等于2个三维的积 2x2x1 * 2x2x1),40是结构体的字节长度  
        buffer = new ComputeBuffer(bufferArrayLength, 12);  
        DBuffer[] values = new DBuffer[bufferArrayLength];  
        for (int i = 0; i < bufferArrayLength; i++)  
        {  
            DBuffer m = new DBuffer();  
            SetStruct(ref m, displacedVertices[i]);  
            values[i] = m;  
        }  
        // 初始化结构体并赋予buffer  
        buffer.SetData(values);  
    }  
    void SetStruct(ref DBuffer m, Vector3 vertexPos)  
    {  
        m.vertexPos = vertexPos;  
    }  
    void Dispatch(float force, Vector3 pressPos)  
    {  
        //必须分配足够多的线程  
        //int groupx = (int)Mathf.Pow(bufferArrayLength / 256, 1 / 3);  
        shader.SetFloat("force", force);  
        shader.SetVector("pressPos", pressPos);  
        shader.SetInt("groupx", 8);  
        shader.SetInt("groupy", 8);  
        int kid = shader.FindKernel("CSMain");  
        shader.SetBuffer(kid, "dBuffer", buffer);  
        shader.Dispatch(kid, 8, 8, 8);  
    }  
    #region private  
    #endregion  
    void ReleaseBuffer()  
    {  
        buffer.Release();  
    }  
    private void OnDisable()  
    {  
        ReleaseBuffer();  
    }  
}  
// Each #kernel tells which function to compile; you can have many kernels  
#pragma kernel CSMain  
struct DeformBuffer  
{  
    float3 vertexPos;//作用的mesh顶点  
};  
RWStructuredBuffer<DeformBuffer> dBuffer;  
float force;//力  
float3 pressPos;//力的作用点  
uint groupx;  
uint groupy;  
[numthreads(8,8,8)]  
void CSMain (uint3 id : SV_DispatchThreadID)  
{  
    int index = id.x + id.y * groupx * 8 + id.z * groupx * groupy * 8 * 8;  
    float3 pointToVertex =  dBuffer[index].vertexPos -pressPos;  
    float attenuatedForce = force / (1 +length(pointToVertex));  
    float3 Velocity0 = normalize( pointToVertex) * attenuatedForce * 0.01f;  
    dBuffer[index].vertexPos += Velocity0;  
}  
来自:http://blog.csdn.net/baidu_16312167/article/details/78135753

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引