Context Free: язык для генерации изображений



    Эта картина сгенерирована программой 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 за ссылку.
    Support the author
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 31

      +5
      Обалдеть. Теперь и я смогу нарисовать маленький шедевр.
        +1
        Не только Вы один)
        +38
        Охренеть Ализар выдал. Даже не перевод
          +2
          Постарался — накопировал кода и картинок с галереи.

          P.S. Уже было:
          habrahabr.ru/blogs/crazydev/28393/
            +3
            В той статье нет такого ВАУ-эффекта.
          +3
          Насколько я понимаю, это дальнейшее развитие идеи L-систем?
            +5
            Ничего себе!
            «Ancient Scripts» вообще мозг вынес.
              0
              Вау! интересно а в гейм девелопмент это можно как ни будь применить?
              +1
              покруче брейнфака будет…
                +1
                Первые картинки вызвали обычный интерес, но последняя просто поразила.
                Ибо + поставить не могу, посему просто спасибо.
                  +1
                  Мне одному это чем-то напомнило milkdrop под winamp?
                    0
                    Очень напомнило. У меня подозрение, что это оттуда растет.
                    +30
                    Занятная штуковина! Хабр Серпинского:



                    Исходник
                      +6
                      хабрапроцессор
                        +1
                        Срабатывает, кстати, одна из зрительных иллюзий: буквы кажутся немного наклоненными в разные стороны.
                          +20
                          Вот пока ваш комментарий не прочитал не казались!
                            +22
                            А мне и так не кажутся)
                        +1
                        Погуглил, единственное упоминание на русском языке — эта статья… Что ж, на днях вооружусь словарём и пойду изучать.
                          –18
                          Главный вопрос — а зачем?
                            +9
                            Вы, наверное, картинки отключили в браузере.
                            +14
                            интересно, когда в картинных галереях будут вывешивать исходный код вместо картин?
                              +24
                              Бэндер, разлогинься :)
                              –4
                              Воруй убивай! А лецензии удосужились на «картинки» и код почитать?
                              «Attribution — You must attribute the work...»
                              «Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page. »
                                0
                                А никто не знает — будет ли продолжено развитие AGG или автор на него забил?
                                (хотя с другой стороны — все что нужно — работает)
                                  0
                                  Можно задать вопрос автору напрямую: McSeem2 на RSDN.ru
                                  0
                                  Афигеть! Рукопись восхитительна! И дерево!
                                  :)
                                    0
                                    Предпоследняя картинка «таймлайн» произвела самое большое впечатление. Вообще обалденное соотношение размера кода к количеству деталей в изображении!
                                      0
                                      У меня одного предпоследняя картина не… эээ… не компилится?
                                      Error in (� at line 2 — syntax error
                                        0
                                        Тут нужно использовать слово «рендерится».

                                      Only users with full accounts can post comments. Log in, please.