<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7484535416600256040</id><updated>2025-11-25T16:01:11.359+01:00</updated><category term="Tutorials"/><category term="Scripts"/><category term="Games4Cinema4D"/><title type='text'>safina3d</title><subtitle type='html'>For people who love 3D and Programming</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://safina3d.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-1973440103956861506</id><published>2019-10-31T01:11:00.017+01:00</published><updated>2024-03-06T01:12:59.232+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Tutorials"/><title type='text'>Create your first C4D plugin</title><content type='html'>&lt;p&gt;
The main purpose of this tutorial is to explain the process of creating Cinema 4D plugins. Object generator plugins (ObjectData) are a good starting point, as they are easy to understand and develop. This tutorial will show you how to create a &lt;a href=&quot;https://en.wikipedia.org/wiki/Torus_knot&quot; target=&quot;_blank&quot;&gt;3D Torus Knot&lt;/a&gt; generator from scratch using Python.
&lt;/p&gt;
&lt;p&gt;
It&#39;s important to note that in real-world projects, plugin creation is not always straightforward. We often go through a prototyping phase by doing a POC (proof of concept) to check the feasibility of our idea. This allows us to quickly test and only after that, we can begin developing the plugin.
&lt;/p&gt;

&lt;br /&gt;

&lt;iframe src=&quot;https://www.youtube.com/embed/bm03M_NbtFM&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;



&lt;p class=&quot;mt-2&quot;&gt;
The TorusKnot plugin for Cinema 4D allows you to generate splines in the shape of a torus knot. It uses the following mathematical properties to calculate the points of the spline:
&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The variable t, which defines the position of each point on the spline. This variable can range from MIN_T to MAX_T, with a T_STEP interval between each value used.&lt;/li&gt;
  &lt;li&gt;The radii R and r, which determine the general shape of the torus knot. R corresponds to KNOT_PARAM_R0, and r corresponds to KNOT_PARAM_R1.&lt;/li&gt;
  &lt;li&gt;The parameter n, which determines the number of turns of the spline. The higher this number is, the more turns the spline will have.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By using these parameters, the TorusKnot plugin allows you to generate splines in the shape of a torus knot in a simple and fast way, offering many possibilities for creating complex 3D shapes in Cinema 4D.&lt;/p&gt;


&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4SqKSxOqoK1Xk9n8eL1ntISC7kZzQgUjJM8U0UKvaxIEFm5XGe-Ulhdc6BY46dJdbNyOnVHHEIG1Rut2NecFRQ9GkgcWWixYzIPv6Gosi8TKBf9O_2Ir15mtYXm1c2RbLH5jvRKO8Cno/s1600/tk.png&quot; /&gt;


&lt;br&gt;&lt;br&gt;

&lt;h4 class=&quot;mb-1&quot;&gt;Some useful links&lt;/h4&gt;
&lt;ul&gt;
 &lt;li&gt;&lt;a href=&quot;https://www.mathcurve.com/courbes3d.gb/solenoidtoric/solenoidtoric.shtml&quot;&gt;Toric solenoid&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;https://developers.maxon.net/docs/Cinema4DPythonSDK/html/index.html&quot; target=&quot;_blank&quot;&gt;Python SDK documentation&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;https://developers.maxon.net/docs/Cinema4DCPPSDK/html/page_description_resource.html#section_descriptionresource_namingconvention&quot; target=&quot;_blank&quot; &gt;Description Resource&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;https://developers.maxon.net/?page_id=3224&quot; target=&quot;_blank&quot; &gt;How to get Plugin IDs ?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href=&quot;https://developers.maxon.net/docs/Cinema4DPythonSDK/html/misc/pluginstructure.html&quot; target=&quot;_blank&quot; &gt;Plugin Structure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class=&quot;plugin-toolbar mt-3&quot;&gt;
  &lt;div class=&quot;plugin-toolbar__item&quot;&gt;
    &lt;a href=&quot;http://bit.ly/2MZfWlV&quot; rel=&quot;external&quot;&gt;
      &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 512 512&quot;&gt;
        &lt;path
          d=&quot;M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32V274.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32zM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V416c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z&quot;
        /&gt;
      &lt;/svg&gt;
      Download
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;

