Unity考虑做个zbrush效果 mesh 鼠标挤压变形效果,compute shader
发表于2018-03-07
想用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