I am trying to use verlet integration for making a soft body sphere.
I basically create a mesh and attach each vertex by springs. I am using three.js to render the sphere. I believe everything is working correctly, but I am unsure about how to get the desired results. My ball collapses if the connections are too weak or explodes if too rigid. Something doesn't seem right. The problem occurs the moment the object falls and hits the ground. I will post the major parts of my code, however I am unsure if my approach is valid and can be used to produce the results I want.
function verletStick3D(p1, p2, distance, rigid){
this.type = "stick";
this.p1 = p1;
this.p2 = p2;
this.distance = distance;
this.rigid = rigid;
this.update = function(){
var dx = this.p1.x - this.p2.x;
var dy = this.p1.y - this.p2.y;
var dz = this.p1.z - this.p2.z;
var distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
var difference = this.distance - distance;
var percent = difference / distance / 2;
var offsetX = dx * percent * this.rigid;
var offsetY = dy * percent * this.rigid;
var offsetZ = dz * percent * this.rigid;
this.p1.x += offsetX;
this.p1.y += offsetY;
this.p1.z += offsetZ;
this.p2.x -= offsetX;
this.p2.y -= offsetY;
this.p2.z -= offsetZ;
}
}
function verletPoint3D(x, y,z, maxX, maxZ, bounce = 0.9, friction =
1.0, gravity = {x:0, y:-0.03, z:0}){
y = y + 10;
this.type = "point";
this.x=x;
this.y=y;
this.z=z;
this.xOld=x;
this.yOld=y;
this.zOld=z;
this.bounce = bounce;
this.friction = friction;
this.gravity = gravity;
this.update = function(){
var vx = (this.x - this.xOld) * this.friction;
var vy = (this.y - this.yOld) * this.friction;
var vz = (this.z - this.zOld) * this.friction;
this.xOld = this.x;
this.yOld = this.y;
this.zOld = this.z;
this.x += vx;
this.y += vy;
this.z += vz;
this.y += this.gravity.y;
this.x += this.gravity.x;
this.z += this.gravity.z;
}
this.setGravity = function(gravity){
this.gravity = gravity;
}
this.constrain = function(){
var vx = (this.x - this.xOld) ;
var vy = (this.y - this.yOld) ;
if(this.x > this.maxX){
this.x = width;
this.xOld = this.x + vx * this.bounce;
}
if(this.x < this.minX){
this.x ;
this.xOld = this.x + vx * this.bounce;
}
if(this.z > this.maxZ ){
this.z = height ;
this.zOld = this.z + vz * this.bounce;
}
if(this.z < this.minZ){
this.z = 0;
this.zOld = this.z + vz * this.bounce;
}
if(this.y < 0){
this.y = 0;
this.yOld = this.y + vy * this.bounce;
}
}
}
function verletFromMesh(vertices, faces, maxX, maxY){
var points = [];
for(var i = 0; i < vertices.length; i++){
var p = new verletPoint3D(vertices[i].x, vertices[i].y, vertices[i].z, maxX, maxY, 0.9, 0.9);
points.push(p);
}
var springs = []
/*
for(var i = 0; i < faces.length; i++){
var face = faces[i];
var p1 = face.a;
var p2 = face.b;
var p3 = face.c;
springs.push(new verletStick( p1,p2, distance3D(p1, p2), 1.0) )
springs.push(new verletStick( p2,p3, distance3D(p2, p3), 1.0) )
springs.push(new verletStick( p3,p1, distance3D(p3, p1), 1.0) )
}*/
for(var i = 0; i < points.length; i++){
var p1 = points[i];
for(var j= i+1; j < points.length; j++){
var p2 = points[j];
if(p1.x == p2.x && p1.y == p2.y && p1.z == p2.z)
continue;
var dist = distance3D(p1, p2)
springs.push(new verletStick3D( p1,p2, dist, 1.0) )
}
}
return new verletObj(points, springs);
}