</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/1973440103956861506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/1973440103956861506'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2019/10/torus-knot.html' title='Create your first C4D plugin'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/bm03M_NbtFM/default.jpg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-4498741637893156420</id><published>2019-10-02T03:53:00.013+02:00</published><updated>2024-02-11T15:36:05.413+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Tutorials"/><title type='text'>How to install python 3rd party library in Cinema 4D ?</title><content type='html'>&lt;div&gt;
  &lt;h3&gt;Update (For R21 and +)&lt;/h3&gt;   
  &lt;pre&gt;
	1- Download https://bootstrap.pypa.io/get-pip.py.
	2- Download the c4dpy version matching your Cinema 4D version. (Already included in R21 and +)
	3- Move c4dpy and get-pip.py in the Cinema 4D folder.
	4- Open a shell to the Cinema 4D folder:
		|_ Window: Type cmd in the top path and press Enter.
		|_ Mac: Open a new shell, then with cd navigate to your Cinema 4D folder. (You can drag and drop the path).
	5- Run this command line c4dpy get-pip.py. This will execute the get-pip script which will, download and install the pip module.
	6- Now you can start to play with pip c4dpy -m pip install pygame. c4dpy allow to runs any module with the -m argument see c4dpy commandline. 
  &lt;/pre&gt;
	
  Source: &lt;a href=&quot;https://plugincafe.maxon.net/topic/11384/3rd-party-apis-into-pyp-pypv-file/2&quot; alt=&quot;&quot;&gt;plugincafe&lt;/a&gt; 
&lt;/div&gt;

&lt;br /&gt;
&lt;br /&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;
    &lt;iframe src=&quot;https://www.youtube.com/embed/a2I0UHxFZJE&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;br /&gt;

&lt;pre&gt;
    1- Go to Cinema 4D python&#39;s directory
    2- If &quot;pip&quot; is not installed yet, download the get-pip.py file from https://bootstrap.pypa.io/get-pip.py
    3- Install pip (command line): .\python get-pip.py 
    4- Install pygame : .\python -m pip install pygame
&lt;/pre&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/4498741637893156420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/4498741637893156420'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2019/10/how-to-install-python-3rd-party-library.html' title='How to install python 3rd party library in Cinema 4D ?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/a2I0UHxFZJE/default.jpg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-8376442244702969260</id><published>2019-03-26T07:40:00.002+01:00</published><updated>2024-02-09T14:25:49.694+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Scripts"/><title type='text'>Measure the execution time of a script</title><content type='html'>&lt;p&gt;
Sometimes we have to choose between several algorithms that have the same goal. Performance and therefore the execution time can be considered as a good criterion, although there are many others.
For that the best solution would be to use a profiling tool, but if you want a quick solution we can simply calculate the difference of time between the beginning and the end of each algorithm. 
&lt;/p&gt;

&lt;p&gt;
In python, for ease and clarity of use, we can write this as a custom decorator and call it anywhere in our script.
&lt;/p&gt;

&lt;p&gt;
To use this decorator :
&lt;ol&gt;
  &lt;li&gt; Add the following snippet to your source code&lt;/li&gt;
  &lt;li&gt; Add the &lt;strong&gt;@measure()&lt;/strong&gt; annotation above the function&#39;s signature that you want to test&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;

&lt;br/&gt;
&lt;pre&gt;
def measure(iterations=1):
    &quot;&quot;&quot;
    This decorator allows you to print the average execution time of a function
    :param iterations: number of times that function will be called
    &quot;&quot;&quot;
    import time

    def decorator(fn):

        def wrapper(*args, **kwargs):
            _sum = 0.0
            _result = None
            for i in xrange(iterations):
                _start = time.time()
                _result = fn(*args, **kwargs)
                _sum += time.time() - _start

            print &#39;&quot;%s&quot; Function called %s time(s). Average execution time: %f sec&#39; % (fn.__name__, iterations, _sum / iterations)
            return _result

        return wrapper

    return decorator
