adds id editor
This commit is contained in:
parent
28ab2072e5
commit
40a7e4b8ba
16 changed files with 367 additions and 18 deletions
6
docu/planned_features.md
Normal file
6
docu/planned_features.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## Planned features
|
||||||
|
|
||||||
|
### ID Mask - Editor
|
||||||
|
- [ ] A way to automatically get already used colors, f.E. you already did it by hand
|
||||||
|
- [ ] Select by color
|
||||||
|
- [ ] Update after color change
|
||||||
|
|
@ -1,5 +1,22 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from src.operators.create_id_mask import CreateIDMaskOperator
|
||||||
|
from src.operators.id_editor_create_id import IDEDITOR_CreateIDOperator
|
||||||
|
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
|
||||||
|
from src.operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator
|
||||||
|
from src.panels.id_mask_editor_id_list import IDMaskEditorIDList
|
||||||
|
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
|
||||||
|
from . panels.bake_panel_options import BakeToIDOptionsPanel
|
||||||
|
from . operators.bake_to_id_map import BakeToIDMapOperator
|
||||||
|
from . panels.bake_panel import BakeToIDMapPanel
|
||||||
|
from . panels.bake_panel_info import BakeToIDInfoPanel
|
||||||
|
from . panels.id_mask_editor import IDMaskEditorPanel
|
||||||
|
from . properties.bake_properties import BakeToIDProperties
|
||||||
|
|
||||||
|
from src.properties.id_mask_editor_properties import IDMaskEditorProperties
|
||||||
|
|
||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Bake ID Mask",
|
"name": "ID Mask - Tools",
|
||||||
"author": "iedSoftworks",
|
"author": "iedSoftworks",
|
||||||
"description": "",
|
"description": "",
|
||||||
# !VERSION
|
# !VERSION
|
||||||
|
|
@ -7,20 +24,21 @@ bl_info = {
|
||||||
"category": "Object"
|
"category": "Object"
|
||||||
}
|
}
|
||||||
|
|
||||||
import bpy
|
|
||||||
|
|
||||||
from . panels.panel_options import BakeToIDOptionsPanel
|
|
||||||
from . operators.bake_to_id_map import BakeToIDMapOperator
|
|
||||||
from . panels.panel import BakeToIDMapPanel
|
|
||||||
from . panels.panel_info import BakeToIDInfoPanel
|
|
||||||
from . properties.bake_to_id import BakeToIDProperties
|
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
BakeToIDMapOperator,
|
BakeToIDMapOperator,
|
||||||
BakeToIDMapPanel,
|
BakeToIDMapPanel,
|
||||||
BakeToIDInfoPanel,
|
BakeToIDInfoPanel,
|
||||||
BakeToIDOptionsPanel,
|
BakeToIDOptionsPanel,
|
||||||
BakeToIDProperties,
|
BakeToIDProperties,
|
||||||
|
|
||||||
|
IDMaskEditorValueProperties,
|
||||||
|
IDMaskEditorProperties,
|
||||||
|
IDMaskEditorPanel,
|
||||||
|
CreateIDMaskOperator,
|
||||||
|
IDMaskEditorIDList,
|
||||||
|
IDEDITOR_CreateIDOperator,
|
||||||
|
IDEDITOR_RemoveIDOperator,
|
||||||
|
IDEDITOR_PaintIDMaskOperator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -29,7 +47,7 @@ def register():
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties))
|
setattr(bpy.types.Scene, 'bake_to_id_props', bpy.props.PointerProperty(type=BakeToIDProperties))
|
||||||
|
setattr(bpy.types.Mesh, 'id_mask_editor_properties', bpy.props.PointerProperty(type=IDMaskEditorProperties))
|
||||||
|
|
||||||
def unregister():
|
def unregister():
|
||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
import colorsys
|
|
||||||
import math
|
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from ..types.colors import get_color
|
from ..types.colors import get_color
|
||||||
|
|
|
||||||
38
src/operators/create_id_mask.py
Normal file
38
src/operators/create_id_mask.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
|
||||||
|
class CreateIDMaskOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "id_mask_editor.create_id_mask_attribute"
|
||||||
|
bl_label = ""
|
||||||
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
return 'ID_MASK' not in mesh.color_attributes
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
|
||||||
|
if 'ID_MASK' in mesh.color_attributes:
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
bpy.ops.geometry.color_attribute_add(name='ID_MASK', data_type='FLOAT_COLOR', domain='CORNER')
|
||||||
|
mesh.id_mask_editor_properties.target_attribute = 'ID_MASK'
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
33
src/operators/id_editor_create_id.py
Normal file
33
src/operators/id_editor_create_id.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
|
||||||
|
from src.types.colors import get_color
|
||||||
|
|
||||||
|
|
||||||
|
class IDEDITOR_CreateIDOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "id_mask_editor.create_id_mask"
|
||||||
|
bl_label = "id_mask_editor.create_id_mask"
|
||||||
|
|
||||||
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
properties = mesh.id_mask_editor_properties
|
||||||
|
collection = properties.possible_ids
|
||||||
|
new_id = collection.add()
|
||||||
|
|
||||||
|
color = get_color(properties.colors)
|
||||||
|
colors = color.get_colors(properties)
|
||||||
|
colorCount = len(colors)
|
||||||
|
current_id_color = colors[properties.current_color_id % colorCount]
|
||||||
|
new_id.color = current_id_color
|
||||||
|
properties.current_color_id += 1
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
38
src/operators/id_editor_paint.py
Normal file
38
src/operators/id_editor_paint.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
class IDEDITOR_PaintIDMaskOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "id_mask_editor.paint_id_mask"
|
||||||
|
bl_label = "Paint"
|
||||||
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
old_mode = bpy.context.object.mode
|
||||||
|
if old_mode != "OBJECT":
|
||||||
|
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
properties = mesh.id_mask_editor_properties
|
||||||
|
collection = properties.possible_ids
|
||||||
|
color = collection[properties.active_id].color
|
||||||
|
|
||||||
|
color_attribute = mesh.color_attributes.get(properties.target_attribute)
|
||||||
|
|
||||||
|
selected_polygons = []
|
||||||
|
for polygon in mesh.polygons:
|
||||||
|
if not polygon.select:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for idx in polygon.loop_indices:
|
||||||
|
color_attribute.data[idx].color = (color.r, color.g, color.b, 1.0)
|
||||||
|
|
||||||
|
if old_mode != "OBJECT":
|
||||||
|
bpy.ops.object.mode_set(mode=old_mode, toggle=False)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
41
src/operators/id_editor_remove_id.py
Normal file
41
src/operators/id_editor_remove_id.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
|
||||||
|
from src.types.colors import get_color
|
||||||
|
|
||||||
|
|
||||||
|
class IDEDITOR_RemoveIDOperator(bpy.types.Operator):
|
||||||
|
bl_idname = "id_mask_editor.remove_id_mask"
|
||||||
|
bl_label = "id_mask_editor.remove_id_mask"
|
||||||
|
|
||||||
|
bl_options = {'INTERNAL'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
properties = mesh.id_mask_editor_properties
|
||||||
|
collection = properties.possible_ids
|
||||||
|
return 0 <= properties.active_id < len(collection)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
obj = context.active_object
|
||||||
|
if obj.type != 'MESH':
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
if not obj.data:
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
mesh = obj.data
|
||||||
|
properties = mesh.id_mask_editor_properties
|
||||||
|
collection = properties.possible_ids
|
||||||
|
collection.remove(properties.active_id)
|
||||||
|
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
@ -3,7 +3,7 @@ import bpy
|
||||||
|
|
||||||
class BakeToIDMapPanel(bpy.types.Panel):
|
class BakeToIDMapPanel(bpy.types.Panel):
|
||||||
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
|
bl_idname = "PANEL.BAKE_TO_ID_MAP_PT_SETTINGS"
|
||||||
bl_label = "Bake to ID Map"
|
bl_label = "Bake ID Mask"
|
||||||
bl_space_type = "VIEW_3D"
|
bl_space_type = "VIEW_3D"
|
||||||
bl_region_type = "UI"
|
bl_region_type = "UI"
|
||||||
bl_category = "Tool"
|
bl_category = "Tool"
|
||||||
90
src/panels/id_mask_editor.py
Normal file
90
src/panels/id_mask_editor.py
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from src.operators.create_id_mask import CreateIDMaskOperator
|
||||||
|
from src.operators.id_editor_create_id import IDEDITOR_CreateIDOperator
|
||||||
|
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
|
||||||
|
from src.operators.id_editor_remove_id import IDEDITOR_RemoveIDOperator
|
||||||
|
from src.types.colors import get_color
|
||||||
|
|
||||||
|
|
||||||
|
class IDMaskEditorPanel(bpy.types.Panel):
|
||||||
|
bl_idname = "ID_MASK_EDITOR_PT_Panel"
|
||||||
|
bl_label = "ID Mask Editor"
|
||||||
|
bl_category = "Tool"
|
||||||
|
bl_space_type = "VIEW_3D"
|
||||||
|
bl_region_type = "UI"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context):
|
||||||
|
if not context.object:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not context.object.type == 'MESH':
|
||||||
|
return False
|
||||||
|
|
||||||
|
return context.object.mode == "EDIT"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
layout.use_property_decorate = True
|
||||||
|
|
||||||
|
mesh = context.object.data
|
||||||
|
properties = mesh.id_mask_editor_properties
|
||||||
|
|
||||||
|
target_attribute_row = layout.row(align=True)
|
||||||
|
has_attribute = properties.target_attribute
|
||||||
|
|
||||||
|
target_attribute_row.prop_search(
|
||||||
|
properties,
|
||||||
|
'target_attribute',
|
||||||
|
mesh,
|
||||||
|
'color_attributes',
|
||||||
|
icon='GROUP_VCOL'
|
||||||
|
)
|
||||||
|
target_attribute_row.operator(CreateIDMaskOperator.bl_idname, icon='ADD', text="")
|
||||||
|
|
||||||
|
if not has_attribute:
|
||||||
|
return
|
||||||
|
|
||||||
|
layout.prop(properties, "colors")
|
||||||
|
color = get_color(properties.colors)
|
||||||
|
self.draw_options(context, layout, properties, color)
|
||||||
|
|
||||||
|
layout.separator()
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
|
||||||
|
col = row.column()
|
||||||
|
col.operator(IDEDITOR_PaintIDMaskOperator.bl_idname, icon='VPAINT_HLT')
|
||||||
|
col.template_list(
|
||||||
|
'IDMaskEditorIDList',
|
||||||
|
'IDMaskEditorIDList',
|
||||||
|
properties,
|
||||||
|
'possible_ids',
|
||||||
|
properties,
|
||||||
|
'active_id',
|
||||||
|
rows=3
|
||||||
|
)
|
||||||
|
|
||||||
|
col = row.column(align=True)
|
||||||
|
col.operator(IDEDITOR_CreateIDOperator.bl_idname, icon='ADD', text="")
|
||||||
|
col.operator(IDEDITOR_RemoveIDOperator.bl_idname, icon='REMOVE', text="")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def draw_options(self, context, layout, props, element):
|
||||||
|
|
||||||
|
has_render_ui = 'render_ui' in dir(element)
|
||||||
|
has_connected_properties = 'connected_properties' in dir(element) and len(element.connected_properties) > 0
|
||||||
|
|
||||||
|
if not has_render_ui and not has_connected_properties:
|
||||||
|
return
|
||||||
|
|
||||||
|
object_box = layout.box()
|
||||||
|
|
||||||
|
if has_render_ui:
|
||||||
|
element.render_ui(context, object_box, props)
|
||||||
|
return
|
||||||
|
|
||||||
|
for setting in element.connected_properties:
|
||||||
|
object_box.prop(props, setting)
|
||||||
17
src/panels/id_mask_editor_id_list.py
Normal file
17
src/panels/id_mask_editor_id_list.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from src.operators.id_editor_paint import IDEDITOR_PaintIDMaskOperator
|
||||||
|
|
||||||
|
|
||||||
|
class IDMaskEditorIDList(bpy.types.UIList):
|
||||||
|
def draw_item(self, _context, layout, data, attribute, _icon, _active_data, _active_propname, _index):
|
||||||
|
layout.alignment = 'EXPAND'
|
||||||
|
|
||||||
|
split = layout.split(factor=0.15)
|
||||||
|
split.alignment = 'LEFT'
|
||||||
|
split.prop(attribute, 'color', text='')
|
||||||
|
|
||||||
|
split.emboss = 'NONE'
|
||||||
|
split2 = split.split(factor=0.75)
|
||||||
|
split2.prop(attribute, "name", text="")
|
||||||
|
split2.emboss = 'NORMAL'
|
||||||
58
src/properties/id_mask_editor_properties.py
Normal file
58
src/properties/id_mask_editor_properties.py
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from bpy.types import (PropertyGroup, Palette, FloatColorAttribute)
|
||||||
|
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty, PointerProperty, CollectionProperty)
|
||||||
|
|
||||||
|
from src.properties.id_mask_editor_value_properties import IDMaskEditorValueProperties
|
||||||
|
from src.types.colors import get_color_enum
|
||||||
|
|
||||||
|
def on_target_attribute_set(self, value):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def on_target_attribute_get(self):
|
||||||
|
if bpy.context.active_object is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if bpy.context.active_object.data is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if bpy.context.active_object.type != 'MESH':
|
||||||
|
return None
|
||||||
|
|
||||||
|
color_attributes = bpy.context.active_object.data.color_attributes[0]
|
||||||
|
|
||||||
|
return color_attributes
|
||||||
|
|
||||||
|
class IDMaskEditorProperties(PropertyGroup):
|
||||||
|
colors: EnumProperty(
|
||||||
|
items=get_color_enum(),
|
||||||
|
name="Color Source",
|
||||||
|
description="From where to take the colors",
|
||||||
|
default=get_color_enum()[0][0]
|
||||||
|
)
|
||||||
|
|
||||||
|
colors_color_palette_palette: PointerProperty(
|
||||||
|
type=Palette,
|
||||||
|
name='Color Palette',
|
||||||
|
description="The Color Palette used for colors"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_attribute: StringProperty(
|
||||||
|
name='',
|
||||||
|
description="The attribute to write the ID Mask to"
|
||||||
|
)
|
||||||
|
|
||||||
|
possible_ids: CollectionProperty(
|
||||||
|
type=IDMaskEditorValueProperties,
|
||||||
|
name='Entries',
|
||||||
|
)
|
||||||
|
|
||||||
|
active_id: IntProperty(
|
||||||
|
name="",
|
||||||
|
description="",
|
||||||
|
default=0
|
||||||
|
)
|
||||||
|
|
||||||
|
current_color_id: IntProperty(
|
||||||
|
default=0
|
||||||
|
)
|
||||||
17
src/properties/id_mask_editor_value_properties.py
Normal file
17
src/properties/id_mask_editor_value_properties.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
from bpy.types import (PropertyGroup)
|
||||||
|
from bpy.props import (StringProperty, FloatVectorProperty)
|
||||||
|
|
||||||
|
class IDMaskEditorValueProperties(PropertyGroup):
|
||||||
|
name: StringProperty(
|
||||||
|
name="Name",
|
||||||
|
description="ID-Name",
|
||||||
|
default='ID'
|
||||||
|
)
|
||||||
|
|
||||||
|
color: FloatVectorProperty(
|
||||||
|
name="Color",
|
||||||
|
subtype='COLOR',
|
||||||
|
default=[1.0, 1.0, 1.0],
|
||||||
|
min=0,
|
||||||
|
max=1
|
||||||
|
)
|
||||||
|
|
@ -23,10 +23,6 @@ def paint_targets(props, targets, colors):
|
||||||
|
|
||||||
layer_name = props.target_vertex_color_attribute_name
|
layer_name = props.target_vertex_color_attribute_name
|
||||||
for mesh in sorted_targets:
|
for mesh in sorted_targets:
|
||||||
|
|
||||||
if layer_name in mesh.attributes:
|
|
||||||
mesh.attributes.remove(mesh.attributes[layer_name])
|
|
||||||
|
|
||||||
color_attribute = get_color_attribute(props, mesh.attributes, layer_name)
|
color_attribute = get_color_attribute(props, mesh.attributes, layer_name)
|
||||||
|
|
||||||
for (indecies, color) in sorted_targets[mesh]:
|
for (indecies, color) in sorted_targets[mesh]:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue