lmmx / 2020-viz

0 stars 0 forks source link

Christmas tree Mathematica remake #2

Open lmmx opened 3 years ago

lmmx commented 3 years ago

There's one here and an incredible on here (direct link)

mathematica-tree

The description is as follows:


I noticed that a Reddit post about programming a lighted Christmas Tree from a simple equation

t * Sin(t)

became very popular on Reddit. It is connected to a program a programmer developed. I thought how fast we can make it with Wolfram language ? Here is the result with slight flickering ;-) Note a very special care needs to be paid to the dimming of the lights at a larger distances, and pretty shadowing.

This .GIF file has 100 frames. Enjoy!

PD = .5; s[t_, f_] := t^.6 - f;
dt[cl_, ps_, sg_, hf_, dp_, f_] := {PointSize, Hue[cl, 1, .6 + sg .4 Sin[hf s[t, f]]], 
Point[{-sg s[t, f] Sin[s[t, f]], -sg s[t, f] Cos[s[t, f]], dp + s[t, f]}]};
frames = ParallelTable[

Graphics3D[Table[{dt[1, .01, -1, 1, 0, f], dt[.45, .01, 1, 1, 0, f], 
dt[1, .005, -1, 4, .2, f], dt[.45, .005, 1, 4, .2, f]}, {t, 0, 200, PD}],

ViewPoint -> Left, BoxRatios -> {1, 1, 1.3}, ViewVertical -> {0, 0, -1}, 
ViewCenter -> {{0.5, 0.5, 0.5}, {0.5, 0.55}}, Boxed -> False, 
PlotRange -> {{-20, 20}, {-20, 20}, {0, 20}}, Background -> Black],

{f, 0, 1, .01}];

Export["tree.gif", frames]
lmmx commented 3 years ago

The program can be broken up into 4 sections as follows:

1: Initialise the distance parameter

PD = .5
s[t_, f_] := t^.6 - f

2: ???

This part is cryptic (as is typical for graphics code, the terseness makes the meaning of individual variables unclear).

At first glance I thought this was an alias of Dt (which is Mathematica's derivative) but in fact it's a custom function definition dt, taking 6 arguments:

dt[cl_, ps_, sg_, hf_, dp_, f_] := {
    PointSize,
    Hue[cl, 1, .6 + sg .4 Sin[hf s[t, f]]], 
    Point[
        {
            -sg s[t, f] Sin[s[t, f]],
            -sg s[t, f] Cos[s[t, f]],
            dp + s[t, f]
        }
    ]
};

I would guess that maybe(!?):

...but at this point the trail seems to go cold: I can't figure out what the functions sg or dp do (they don't show up searching Mathematica's docs, whereas I expected them to be functions from this code)

3: Create frames

The frames are created as "ParallelTable" (which I imagine is like a NumPy NdArray) containing the options for a Graphics3D representation of a 3D image:

frames = ParallelTable[
    Graphics3D[
        Table[
            {
                dt[1, .01, -1, 1, 0, f],
                dt[.45, .01, 1, 1, 0, f], 
                dt[1, .005, -1, 4, .2, f],
                dt[.45, .005, 1, 4, .2, f]
            },
            {
                t, 0, 200, PD
            }
        ],
        ViewPoint -> Left,
        BoxRatios -> {1, 1, 1.3},
        ViewVertical -> {0, 0, -1}, 
        ViewCenter -> {{0.5, 0.5, 0.5}, {0.5, 0.55}},
        Boxed -> False, 
        PlotRange -> {{-20, 20}, {-20, 20}, {0, 20}},
        Background -> Black
    ],
    {f, 0, 1, .01}
];

4: Export GIF

Export["tree.gif", frames]

This one's easy, the equivalent in matplotlib is FuncAnimation.save

lmmx commented 3 years ago

Oops, I appear to have mixed up the one above which recreates the Javascript tree to the one posted in the replies, the GIF of which I embedded above. The source of this is actually a commenter, Silvia Hao, who writes the following


PD = .5;
s[t_, f_] := t^.6 - f
dt[cl_, ps_, sg_, hf_, dp_, f_, flag_] := Module[
    {sv, basePt},
    {
        PointSize[ps],
        sv = s[t, f];
        Hue[
            cl (1 + Sin[.02 t])/2, 1, .3 + sg .3 Sin[hf sv]
        ],
        basePt = {
            -sg s[t, f] Sin[sv],
            -sg s[t, f] Cos[sv],
            dp + sv
        };
        Point[basePt],
        If[flag,
           {
               Hue[
                   cl (1 + Sin[.1 t])/2,
                   1,
                   .6 + sg .4 Sin[hf sv]
                ],
         PointSize[RandomReal[.01]],
         Point[
             basePt + 1/2 RotationTransform[
                 20 sv,
                 {
                     -Cos[sv],
                     Sin[sv],
                     0
                  }
              ][
                  {
                      Sin[sv],
                      Cos[sv],
                      0
                  }
              ]
        ]
    },
    {}]
}]

frames = ParallelTable[
                       Graphics3D[Table[{
                                         dt[1, .01, -1, 1, 0, f, True], dt[.45, .01, 1, 1, 0, f, True],
                                         dt[1, .005, -1, 4, .2, f, False],
                                         dt[.45, .005, 1, 4, .2, f, False]},
                                        {t, 0, 200, PD}],
                                  ViewPoint -> Left, BoxRatios -> {1, 1, 1.3},
                                  ViewVertical -> {0, 0, -1},
                                  ViewCenter -> {{0.5, 0.5, 0.5}, {0.5, 0.55}}, Boxed -> False,
                                  PlotRange -> {{-20, 20}, {-20, 20}, {0, 20}}, Background -> Black],
                       {f, 0, 1, .01}];
lmmx commented 3 years ago

Once again this can be split out into parts:

1: distance parameter PD and a shrinking function s

PD = .5;
s[t_, f_] := t^.6 - f

This is unchanged from above

2: ...

dt[cl_, ps_, sg_, hf_, dp_, f_, flag_] := Module[
    {sv, basePt},
         {PointSize[ps],
          sv = s[t, f];
          Hue[cl (1 + Sin[.02 t])/2, 1, .3 + sg .3 Sin[hf sv]],
          basePt = {-sg s[t, f] Sin[sv], -sg s[t, f] Cos[sv], dp + sv};
          Point[basePt],
         If[flag,
            {Hue[cl (1 + Sin[.1 t])/2, 1, .6 + sg .4 Sin[hf sv]], PointSize[RandomReal[.01]],
             Point[basePt + 1/2 RotationTransform[20 sv, {-Cos[sv], Sin[sv], 0}][{Sin[sv], Cos[sv], 0}]]},
            {}]
        }]

frames = ParallelTable[
                       Graphics3D[Table[{
                                         dt[1, .01, -1, 1, 0, f, True], dt[.45, .01, 1, 1, 0, f, True],
                                         dt[1, .005, -1, 4, .2, f, False],
                                         dt[.45, .005, 1, 4, .2, f, False]},
                                        {t, 0, 200, PD}],
                                  ViewPoint -> Left, BoxRatios -> {1, 1, 1.3},
                                  ViewVertical -> {0, 0, -1},
                                  ViewCenter -> {{0.5, 0.5, 0.5}, {0.5, 0.55}}, Boxed -> False,
                                  PlotRange -> {{-20, 20}, {-20, 20}, {0, 20}}, Background -> Black],
                       {f, 0, 1, .01}];
lmmx commented 3 years ago

Update: see here for one someone already ported (though no twinkling)