User talk:MarkGX

You accidentally edited the main page. Here is the content that you were working on before I reverted it:

-

Introduction
This c# code demonstrates how to deformate a mesh at runtime using smoothing algorithms.

To solve this problem in a reasonable computational time a good algorithm is needed to solve the adjacent vertex problem. Unity lacks mesh manipulation utilities and some manual effort is required to achieve this.

(Note: I'm no unity expert so please don't shoot the piano player he is trying his best and improve anything.)

Basic Theory
Given a Mesh/SkinnedMeshRenderer Vector3[] v = mesh.vertices,  and int[] t = mesh.triangles.

For each vertex i in the mesh, find the set of neighboring vertices.

Computing the Laplacian Smooth Filter p[i] = ( 1 / number of adjacent vertices ) * summation of the adjacent vertices.

Laplacian smoothing introduces shrinkage, so the HC-Algorithm is applied as an extension to reduce this issue. (More computationally expensive though !).

General Discussion
Although the code demonstrates smoothing meshes, it provides a more generic strategy for manipulating meshes in Unity as many deformation algorithms could be applied. Have Fun!

TestSmoothFilter.cs
using UnityEngine; using System.Collections;

/*	Apply to any meshed gameobject for smoothing.

Works also by replacing MeshFilter with SkinnedMeshRenderer and use sharedMesh

At present tests Laplacian Smooth Filter and HC Reduced Shrinkage Variant Filter public class TestSmoothFilter : MonoBehaviour {

private Mesh sourceMesh; private Mesh workingMesh; void Start {		MeshFilter meshFilter = gameObject.GetComponentInChildren; // Clone the cloth mesh to work on		sourceMesh = new Mesh; // Get the sourceMesh sourceMesh = meshFilter.mesh; // Clone the sourceMesh workingMesh = CloneMesh(sourceMesh); // Reference workingMesh to see deformations skinnedmesh.mesh = workingMesh; // Apply Laplacian Smoothing Filter to Mesh int iterations = 1; for(int i=0; i<iterations; i++) workingMesh.vertices = SmoothFilter.laplacianFilter(workingMesh.vertices, workingMesh.triangles); //workingMesh.vertices = hcFilter(sourceMesh.vertices, workingMesh.vertices, workingMesh.triangles, 0.0f, 0.5f); }	// Clone a mesh private static Mesh CloneMesh(Mesh mesh) {       Mesh clone = new Mesh; clone.vertices = mesh.vertices; clone.normals = mesh.normals; clone.tangents = mesh.tangents; clone.triangles = mesh.triangles; clone.uv = mesh.uv; clone.uv1 = mesh.uv1; clone.uv2 = mesh.uv2; clone.bindposes = mesh.bindposes; clone.boneWeights = mesh.boneWeights; clone.bounds = mesh.bounds; clone.colors = mesh.colors; clone.name = mesh.name; //TODO : Are we missing anything? return clone; } }

SmoothFilter.cs
using UnityEngine; using System.Collections; using System.Collections.Generic;

/*   MeshSmoothTest Laplacian Smooth Filter, HC-Smooth Filter MarkGX, Jan 2011 public class SmoothFilter : MonoBehaviour {	/*		Standard Laplacian Smooth Filter */	public static Vector3[] laplacianFilter(Vector3[] sv, int[] t)	{ Vector3[] wv = new Vector3[sv.Length]; List adjacentVertices = new List; float dx = 0.0f; float dy = 0.0f; float dz = 0.0f; for (int vi=0; vi< sv.Length; vi++) {			// Find the sv neighboring vertices adjacentVertices = MeshUtils.findAdjacentNeighbors (sv, t, sv[vi]); if (adjacentVertices.Count != 0) {				dx = 0.0f; dy = 0.0f; dz = 0.0f; //Debug.Log("Vertex Index Length = "+vertexIndexes.Length); // Add the vertices and divide by the number of vertices for (int j=0; j 0.5 */	public static Vector3[] hcFilter(Vector3[] sv, Vector3[] pv, int[] t, float alpha, float beta) {		Vector3[] wv = new Vector3[sv.Length]; Vector3[] bv = new Vector3[sv.Length];

// Perform Laplacian Smooth wv = laplacianFilter(sv, t); // Compute Differences for(int i=0; i<wv.Length; i++) {			bv[i].x = wv[i].x - (alpha * sv[i].x + ( 1 - alpha ) * sv[i].x ); bv[i].y = wv[i].y - (alpha * sv[i].y + ( 1 - alpha ) * sv[i].y ); bv[i].z = wv[i].z - (alpha * sv[i].z + ( 1 - alpha ) * sv[i].z ); }		List adjacentIndexes = new List ; float dx = 0.0f; float dy = 0.0f; float dz = 0.0f; for(int j=0; j<bv.Length; j++) {			adjacentIndexes.Clear; // Find the bv neighboring vertices adjacentIndexes = MeshUtils.findAdjacentNeighborIndexes (sv, t, sv[j]); dx = 0.0f; dy = 0.0f; dz = 0.0f; for (int k=0; k<adjacentIndexes.Count; k++) {				dx += bv[adjacentIndexes[k]].x;				dy += bv[adjacentIndexes[k]].y;				dz += bv[adjacentIndexes[k]].z;			} wv[j].x -= beta * bv[j].x + ((1 - beta) / adjacentIndexes.Count) * dx; wv[j].y -= beta * bv[j].y + ((1 - beta) / adjacentIndexes.Count) * dy; wv[j].z -= beta * bv[j].z + ((1 - beta) / adjacentIndexes.Count) * dz; }		return wv; } }

MeshUtils.cs
using UnityEngine; using System.Collections; using System.Collections.Generic;

/*	Useful mesh functions public class MeshUtils : MonoBehaviour {	// Finds a set of adjacent vertices for a given vertex // Note the success of this routine expects only the set of neighboring faces to eacn contain one vertex corresponding // to the vertex in question public static List findAdjacentNeighbors ( Vector3[] v, int[] t, Vector3 vertex ) {		ListadjacentV = new List; List facemarker = new List ; int facecount = 0; // Find matching vertices for (int i=0; i<v.Length; i++) if (Mathf.Approximately (vertex.x, v[i].x) && 				Mathf.Approximately (vertex.y, v[i].y) && 				Mathf.Approximately (vertex.z, v[i].z)) {					int v1 = 0; int v2 = 0; bool marker = false; // Find vertex indices from the triangle array for(int k=0; k<t.Length; k=k+3) if(facemarker.Contains(k) == false) {							v1 = 0; v2 = 0; marker = false; if(i == t[k]) {								v1 = t[k+1]; v2 = t[k+2]; marker = true; }

if(i == t[k+1]) {								v1 = t[k]; v2 = t[k+2]; marker = true; }							if(i == t[k+2]) {								v1 = t[k]; v2 = t[k+1]; marker = true; }							facecount++; if(marker) {								// Once face has been used mark it so it does not get used again facemarker.Add(k);

// Add non duplicate vertices to the list if ( isVertexExist(adjacentV, v[v1]) == false ) {										adjacentV.Add(v[v1]); //Debug.Log("Adjacent vertex index = " + v1); }								if ( isVertexExist(adjacentV, v[v2]) == false ) {									adjacentV.Add(v[v2]); //Debug.Log("Adjacent vertex index = " + v2); }								marker = false; }						}			}		//Debug.Log("Faces Found = " + facecount); return adjacentV; }	// Finds a set of adjacent vertices for a given vertex // Note the success of this routine expects only the set of neighboring faces to eacn contain one vertex corresponding // to the vertex in question public static List findAdjacentNeighborIndexes ( Vector3[] v, int[] t, Vector3 vertex ) {		List adjacentIndexes = new List ; ListadjacentV = new List; List facemarker = new List ; int facecount = 0; // Find matching vertices for (int i=0; i<v.Length; i++) if (Mathf.Approximately (vertex.x, v[i].x) && 				Mathf.Approximately (vertex.y, v[i].y) && 				Mathf.Approximately (vertex.z, v[i].z)) {					int v1 = 0; int v2 = 0; bool marker = false; // Find vertex indices from the triangle array for(int k=0; k<t.Length; k=k+3) if(facemarker.Contains(k) == false) {							v1 = 0; v2 = 0; marker = false; if(i == t[k]) {								v1 = t[k+1]; v2 = t[k+2]; marker = true; }

if(i == t[k+1]) {								v1 = t[k]; v2 = t[k+2]; marker = true; }							if(i == t[k+2]) {								v1 = t[k]; v2 = t[k+1]; marker = true; }							facecount++; if(marker) {								// Once face has been used mark it so it does not get used again facemarker.Add(k);

// Add non duplicate vertices to the list if ( isVertexExist(adjacentV, v[v1]) == false ) {										adjacentV.Add(v[v1]); adjacentIndexes.Add(v1); //Debug.Log("Adjacent vertex index = " + v1); }								if ( isVertexExist(adjacentV, v[v2]) == false ) {									adjacentV.Add(v[v2]); adjacentIndexes.Add(v2); //Debug.Log("Adjacent vertex index = " + v2); }								marker = false; }						}			}		//Debug.Log("Faces Found = " + facecount); return adjacentIndexes; }	// Does the vertex v exist in the list of vertices static bool isVertexExist(ListadjacentV, Vector3 v)	{ bool marker = false; foreach (Vector3 vec in adjacentV) if (Mathf.Approximately(vec.x,v.x) && Mathf.Approximately(vec.y,v.y) && Mathf.Approximately(vec.z,v.z)) {		     marker = true; break; }		return marker; } }