/** * * PixelFlow | Copyright (C) 2016 Thomas Diewald - http://thomasdiewald.com * * A Processing/Java library for high performance GPU-Computing (GLSL). * MIT License: https://opensource.org/licenses/MIT * */ package SoftBody2D.SoftBody2D_ParticleCollisionSystem; import com.thomasdiewald.pixelflow.java.softbodydynamics.particle.DwParticle2D; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PGraphics; import processing.core.PShape; public class ParticleSystem { // for customizing the particle we just extends the original class and // Override what we want to customize static class CustomVerletParticle2D extends DwParticle2D{ public CustomVerletParticle2D(int idx) { super(idx); } @Override public void updateShapeColor(){ setColor(0xFF020100); // super.updateShapeColor(); } } // particle system public float PARTICLE_SCREEN_FILL_FACTOR = 0.9f; public int PARTICLE_COUNT = 500; // particle behavior public float MULT_GRAVITY = 0.50f; DwParticle2D.Param particle_param = new DwParticle2D.Param(); public PApplet papplet; public DwParticle2D[] particles; public PShape shp_particlesystem; public int size_x; public int size_y; public ParticleSystem(PApplet papplet, int size_x, int size_y){ this.papplet = papplet; this.size_x = size_x; this.size_y = size_y; } public void setParticleCount(int count){ if( count == PARTICLE_COUNT && particles != null && particles.length == PARTICLE_COUNT){ return; } PARTICLE_COUNT = count; initParticles(); } public void setFillFactor(float screen_fill_factor){ if(screen_fill_factor == PARTICLE_SCREEN_FILL_FACTOR){ return; } PARTICLE_SCREEN_FILL_FACTOR = screen_fill_factor; initParticlesSize(); initParticleShapes(); } public void initParticles(){ particles = new DwParticle2D[PARTICLE_COUNT]; for (int i = 0; i < PARTICLE_COUNT; i++) { particles[i] = new CustomVerletParticle2D(i); particles[i].setCollisionGroup(i); particles[i].setParamByRef(particle_param); } initParticlesSize(); initParticlesPosition(); initParticleShapes(); } public void initParticlesSize(){ float radius = (float)Math.sqrt((size_x * size_y * PARTICLE_SCREEN_FILL_FACTOR) / PARTICLE_COUNT) * 0.5f; radius = Math.max(radius, 1); float rand_range = 0.5f; float r_min = radius * (1.0f - rand_range); float r_max = radius * (1.0f + rand_range); DwParticle2D.MAX_RAD = r_max; papplet.randomSeed(0); for (int i = 0; i < PARTICLE_COUNT; i++) { float pr = papplet.random(r_min, r_max); particles[i].setRadius(pr); particles[i].setMass(r_max*r_max/(pr*pr) ); } particles[0].setRadius(r_max*1.5f); } public void initParticlesPosition(){ papplet.randomSeed(0); for (int i = 0; i < PARTICLE_COUNT; i++) { float px = papplet.random(0, size_x - 1); float py = papplet.random(0, size_y - 1); particles[i].setPosition(px, py); } } public void initParticleShapes(){ papplet.shapeMode(PConstants.CORNER); shp_particlesystem = papplet.createShape(PShape.GROUP); for (int i = 0; i < PARTICLE_COUNT; i++) { PShape shp_particle = createParticleShape(particles[i]); particles[i].setShape(shp_particle); shp_particlesystem.addChild(shp_particle); } } // create the shape that is going to be rendered public PShape createParticleShape(DwParticle2D particle){ final float rad = particle.rad; PShape shp_particle = papplet.createShape(PShape.GROUP); // compute circle resolution, depending on the radius we reduce/increase // the number of vertices we need to render float threshold1 = 1; // radius shortening for arc segments float threshold2 = 140; // arc between segments double arc1 = Math.acos(Math.max((rad-threshold1), 0) / rad); double arc2 = (180 - threshold2) * Math.PI / 180; double arc = Math.min(arc1, arc2); int num_vtx = (int)Math.ceil(2*Math.PI/arc); // actual circle PShape circle = papplet.createShape(PShape.GEOMETRY); circle.beginShape(); circle.noStroke(); circle.fill(200,100); for(int i = 0; i < num_vtx; i++){ float vx = (float) Math.cos(i * 2*Math.PI/num_vtx) * 1; float vy = (float) Math.sin(i * 2*Math.PI/num_vtx) * 1; circle.vertex(vx, vy); } circle.endShape(PConstants.CLOSE); // line, to indicate the velocity-direction of the particle PShape line = papplet.createShape(PShape.GEOMETRY); line.beginShape(PConstants.LINES); line.stroke(255, 100); line.strokeWeight(1f/rad); line.vertex(0, 0); line.vertex(-1, 0); line.endShape(); shp_particle.addChild(circle); shp_particle.addChild(line); return shp_particle; } void display(PGraphics pg) { pg.shape(shp_particlesystem); } }