1
Procedural Content Generation with ClojureMike Anderson
2
Contents
1. Procedural Content Generation
2. Introducing Clojure
3. Creating content with Clisk
3
Definition
Procedural content generation (PCG)
is the programmatic generation
of content using algorithms, which may
incorporate random or pseudo-random
processes
4
Some applicationsContent Types Examples
Images
• 3D model textures
• Abstract art
Pioneering work by Ken
Perlin (inventor of Perlin
noise)
Music
• Melodies
• Synthesised sounds
Work by Jeremy
Leach
http://algorithmiccomposition.org/
Game content
• Game items
• Random maps
Roguelike games
Virtual Worlds
• Landscapes
• Plants / animals
• Alien races
No Man’s Sky
(planned release 2016)
5
Image Generation
(0,0)y-a
xis
(0,1) (1,1)
(1,0)
pixel colour = f(x, y)
x-axis
6
Image “Composition”
x
f(x, y) g(x, y)
=
f(x, y) * g(x, y)
The Big Idea: Use a functional language to compose images!
7
Contents
1. Procedural Content Generation
2. Introducing Clojure
3. Creating content with Clisk
8
What is Clojure?
JVM Language
Functional Dynamic
9
Data types – The Usual
Type Representation
Long integers 42
Double precision reals 3.14159265359
Strings “Hello World”
Characters \M
Hex 0xFF8000
All represented by equivalent Java
Objects “under the hood”
10
Data types – The Not-So Usual
Type Representation
Keywords :foo
Symbols 'hello
Ratios 1/3
Regexes #"[0-9]+"
BigInt 15511210043330985984000000N
BigDecimal 189675.1678969698698969986M
Base-N numbers 3r1201200
11
Data types – Collections
Type Representation
Maps {:foo 10 :bar 20}
Sets #{2 3 5 7 11 13}
Vectors [1 2 3 :foo]
Lists '(foo a b c)
All collections in Clojure are Immutable!
12
Lisp = “Lots of Irritating Silly Parentheses”?
myfunction(alpha, beta)C-like languages
(myfunction alpha beta)Lisp
Usually the same number of parentheses!
13
Expressions
Function
application
=> (+ 11 31)42
Nested
Expressions
=> (+ 11 (* 30 30))911
Local definitions
=> (let [x 11](* x 100))
1100
14
Functions
Function definition
=> (defn triple [x](* x 3))
=> (triple 10)30
Higher order
functions
=> (map triple [1 2 3])(3 6 9)
15
“Code is Data”
=> (+ 2 3)5
=> '(+ 2 3)(+ 2 3)
=> (eval '(+ 2 3))5
16
Java Interop
Java myObject.doSomething(foo, bar);
Clojure (.doSomething myObject foo bar)
17
Contents
1. Procedural Content Generation
2. Introducing Clojure
3. Creating content with Clisk
18
https://github.com/mikera/clisk
To follow along:
- Clone the repo at: https://github.com/mikera/clisk
- All examples are in: src/test/clojure/clisk/workshop/
19
Collaborative spirit – all about sharing!
Open Source Project
Open Source Language
Open Source content “Recipes”
20
Example from “TweeGeeMee”
https://twitter.com/tweegeemee/status/676985464813953029
21@TweeGeeMee twitter bot by Roger Allen
@TweeGeeMee evolved images
22
Example from “Clevolution”
https://twitter.com/deathbob/status/661294702759669760
23
Image Generation
(0,0)
y-a
xis
(0,1) (1,1)
(1,0)
pixel colour = [x 0 0]
x-axis
REPL
Command(show [x 0 0])
24
Image Generation
(0,0)
y-a
xis
(0,1) (1,1)
(1,0)
pixel colour = [x y 0]
x-axis
REPL
Command(show [x y 0])
25
Implementation notes
• Clisk functions actually generate ASTs
• “show” function compiles the AST into efficient low-level code, something like*:
• Lisp makes this (comparatively) easy!
This is very simplified! The real compiled code includes support for multi-threading,
caching of texture objects, making use of fast primitive maths etc.
*
(dotimes [y height](dotimes [x width](let [colour ....calculation code....](.setRGB image x y colour))))
26
Many primitives
Solid colours (show [0.1 0.7 1.0])
Patterns (show (checker red pink))
Texture maps (show clojure)
27
Transformations - scaling
Base (show (checker red pink))
Scaled
(show (scale 0.3(checker red pink)))
28
Transformations – offsets
Base (show (checker red pink))
Offset
(show (offset [0.2 0.2](checker red pink)))
29
Transformations – warps
Base (show (checker red pink))
Warped
(show (warp(scale 0.2 vnoise)(checker red pink)))
30
Noise functions
Monochomatic
noise(show (scale 0.2 noise))
Vector noise (show (scale 0.2 vnoise))
Plasma (show (scale 0.2 plasma))
31
Live coding time!
32
Images from the Gallery: Stained Glass
(show (let [voronoi1 (voronoi :points 512)] (v*(v* 20.0 (voronoi-blocks :voronoi voronoi1))(warp (voronoi-points :voronoi voronoi1) grain)))
:size 512)
Key techniques:
• Use a Voronoi map to create “cells”
• Multiply with the psuedo-random “grain” function to colour cells
33
Images from the Gallery: Mandelbrot
(show (viewport [-2 -1.5] [1 1.5](fractal:while (v- 2 (length [x y])):update (v+ c [(v- (v* x x) (v* y y))
(v* 2 x y)]):result (vplasma (v* 0.1 'i)):bailout-result black:max-iterations 1000)) :size 256)
Key techniques:
• Use the “fractal” function to create an iterative process
• Simulate complex numbers (x+ iy) using regular clisk vectors
• Use a viewport to see the relevant region of the Mandelbrot set
34
Images from the Gallery: Voronoi Fractal
(show (let [voronoi1 (voronoi :points 32)] (fractal
:while (v- 0.97 (voronoi-function(v- 1 (v* (vdivide (v- y x) y)
(vdivide (v- z x) z))):voronoi voronoi1))
:update (v+ (v* pos 2) pos):result (vdivide 3 (v+ 3 'i)):max-iterations 4)) :size 512)
Key techniques:
• Voronoi map used to create a “net” pattern
• Use the “fractal” function to create iterative layers
• If it hits the net, stop
• Else continue to next layer with a scaled version of the net
3535
BACKUP / OUT
Top Related