C4D Script - Random Vertex Color

RandomVertexColor is a python script for Cinema R18 and higher, which allows you to assign random color to connected vertices using the new Vertex Color Tag. I did this script very quickly, the implementation may be a little "naive". I'll try to make some optimizations next time.

This script will use the vertex color tag associated with the selected object, otherwise a new one is created. Afterwards, a random color is applied on every connected vertices chunk

How to use ?

  • Select your object
  • Execute RandomVertexColor script by choosing it from the script menu or pressing the Execute button if you use the script manager



c4d random vertex color figure


# -*- coding: utf-8 -*-

# Author: safina3d
# Website: safina3d.blogspot.com
# Description: Assign random color to connected vertices using  Vertex Color Tag

import c4d
from c4d import utils, Vector
from random import randint


def get_random_color():
    """ Return a random color as c4d.Vector """

    def get_random_value():
        """ Return a random value between 0.0 and 1.0 """
        return randint(0, 255) / 256.0

    return Vector(get_random_value(), get_random_value(), get_random_value())


def get_connected_polygons(nbr, start_index):
    # type: (Neigbour, int) -> int[]
    result = [start_index]
    to_do = []
    done = []
    current = start_index

    while current is not None:
        connected_polygons = filter(lambda v: v != -1 and v not in result, nbr.GetPolyInfo(current)["face"])
        result += connected_polygons
        done.append(current)
        to_do += filter(lambda v: v not in done, connected_polygons)
        current = to_do.pop() if len(to_do) else None

    return result


def polygons_to_vertices(op, polygon_list):
    # type: (BaseObject, int[]) -> int[]
    vertices = []
    for polygon_index in polygon_list:
        pts = op.GetPolygon(polygon_index)
        vertices += [pts.a, pts.b, pts.c, pts.d]
    return list(set(vertices))


def get_chunks(nbr, op, remaining_polys):
    # type: (Neigbour, BaseObject, int[]) -> int[][]
    _chunks = []

    while len(remaining_polys) > 0:
        connected_polygons = get_connected_polygons(nbr, remaining_polys[0])
        _chunks.append(polygons_to_vertices(op, connected_polygons))
        remaining_polys = list(set(remaining_polys).difference(connected_polygons))

    return _chunks


def main():
    if op is None:
        return

    if c4d.OBJECT_POLYGON != op.GetType():
        return

    neigbour = utils.Neighbor()
    neigbour.Init(op)

    vertex_color_tag = op.GetTag(c4d.Tvertexcolor)

    if vertex_color_tag is None:
        vertex_color_tag = c4d.VariableTag(c4d.Tvertexcolor, op.GetPointCount())
        op.InsertTag(vertex_color_tag)

    doc.SetActiveTag(vertex_color_tag)
    data = vertex_color_tag.GetDataAddressW()

    remaining_polys = range(op.GetPolygonCount())

    chunks = get_chunks(neigbour, op, remaining_polys)

    for chunk in chunks:
        color = get_random_color()
        for vertex in chunk:
            c4d.VertexColorTag.SetColor(data, None, None, vertex, color)

    c4d.EventAdd()


if __name__ == '__main__':
    main()

C4D Script - Game of life

Another programming classic : Game Of Life (Cellular Automata family).

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.

The original Game of life rules (for a 2D space) are:

  • Each cell with one or no neighbors dies, as if by solitude.
  • Each cell with more than three neighbors dies, as if by overpopulation.
  • Each cell with two or three neighbors survives.
  • Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

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.

It'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 :)

Download Game of life project file

To create your own simulation, you have to :

  1. Define a set of starting points (see fill_grid method in source code)
  2. Set up your simulation rules
  3. Press play button to start simulation

Game of life

Source code


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):
        """
        Place here your points coordinates
        """
        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):
        """ Get next cells generation """

        new_generation = Generation()

        def birth(i, j, k):
            """ Checks if a new cell can be born """
            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 <= count <= birth_max:
                    new_generation.grid.set_value(i, j, k, Cell())

        def update_cell(selected_cell, i, j, k):
            """ Checks if the current cell can survive """
            count = self.get_cells_count_around(i, j, k)
            if survival_min <= count <= 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 > 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()

C4D Script - Minesweeper


Cinema 4D gives us a 3D engine, Objects, Gui and some programming languages.. that's all what we need to create some games.. of course there is some limitations, but it still possible.
that's why i developped a classic game "Minesweeper". The first of a long series (I hope...) of #Games4Cinema
This script is a draft, it still needs some features like placing flags or option menu etc...

Enjoy :)

minesweeper default minesweeper gameover

Installation

  • Clone the project or download the zip file and extract it into the Maxon scripts directory.
    • WindowsC:\Program Files\MAXON\CINEMA 4D R<version>\library\scripts\
    • MacOs/Applications/MAXON/CINEMA 4D R<version>/library/scripts/
  • Restart Cinema 4D
  • Open Cinema 4D Menu
    • Script » User scripts » Minesweeper » minesweeper


# 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__ == '__main__':
    dlg = MinesweeperGui(15, 10, Level.EASY)
    dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC)

Update: HNDisabler+

HNDisabler+ is a free Cinema 4D plugin (R13 and +) which allows you to enable, disable and change the visibility of one or multiple objects just by one click.

All objects are grouped by type, so, you can for instance disable all Hypernurbs or Bool objects at the same time, which is useful especially when you work on very heavy scenes.

Download HNDisabler+

Checkout the new HNDisabler plugin page


enjoy!


Update : zArabic 1.3


What's new in this version ?

  • you can use it for both sys Mac and Windows.
  • you can use Harakate / Tachkil when you write.
  • some known bugs corrected.
  • more efficient code.
  • also, you can copy the translated text to oher software such Photohop or AE.
  • etc...


ما الجديد في هذه االنسخة ؟
  • يمكن استخدام المقبس على الماك و الويندوز
  • يمكن استخدام التشكيل عند الكتابة
  • بعض الأخطاء المعروفة تم تصحيحها
  • يمكن تصدير النص الناتج الى برامج أخرى مثل الفوتوشوب أو غيره

Download zArabic 1.3.5

Check out the new zArabic plugin page