sghr / iGeo

iGeo: Computational Design and 3D Modeling Library for Processing

Home Page:http://igeo.jp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Applying forces of a compound field to a non-IGeo object

co-ord opened this issue · comments

Dear Sugihara San,

I would like to apply forces of 2 ICompoundField() (curl field + attractor field) to a Boid() object that I've coded myself. This boid has an applyForce() function where it reads the force value corresponding to its position in the compound field and then add it to its acceleration vector.

def applyForce(self):
        curlForce = curl.get(IVec(self.pos.x, self.pos.y, self.pos.z))
        curlForce = PVector(curlForce.x(), curlForce.y(), curlForce.z())
        
        attrForce = attr.get(IVec(self.pos.x, self.pos.y, self.pos.z))
        attrForce = PVector(attrForce.x(), attrForce.y(), attrForce.z())
        
        self.acc.add(curlForce + attrForce)  # simple addition of the 2 forces

Unfortunately, doing so gives me very different results from your original sketch entitled "Swarm Formation by Force Fields".

Capture d’écran (115)

  • Particles (boids) are sucked by the attractors instead of flocking around
  • Gravity doesn't seem to apply (despite IGravity(0,0,-2) in setup())
  • Curl force is too strong when attraction force is removed (boids seem to be on rails)

I would really appreciate if you could explain how did you mix the curl force and attraction force together to get such a smooth motion.

Respectfully,

solub

Edit: Full script if needed

add_library('peasycam')
add_library('hemesh')
add_library('igeo')

W, H, D, s = 10, 15, 10, 100 
N = W*H*D

def setup():
    #size(1000, 600, P3D)
    fullScreen(P3D)
    randomSeed(1008)
    strokeWeight(.7)
    stroke(60)
    noFill()
    
    global curl, attr, boids
    
    cam = PeasyCam(this, 1600)
    boids = [Boid() for i in xrange(25)]
    
    curl = ICompoundField()
    attr = ICompoundField()
    
    for i in xrange(10):
        pt = IRand.pt(W*s*.25, 100, D*s*.25, W*s*.75, H*s, D*s*.75)
        curl.add(IPointCurlField(pt, IVec(0, -1, 0)).intensity(-20))
        attr.add(IAttractor(pt).intensity(20))

    IGravity(0,0,-2)
    
    
def draw():
    background('#FFFFFF')
    translate((-W*s)>>1, (-H*s)>>1, (-D*s)>>1)
    
    # Displaying the random points in the field
    pushStyle()
    stroke(255, 30, 30)
    strokeWeight(8)
    for p in curl.pointFields:
        point(p.pos().x(), p.pos().y(), p.pos().z())
    popStyle()


    # Updating boids
    for b in boids:
        b.render()
        b.update()
        b.flock()
        b.applyForce() #Trying to apply the forces of the compound fields to the boids
    


    
class Boid(object):
    def __init__(self):
        self.pos = PVector(random(W*s), 0, random(D*s))
        self.vel = PVector().setMag(3)
        self.acc = PVector()
        self.radius = 50
        self.maxSpeed = 1.5
        self.maxForce = .1
        self.trail = []

                
    def update(self):    
        self.pos.add(self.vel)
        self.vel.add(self.acc)
        self.vel.limit(self.maxSpeed)
        self.acc.mult(0)
        
    
    def applyForce(self):
        curlForce = curl.get(IVec(self.pos.x, self.pos.y, self.pos.z))
        curlForce = PVector(curlForce.x(), curlForce.y(), curlForce.z())
        
        attrForce = attr.get(IVec(self.pos.x, self.pos.y, self.pos.z))
        attrForce = PVector(attrForce.x(), attrForce.y(), attrForce.z())
        
        self.acc.add(curlForce + attrForce)
            
        
    def flock(self):
        count = 0
        aVel = PVector() #average velocity
        aPos = PVector() #average position
        aDif = PVector() #average difference

        for b in boids:
            d = self.pos.dist(b.pos)
            if b != self and d < self.radius:
                count += 1
        
                aVel += b.vel
                aPos += b.pos
                
                diff = self.pos.copy().sub(b.pos)
                aDif += diff.div(d) #inversional to distance (the farther, the lower the magnitude)
                    
        if count > 0:      
            
            #Alignment 
            aVel.div(count).setMag(self.maxSpeed) #maxSpeed prevent from steering too hard
            alignSteering = aVel.sub(self.vel).limit(self.maxForce)
            
            #Cohesion
            aPos.div(count)
            coheSteering = aPos.sub(self.pos).setMag(self.maxSpeed).sub(self.vel).limit(self.maxForce)
            
            #Separation
            aDif.div(count)
            sepaSteering = aDif.setMag(self.maxSpeed).sub(self.vel).limit(self.maxForce)
            

            self.acc.add(coheSteering + sepaSteering) #+ alignSteering # Alignment set to 0 by Sugihara san in his original sketch
                                                                                
        
    def render(self):
        pushStyle()
        strokeWeight(8)
        point(self.pos.x, self.pos.y, self.pos.z) 
        popStyle()
        
        # Trail
        if frameCount%10 == 0:
            self.trail.append(PVector(self.pos.x, self.pos.y, self.pos.z))
            
        if len(self.trail) > 0:
            for i in xrange(1, len(self.trail)):
                line(self.trail[i-1].x, self.trail[i-1].y, self.trail[i-1].z, self.trail[i].x, self.trail[i].y, self.trail[i].z)