788 lines
29 KiB
Python
788 lines
29 KiB
Python
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
# #
|
|
# (c) Alessandro Zomparelli #
|
|
# (2017) #
|
|
# #
|
|
# http://www.co-de-it.com/ #
|
|
# #
|
|
# ############################################################################ #
|
|
|
|
|
|
import bpy, bmesh
|
|
from bpy.types import Operator
|
|
from bpy.props import (
|
|
IntProperty,
|
|
BoolProperty,
|
|
EnumProperty,
|
|
PointerProperty,
|
|
StringProperty,
|
|
FloatProperty
|
|
)
|
|
from bpy.types import (
|
|
Operator,
|
|
Panel,
|
|
PropertyGroup,
|
|
)
|
|
|
|
import numpy as np
|
|
from mathutils import Vector
|
|
from math import pi
|
|
from .utils import (
|
|
find_curves,
|
|
update_curve_from_pydata,
|
|
simple_to_mesh,
|
|
convert_object_to_mesh,
|
|
get_weight_numpy,
|
|
loops_from_bmesh,
|
|
get_mesh_before_subs
|
|
)
|
|
import time
|
|
|
|
|
|
def anim_curve_active(self, context):
|
|
ob = context.object
|
|
props = ob.tissue_to_curve
|
|
try:
|
|
props.object.name
|
|
if not ob.tissue.bool_lock:
|
|
bpy.ops.object.tissue_convert_to_curve_update()
|
|
except: pass
|
|
|
|
|
|
class tissue_to_curve_prop(PropertyGroup):
|
|
object : PointerProperty(
|
|
type=bpy.types.Object,
|
|
name="",
|
|
description="Source object",
|
|
update = anim_curve_active
|
|
)
|
|
bool_smooth : BoolProperty(
|
|
name="Smooth Shading",
|
|
default=True,
|
|
description="Output faces with smooth shading rather than flat shaded",
|
|
update = anim_curve_active
|
|
)
|
|
bool_lock : BoolProperty(
|
|
name="Lock",
|
|
description="Prevent automatic update on settings changes or if other objects have it in the hierarchy.",
|
|
default=False,
|
|
update = anim_curve_active
|
|
)
|
|
bool_dependencies : BoolProperty(
|
|
name="Update Dependencies",
|
|
description="Automatically updates source object as well, when possible",
|
|
default=False,
|
|
update = anim_curve_active
|
|
)
|
|
bool_run : BoolProperty(
|
|
name="Animatable Curve",
|
|
description="Automatically recompute the conversion when the frame is changed.",
|
|
default = False
|
|
)
|
|
use_modifiers : BoolProperty(
|
|
name="Use Modifiers",
|
|
default=True,
|
|
description="Automatically apply Modifiers and Shape Keys",
|
|
update = anim_curve_active
|
|
)
|
|
subdivision_mode : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('CAGE', "Cage", ""),
|
|
('INNER', "Inner", "")
|
|
),
|
|
default='CAGE',
|
|
name="Subdivided Edges",
|
|
update = anim_curve_active
|
|
)
|
|
use_endpoint_u : BoolProperty(
|
|
name="Endpoint U",
|
|
default=True,
|
|
description="Make all open nurbs curve meet the endpoints",
|
|
update = anim_curve_active
|
|
)
|
|
clean_distance : FloatProperty(
|
|
name="Merge Distance", default=0, min=0, soft_max=10,
|
|
description="Merge Distance",
|
|
update = anim_curve_active
|
|
)
|
|
nurbs_order : IntProperty(
|
|
name="Order", default=4, min=2, max=6,
|
|
description="Nurbs order",
|
|
update = anim_curve_active
|
|
)
|
|
system : IntProperty(
|
|
name="System", default=0, min=0,
|
|
description="Particle system index",
|
|
update = anim_curve_active
|
|
)
|
|
bounds_selection : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('BOUNDS', "Boundaries", ""),
|
|
('INNER', "Inner", "")
|
|
),
|
|
default='ALL',
|
|
name="Boundary Selection",
|
|
update = anim_curve_active
|
|
)
|
|
periodic_selection : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('OPEN', "Open", ""),
|
|
('CLOSED', "Closed", "")
|
|
),
|
|
default='ALL',
|
|
name="Periodic Selection",
|
|
update = anim_curve_active
|
|
)
|
|
spline_type : EnumProperty(
|
|
items=(
|
|
('POLY', "Poly", ""),
|
|
('BEZIER', "Bezier", ""),
|
|
('NURBS', "NURBS", "")
|
|
),
|
|
default='POLY',
|
|
name="Spline Type",
|
|
update = anim_curve_active
|
|
)
|
|
mode : EnumProperty(
|
|
items=(
|
|
('LOOPS', "Loops", ""),
|
|
('EDGES', "Edges", ""),
|
|
('PARTICLES', "Particles", "")
|
|
),
|
|
default='LOOPS',
|
|
name="Conversion Mode",
|
|
update = anim_curve_active
|
|
)
|
|
vertex_group : StringProperty(
|
|
name="Radius", default='',
|
|
description="Vertex Group used for variable radius",
|
|
update = anim_curve_active
|
|
)
|
|
invert_vertex_group : BoolProperty(default=False,
|
|
description='Inverte the value of the Vertex Group',
|
|
update = anim_curve_active
|
|
)
|
|
vertex_group_factor : FloatProperty(
|
|
name="Factor",
|
|
default=0,
|
|
min=0,
|
|
max=1,
|
|
description="Depth bevel factor to use for zero vertex group influence",
|
|
update = anim_curve_active
|
|
)
|
|
only_sharp : BoolProperty(
|
|
default=False,
|
|
name="Only Sharp Edges",
|
|
description='Convert only Sharp edges',
|
|
update = anim_curve_active
|
|
)
|
|
pattern_depth : FloatProperty(
|
|
name="Depth",
|
|
default=0.02,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Displacement pattern depth",
|
|
update = anim_curve_active
|
|
)
|
|
pattern_offset : FloatProperty(
|
|
name="Offset",
|
|
default=0,
|
|
soft_min=-1,
|
|
soft_max=1,
|
|
description="Displacement pattern offset",
|
|
update = anim_curve_active
|
|
)
|
|
pattern0 : IntProperty(
|
|
name="Step 0",
|
|
default=0,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Pattern step 0",
|
|
update = anim_curve_active
|
|
)
|
|
pattern1 : IntProperty(
|
|
name="Step 1",
|
|
default=0,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Pattern step 1",
|
|
update = anim_curve_active
|
|
)
|
|
|
|
class tissue_convert_to_curve(Operator):
|
|
bl_idname = "object.tissue_convert_to_curve"
|
|
bl_label = "Tissue Convert to Curve"
|
|
bl_description = "Convert selected mesh to Curve object"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
object : StringProperty(
|
|
name="",
|
|
description="Source object",
|
|
default = ""
|
|
)
|
|
bool_smooth : BoolProperty(
|
|
name="Smooth Shading",
|
|
default=True,
|
|
description="Output faces with smooth shading rather than flat shaded"
|
|
)
|
|
use_modifiers : BoolProperty(
|
|
name="Use Modifiers",
|
|
default=True,
|
|
description="Automatically apply Modifiers and Shape Keys"
|
|
)
|
|
subdivision_mode : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('CAGE', "Cage", ""),
|
|
('INNER', "Inner", "")
|
|
),
|
|
default='CAGE',
|
|
name="Subdivided Edges"
|
|
)
|
|
use_endpoint_u : BoolProperty(
|
|
name="Endpoint U",
|
|
default=True,
|
|
description="Make all open nurbs curve meet the endpoints"
|
|
)
|
|
nurbs_order : IntProperty(
|
|
name="Order", default=4, min=2, max=6,
|
|
description="Nurbs order"
|
|
)
|
|
system : IntProperty(
|
|
name="System", default=0, min=0,
|
|
description="Particle system index"
|
|
)
|
|
clean_distance : FloatProperty(
|
|
name="Merge Distance", default=0, min=0, soft_max=10,
|
|
description="Merge Distance"
|
|
)
|
|
spline_type : EnumProperty(
|
|
items=(
|
|
('POLY', "Poly", ""),
|
|
('BEZIER', "Bezier", ""),
|
|
('NURBS', "NURBS", "")
|
|
),
|
|
default='POLY',
|
|
name="Spline Type"
|
|
)
|
|
bounds_selection : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('BOUNDS', "Boundaries", ""),
|
|
('INNER', "Inner", "")
|
|
),
|
|
default='ALL',
|
|
name="Boundary Selection"
|
|
)
|
|
periodic_selection : EnumProperty(
|
|
items=(
|
|
('ALL', "All", ""),
|
|
('OPEN', "Open", ""),
|
|
('CLOSED', "Closed", "")
|
|
),
|
|
default='ALL',
|
|
name="Periodic Selection"
|
|
)
|
|
mode : EnumProperty(
|
|
items=(
|
|
('LOOPS', "Loops", ""),
|
|
('EDGES', "Edges", ""),
|
|
('PARTICLES', "Particles", "")
|
|
),
|
|
default='LOOPS',
|
|
name="Conversion Mode"
|
|
)
|
|
vertex_group : StringProperty(
|
|
name="Radius", default='',
|
|
description="Vertex Group used for variable radius"
|
|
)
|
|
invert_vertex_group : BoolProperty(default=False,
|
|
description='Inverte the value of the Vertex Group'
|
|
)
|
|
vertex_group_factor : FloatProperty(
|
|
name="Factor",
|
|
default=0,
|
|
min=0,
|
|
max=1,
|
|
description="Depth bevel factor to use for zero vertex group influence"
|
|
)
|
|
only_sharp : BoolProperty(
|
|
default=False,
|
|
name="Only Sharp Edges",
|
|
description='Convert only Sharp edges'
|
|
)
|
|
pattern_depth : FloatProperty(
|
|
name="Depth",
|
|
default=0.02,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Displacement pattern depth"
|
|
)
|
|
pattern_offset : FloatProperty(
|
|
name="Offset",
|
|
default=0,
|
|
soft_min=-1,
|
|
soft_max=1,
|
|
description="Displacement pattern offset"
|
|
)
|
|
pattern0 : IntProperty(
|
|
name="Step 0",
|
|
default=0,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Pattern step 0"
|
|
)
|
|
pattern1 : IntProperty(
|
|
name="Step 1",
|
|
default=0,
|
|
min=0,
|
|
soft_max=10,
|
|
description="Pattern step 1"
|
|
)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
try:
|
|
#bool_tessellated = context.object.tissue_tessellate.generator != None
|
|
ob = context.object
|
|
return ob.type in ('MESH','CURVE','SURFACE','FONT') and ob.mode == 'OBJECT'# and bool_tessellated
|
|
except:
|
|
return False
|
|
|
|
def invoke(self, context, event):
|
|
self.object = context.object.name
|
|
return context.window_manager.invoke_props_dialog(self)
|
|
|
|
def draw(self, context):
|
|
ob = context.object
|
|
ob0 = bpy.data.objects[self.object]
|
|
#props = ob.tissue_to_curve
|
|
layout = self.layout
|
|
col = layout.column(align=True)
|
|
row = col.row(align=True)
|
|
#row.label(text='Object: ' + self.object)
|
|
#row.prop_search(self, "object", context.scene, "objects")
|
|
#row.prop(self, "use_modifiers")#, icon='MODIFIER', text='')
|
|
col.separator()
|
|
col.label(text='Conversion Mode:')
|
|
row = col.row(align=True)
|
|
row.prop(
|
|
self, "mode", text="Conversion Mode", icon='NONE', expand=True,
|
|
slider=False, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
if self.mode == 'PARTICLES':
|
|
col.separator()
|
|
col.prop(self, "system")
|
|
col.separator()
|
|
if self.mode in ('LOOPS', 'EDGES'):
|
|
row = col.row(align=True)
|
|
row.prop(self, "use_modifiers")
|
|
col2 = row.column(align=True)
|
|
if self.use_modifiers:
|
|
col2.prop(self, "subdivision_mode", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col2.enabled = False
|
|
for m in bpy.data.objects[self.object].modifiers:
|
|
if m.type in ('SUBSURF','MULTIRES'): col2.enabled = True
|
|
col.separator()
|
|
row = col.row(align=True)
|
|
row.label(text='Filter Edges:')
|
|
col2 = row.column(align=True)
|
|
col2.prop(self, "bounds_selection", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col2.prop(self, 'only_sharp')
|
|
col.separator()
|
|
if self.mode == 'LOOPS':
|
|
row = col.row(align=True)
|
|
row.label(text='Filter Loops:')
|
|
row.prop(self, "periodic_selection", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col.separator()
|
|
col.label(text='Spline Type:')
|
|
row = col.row(align=True)
|
|
row.prop(
|
|
self, "spline_type", text="Spline Type", icon='NONE', expand=True,
|
|
slider=False, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
if self.spline_type == 'NURBS':
|
|
col.separator()
|
|
col.label(text='Nurbs splines:')
|
|
row = col.row(align=True)
|
|
row.prop(self, "use_endpoint_u")
|
|
row.prop(self, "nurbs_order")
|
|
col.separator()
|
|
col.prop(self, "bool_smooth")
|
|
if ob0.type == 'MESH' and self.mode != 'PARTICLES':
|
|
col.separator()
|
|
col.label(text='Variable Radius:')
|
|
row = col.row(align=True)
|
|
row.prop_search(self, 'vertex_group', ob0, "vertex_groups", text='')
|
|
row.prop(self, "invert_vertex_group", text="", toggle=True, icon='ARROW_LEFTRIGHT')
|
|
row.prop(self, "vertex_group_factor")
|
|
col.separator()
|
|
col.label(text='Clean curves:')
|
|
col.prop(self, "clean_distance")
|
|
col.separator()
|
|
col.label(text='Displacement Pattern:')
|
|
row = col.row(align=True)
|
|
row.prop(self, "pattern0")
|
|
row.prop(self, "pattern1")
|
|
row = col.row(align=True)
|
|
row.prop(self, "pattern_depth")
|
|
row.prop(self, "pattern_offset")
|
|
|
|
def execute(self, context):
|
|
ob = context.active_object
|
|
|
|
crv = bpy.data.curves.new(ob.name + '_Curve', type='CURVE')
|
|
crv.dimensions = '3D'
|
|
new_ob = bpy.data.objects.new(ob.name + '_Curve', crv)
|
|
bpy.context.collection.objects.link(new_ob)
|
|
context.view_layer.objects.active = new_ob
|
|
|
|
new_ob.select_set(True)
|
|
ob.select_set(False)
|
|
new_ob.matrix_world = ob.matrix_world
|
|
|
|
new_ob.tissue.tissue_type = 'TO_CURVE'
|
|
new_ob.tissue.bool_lock = True
|
|
|
|
props = new_ob.tissue_to_curve
|
|
props.object = ob
|
|
props.use_modifiers = self.use_modifiers
|
|
props.subdivision_mode = self.subdivision_mode
|
|
props.clean_distance = self.clean_distance
|
|
props.spline_type = self.spline_type
|
|
props.mode = self.mode
|
|
props.use_endpoint_u = self.use_endpoint_u
|
|
props.nurbs_order = self.nurbs_order
|
|
props.vertex_group = self.vertex_group
|
|
props.vertex_group_factor = self.vertex_group_factor
|
|
props.invert_vertex_group = self.invert_vertex_group
|
|
props.bool_smooth = self.bool_smooth
|
|
props.system = self.system
|
|
props.periodic_selection = self.periodic_selection
|
|
props.bounds_selection = self.bounds_selection
|
|
props.only_sharp = self.only_sharp
|
|
props.pattern0 = self.pattern0
|
|
props.pattern1 = self.pattern1
|
|
props.pattern_depth = self.pattern_depth
|
|
props.pattern_offset = self.pattern_offset
|
|
|
|
new_ob.tissue.bool_lock = False
|
|
|
|
bpy.ops.object.tissue_convert_to_curve_update()
|
|
|
|
return {'FINISHED'}
|
|
|
|
class tissue_convert_to_curve_update(Operator):
|
|
bl_idname = "object.tissue_convert_to_curve_update"
|
|
bl_label = "Tissue Update Curve"
|
|
bl_description = "Update Curve object"
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
try:
|
|
ob = context.object
|
|
bool_curve = ob.tissue_to_curve.object != None
|
|
return ob.type == 'CURVE' and ob.mode == 'OBJECT' and bool_curve
|
|
except:
|
|
return False
|
|
|
|
def execute(self, context):
|
|
start_time = time.time()
|
|
|
|
ob = context.object
|
|
props = ob.tissue_to_curve
|
|
ob0 = props.object
|
|
if props.mode == 'PARTICLES':
|
|
eval_ob = ob0.evaluated_get(context.evaluated_depsgraph_get())
|
|
system_id = min(props.system, len(eval_ob.particle_systems))
|
|
psystem = eval_ob.particle_systems[system_id]
|
|
ob.data.splines.clear()
|
|
particles = psystem.particles
|
|
for id,p in enumerate(particles):
|
|
s = ob.data.splines.new('POLY')
|
|
if psystem.settings.type == 'HAIR':
|
|
n_pts = len(p.hair_keys)
|
|
pts = [0]*3*n_pts
|
|
p.hair_keys.foreach_get('co',pts)
|
|
co = np.array(pts).reshape((-1,3))
|
|
else:
|
|
n_pts = 2**psystem.settings.display_step + 1
|
|
pts = []
|
|
for i in range(n_pts):
|
|
vec = psystem.co_hair(eval_ob, particle_no=id,step=i)
|
|
vec = ob0.matrix_world.inverted() @ vec
|
|
pts.append(vec)
|
|
co = np.array(pts)
|
|
w = np.ones(n_pts).reshape((n_pts,1))
|
|
co = np.concatenate((co,w),axis=1).reshape((n_pts*4))
|
|
s.points.add(n_pts-1)
|
|
s.points.foreach_set('co',co)
|
|
|
|
else:
|
|
_ob0 = ob0
|
|
ob0 = convert_object_to_mesh(ob0, apply_modifiers=props.use_modifiers)
|
|
me = ob0.data
|
|
n_verts = len(me.vertices)
|
|
verts = [0]*n_verts*3
|
|
me.vertices.foreach_get('co',verts)
|
|
verts = np.array(verts).reshape((-1,3))
|
|
|
|
normals = [0]*n_verts*3
|
|
me.vertices.foreach_get('normal',normals)
|
|
normals = np.array(normals).reshape((-1,3))
|
|
#tilt = np.degrees(np.arcsin(normals[:,2]))
|
|
#tilt = np.arccos(normals[:,2])/2
|
|
|
|
verts = np.array(verts).reshape((-1,3))
|
|
if props.mode in ('LOOPS','EDGES'):
|
|
bm = bmesh.new()
|
|
bm.from_mesh(me)
|
|
bm.verts.ensure_lookup_table()
|
|
bm.edges.ensure_lookup_table()
|
|
bm.faces.ensure_lookup_table()
|
|
todo_edges = list(bm.edges)
|
|
if props.use_modifiers and props.subdivision_mode != 'ALL':
|
|
me0, subs = get_mesh_before_subs(_ob0)
|
|
n_edges0 = len(me0.edges)
|
|
bpy.data.meshes.remove(me0)
|
|
if props.subdivision_mode == 'CAGE':
|
|
todo_edges = todo_edges[:n_edges0*(2**subs)]
|
|
elif props.subdivision_mode == 'INNER':
|
|
todo_edges = todo_edges[n_edges0*(2**subs):]
|
|
|
|
if props.only_sharp:
|
|
_todo_edges = []
|
|
sharp_verts = []
|
|
for e in todo_edges:
|
|
edge = me.edges[e.index]
|
|
if edge.use_edge_sharp:
|
|
_todo_edges.append(e)
|
|
sharp_verts.append(edge.vertices[0])
|
|
sharp_verts.append(edge.vertices[1])
|
|
todo_edges = _todo_edges
|
|
|
|
if props.bounds_selection == 'BOUNDS': todo_edges = [e for e in todo_edges if len(e.link_faces)<2]
|
|
elif props.bounds_selection == 'INNER': todo_edges = [e for e in todo_edges if len(e.link_faces)>1]
|
|
|
|
if props.mode == 'EDGES':
|
|
ordered_points = [[e.verts[0].index, e.verts[1].index] for e in todo_edges]
|
|
elif props.mode == 'LOOPS':
|
|
vert_loops, edge_loops = loops_from_bmesh(todo_edges)
|
|
if props.only_sharp:
|
|
ordered_points = []
|
|
for loop in vert_loops:
|
|
loop_points = []
|
|
for v in loop:
|
|
if v.index in sharp_verts:
|
|
loop_points.append(v.index)
|
|
else:
|
|
if len(loop_points)>1:
|
|
ordered_points.append(loop_points)
|
|
loop_points = []
|
|
if len(loop_points)>1:
|
|
ordered_points.append(loop_points)
|
|
#ordered_points = [[v.index for v in loop if v.index in sharp_verts] for loop in vert_loops]
|
|
else:
|
|
ordered_points = [[v.index for v in loop] for loop in vert_loops]
|
|
if props.periodic_selection == 'CLOSED':
|
|
ordered_points = [points for points in ordered_points if points[0] == points[-1]]
|
|
elif props.periodic_selection == 'OPEN':
|
|
ordered_points = [points for points in ordered_points if points[0] != points[-1]]
|
|
else:
|
|
try:
|
|
ordered_points = find_curves(edges, n_verts)
|
|
except:
|
|
bpy.data.objects.remove(ob0)
|
|
return {'CANCELLED'}
|
|
|
|
try:
|
|
weight = get_weight_numpy(ob0.vertex_groups[props.vertex_group], n_verts)
|
|
if props.invert_vertex_group: weight = 1-weight
|
|
fact = props.vertex_group_factor
|
|
if fact > 0:
|
|
weight = weight*(1-fact) + fact
|
|
except:
|
|
weight = None
|
|
|
|
# Set curves Tilt
|
|
'''
|
|
tilt = []
|
|
for points in ordered_points:
|
|
if points[0] == points[-1]: # Closed curve
|
|
pts0 = [points[-1]] + points[:-1] # i-1
|
|
pts1 = points[:] # i
|
|
pts2 = points[1:] + [points[0]] # 1+1
|
|
else: # Open curve
|
|
pts0 = [points[0]] + points[:-1] # i-1
|
|
pts1 = points[:] # i
|
|
pts2 = points[1:] + [points[-1]] # i+1
|
|
curve_tilt = []
|
|
for i0, i1, i2 in zip(pts0, pts1, pts2):
|
|
pt0 = Vector(verts[i0])
|
|
pt1 = Vector(verts[i1])
|
|
pt2 = Vector(verts[i2])
|
|
tan1 = (pt1-pt0).normalized()
|
|
tan2 = (pt2-pt1).normalized()
|
|
vec_tan = -(tan1 + tan2).normalized()
|
|
vec2 = vec_tan.cross(Vector((0,0,1)))
|
|
vec_z = vec_tan.cross(vec2)
|
|
nor = normals[i1]
|
|
if vec_z.length == 0:
|
|
vec_z = Vector(nor)
|
|
ang = vec_z.angle(nor)
|
|
if nor[2] < 0: ang = 2*pi-ang
|
|
#if vec_tan[0] > vec_tan[1] and nor[0]>0: ang = -ang
|
|
#if vec_tan[0] > vec_tan[2] and nor[0]>0: ang = -ang
|
|
#if vec_tan[0] < vec_tan[1] and nor[1]>0: ang = -ang
|
|
#if nor[0]*nor[1]*nor[2] < 0: ang = -ang
|
|
if nor[2] == 0: ang = -5*pi/4
|
|
#ang = max(ang, np.arccos(nor[2]))
|
|
curve_tilt.append(ang)
|
|
#curve_tilt.append(np.arccos(nor[2]))
|
|
tilt.append(curve_tilt)
|
|
'''
|
|
depth = props.pattern_depth
|
|
offset = props.pattern_offset
|
|
pattern = [props.pattern0,props.pattern1]
|
|
update_curve_from_pydata(ob.data, verts, normals, weight, ordered_points, merge_distance=props.clean_distance, pattern=pattern, depth=depth, offset=offset)
|
|
|
|
|
|
bpy.data.objects.remove(ob0)
|
|
for s in ob.data.splines:
|
|
s.type = props.spline_type
|
|
if s.type == 'NURBS':
|
|
s.use_endpoint_u = props.use_endpoint_u
|
|
s.order_u = props.nurbs_order
|
|
ob.data.splines.update()
|
|
if not props.bool_smooth: bpy.ops.object.shade_flat()
|
|
|
|
end_time = time.time()
|
|
print('Tissue: object "{}" converted to Curve in {:.4f} sec'.format(ob.name, end_time-start_time))
|
|
|
|
return {'FINISHED'}
|
|
|
|
|
|
class TISSUE_PT_convert_to_curve(Panel):
|
|
bl_space_type = 'PROPERTIES'
|
|
bl_region_type = 'WINDOW'
|
|
bl_context = "data"
|
|
bl_label = "Tissue Convert to Curve"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
try:
|
|
#bool_curve = context.object.tissue_to_curve.object != None
|
|
ob = context.object
|
|
return ob.type == 'CURVE' and ob.tissue.tissue_type == 'TO_CURVE'
|
|
except:
|
|
return False
|
|
|
|
def draw(self, context):
|
|
ob = context.object
|
|
props = ob.tissue_to_curve
|
|
|
|
layout = self.layout
|
|
#layout.use_property_split = True
|
|
#layout.use_property_decorate = False
|
|
col = layout.column(align=True)
|
|
row = col.row(align=True)
|
|
#col.operator("object.tissue_convert_to_curve_update", icon='FILE_REFRESH', text='Refresh')
|
|
row.operator("object.tissue_update_tessellate_deps", icon='FILE_REFRESH', text='Refresh') ####
|
|
lock_icon = 'LOCKED' if ob.tissue.bool_lock else 'UNLOCKED'
|
|
#lock_icon = 'PINNED' if props.bool_lock else 'UNPINNED'
|
|
deps_icon = 'LINKED' if ob.tissue.bool_dependencies else 'UNLINKED'
|
|
row.prop(ob.tissue, "bool_dependencies", text="", icon=deps_icon)
|
|
row.prop(ob.tissue, "bool_lock", text="", icon=lock_icon)
|
|
col2 = row.column(align=True)
|
|
col2.prop(ob.tissue, "bool_run", text="",icon='TIME')
|
|
col2.enabled = not ob.tissue.bool_lock
|
|
|
|
col.separator()
|
|
row = col.row(align=True)
|
|
row.prop_search(props, "object", context.scene, "objects")
|
|
row.prop(props, "use_modifiers", icon='MODIFIER', text='')
|
|
col.separator()
|
|
col.label(text='Conversion Mode:')
|
|
row = col.row(align=True)
|
|
row.prop(
|
|
props, "mode", icon='NONE', expand=True,
|
|
slider=False, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
if props.mode == 'PARTICLES':
|
|
col.separator()
|
|
col.prop(props, "system")
|
|
col.separator()
|
|
|
|
if props.mode in ('LOOPS', 'EDGES'):
|
|
row = col.row(align=True)
|
|
row.prop(props, "use_modifiers")
|
|
col2 = row.column(align=True)
|
|
if props.use_modifiers:
|
|
col2.prop(props, "subdivision_mode", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col2.enabled = False
|
|
for m in props.object.modifiers:
|
|
if m.type in ('SUBSURF','MULTIRES'): col2.enabled = True
|
|
col.separator()
|
|
row = col.row(align=True)
|
|
row.label(text='Filter Edges:')
|
|
col2 = row.column(align=True)
|
|
col2.prop(props, "bounds_selection", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col2.prop(props, 'only_sharp')
|
|
col.separator()
|
|
if props.mode == 'LOOPS':
|
|
row = col.row(align=True)
|
|
row.label(text='Filter Loops:')
|
|
row.prop(props, "periodic_selection", text='', icon='NONE', expand=False,
|
|
slider=True, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
col.separator()
|
|
|
|
col.label(text='Spline Type:')
|
|
row = col.row(align=True)
|
|
row.prop(
|
|
props, "spline_type", text="Spline Type", icon='NONE', expand=True,
|
|
slider=False, toggle=False, icon_only=False, event=False,
|
|
full_event=False, emboss=True, index=-1)
|
|
if props.spline_type == 'NURBS':
|
|
col.separator()
|
|
col.label(text='Nurbs Splines:')
|
|
row = col.row(align=True)
|
|
row.prop(props, "use_endpoint_u")
|
|
row.prop(props, "nurbs_order")
|
|
col.separator()
|
|
col.prop(props, "bool_smooth")
|
|
if props.object.type == 'MESH':
|
|
col.separator()
|
|
col.label(text='Variable Radius:')
|
|
row = col.row(align=True)
|
|
row.prop_search(props, 'vertex_group', props.object, "vertex_groups", text='')
|
|
row.prop(props, "invert_vertex_group", text="", toggle=True, icon='ARROW_LEFTRIGHT')
|
|
row.prop(props, "vertex_group_factor")
|
|
col.separator()
|
|
col.label(text='Clean Curves:')
|
|
col.prop(props, "clean_distance")
|
|
col.separator()
|
|
col.label(text='Displacement Pattern:')
|
|
row = col.row(align=True)
|
|
row.prop(props, "pattern0")
|
|
row.prop(props, "pattern1")
|
|
row = col.row(align=True)
|
|
row.prop(props, "pattern_depth")
|
|
row.prop(props, "pattern_offset")
|