Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class AdvancedSettingsPanel(Panel):
def draw(self, context):
mtree_props = context.scene.mtree_props
layout = self.layout
scene = context.scene

box = layout.box()
box.prop(mtree_props, 'mat')
Expand All @@ -292,6 +293,8 @@ def draw(self, context):
if mtree_props.particle:
box.prop(mtree_props, 'number')
box.prop(mtree_props, 'display')
box.prop_search(mtree_props, "twig_particle", scene, "objects")
box.prop(mtree_props, 'particle_size')


class WindAnimationPanel(Panel):
Expand Down Expand Up @@ -333,6 +336,7 @@ class MakeTwigPanel(Panel):
def draw(self, context):
mtree_props = context.scene.mtree_props
layout = self.layout
scene = context.scene

row = layout.row()
row.scale_y = 1.5
Expand All @@ -345,11 +349,12 @@ def draw(self, context):
box = layout.box()
box.label("Twig Options")
box.prop(mtree_props, "leaf_size")
box.prop_search(mtree_props, "leaf_object", scene, "objects")
box.prop(mtree_props, "leaf_chance")
box.prop(mtree_props, "leaf_weight")
box.prop(mtree_props, "TwigSeedProp")
box.prop(mtree_props, "twig_iteration")
box.prop_search(mtree_props, "twig_bark_material", bpy.data, "materials")
box.prop_search(mtree_props, "twig_leaf_material", bpy.data, "materials")


class MakeTreePresetsPanel(Panel):
Expand Down Expand Up @@ -566,6 +571,15 @@ class ModularTreePropertyGroup(PropertyGroup):
name="Particles in Viewport",
default=500)

twig_particle = StringProperty(
name='twig or leaf object',
default='')

particle_size = FloatProperty(
name="twig/leaf size",
min=0,
default=1.5)

break_chance = FloatProperty(
name="Break Chance",
default=0.02)
Expand All @@ -583,8 +597,11 @@ class ModularTreePropertyGroup(PropertyGroup):
min=0,
default=.5)

twig_leaf_material = StringProperty(
name="Leaf Material")
leaf_weight = FloatProperty(
name="Leaf Weight",
min=0,
max=1,
default=.2)

twig_bark_material = StringProperty(
name="Twig Bark Material")
Expand All @@ -599,6 +616,11 @@ class ModularTreePropertyGroup(PropertyGroup):
soft_max=10,
default=9)

leaf_object = StringProperty(
name="leaf object",
default="",
description="The object used for the leaves. \nThe leaf must be on Y axis and the rotation must be applied")

