Currently im trying to make an addon for the Space Colonization Algorithm in Blender. At the moment i only have a skeleton as a tree. Does anybody have an idea on how to thicken the tree so it does look somewhat realistic? I already tried the skin modifier, but that makes everywhere the same thickness and thinning it down by hand is not a possibility. And the bevel modifier behaves strangely since i probably have too many points. Thanks, Nebeig Tree example

edit: I tried it with the following code:

import bpy
radius = 0.4

obj = bpy.data.objects['Tree']


for v in obj.data.skin_vertices[0].data:
radius -= 0.00025
v.radius = (radius,radius)


but blender chrashes when i try to execute the script.

    from random import randint, random, uniform
from copy import copy, deepcopy

def getDistance(p0, p1):
        return sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2 + (p0[2] - 

   # importiert von https://blender.stackexchange.com/questions/5898/how-can-i- 

class Tree:
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_label = 'Tools Tab Label'
    bl_context = 'objectmode'
    bl_category = 'SC'

def __init__(self):
    # Vektor operationen

    def div(x,y):
        return(x[0]/y, x[1]/y, x[2]/y)

    def sub(x,y):
        return(x[0]-y[0], x[1]-y[1], x[2]-y[2])

    def normieren(x,y):
        länge = sqrt(x[0]**2 + x[1]**2 + x[2]**2)
        return((x[0]/länge + x[1]/länge+ x[2]/länge)*y)

    def length_squared(u):
        return sum([a ** 2 for a in u])

    def add(u, v):    
        return [a + b for a, b in zip(u, v)]

    def norm(u):
        return setlength(u, 0.5)

    def scale_by_scalar(u, scalar):
        return [a * scalar for a in u]

    def length(u):
        return math.sqrt(length_squared(u))

    def setlength(u, l):
        return scale_by_scalar(u, l / length(u))

    branches = []
    leaves = [] 
    verts = ()
    closeEnough = 0 # False

    #leaves generieren
    for i in range(0,150):
        #bpy.ops.mesh.primitive_uv_sphere_add(size=0.1, location=leaves[i].pos)
        i =+ 1

    #Stamm machen    
    root = Branch(None,(0,0,0),(0,0,0.5))
    current = root       

    max_dist = 3
    min_dist = 1
    while closeEnough == 0: # False             
        for i in range (len(leaves)):
            g = 0
            g = getDistance(current.pos, leaves[i].pos)
            if (g < max_dist):
                print('schlaufe 1')
                closeEnough = 1
            if (closeEnough == 0):
                print('         schlaufe 2          ')
                nextPos = tuple(add(branches[i].pos,branches[i].dir))
                branch = Branch(i,nextPos,branches[i].dir)
                current = branch
                if (g > 100):

    #Der eigentliche Algorithmus                    
    def grow(self):           
        self.record = 100000
        for i in range(len(leaves)):
            leaf = leaves[i]
            closestBranch = None
            self.closestDir = None

            #Den nächsten Ast bestimmen
            for j in range(len(branches)):
                branch = branches[j]
                dir = sub(leaf.pos ,branch.pos)
                d = length(dir)
                if (d < min_dist):
                #elif(d > max_dist):      
                elif (closestBranch == None or d < self.record):
                    closestBranch = branch
                    self.record = d

            #Dessen Richtung bestimmen                              
            if (closestBranch is not None):
                newDir = tuple(sub(leaf.pos, closestBranch.pos))
                newDirnormed = norm(newDir)
                closestBranch.dir = tuple(add(closestBranch.dir, 
                closestBranch.count += 1

        #alle Blätter entfernen die erreicht wurden                       
        for i in reversed(range(len(leaves))):
            if (leaves[i].erreicht == 1):

        branchcopy = deepcopy(branches)    
        for i in reversed(range(len(branches))):
            branch = branches[i]
            if (branch.count > 0):               
                branch.dir = tuple(div(branch.dir,branch.count))
                newPos = tuple(add(branch.pos,branch.dir))
                newB = Branch(i, newPos, branch.dir)

    for i in range(70):    

    # this assumes all vertex positions are unique (= do not overlap)
    # create a mapping from vertex position to vertex index 
    verts = {b.pos:i for i,b in enumerate(branches)}
    # create vertex pairs as edge by locating vert index based on 
    edges = [ (verts[b.pos],verts[branches[b.parent].pos])for b in branches
    if b.parent is not None]
    # replace vertex mapping by simple list of coordinates
    verts = [b.pos for b in branches]

    mesh = bpy.data.meshes.new("tree_mesh")
    mesh.from_pydata(verts, edges, faces=[])

    obj = bpy.data.objects.new("Tree", mesh)

    scene = bpy.context.scene
    #remove doubles muss man noch machen

    obj = bpy.data.objects['Tree']
    for v in obj.vertices:
        v.select = True
        bpy.ops.transform.skin_resize(value=(0.695461, 0.695461, 0.695461))
        v.deselect = True

tree= Tree()
  • 1
    $\begingroup$ If you add the skin modifier to your mesh, it will create a 'skin_vertices' object in it, where you can access to the radius of the vertices... For example: bpy.data.objects['Obj'].data.skin_vertices[''].data[0].radius = (1.0, 1.0) $\endgroup$ – Secrop Jul 20 '18 at 10:56
  • $\begingroup$ Probably something wrong with your mesh... that script works ok here. Post your blend file for inspection. $\endgroup$ – Secrop Jul 20 '18 at 14:17

I resolved the problem by setting the name of the radius variable to something different than radius.


Try the Sapling Tree Gen add-on. You should have it in your copy of Blender and activate it.


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.