2020-07-12 21:04:38 +08:00
import bpy , bmesh
2020-10-07 15:20:51 +08:00
import mathutils
2020-10-06 23:57:21 +08:00
import bpy.types
from . import utils , preferences
2020-07-12 21:04:38 +08:00
2020-09-02 23:04:21 +08:00
class BALLANCE_OT_rail_uv ( bpy . types . Operator ):
2020-07-20 10:13:18 +08:00
"""Create a UV for rail"""
bl_idname = "ballance.rail_uv"
bl_label = "Create Rail UV"
bl_options = { 'UNDO' }
2020-10-06 23:57:21 +08:00
uv_type : bpy . props . EnumProperty (
name = "Type" ,
description = "Define how to create UV" ,
items = (
( "POINT" , "Point" , "All UV will be created in a specific point" ),
( "UNIFORM" , "Uniform" , "All UV will be created within 1x1" ),
( "SCALE" , "Scale" , "Give a scale number to scale UV" )
),
)
2020-10-19 22:12:27 +08:00
projection_axis : bpy . props . EnumProperty (
name = "Projection axis" ,
description = "Projection axis" ,
items = (
( "X" , "X axis" , "X axis" ),
( "Y" , "Y axis" , "Y axis" ),
( "Z" , "Z axis" , "Z axis" )
),
)
2020-10-06 23:57:21 +08:00
uv_scale : bpy . props . FloatProperty (
name = "Scale" ,
description = "The scale of UV" ,
min = 0.0 ,
default = 1.0 ,
)
2020-07-20 10:13:18 +08:00
@classmethod
def poll ( self , context ):
return check_rail_target ()
2020-10-06 23:57:21 +08:00
def invoke ( self , context , event ):
wm = context . window_manager
return wm . invoke_props_dialog ( self )
2020-07-20 10:13:18 +08:00
def execute ( self , context ):
2020-10-07 15:20:51 +08:00
if context . scene . BallanceBlenderPluginProperty . material_picker == None :
utils . ShowMessageBox (( "No specific material" , ), "Lost parameter" , 'ERROR' )
else :
2020-10-19 22:12:27 +08:00
create_rail_uv ( self . uv_type , context . scene . BallanceBlenderPluginProperty . material_picker , self . uv_scale , self . projection_axis )
2020-07-20 10:13:18 +08:00
return { 'FINISHED' }
2020-10-06 23:57:21 +08:00
def draw ( self , context ):
layout = self . layout
layout . prop ( self , "uv_type" )
layout . prop ( context . scene . BallanceBlenderPluginProperty , "material_picker" )
2020-10-19 22:12:27 +08:00
if self . uv_type != 'POINT' :
layout . prop ( self , "projection_axis" )
2020-10-06 23:57:21 +08:00
if self . uv_type == 'SCALE' :
layout . prop ( self , "uv_scale" )
2020-07-20 10:13:18 +08:00
# ====================== method
def check_rail_target ():
2020-07-12 21:04:38 +08:00
for obj in bpy . context . selected_objects :
if obj . type != 'MESH' :
continue
2020-07-20 10:13:18 +08:00
if obj . mode != 'OBJECT' :
continue
return True
return False
2020-10-07 20:38:01 +08:00
def get_distance ( iterator ):
is_first_min = True
is_first_max = True
max_value = 0.0
min_value = 0.0
for item in iterator :
if is_first_max :
is_first_max = False
max_value = item
else :
if item > max_value :
max_value = item
if is_first_min :
is_first_min = False
min_value = item
else :
if item < min_value :
min_value = item
return max_value - min_value
2020-10-19 22:12:27 +08:00
def create_rail_uv ( rail_type , material_pointer , scale_size , projection_axis ):
2020-10-07 15:20:51 +08:00
objList = []
2020-07-20 10:13:18 +08:00
ignoredObj = []
for obj in bpy . context . selected_objects :
if obj . type != 'MESH' :
ignoredObj . append ( obj . name )
continue
if obj . mode != 'OBJECT' :
ignoredObj . append ( obj . name )
continue
2020-08-31 21:56:08 +08:00
if obj . data . uv_layers . active is None :
2020-09-02 23:04:21 +08:00
# create a empty uv for it.
obj . data . uv_layers . new ( do_init = False )
2020-07-12 21:04:38 +08:00
2020-10-07 15:20:51 +08:00
objList . append ( obj )
2020-07-12 21:04:38 +08:00
2020-10-07 15:20:51 +08:00
for obj in objList :
mesh = obj . data
# clean it material and set rail first
obj . data . materials . clear ()
obj . data . materials . append ( material_pointer )
2020-10-07 20:38:01 +08:00
# copy mesh vec for scale or uniform mode
vecList = mesh . vertices [:]
2020-10-07 15:20:51 +08:00
real_scale = 1.0
if rail_type == 'SCALE' :
real_scale = scale_size
elif rail_type == 'UNIFORM' :
# calc proper scale
2020-10-19 22:12:27 +08:00
if projection_axis == 'X' :
maxLength = max (
get_distance ( vec . co [ 1 ] for vec in vecList ),
get_distance ( vec . co [ 2 ] for vec in vecList )
)
elif projection_axis == 'Y' :
maxLength = max (
get_distance ( vec . co [ 0 ] for vec in vecList ),
get_distance ( vec . co [ 2 ] for vec in vecList )
)
elif projection_axis == 'Z' :
maxLength = max (
get_distance ( vec . co [ 0 ] for vec in vecList ),
get_distance ( vec . co [ 1 ] for vec in vecList )
)
2020-10-07 15:20:51 +08:00
real_scale = 1.0 / maxLength
2020-07-12 21:04:38 +08:00
uv_layer = mesh . uv_layers . active . data
for poly in mesh . polygons :
for loop_index in range ( poly . loop_start , poly . loop_start + poly . loop_total ):
2020-10-07 15:20:51 +08:00
# get correspond vec index
index = mesh . loops [ loop_index ] . vertex_index
if rail_type == 'POINT' :
# set to 1 point
uv_layer [ loop_index ] . uv [ 0 ] = 0
uv_layer [ loop_index ] . uv [ 1 ] = 1
else :
# following xy -> uv scale
2020-10-19 22:12:27 +08:00
#
# use Z axis: X->U Y->V
# use X axis: Y->U Z->V
# use Y axis: X->U Z->V
if projection_axis == 'X' :
uv_layer [ loop_index ] . uv [ 0 ] = vecList [ index ] . co [ 1 ] * real_scale
uv_layer [ loop_index ] . uv [ 1 ] = vecList [ index ] . co [ 2 ] * real_scale
elif projection_axis == 'Y' :
uv_layer [ loop_index ] . uv [ 0 ] = vecList [ index ] . co [ 0 ] * real_scale
uv_layer [ loop_index ] . uv [ 1 ] = vecList [ index ] . co [ 2 ] * real_scale
elif projection_axis == 'Z' :
uv_layer [ loop_index ] . uv [ 0 ] = vecList [ index ] . co [ 0 ] * real_scale
uv_layer [ loop_index ] . uv [ 1 ] = vecList [ index ] . co [ 1 ] * real_scale
2020-07-12 21:04:38 +08:00
2020-07-20 10:13:18 +08:00
if len ( ignoredObj ) != 0 :
2020-10-07 15:20:51 +08:00
utils . ShowMessageBox (( "Following objects are not processed due to they are not suit for this function now: " , ) + tuple ( ignoredObj ), "Execution result" , 'INFO' )