home contents changes options help

a little test with an early blender tool by macouno, http://studio.kyperjokki.fi/data/swarm/0001_0101.avi

blend for that stupidity is swarm3.blend

@path "classes"

@include "Stationary.tz" @include "Control.tz" @include "Mobile.tz"

@define SWARM_SIZE 80.

# # This simulation is inspired by Craig Reynolds classic Boids flocking # algorithm. The implementation is a bit more complicated than some of # the other breve demos. # # The idea behind the algorithm is that each bird is influenced by three # main urges: # 1) the urge to avoid collisions with neighbors # 2) the urge to stay close to neighbors # 3) the urge to match the velocity of neighbors # # These three urges are implemented in the Birds class, and by giving # them different weights, we produce different flocking behaviors. # Additionally, this simulation adds a "random" urge, and an urge # to stay close to the center of the world. # # If a bird touches the ground, it will land and stay on the ground # for a short time before rejoining the flock. # # Run the demo as it is and try the different behaviors from the # Simulation menu. Then try modifying the urge weights in the # Birds class yourself to change the behavior of the flock. # # This demo was O(n^2) previous to breve 1.2. We used to make every # bird look at the location of every other bird in order to assess # whether it was close enough to have an influence on behavior. Starting # in breve version 1.2 we support "neighborhoods", a very fast and # efficient way for objects in the simulation to find other objects # within a certain range. # # It is unfortunate that sometimes it is difficult to see all the birds at # once, and that if the flock breaks in two, the camera may point in between # them such that neither is visible. #

Controller Swarm.

Control : Swarm { + variables: birds (list). item (object). breveTexture (int). cloudTexture (int). selection (object).

# the menu items corresponding to different flocking behaviors

wackyMenu (object). obedientMenu (object). normalMenu (object).

+ to click on item (object): if selection: selection hide-neighbor-lines. if item: item show-neighbor-lines.

selection = item.

super click on item.

+ to init: floor (object).

# Set up menus to modify the type of movement allowed.

self add-menu named "Smoosh The Birdies" for-method "squish". self add-menu-separator. obedientMenu = (self add-menu named "Flock Obediently" for-method "flock-obediently"). normalMenu = (self add-menu named "Flock Normally" for-method "flock-normally"). wackyMenu = (self add-menu named "Flock Wackily" for-method "flock-wackily").

self enable-lighting. self enable-smooth-drawing. self move-light to (0, 20, 20).

breveTexture = (self load-image from "breve.sgi"). cloudTexture = (self load-image from "clouds.sgi").

# Add a huge floor.

floor = new Stationary. floor register with-shape (new Shape init-with-cube size (100, 2, 100)) at-location (0, -5, 0). floor catch-shadows.

birds = SWARM_SIZE new Birds.

birds set-bitmap to breveTexture.

# we'll call this method to set up the initial bird behavior.

self flock-normally.

self set-background-texture to cloudTexture.

self offset-camera by (5, 1.5, 6).

self enable-shadows.

+ to iterate: location (vector). topDiff (double). highLoc (vector).

self update-neighbors.

# get the average location, and point the camera at it.

foreach item in birds: { item fly. location += (item get-location).

if | (item get-location) | > | highLoc |: highLoc = (item get-location). }

# in the context of a number, the list represents the number of items # in the list.

location /= birds. # print "the highest location is $location".

topDiff = 0.0.

foreach item in birds: { if topDiff < |location - (item get-location) |: topDiff = | location - (item get-location) |. }

# we'll try to keep the camera aimed at the center of the # flock, and zoom in and out depending on how spread out the # flock is. it's doesn't work very well :).

self aim-camera at location. self zoom-camera to (.5 * topDiff) + 10.

# call the superclass iterate method to step the simulation forward.

super iterate.

# The following methods are the menu items we provide.

+ to squish: birds move to (0, 0, 0).

+ to flock-normally: birds flock-normally. normalMenu check. obedientMenu uncheck. wackyMenu uncheck.

+ to flock-obediently: birds flock-obediently. normalMenu uncheck. obedientMenu check. wackyMenu uncheck.

+ to flock-wackily: birds flock-wackily. normalMenu uncheck. obedientMenu uncheck. wackyMenu check. }

