void GenerateParticles(R3Scene *scene, double current_time, double delta_time) { for (int i = 0; i < scene->NParticleSources(); i++) { R3ParticleSource *source = scene->ParticleSource(i); // spheres if (source->shape->type == R3_SPHERE_SHAPE) { // remainder term for fraction of particle double numberweshouldmake = delta_time * source->rate + source->remainder; int nparts = (int) floor(numberweshouldmake); source->remainder = numberweshouldmake - nparts; for (int p = 0; p < nparts; p++) { R3Particle *newpart = new R3Particle(); // calculate position and velocity double u = RandomNumber(); double theta = 2*PI*u; double v = RandomNumber(); double phi = acos(2*v-1); double r = source->shape->sphere->Radius(); R3Point center = source->shape->sphere->Center(); double x = r*cos(theta)*sin(phi); double y = r*sin(theta)*sin(phi); double z = r*cos(phi); R3Vector n = R3Vector(x,y,z); n.Normalize(); // find tangent vector, use lecture notes to get velocity R3Plane plane = R3Plane(R3Point(0,0,0),n); R3Vector a; do { a = R3Vector(RandomNumber(),RandomNumber(),RandomNumber()); a.Project(plane); } while (a.Length() == 0.0); a.Normalize(); double t1 = 2*PI*RandomNumber(); double t2 = sin(source->angle_cutoff)*RandomNumber(); a.Rotate(n,t1); R3Vector vec = R3Vector(a); R3Vector cross = R3Vector(vec); cross.Cross(n); vec.Rotate(cross,acos(t2)); newpart->position = center + n*r; newpart->velocity = vec*source->velocity; //update newpart->mass = source->mass; newpart->fixed = source->fixed; newpart->drag = source->drag; newpart->elasticity = source->elasticity; newpart->lifetime = source->lifetime; newpart->lifetimeactive = source->lifetimeactive; newpart->material = source->material; scene->particles.push_back(newpart); } } // CIRCLE if (source->shape->type == R3_CIRCLE_SHAPE) { double numberweshouldmake = delta_time * source->rate + source->remainder; int nparts = (int) floor(numberweshouldmake); source->remainder = numberweshouldmake - nparts; for (int p = 0; p < nparts; p++) { R3Particle *newpart = new R3Particle(); // calculate position and velocity double r = source->shape->circle->Radius(); R3Point center = source->shape->circle->Center(); R3Plane plane = source->shape->circle->Plane(); R3Vector n = plane.Normal(); n.Normalize(); // get a random point on a circle double xcirc, ycirc; do { xcirc = 2*r*(RandomNumber() - 0.5); ycirc = 2*r*(RandomNumber() - 0.5); } while (xcirc*xcirc + ycirc*ycirc > r*r); // get basis vectors of circle R3Vector tang; do { tang = R3Vector(RandomNumber(),RandomNumber(),RandomNumber()); tang.Project(plane); } while (tang.Length() == 0.0); R3Vector othertang = R3Vector(tang); othertang.Cross(n); othertang.Normalize(); tang.Normalize(); R3Point pos = center + tang*xcirc + othertang*ycirc; R3Vector a = R3Vector(tang); double t1 = 2*PI*RandomNumber(); double t2 = sin(source->angle_cutoff)*RandomNumber(); a.Rotate(n,t1); R3Vector vec = R3Vector(a); R3Vector cross = R3Vector(vec); cross.Cross(n); vec.Rotate(cross,acos(t2)); newpart->position = pos; newpart->velocity = vec*source->velocity; newpart->mass = source->mass; newpart->fixed = source->fixed; newpart->drag = source->drag; newpart->elasticity = source->elasticity; newpart->lifetime = source->lifetime; newpart->lifetimeactive = source->lifetimeactive; newpart->material = source->material; scene->particles.push_back(newpart); } } } for (int i = 0; i < (int)scene->enemies.size(); i++) { R3Enemy *enemy = scene->enemies[i]; // spheres if (enemy->shape->type == R3_SPHERE_SHAPE) { // remainder term for fraction of particle double numberweshouldmake = delta_time * enemy->rate + enemy->remainder; int nparts = (int) floor(numberweshouldmake); enemy->remainder = numberweshouldmake - nparts; for (int p = 0; p < nparts; p++) { R3Particle *newpart = new R3Particle(); // calculate position and velocity double u = RandomNumber(); double theta = 2*PI*u; double v = RandomNumber(); double phi = acos(2*v-1); double r = enemy->shape->sphere->Radius(); R3Point center = enemy->shape->sphere->Center(); double x = r*cos(theta)*sin(phi); double y = r*sin(theta)*sin(phi); double z = r*cos(phi); R3Vector n = R3Vector(x,y,z); n.Normalize(); // find tangent vector, use lecture notes to get velocity R3Plane plane = R3Plane(R3Point(0,0,0),n); R3Vector a; do { a = R3Vector(RandomNumber(),RandomNumber(),RandomNumber()); a.Project(plane); } while (a.Length() == 0.0); a.Normalize(); double t1 = 2*PI*RandomNumber(); double t2 = sin(enemy->angle_cutoff)*RandomNumber(); a.Rotate(n,t1); R3Vector vec = R3Vector(a); R3Vector cross = R3Vector(vec); cross.Cross(n); vec.Rotate(cross,acos(t2)); newpart->position = center + n*r; newpart->velocity = vec*enemy->velocity; //update newpart->mass = enemy->mass; newpart->fixed = enemy->fixed; newpart->drag = enemy->drag; newpart->elasticity = enemy->elasticity; newpart->lifetime = enemy->lifetime; newpart->lifetimeactive = enemy->lifetimeactive; newpart->material = enemy->material; scene->particles.push_back(newpart); } } // CIRCLE if (enemy->shape->type == R3_CIRCLE_SHAPE) { double numberweshouldmake = delta_time * enemy->rate + enemy->remainder; int nparts = (int) floor(numberweshouldmake); enemy->remainder = numberweshouldmake - nparts; for (int p = 0; p < nparts; p++) { R3Particle *newpart = new R3Particle(); // calculate position and velocity double r = enemy->shape->circle->Radius(); R3Point center = enemy->shape->circle->Center(); R3Plane plane = enemy->shape->circle->Plane(); R3Vector n = plane.Normal(); n.Normalize(); // get a random point on a circle double xcirc, ycirc; do { xcirc = 2*r*(RandomNumber() - 0.5); ycirc = 2*r*(RandomNumber() - 0.5); } while (xcirc*xcirc + ycirc*ycirc > r*r); // get basis vectors of circle R3Vector tang; do { tang = R3Vector(RandomNumber(),RandomNumber(),RandomNumber()); tang.Project(plane); } while (tang.Length() == 0.0); R3Vector othertang = R3Vector(tang); othertang.Cross(n); othertang.Normalize(); tang.Normalize(); R3Point pos = center + tang*xcirc + othertang*ycirc; R3Vector a = R3Vector(tang); double t1 = 2*PI*RandomNumber(); double t2 = sin(enemy->angle_cutoff)*RandomNumber(); a.Rotate(n,t1); R3Vector vec = R3Vector(a); R3Vector cross = R3Vector(vec); cross.Cross(n); vec.Rotate(cross,acos(t2)); newpart->position = pos; newpart->velocity = vec * 1.0; newpart->mass = enemy->mass; newpart->fixed = enemy->fixed; newpart->drag = enemy->drag; newpart->elasticity = enemy->elasticity; newpart->lifetime = enemy->lifetime; newpart->lifetimeactive = enemy->lifetimeactive; newpart->material = enemy->material; scene->particles.push_back(newpart); } } } }
void UpdateParticles(R3Scene *scene, double current_time, double delta_time, int integration_type) { // array of ints to be deleted std::vector<int> tobedeleted; // for each particle for(int i = 0; i < scene->NParticles(); i++) { R3Particle *particle = scene->Particle(i); bool needstobedeleted = false; // check lifetime deletion if (particle->lifetimeactive) { if (particle->lifetime < 0) needstobedeleted = true; particle->lifetime -= delta_time; } R3Vector positionchange; R3Vector velocitychange; // Euler if (integration_type == EULER_INTEGRATION) { R3Vector f = ForceVector(scene, current_time, particle, particle->position, particle->velocity); positionchange = particle->velocity*delta_time; velocitychange = delta_time*f/particle->mass; } // midpoint else if (integration_type == MIDPOINT_INTEGRATION) { R3Vector f = ForceVector(scene, current_time, particle, particle->position, particle->velocity); R3Point xmid = particle->position + delta_time*particle->velocity/2.0; R3Vector vmid = particle->velocity + delta_time*f/particle->mass/2.0; R3Vector midf = ForceVector(scene, current_time, particle, xmid, vmid); positionchange = vmid*delta_time; velocitychange = delta_time*midf/particle->mass; } // rk4 else if (integration_type == RK4_INTEGRATION) { R3Vector fk1 = ForceVector(scene, current_time, particle, particle->position, particle->velocity); R3Vector v1 = particle->velocity; R3Point x2 = particle->position + delta_time*particle->velocity/2.0; R3Vector v2 = particle->velocity + delta_time*fk1/particle->mass/2.0; R3Vector fk2 = ForceVector(scene, current_time, particle, x2, v2); R3Vector v3 = particle->velocity + delta_time*fk2/particle->mass/2.0; R3Vector fk3 = ForceVector(scene, current_time, particle, x2, v3); R3Point x4 = particle->position + delta_time*particle->velocity; R3Vector v4 = particle->velocity + delta_time*fk3/particle->mass; R3Vector fk4 = ForceVector(scene, current_time,particle,x4, v4); R3Vector finalf = (fk1+ 2*fk2 + 2*fk3 + fk4)/(6.0); R3Vector finalv = (v1+ 2*v2 +2*v3 + v4)/(6.0); positionchange = finalv*delta_time; velocitychange = delta_time*finalf/particle->mass; } // adaptive method else if (integration_type == ADAPTIVE_STEP_SIZE_INTEGRATION) { int numbersteps = 1; R3Vector poschange1; R3Vector velchange1; R3Vector poschange2; R3Vector velchange2; double error; // do first euler for (int step = 0; step < numbersteps; step++) { poschange2 = R3Vector(0,0,0); velchange2 = R3Vector(0,0,0); R3Vector f = ForceVector(scene, current_time, particle, particle->position + poschange2, particle->velocity + velchange2); poschange2 += particle->velocity*delta_time/numbersteps; velchange2 += delta_time*f/particle->mass/numbersteps; } // half below threshold do { poschange1 = poschange2; velchange1 = velchange2; numbersteps *= 2; // euler integrate with twice the number of steps for (int step = 0; step < numbersteps; step++) { poschange2 = R3Vector(0,0,0); velchange2 = R3Vector(0,0,0); R3Vector f = ForceVector(scene, current_time, particle, particle->position + poschange2, particle->velocity + velchange2); poschange2 += particle->velocity*delta_time/numbersteps/2.0; velchange2 += delta_time*f/particle->mass/numbersteps/2.0; } double d1 = (poschange1 - poschange2).Length(); double d2 = (velchange1 - velchange2).Length(); // error for both velocity and position error = d1 + d2; } while (error > ADAPTIVE_THRESHOLD); positionchange = poschange2; velocitychange = velchange2; } else { fprintf(stderr, "invalid integration type\n"); return; } // new values R3Point nextpos = particle->position + positionchange; R3Vector nextvel = particle->velocity + velocitychange; // check if particle needs to deleted int i = 0; for (; i < scene->NParticleSinks(); i++) { R3ParticleSink *sink = scene->ParticleSink(i); //sphere sink if (sink->shape->type == R3_SPHERE_SHAPE) { double r = sink->shape->sphere->Radius(); R3Point center = sink->shape->sphere->Center(); // inside the sphere? if (R3Distance(nextpos,center) < r) needstobedeleted = true; R3Vector toward1 = particle->position - center; R3Vector toward2 = nextpos - center; // goes flying through the sphere? if (toward1.Dot(toward2) < 0) needstobedeleted = true; } } if (!needstobedeleted) { // check for bouncing in scene R3Vector to = nextpos - particle->position; to.Normalize(); R3Ray *r = new R3Ray(particle->position, to); R3Intersect intersect = ComputeIntersect(scene,scene->Root(),r); if (intersect.intersected && intersect.t < R3Distance(nextpos,particle->position)) { R3Plane plane = R3Plane(intersect.pos,intersect.norm); R3Point first = particle->position; R3Point second = intersect.pos; R3Point third = nextpos; // calculate new position R3Vector posreflect = third-second; R3Vector posreflectplanar = R3Vector(posreflect); posreflectplanar.Project(plane); R3Vector posreflectnorm = posreflect - posreflectplanar; R3Vector purenorm = R3Vector(posreflectnorm); posreflectnorm *= -1*(particle->elasticity); purenorm.Normalize(); purenorm *= -1; nextpos = second + posreflectplanar + posreflectnorm + eps*purenorm; // calculate new velocity R3Vector velreflect = R3Vector(nextvel); R3Vector velreflectplanar = R3Vector(velreflect); velreflectplanar.Project(plane); R3Vector velreflectnorm = velreflect - velreflectplanar; purenorm = R3Vector(velreflectnorm); velreflectnorm *= -1*(particle->elasticity); purenorm *= -1; purenorm.Normalize(); nextvel = velreflectnorm + velreflectplanar + eps*purenorm; } // update position if (!particle->fixed) particle->position = nextpos; if (!particle->fixed) particle->velocity = nextvel; } // push on deletion vector else { int del = i; tobedeleted.push_back(del); } } // deleting particles for (unsigned int i = 0; i < tobedeleted.size(); i++) { //swap contents of partcile vector with last element R3Particle *temp = scene->particles.back(); scene->particles[scene->particles.size() - 1] = scene->particles[tobedeleted[i]]; scene->particles[tobedeleted[i]] = temp; // delete last element scene->particles.pop_back(); } }