motiv-cloud

Übersicht: Python & Blender


Objectives

a

What can be modeled? The most common themes are landscapes with the following objects that we want to create in some cases:

  • Clouds
  • Stones
  • Trees
  • Gras
  • Water
  • Mountains/landscape

Instructions

Tasks:
  1. Configure Blender for skripting and rendering.
  2. Create a copy of the template (see Collection at the Appendix)
  3. Create the script of this station. Don't to forget to diverify the parmeters or the other parts of the script.

Clouds and Stones

Let's start with stones and clouds, later on we will place this objects in a szene. They differ only in size and color. Later we can possibly reuse this kind of object as a treetop.

Let's create a ICO-Sphere as a first step. We should prefer this type over a UV-Sphere because it is formed from triangles and better suitable for irregular structures.

The Template

use-cases/art/low-poly/cloud-skel.py (Source)

#!bpy
"""
Name: 'Cloud-Generator'
Blender: 2.7x
Group: 'Low poly'
Tooltip: 'Part of a Low-Poly-Skripts collection'
"""
import bpy


class Cloud():
    """Create a cloud as low poly"""

    def __init__(self):
        pass

    def setColor(self):
        pass

    def new(self):
        """ constuction of a new cloud """
        pass

    def remove(self):
        """ Delete a cloud or all"""
        pass

if __name__ == "__main__":

    # switch to object mode, if nessasary
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')
    cloud = Cloud()

The first cloud

The missing part is a command that can create a picture like this:

/use-cases/art/low-poly/cloud.png

use-cases/art/low-poly/cloud-a.py (Source)

        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(-3, 10, 8))

The command can be discovered at different locations. Here a again is short list:

  • Have a look at the Tool-Tip if you are using the Add-Menu.
  • Clicking on the Tool-Tip is switching to the online documentation.
  • After execution of a command a log entry in the info window is available (enlarge the info window).
  • There is a list of operators (menu: Help | Operator Cheat Sheet), search in this list.
  • Use the console window to explore the object hirachy, available operators and attributes.
  • Search the web for useful hints.
  • Ask other people.
  • Bay a book.

If you copy the command from the info window (click right mouse button to mark the line), copy & paste as usual, you get the long version. In most cases you can delete the layer part of the command and it is much shorter! If you have finished with copying the line, don't forget to right-click again and therefore deselect the line.

Naming the Objects

If you have many objects in a szene, selection by name is comphtable. So lets put a name at our new object. Before we cut the somewhat long path from module yet and thus save typing for the subsequent lines.

use-cases/art/low-poly/cloud-a.py (Source)

    def new(self):
        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(-3, 10, 8))
        obj = bpy.context.object
        obj.name = "cloud"

All at one Place

If we add multiple objects, they are all located at the same place. Lets create random values to set every object on an other location.

  1. Import random, it creates new numbers with every call. We will use these Module very often!

    import random
    
  2. Not nessasary, but an integer is better to read and handle. Let's convert the float values to integers. We also using two values (min and max see alos line 5-7).

    use-cases/art/low-poly/cloud-e.py (Source)

    1
    2
    3
    4
    5
    6
    7
            """ constuction of a new cloud """
            bpy.ops.mesh.primitive_ico_sphere_add(location=(0, 0, 0))
            obj = bpy.context.object
            obj.name = "cloud"
            obj.location.x = int(random.uniform(min +10 * -1, max + 10))
            obj.location.y = int(random.uniform(min, max)) * 10
            obj.location.z = int(random.uniform(min, max +3 )) * 10
    

A variable Cloud Size

The clouds have the same size at the moment. Lets change this behavior (lines 10-12).

use-cases/art/low-poly/cloud-e.py (Source)

    def new(self, min=0, max=1):
        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(0, 0, 0))
        obj = bpy.context.object
        obj.name = "cloud"
        obj.location.x = int(random.uniform(min +10 * -1, max + 10))
        obj.location.y = int(random.uniform(min, max)) * 10
        obj.location.z = int(random.uniform(min, max +3 )) * 10

        obj.scale[0] = int(random.uniform(min + 1, max + 3))
        obj.scale[1] = int(random.uniform(min + 1, max + 3))
        obj.scale[2] = int(random.uniform(min + 1, max + 4))

Cleanup

If you started the script often, you will discover a huge and growing number of objects! The template contains a method to delete the old objects with every run. What happens at this point:

We check, if a name was given. If this is true we use this name, if not we use all names starting with cloud. At the end all selected objects are deleted.

use-cases/art/low-poly/cloud-e.py (Source)

        """ Delete a cloud or all"""

        if name:
            bpy.ops.object.select_pattern(pattern=name)
        else:
            bpy.ops.object.select_pattern(pattern="cloud*")

        bpy.ops.object.delete()

Change the Corpus

Our clouds are still spheres. Lets change this. A modifier will do this (DISPLACE at line 18). Therefor we have to switch to the edit mode, this is mandatory (see lines 12-16 and 19-21).

