/* Computes acceleration to every control point of the jello cube, which is in state given by 'jello'. Returns result in array 'a'. */ void computeAcceleration(struct world * jello, struct point a[8][8][8]) { bool side; point planeNormal; // check the position of the jello cube inclinedPlaneSide(jello, jello->p[0][0][0], side, planeNormal); if (side == false) { pMULTIPLY(planeNormal, -1, planeNormal); } for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { for (int k = 0; k < 8; k++) { a[i][j][k].x = 0; a[i][j][k].y = 0; a[i][j][k].z = 0; // calculate the internal force of the jello structualForce(jello, i, j, k, a[i][j][k]); shearForce(jello, i, j, k, a[i][j][k]); bendForce(jello, i, j, k, a[i][j][k]); ////internalForce(jello, i, j, k, ); //point internalForce = a[i][j][k]; // calculate the external force in the bounding box point externF; externalForce(jello, i, j, k, externF); pSUM(a[i][j][k], externF, a[i][j][k]); // calculate the collision force in the bounding box //point collisionF; collisionForce(jello, i, j, k, a[i][j][k]); // check the point position bool s; inclinedPlaneSide(jello, jello->p[i][j][k], s, planeNormal); // calculate the inclined plane response force in the bounding box //point pCollisionF; planeCollisionForce(jello, i, j, k, s, planeNormal, a[i][j][k]); // calculate the acceleration using F = m * a, a = F / m //point F; /*pSUM(internF, externF, F); pSUM(F, collisionF, F); pSUM(F, pCollisionF, F);*/ pMULTIPLY(a[i][j][k], (1 / jello->mass), a[i][j][k]); } } } }
/* Calculate the acceleration of every particle in a brute force manner (n^2). Used for debugging. */ void PARTICLE_SYSTEM::calculateAccelerationBrute() { /////////////////// // STEP 1: UPDATE DENSITY & PRESSURE OF EACH PARTICLE for (int i = 0; i < PARTICLE::count; i++) { // grab ith particle reference PARTICLE& particle = _particles[i]; // now iteratate through neighbors particle.density() = 0.0; for (int j = 0; j < PARTICLE::count; j++) { PARTICLE& neighborParticle = _particles[j]; vec3 diffPosition = particle.position() - neighborParticle.position(); float radiusSquared = dot(diffPosition, diffPosition); if (radiusSquared <= h*h) particle.density() += Wpoly6(radiusSquared); } particle.density() *= PARTICLE_MASS; // p = k(density - density_rest) particle.pressure() = GAS_STIFFNESS * (particle.density() - REST_DENSITY); //totalDensity += particle.density(); } /////////////////// // STEP 2: COMPUTE FORCES FOR ALL PARTICLES for (int i = 0; i < PARTICLE::count; i++) { PARTICLE& particle = _particles[i]; //cout << "particle id: " << particle.id() << endl; vec3 f_pressure, f_viscosity, f_surface, f_gravity(0.0, particle.density() * -9.80665, 0.0), n, colorFieldNormal, colorFieldLaplacian; // n is gradient of colorfield //float n_mag; for (int j = 0; j < PARTICLE::count; j++) { PARTICLE& neighbor = _particles[j]; vec3 diffPosition = particle.position() - neighbor.position(); vec3 diffPositionNormalized = normalize(diffPosition); // need? float radiusSquared = dot(diffPosition, diffPosition); if (radiusSquared <= h*h) { if (radiusSquared > 0.0) { //neighborsVisited++; //cout << neighborsVisited << endl; //cout << neighbor.id() << endl; vec3 gradient; Wpoly6Gradient(diffPosition, radiusSquared, gradient); f_pressure += (particle.pressure() + neighbor.pressure()) / (2.0f * neighbor.density()) * gradient; colorFieldNormal += gradient / neighbor.density(); } f_viscosity += (neighbor.velocity() - particle.velocity()) * WviscosityLaplacian(radiusSquared) / neighbor.density(); colorFieldLaplacian += Wpoly6Laplacian(radiusSquared) / neighbor.density(); } } f_pressure *= -PARTICLE_MASS; //totalPressure += f_pressure; f_viscosity *= VISCOSITY * PARTICLE_MASS; colorFieldNormal *= PARTICLE_MASS; particle.normal = -1.0f * colorFieldNormal; colorFieldLaplacian *= PARTICLE_MASS; // surface tension force float colorFieldNormalMagnitude = colorFieldNormal.length(); if (colorFieldNormalMagnitude > surfaceThreshold) { particle.flag() = true; f_surface = -SURFACE_TENSION * colorFieldLaplacian * colorFieldNormal / colorFieldNormalMagnitude; } else { particle.flag() = false; } // ADD IN SPH FORCES particle.acceleration() = (f_pressure + f_viscosity + f_surface + f_gravity) / particle.density(); // EXTERNAL FORCES HERE (USER INTERACTION, SWIRL) vec3 f_collision; collisionForce(particle, f_collision); } }
/* Calculate the acceleration of each particle using a grid optimized approach. For each particle, only particles in the same grid cell and the (26) neighboring grid cells must be considered, since any particle beyond a grid cell distance away contributes no force. */ void PARTICLE_SYSTEM::calculateAcceleration() { /////////////////// // STEP 1: UPDATE DENSITY & PRESSURE OF EACH PARTICLE for (int x = 0; x < (*grid).xRes(); x++) { for (int y = 0; y < (*grid).yRes(); y++) { for (int z = 0; z < (*grid).zRes(); z++) { vector<PARTICLE>& particles = (*grid)(x,y,z); for (int p = 0; p < particles.size(); p++) { PARTICLE& particle = particles[p]; particle.density() = 0.0; // now iteratate through neighbors for (int offsetX = -1; offsetX <= 1; offsetX++) { if (x+offsetX < 0) continue; if (x+offsetX >= (*grid).xRes()) break; for (int offsetY = -1; offsetY <= 1; offsetY++) { if (y+offsetY < 0) continue; if (y+offsetY >= (*grid).yRes()) break; for (int offsetZ = -1; offsetZ <= 1; offsetZ++) { if (z+offsetZ < 0) continue; if (z+offsetZ >= (*grid).zRes()) break; vector<PARTICLE>& neighborGridCellParticles = (*grid)(x+offsetX, y+offsetY, z+offsetZ); for (int i = 0; i < neighborGridCellParticles.size(); i++) { PARTICLE& neighborParticle = neighborGridCellParticles[i]; vec3 diffPosition = particle.position() - neighborParticle.position(); float radiusSquared = dot(diffPosition, diffPosition); if (radiusSquared <= h*h) particle.density() += Wpoly6(radiusSquared); } } } } particle.density() *= PARTICLE_MASS; // p = k(density - density_rest) particle.pressure() = GAS_STIFFNESS * (particle.density() - REST_DENSITY); } } } } /////////////////// // STEP 2: COMPUTE FORCES FOR ALL PARTICLES for (int x = 0; x < (*grid).xRes(); x++) { for (int y = 0; y < (*grid).yRes(); y++) { for (int z = 0; z < (*grid).zRes(); z++) { vector<PARTICLE>& particles = (*grid)(x,y,z); for (int p = 0; p < particles.size(); p++) { PARTICLE& particle = particles[p]; //cout << "particle id: " << particle.id() << endl; vec3 f_pressure, f_viscosity, f_surface, f_gravity = gravityVector * particle.density(), colorFieldNormal; float colorFieldLaplacian; // now iteratate through neighbors for (int offsetX = -1; offsetX <= 1; offsetX++) { if (x+offsetX < 0) continue; if (x+offsetX >= (*grid).xRes()) break; for (int offsetY = -1; offsetY <= 1; offsetY++) { if (y+offsetY < 0) continue; if (y+offsetY >= (*grid).yRes()) break; for (int offsetZ = -1; offsetZ <= 1; offsetZ++) { if (z+offsetZ < 0) continue; if (z+offsetZ >= (*grid).zRes()) break; vector<PARTICLE>& neighborGridCellParticles = (*grid)(x+offsetX, y+offsetY, z+offsetZ); for (int i = 0; i < neighborGridCellParticles.size(); i++) { PARTICLE& neighbor = neighborGridCellParticles[i]; //if (particle.id() == neighbor.id()) continue; // SKIPPING COMPARISON OF THE SAME PARTICLE vec3 diffPosition = particle.position() - neighbor.position(); float radiusSquared = dot(diffPosition, diffPosition); if (radiusSquared <= h*h) { vec3 poly6Gradient, spikyGradient; Wpoly6Gradient(diffPosition, radiusSquared, poly6Gradient); WspikyGradient(diffPosition, radiusSquared, spikyGradient); if (particle.id() != neighbor.id()) { f_pressure += (float)(particle.pressure()/pow(particle.density(),2)+neighbor.pressure()/pow(neighbor.density(),2))*spikyGradient; f_viscosity += (neighbor.velocity() - particle.velocity()) * WviscosityLaplacian(radiusSquared) / neighbor.density(); } colorFieldNormal += poly6Gradient / neighbor.density(); colorFieldLaplacian += Wpoly6Laplacian(radiusSquared) / neighbor.density(); } } } } } // end of neighbor grid cell iteration f_pressure *= -PARTICLE_MASS * particle.density(); f_viscosity *= VISCOSITY * PARTICLE_MASS; colorFieldNormal *= PARTICLE_MASS; particle.normal = -1.0f * colorFieldNormal; colorFieldLaplacian *= PARTICLE_MASS; // surface tension force float colorFieldNormalMagnitude = colorFieldNormal.length(); if (colorFieldNormalMagnitude > SURFACE_THRESHOLD) { particle.flag() = true; f_surface = -SURFACE_TENSION * colorFieldNormal / colorFieldNormalMagnitude * colorFieldLaplacian; } else { particle.flag() = false; } // ADD IN SPH FORCES particle.acceleration() = (f_pressure + f_viscosity + f_surface + f_gravity) / particle.density(); // EXTERNAL FORCES HERE (USER INTERACTION, SWIRL) vec3 f_collision; collisionForce(particle, f_collision); } } } } }