Hi!
I’m trying to create a character similar to the character in Gish and have looked at Verlet integration to create the required dynamics for it.
What I am currently doing is creating a sphere object in Unity3d and applying the algorithm to the vertices that makes up the sphere.
The first problem I have is that the sphere doesn’t deform into the expected shape caused by the gravity pulling on it and secondly the sphere starts to vibrate wildly after a while.
I believe this problem to be caused by how I have created the constraints that link up the vertices.
private var vertices:Vector3[];
private var old_vertices:Vector3[];
private var forces:Vector3[];
private var num_vertices:int;
private var mesh:Mesh;
private var fTimeStep:float = 0.01;
private var num_iterations = 1;
private var bounds:Bounds;
private var num_constraints:int;
private var constraints:Array;
private var origin:Vector3 = Vector3.zero;
var gravity:Vector3 = new Vector3(0, -1, 0);
function TimeStep() {
AccumulateForces();
Verlet();
SatisfyConstraints();
}
function Verlet() {
for(i = 0; i < num_vertices; i++) {
var temp:Vector3 = vertices[i];
vertices[i] += vertices[i]-old_vertices[i]+forces[i]*fTimeStep*fTimeStep;
old_vertices[i] = temp;
}
}
// constraint class
class Constraint {
var m_v1:int;
var m_v2:int;
var m_length:float;
function Constraint(v1:int, v2:int, length:float) {
m_v1 = v1;
m_v2 = v2;
m_length = length;
}
}
// calculates the distance between 2 vertices
function RestLength(v1:int, v2:int) {
return Vector3.Distance(vertices[v1], vertices[v2]);
}
function DistanceToOrigin(v:int) {
return Vector3.Distance(vertices[v], origin);
}
function SatisfyConstraints() {
for(j = 0; j < num_iterations; j++) {
// keep vertices within the sphere
// without any constraints in place, the sphere should collapse
for(i = 0; i < num_vertices; i++) {
vertices[i] = Vector3.Min(Vector3.Max(vertices[i], bounds.min), bounds.max);
}
// adjustment of constraints
for(i = 0; i < num_constraints; i++) {
if(constraints[i].m_v2 == -1) {
var o_delta:Vector3 = vertices[constraints[i].m_v1]-origin;
var o_deltaLength:float = DistanceToOrigin(constraints[i].m_v1);
var o_diff = (o_deltaLength-constraints[i].m_length)/o_deltaLength;
vertices[constraints[i].m_v1] -= o_delta*0.5*o_diff;
origin += o_delta*0.5*o_diff;
}
else {
var delta:Vector3 = vertices[constraints[i].m_v1]-vertices[constraints[i].m_v2];
var deltaLength:float = RestLength(constraints[i].m_v1, constraints[i].m_v2);
var diff = (deltaLength-constraints[i].m_length)/deltaLength;
vertices[constraints[i].m_v1] -= delta*0.5*diff;
vertices[constraints[i].m_v2] += delta*0.5*diff;
}
}
}
}
function AccumulateForces() {
for(i = 0; i < num_vertices; i++) {
forces[i] = gravity;
}
}
function Start() {
mesh = GetComponent(MeshFilter).mesh;
num_vertices = mesh.vertexCount;
vertices = mesh.vertices;
old_vertices = mesh.vertices; // or should it be initialized zero vectors
forces = new Vector3[num_vertices];
bounds = mesh.bounds;
// build constraints
// how many constraints do we need?
// let's try building a constraint for each edge of a triangle first
constraints = new Array();
var triangles:int[] = mesh.triangles;
for(i = 0; i < triangles.Length; i+=3) {
var v1 = triangles[i];
var v2 = triangles[i+1];
var v3 = triangles[i+2];
/*constraints.Add(Constraint(v1, -1, DistanceToOrigin(v1)));
constraints.Add(Constraint(v1, v2, RestLength(v1, v2)));
constraints.Add(Constraint(v2, -1, DistanceToOrigin(v2)));
constraints.Add(Constraint(v2, v3, RestLength(v2, v3)));
constraints.Add(Constraint(v3, -1, DistanceToOrigin(v3)));
constraints.Add(Constraint(v3, v1, RestLength(v3, v1)));*/
constraints.Add(Constraint(v1, -1, DistanceToOrigin(v1)));
constraints.Add(Constraint(v1, v3, RestLength(v1, v3)));
constraints.Add(Constraint(v3, -1, DistanceToOrigin(v3)));
constraints.Add(Constraint(v3, v2, RestLength(v3, v2)));
constraints.Add(Constraint(v2, -1, DistanceToOrigin(v2)));
constraints.Add(Constraint(v2, v1, RestLength(v2, v1)));
}
num_constraints = constraints.length;
}
function Update () {
TimeStep();
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
The part that links up to the origin is a bit messy but i’m working on it.
Above is my code. To try out, create a sphere and link it with this script.
My question is
-
Should I create constrains for every edge of each triangle of the sphere?
-
Should I create constraints for every vertex to the origin?
-
How should the indices in the triangles array be read? I am asking this because the commented-out code block gives a different effect.
-
What would be the simplest way to create a goo like character in Unity3D other than using the softbody script that is available?
Any help would be greatly appreciated!
Thanks!