Skip to content

Instantly share code, notes, and snippets.

@josemorval
Last active January 19, 2020 17:33
Show Gist options
  • Save josemorval/4a2c89a8f1bd560b1c79ddcb1c5fe7b6 to your computer and use it in GitHub Desktop.
Save josemorval/4a2c89a8f1bd560b1c79ddcb1c5fe7b6 to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//Protoype of Free-Form Deformation based on http://faculty.cs.tamu.edu/schaefer/teaching/689_Fall2006/p151-sederberg.pdf
public class FFDModifier : MonoBehaviour
{
public GameObject modelObject;
public GameObject ffdGizmo;
public int divX;
public int divY;
public int divZ;
MeshRenderer modelRenderer;
MeshFilter modelFilter;
int[,] binNM;
GameObject[,,] gizmoMarkers;
Vector3[] vscoef;
bool gridDefined;
void Start()
{
gridDefined = false;
modelRenderer = modelObject.GetComponent<MeshRenderer>();
modelFilter = modelObject.GetComponent<MeshFilter>();
}
void Update()
{
//Setup markers based on bounding of the geometry
if (Input.GetKeyDown(KeyCode.G))
{
foreach (Transform child in transform)
{
GameObject.Destroy(child.gameObject);
}
Bounds b = modelRenderer.bounds;
Vector3 vSize = b.size;
Vector3 vMinimum = b.min;
gizmoMarkers = new GameObject[divX,divY,divZ];
//Create gizmo markers
for (int i = 0; i < divX; i++)
{
for(int j = 0; j < divY; j++)
{
for(int k = 0; k < divZ; k++) {
GameObject g = GameObject.Instantiate(ffdGizmo, transform);
Vector3 pos = vMinimum + new Vector3(vSize.x*i/(divX-1f), vSize.y*j/(divY-1f), vSize.z*k/(divZ-1f));
g.transform.position = pos;
gizmoMarkers[i, j, k] = g;
}
}
}
//Compute (s,t,u) coefficientes for points
Vector3 S = new Vector3(vSize.x, 0f, 0f);
Vector3 T = new Vector3(0f, vSize.y, 0f);
Vector3 U = new Vector3(0f, 0f, vSize.z);
Vector3 cST = Vector3.Cross(S, T);
Vector3 cTU = Vector3.Cross(T, U);
Vector3 cSU = Vector3.Cross(S, U);
Mesh modelMesh = modelFilter.mesh;
Vector3[] vs = modelMesh.vertices;
vscoef = new Vector3[vs.Length];
for(int i = 0; i < vs.Length; i++)
{
vscoef[i].x = Vector3.Dot(cTU, vs[i] - vMinimum) / Vector3.Dot(cTU, S);
vscoef[i].y = Vector3.Dot(cSU, vs[i] - vMinimum) / Vector3.Dot(cSU, T);
vscoef[i].z = Vector3.Dot(cST, vs[i] - vMinimum) / Vector3.Dot(cST, U);
}
//Compute binomial coefficients
int numberCoefficients = Mathf.Max(Mathf.Max(divX, divY), divZ);
binNM = new int[numberCoefficients, numberCoefficients];
binNM[0, 0] = 1;
for(int i = 1; i < numberCoefficients; i++)
{
for(int j = 0; j <= i; j++)
{
if(j==0 || j == i)
{
binNM[i, j] = 1;
}
else
{
binNM[i, j] = binNM[i - 1, j - 1] + binNM[i - 1, j];
}
}
}
gridDefined = true;
}
//Now we can move the gizmo markers to modify the geometry
//This is gonna be recoded with job system
if (gridDefined)
{
Mesh mesh = modelFilter.mesh;
Vector3[] vs = mesh.vertices;
for(int l = 0; l < vs.Length; l++)
{
Vector3 vX = Vector3.zero;
Vector3 vY = Vector3.zero;
Vector3 vZ = Vector3.zero;
//Compute final vertex coordinates from gizmo markers points
for (int i = 0; i < divX; i++)
{
vY = Vector3.zero;
for (int j = 0; j < divY; j++)
{
vZ = Vector3.zero;
for (int k = 0; k < divZ; k++)
{
vZ += binNM[divZ - 1, k] * Mathf.Pow(1f - vscoef[l].z, divZ - 1f - k) * Mathf.Pow(vscoef[l].z, k) * gizmoMarkers[i, j, k].transform.position;
}
vZ *= binNM[divY - 1, j] * Mathf.Pow(1f - vscoef[l].y, divY - 1f - j) * Mathf.Pow(vscoef[l].y, j);
vY += vZ;
}
vY *= binNM[divX - 1, i] * Mathf.Pow(1f - vscoef[l].x, divX - 1f - i) * Mathf.Pow(vscoef[l].x, i);
vX += vY;
}
vs[l] = vX;
}
mesh.vertices = vs;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment