Page MenuHome

swarm[1].0.2.py

swarm[1].0.2.py

#!BPY
"""
Name: 'Blender Swarm'
Blender: 248
Group: 'Wizards'
Tooltip: 'Swarm.'
"""
__author__ = "macouno"
__url__ = ("http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/Animation/swarm1.0.2", "http://www.alienhelpdesk.com")
__version__ = "0.2 16/07/06"
__bpydoc__ = """\
Creates a swarm of objects moving randomly around a central object.
Usage:
Shift the objects.
"""
#############################################################
# Code history
#############################################################
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2006: macouno, http://www.macouno.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
import Blender
from Blender import *
import math
import random
####################################################
# GLOBALS
####################################################
## Version.
VERSION ='0.2'
## Settings.
BUTTON = {
'FRAMES': Draw.Create(100), # The nr of frames to animate.
'STEPLEN': Draw.Create(2), # The nr of frames to animate.
'SPEED': Draw.Create(0.5), # The distance to travel in one frame.
'USE_CURRENT': Draw.Create(0), # Whether or not to use the current.
'CURRENT': Draw.Create(0.2), # The force of the current.
'CURRENTDIR': Draw.Create(1), # The axis of the current.
'CONTAINER': Draw.Create("Plane"), # The object to use as the container.
'OBNAME': Draw.Create("Cube"), # The string to look for in object names.
'USE_CONTAINER': Draw.Create(1), # Whether or not to use the container.
'CONDIST': Draw.Create(5.0), # The distance at which objects try to avoid the container.
'ANIMPARENT': Draw.Create(1), # Whether the script should animate the parent object.
'USE_OBNAME': Draw.Create(1), # Whether or not to use the obname value.
'USE_INFMAX': Draw.Create(1), # Whether or not to use the Gmax value.
'INFMAX': Draw.Create(5.0), # The distance at which objects start to avoid each other.
'USE_INFMIN': Draw.Create(1), # Whether or not to use the Gmax value.
'INFMIN': Draw.Create(2.0), # The distance at which objects excert the maximum influense on each other.
'USE_LIM': Draw.Create(1), # Whether or not to use the Gmax value.
'LIM': Draw.Create(50.0), # The minimal distance to the closest object.
'USE_MAXROT': Draw.Create(1), # Whether or not to use the Gmax value.
'MAXROT': Draw.Create(20.0), # The minimal distance to the closest object.
'USE_ROLL': Draw.Create(1), # Whether or not to roll during turn.
'ROLL': Draw.Create(30.0), # The ammount to roll during a turn.
'USE_LIMROT': Draw.Create(1), # Whether or not to use the limrot value.
'LIMROT': Draw.Create(5.0), # The maximum displacement angle in the limited plane.
'LIMDIR': Draw.Create(1), # The plane to constrain the movement to.
'USE_TARGET': Draw.Create(1), # Whether or not to use the target value.
'TARGET': Draw.Create(2), # The target location for each object.
'FLOCK': Draw.Create(1), # Whether or not to really behave like a flock.
'DFLOCK': Draw.Create(1), # Whether or not to make the flock behaviour depend on the distance to the flock centre.
'XFLOCK': Draw.Create(0.5), # The ammount of influense of the flock vectors
'STARTROT': Draw.Create(1) # Whether or not to use the original rotation of the objects.
}
DATA = {
'MESSAGE': "a", # The message string.
'RESULT': "a", # The result string.
}
## Gathered data.
STATE = {
'ERROR': 0, # 1 if an error has taken place.
'OBJECT': 0, # The objects to animate.
'OBNAME': 0, # The objects to animate.
'OBNR': 0, # The total nr of objects.
'LOCATION': 0, # The current locations of the objects.
'ROTATION': 0, # The current rotations of the objects.
'TARLOC': 0, # The places the objects want to go to.
'TARROT': 0, # The rotations the objects want to have.
'IPO': 0 # The ipos for the objects.
}
####################################################
# BASIC FUNCTIONS
####################################################
def Error(message):
DATA['MESSAGE'] = "An error occured!";
DATA['RESULT'] = message;
STATE['ERROR'] =1;
####################################################
# VECTOR FUNCTIONS
####################################################
## Get the vector from one point to another.
def PtoPVector(v1,v2):
return Mathutils.Vector(v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]);
## Normalise a vector.
def NormalizeVector(v):
return Mathutils.Vector(Mathutils.Vector(v)).normalize();
## Get the angle between two vectors.
def VtoVAngle(v1,v2):
if Mathutils.Vector(v1).length == 0.0 or Mathutils.Vector(v2).length == 0.0:
Angle = 0.0;
else:
Angle = Mathutils.AngleBetweenVecs(Mathutils.Vector(v1), Mathutils.Vector(v2));
return Angle;
## Rotate a vector according to a matrix.
def RotVtoMat(v, m):
return m * Mathutils.Vector(v[0],v[1],v[2]);
####################################################
# MATRIX FUNCTIONS
####################################################
## Create a rotation/transformation matrix.
def RotMatrix(deg, size, axis):
return Mathutils.RotationMatrix(float(deg), size, axis);
####################################################
# LOCATION FUNCTIONS
####################################################
## Get the distance between two locations.
def PtoPDist(v1, v2):
return Mathutils.Vector(v1[0]-v2[0],v1[1]-v2[1],v1[2]-v2[2]).length;
####################################################
# TRANSFORMATION FUNCTION
####################################################
# Apply a matrix to a vert and return a vector.
def apply_transform(verts, matrix):
x, y, z = verts
xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
return Mathutils.Vector(
x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc,
x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc,
x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc)
# Apply a matrix to a vert and return a vector.
def normal_transform(verts, matrix):
matrix = matrix.rotationPart()
x, y, z = verts
return Mathutils.Vector(
x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0],
x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1],
x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2])
####################################################
# ADD A BEZIER POINT TO AN EXISTING IPO CURVE
####################################################
## Add a x location ipo bezier point.
def AddIpo(ipo, type, frame, var):
if frame >= 0:
try:
Ipo = ipo.getCurve(type);
if Ipo.evaluate(float(frame)) != var:
Ipo.addBezier((float(frame),var));
except:
Ipo = ipo.addCurve(type);
if "Rot" in type:
Ipo.setInterpolation('Bezier');
else:
Ipo.setInterpolation('Linear');
Ipo.addBezier((float(frame),var));
####################################################
# DRAW A LINE AND TEXT
####################################################
## Draw a title in small text and a line right beneath it.
def DrawTitle(Text, Pos):
BGL.glColor3f(0.7, 0.7 , 0.8);
BGL.glRectf(4, (Pos - 4), 267, (Pos -3));
BGL.glColor3f(0.9, 0.9, 0.95);
BGL.glRasterPos2d(20, Pos);
Draw.Text(Text, "small");
####################################################
# FIND OUT IF THE OBJECT SHOULD AVOID A FACE OF THE CONTAINER
####################################################
def avoidContainer(container, obLoc, Limit):
tarObj = Object.Get(container);
ObMatrix = Mathutils.Matrix(tarObj.getMatrix('worldspace'));
MName = tarObj.getData(1);
me = NMesh.GetRaw(MName);
AvoidVec = [0.0,0.0,0.0];
## Loop through the faces.
for f in me.faces:
inSide = True;
## Get the face normal.
Normal = normal_transform(f.no, ObMatrix);
vx = [0.0,0.0,0.0];
## Loop through the verts.
for v1 in f.v:
## Get the vert coords.
v1 = apply_transform(v1.co, ObMatrix);
vx = [(v1[0] + vx[0]), (v1[1] + vx[1]), (v1[2] + vx[2])];
vx = [(vx[0] / len(f.v)), (vx[1] / len(f.v)), (vx[2] / len(f.v))];
## Get the dot product
dot = - Mathutils.DotVecs(PtoPVector(vx,obLoc),Normal);
## If the point is at the right distance in front of the face.
if dot < Limit and dot > 0:
## Loop through the verts.
for v1 in f.v:
## Only continue if nessecary.
if inSide == True:
## Loop again.
for v2 in f.v:
## Only continue if nessecary.
if v1.co != v2.co and inSide == True:
xNormal = Mathutils.Vector(PtoPVector(v1.co,v2.co)).normalize();
vx = - Mathutils.DotVecs(PtoPVector(v1.co,obLoc),xNormal);
## Use Limit if you need a buffer around the edges for overlaps, use 0.0 for an exact shape.
if vx > Limit:
inSide = False;
else:
inSide = False;
## Add the normal to the avoidance vector if the object is close enough.
if inSide == True:
AvoidVec = [(AvoidVec[0] + Normal[0]), (AvoidVec[1] + Normal[1]), (AvoidVec[2] + Normal[2])];
return AvoidVec;
####################################################
# TARGETS
####################################################
## Get a random target object id.
def RandTarget(ob):
if STATE['OBNR'] >= 2:
if "x" in STATE['OBNAME'][ob]:
This = "y";
else:
This = "x";
Sel = 0;
while Sel == 0:
RandSel = int(math.floor(STATE['OBNR'] * random.random()));
if RandSel != ob: #and This in STATE['OBNAME'][RandSel]:
Sel = 1;
STATE['TAROB'][ob] = RandSel;
## Get the parent object target.
def ParentTarget(ob, frame):
if STATE['OBNAME'][ob] != BUTTON['OBNAME'].val:
try:
ipo = Object.Get(BUTTON['OBNAME'].val).ipo;
xIpo = ipo.getCurve("LocX").evaluate(float(frame));
yIpo = ipo.getCurve("LocY").evaluate(float(frame));
zIpo = ipo.getCurve("LocZ").evaluate(float(frame));
return [xIpo, yIpo, zIpo];
except:
return Object.Get(BUTTON['OBNAME'].val).getLocation();
else:
return [0.0,0.0,0.0];
####################################################
# CHECK THE MAX ANGLE
####################################################
## make the rotation correct according to the max rot.
def CheckMaxAngle(v1, v2):
# if we're constraining to a plane.
if BUTTON['USE_LIMROT'].val == 1:
if BUTTON['LIMDIR'].val == 1:
CheckYRot = VtoVAngle([v1[0],v1[1],v1[2]],[v1[0],v1[1],0.0]);
v3 = [v1[0],v1[1],0.0];
elif BUTTON['LIMDIR'].val == 2:
CheckYRot = VtoVAngle([v1[0],v1[1],v1[2]],[v1[0],0.0,v1[2]]);
v3 = [v1[0],0.0,v1[2]];
elif BUTTON['LIMDIR'].val == 3:
CheckYRot = VtoVAngle([v1[0],v1[1],v1[2]],[0.0,v1[1],v1[2]]);
v3 = [0.0,v1[1],v1[2]];
if CheckYRot > BUTTON['LIMROT'].val:
if BUTTON['LIMROT'].val == 0.0:
ChangeRot = 1;
else:
ChangeRot = (1 - (BUTTON['LIMROT'].val / CheckYRot));
DubRot = 1 - ChangeRot;
v1 = [((v1[0] * DubRot) + (v3[0] * ChangeRot)), ((v1[1] * DubRot) + (v3[1] * ChangeRot)), ((v1[2] * DubRot) + (v3[2] * ChangeRot))];
## See what the angle is between the previous and current moves.
CheckAngle = VtoVAngle(v1, v2);
## If the angle is bigger than the maximum change the vector.
if CheckAngle > BUTTON['MAXROT'].val:
Factor = (BUTTON['MAXROT'].val / CheckAngle);
if round(CheckAngle, 3) == 180.0:
if BUTTON['LIMDIR'].val == 2:
Axis = "y";
elif BUTTON['LIMDIR'].val == 3:
Axis = "x";
else:
Axis = "z";
RotMax = Mathutils.RotationMatrix(float(BUTTON['MAXROT'].val), 3, Axis);
v1 = RotMax * Mathutils.Vector(v1[0], v1[1],v1[2]);
else:
if Mathutils.Vector(v2).length != 0.0:
v2 = NormalizeVector(v2);
v1 = [(v1[0] * Factor) + (v2[0] * (1 - Factor)),(v1[1] * Factor) + (v2[1] * (1 - Factor)),(v1[2] * Factor) + (v2[2] * (1 - Factor))];
return v1;
####################################################
# GET THE VECTOR FOR STARTING ROTATION
####################################################
def GetStartVector(rot):
v1 = [0.0,-1.0,0.0];
if rot[0] != 0.0:
RotMax = Mathutils.RotationMatrix(float(rot[0]), 3, "x");
v1 = RotMax * Mathutils.Vector(v1[0], v1[1],v1[2]);
if rot[1] != 0.0:
RotMax = Mathutils.RotationMatrix(float(rot[1]), 3, "y");
v1 = RotMax * Mathutils.Vector(v1[0], v1[1],v1[2]);
if rot[2] != 0.0:
RotMax = Mathutils.RotationMatrix(float(rot[2]), 3, "z");
v1 = RotMax * Mathutils.Vector(v1[0], v1[1],v1[2]);
return v1;
####################################################
# THE SCRIPT
####################################################
def run():
print "-----------------------------------STARTING---------------------------";
####################################################
# PRESCRIPT
####################################################
STATE['ERROR'] = 0;
## Get the scene.
scene = Blender.Scene.GetCurrent();
cntx = scene.getRenderingContext();
if BUTTON['USE_OBNAME'].val == 1:
## Get a list of all objects with the namestring in their names.
STATE['OBJECT'] = [ob for ob in scene.getChildren() if BUTTON['OBNAME'].val in ob.getName()];
else:
## Get a list of all objects with the namestring in their names.
STATE['OBJECT'] = [ob for ob in scene.getChildren()];
## Get a list of all the names of the objects.
STATE['OBNAME'] = [ob.getName() for ob in STATE['OBJECT']];
## Get a list of all the current locations of the objects.
STATE['LOCATION'] = [ob.getLocation() for ob in STATE['OBJECT']];
## Get a list of all the target locations of the objects.
STATE['TARLOC'] = [ob for ob in STATE['LOCATION']];
## Get a list of all the cuyrrent rotationes of the objects.
STATE['ROTATION'] = [[math.degrees(ob.RotX), math.degrees(ob.RotY), math.degrees(ob.RotZ)] for ob in STATE['OBJECT']];
## Get a list of all the target rotations of the objects.
STATE['TAROB'] = [1 for ob in STATE['OBJECT']];
## Get the transformation vector for each object.
if BUTTON['STARTROT'].val == 1:
STATE['TRANSLOC'] = [GetStartVector(rot) for rot in STATE['ROTATION']];
else:
STATE['TRANSLOC'] = [[0.0,0.0,0.0] for ob in STATE['OBNAME']];
## Get the length of the list with objects.
STATE['OBNR'] = len(STATE['OBNAME']);
## Create an ipo for each object.
STATE['IPO'] = [Ipo.New('Object', str("swarm_" + str(ob))) for ob in STATE['OBNAME']];
## Loop through all objects.
for a in range(STATE['OBNR']):
if BUTTON['ANIMPARENT'].val == 0:
if STATE['OBNAME'][a] != BUTTON['OBNAME'].val:
## Link each ipo to it's object.
STATE['OBJECT'][a].setIpo(STATE['IPO'][a]);
else:
## Link each ipo to it's object.
STATE['OBJECT'][a].setIpo(STATE['IPO'][a]);
## Check for errors;
## Set targets if nessecary.
if BUTTON['USE_TARGET'].val == 1:
if STATE['OBNR'] < 3:
Error("You need at least 2 objects in this mode!");
if BUTTON['USE_CONTAINER'].val == 1:
try:
tarObj = Object.Get(BUTTON['CONTAINER'].val);
MName = tarObj.getData(1);
except:
Error("No container mesh object present!");
if BUTTON['FLOCK'].val == 0:
BUTTON['DFLOCK'].val = 0;
####################################################
# SCRIPT
####################################################
## no error has occured.
if STATE['ERROR'] != 1:
## Loop through all the frames to animate.
for frame in range(BUTTON['FRAMES'].val):
scene.update();
## Draw the progress bar.
progress = round(float(frame + 1) / float(BUTTON['FRAMES'].val), 1);
framestring = str(100 * progress)+ "% frame " + str(frame + 1);
Window.DrawProgressBar(progress, framestring)
## The midpoint of the group.
if BUTTON['USE_LIM'].val == 1 or BUTTON['DFLOCK'].val == 1:
GroupMid = [0.0,0.0,0.0];
for loc in STATE['LOCATION']:
GroupMid = [(GroupMid[0] + loc[0]), (GroupMid[1] + loc[1]), (GroupMid[2] + loc[2])];
GroupMid = [(GroupMid[0] / STATE['OBNR']), (GroupMid[1] / STATE['OBNR']), (GroupMid[2] / STATE['OBNR'])];
## Get the average, minmum and maximum distance from the group centre.
if BUTTON['DFLOCK'].val == 1:
GroupMin = 0;
GroupMax = 0;
GroupAve = 0;
for a in range(STATE['OBNR']):
DistAnce = PtoPDist(GroupMid, STATE['LOCATION'][a]);
if DistAnce < GroupMin or a == 0:
GroupMin = DistAnce;
if DistAnce > GroupMax or a == 0:
GroupMax = DistAnce;
GroupAve = GroupAve + DistAnce;
GroupAve = GroupAve / STATE['OBNR'];
## Loop through the objects to move them all in turn.
for a in range(STATE['OBNR']):
## Set targets if nessecary.
if BUTTON['USE_TARGET'].val == 1:
## If the object is chasing another object make the target their target object's location.
if BUTTON['TARGET'].val == 2:
if frame == 0:
RandTarget(a);
STATE['TARLOC'][a] = STATE['LOCATION'][STATE['TAROB'][a]];
##Chase parent check
elif BUTTON['TARGET'].val == 3:
if STATE['OBNAME'][a] == BUTTON['OBNAME'].val and BUTTON['ANIMPARENT'].val == 0:
STATE['ERROR'] = 1;
else:
STATE['ERROR'] = 0;
STATE['TARLOC'][a] = ParentTarget(a, frame);
## If the object has to be moved at all.
if STATE['ERROR'] != 1:
## Create a 0 dodge vector for alternate than target directions.
DodgeVector = [0.0,0.0,0.0];
setDodge = 0;
bigDodge = 0;
####################################################
# ADDED FLOCK BEHAVIOUR
####################################################
if BUTTON['FLOCK'].val == 1:
FlockVector = [0.0,0.0,0.0];
for b in range(STATE['OBNR']):
v1 = STATE['TRANSLOC'][b];
FlockVector = [(FlockVector[0] + v1[0]), (FlockVector[1] + v1[1]), (FlockVector[2] + v1[2])];
FlockVector = NormalizeVector([(FlockVector[0] / STATE['OBNR']), (FlockVector[1] / STATE['OBNR']), (FlockVector[2] / STATE['OBNR'])]);
####################################################
# AVOID THE CONTAINER
####################################################
if BUTTON['USE_CONTAINER'].val == 1:
AvoidVector = avoidContainer(BUTTON['CONTAINER'].val, STATE['LOCATION'][a], BUTTON['CONDIST'].val);
if AvoidVector != [0.0,0.0,0.0]:
DodgeVector = NormalizeVector(AvoidVector);
setDodge = 1;
bigDodge = 1;
"""
if BUTTON['USE_LIMROT'].val == 1 and VtoVAngle(DodgeVector, STATE['TRANSLOC'][a]) > 135.0:
if BUTTON['LIMDIR'].val == 2:
Axis = "y";
elif BUTTON['LIMDIR'].val == 3:
Axis = "x";
else:
Axis = "z";
RotMax = Mathutils.RotationMatrix(float(BUTTON['MAXROT'].val), 3, Axis);
DodgeVector = RotMax * Mathutils.Vector(STATE['TRANSLOC'][a]);
print frame, STATE['OBNAME'][a], "Revectoring";
"""
####################################################
# AVOID THE OTHER OBJECTS
####################################################
if setDodge == 0:
for b in range(STATE['OBNR']):
if a != b:
d1 = PtoPDist(STATE['LOCATION'][a], STATE['LOCATION'][b]);
if BUTTON['USE_INFMAX'].val == 1 and d1 < BUTTON['INFMAX'].val:
v1 = PtoPVector(STATE['LOCATION'][a], STATE['LOCATION'][b]);
v2 = PtoPVector(STATE['TARLOC'][a] , STATE['LOCATION'][a]);
CheckAngle = VtoVAngle(v1,v2);
if CheckAngle > 90:
v1 = NormalizeVector(v1);
if BUTTON['USE_INFMIN'].val == 1:
Max = BUTTON['INFMAX'].val - BUTTON['INFMIN'].val;
d1 = d1 - BUTTON['INFMIN'].val;
else:
Max = BUTTON['INFMAX'].val;
if d1 <= 0.0:
Factor = 1;
else:
Factor = 1 - (d1 / Max);
DodgeVector = [(DodgeVector[0] + (v1[0] * Factor)), (DodgeVector[1] + (v1[1] * Factor)), (DodgeVector[2] + (v1[2] * Factor))];
setDodge = 1;
####################################################
# STAY NEAR THE GROUP CENTRE
####################################################
if BUTTON['USE_LIM'].val == 1 and setDodge == 0:
## Get the distance to the group centre;
d1 = PtoPDist(STATE['LOCATION'][a], GroupMid);
if d1 > BUTTON['LIM'].val:
ReturnVector = NormalizeVector(PtoPVector(GroupMid, STATE['LOCATION'][a]));
DodgeVector = [(ReturnVector[0] + DodgeVector[0]), (ReturnVector[1] + DodgeVector[1]), (ReturnVector[2] + DodgeVector[2])];
setDodge = 1;
####################################################
# CALCULATE THE ACTUAL MOVEMENT
####################################################
OldLoc = STATE['LOCATION'][a];
OldRot = [STATE['ROTATION'][a][0], STATE['ROTATION'][a][1], STATE['ROTATION'][a][2]];
OldTransLoc = [STATE['TRANSLOC'][a][0], STATE['TRANSLOC'][a][1], STATE['TRANSLOC'][a][2]];
## If we have to dodge another object.
if setDodge == 1:
v1 = DodgeVector;
d1 = PtoPDist([0.0,0.0,0.0], DodgeVector);
else:
v1 = PtoPVector(STATE['TARLOC'][a] , STATE['LOCATION'][a]);
d1 = PtoPDist(STATE['TARLOC'][a], STATE['LOCATION'][a]);
v1 = NormalizeVector(v1);
## For a true flock make sure they copy each other somewhat.
if bigDodge == 0 and BUTTON['FLOCK'].val == 1:
if BUTTON['DFLOCK'].val == 1:
d2= PtoPDist(GroupMid, STATE['LOCATION'][a]);
if float(GroupMax) == 0.0:
fFactor = 1 * BUTTON['XFLOCK'].val;
vFactor = 1 - fFactor;
else:
fFactor = (float(d2) / float(GroupMax)) * BUTTON['XFLOCK'].val;
vFactor = 1.0 - fFactor;
else:
fFactor = 1 * BUTTON['XFLOCK'].val;
vFactor = 1 - fFactor;
v1 = NormalizeVector([((v1[0]* vFactor) + (FlockVector[0] * fFactor)), ((v1[1] * vFactor) + (FlockVector[1] * fFactor)), ((v1[2] * vFactor) + (FlockVector[2] * fFactor))]);
v2 = OldTransLoc;
## Check for maximum rotation.
if BUTTON['USE_MAXROT'].val == 1:
v1 = CheckMaxAngle(v1, v2);
## Get the vector at the correct speed.
STATE['TRANSLOC'][a] = [(v1[0] * BUTTON['SPEED'].val), (v1[1] * BUTTON['SPEED'].val), (v1[2] * BUTTON['SPEED'].val)];
STATE['LOCATION'][a] = Mathutils.Vector(STATE['LOCATION'][a]) + Mathutils.Vector(STATE['TRANSLOC'][a]);
## Add the current temporarily for correct rotation.
if BUTTON['USE_CURRENT'].val == 1:
if BUTTON['CURRENTDIR'].val == 1:
STATE['TRANSLOC'][a] = [(STATE['TRANSLOC'][a][0] + BUTTON['CURRENT'].val), STATE['TRANSLOC'][a][1], STATE['TRANSLOC'][a][2]];
elif BUTTON['CURRENTDIR'].val == 2:
STATE['TRANSLOC'][a] = [STATE['TRANSLOC'][a][0], (STATE['TRANSLOC'][a][1] + BUTTON['CURRENT'].val), STATE['TRANSLOC'][a][2]];
elif BUTTON['CURRENTDIR'].val == 3:
STATE['TRANSLOC'][a] = [STATE['TRANSLOC'][a][0], STATE['TRANSLOC'][a][1], (STATE['TRANSLOC'][a][2] + BUTTON['CURRENT'].val)];
####################################################
# CALCULATE THE ROTATIONS
####################################################
if STATE['TRANSLOC'][a][0] != 0.0:
ZAngle = (math.degrees(math.atan2(STATE['TRANSLOC'][a][1],STATE['TRANSLOC'][a][0])) * 0.1) + 9;
RotChange = ZAngle - OldRot[2];
if RotChange > 18:
RotChange = RotChange - 36;
elif RotChange < -18:
RotChange = RotChange + 36;
ZAngle = OldRot[2] + RotChange;
else:
ZAngle = OldRot[2];
if (STATE['TRANSLOC'][a][1] + STATE['TRANSLOC'][a][0]) != 0.0:
DistAnce = math.sqrt((STATE['TRANSLOC'][a][1]*STATE['TRANSLOC'][a][1])+(STATE['TRANSLOC'][a][0]*STATE['TRANSLOC'][a][0]));
XAngle = (math.degrees(math.atan2(DistAnce, STATE['TRANSLOC'][a][2])) / 10) - 9;
else:
XAngle = OldRot[0];
YAngle = 0.0;
## Calculate roll if wanted
if BUTTON['USE_ROLL'].val == 1 and ZAngle != 0.0 and frame != 0:
if ZAngle == OldRot[2]:
YAngle = OldRot[1];
else:
if round(RotChange, 3) == 18.0:
YAngle = OldRot[1];
else:
if RotChange > BUTTON['MAXROT'].val:
RotChange = BUTTON['MAXROT'].val;
elif RotChange < - BUTTON['MAXROT'].val:
RotChange = - BUTTON['MAXROT'].val;
Factor = RotChange / BUTTON['MAXROT'].val;
YAngle = (BUTTON['ROLL'].val * Factor);
####################################################
# SET THE ROTATIONS AND LOCATIONS
####################################################
## Set the rotation for the object.
STATE['ROTATION'][a] = [XAngle,YAngle,ZAngle];
## Remoce the current now that the rotation is known.
if BUTTON['USE_CURRENT'].val == 1:
if BUTTON['CURRENTDIR'].val == 1:
STATE['TRANSLOC'][a] = [(STATE['TRANSLOC'][a][0] - BUTTON['CURRENT'].val), STATE['TRANSLOC'][a][1], STATE['TRANSLOC'][a][2]];
elif BUTTON['CURRENTDIR'].val == 2:
STATE['TRANSLOC'][a] = [STATE['TRANSLOC'][a][0], (STATE['TRANSLOC'][a][1] - BUTTON['CURRENT'].val), STATE['TRANSLOC'][a][2]];
elif BUTTON['CURRENTDIR'].val == 3:
STATE['TRANSLOC'][a] = [STATE['TRANSLOC'][a][0], STATE['TRANSLOC'][a][1], (STATE['TRANSLOC'][a][2] - BUTTON['CURRENT'].val)];
####################################################
# SET THE IPOS
####################################################
if STATE['ERROR'] != 1:
## Only calculate the frames within the step value.
if frame == 0 or frame == (BUTTON['FRAMES'].val -1) or (float(frame) % float(BUTTON['STEPLEN'].val)) == 0.0:
## Set the ipos where they may apply.
AddIpo(STATE['IPO'][a], 'LocX', (frame), STATE['LOCATION'][a][0]);
AddIpo(STATE['IPO'][a], 'LocY', (frame), STATE['LOCATION'][a][1]);
AddIpo(STATE['IPO'][a], 'LocZ', (frame), STATE['LOCATION'][a][2]);
AddIpo(STATE['IPO'][a], 'RotX', (frame), STATE['ROTATION'][a][0]);
AddIpo(STATE['IPO'][a], 'RotY', (frame), STATE['ROTATION'][a][1]);
AddIpo(STATE['IPO'][a], 'RotZ', (frame), STATE['ROTATION'][a][2]);
DATA['MESSAGE'] = "IPO curves created succesfully.";
DATA['RESULT'] = str(STATE['OBNR']) + " Objects in total.";
## Update the scene.
scene.update();
print "-----------------------------------FINISHED---------------------------";
####################################################
# DRAW THE GUI
####################################################
def gui():
#############################################################
#BACKGROUNDS
#############################################################
BGL.glClearColor(0.5, 0.5, 0.5, 0.0);
BGL.glClear(BGL.GL_COLOR_BUFFER_BIT);
BGL.glColor3f(0, 0, 0); # Black background
BGL.glRectf(1, 1, 269, 496);
BGL.glColor3f(0.9, 0.9, 0.9); # Light background
BGL.glRectf(2, 2, 268, 495)
BGL.glColor3f(0.22, 0.2, 0.21); # Grey
BGL.glRectf(3, 3, 267, 494);
BGL.glColor3f(0.45, 0.45, 0.45); # Grey
BGL.glRectf(10, 430, 259, 480);
#############################################################
#TEXT
#############################################################
BGL.glColor3f(1.0, 1.0, 1.0);
BGL.glRasterPos2d(20, 460);
if DATA['MESSAGE'] != "a":
Draw.Text(str(DATA['MESSAGE']));
BGL.glColor3f(1.0, 0.8, 1.0);
BGL.glRasterPos2d(20, 440);
if DATA['RESULT'] != "a":
Draw.Text(str(DATA['RESULT']));
#############################################################
#BUTTONS
#############################################################
## Frames
DrawTitle("frames", 415);
## The ammount of frames to animate
BUTTON['FRAMES'] = Draw.Number("frames: ", 2, 20, 390, 110, 20, BUTTON['FRAMES'].val, 1, 30000, "The ammount of steps to animate.");
BUTTON['STEPLEN'] = Draw.Number("step: ", 2, 140, 390, 110, 20, BUTTON['STEPLEN'].val, 1, 1000, "The ammount of frames per step.");
## The distance to travel in one frame
BUTTON['SPEED'] = Draw.Number("speed: ", 2, 20, 365, 110, 20, BUTTON['SPEED'].val, 0.00, 1000.00, "The distance to travel in one frame.");
## Frames
DrawTitle("current", 350);
## The direction to escape a collision in when there's no obvious gap.
BUTTON['USE_CURRENT'] = Draw.Toggle(" ", 2, 20, 325, 20, 20, BUTTON['USE_CURRENT'].val, "Use current.");
BUTTON['CURRENT'] = Draw.Number("cur: ", 2, 40, 325, 90, 20, BUTTON['CURRENT'].val, -100.00, 100.00, "The current force.");
types = "Current direction %t|x %x1|y %x2|z %x3";
BUTTON['CURRENTDIR'] = Draw.Menu(types, 2, 140, 325, 50, 20, BUTTON['CURRENTDIR'].val, "The plane of the current.");
## Targets
DrawTitle("targets", 310);
## The target location for each object
BUTTON['USE_TARGET'] = Draw.Toggle(" ", 2, 20, 285, 20, 20, BUTTON['USE_TARGET'].val, "Use escape target setting.");
types = "Target position %t|Chase random %x2|Chase " + str(BUTTON['OBNAME'].val) + " %x3";
BUTTON['TARGET'] = Draw.Menu(types, 2, 40, 285, 90, 20, BUTTON['TARGET'].val, "The target location for each object.");
BUTTON['STARTROT'] = Draw.Toggle("prerot", 2, 140, 285, 50, 20, BUTTON['STARTROT'].val, "Use the original rotation of the object as the starting direction.");
BUTTON['FLOCK'] = Draw.Toggle(" ", 2, 20, 260, 20, 20, BUTTON['FLOCK'].val, "Use the flock setting");
BUTTON['XFLOCK'] = Draw.Number("flock: ", 2, 40, 260, 90, 20, BUTTON['XFLOCK'].val, 0.00, 1.00, "The ammount of influense the flock vector has.");
BUTTON['DFLOCK'] = Draw.Toggle("f dist", 2, 140, 260, 50, 20, BUTTON['DFLOCK'].val, "Make the flock behaviour depend on the distance from the flock center.");
## Rotations
DrawTitle("rotations", 245);
## The minimal object distance.
BUTTON['USE_MAXROT'] = Draw.Toggle(" ", 2, 20, 220, 20, 20, BUTTON['USE_MAXROT'].val, "Use the max value.");
BUTTON['MAXROT'] = Draw.Number("max: ", 2, 40, 220, 90, 20, BUTTON['MAXROT'].val, 0.00, 360.00, "The maximum rotation for an object in one step.");
BUTTON['USE_ROLL'] = Draw.Toggle(" ", 2, 140, 220, 20, 20, BUTTON['USE_ROLL'].val, "Use roll value.");
BUTTON['ROLL'] = Draw.Number("roll: ", 2, 160, 220, 90, 20, BUTTON['ROLL'].val, -180.00, 180.00, "The maximum roll during a turn.");
## The minimal object distance.
BUTTON['USE_LIMROT'] = Draw.Toggle(" ", 2, 20, 195, 20, 20, BUTTON['USE_LIMROT'].val, "Use the cons value.");
BUTTON['LIMROT'] = Draw.Number("cons: ", 2, 40, 195, 90, 20, BUTTON['LIMROT'].val, 0.00, 180.00, "The maximum rotation in the locked plane.");
types = "constrain in plane %t|x %x1|y %x2|z %x3";
BUTTON['LIMDIR'] = Draw.Menu(types, 2, 140, 195, 50, 20, BUTTON['LIMDIR'].val, "The plane to constrain the movement in.");
## Distances
DrawTitle("distances", 180);
## Checks
if BUTTON['LIM'].val != 0.0 and BUTTON['LIM'].val < BUTTON['INFMAX'].val:
BUTTON['LIM'].val = BUTTON['INFMAX'].val;
if BUTTON['INFMAX'].val < BUTTON['INFMIN'].val:
BUTTON['INFMIN'].val = BUTTON['INFMAX'].val;
## The minimal object distance.
BUTTON['USE_INFMIN'] = Draw.Toggle(" ", 2, 20, 155, 20, 20, BUTTON['USE_INFMIN'].val, "Use the min value.");
BUTTON['INFMIN'] = Draw.Number("min: ", 2, 40, 155, 90, 20, BUTTON['INFMIN'].val, 0.000, 100.0, "The distance below which objects try to avoid each other most.");
## The minimal object distance.
BUTTON['USE_INFMAX'] = Draw.Toggle(" ", 2, 140, 155, 20, 20, BUTTON['USE_INFMAX'].val, "Use the max value.");
BUTTON['INFMAX'] = Draw.Number("max: ", 2, 160, 155, 90, 20, BUTTON['INFMAX'].val, 0.000, 100.0, "The distance at which objects start to avoid each other.");
## The minimal object distance.
BUTTON['USE_LIM'] = Draw.Toggle(" ", 2, 20, 130, 20, 20, BUTTON['USE_LIM'].val, "Use the lim value.");
BUTTON['LIM'] = Draw.Number("lim: ", 2, 40, 130, 90, 20, BUTTON['LIM'].val, 0.000, 100.0, "The maximum distance any object wants to be from the midpoint of the swarm.");
## mayor functions
DrawTitle("container", 115);
## Object name
BUTTON['USE_CONTAINER'] = Draw.Toggle(" ", 2, 20, 90, 20, 20, BUTTON['USE_CONTAINER'].val, "Use the obname string.");
BUTTON['CONTAINER'] = Draw.String("avoid: ", 2, 40, 90, 100, 20, BUTTON['CONTAINER'].val, 128, "The word to look for in the name of all objects to animate.");
## Get selected object button
Draw.Button("SET", 5, 140, 90, 30, 20, "Get the name of the currently selected object!");
BUTTON['CONDIST'] = Draw.Number("dist: ", 2, 180, 90, 70, 20, BUTTON['CONDIST'].val, 0.000, 100.0, "The distance at which objects start to avoid the container.");
## mayor functions
DrawTitle("naming variable", 75);
## Object name
BUTTON['USE_OBNAME'] = Draw.Toggle(" ", 2, 20, 50, 20, 20, BUTTON['USE_OBNAME'].val, "Use the obname string.");
BUTTON['OBNAME'] = Draw.String("obname: ", 2, 40, 50, 130, 20, BUTTON['OBNAME'].val, 128, "The word to look for in the name of all objects to animate.");
## Get selected object button
Draw.Button("SET", 4, 170, 50, 30, 20, "Get the name of the currently selected object!");
BUTTON['ANIMPARENT'] = Draw.Toggle("anim", 2, 210, 50, 40, 20, BUTTON['ANIMPARENT'].val, "Deselect if you want to chase the object (parent) with this name and it's been pre-animated.");
## mayor functions
DrawTitle("mayor functions", 35);
## Reset gui button
Draw.Button("RUN", 1, 20, 10, 150, 20, "Run the script!");
## Exit button
Draw.Button("EXIT", 3, 180, 10, 70, 20, "Exit the script!");
####################################################
# CHECK FOR THE ESCAPE KEY
####################################################
## Close down the script in case the esc key was hit.
def event(evt, val):
if (evt == Draw.ESCKEY and not val): Draw.Exit();
####################################################
# ACTION AFTER A BUTTON HAS BEEN PRESSED
####################################################
## Global BUTTON
def bevent(evt):
## Run the script
if (evt == 1):
run();
Draw.Redraw();
## Redraw interface
elif (evt == 2):
Draw.Redraw();
## Exit the script
elif (evt == 3):
Draw.Exit();
## Get the currently selected object's name;
elif (evt == 4):
try:
BUTTON['OBNAME'].val = Blender.Scene.GetCurrent().getActiveObject().getName();
DATA['MESSAGE'] = "New name string retrieved.";
DATA['RESULT'] = str(BUTTON['OBNAME'].val);
Draw.Redraw();
except:
DATA['MESSAGE'] = "An error occured!";
DATA['RESULT'] = "No object selected!";
Draw.Redraw();
## Get the currently selected object's name;
elif (evt == 5):
try:
if Blender.Scene.GetCurrent().getActiveObject().getType() == 'Mesh':
BUTTON['CONTAINER'].val = Blender.Scene.GetCurrent().getActiveObject().getName();
DATA['MESSAGE'] = "New container name retrieved.";
DATA['RESULT'] = str(BUTTON['CONTAINER'].val);
else:
DATA['MESSAGE'] = "An error occured!";
DATA['RESULT'] = "No mesh object selected!";
Draw.Redraw();
except:
DATA['MESSAGE'] = "An error occured!";
DATA['RESULT'] = "No object selected!";
Draw.Redraw();
####################################################
# REGISTER THE FUNCTIONS
####################################################
Draw.Register(gui, event, bevent);

File Metadata

Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
ed/82/31f7739c78a023d63572024f3e95

Event Timeline