&lt;/pre&gt;

&lt;br/&gt;&lt;br/&gt;
&lt;h4&gt;Example&lt;/h4&gt;

&lt;pre&gt;
@measure()
def my_function():
    ...
&lt;/pre&gt;
&lt;br/&gt;
&lt;p&gt;The tested function is called once, but we can increase the number of iterations to get a more precise value. this can be achieved by changing the value of the decorator&#39;s argument&lt;/p&gt;

&lt;pre&gt;
@measure(1000)
def my_function():
    ...
&lt;/pre&gt;


&lt;br/&gt;&lt;br/&gt;

&lt;h4&gt;Example of use&lt;/h4&gt;
&lt;p&gt;Let&#39;s say we have a scene containing 2000 different objects and we want to sort them (in the object manager) by type, and by name (if they have the same type).&lt;/p&gt;
&lt;p&gt;In the following source code we test 3 sorting algorithms:
&lt;ul&gt;
&lt;li&gt; Python default sort algorithm (&lt;a href=&quot;https://en.wikipedia.org/wiki/Timsort&quot; target=&quot;_blank&quot;&gt;Timsort&lt;/a&gt;) &lt;/li&gt;
&lt;li&gt; The Insertion sort &lt;/li&gt;
&lt;li&gt; The Bubble sort &lt;/li&gt;
&lt;/ul&gt;
the goal is to know which one is the fastest.
&lt;/p&gt;


&lt;pre&gt;
import c4d


def measure(iterations=1):
    &quot;&quot;&quot;
    This decorator allows you to print the average execution time of a function
    :param iterations: number of times that function will be called
    :return: fn
    &quot;&quot;&quot;
    import time

    def decorator(fn):
        def wrapper(*args, **kwargs):
            _sum = 0.0
            _result = None
            for i in xrange(iterations):
                _start = time.time()
                _result = fn(*args, **kwargs)
                _sum += time.time() - _start

            print &#39;&quot;%s&quot; Function called %s time(s). Average execution time: %f sec&#39; % (fn.__name__, iterations, _sum / iterations)
            return _result
        return wrapper
    return decorator


def gt(a, b):
    &quot;&quot;&quot; Checks that A value is greater than B &quot;&quot;&quot;
    type_a = a.GetType()
    type_b = b.GetType()
    
    if type_a == type_b:
        return a.GetName() &gt; b.GetName()
    
    return a.GetType() &gt; b.GetType()


def insertion_sort(array):
    &quot;&quot;&quot; This function allows you to sort an array using the insertion sort algorithm &quot;&quot;&quot;
    count = len(array)
    for i in xrange(count):
        current_value = array[i]
        pos = i
        while pos &gt; 0 and gt(array[pos - 1], current_value):
            array[pos] = array[pos - 1]
            pos = pos - 1
        array[pos] = current_value
    return array


def bubble_sort(array):
    &quot;&quot;&quot; This function allows you to sort an array using the bubble sort algorithm &quot;&quot;&quot;
    def swap(a, b):
        array[a], array[b] = array[b], array[a]

    count = len(array)
    swapped = True
    idx = -1
    while swapped:
        swapped = False
        idx = idx + 1
        for i in xrange(1, count - idx):
            if gt(array[i - 1], array[i]):
                swap(i - 1, i)
                swapped = True
                    
    return array


def _cmp(obj_a, obj_b):    
    return cmp(obj_a.GetType(), obj_b.GetType()) or cmp(obj_a.GetName(), obj_b.GetName())


def update_manager(doc, object_list):
    &quot;&quot;&quot; Updates all objects position in the object manager &quot;&quot;&quot;
    doc.StartUndo()    
    for obj in object_list:
        doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
        obj.Remove()
        doc.InsertObject(obj, None, None)
    
    doc.EndUndo()


@measure()
def main():

    obj = doc.GetFirstObject()
    if not obj: return
    
    objects = [obj]
    obj = obj.GetNext()
    while obj:
        objects.append(obj)
        obj = obj.GetNext()

    # Default sorting
    objects.sort(cmp=_cmp)

    # Insertion sorting
    # objects = insertion_sort(objects)

    # Bubble sorting
    # objects = bubble_sort(objects)

    objects.reverse()
    update_manager(doc, objects)
    
    c4d.EventAdd()


if __name__ == &#39;__main__&#39;:
    main()

&lt;/pre&gt;

&lt;br/&gt;

&lt;h4&gt;The results&lt;/h4&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-eeiSuacP4cFxZ9K_P19kzmoVyEWKPzp2HV-9quIyC-zfnPTQYxzI8tf3m3AOq93TCuji26DY-tIYwEMei2OwoZmyX1ZIZX5X63BikXTbQ9o3KQGw9C_r_w4bHyq36N9qDUSbVdskmnk/s1600/result.png&quot; /&gt;
&lt;/div&gt;



</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/8376442244702969260'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/8376442244702969260'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2019/03/measure-execution-time-of-script.html' title='Measure the execution time of a script'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-eeiSuacP4cFxZ9K_P19kzmoVyEWKPzp2HV-9quIyC-zfnPTQYxzI8tf3m3AOq93TCuji26DY-tIYwEMei2OwoZmyX1ZIZX5X63BikXTbQ9o3KQGw9C_r_w4bHyq36N9qDUSbVdskmnk/s72-c/result.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-8953740334348972711</id><published>2018-01-26T22:54:00.010+01:00</published><updated>2024-07-02T04:07:37.581+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Scripts"/><title type='text'>Random Vertex Color</title><content type='html'>&lt;p&gt;
  &lt;strong&gt;RandomVertexColor&lt;/strong&gt; is a Python script for Cinema 4D R18 and
  higher, designed to assign random colors to connected vertices using the
  Vertex Color Tag.
&lt;/p&gt;
&lt;p&gt;
  The script utilizes the vertex color tag associated with the selected object;
  if none exists, it creates a new one. Subsequently, random colors are applied
  to each connected chunk of vertices.
&lt;/p&gt;

&lt;br /&gt;
&lt;h4 class=&quot;mt-2 mb-1&quot;&gt;Installation:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Download the RandomVertexColor.py script.&lt;/li&gt;
  &lt;li&gt;Copy the script to the Cinema 4D scripts directory:&lt;/li&gt;
  &lt;ul&gt;
    &lt;li&gt;On Windows: C:\Program Files\MAXON\Cinema 4D RXX\library\scripts&lt;/li&gt;
    &lt;li&gt;On macOS: /Applications/MAXON/Cinema 4D RXX/library/scripts&lt;/li&gt;
  &lt;/ul&gt;
&lt;/ul&gt;

&lt;h4 class=&quot;mt-2 mb-1&quot;&gt;How to Use:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Select your polygon object.&lt;/li&gt;
  &lt;li&gt;
    Execute the RandomVertexColor script by selecting it from the script menu or
    pressing the Execute button in the script manager.
  &lt;/li&gt;
&lt;/ul&gt;

&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align:center;&quot;&gt;
  &lt;img
       class=&quot;rbox&quot;
    src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMH8MZwr734fLLLiFLmXa7yhvdVXaTauziTXkEkMa2BdMx7WL5feaQBMSUFdvrpT5yZhpAGALZHkk_7KGrh0qrQTNa4Woyasc670-ycQvRaBdSrw2nPyhAqIWp5aF9z8Bw64GDKHOttWk/s1600/figure.png&quot;
    alt=&quot;c4d random vertex color figure&quot;
  /&gt;
&lt;/div&gt;

&lt;h4 class=&quot;mt-2 mb-1&quot;&gt;ChangeLog:&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;strong&gt;V1.2&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Optimized performance&lt;/li&gt;
      &lt;li&gt;Added detailed documentation and type hints&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;strong&gt;V1.1&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;Code refactoring&lt;/li&gt;
      &lt;li&gt;R23 support added&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;br /&gt;
&lt;div class=&quot;plugin-toolbar mt-3&quot;&gt;
  &lt;div class=&quot;plugin-toolbar__item&quot;&gt;
    &lt;a href=&quot;https://gumroad.com/l/mwChy&quot; rel=&quot;external&quot; target=&quot;_blank&quot;&gt;
      &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 512 512&quot;&gt;
        &lt;path
          d=&quot;M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32V274.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32zM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V416c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z&quot;
        /&gt;
      &lt;/svg&gt;
      Download
    &lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/8953740334348972711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/8953740334348972711'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2018/01/random-vertex-color.html' title='Random Vertex Color'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMH8MZwr734fLLLiFLmXa7yhvdVXaTauziTXkEkMa2BdMx7WL5feaQBMSUFdvrpT5yZhpAGALZHkk_7KGrh0qrQTNa4Woyasc670-ycQvRaBdSrw2nPyhAqIWp5aF9z8Bw64GDKHOttWk/s72-c/figure.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-7338921006326789512</id><published>2018-01-01T06:38:00.005+01:00</published><updated>2024-02-09T16:56:45.032+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Scripts"/><title type='text'>Game of life</title><content type='html'>&lt;p&gt;Another programming classic : &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life&quot; target=&quot;_blank&quot;&gt;Game Of Life (Cellular Automata family)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Game of life is not a game and has nothing to do with life. but where it gets interesting, is in the fact that you can build complexe patterns whith different behaviours only with very simple rules.&lt;/p&gt;
&lt;p&gt;The original Game of life rules (for a 2D space) are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Each cell with one or no neighbors dies, as if by solitude.&lt;/li&gt;
  &lt;li&gt;Each cell with more than three neighbors dies, as if by overpopulation.&lt;/li&gt;
  &lt;li&gt;Each cell with two or three neighbors survives.&lt;/li&gt;
  &lt;li&gt;Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;
In this script (Xpresso python node) I tried to create 3D version of Game of life with the possibility to have dynamic rules. You can start with some rules and change them right in the middle of your simulation.
&lt;/p&gt;
&lt;p&gt;
It&#39;s a is time based animation. Every frame, new calculations are done and there is no bounderies for your final shape. as far as your rules allows expansion of your pattern and your PC can handle it :)
&lt;/p&gt;
&lt;a href=&quot;http://bit.ly/2CzL84j&quot;&gt;&lt;i class=&quot;fa fa-arrow-circle-o-right&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt; Download Game of life project file&lt;/a&gt;
&lt;br/&gt;
&lt;br/&gt;

&lt;div style=&quot;text-align: center;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/o-CKyVY4ZTk&quot; frameborder=&quot;0&quot; gesture=&quot;media&quot; allow=&quot;encrypted-media&quot; allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;br/&gt;
&lt;p&gt;To  create your own simulation, you have to :&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Define a set of starting points (see &lt;strong&gt;fill_grid&lt;/strong&gt; method in source code)
    &lt;li&gt;Set up your simulation rules&lt;/li&gt;
    &lt;li&gt;Press play button to start simulation&lt;/li&gt;
  &lt;/ol&gt;

&lt;br/&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb4_nV8WgDKxb7mGSUo0hdl_dXw4BIt7Q_flpeqCsspyRSO_tV0aiTo9Znzkz8qsVQTcEoSfF5U2esaZsrGTbkCp2dwJQCs_Ee9Fa7sd_OO-eiDvK7M-8u5hVrmr41Q-HaAAImzrLcQL8/s1600/gol.png&quot; alt=&quot;Game of life&quot;/&gt;&lt;/div&gt;
&lt;br/&gt;

&lt;h3&gt;Source code&lt;/h3&gt; 

&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;
import c4d
from c4d import documents, Vector
from collections import defaultdict


class MultidimensionalDictionary:

    def __init__(self):
        self.cells = defaultdict(lambda: defaultdict(dict))

    def get_value(self, i, j, k):
        if self.cells.has_key(i) and self.cells[i].has_key(j) and self.cells[i][j].has_key(k):
            return self.cells[i][j][k]
        return None

    def set_value(self, i, j, k, value):
        self.cells[i][j][k] = value
        return self

    def for_each(self, fn):
        for ikey, ivalue in self.cells.items():
            for jkey, jvalue in ivalue.items():
                for kkey, kvalue in jvalue.items():
                    fn(kvalue, ikey, jkey, kkey)


class Helper:

    @staticmethod
    def create_dict():
        return defaultdict(lambda: defaultdict(dict))

    @staticmethod
    def for_each(array, fn):
        for value in array:
            fn(value)

    @staticmethod
    def loop_around(i, j, k, fn):
        for a in xrange(i - 1, i + 2):
            for b in xrange(j - 1, j + 2):
                for c in xrange(k - 1, k + 2):
                    if (a, b, c) != (i, j, k):
                        fn(a, b, c)

    @staticmethod
    def fill_grid(generation):
        &quot;&quot;&quot;
        Place here your points coordinates
        &quot;&quot;&quot;
        init_points = [(-1, 0, 0), (1, 0, 0), (0, 0, 1), (0, 0, -1), (0, 1, 0), (0, -1, 0)]

        for p in init_points:
            generation.grid.set_value(p[0], p[1], p[2], Cell())


class Cell:

    def __init__(self, age=1):
        self.age = age


class Generation:

    def __init__(self):
        self.grid = MultidimensionalDictionary()

    def get_cells_count_around(self, i, j, k):
        counter = 0
        for a in xrange(i - 1, i + 2):
            for b in xrange(j - 1, j + 2):
                for c in xrange(k - 1, k + 2):
                    if self.grid.get_value(a, b, c):
                        counter += 1

        return counter - 1 if self.grid.get_value(i, j, k) else counter

    def get_next_generation(self):
        &quot;&quot;&quot; Get next cells generation &quot;&quot;&quot;

        new_generation = Generation()

        def birth(i, j, k):
            &quot;&quot;&quot; Checks if a new cell can be born &quot;&quot;&quot;
            current_cell = self.grid.get_value(i, j, k)
            if current_cell is None:
                count = self.get_cells_count_around(i, j, k)
                if birth_min &lt;= count &lt;= birth_max:
                    new_generation.grid.set_value(i, j, k, Cell())

        def update_cell(selected_cell, i, j, k):
            &quot;&quot;&quot; Checks if the current cell can survive &quot;&quot;&quot;
            count = self.get_cells_count_around(i, j, k)
            if survival_min &lt;= count &lt;= survival_max:
                selected_cell.age += 1
                new_generation.grid.set_value(i, j, k, selected_cell)
            Helper.loop_around(i, j, k, birth)

        self.grid.for_each(update_cell)
        return new_generation


class C4dRender:

    SCALE_COEF = 1
    OLDEST_CELL_AGE = 0

    def __init__(self):
        self.generation = Generation()
        self.doc = documents.GetActiveDocument()
        self.tp = self.doc.GetParticleSystem()
        self.root_group = self.tp.GetRootGroup()

        Helper.fill_grid(self.generation)

    def update(self):
        self.tp.FreeAllParticles()
        self.generation.grid.for_each(self.render)
        c4d.EventAdd()
        self.generation = self.generation.get_next_generation()

    def render(self, cell, i, j, k):
        C4dRender.OLDEST_CELL_AGE = cell.age if cell.age &gt; C4dRender.OLDEST_CELL_AGE else C4dRender.OLDEST_CELL_AGE
        # drawing particle
        p = self.tp.AllocParticle()
        self.tp.SetGroup(p, self.root_group)
        self.tp.SetPosition(p, Vector(i, j, k) * C4dRender.SCALE_COEF)
        self.tp.SetSize(p, cell.age * 0.5)
        self.tp.SetColor(p, Vector(c4d.utils.RangeMap(cell.age, 0, C4dRender.OLDEST_CELL_AGE, 0, 1, True), 0.2, 0.4))

instance = C4dRender()

def main():

    if frame % refresh == 0:
        instance.update()
&lt;/code&gt;&lt;/pre&gt;



</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/7338921006326789512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/7338921006326789512'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2018/01/game-of-life.html' title='Game of life'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/o-CKyVY4ZTk/default.jpg" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-1272666321033300830</id><published>2017-11-27T16:31:00.004+01:00</published><updated>2024-02-09T14:04:26.809+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Games4Cinema4D"/><title type='text'>Minesweeper</title><content type='html'>&lt;div style=&quot;clear: both;&quot;&gt;
&lt;br /&gt;
Cinema 4D gives us a 3D engine, Objects, Gui and some programming languages.. that&#39;s all what we need to create some games.. of course there is some limitations, but it still possible.
&lt;/div&gt;
that&#39;s why i developped a classic game &quot;Minesweeper&quot;. The first of a long series (I hope...) of #Games4Cinema
&lt;br /&gt;
This script is a draft, it still needs some features like placing flags or option menu etc...
&lt;br /&gt;
&lt;br /&gt;
Enjoy :)
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;img alt=&quot;minesweeper default&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMfNg2d5EbTpYJmpizFsk1zWnoSaEQZEf77lz1Pq2HUxqcbEB5_lBEhvTZBqQiCrODNOWAo220EQ921W45ts0RrQWY2mqsnccOvEmubrG54SJN9AJ3yVjzFQKhVBeWKgO67oBiboaVMFA/s1600/minesweeper.png&quot; /&gt;
  &lt;img alt=&quot;minesweeper gameover&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWWw6QG-RBI_Lkf-22pMRpNcq1nhmiqyvHqyAUk5yAk2gv5wb9HwN2oeX5K_ahTR2wjyjcQLLP80BzCbT5zAFJ4qRgrjpMS4OXBwrOkZ5MuZT4ZXNy8QPwg8HPK7ZkOZPVqdqHO9mz29Y/s1600/minesweeper2.png&quot; /&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;
