forked from icosa-foundation/open-brush
/
SymmetryScript.Boids.lua
107 lines (86 loc) · 3.32 KB
/
SymmetryScript.Boids.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Settings = {space = "pointer"}
Parameters = {
copies = {label = "Number of copies", type="int", min=1, max=24, default=8},
separationForce = {label = "Separation Amount", type="float", min=0, max=10, default = 1.5},
alignmentForce = {label = "Alignment Amount", type="float", min=0, max=10, default = 5.0},
--cohesionForce = {label = "Cohesion Amount", type="float", min=0, max=10, default = 1.0},
originForce = {label = "Pointer Attraction", type="float", min=0, max=10, default = 5.0},
}
cohesionForce = 1.0 -- We need more room for parameters!
symmetryHueShift = require "symmetryHueShift"
local Boid = {}
Boid.__index = Boid
function Boid.new(position, velocity)
local self = setmetatable({}, Boid)
self.position = position
self.velocity = velocity
self.orientation = Rotation:LookRotation(self.velocity, Vector3.up)
return self
end
function Boid:update(dt, boids)
local sep, align, coh = self:calculateForces(boids)
-- Calculate a force vector pointing towards the origin
local attractionToOrigin = Vector3.zero - self.position
attractionToOrigin = attractionToOrigin.normalized
self.velocity = self.velocity + (sep * separationForce)
self.velocity = self.velocity + (align * alignmentForce)
self.velocity = self.velocity + (coh * cohesionForce)
-- Apply the attraction to origin force
self.velocity = self.velocity + (attractionToOrigin * originForce)
self.velocity = self.velocity:ClampMagnitude(5)
self.position = self.position + (self.velocity * dt)
self.orientation = Rotation:LookRotation(self.velocity, Vector3.up)
end
function Boid:calculateForces(boids)
local separation = Vector3.zero
local alignment = Vector3.zero
local cohesion = Vector3.zero
local count = 0
for _, other in ipairs(boids) do
if other ~= self then
local direction = self.position - other.position
local distanceSquared = direction.sqrMagnitude
if distanceSquared < 25 and distanceSquared > 0 then
separation = separation + (direction / distanceSquared)
alignment = alignment + other.velocity
cohesion = cohesion + other.position
count = count + 1
end
end
end
if count > 0 then
separation = separation / count
alignment = (alignment / count).normalized
cohesion = ((cohesion / count) - self.position).normalized
end
return separation, alignment, cohesion
end
local boids = {}
function Start()
initialHsv = Brush.colorHsv
end
function randomFloat(x)
-- Returns a random float in the range [-x, x]
return -x + (2 * x) * Random.value
end
function Main()
if Brush.triggerPressedThisFrame then
-- Initialize boids with random positions and velocities
boids = {}
for i = 1, copies do
local position = Random.insideUnitSphere * 0.25
local velocity = Random.insideUnitSphere * 0.1
boids[i] = Boid.new(position, velocity)
end
symmetryHueShift.generate(copies, initialHsv)
end
return updateBoids(0.01)
end
function updateBoids(dt)
pointers = Path:New()
for _, boid in ipairs(boids) do
boid:update(dt, boids)
pointers:Insert(Transform:New(boid.position, boid.orientation))
end
return pointers
end