Merge pull request #3 from Neintonine/develop

Develop
This commit is contained in:
Michel Fedde 2024-01-30 21:24:41 +01:00 committed by GitHub
commit feb1887a7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 270 additions and 89 deletions

View file

@ -1 +1 @@
1.1.0 1.1.0+build.1

View file

@ -5,4 +5,3 @@ if __name__ == "__main__":
currentVersion = versioning.get_version() currentVersion = versioning.get_version()
nextVersion = currentVersion.bump_minor() nextVersion = currentVersion.bump_minor()
versioning.save_version(nextVersion) versioning.save_version(nextVersion)

View file

@ -21,7 +21,6 @@ classes = (
BakeToIDMapPanel, BakeToIDMapPanel,
BakeToIDInfoPanel, BakeToIDInfoPanel,
BakeToIDOptionsPanel, BakeToIDOptionsPanel,
BakeToIDAdvancedMenu,
BakeToIDProperties, BakeToIDProperties,
) )

View file

@ -3,7 +3,9 @@ import math
import bpy import bpy
from .. types import (get_source, get_target) from ..types.colors import get_color
from .. types.sources import get_source
from .. types.targets import get_target
class BakeToIDMapOperator(bpy.types.Operator): class BakeToIDMapOperator(bpy.types.Operator):
@ -27,27 +29,44 @@ class BakeToIDMapOperator(bpy.types.Operator):
def paint_id_mask(self, context, props): def paint_id_mask(self, context, props):
source = get_source(props.source) source = get_source(props.source)
targets = source.get_targets(context) targets = self.get_targets(context, source, props)
if len(targets) < 1: if len(targets) < 1:
return return
totalTargets = len(targets) color = get_color(props.colors)
colors = [] colors = color.get_colors(props)
total_hues = props.adv_total_hues
total_satuations = props.adv_total_satuations
total_brightnesses = props.adv_total_brightnesses
satuations_break_point = math.pow(total_brightnesses, total_hues)
for i in range(totalTargets):
h = (i / total_hues) % 1
l = (math.ceil(i / total_hues) % total_brightnesses) / total_brightnesses
s = math.ceil(i / satuations_break_point) / total_satuations
colors.append(colorsys.hls_to_rgb(h, l, s))
target = get_target(props.target) target = get_target(props.target)
self.paint_targets(props, target, targets, colors)
if 'after_painting' in dir(source):
source.after_painting(context, props)
def get_targets(self, context, source, props):
if props.selection_mode == 'SINGLE':
return source.get_targets([context.active_object])
if props.selection_mode == 'MULTIPLE_COMBINED':
return source.get_targets(context.selected_objects)
if props.selection_mode == 'MULTIPLE_SEPARATE':
result = []
for obj in context.selected_objects:
if obj.type != 'MESH':
continue
obj_targets = source.get_targets([obj])
result.append(obj_targets)
return result
raise ValueError('Invalid selection_mode')
def paint_targets(self, props, target, targets, colors):
if props.selection_mode == 'MULTIPLE_SEPARATE':
for targetList in targets:
target.paint_targets(props,targetList, colors)
return
target.paint_targets(props, targets, colors) target.paint_targets(props, targets, colors)
source.after_painting(context, props)

View file

@ -13,4 +13,19 @@ class BakeToIDMapPanel(bpy.types.Panel):
layout.use_property_split = True layout.use_property_split = True
layout.use_property_decorate = False # No animation. layout.use_property_decorate = False # No animation.
self.layout.operator("object.bake_to_id_map", text="Bake") props = context.scene.bake_to_id_props
operator_row = layout.row()
operator_row.operator("object.bake_to_id_map", text="Bake")
operator_row.enabled = self.check_if_props_valid(context, props)
layout.prop(props, "selection_mode")
def check_if_props_valid(self, context, props):
if (props.selection_mode == "SINGLE" and context.active_object is None):
return False
if (props.selection_mode != "SINGLE" and len(context.selected_objects) < 1):
return False
return True

View file

@ -21,4 +21,4 @@ class BakeToIDAdvancedMenu(bpy.types.Panel):
layout.prop(props, "adv_total_satuations") layout.prop(props, "adv_total_satuations")
layout.prop(props, "adv_total_brightnesses") layout.prop(props, "adv_total_brightnesses")
layout.label(text="Max ID-count: " + str( layout.label(text="Max ID-count: " + str(
math.pow(math.pow(props.adv_total_hues, props.adv_total_satuations), props.adv_total_brightnesses))) ))

View file