Installation&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Clone the project or download the zip file and extract it into the Maxon scripts directory.
   &lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;display: inline-block; width: 5rem;&quot;&gt;Windows&lt;/span&gt;&lt;span class=&quot;code&quot;&gt;C:\Program Files\MAXON\CINEMA 4D R&amp;lt;version&amp;gt;\library\scripts\&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;display: inline-block; width: 5rem;&quot;&gt;MacOs&lt;/span&gt;&lt;span class=&quot;code&quot;&gt;/Applications/MAXON/CINEMA 4D R&amp;lt;version&amp;gt;/library/scripts/&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Restart Cinema 4D&lt;/li&gt;
&lt;li&gt;Open Cinema 4D Menu&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Script » User scripts » Minesweeper » minesweeper&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code class=&quot;python&quot;&gt;
# You can change the size of the grid and difficulty by changing the values passed to the `MinesweeperGui` object.
# The args are: Rows, Columns, Difficulty[EASY|MEDIUM|DIFFICULT]

if __name__ == &#39;__main__&#39;:
    dlg = MinesweeperGui(15, 10, Level.EASY)
    dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)
&lt;/code&gt;&lt;/pre&gt;

&lt;div class=&quot;plugin-toolbar&quot;&gt;
  &lt;div&gt;
  &lt;a href=&quot;http://bit.ly/2AGvFkW&quot; rel=&quot;external&quot;&gt;
    &lt;i aria-hidden=&quot;true&quot; class=&quot;fa fa-download&quot;&gt;&lt;/i&gt;
    &lt;p&gt;Download&lt;/p&gt;
  &lt;/a&gt;
  &lt;/div&gt;
  &lt;div&gt;
  &lt;a href=&quot;https://github.com/safina3d/c4d-minesweepr&quot; rel=&quot;external&quot; target=&quot;_blank&quot;&gt;
    &lt;i aria-hidden=&quot;true&quot; class=&quot;fa fa-github&quot;&gt;&lt;/i&gt;
    &lt;p&gt;Source code&lt;/p&gt;
  &lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/1272666321033300830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/1272666321033300830'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2017/11/games4cinema4d-minesweeper.html' title='Minesweeper'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMfNg2d5EbTpYJmpizFsk1zWnoSaEQZEf77lz1Pq2HUxqcbEB5_lBEhvTZBqQiCrODNOWAo220EQ921W45ts0RrQWY2mqsnccOvEmubrG54SJN9AJ3yVjzFQKhVBeWKgO67oBiboaVMFA/s72-c/minesweeper.png" height="72" width="72"/></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-747262394625808881</id><published>2011-10-26T05:28:00.002+02:00</published><updated>2024-02-09T17:16:08.750+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Tutorials"/><title type='text'>XPresso, Wheel animation</title><content type='html'>&lt;p&gt;This tutorial is a simple introduction to Xpresso and Thinking Particles.&lt;/p&gt;