Mobile : Birds { + variables: landed (int).

# These are all parameters that can change the way the flock # behaves. Look at the flock-normally method for an example.

cruiseDistance (float).

maxAcceleration (float). maxVelocity (float).

wanderConstant (float). worldCenterConstant (float). centerConstant (float). velocityConstant (float). spacingConstant (float).

+ to init: # register the object, set the initial location, velocity and color.

self register with-shape ((new Shape) init-with-sphere radius .1). self move to random[(10, 10, 10)] - (5, -5, 5). self set-velocity to random[(20, 20, 20)] - (10, 10, 10). self set-color to random[(1, 1, 1)].

# when we hit the ground, we want to land on it using the method "land". # it gets called automatically when the collision occurs.

self handle-collisions with-type "Stationary" with-method "land".

# set the neighborhood radius that we will look in to find neighbors.

self set-neighborhood-size to 3.0.

+ to flock-normally: wanderConstant = 4.0. worldCenterConstant = 5.0. centerConstant = 2.0. velocityConstant = 2.0. spacingConstant = 5.0.

maxVelocity = 15. maxAcceleration = 15. cruiseDistance = .4.

+ to flock-normally-old: wanderConstant = 6.0. worldCenterConstant = 5.0. centerConstant = 2.0. velocityConstant = 4.0. spacingConstant = 5.0.

maxVelocity = 20. maxAcceleration = 12. cruiseDistance = .4.

+ to flock-obediently: # The obedient flocking has a lower maxAcceleration, which means that # the objects don't react as quickly. This has a calming effect on the # agents.

wanderConstant = 6.0. worldCenterConstant = 6.0. centerConstant = 2.0. velocityConstant = 3.0. spacingConstant = 4.0.

maxVelocity = 16. maxAcceleration = 20. cruiseDistance = 1.

+ to flock-wackily: # The wacky flocking has a high maximum acceleration so that the # agents act heavily on all of their impulses every iteration. # This makes them swarm like insects.

wanderConstant = 8.0. worldCenterConstant = 14.0. centerConstant = 1.0. velocityConstant = 3.0. spacingConstant = 4.0.

maxVelocity = 20. maxAcceleration = 30. cruiseDistance = .5.

+ to land with ground (object): # if we hit the ground, we stop moving and set the landed flag to 1.

# print "Landing".

self set-acceleration to (0, 0, 0). self set-velocity to (0, 0, 0).

landed = 1.

# we don't want to keep colliding with the ground, or else we'll # keep on getting stuck again at every iteration--move up just a # tiny bit.

self offset by (0, 0.1, 0).

+ to check-landed: # Ask the object if it has landed...

return landed.

+ to fly: # This is the method which does it all.

bird (object). toNeighbor (vector).

centerUrge (vector). worldCenterUrge (vector). velocityUrge (vector). spacingUrge (vector). wanderUrge (vector).

acceleration (vector).

newVelocity (vector).

neighbors (list).

take-off (int).

# get a list of neighbors within our neighborhood-size # (set during init), and check to see if they're visible. # using get neighbors, we very quickly get a list of # eligible objects and then check them further. this is # much faster than checking every bird in the simulation.

foreach bird in (self get-neighbors): if (self check-visibility of bird): push bird onto neighbors.

# if we're on the ground now, we'll pick a random number to see if we # take off again. The chances are 1 in 40, which is actually pretty # reasonable since this code is called every iteration.

if landed: { take-off = random[40].

if take-off == 1: { # if we decide to take off, pick a random direction, # but not towards the ground.

landed = 0. self set-velocity to random[(.1, 1.1, .1)] - (.05, 0, .05). } else { return. } }

# get the urge towards the center, and velocity matching urge.

centerUrge = (self get-center-urge with neighbors). velocityUrge = (self get-velocity-urge with neighbors).

# are we too close to our neighbors? get a vector which reflects that # urge.

foreach bird in neighbors: { toNeighbor = (self get-location) - (bird get-location). if |toNeighbor| < cruiseDistance: spacingUrge += toNeighbor. }

# Are we wandering too far from the center of the world?

if |(self get-location)| > 10: worldCenterUrge = -(self get-location).

# Add a random component to the accumulation.

wanderUrge = random[(2, 2, 2)] - (1, 1, 1).

# normalize all of the vectors to length 1.

if |spacingUrge|: spacingUrge /= |spacingUrge|. if |worldCenterUrge|: worldCenterUrge /= |worldCenterUrge|. if |velocityUrge|: velocityUrge /= |velocityUrge|. if |centerUrge|: centerUrge /= |centerUrge|. if |wanderUrge|: wanderUrge /= |wanderUrge|.

wanderUrge = wanderConstant. worldCenterUrge = worldCenterConstant. centerUrge = centerConstant. velocityUrge = velocityConstant. spacingUrge *= spacingConstant.

acceleration = (worldCenterUrge + centerUrge + velocityUrge + spacingUrge + wanderUrge).

if |acceleration| != 0: acceleration /= |acceleration|. self set-acceleration to maxAcceleration * acceleration.

newVelocity = (self get-velocity).

if |newVelocity| > maxVelocity: newVelocity = maxVelocity * newVelocity/|newVelocity|.

self set-velocity to newVelocity.

+ to get-velocity-urge with flock (list): item (object). count (float). velocity (vector).

# get the average velocity of all the visible birds in the flock. foreach item in flock: { count += 1. velocity += (item get-velocity). }

if count == 0: return (0, 0, 0).

velocity /= count.

return velocity - (self get-velocity).

+ to get-center-urge with flock (list): item (object). count (float). center (vector).

# get the average location of all the visible birds in the flock.

foreach item in flock: { count += 1. center += (item get-location). }

if count == 0: return (0, 0, 0).

center /= count.

return center - (self get-location).

+ to check-visibility of item (object): # An item is visible if it is within a certain angle (2.0 radians) # of the direction we're facing (assumed to be a vector in the # direction we're moving).

if (item == self): return 0. if !(item is a "Birds"): return 0. if (self get-angle to item) > 2.0: return 0. if (item check-landed): return 0.

return 1.

+ to get-angle to otherMobile (object): tempVector (vector).

tempVector = (otherMobile get-location) - (self get-location). return angle((self get-velocity), tempVector). }