import processing.opengl.*; //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // Written by v3ga - http://www.v3ga.net // Updated to processing 118 by Martin Antolini //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- float DEGTORAD = PI/180.0f; //------------------------------------------------------------ // Globals //------------------------------------------------------------ VerletPhysicsEngine Verlet; MeshParticleObject Pyramid; MeshParticleObject Sphere; MeshParticleObject currentObj; Container boxContainer; ArcBall_ arcball; float gTime, gLastTime, gdt; boolean showParticle; //------------------------------------------------------------ // Main //------------------------------------------------------------ void setup() { // Physics Engine Verlet = new VerletPhysicsEngine(); Verlet.m_gravity = new vector3(0.0f, 9.81f , 0.0f); Verlet.m_nbIterations = 3; // Objects createSphere(75.0f, 6, 6, 0.65f); // createSphere(float s, int sliceNb, int slicePointNb, float jello) currentObj = Sphere; showParticle = false; // Container boxContainer = new Container(200.0f); // Rendering size(800,600, OPENGL); rectMode(CENTER); // Control arcball = new ArcBall_(); // Time gLastTime = 0.0f; } void draw() { gTime = millis(); gdt = (gTime - gLastTime)*0.001; gLastTime = gTime; // Center background(255); translate(0.5*width,0.5*height, 200); // Step Verlet.M_step(gdt); // Input Transform boxContainer.m_orientation = multiply(arcball.mouseQuat, arcball.startQuat); boxContainer.m_orientation.normalize(); boxContainer.M_update(); // Render drawScene(); } void drawScene() { pushMatrix(); applyMatrix ( boxContainer.m_matrix3[0], boxContainer.m_matrix3[3], boxContainer.m_matrix3[6], 0.0, boxContainer.m_matrix3[1], boxContainer.m_matrix3[4], boxContainer.m_matrix3[7], 0.0, boxContainer.m_matrix3[2], boxContainer.m_matrix3[5], boxContainer.m_matrix3[8], 0.0, 0.0, 0.0, 0.0, 1.0 ); boxContainer.M_render(); currentObj.M_render(showParticle? MeshParticleObject.WIRED : MeshParticleObject.FLAT); popMatrix(); } //------------------------------------------------------------ // Control //------------------------------------------------------------ void mousePressed() { arcball.circlePointStart.x = (mouseX - 0.5*width) / (0.5*width); arcball.circlePointStart.y = (mouseY - 0.5*height) / (0.5*width); arcball.spherePointStart = arcball.getPointSphere(arcball.circlePointStart); arcball.startQuat.set(boxContainer.m_orientation); arcball.mouseQuat.setIdentity(); } void mouseDragged() { arcball.circlePointEnd.x = (mouseX - 0.5*width) / (0.5*width); arcball.circlePointEnd.y = (mouseY - 0.5*height) / (0.5*width); arcball.spherePointEnd = arcball.getPointSphere(arcball.circlePointEnd); arcball.mouseQuat = arcball.getQuat(arcball.spherePointStart, arcball.spherePointEnd); } void keyPressed() { switch(key) { case 'G': case 'g': Verlet.m_gravity.y = -Verlet.m_gravity.y ; break; case 'P': case 'p': showParticle = !showParticle; break; } } // **************************** // class Particle // **************************** class Particle { int m_id; vector3 m_pos = new vector3(); // position vector3 m_oldpos = new vector3(); // previous position vector3 m_a = new vector3(); // acceleration Particle(int id) { m_id = id; m_pos.zero(); m_oldpos.zero(); } Particle(int id, float x0, float y0, float z0) { m_id = id; m_pos.set(x0, y0, z0); m_oldpos.set(x0, y0, z0); } } // **************************** // Constraint // **************************** class Constraint { final static int RIGID = 0x01; final static int SOFT = 0x02; int m_type; float m_restLength; float m_softLength = 0.0f; int m_A,m_B; particleSystem m_parent; float m_jellyCoeff; boolean m_isDraw; Constraint(particleSystem parent, int A, int B, int type, float jellyCoeff, boolean isDraw) { m_parent = parent; m_type = type; m_A = A; m_B = B; m_jellyCoeff = jellyCoeff; m_isDraw = isDraw; M_setRestLength(); } //------------------------------------------------------------ // M_setRestLength() //------------------------------------------------------------ void M_setRestLength() { float dx = m_parent.m_P[m_B].m_pos.x - m_parent.m_P[m_A].m_pos.x; float dy = m_parent.m_P[m_B].m_pos.y - m_parent.m_P[m_A].m_pos.y; float dz = m_parent.m_P[m_B].m_pos.z - m_parent.m_P[m_A].m_pos.z; m_restLength = sqrt(dx*dx + dy*dy + dz*dz); } //------------------------------------------------------------ // M_draw() //------------------------------------------------------------ void M_draw() { if (!m_isDraw) return; float x1,y1,x2,y2,z1,z2; x1 = m_parent.m_P[m_A].m_pos.x ; y1 = m_parent.m_P[m_A].m_pos.y ; z1 = m_parent.m_P[m_A].m_pos.z ; x2 = m_parent.m_P[m_B].m_pos.x ; y2 = m_parent.m_P[m_B].m_pos.y ; z2 = m_parent.m_P[m_B].m_pos.z ; noFill(); stroke(150,150,150,127); line (x1,y1,z1,x2,y2,z2); noStroke(); fill(255,0,0); pushMatrix(); translate(x1,y1,z1); box(4); popMatrix(); pushMatrix(); translate(x2,y2,z2); box(4); popMatrix(); } } // **************************** // class particleSystem // **************************** class particleSystem { int m_nb; int m_nbC; Particle[] m_P; Constraint[] m_C; boolean m_isJelly; vector3[] m_temp; particleSystem(int nbParticles, int nbConstraints) { m_nb = nbParticles; m_nbC = nbConstraints; m_P = new Particle[nbParticles]; if (m_nbC !=0 ) m_C = new Constraint[nbConstraints]; m_temp = new vector3[nbParticles]; } //------------------------------------------------------------ // M_draw() //------------------------------------------------------------ void M_draw() { pushMatrix(); for (int i=0;i gravity in Local frame of container //boxContainer.M_makeMatrix3Inv(); g_.x = boxContainer.m_matrix3[0] * m_gravity.x + boxContainer.m_matrix3[1] * m_gravity.y + boxContainer.m_matrix3[2] * m_gravity.z; g_.y = boxContainer.m_matrix3[3] * m_gravity.x + boxContainer.m_matrix3[4] * m_gravity.y + boxContainer.m_matrix3[5] * m_gravity.z; g_.z = boxContainer.m_matrix3[6] * m_gravity.x + boxContainer.m_matrix3[7] * m_gravity.y + boxContainer.m_matrix3[8] * m_gravity.z; // ---> gravity for (int i=0;i Compute the length of a constraint when it collides for (int i=0;i Compute now the length of the constraint to be restored for (int i=0;i Satisfy World Constraints + internal constraints for (int nIt = 0 ; nIt Vertex Array vIndex = 3; for (int n=0 ; n Particles Sphere.M_createParticles(); // ---> Constraints Sphere.m_C[0] = new Constraint( (particleSystem) Sphere, 1, 0, Constraint.SOFT, jelly,false); Sphere.m_C[1] = new Constraint( (particleSystem) Sphere, 1, 2, Constraint.SOFT, jelly,false); cIndex = 2; for (int n=0 ; n Caps for (int n=0 ; n Body for (int n=0 ; n Normals Sphere.M_createNormals(); } // **************************** // Cubic Container // **************************** class Container { float m_w,m_w2; Quat m_orientation = new Quat(); float[] m_matrix3 = new float[9]; Container(float w) { this.m_w = w; this.m_w2 = 0.5f*w; } void M_render() { stroke(220); noFill(); box(m_w); } void M_update() { m_matrix3 = m_orientation.toMatrix3(); } } //************************************************** //************************************************** //------------------------------------------------------------ // vector3 //------------------------------------------------------------ class vector3 { float x,y,z; vector3() { this.x = 0.0; this.y = 0.0; this.z = 0.0; } vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } void set(vector3 v) { this.x = v.x; this.y = v.y; this.z = v.z; } void set(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } void norm() { float n = sqrt(x*x + y*y + z*z); this.x /= n; this.y /= n; this.z /= n; } void zero() { x = 0.0; y = 0.0; z = 0.0; } void output() { print( "(" + this.x + " ; " + this.y + " ; " + this.z + ")\n"); } } vector3 cross(vector3 a, vector3 b) { vector3 result = new vector3(); result.x = a.y*b.z - a.z*b.y; result.y = a.z*b.x - a.x*b.z; result.z = a.x*b.y - a.y*b.x; return result; } // **************************** // Face // **************************** class Face { int A,B,C; vector3 n; Face(int A, int B, int C) { this.A = A; this.B = B; this.C = C; } } //------------------------------------------------------------ // Quat class //------------------------------------------------------------ class Quat { float r,x,y,z; Quat() { setIdentity(); } Quat(float r, float x, float y, float z) { set(r,x,y,z); } void setIdentity() { this.r = 1.0; this.x = 0.0; this.y = 0.0; this.z = 0.0; } void set(float r,float x,float y,float z) { this.r = r; this.x = x; this.y = y; this.z = z; } void set(float r, vector3 v) { this.r = r; this.x = v.x; this.y = v.y; this.z = v.z; } void set(Quat q) { this.r = q.r; this.x = q.x; this.y = q.y; this.z = q.z; } void normalize() { float norm; norm = sqrt(r*r + x*x + y*y + z*z); this.r /= norm; this.x /= norm; this.y /= norm; this.z /= norm; } boolean isUnit() { return (r*r + x*x + y*y + z*z > 0.99); } void conjuguate() { this.x = -this.x; this.y = -this.y; this.z = -this.z; } void multiplyBy(Quat q2) { Quat qTemp=new Quat(); qTemp.r = this.r; qTemp.x = this.x; qTemp.y = this.y; qTemp.z = this.z; this.r = qTemp.r * q2.r - (qTemp.x * q2.x + qTemp.y * q2.y + qTemp.z * q2.z); this.x = qTemp.r * q2.x + q2.r * qTemp.x + qTemp.y * q2.z - qTemp.z * q2.y; this.y = qTemp.r * q2.y - q2.z * qTemp.x + qTemp.y * q2.r + qTemp.z * q2.x; this.z = qTemp.r * q2.z + q2.y * qTemp.x - qTemp.y * q2.x + qTemp.z * q2.r; } void multiplyBy(float a) { this.r *= a; this.x *= a; this.y *= a; this.z *= a; } void vectorTransform(vector3 v) { this.r = 0; this.x = v.x; this.y = v.y; this.z = v.z; } float[] toMatrix3() { float rx, ry, rz, xx, yy, yz, xy, xz, zz, x2, y2, z2; float[] matrix = new float[9]; x2 = this.x + this.x; y2 = this.y + this.y; z2 = this.z + this.z; xx = this.x * x2; xy = this.x * y2; xz = this.x * z2; yy = this.y * y2; yz = this.y * z2; zz = this.z * z2; rx = this.r * x2; ry = this.r * y2; rz = this.r * z2; matrix[0] = 1.0 - (yy + zz); matrix[1] = xy + rz; matrix[2] = xz - ry; matrix[3] = xy - rz; matrix[4] = 1.0 - (xx + zz); matrix[5] = yz + rx; matrix[6] = xz + ry; matrix[7] = yz - rx; matrix[8] = 1.0 - (xx + yy); return matrix; } } // ------------------------------------------------------------- // Multiply() // q = q1*q2 // ------------------------------------------------------------- Quat multiply(Quat q1, Quat q2) { Quat result = new Quat(); result.r = q1.r * q2.r - (q1.x * q2.x + q1.y * q2.y + q1.z * q2.z); result.x = q1.r * q2.x + q2.r * q1.x + q1.y * q2.z - q1.z * q2.y; result.y = q1.r * q2.y - q2.z * q1.x + q1.y * q2.r + q1.z * q2.x; result.z = q1.r * q2.z + q2.y * q1.x - q1.y * q2.x + q1.z * q2.r; return result; } Quat multiply(Quat q, float a) { Quat result = new Quat(); result.r = q.r * a; result.x = q.x * a; result.y = q.y * a; result.z = q.z * a; return result; } // ------------------------------------------------------------- // vectorRotate() // Rotates a vector3 , rotation given by a Quat // result = q.v.q^-1 // ------------------------------------------------------------- vector3 vectorRotate(vector3 v, Quat rot) { vector3 result = new vector3(); Quat invr = new Quat(); Quat qv = new Quat(); Quat tmp = new Quat(); invr.r = rot.r; invr.x = -rot.x; invr.z = -rot.y; invr.z = -rot.z; qv.vectorTransform(v); tmp = multiply(qv, invr); invr = multiply(rot, tmp); result.x = invr.x; result.y = invr.y; result.z = invr.z; return result; } // ------------------------------------------------------------- // eulerTransform // Takes 3 angles, and returns a Quat // ------------------------------------------------------------- Quat eulerTransform(float alpha, float beta, float gamma) { Quat result = new Quat(); float cr, cp, cy, sr, sp, sy, cpcy, spsy; alpha *= DEGTORAD; beta *= DEGTORAD; gamma *= DEGTORAD; cr = cos(alpha/2); cp = cos(beta/2); cy = cos(gamma/2); sr = sin(alpha/2); sp = sin(beta/2); sy = sin(gamma/2); cpcy = cp * cy; spsy = sp * sy; result.r = cr * cpcy + sr * spsy; result.x = sr * cpcy - cr * spsy; result.y = cr * sp * cy + sr * cp * sy; result.z = cr * cp * sy - sr * sp * cy; return result; } // ------------------------------------------------------------- // SLERP: Spherical Linear Interpolation // Step from q1 to q2, 0= 0.01 ) { // standard case (slerp) omega = (float)Math.acos(cos_omega); sin_omega = sin(omega); scale0 = sin((1.0 - t) * omega) / sin_omega; scale1 = sin(t * omega) / sin_omega; } else { // "from" and "to" Quats are very close // ... so we can do a linear interpolation scale0 = 1.0 - t; scale1 = t; } // calculate final values result.r = scale0 * q1.r + scale1 * to1[0]; result.x = scale0 * q1.x + scale1 * to1[1]; result.y = scale0 * q1.y + scale1 * to1[2]; result.z = scale0 * q1.z + scale1 * to1[3]; return result; } // **************************** // class ArcBall // **************************** class ArcBall_ { vector3 circlePointStart, circlePointEnd, spherePointStart, spherePointEnd; Quat startQuat, mouseQuat; ArcBall_() { circlePointStart = new vector3(); circlePointEnd = new vector3(); spherePointStart = new vector3(); spherePointEnd = new vector3(); startQuat = new Quat(); mouseQuat = new Quat(); } vector3 getPointSphere(vector3 P) { float r = P.x*P.x + P.y*P.y; vector3 result = new vector3(); result.x = P.x; result.y = P.y; result.z = P.z; if(r>1.0) { float sr = sqrt(r); result.x /= sr; result.y /= sr; result.z = 0.0; } else result.z = sqrt( 1.0-r); return result; } Quat getQuat(vector3 pStartPoint, vector3 pEndPoint) { Quat result = new Quat(); vector3 crossResult; float dotResult; crossResult = cross(pStartPoint,pEndPoint); dotResult = pStartPoint.x*pEndPoint.x + pStartPoint.y*pEndPoint.y + pStartPoint.z*pEndPoint.z; result.set(dotResult, crossResult); return result; } }