use-cases/art/low-poly/cloud-e.py (Source)

        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(0, 0, 0))
        obj = bpy.context.object
        obj.name = "cloud"
        obj.location.x = int(random.uniform(min +10 * -1, max + 10))
        obj.location.y = int(random.uniform(min, max)) * 10
        obj.location.z = int(random.uniform(min, max +3 )) * 10

        obj.scale[0] = int(random.uniform(min + 1, max + 3))
        obj.scale[1] = int(random.uniform(min + 1, max + 3))
        obj.scale[2] = int(random.uniform(min + 1, max + 4))

        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.subdivide()
        bpy.ops.mesh.subdivide()
        bpy.ops.object.editmode_toggle()

        bpy.ops.object.modifier_add(type='DISPLACE')
        STUCCI_TEX = bpy.data.textures.new("Stucci tex", type="STUCCI")
        obj.modifiers["Displace"].texture = STUCCI_TEX
        obj.modifiers["Displace"].strength = .2

Colored Clouds

Each cloud should get a new color. The random method should do this for us (lines 24-31). We try to get blue color values, but clouds may have different colors too. Have a look to the sky!

use-cases/art/low-poly/cloud-e.py (Source)

        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(0, 0, 0))
        obj = bpy.context.object
        obj.name = "cloud"
        obj.location.x = int(random.uniform(min +10 * -1, max + 10))
        obj.location.y = int(random.uniform(min, max)) * 10
        obj.location.z = int(random.uniform(min, max +3 )) * 10

        obj.scale[0] = int(random.uniform(min + 1, max + 3))
        obj.scale[1] = int(random.uniform(min + 1, max + 3))
        obj.scale[2] = int(random.uniform(min + 1, max + 4))

        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.subdivide()
        bpy.ops.mesh.subdivide()
        bpy.ops.object.editmode_toggle()

        bpy.ops.object.modifier_add(type='DISPLACE')
        STUCCI_TEX = bpy.data.textures.new("Stucci tex", type="STUCCI")
        obj.modifiers["Displace"].texture = STUCCI_TEX
        obj.modifiers["Displace"].strength = .2

        MATERIAL_CLOUD = bpy.data.materials.new('cloud')
        self.setColor(obj,
                      MATERIAL_CLOUD,
                      (random.uniform(0, .3),
                       random.uniform(0, .3),
                       random.uniform(0.3, 1)))

Five Clouds Please

Our cloud generator is is almost finished. Lets do the following steps:

  • Delete all clouds
  • Create five new clouds

use-cases/art/low-poly/cloud-e.py (Source)

1
2
3
4
5
6
7
8
    # switch to object mode, if nessasary
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')
    cloud = Cloud()
    cloud.remove()
    for i in range(5):
        cloud = Cloud()
        cloud.new()
/use-cases/art/low-poly/five-clouds.png

The Script as Whole

use-cases/art/low-poly/cloud-e.py (Source)

#!bpy
"""
Name: 'Cloud-Generator'
Blender: 2.7x
Group: 'Low poly'
Tooltip: 'Part of a Low-Poly-Skripts collection'
"""
import bpy
import random

class Cloud():
    """Create a cloud as low poly"""

    def __init__(self):
        pass

    def setColor(self, obj, material, color):
        material.diffuse_color = color
        material.specular_hardness = 200
        obj.data.materials.append(material)

    def new(self, min=0, max=1):
        """ constuction of a new cloud """
        bpy.ops.mesh.primitive_ico_sphere_add(location=(0, 0, 0))
        obj = bpy.context.object
        obj.name = "cloud"
        obj.location.x = int(random.uniform(min +10 * -1, max + 10))
        obj.location.y = int(random.uniform(min, max)) * 10
        obj.location.z = int(random.uniform(min, max +3 )) * 10

        obj.scale[0] = int(random.uniform(min + 1, max + 3))
        obj.scale[1] = int(random.uniform(min + 1, max + 3))
        obj.scale[2] = int(random.uniform(min + 1, max + 4))

        bpy.ops.object.editmode_toggle()
        bpy.ops.mesh.subdivide()
        bpy.ops.mesh.subdivide()
        bpy.ops.object.editmode_toggle()

        bpy.ops.object.modifier_add(type='DISPLACE')
        STUCCI_TEX = bpy.data.textures.new("Stucci tex", type="STUCCI")
        obj.modifiers["Displace"].texture = STUCCI_TEX
        obj.modifiers["Displace"].strength = .2

        MATERIAL_CLOUD = bpy.data.materials.new('cloud')
        self.setColor(obj,
                      MATERIAL_CLOUD,
                      (random.uniform(0, .3),
                       random.uniform(0, .3),
                       random.uniform(0.3, 1)))

    def remove(self, name=None):
        """ Delete a cloud or all"""

        if name:
            bpy.ops.object.select_pattern(pattern=name)
        else:
            bpy.ops.object.select_pattern(pattern="cloud*")

        bpy.ops.object.delete()


if __name__ == "__main__":

    # switch to object mode, if nessasary
    if bpy.ops.object.mode_set.poll():
        bpy.ops.object.mode_set(mode='OBJECT')
    cloud = Cloud()
    cloud.remove()
    for i in range(5):
        cloud = Cloud()
        cloud.new()

Comments