CM3D2 Converter.misc_MESH_MT_attribute_context_menu

  1# 「プロパティ」エリア → 「メッシュデータ」タブ → 「頂点グループ」パネル → ▼ボタン
  2import time
  3import bpy
  4import bmesh
  5import mathutils
  6from . import common
  7from . import compat
  8from .translations.pgettext_functions import *
  9
 10
 11# メニュー等に項目追加
 12def menu_func(self, context):
 13    icon_id = common.kiss_icon()
 14    self.layout.separator()
 15    self.layout.operator('geometry.attribute_from_custom_normals', icon_value=icon_id)
 16    if (self.__class__.__name__ == 'MESH_MT_attribute_context_menu'):
 17        self.layout.operator('geometry.attribute_convert_normals', icon_value=icon_id)
 18    #self.layout.operator('geometry.attribute_from_custom_normals', icon_value=compat.icon('NORMALS_VERTEX_FACE'))
 19
 20
 21@compat.BlRegister()
 22class CNV_OT_attribute_from_custom_normals(bpy.types.Operator):
 23    bl_idname = 'geometry.attribute_from_custom_normals'
 24    bl_label = "From Custom Normals"
 25    bl_description = "Creates a new attribute from the custom split normals"
 26    bl_options = {'REGISTER', 'UNDO'}
 27
 28    items = [
 29        ('FLOAT_VECTOR', "Vector"     , "3D vector with floating point values"     , 'NONE', 1),
 30        ('FLOAT_COLOR' , "Float Color", "RGBA color with floating point precisions", 'NONE', 2),
 31        ('BYTE_COLOR'  , "Byte Color" , "RGBA color with 8-bit precision"          , 'NONE', 3),
 32    ]
 33
 34    data_type = bpy.props.EnumProperty(items=items, name="Data Type", default='FLOAT_COLOR')
 35
 36    @classmethod
 37    def poll(cls, context):
 38        obs = context.selected_objects
 39        active_ob = context.active_object
 40        if active_ob.type != 'MESH':
 41            return False
 42        return True
 43
 44    def invoke(self, context, event):
 45        return context.window_manager.invoke_props_dialog(self)
 46
 47    def draw(self, context):
 48        self.layout.prop(self, 'data_type')
 49        pass
 50
 51    def execute(self, context):
 52        ob = context.active_object
 53        me = ob.data
 54
 55        pre_mode = ob.mode
 56        bpy.ops.object.mode_set(mode='OBJECT')
 57
 58        me.calc_normals_split()
 59
 60        if (compat.IS_LEGACY or bpy.app.version < (2, 91)):
 61            return {'ERROR'}
 62        else:
 63            attribute = me.attributes.new('custom_normals', self.data_type, 'CORNER')
 64            attribute_data = attribute.data
 65
 66        for key in attribute.data.keys():
 67            print(repr(key))
 68
 69        for loop_index, loop in enumerate(me.loops):
 70            if isinstance(attribute, bpy.types.FloatVectorAttribute):
 71                attribute.data[loop_index].vector = loop.normal
 72            else:
 73                attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
 74                    loop.normal[0] * 0.5 + 0.5,
 75                    loop.normal[1] * 0.5 + 0.5,
 76                    loop.normal[2] * 0.5 + 0.5,
 77                    1,
 78                )
 79
 80        
 81        
 82        bpy.ops.object.mode_set(mode=pre_mode)
 83        return {'FINISHED'}
 84
 85@compat.BlRegister()
 86class CNV_OT_attribute_convert_normals(bpy.types.Operator):
 87    bl_idname = 'geometry.attribute_convert_normals'
 88    bl_label = "Convert Normals"
 89    bl_description = "Converts the data type of the normals attribute"
 90    bl_options = {'REGISTER', 'UNDO'}
 91
 92    items = [
 93        ('FLOAT_VECTOR', "Vector"     , "3D vector with floating point values"     , 'NONE', 1),
 94        ('FLOAT_COLOR' , "Float Color", "RGBA color with floating point precisions", 'NONE', 2),
 95        ('BYTE_COLOR'  , "Byte Color" , "RGBA color with 8-bit precision"          , 'NONE', 3),
 96    ]
 97
 98    data_type = bpy.props.EnumProperty(items=items, name="Data Type", default='FLOAT_COLOR')
 99
