Эта картина сгенерирована программой Context Free по следующему описанию:
startshape T
// FLIGIZ
background{b -1}
tile {s 2.5}
rule T {3*{r 120 hue 30}S{x .3}}
rule S 3{CIRCLE{hue 30}4*{r 20 b.007 sat .1}S[s.3.7y.9]}
rule S {CIRCLE{hue 15}9*{r 20 b.05 hue -3}S[s.3.7y.9]}
rule S {S{flip 90}}
Для описания изображений в программе Context Free используется язык программирования CFDG с контекстно-свободной грамматикой, созданный специально для генерации изображений. Грубо говоря, это набор базовых правил со всего двумя терминалами CIRCLE и SQUARE. Рендеринг осуществляется с помощью библиотеки Anti-Grain Geometry Максима Шеманарева.
Вот несколько других картин из галереи Context Free Art. Все работы в галерее опубликованы под лицензией Creative Commons (по клику — ссылка на оригинал).
Код
startshape START
rule START {
CIRCLE{}
RAINBOW_SPLIT{hue 0 sat 0 b 0}
RAINBOW_SPLIT{r 180 hue 120 sat 0}
}
rule RAINBOW_SPLIT{
RAINBOW{}
}
rule RAINBOW_SPLIT{
RAINBOW_MINI{alpha -.9 y -.4 s .2 flip 1 b -1}
RAINBOW{}
}
rule RAINBOW{
SHADOW{}
CIRCLE{}
HIGHLIGHT{}
RAINBOW_SPLIT{hue 1.5 sat .1 s .99 b .001 x .09 r 2.8 }
}
rule RAINBOW_MINI{
SHADOW{}
CIRCLE{}
HIGHLIGHT{}
RAINBOW_MINI{alpha .1 hue 2 s .98 x .3 r 2.8 }
}
rule RAINBOW_MINI .04{
SHADOW{}
CIRCLE{}
HIGHLIGHT{}
RAINBOW_MINI{flip 1 alpha .1 hue 5 s .99 x .3 r 2.8 }
}
rule SHADOW {
CIRCLE{hue 3 b -1 sat -.6 s 1.1 y .04 alpha -.7}
}
rule HIGHLIGHT {
CIRCLE{ hue 3 b .7 sat -.3 s .98 y .05}
CIRCLE{ hue 3 b 2 sat -.7 s .9 y .01}
}
Код
/*
Ancient Scripts by Leaf Garland
*/
background { hue 40 sat 0.2 b -0.2}
startshape LINES
rule LINES {
20 * {y -90} NEWLINE {hue 90 sat 0.7 b 0.2 a -0.5}
}
rule NEWLINE {
LINE {y 0}
}
rule NEWLINE {
LINE {y 20}
}
rule NEWLINE {
LINE {y 30}
}
rule LINE {
50 * {x 36} CHAR {}
}
rule CHAR 0.3 {
// space
}
rule CHAR {
2 * {x 20 flip 180} STROKE {r 90}
2 * {y 20 flip 180} STROKE {}
}
rule CHAR {
4 * {r 60} STROKE {}
}
rule CHAR {
STROKE {r 90}
3 * {y 10 flip 180} STROKE {}
}
rule STROKE {
B {}
}
rule STROKE {
B {flip 90}
}
rule B 30 {
MARK {}
B {x .6 r 10}
}
rule B 30 {
MARK {}
B {x .6 r 3}
}
rule B 250 {
MARK {}
B {x .9}
}
rule B 10 {
MARK {}
B {flip 90}
}
rule B 10 { }
rule MARK 3 {
CIRCLE {}
}
rule MARK {
CIRCLE {s 2}
}
rule MARK {
SQUARE {s 3}
}
rule MARK {
CIRCLE {s 4}
}
rule MARK 0.01 {
CIRCLE {s 7}
}
Код
background{b -1} startshape init
rule init{time{z 0 r -90 sat .5 |h 220}}
//CONTROL
rule time 40 {draw{} time{r 1 s .9991 b .1| a .1|}}
rule time {slow{|b -1 |a 1 |sat 1}}
rule time {slow{|b 1 |a -1 |sat 1}}
rule slow 20 {draw{} slow{ r 1 s .9991 b .03| a .03| h -1}}
rule slow {time{|sat -1}}
//IMAGING
rule draw{
SQUARE[z 0 x 1 s .27 .018 x -.5 a 1 h 1|]
stars{z 1 x .91}
cloud[z 2 x .83 s .17 x .5 h .7| a 1 sat .3|]
ground[z 3 x .73 s .1 x .5]
}
rule ground{
SQUARE[s 1 .18 a 1 b -.5]
highlight{s 1 .14}
stuff{z 1}
}
rule stuff 5 {block[z 79 x .5 s .7225 .2 x -.5 a 1]}
rule stuff {bush[z 86 x -.5 s 1.62 r -90 b -.7| a 1]}
rule stuff {}
rule block 2 {block{b -.1|}}
rule block 3 {block[z -4 x .5 s .7225 x -.5 b .4|]}
rule block 1 {block2{} block[z -4 x .5 s .64 x -.5 b .4|]}
rule block2 {block3[x -.5 s .5 x .5 h 12]}
rule block2 {block3[x -.5 s .5 x .5 h -12]}
rule block3{SQUARE{} gleam{}}
rule gleam{}
rule gleam 2 {highlight{a 1}}
rule highlight{SQUARE[z 50 x .5 s .02 1 x -.5 b 1]}
rule bush 2 {bush[z -2 y .617 s .85 y -.617 b .3|]}
rule bush {tree{h 180 sat -.4 b -.7}}
rule tree {
SQUARE{y .08 s .064 .16}
fork{y .155}
fork{y .155 f 90}
}
rule branch{tree{}}
rule branch 3 {
SQUARE{y .192 s .064 .384}
fork{y .38}
fork{y .38 f 90}
}
rule fork{branch{r 22 s .7}}
rule fork{branch{r 33 s .7}}
rule fork 0.2 {}
rule stars {}
rule stars 6 {star1{sat -1 h .99|} stars{}}
rule star1 {star1{sat .12}}
rule star1 6 {star1{r 139}}
rule star1 {star2{}}
rule star2 {star3{x .05 s .8}}
rule star2 {star3{}}
rule star3 9 {star3{s .8}}
rule star3 {CIRCLE{x .03 s .007 b 1 h -.55|}}
rule cloud 25 {}
rule cloud{puff[ x -.6 s .25 .6 x .5 a -.95 h 170 sat .2]}
rule puff 7 {TRIANGLE{} puff{x .5 r 20 s .91}}
rule puff { TRIANGLE{} puff{x .5 f 0 s .91}}
rule puff 5 {puff{x .5 r 20 s .9} puff{z 1 s .9 sat -.2 b
.02}}
Код
//CKL
startshape MAIN
CF::Background = [hue 0 sat 0.84 b -0.9]
CF::MinimumSize = 1
// how far to move each tree part in the local Y axis
GTreePartMove = 0.02
// how much to scale each successive tree part
GTreePartScale = 0.990
// Min and max length for the size of the trunk
MaxTrunkDepth() = randint(10,40)
// Min and max length for a branch coming off the trunk
MaxTrunkBranchDepth() = randint(20,90)
// Min and max length for a leaf branch
MaxLeafBranchDepth() = randint(50,200)
// returns a random int between (-High,-Low) and (Low,High)
RandRange(Low,High) = select( randint(), -1, 1 ) *
randint(Low,High)
// Returns a rotation angle for a new branch
NewBranchRotation() = randint(25,50)
// Returns a random scale for a new branch
NewBranchScale() = rand(0.6,0.9)
NewStemRotation() = RandRange(30,50)
NewSteamScale() = rand(0.4,0.6)
LeafScale(Depth) = Depth / 250
// returns a random rotaiton amount of a single branch, to
give them a less rigid shape
BranchTwistSmall() = randint(10) - 5
BranchTwistLarge() = RandRange(10,25)
shape MAIN
rule 1 {
SKY [ z -2 s 100 ]
SUN [ z -1 s 400 ]
TREE [ x -0.1 y -0.75 ]
GRASS [ x -1 y -1 ]
}
shape SKY
rule 1 {
CIRCLE [ s rand(0.02,0.04) rand(0.01,0.03) sat 1 a
-0.02 ]
SKY [ s 0.9990 b 0.0005 hue 0.018 a -0.001 ]
}
shape SUN
rule 1 {
CIRCLE [ s rand(0.001,0.002) sat 0.84 b 1 a -0.95 ]
SUN [[ r 40 s 0.9990 y 0.0001 hue (0.02,48) ]]
}
shape GRASS
rule 1 {
loop 20 [ y 0.01 ]
loop 200 [ x 0.01 ]
GRASSBLADE [ x rand(0.02) y rand(0.1) ]
}
shape GRASSBLADE
rule 1 {
CIRCLE [ s 0.02 a -0.9 ]
GRASSBLADE [ y 0.01 s 0.95 r BranchTwistSmall() ]
}
shape TREE
rule 1 {
TRUNK( 0, MaxTrunkDepth() ) [ r ( randint(20) - 10 )
]
}
shape TRUNK( natural Depth, natural EndDepth )
rule 20 {
TreePart[]
if ( Depth > EndDepth )
{
TRUNKSPLIT(Depth) []
}
else
{
TRUNK( Depth + 1, EndDepth ) [ y GTreePartMove s
GTreePartScale]
}
}
rule 5 {
TRUNK( Depth + 1, EndDepth ) [ r BranchTwistSmall()
]
}
shape TRUNKSPLIT( natural Depth )
rule 1 {
// split right
TRUNKBRANCH( Depth, Depth + MaxTrunkBranchDepth() )
[ r NewBranchRotation() s NewBranchScale() ]
TRUNKBRANCH( Depth, Depth + MaxTrunkBranchDepth() )
[ r randint(-20,0) s NewBranchScale() ]
}
rule 1 {
// split left
TRUNKBRANCH( Depth, Depth + MaxTrunkBranchDepth() )
[ r -NewBranchRotation() s NewBranchScale() ]
TRUNKBRANCH( Depth, Depth + MaxTrunkBranchDepth() )
[ r -randint(-20,0) s NewBranchScale() ]
}
shape TRUNKBRANCH( natural Depth, natural EndDepth )
rule 1000 {
TreePart[]
if ( Depth > EndDepth )
{
TRUNKBRANCHSPLIT(Depth) []
}
else
{
TRUNKBRANCH( Depth + 1, EndDepth ) [ y
GTreePartMove s GTreePartScale]
}
}
rule 200 {
TRUNKBRANCH( Depth + 1, EndDepth ) [ r
BranchTwistSmall() ]
}
rule 50 {
TRUNKBRANCH( Depth + 1, EndDepth ) [ r
BranchTwistLarge() ]
}
rule 1 {
TRUNKBRANCH( Depth + 1, EndDepth ) [ ]
LEAFBUNCH( Depth ) [ r NewBranchRotation() ]
}
rule 1 {
TRUNKBRANCH( Depth + 1, EndDepth ) [ ]
LEAFBUNCH( Depth ) [ r -NewBranchRotation() ]
}
shape TRUNKBRANCHSPLIT( natural Depth )
rule 1 {
// split right
LEAFBRANCH( Depth, Depth + MaxLeafBranchDepth() ) [
r NewBranchRotation() s NewBranchScale() ]
LEAFBRANCH( Depth, Depth + MaxLeafBranchDepth() ) [
r randint(-20,0) s NewBranchScale() ]
}
rule 1 {
// split left
LEAFBRANCH( Depth, Depth + MaxLeafBranchDepth() ) [
r -NewBranchRotation() s NewBranchScale() ]
LEAFBRANCH( Depth, Depth + MaxLeafBranchDepth() ) [
r -randint(-20,0) s NewBranchScale() ]
}
shape LEAFBRANCH( natural Depth, natural EndDepth )
rule 50 {
TreePart[]
if ( Depth > EndDepth )
{
//TRUNKBRANCHSPLIT(Depth) []
}
else
{
LEAFBRANCH( Depth + 1, EndDepth ) [ y
GTreePartMove s GTreePartScale]
}
}
rule 50 {
LEAFBRANCH( Depth + 1, EndDepth ) [ r
BranchTwistSmall() ]
}
rule 5 {
LEAFBUNCH( Depth ) []
}
//rule 1 {
// TRUNKBRANCHSPLIT(Depth) []
//}
shape LEAFBUNCH( natural Depth )
rule 100 {
TreePart [ ]
LEAFBUNCH( Depth + 1 ) [ y GTreePartMove s
GTreePartScale a -0.01 r BranchTwistSmall() ]
}
rule 25 {
LEAFSTEM( Depth ) [ r NewStemRotation() s
NewSteamScale() ]
LEAFBUNCH( Depth ) []
}
rule 1 {
// split right
LEAFBUNCH( Depth ) [ r NewBranchRotation() s
NewBranchScale() ]
LEAFBUNCH( Depth ) [ r randint(-20,0) s
NewBranchScale() ]
}
rule 1 {
// split left
LEAFBUNCH( Depth ) [ r -NewBranchRotation() s
NewBranchScale() ]
LEAFBUNCH( Depth ) [ r -randint(-20,0) s
NewBranchScale() ]
}
shape LEAFSTEM( natural Depth )
rule 100 {
TreePart []
LEAFSTEM( Depth + 1 ) [ y GTreePartMove s 0.98 a
-0.05 ]
}
rule 25 {
LEAFSTEM( Depth + 1 ) [ r BranchTwistSmall() ]
}
rule 25 {
LEAF(Depth) [ r BranchTwistSmall() ]
LEAFSTEM(Depth) []
}
shape LEAF( natural Depth )
rule 1 {
LEAFSTAMP [[ s LeafScale(Depth) y 0.5 ]]
}
shape LEAFSTAMP
rule 1 {
CIRCLE [ a -0.1 s rand(0.1,0.8) 1 ]
}
shape TreePart
rule 1 {
CIRCLE [ s 0.1 ]
CIRCLE [ s 0.1 x +0.005 a -0.9 ]
CIRCLE [ s 0.1 x -0.005 a -0.9 ]
CIRCLE [ s 0.1 x +0.0075 a -0.9 ]
CIRCLE [ s 0.1 x -0.0075 a -0.9 ]
CIRCLE [ s 0.1 x +0.0125 a -0.9 ]
CIRCLE [ s 0.1 x -0.0125 a -0.9 ]
}
Программа Context Free распространяется под лицензией GPL, скачать её можно здесь (Win / Mac / Linux), документация.
Добавим, что это не единственная инициатива по созданию удобной грамматики для генерации изображений. Например, вот open source проект Structure Synth для 3D-графики.
UPD. Оказывается, про Context Free на Хабре писали аж в 2008 году! Спасибо Imposeren за ссылку.