@ -1,7 +1,7 @@
import bpy import bpy
from .. operators.bake_to_id_map import BakeToIDMapOperator from ..types.colors import get_color
from ..types import get_source from .. types.sources import get_source
class BakeToIDInfoPanel(bpy.types.Panel): class BakeToIDInfoPanel(bpy.types.Panel):
@ -19,5 +19,31 @@ class BakeToIDInfoPanel(bpy.types.Panel):
source = get_source(props.source) source = get_source(props.source)
layout.label(text="Selected Object-Count: " + str(len(context.selected_objects))) if props.selection_mode != 'SINGLE':
layout.label(text="Estimated ID-Count: " + str(source.estimate_ids(context, props))) layout.label(text="Selected Object-Count: " + str(len(context.selected_objects)))
if props.selection_mode == 'SINGLE':
layout.label(text="ID-Total: " + str(source.estimate_ids([context.active_object])))
if props.selection_mode == 'MULTIPLE_SEPARATE':
total = 0
count = 0
for obj in context.selected_objects:
if (obj.type != 'MESH'):
continue
total += source.estimate_ids([obj])
count += 1
layout.label(text="Estimated ID-Total: " + str(total))
try:
layout.label(text="Estimated ID-Average: " + str(total / count))
except ZeroDivisionError:
layout.label(text="Estimated ID-Average: 0")
if props.selection_mode == 'MULTIPLE_COMBINED':
layout.label(text="ID-Total: " + str(source.estimate_ids(context.selected_objects)))
color = get_color(props.colors)
layout.label(text="Colors available: " + str(color.get_count(props)))

View file

@ -2,7 +2,8 @@ import textwrap
import bpy import bpy
from src.types import get_source, get_target from .. types.sources import get_source
from .. types.targets import get_target
class BakeToIDOptionsPanel(bpy.types.Panel): class BakeToIDOptionsPanel(bpy.types.Panel):
@ -15,19 +16,28 @@ class BakeToIDOptionsPanel(bpy.types.Panel):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
props = context.scene.bake_to_id_props props = context.scene.bake_to_id_props
layout.prop(props, "source") layout.prop(props, "source")
source = get_source(props.source) source = get_source(props.source)
source_settings_box = layout.box()
for setting in source.connected_properties: if len(source.connected_properties) > 0:
source_settings_box.prop(props, setting) source_settings_box = layout.box()
for setting in source.connected_properties:
source_settings_box.prop(props, setting)
layout.separator() layout.separator()
layout.prop(props, "target") layout.prop(props, "target")
target = get_target(props.target) target = get_target(props.target)
target_settings_box = layout.box() if len(target.connected_properties) > 0:
for setting in target.connected_properties: target_settings_box = layout.box()
target_settings_box.prop(props, setting) for setting in target.connected_properties:
target_settings_box.prop(props, setting)
layout.separator()
layout.prop(props, "colors")

View file