&lt;p&gt;Project file &lt;a href=&quot;http://dl.dropbox.com/u/30974024/Tutos/Wheel.zip&quot;&gt;&lt;i class=&quot;fa fa-arrow-circle-o-right&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt; wheel.zip&lt;/a&gt;&lt;/p&gt;
&lt;br /&gt;


&lt;div class=&quot;video-container&quot;&gt;
    &lt;h4&gt;Part I&lt;/h4&gt;
    &lt;iframe src=&quot;https://player.vimeo.com/video/31119546&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;div class=&quot;video-container&quot;&gt;
    &lt;h4&gt;Part II&lt;/h4&gt;
    &lt;iframe allowfullscreen frameborder=&quot;0&quot; src=&quot;https://player.vimeo.com/video/35168681&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;Render test&lt;/p&gt;
&lt;div class=&quot;video-container&quot;&gt;
    &lt;iframe allowfullscreen frameborder=&quot;0&quot; src=&quot;//player.vimeo.com/video/30772198&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/747262394625808881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/747262394625808881'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2011/10/tutorial-wheel-animation-part-i.html' title='XPresso, Wheel animation'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-7484535416600256040.post-4896219030694636087</id><published>2010-12-23T17:04:00.005+01:00</published><updated>2024-02-09T13:40:10.686+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Tutorials"/><title type='text'>Creating a Rain setup with Thinking Particles</title><content type='html'>&lt;div class=&quot;video-container&quot;&gt;
  &lt;iframe frameborder=&quot;0&quot; src=&quot;//player.vimeo.com/video/18121111?loop=1&quot;&gt;&lt;/iframe&gt;
  &lt;div style=&quot;text-align: center;&quot;&gt;  
    &lt;a href=&quot;http://vimeo.com/18121111&quot;&gt;Cinema 4D : Rain Test #01&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/user2890137&quot;&gt;safina3d&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com/&quot;&gt;Vimeo&lt;/a&gt;.&lt;br /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h4&gt;Tutorial&lt;/h4&gt;