100    @classmethod
101    def poll(cls, context):
102        obs = context.selected_objects
103        active_ob = context.active_object
104        if active_ob.type != 'MESH':
105            return False
106        return True
107
108    def invoke(self, context, event):
109        me = context.active_object.data
110
111        if isinstance(me.attributes.active, bpy.types.FloatVectorAttribute):
112            self.data_type = 'FLOAT_COLOR'
113        else:
114            self.data_type = 'FLOAT_VECTOR'
115
116        return context.window_manager.invoke_props_dialog(self)
117
118    def draw(self, context):
119        self.layout.prop(self, 'data_type')
120        pass
121
122    def execute(self, context):
123        ob = context.active_object
124        me = ob.data
125
126        pre_mode = ob.mode
127        bpy.ops.object.mode_set(mode='OBJECT')
128
129        if (compat.IS_LEGACY or bpy.app.version < (3,1)):
130            return {'ERROR'}
131
132        old_attribute = me.attributes.active
133        name = old_attribute.name
134
135        old_data = [None] * len(me.loops)
136
137        # store old data
138        for loop_index, loop in enumerate(me.loops):
139            if isinstance(old_attribute, bpy.types.FloatVectorAttribute):
140                old_data[loop_index] = old_attribute.data[loop_index].vector
141            else:
142                color = old_attribute.data[loop_index].color
143                old_data[loop_index] = ( # convert from range (0, 1) to range (-1, 1)
144                    (color[0] - 0.5) / 0.5,
145                    (color[1] - 0.5) / 0.5,
146                    (color[2] - 0.5) / 0.5,
147                )
148        
149        # create new attribute
150        new_attribute = me.attributes.new(f'temp_{name}', self.data_type, 'CORNER')
151
152        # set new data
153        for loop_index, loop in enumerate(me.loops):
154            old_loop_data = old_data[loop_index]
155            if isinstance(new_attribute, bpy.types.FloatVectorAttribute):
156                new_attribute.data[loop_index].vector = old_loop_data
157            else:
158                new_attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
159                    old_loop_data[0] * 0.5 + 0.5,
160                    old_loop_data[1] * 0.5 + 0.5,
161                    old_loop_data[2] * 0.5 + 0.5,
162                    1,
163                )
164        
165        # delete old attribute
166        me.attributes.remove(me.attributes[name])
167
168        # restore state
169        new_attribute.name = name
170        bpy.ops.object.mode_set(mode=pre_mode)
171        return {'FINISHED'}
@compat.BlRegister()
class CNV_OT_attribute_from_custom_normals(bpy_types.Operator):
22@compat.BlRegister()
23class CNV_OT_attribute_from_custom_normals(bpy.types.Operator):
24    bl_idname = 'geometry.attribute_from_custom_normals'
25    bl_label = "From Custom Normals"
26    bl_description = "Creates a new attribute from the custom split normals"
27    bl_options = {'REGISTER', 'UNDO'}
28
29    items = [
30        ('FLOAT_VECTOR', "Vector"     , "3D vector with floating point values"     , 'NONE', 1),
31        ('FLOAT_COLOR' , "Float Color", "RGBA color with floating point precisions", 'NONE', 2),
32        ('BYTE_COLOR'  , "Byte Color" , "RGBA color with 8-bit precision"          , 'NONE', 3),
33    ]
34
35    data_type = bpy.props.EnumProperty(items=items, name="Data Type", default='FLOAT_COLOR')
36
37    @classmethod
38    def poll(cls, context):
39        obs = context.selected_objects
40        active_ob = context.active_object
41        if active_ob.type != 'MESH':
42            return False
43        return True
44
45    def invoke(self, context, event):
46        return context.window_manager.invoke_props_dialog(self)
47
48    def draw(self, context):
49        self.layout.prop(self, 'data_type')
50        pass
51
52    def execute(self, context):
53        ob = context.active_object
54        me = ob.data
55
56        pre_mode = ob.mode
57        bpy.ops.object.mode_set(mode='OBJECT')
58
59        me.calc_normals_split()
60
61        if (compat.IS_LEGACY or bpy.app.version < (2, 91)):
62            return {'ERROR'}
63        else:
64            attribute = me.attributes.new('custom_normals', self.data_type, 'CORNER')
65            attribute_data = attribute.data
66
67        for key in attribute.data.keys():
68            print(repr(key))
69
70        for loop_index, loop in enumerate(me.loops):
71            if isinstance(attribute, bpy.types.FloatVectorAttribute):
72                attribute.data[loop_index].vector = loop.normal
73            else:
74                attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
75                    loop.normal[0] * 0.5 + 0.5,
76                    loop.normal[1] * 0.5 + 0.5,
77                    loop.normal[2] * 0.5 + 0.5,
78                    1,
79                )
80
81        
82        
83        bpy.ops.object.mode_set(mode=pre_mode)
84        return {'FINISHED'}
bl_idname = 'geometry.attribute_from_custom_normals'
bl_label = 'From Custom Normals'
bl_description = 'Creates a new attribute from the custom split normals'
bl_options = {'REGISTER', 'UNDO'}
items = [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)]
data_type: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)], 'name': 'Data Type', 'default': 'FLOAT_COLOR', 'attr': 'data_type'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)], 'name': 'Data Type', 'default': 'FLOAT_COLOR', 'attr': 'data_type'}>
@classmethod
def poll(cls, context):
37    @classmethod
38    def poll(cls, context):
39        obs = context.selected_objects
40        active_ob = context.active_object
41        if active_ob.type != 'MESH':
42            return False
43        return True
def invoke(self, context, event):
45    def invoke(self, context, event):
46        return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
48    def draw(self, context):
49        self.layout.prop(self, 'data_type')
50        pass
def execute(self, context):
52    def execute(self, context):
53        ob = context.active_object
54        me = ob.data
55
56        pre_mode = ob.mode
57        bpy.ops.object.mode_set(mode='OBJECT')
58
59        me.calc_normals_split()
60
61        if (compat.IS_LEGACY or bpy.app.version < (2, 91)):
62            return {'ERROR'}
63        else:
64            attribute = me.attributes.new('custom_normals', self.data_type, 'CORNER')
65            attribute_data = attribute.data
66
67        for key in attribute.data.keys():
68            print(repr(key))
69
70        for loop_index, loop in enumerate(me.loops):
71            if isinstance(attribute, bpy.types.FloatVectorAttribute):
72                attribute.data[loop_index].vector = loop.normal
73            else:
74                attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
75                    loop.normal[0] * 0.5 + 0.5,
76                    loop.normal[1] * 0.5 + 0.5,
77                    loop.normal[2] * 0.5 + 0.5,
78                    1,
79                )
80
81        
82        
83        bpy.ops.object.mode_set(mode=pre_mode)
84        return {'FINISHED'}
bl_rna = <bpy_struct, Struct("GEOMETRY_OT_attribute_from_custom_normals")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
get
pop
as_pointer
keyframe_insert
keyframe_delete
driver_add
driver_remove
is_property_set
property_unset
is_property_hidden
is_property_readonly
is_property_overridable_library
property_overridable_library_set
path_resolve
path_from_id
type_recast
bl_rna_get_subclass_py
bl_rna_get_subclass
id_properties_ensure
id_properties_clear
id_properties_ui
id_data
@compat.BlRegister()
class CNV_OT_attribute_convert_normals(bpy_types.Operator):
 86@compat.BlRegister()
 87class CNV_OT_attribute_convert_normals(bpy.types.Operator):
 88    bl_idname = 'geometry.attribute_convert_normals'
 89    bl_label = "Convert Normals"
 90    bl_description = "Converts the data type of the normals attribute"
 91    bl_options = {'REGISTER', 'UNDO'}
 92
 93    items = [
 94        ('FLOAT_VECTOR', "Vector"     , "3D vector with floating point values"     , 'NONE', 1),
 95        ('FLOAT_COLOR' , "Float Color", "RGBA color with floating point precisions", 'NONE', 2),
 96        ('BYTE_COLOR'  , "Byte Color" , "RGBA color with 8-bit precision"          , 'NONE', 3),
 97    ]
 98
 99    data_type = bpy.props.EnumProperty(items=items, name="Data Type", default='FLOAT_COLOR')