tree_number = IntProperty(
name="Tree Number",
min=2,
Expand Down
30 changes: 19 additions & 11 deletions generator_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ def execute(self, context):

seed(mtree_props.TwigSeedProp)
save_preserve_trunk = mtree_props.preserve_trunk
save_trunk_split_angle = mtree_props.split_angle # This variable is never used! Should it be?
save_randomangle = mtree_props.randomangle
save_trunk_variation = mtree_props.trunk_variation
save_radius = mtree_props.radius
Expand Down Expand Up @@ -146,6 +145,7 @@ def execute(self, context):
save_number = mtree_props.number
save_display = mtree_props.display
save_break_chance = mtree_props.break_chance
save_use_grease_pencil = mtree_props.use_grease_pencil

mtree_props.preserve_trunk = False
mtree_props.trunk_split_angle = 0
Expand Down Expand Up @@ -180,6 +180,7 @@ def execute(self, context):
mtree_props.number = 0
mtree_props.display = 0
mtree_props.break_chance = 0
mtree_props.use_grease_pencil = False

if bpy.data.materials.get("twig bark") is None:
build_bark_material("twig bark")
Expand All @@ -191,16 +192,23 @@ def execute(self, context):

twig = bpy.context.active_object
twig.name = 'twig'
leafs = []
twig.active_material = bpy.data.materials.get(mtree_props.twig_bark_material)
for (position, direction, rotation) in twig_leafs:
for i in range(randint(1, 3)):
if random() < mtree_props.leaf_chance:
add_leaf(position + direction * .5 * random(), direction + Vector((random(), random(), random())),
rotation + random() * 5, (1 + random()) * mtree_props.leaf_size)
bpy.context.active_object.active_material = bpy.data.materials.get(mtree_props.twig_leaf_material)
twig.select = True
scene.objects.active = twig

for (position, direction) in twig_leafs:
if random() < mtree_props.leaf_chance:
for i in range(randint(1, 3)):
if random() < mtree_props.leaf_chance:
add_leaf(position+direction*random(), direction+Vector((random()-.5, random()-.5, 0))*.2, mtree_props.leaf_size*(2+random()), mtree_props.leaf_object, mtree_props.leaf_weight)
leafs.append(bpy.context.active_object)
if not bpy.context.active_object.data.materials.items():
mat = bpy.data.materials.get("leaf_mat")
if mat is None:
mat = bpy.data.materials.new(name="leaf_mat")
bpy.context.active_object.active_material = mat
twig.select = True
scene.objects.active = twig
for i in leafs:
i.select = True
bpy.ops.object.join()
bpy.ops.transform.rotate(value=-1.5708, axis=(1, 0, 0))
bpy.ops.transform.resize(value=(0.25, 0.25, 0.25))
Expand Down Expand Up @@ -240,6 +248,7 @@ def execute(self, context):
mtree_props.number = save_number
mtree_props.display = save_display
mtree_props.break_chance = save_break_chance
mtree_props.use_grease_pencil = save_use_grease_pencil

return {'FINISHED'}

Expand Down Expand Up @@ -332,7 +341,6 @@ def execute(self, context):
return {'CANCELLED'}

if is_tree_prop:
pos = obj.location # this is never used...should it be?
scale = obj.scale
rot = obj.rotation_euler
bpy.ops.mod_tree.add_twig()
Expand Down
10 changes: 7 additions & 3 deletions particle_configurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
# along with Modular Tree. If not, see <http://www.gnu.org/licenses/>.
# ##### END GPL LICENSE BLOCK #####

import bpy

def create_system(ob, number, display, vertex_group):

def create_system(ob, number, display, vertex_group, object_name, size):
""" Creates a particle system

Args:
Expand All @@ -31,7 +33,7 @@ def create_system(ob, number, display, vertex_group):
g = vertex_group

# customize the particle system
leaf = ob.modifiers.new("psys name", 'PARTICLE_SYSTEM')
leaf = ob.modifiers.new("leafs", 'PARTICLE_SYSTEM')
part = ob.particle_systems[0]
part.vertex_group_density = g.name
settings = leaf.particle_system.settings
Expand All @@ -46,7 +48,9 @@ def create_system(ob, number, display, vertex_group):
settings.use_rotations = True
settings.phase_factor = 1
settings.phase_factor_random = 1
settings.particle_size = 0.015
settings.particle_size = 0.1 * size
settings.size_random = 0.25
settings.brownian_factor = 1
settings.render_type = "OBJECT"
if bpy.data.objects.get(object_name) is not None:
settings.dupli_object = bpy.context.scene.objects[object_name]
90 changes: 51 additions & 39 deletions tree_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ def interpolate(verts1, verts2, t):
[(14, 19), (22, 25), (25, 29), (6, 29)])

Trunks = [trunk, trunk2, trunk3, trunk4, trunk5]
Joncts = [S1, S2, S3, S4, trunk,trunk2,trunk5]
Joncts = [S1, S2, S3, S4, trunk, trunk2, trunk5]

class Trunk:
"""This is used to represent the base of a trunk with roots"""
Expand Down Expand Up @@ -848,37 +848,45 @@ def fix_normals(inside):
bpy.ops.object.mode_set(mode='OBJECT')


def add_leaf(position, direction, rotation, scale):
scene = bpy.context.scene

verts, faces = ([(-1.0, 0.07, 0.05), (1.0, 0.07, 0.05), (-1.0, -1.01, 1.75),
(1.0, -1.01, 1.75), (-1.0, -0.76, 1.1), (-1.0, -0.38, 0.55),
(1.0, -0.38, 0.55), (1.0, -0.76, 1.1), (-0.33, 0.0, 0.0),
(0.33, 0.0, 0.0), (0.33, -1.16, 1.64), (-0.33, -1.16, 1.64),
(0.33, -0.56, 0.42), (-0.33, -0.56, 0.42), (0.33, -0.9, 1.0), (-0.33, -0.9, 1.0)],
def sign (a):
return 1 if a > 0 else -1 if a < 0 else 0

[(14, 7, 3, 10), (9, 1, 6, 12), (12, 6, 7, 14), (5, 13, 15, 4), (13, 12, 14, 15),
(0, 8, 13, 5), (8, 9, 12, 13), (4, 15, 11, 2), (15, 14, 10, 11)])

verts = [Vector(v) for v in verts]
verts = rot_scale(verts, scale, direction, rotation)
verts = [v + position for v in verts]
def add_leaf(position, direction, scale,leaf,leaf_weight):
scene = bpy.context.scene
direction= Vector((0,1,0)) * leaf_weight + (1-leaf_weight) * direction
direction.normalize()

mesh = bpy.data.meshes.new("leaf")
mesh.from_pydata(verts, [], faces)
mesh.update(calc_edges=False)
for select_ob in bpy.context.selected_objects:
select_ob.select = False
leaf_object = scene.objects[leaf]
# scene.objects[leaf].select = True
# bpy.context.scene.objects.active = scene.objects[leaf]
# bpy.ops.object.duplicate()
new_leaf = leaf_object.copy()
new_leaf.data = leaf_object.data.copy()
bpy.context.scene.objects.link(new_leaf)
leaf_object = new_leaf
leaf_object.select = True
bpy.context.scene.objects.active = leaf_object
# scene.objects[leaf].select = False
# leaf_object = bpy.context.active_object
dim = max(bpy.context.object.dimensions)
bpy.ops.transform.resize(value = (scale/dim, scale/dim, scale/dim))
leaf_object.location = position
bpy.ops.transform.rotate(value=pi/2, axis=(1, 0, 0))
Y = Vector((direction.x,0,direction.z))
X = Vector((0,direction.y, direction.z))
angle_Y = 0 if Y == Vector((0,0,0)) else Vector((0,0,1)).angle(Y)*sign(direction.x)
angle_X = 0 if X == Vector((0, 0, 0)) else Vector((0, 0, 1)).angle(X) * sign(-direction.y)
if abs(angle_Y) > pi/2:
angle_Y /= 3
if angle_X > 0:
angle_X /= 4
bpy.ops.transform.rotate(value = angle_Y, axis=(0, 1, 0))
bpy.ops.transform.rotate(value=angle_X, axis=(1, 0, 0))

obj = bpy.data.objects.new("leaf", mesh)
obj.location = scene.cursor_location

scene.objects.link(obj)
scene.objects.active = obj

obj.select = True
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.001)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.shade_smooth()

def rehash_set(s, p_dist):
new_set = []
Expand Down Expand Up @@ -910,14 +918,14 @@ def create_tree(position, is_twig=False):

Details:
There is a list of vertices, a list of faces and a list of seams.
There is a list of all current end of the tree. At each iteration all those ends can evolve in three diferent ways:
There is a list of all current end of the tree. At each iteration all those ends can evolve in three different ways:
-The end can continue to grow as a branch, with a new end
-The end can be splited in two branches, with a new end each
-The end can be spliced in two branches, with a new end each
-The end can break
Depending on this choice, vertices and faces of a Module, Split or end cap will be added to the vertices and faces list.
This processus is executed for both roots and branches generation.
This process is executed for both roots and branches generation.
After this, the tree object itself is created, the vertices, faces and seams are applied.
Once the object is created, it can be unwrapped, a material is asigned or created, and an armature is created.
Once the object is created, it can be unwrapped, a material is assigned or created, and an armature is created.


Args:
Expand Down Expand Up @@ -1026,17 +1034,22 @@ def create_tree(position, is_twig=False):

for E in extremites:
indexes, radius, direction, s_index, Lb, trunk2, curr_rotation = E

real_radius = (verts[indexes[0]] - verts[indexes[3]]).length
new_rotation = (curr_rotation + mtree_props.branch_rotate + 2 * (1 - random()) * mtree_props.branch_random_rotate) % 360

if i > mtree_props.preserve_end:
trunk2 = False
pos = position
pos = Vector((0,0,0))

for k in indexes:
pos += verts[k]
pos /= len(indexes)
direction.normalize()

if is_twig and i>2:
twig_leafs.append((pos, direction))

end = pos + direction * 10

point_forces = [ob for ob in bpy.data.objects if ob.type == 'EMPTY' and ob.field.type == 'FORCE']
Expand Down Expand Up @@ -1097,19 +1110,19 @@ def create_tree(position, is_twig=False):
nb = (len(bones) + 1, sortie)
nextremites.append((ni, radius * 0.98, direction, nsi, nb, trunk2, curr_rotation))

elif i == mtree_props.iteration + mtree_props.trunk_length - 1 or random() < mtree_props.break_chance or (verts[indexes[0]] - verts[indexes[3]]).length < mtree_props.branch_min_radius:
elif i == mtree_props.iteration + mtree_props.trunk_length - 1 or random() < mtree_props.break_chance or real_radius < mtree_props.branch_min_radius:
end_verts = [Vector(v) for v in end_cap.verts]
end_faces = [f for f in end_cap.faces]
if is_twig:
twig_leafs.append((pos, direction, curr_rotation))

n = len(verts)
join_branch(verts, faces, indexes, radius, mtree_props.trunk_space, end_verts, direction,
mtree_props.trunk_variation, s_index, seams2)

faces += [add_tuple(f, n) for f in end_faces]
end_seams = [(1, 0), (2, 1), (3, 2), (4, 3), (5, 4), (6, 5), (7, 6), (0, 7)]
seams2 += [add_tuple(f, n) for f in end_seams]
leafs_weight_indexes.append(len(verts)-1)
if real_radius < mtree_props.radius / 4:
leafs_weight_indexes.append(len(verts)-1)

elif i < mtree_props.iteration + mtree_props.trunk_length - 1 and i == mtree_props.trunk_length + 1 or random() < split_probability:
variation = mtree_props.trunk_variation if trunk2 else mtree_props.randomangle
Expand Down Expand Up @@ -1151,8 +1164,7 @@ def create_tree(position, is_twig=False):
length = mtree_props.trunk_space if trunk2 else mtree_props.branch_length
ni, direction, nsi = join_branch(verts, faces, indexes, radius, length, branch_verts, direction,
variation, s_index, seams2)
if is_twig:
twig_leafs.append((pos + direction * length * random(), direction, curr_rotation))

sortie = pos + direction * mtree_props.branch_length

if i <= mtree_props.bones_iterations:
Expand Down Expand Up @@ -1218,7 +1230,7 @@ def create_tree(position, is_twig=False):
# particle setup
if mtree_props.particle:
print("Configuring Particle System...")
create_system(obj, mtree_props.number, mtree_props.display, vgroups["leaf"])
create_system(obj, mtree_props.number, mtree_props.display, vgroups["leaf"], mtree_props.twig_particle, mtree_props.particle_size)

# uv unwrapping
if mtree_props.uv:
Expand Down