&lt;div class=&quot;video-container&quot;&gt;
  &lt;iframe frameborder=&quot;0&quot; src=&quot;//player.vimeo.com/video/18310667?loop=1&quot;&gt;&lt;/iframe&gt;
  &lt;div style=&quot;text-align: center;&quot;&gt;
    &lt;a href=&quot;http://vimeo.com/18310667&quot;&gt;Tutorial : Rain with Thinking Particles&lt;/a&gt; from &lt;a href=&quot;http://vimeo.com/user2890137&quot;&gt;safina3d&lt;/a&gt; on &lt;a href=&quot;http://vimeo.com/&quot;&gt;Vimeo&lt;/a&gt;.
  &lt;/div&gt;
&lt;/div&gt;


&lt;h4&gt;Ripple effect&lt;/h4&gt;
&lt;div class=&quot;video-container&quot;&gt;
  &lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; src=&quot;//www.youtube.com/embed/0hJ7bgpUMNA&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;div&gt;
&lt;a href=&quot;http://bit.ly/2kYNBgo&quot;&gt;&lt;i class=&quot;fa fa-arrow-circle-o-right&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt; Download the project file&lt;/a&gt;
&lt;/div&gt;
</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/4896219030694636087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7484535416600256040/posts/default/4896219030694636087'/><link rel='alternate' type='text/html' href='http://safina3d.blogspot.com/2010/12/rain-test-01.html' title='Creating a Rain setup with Thinking Particles'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author></entry></feed>