4
$\begingroup$

I want to recreate this animation I found online, of a giant clock that displays the time using many smaller clocks. The minute and hour hands of the smaller clocks rearrange into symmetry and shows the time. This is the particular image I found:

The giant clock

(The clock showing the time.)

(The video: Giant clock made out of tiny clocks)

For sake of simplicity: I want the needles of those clocks moving and align to show a single digit.

$\endgroup$
11
$\begingroup$

Here is the simple scene that I made using animation nodes:

enter image description here

I made 2 arrows, and duplicated it 5*8 times:

enter image description here

enter image description here

Each arrow is sent to the node program, which determines the position in the space and the rotation:

enter image description here

First, I divided the index by 5 and took the remainder of the division to get the coordinates (x and y index) of the arrow:

enter image description here

Next, I just multiplied it to get the correct scale of the arrow's matrix (x and y coordinates):

enter image description here

How to get the rotation? First, I wrote a map, which determines the rotation of each arrow. I made it using a list of "box symbols" ("┌","─","┐", etc..):

┌───┐
│┌──┘
││    
│└──┐
│┌─┐│
││ ││
│└─┘│
└───┘

Then I wrote the script, which converts a correct symbol into 2 angles:

out=[0,0]
if(letter=="┌"):
    out=[-90,180]
if(letter=="─"):
    out=[-90,90]
if(letter=="│"):
    out=[0,180]
if(letter=="┐"):
    out=[180,90]    
if(letter=="┘"):
    out=[0,90]      
if(letter=="└"):
    out=[0,-90]  

rot=out[arrow] 

So when I put the correct letter and arrow index (0 or 1 - first or second arrow) it outputs the correct angle:

enter image description here

This script block gets the letter from the text "map":

enter image description here

and finally I used the animate float node to make a transition between a random angle and that angle:

enter image description here

As you see, you need to know a little about Animation nodes and scripting. This is the file (NOTE: it will not work without Animation Nodes!):

$\endgroup$
  • $\begingroup$ Well done my friend. Understanding Animation nodes (or just math) is my dream. Sorry for the link but I need to: gph.is/2cpbE6Y $\endgroup$ – cgslav Aug 3 '18 at 21:52
6
$\begingroup$

First, the way of representing the digits has to be defined. In this answer, I shall use a low resolution image representing each digit. The image is a $10 \times 12$ binary image like this image representing the digit $4$:

Example Digit

Each $2 \times 2$ pixels represent a clock, so we have $\frac{10}{2}\times \frac{12}{2} = 5\times 6 = 30$ clocks. Each pointer have a limited number of directions it can point at, in particular, it can have an angle $0, \frac{\pi}{2}, \pi, \frac{3}{2}\pi$. By looking at each four pixels of each clock we can determine the orientation of its pointers. Since we have four pixels, then we have $2^4=16$ possible combination, however, if the image is inverted, nothing changes, making the number of possible orientations to be $8$. We can encode the the four pixels in a 4-bit number where each bit represents a pixel. Then one can compute a look up table for each possible 4-bit number that stores the orientation of each pointer. By looking at the reference image, we can find that LUT to be:

p1 = [undetermined, 0   , pi/2, 0 , pi      , undetermined, pi/2  , 0     ]
p2 = [undetermined, pi/2, pi  , pi, 1.5*pi  , undetermined, 1.5*pi, 1.5*pi]

Where p1 and p2 stores the orientation of the first and second pointer such that the index of each orientation is the 4-bit number that characterizes each combination. The undetermined indicates that all pixels are identical or that the first and third or the second and fourth quadrants are similar contrary to the others and thus no orientation can be determined.

In Animation Nodes, I will read the image as a single channel using the expression:

bpy.data.images[imageName].pixels[:][::4]

Where [:] copies the image values and [::4] get us every fourth element because we only need the first channel. (From RGBA we only need R) Then, I am going to get the width and height of the image using the expression:

width = bpy.data.images[imageName].size[0]
height = bpy.data.images[imageName].size[1]

Then, I am going to encode the pixels in the 4-bit number clock by using the following code:

LUT = []
for h in range(height // 2):
    for w in range(width // 2):
        clock = 0
        if pixels[(h * 2 + 1) * width + w * 2 + 1]: clock |= 1
        if pixels[(h * 2 + 1) * width + w * 2    ]: clock |= 2
        if pixels[h * 2 * width + w * 2          ]: clock |= 4
        if pixels[h * 2 * width + w * 2 + 1      ]: clock |= 8
        LUT.append(clock)

Since the width and height is double the number of clocks, we loop over only have of them. We initialize the 4-bit number to be zero and for each pixel, check if it is equal to a non zero and if yes, set its corresponding bit to one using the or operator. Then we append the 4-bit number to a list and return it. We only computed $8$ of the combinations, the other $8$ are identical to those computed as we said except their order is reversed, we could either invert the 4-bit number if it surpassed $8$ or combine the list to itself head to head which we shall do because it is easier.

The next step is to evaluate the LUT at the previously computed numbers, forming an Euler from that and constructing a matrix list along the points of a uniform grid. Those matrices represents the orientation of the pointers and their locations and a simple grid mesh can be transformed along them creating the pointers we need.

Node Tree

Result

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.