@ -1,17 +1,30 @@
from bpy.types import (PropertyGroup) from bpy.types import (PropertyGroup)
from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty) from bpy.props import (EnumProperty, BoolProperty, IntProperty, StringProperty)
from src.types import get_source_enum, get_targets_enum from src.types.colors import get_color_enum
from src.types.sources import get_source_enum
from src.types.targets import get_targets_enum
class BakeToIDProperties(PropertyGroup): class BakeToIDProperties(PropertyGroup):
selection_mode: EnumProperty(
items=[
("SINGLE", "Only active element", "Only use the currently selected element", 0),
("MULTIPLE_SEPARATE", "Use Selection, separate", "It performs the transfer for every selected element, but each get there own ids", 1),
("MULTIPLE_COMBINED", "Use Selection, combined", "It performs the transfer for every selected element, combining the ids", 2)
],
name="Selection Mode",
description="Specifies how the 3D View-Selection is gonna be used.",
default="MULTIPLE_SEPARATE"
)
source: EnumProperty( source: EnumProperty(
items=get_source_enum(), items=get_source_enum(),
name="Source", name="Source",
description="From where should the IDs be taken", description="From where should the IDs be taken",
default = "MATERIAL_INDEX" default="MATERIAL_INDEX"
) )
target: EnumProperty( target: EnumProperty(
items=get_targets_enum(), items=get_targets_enum(),
name="Target", name="Target",
@ -19,7 +32,14 @@ class BakeToIDProperties(PropertyGroup):
default=get_targets_enum()[0][0] default=get_targets_enum()[0][0]
) )
source_materials_remove_all : BoolProperty( colors: EnumProperty(
items=get_color_enum(),
name="Color Source",
description="From where to take the colors",
default=get_color_enum()[0][0]
)
source_materials_remove_all: BoolProperty(
name="Remove all source materials", name="Remove all source materials",
default=False, default=False,
description="Removes every material except the first one." description="Removes every material except the first one."
@ -29,6 +49,11 @@ class BakeToIDProperties(PropertyGroup):
name="Color Attribute", name="Color Attribute",
default="ID_MASK", default="ID_MASK",
) )
target_vertex_color_override_attribute: BoolProperty(
name="Override Color Attribute",
default=True,
description="If set true, the attribute will be deleted and recreated, if it already exists. If set false, the data will just be overwritten."
)
adv_total_hues: IntProperty( adv_total_hues: IntProperty(
name="Total Hues", name="Total Hues",

View file

@ -1,43 +0,0 @@
from . sources import material_index as source_mat_index
from . targets import vertex_colors as target_vertex_colors
_sources = [
source_mat_index
]
_targets = [
target_vertex_colors
]
def get_source(id):
for source in _sources:
if source.source_id == id:
return source
raise Exception("Source not found: " + id)
def get_target(id):
for target in _targets:
if target.target_id == id:
return target
raise Exception("Target not found: " + id)
def get_source_enum():
enumList = []
i = 0
for source in _sources:
enumList.append((source.source_id, source.name, source.description, i))
i += 1
return enumList
def get_targets_enum():
enumList = []
i = 0
for target in _targets:
enumList.append((target.target_id, target.name, target.description, i))
i += 1
return enumList

View file

@ -0,0 +1,24 @@
from . import generated
_colors = [
generated
]
def get_color(id):
for color in _colors:
if color.color_id == id:
return color
raise Exception("Source not found: " + id)
def get_color_enum():
enum_list = []
i = 0
for color in _colors:
enum_list.append((color.color_id, color.name, color.description, i))
i += 1
return enum_list

View file

@ -0,0 +1,32 @@
import colorsys
import math
color_id = 'GENERATED'
name = 'Generated'
description = 'The colors get generated on-the-fly'
MAX_BRIGHTNESS_STEPS = 8
MAX_SATURATION_STEPS = 8
MAX_HUES_STEPS = 8
def get_colors(props):
return gen_colors()
def get_count(props):
return len(gen_colors())
def gen_colors():
colors = []
for brightnessStep in range(0, MAX_BRIGHTNESS_STEPS):
v = 1 - (brightnessStep / MAX_BRIGHTNESS_STEPS)
for satuationStep in range(0, MAX_SATURATION_STEPS):
s = 1 - (satuationStep / MAX_SATURATION_STEPS)
for hueStep in range(0, MAX_HUES_STEPS):
h = hueStep / MAX_HUES_STEPS
color = colorsys.hsv_to_rgb(h, s, v)
colors.append(color)
return colors

View file

@ -0,0 +1,25 @@
from . import material_index
from . import object
_sources = [
material_index,
object
]
def get_source(id):
for source in _sources:
if source.source_id == id:
return source
raise Exception("Source not found: " + id)
def get_source_enum():
enum_list = []
i = 0
for source in _sources:
enum_list.append((source.source_id, source.name, source.description, i))
i += 1
return enum_list

View file

@ -6,9 +6,9 @@ connected_properties = [
'source_materials_remove_all' 'source_materials_remove_all'
] ]
def get_targets(context): def get_targets(objects):
targets = [] targets = []
for obj in context.selected_objects: for obj in objects:
if not obj.material_slots: continue if not obj.material_slots: continue
mesh = obj.data mesh = obj.data
@ -33,9 +33,9 @@ def after_painting(context, props):
for obj in context.selected_objects: for obj in context.selected_objects:
obj.data.materials.clear() obj.data.materials.clear()
def estimate_ids(context, props): def estimate_ids(objects):
count = 0 count = 0
for obj in context.selected_objects: for obj in objects:
count += len(obj.material_slots) count += len(obj.material_slots)
return count return count

View file

@ -0,0 +1,16 @@
source_id = 'OBJECT'
name = 'Object ID'
description = 'Uses the object id as basis for the ID mask.'
connected_properties = []
def get_targets(objects):
targets = []
for obj in objects:
mesh = obj.data
targets.append((mesh, mesh.polygons))
return targets
def estimate_ids(objects):
return len(objects)

View file

@ -0,0 +1,23 @@
from . import vertex_colors
_targets = [
vertex_colors
]
def get_target(id):
for target in _targets:
if target.target_id == id:
return target
raise Exception("Target not found: " + id)
def get_targets_enum():
enum_list = []
i = 0
for target in _targets:
enum_list.append((target.target_id, target.name, target.description, i))
i += 1
return enum_list

View file

@ -3,7 +3,8 @@ name = 'Color Attribute / Vertex Color'
description = 'Bakes the ID onto a color attribute (previously known as Vertex Color)' description = 'Bakes the ID onto a color attribute (previously known as Vertex Color)'
connected_properties = [ connected_properties = [
'target_vertex_color_attribute_name' 'target_vertex_color_attribute_name',
'target_vertex_color_override_attribute'
] ]
@ -21,12 +22,22 @@ 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: if layer_name in mesh.attributes:
mesh.attributes.remove(mesh.attributes[layer_name]) mesh.attributes.remove(mesh.attributes[layer_name])
color_attribute = mesh.attributes.new(name=layer_name, type='FLOAT_COLOR', domain='CORNER') color_attribute = get_color_attribute(props, mesh.attributes, layer_name)
for (indecies, color) in sorted_targets[mesh]: for (indecies, color) in sorted_targets[mesh]:
for polygon in indecies: for polygon in indecies:
for idx in polygon.loop_indices: for idx in polygon.loop_indices:
color_attribute.data[idx].color = (color[0], color[1], color[2], 1.0) color_attribute.data[idx].color = (color[0], color[1], color[2], 1.0)
def get_color_attribute(props, attributes, layer_name):
if layer_name in attributes:
if not props.target_vertex_color_override_attribute:
return attributes[layer_name]
attributes.remove(attributes[layer_name])
return attributes.new(name=layer_name, type='FLOAT_COLOR', domain='CORNER')