100
101    @classmethod
102    def poll(cls, context):
103        obs = context.selected_objects
104        active_ob = context.active_object
105        if active_ob.type != 'MESH':
106            return False
107        return True
108
109    def invoke(self, context, event):
110        me = context.active_object.data
111
112        if isinstance(me.attributes.active, bpy.types.FloatVectorAttribute):
113            self.data_type = 'FLOAT_COLOR'
114        else:
115            self.data_type = 'FLOAT_VECTOR'
116
117        return context.window_manager.invoke_props_dialog(self)
118
119    def draw(self, context):
120        self.layout.prop(self, 'data_type')
121        pass
122
123    def execute(self, context):
124        ob = context.active_object
125        me = ob.data
126
127        pre_mode = ob.mode
128        bpy.ops.object.mode_set(mode='OBJECT')
129
130        if (compat.IS_LEGACY or bpy.app.version < (3,1)):
131            return {'ERROR'}
132
133        old_attribute = me.attributes.active
134        name = old_attribute.name
135
136        old_data = [None] * len(me.loops)
137
138        # store old data
139        for loop_index, loop in enumerate(me.loops):
140            if isinstance(old_attribute, bpy.types.FloatVectorAttribute):
141                old_data[loop_index] = old_attribute.data[loop_index].vector
142            else:
143                color = old_attribute.data[loop_index].color
144                old_data[loop_index] = ( # convert from range (0, 1) to range (-1, 1)
145                    (color[0] - 0.5) / 0.5,
146                    (color[1] - 0.5) / 0.5,
147                    (color[2] - 0.5) / 0.5,
148                )
149        
150        # create new attribute
151        new_attribute = me.attributes.new(f'temp_{name}', self.data_type, 'CORNER')
152
153        # set new data
154        for loop_index, loop in enumerate(me.loops):
155            old_loop_data = old_data[loop_index]
156            if isinstance(new_attribute, bpy.types.FloatVectorAttribute):
157                new_attribute.data[loop_index].vector = old_loop_data
158            else:
159                new_attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
160                    old_loop_data[0] * 0.5 + 0.5,
161                    old_loop_data[1] * 0.5 + 0.5,
162                    old_loop_data[2] * 0.5 + 0.5,
163                    1,
164                )
165        
166        # delete old attribute
167        me.attributes.remove(me.attributes[name])
168
169        # restore state
170        new_attribute.name = name
171        bpy.ops.object.mode_set(mode=pre_mode)
172        return {'FINISHED'}
bl_idname = 'geometry.attribute_convert_normals'
bl_label = 'Convert Normals'
bl_description = 'Converts the data type of the normals attribute'
bl_options = {'REGISTER', 'UNDO'}
items = [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)]
data_type: <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)], 'name': 'Data Type', 'default': 'FLOAT_COLOR', 'attr': 'data_type'}> = <_PropertyDeferred, <built-in function EnumProperty>, {'items': [('FLOAT_VECTOR', 'Vector', '3D vector with floating point values', 'NONE', 1), ('FLOAT_COLOR', 'Float Color', 'RGBA color with floating point precisions', 'NONE', 2), ('BYTE_COLOR', 'Byte Color', 'RGBA color with 8-bit precision', 'NONE', 3)], 'name': 'Data Type', 'default': 'FLOAT_COLOR', 'attr': 'data_type'}>
@classmethod
def poll(cls, context):
101    @classmethod
102    def poll(cls, context):
103        obs = context.selected_objects
104        active_ob = context.active_object
105        if active_ob.type != 'MESH':
106            return False
107        return True
def invoke(self, context, event):
109    def invoke(self, context, event):
110        me = context.active_object.data
111
112        if isinstance(me.attributes.active, bpy.types.FloatVectorAttribute):
113            self.data_type = 'FLOAT_COLOR'
114        else:
115            self.data_type = 'FLOAT_VECTOR'
116
117        return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
119    def draw(self, context):
120        self.layout.prop(self, 'data_type')
121        pass
def execute(self, context):
123    def execute(self, context):
124        ob = context.active_object
125        me = ob.data
126
127        pre_mode = ob.mode
128        bpy.ops.object.mode_set(mode='OBJECT')
129
130        if (compat.IS_LEGACY or bpy.app.version < (3,1)):
131            return {'ERROR'}
132
133        old_attribute = me.attributes.active
134        name = old_attribute.name
135
136        old_data = [None] * len(me.loops)
137
138        # store old data
139        for loop_index, loop in enumerate(me.loops):
140            if isinstance(old_attribute, bpy.types.FloatVectorAttribute):
141                old_data[loop_index] = old_attribute.data[loop_index].vector
142            else:
143                color = old_attribute.data[loop_index].color
144                old_data[loop_index] = ( # convert from range (0, 1) to range (-1, 1)
145                    (color[0] - 0.5) / 0.5,
146                    (color[1] - 0.5) / 0.5,
147                    (color[2] - 0.5) / 0.5,
148                )
149        
150        # create new attribute
151        new_attribute = me.attributes.new(f'temp_{name}', self.data_type, 'CORNER')
152
153        # set new data
154        for loop_index, loop in enumerate(me.loops):
155            old_loop_data = old_data[loop_index]
156            if isinstance(new_attribute, bpy.types.FloatVectorAttribute):
157                new_attribute.data[loop_index].vector = old_loop_data
158            else:
159                new_attribute.data[loop_index].color = ( # convert from range(-1, 1) to range(0, 1)
160                    old_loop_data[0] * 0.5 + 0.5,
161                    old_loop_data[1] * 0.5 + 0.5,
162                    old_loop_data[2] * 0.5 + 0.5,
163                    1,
164                )
165        
166        # delete old attribute
167        me.attributes.remove(me.attributes[name])
168
169        # restore state
170        new_attribute.name = name
171        bpy.ops.object.mode_set(mode=pre_mode)
172        return {'FINISHED'}
bl_rna = <bpy_struct, Struct("GEOMETRY_OT_attribute_convert_normals")>
Inherited Members
bpy_types.Operator
as_keywords
poll_message_set
builtins.bpy_struct
keys
values
get
pop
as_pointer
keyframe_insert
keyframe_delete
driver_add
driver_remove
is_property_set
property_unset
is_property_hidden
is_property_readonly
is_property_overridable_library
property_overridable_library_set
path_resolve
path_from_id
type_recast
bl_rna_get_subclass_py
bl_rna_get_subclass
id_properties_ensure
id_properties_clear
id_properties_ui
id_data