Styles UI - moved UI from shader graph N-panel to Styles UI #3912

Moved all shading style and textures parameters from shader-graph N-panel to general Styles UI. Shader graph now also update in real time on any prop changes in Styles UI.

Now there is practically no need to switch to shader graph to edit styles shaders - all parameters are available from the Styles UI. That also allows you to edit styles and see the results in viewport even if the edited style is not the one that's currently active.

small demo - https://imgur.com/a/i2suoZw
This commit is contained in:
Andrej730
2023-12-07 15:25:20 +05:00
parent d0c68d3f5b
commit fa31e10a77
9 changed files with 425 additions and 453 deletions
@@ -23,8 +23,9 @@ classes = (
operator.ActivateExternalStyle,
operator.AddPresentationStyle,
operator.AddStyle,
operator.AddSurfaceTexture,
operator.BrowseExternalStyle,
operator.ClearTextureMapPath,
operator.RemoveTextureMap,
operator.ChooseTextureMapPath,
operator.DisableAddingPresentationStyle,
operator.DisableEditingExternalStyle,
@@ -46,6 +47,7 @@ classes = (
operator.UpdateStyleColours,
operator.UpdateStyleTextures,
prop.Style,
prop.Texture,
prop.BIMStylesProperties,
prop.BIMStyleProperties,
ui.BIM_PT_styles,
@@ -53,7 +55,6 @@ classes = (
ui.BIM_PT_style_attributes,
ui.BIM_PT_external_style_attributes,
ui.BIM_UL_styles,
ui.BIM_PT_STYLE_GRAPH,
)
@@ -34,12 +34,23 @@ class StylesData:
@classmethod
def load(cls):
cls.data = {
"styles_to_blender_material_names": cls.styles_to_blender_material_names(),
"style_types": cls.style_types(),
"total_styles": cls.total_styles(),
"reflectance_methods": cls.reflectance_methods(),
}
cls.is_loaded = True
@classmethod
def styles_to_blender_material_names(cls):
ifc_file = tool.Ifc.get()
props = bpy.context.scene.BIMStylesProperties
materials = []
for style in props.styles:
material = tool.Ifc.get_object(ifc_file.by_id(style.ifc_definition_id))
materials.append(material.name if material is not None else None)
return materials
@classmethod
def reflectance_methods(cls):
declaration = tool.Ifc.schema().declaration_by_name("IfcReflectanceMethodEnum")
@@ -24,8 +24,7 @@ import blenderbim.tool as tool
import blenderbim.core.style as core
import ifcopenshell.util.representation
from pathlib import Path
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.style.data import StylesData, StyleAttributesData
from blenderbim.bim.module.style.data import StyleAttributesData
from mathutils import Vector
@@ -33,14 +32,15 @@ class UpdateStyleColours(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.update_style_colours"
bl_label = "Save Current Shading Style"
bl_description = (
"Save current style values to IfcSurfaceStyleShading.\n\n" + "ALT+CLICK to see saved values details"
"Update IfcSurfaceStyleShading based on current blender material shading graph.\n\n"
+ "ALT+CLICK to see saved values details"
)
bl_options = {"REGISTER", "UNDO"}
verbose: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
def invoke(self, context, event):
# verobse print to console on alt+click
# verbose print to console on alt+click
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
if event.type == "LEFTMOUSE" and event.alt:
self.verbose = True
@@ -51,12 +51,12 @@ class UpdateStyleColours(bpy.types.Operator, tool.Ifc.Operator):
core.update_style_colours(tool.Ifc, tool.Style, obj=mat, verbose=self.verbose)
if self.verbose:
self.report({"INFO"}, "Check the system console to see saved style properties")
tool.Style.set_surface_style_props(mat)
class UpdateStyleTextures(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.update_style_textures"
bl_label = "Update Style Textures"
bl_description = "Update IfcSurfaceStyleWithTextures based on current blender material shading graph"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
@@ -82,6 +82,7 @@ class RemoveStyle(bpy.types.Operator, tool.Ifc.Operator):
class AddStyle(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.add_style"
bl_label = "Add Style"
bl_description = "Add IfcSurfaceStyle to the active material"
bl_options = {"REGISTER", "UNDO"}
def _execute(self, context):
@@ -120,6 +121,12 @@ class DisableEditingStyle(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
props = bpy.context.scene.BIMStylesProperties
style = tool.Ifc.get().by_id(props.is_editing_style)
material = tool.Ifc.get_object(style)
# just to trigger style update
material.BIMStyleProperties.active_style_type = material.BIMStyleProperties.active_style_type
props.is_editing_style = 0
@@ -146,19 +153,14 @@ class UpdateCurrentStyle(bpy.types.Operator):
)
bl_options = {"REGISTER", "UNDO"}
update_all: bpy.props.BoolProperty(name="Update All", default=False, options={"SKIP_SAVE"})
style_id: bpy.props.IntProperty(default=0, options={"SKIP_SAVE"})
@classmethod
def poll(cls, context):
poll = (
context.active_object is not None
and context.active_object.active_material is not None
and context.active_object.active_material.BIMMaterialProperties.ifc_style_id != 0
)
if not poll:
cls.poll_message_set(
"Object is not selected or material is not assigned or material doesn't have IFC Style"
)
return poll
if not context.selected_objects:
cls.poll_message_set("No objects selected")
return False
return True
def invoke(self, context, event):
# updating all styles on shift+click
@@ -168,16 +170,18 @@ class UpdateCurrentStyle(bpy.types.Operator):
return self.execute(context)
def execute(self, context):
current_style_type = context.active_object.active_material.BIMStyleProperties.active_style_type
style = tool.Ifc.get().by_id(self.style_id)
material = tool.Ifc.get_object(style)
current_style_type = material.BIMStyleProperties.active_style_type
if self.update_all:
context.scene.BIMStylesProperties.active_style_type = current_style_type
return {"FINISHED"}
materials = []
for obj in context.selected_objects:
mat = obj.active_material
if mat and mat.BIMMaterialProperties.ifc_style_id != 0:
mat.BIMStyleProperties.active_style_type = current_style_type
for mat in obj.data.materials:
if mat and mat.BIMMaterialProperties.ifc_style_id != 0:
mat.BIMStyleProperties.active_style_type = current_style_type
return {"FINISHED"}
@@ -231,7 +235,9 @@ class BrowseExternalStyle(bpy.types.Operator):
description="List of objects in the .blend file",
items=get_data_blocks,
)
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
use_relative_path: bpy.props.BoolProperty(
name="Use Relative Path", description="Save path relative to IFC file", default=True
)
directory: bpy.props.StringProperty(
name="Directory",
description="Start file browsing directory",
@@ -266,11 +272,11 @@ class BrowseExternalStyle(bpy.types.Operator):
def execute(self, context):
if self.data_block_type == "0":
self.report({"ERROR"}, "Select a data block type")
self.report({"ERROR"}, "Select a data block type in the side panel of the file browser")
return {"CANCELLED"}
if self.data_block == "":
self.report({"ERROR"}, "Select a data block")
self.report({"ERROR"}, "Select a data block in the side panel of the file browser")
return {"CANCELLED"}
if not os.path.exists(self.filepath):
@@ -413,10 +419,12 @@ class SelectByStyle(bpy.types.Operator, tool.Ifc.Operator):
class ChooseTextureMapPath(bpy.types.Operator):
bl_idname = "bim.choose_texture_map_path"
bl_label = "Choose Texture Map Path"
bl_options = {"REGISTER", "UNDO"}
texture_map_prop: bpy.props.StringProperty(default="")
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
texture_map_index: bpy.props.IntProperty(default=-1, options={"SKIP_SAVE"})
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
use_relative_path: bpy.props.BoolProperty(
name="Use Relative Path", description="Save path relative to IFC file", default=True
)
filepath: bpy.props.StringProperty(
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
)
@@ -427,16 +435,9 @@ class ChooseTextureMapPath(bpy.types.Operator):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
@classmethod
def poll(cls, context):
poll = getattr(context, "material", None)
if not poll:
cls.poll_message_set("Select a material")
return poll
def execute(self, context):
if not self.texture_map_prop:
self.report({"ERROR"}, "Provide a texture map")
if self.texture_map_index < 0:
self.report({"ERROR"}, "Provide a texture map index")
return {"CANCELLED"}
abs_path = Path(self.filepath)
@@ -445,30 +446,26 @@ class ChooseTextureMapPath(bpy.types.Operator):
else:
image_filepath = abs_path
props = context.material.BIMStyleProperties
setattr(props, self.texture_map_prop, image_filepath.as_posix())
texture = context.scene.BIMStylesProperties.textures[self.texture_map_index]
texture.path = image_filepath.as_posix()
return {"FINISHED"}
class ClearTextureMapPath(bpy.types.Operator):
bl_idname = "bim.clear_texture_map_path"
bl_label = "Clear Texture Map Path"
bl_options = {"REGISTER", "UNDO"}
texture_map_prop: bpy.props.StringProperty(default="")
@classmethod
def poll(cls, context):
poll = getattr(context, "material", None)
if not poll:
cls.poll_message_set("Select a material")
return poll
class RemoveTextureMap(bpy.types.Operator):
bl_idname = "bim.remove_texture_map"
bl_label = "Remove Texture Map"
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
texture_map_index: bpy.props.IntProperty(default=-1, options={"SKIP_SAVE"})
def execute(self, context):
if not self.texture_map_prop:
self.report({"ERROR"}, "Provide a texture map")
if self.texture_map_index < 0:
self.report({"ERROR"}, "Provide a texture map index")
return {"CANCELLED"}
props = context.material.BIMStyleProperties
setattr(props, self.texture_map_prop, "")
props = context.scene.BIMStylesProperties
props.textures.remove(self.texture_map_index)
# just to trigger shader graph update
props.surface_colour = props.surface_colour
return {"FINISHED"}
@@ -546,74 +543,15 @@ class EnableEditingSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
props = bpy.context.scene.BIMStylesProperties
style = tool.Ifc.get().by_id(self.style)
shading = None
surface_style = None
for style2 in style.Styles:
if style2.is_a() == self.ifc_class:
surface_style = style2
if style2.is_a() == "IfcSurfaceStyleShading":
shading = style2
color_to_tuple = lambda x: (x.Red, x.Green, x.Blue)
if surface_style:
if self.ifc_class == "IfcSurfaceStyleShading":
props.surface_colour = color_to_tuple(surface_style.SurfaceColour)
props.transparency = surface_style.Transparency or 0.0
elif self.ifc_class == "IfcSurfaceStyleRendering":
props.surface_colour = color_to_tuple(surface_style.SurfaceColour)
props.transparency = surface_style.Transparency or 0.0
if surface_style.DiffuseColour:
props.is_diffuse_colour_null = False
if surface_style.DiffuseColour.is_a("IfcColourRgb"):
props.diffuse_colour_class = "IfcColourRgb"
props.diffuse_colour = color_to_tuple(surface_style.DiffuseColour)
else:
props.diffuse_colour_class = "IfcNormalisedRatioMeasure"
props.diffuse_colour_ratio = surface_style.DiffuseColour.wrappedValue
else:
props.is_diffuse_colour_null = False
if surface_style.SpecularColour:
props.is_specular_colour_null = False
if surface_style.SpecularColour.is_a("IfcColourRgb"):
props.specular_colour_class = "IfcColourRgb"
props.specular_colour = color_to_tuple(surface_style.SpecularColour)
else:
props.specular_colour_class = "IfcNormalisedRatioMeasure"
props.specular_colour_ratio = surface_style.SpecularColour.wrappedValue
else:
props.is_specular_colour_null = False
if surface_style.SpecularHighlight:
props.is_specular_highlight_null = False
if surface_style.SpecularHighlight.is_a("IfcSpecularRoughness"):
props.specular_highlight = surface_style.SpecularHighlight.wrappedValue
else:
props.is_specular_highlight_null = False # Exponent is meaningless
else:
props.is_specular_highlight_null = True
props.reflectance_method = surface_style.ReflectanceMethod
elif self.ifc_class == "IfcExternallyDefinedSurfaceStyle":
attributes = props.external_style_attributes
attributes.clear()
blenderbim.bim.helper.import_attributes2(surface_style, attributes)
else:
if self.ifc_class == "IfcSurfaceStyleRendering":
if shading:
props.surface_colour = color_to_tuple(shading.SurfaceColour)
props.transparency = shading.Transparency or 0.0
elif self.ifc_class == "IfcExternallyDefinedSurfaceStyle":
attributes = props.external_style_attributes
attributes.clear()
blenderbim.bim.helper.import_attributes2(self.ifc_class, attributes)
props.is_editing_style = self.style
props.is_editing_class = self.ifc_class
tool.Style.set_surface_style_props()
surface_style = tool.Style.get_style_elements(style).get(self.ifc_class, None)
if self.ifc_class == "IfcExternallyDefinedSurfaceStyle":
attributes = props.external_style_attributes
attributes.clear()
blenderbim.bim.helper.import_attributes2(surface_style or self.ifc_class, attributes)
class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
@@ -625,16 +563,11 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
self.props = bpy.context.scene.BIMStylesProperties
self.style = tool.Ifc.get().by_id(self.props.is_editing_style)
self.surface_style = None
self.shading_style = None
self.rendering_style = None
for style2 in self.style.Styles:
if style2.is_a() == self.props.is_editing_class:
self.surface_style = style2
if style2.is_a() == "IfcSurfaceStyleShading":
self.shading_style = style2
if style2.is_a() == "IfcSurfaceStyleRendering":
self.rendering_style = style2
style_elements = tool.Style.get_style_elements(self.style)
self.surface_style = style_elements.get(self.props.is_editing_class, None)
self.shading_style = style_elements.get("IfcSurfaceStyleShading", None)
self.rendering_style = style_elements.get("IfcSurfaceStyleRendering", None)
self.texture_style = style_elements.get("IfcSurfaceStyleWithTextures", None)
if self.surface_style:
self.edit_existing_style()
@@ -665,8 +598,27 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
attributes=self.get_rendering_attributes(),
)
tool.Loader.create_surface_style_rendering(material, self.surface_style)
elif self.props.is_editing_class == "IfcSurfaceStyleWithTextures":
# TODO: fix same issues as with creating new IfcSurfaceStyleWithTextures
material = tool.Ifc.get_object(self.style)
shading_style = self.rendering_style or self.shading_style
if self.rendering_style is None:
self.report(
{"ERROR"},
"Editing texture styles without defining shading/rendering style is not yet supported. "
"Define shading/render style first",
)
return {"CANCELLED"}
textures = tool.Ifc.run("style.add_surface_textures", material=material, uv_maps=[])
texture_style = tool.Ifc.run(
"style.add_surface_style",
style=self.style,
ifc_class="IfcSurfaceStyleWithTextures",
attributes={"Textures": textures},
)
tool.Loader.create_surface_style_with_textures(material, shading_style, texture_style)
elif self.surface_style.is_a() == "IfcExternallyDefinedSurfaceStyle":
surface_style = ifcopenshell.api.run(
ifcopenshell.api.run(
"style.edit_surface_style",
tool.Ifc.get(),
style=self.surface_style,
@@ -693,6 +645,30 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
attributes=self.get_rendering_attributes(),
)
tool.Loader.create_surface_style_rendering(material, surface_style)
elif self.props.is_editing_class == "IfcSurfaceStyleWithTextures":
# TODO: rework add_surface_textures to work without blender
# otherwise we lose textures that are not used in the shader
# and we also doesn't recognize relative paths if .blend file is not saved
# TODO: provide `uv_maps` - need to rework .get_uv_maps not to depend on a single representation
material = tool.Ifc.get_object(self.style)
shading_style = self.rendering_style or self.shading_style
# TODO: support creating texture styles without defining shading style first
if self.rendering_style is None:
self.report(
{"ERROR"},
"Creating texture styles without defining shading/rendering style is not yet supported. "
"Define shading/render style first",
)
return {"CANCELLED"}
textures = tool.Ifc.run("style.add_surface_textures", material=material, uv_maps=[])
if textures:
texture_style = tool.Ifc.run(
"style.add_surface_style",
style=self.style,
ifc_class="IfcSurfaceStyleWithTextures",
attributes={"Textures": textures},
)
tool.Loader.create_surface_style_with_textures(material, shading_style, texture_style)
elif self.props.is_editing_class == "IfcExternallyDefinedSurfaceStyle":
surface_style = ifcopenshell.api.run(
"style.add_surface_style",
@@ -726,7 +702,7 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
if self.props.is_specular_highlight_null:
specular_highlight = None
else:
specular_highlight = {"SpecularRoughness": self.props.specular_highlight}
specular_highlight = {"IfcSpecularRoughness": self.props.specular_highlight}
return {
"SurfaceColour": self.color_to_dict(self.props.surface_colour),
@@ -741,6 +717,24 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
return {"Red": x[0], "Green": x[1], "Blue": x[2]}
class AddSurfaceTexture(bpy.types.Operator):
bl_idname = "bim.add_surface_texture"
bl_label = "Add Surface Texture"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
if len(context.scene.BIMStylesProperties.textures) >= 8:
cls.poll_message_set("Only 8 texture maps available")
return False
return True
def execute(self, context):
props = context.scene.BIMStylesProperties
props.textures.add()
return {"FINISHED"}
class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.save_uv_to_style"
bl_label = "Save UV To Style"
+100 -135
View File
@@ -17,7 +17,7 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
from blenderbim.bim.ifc import IfcStore
import blenderbim.tool as tool
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.style.data import StylesData
from bpy.types import PropertyGroup
@@ -31,7 +31,6 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
import blenderbim.tool as tool
def get_style_types(self, context):
@@ -74,6 +73,45 @@ def update_shading_styles(self, context):
tool.Style.change_current_style_type(mat, self.active_style_type)
def update_shader_graph(self, context):
props = self.id_data.BIMStylesProperties if isinstance(self, Texture) else self
if not props.update_graph:
return
style = tool.Ifc.get().by_id(props.is_editing_style)
material = tool.Ifc.get_object(style)
shading_data = tool.Style.get_shading_style_data_from_props()
textures_data = tool.Style.get_texture_style_data_from_props()
tool.Loader.create_surface_style_rendering(material, shading_data)
tool.Loader.create_surface_style_with_textures(material, shading_data, textures_data)
UV_MODES = [
("UV", "UV", "Actual UV data presented on the geometry"),
("Generated", "Generated", "Automatically-generated UV from the vertex positions of the mesh"),
("Camera", "Camera", "UV from position coordinate in camera space"),
]
TEXTURE_MAPS_MODS = (
("DIFFUSE", "DIFFUSE", ""),
("NORMAL", "NORMAL", ""),
("METALLICROUGHNESS", "METALLICROUGHNESS", "Green Channel = Roughness,\nBlue Channel = Metallic"),
("SPECULAR", "SPECULAR", ""),
("SHININESS", "SHININESS", ""),
("EMISSIVE", "EMISSIVE", ""),
("OCCLUSION", "OCCLUSION", ""),
("AMBIENT", "AMBIENT", ""),
)
class Texture(PropertyGroup):
mode: EnumProperty(name="Type Of Texture", items=TEXTURE_MAPS_MODS, update=update_shader_graph)
# NOTE: subtype `FILE_PATH` is not used to avoid .blend relative paths
path: StringProperty(name="Texture Path", update=update_shader_graph)
class BIMStylesProperties(PropertyGroup):
is_adding: BoolProperty(name="Is Adding")
is_editing: BoolProperty(name="Is Editing")
@@ -98,31 +136,81 @@ class BIMStylesProperties(PropertyGroup):
name="Surface Style Class",
default="IfcSurfaceStyleShading",
)
surface_colour: bpy.props.FloatVectorProperty(
name="Surface Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3
update_graph: BoolProperty(
name="Update Shade Graph on Prop Change",
description="Update shader graph in real time\nas you update style properties",
default=True,
)
transparency: bpy.props.FloatProperty(name="Transparency", default=0.0, min=0.0, max=1.0)
# shading props
surface_colour: bpy.props.FloatVectorProperty(
name="Surface Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3, update=update_shader_graph
)
transparency: bpy.props.FloatProperty(
name="Transparency", default=0.0, min=0.0, max=1.0, update=update_shader_graph
)
# TODO: do something on null?
is_diffuse_colour_null: BoolProperty(name="Is Null")
diffuse_colour_class: EnumProperty(
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
name="Diffuse Colour Class",
update=update_shader_graph,
)
diffuse_colour: bpy.props.FloatVectorProperty(
name="Diffuse Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3
name="Diffuse Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3, update=update_shader_graph
)
diffuse_colour_ratio: bpy.props.FloatProperty(
name="Diffuse Ratio", default=0.0, min=0.0, max=1.0, update=update_shader_graph
)
diffuse_colour_ratio: bpy.props.FloatProperty(name="Diffuse Ratio", default=0.0, min=0.0, max=1.0)
is_specular_colour_null: BoolProperty(name="Is Null")
specular_colour_class: EnumProperty(
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
name="Specular Colour Class",
update=update_shader_graph,
default="IfcNormalisedRatioMeasure",
)
specular_colour: bpy.props.FloatVectorProperty(
name="Specular Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3
name="Specular Colour",
subtype="COLOR",
default=(1, 1, 1),
min=0.0,
max=1.0,
size=3,
update=update_shader_graph,
)
specular_colour_ratio: bpy.props.FloatProperty(
name="Specular Ratio",
description="Used as Metallic value in PHYSICAL Reflectance Method",
default=0.0,
min=0.0,
max=1.0,
update=update_shader_graph,
)
specular_colour_ratio: bpy.props.FloatProperty(name="Specular Ratio", default=0.0, min=0.0, max=1.0)
is_specular_highlight_null: BoolProperty(name="Is Null")
specular_highlight: bpy.props.FloatProperty(name="Specular Highlight", default=0.0, min=0.0, max=1.0)
reflectance_method: EnumProperty(name="Reflectance Method", items=get_reflectance_methods)
specular_highlight: bpy.props.FloatProperty(
name="Specular Highlight",
description="Used as Roughness value in PHYSICAL Reflectance Method",
default=0.0,
min=0.0,
max=1.0,
update=update_shader_graph,
)
reflectance_method: EnumProperty(
name="Reflectance Method",
items=get_reflectance_methods,
update=update_shader_graph,
)
# textures props
textures: CollectionProperty(name="Textures", type=Texture)
uv_mode: EnumProperty(
name="UV Mode",
description="Type of UV used for the textures",
items=UV_MODES,
default="UV",
update=update_shader_graph,
)
styles: CollectionProperty(name="Styles", type=Style)
active_style_index: IntProperty(name="Active Style Index")
active_style_type: EnumProperty(
@@ -157,54 +245,13 @@ def update_shading_style(self, context):
if rendering_style and texture_style:
tool.Loader.create_surface_style_with_textures(blender_material, rendering_style, texture_style)
tool.Style.set_surface_style_props(blender_material)
tool.Style.record_shading(blender_material)
# TODO: support more more methods
# based on https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcReflectanceMethodEnum.htm
REFLECTANCE_METHODS = [
("PHYSICAL", "PHYSICAL", ""),
("FLAT", "FLAT", ""),
("METAL", "METAL", ""),
("MATT", "MATT", ""),
("GLASS", "GLASS", ""),
("NOTDEFINED", "NOTDEFINED", ""),
]
UV_MODES = [
("UV", "UV", "Actual UV data presented on the geometry"),
("Generated", "Generated", "Automatically-generated UV from the vertex positions of the mesh"),
("Camera", "Camera", "UV from position coordinate in camera space"),
]
def update_shader_graph(self, context):
if not self.update_graph:
return
material = self.id_data
style_data = tool.Style.get_surface_style_from_props(material)
textures_data = tool.Style.get_texture_style_from_props(material)
tool.Loader.create_surface_style_rendering(material, style_data)
tool.Loader.create_surface_style_with_textures(material, style_data, textures_data)
def update_graph_get(self):
return self.get("update_graph", True)
def update_graph_set(self, value):
self["update_graph"] = value
if value:
material = self.id_data
tool.Style.set_surface_style_props(material)
class BIMStyleProperties(PropertyGroup):
# TODO: remove, as attributes already moved to styles ui
attributes: CollectionProperty(name="Attributes", type=Attribute)
is_editing: BoolProperty(name="Is Editing")
external_style_attributes: CollectionProperty(name="External Style Attributes", type=Attribute)
is_editing_external_style: BoolProperty(name="Is Editing External Style")
@@ -215,85 +262,3 @@ class BIMStyleProperties(PropertyGroup):
default="Shading",
update=update_shading_style,
)
update_graph: BoolProperty(
name="Update Shade Graph on Prop Change",
description="Update shader graph in real time\nas you update style properties",
default=True,
get=update_graph_get,
set=update_graph_set,
)
uv_mode: EnumProperty(
name="UV Mode",
description="Type of UV used for the textures",
items=UV_MODES,
default="UV",
update=update_shader_graph,
)
# GLTF style properties
reflectance_method: EnumProperty(
name="Reflectance Method",
description="Reflectance method to use for the material",
items=REFLECTANCE_METHODS,
default="PHYSICAL",
update=update_shader_graph,
)
surface_color: bpy.props.FloatVectorProperty(
name="Surface Color",
subtype="COLOR",
default=(1, 1, 1, 1),
min=0.0,
max=1.0,
size=4,
update=update_shader_graph,
)
diffuse_color: bpy.props.FloatVectorProperty(
name="Diffuse Color",
subtype="COLOR",
default=(1, 1, 1, 1),
min=0.0,
max=1.0,
size=4,
update=update_shader_graph,
)
transparency: bpy.props.FloatProperty(
name="Transparency", default=0.0, min=0.0, max=1.0, update=update_shader_graph
)
roughness: bpy.props.FloatProperty(name="Roughness", default=0.0, min=0.0, max=1.0, update=update_shader_graph)
metallic: bpy.props.FloatProperty(name="Metallic", default=0.0, min=0.0, max=1.0, update=update_shader_graph)
# texture paths
normal_path: bpy.props.StringProperty(
name="NormalMap",
maxlen=1024,
default="",
update=update_shader_graph,
)
emissive_path: bpy.props.StringProperty(
name="Emissive",
maxlen=1024,
default="",
update=update_shader_graph,
)
metallic_roughness_path: bpy.props.StringProperty(
name="Metallic/Roughness",
maxlen=1024,
default="",
update=update_shader_graph,
description="Green Channel = Roughness,\nBlue Channel = Metallic",
)
diffuse_path: bpy.props.StringProperty(
name="Diffuse",
maxlen=1024,
default="",
update=update_shader_graph,
)
occlusion_path: bpy.props.StringProperty(
name="Occlusion",
description="Note that occlusion isn't actually used in Blender shader, we're just storing the data",
maxlen=1024,
default="",
update=update_shader_graph,
)
@@ -18,11 +18,11 @@
import bpy
import blenderbim.bim.helper
import blenderbim.tool as tool
from bpy.types import Panel, UIList
from blenderbim.bim.ifc import IfcStore
from blenderbim.bim.module.style.data import StylesData, StyleAttributesData
from bl_ui.properties_material import MaterialButtonsPanel
from blenderbim.tool.style import TEXTURE_MAPS_BY_METHODS, STYLE_TEXTURE_PROPS_MAP
class BIM_PT_styles(Panel):
@@ -59,6 +59,7 @@ class BIM_PT_styles(Panel):
self.layout.template_list("BIM_UL_styles", "", self.props, "styles", self.props, "active_style_index")
# adding a new IfcSurfaceStyle
if self.props.is_adding:
box = self.layout.box()
row = box.row()
@@ -75,14 +76,23 @@ class BIM_PT_styles(Panel):
row.operator("bim.add_presentation_style", text="Save New Style", icon="CHECKMARK")
row.operator("bim.disable_adding_presentation_style", text="", icon="CANCEL")
# style ui tools
if self.props.styles and self.props.active_style_index < len(self.props.styles):
row = self.layout.row(align=True)
style = self.props.styles[self.props.active_style_index]
material_name = StylesData.data["styles_to_blender_material_names"][self.props.active_style_index]
material = bpy.data.materials[material_name]
op = row.operator("bim.enable_editing_style", text="Edit Style", icon="GREASEPENCIL")
op.style = style.ifc_definition_id
row.operator("bim.select_by_style", text="", icon="RESTRICT_SELECT_OFF").style = style.ifc_definition_id
row.operator("bim.remove_style", text="", icon="X").style = style.ifc_definition_id
row = self.layout.row(align=True)
row.prop(material.BIMStyleProperties, "active_style_type", icon="SHADING_RENDERED", text="")
op = row.operator("bim.update_current_style", icon="FILE_REFRESH", text="")
op.style_id = style.ifc_definition_id
if self.props.style_type == "IfcSurfaceStyle":
self.layout.label(text="Surface Style Element:")
col = self.layout.column(align=True)
@@ -109,6 +119,7 @@ class BIM_PT_styles(Panel):
op.ifc_class = "IfcExternallyDefinedSurfaceStyle"
op.style = style.ifc_definition_id
# display style elements props during edit
if self.props.is_editing_style:
if self.props.is_editing_class == "IfcSurfaceStyle":
blenderbim.bim.helper.draw_attributes(self.props.attributes, self.layout)
@@ -121,8 +132,10 @@ class BIM_PT_styles(Panel):
self.draw_surface_style_rendering()
elif self.props.is_editing_class == "IfcExternallyDefinedSurfaceStyle":
self.draw_externally_defined_surface_style()
elif self.props.is_editing_class == "IfcSurfaceStyleWithTextures":
self.draw_surface_style_with_textures()
else:
# TODO: UI for Texture, Lighting, Refract
# TODO: UI Lighting, Refract
self.layout.label(text=f"{self.props.is_editing_class} UI is not yet supported.")
def draw_surface_style_shading(self):
@@ -142,8 +155,12 @@ class BIM_PT_styles(Panel):
row = self.layout.row()
row.prop(self.props, "reflectance_method")
if self.props.reflectance_method not in ("PHYSICAL", "NOTDEFINED", "FLAT"):
self.layout.label(text=f"Supported reflectance methods are:")
self.layout.label(text=f"PHYSICAL / NOTDEFINED / FLAT")
row = self.layout.row(align=True)
row.label(text="Diffuse")
row.label(text="Emissive" if self.props.reflectance_method == "FLAT" else "Diffuse")
row.prop(self.props, "diffuse_colour_class", text="")
if self.props.diffuse_colour_class == "IfcColourRgb":
row.prop(self.props, "diffuse_colour", text="")
@@ -192,6 +209,28 @@ class BIM_PT_styles(Panel):
row.operator("bim.edit_surface_style", text="Save Rendering Style", icon="CHECKMARK")
row.operator("bim.disable_editing_style", text="", icon="CANCEL")
def draw_surface_style_with_textures(self):
textures = self.props.textures
row = self.layout.row(align=True)
row.label(text=f"Style has {len(textures)} textures", icon="SHADING_TEXTURE")
row.operator("bim.add_surface_texture", text="", icon="ADD")
self.layout.prop(self.props, "uv_mode")
for i, texture in enumerate(textures):
split = self.layout.split(factor=0.30, align=True)
split.column(align=True).prop(texture, "mode", text="")
# path
row = split.column(align=True).row(align=True)
row.prop(texture, "path", text="")
op_path = row.operator("bim.choose_texture_map_path", text="", icon="FILEBROWSER")
op_clear = row.operator("bim.remove_texture_map", text="", icon="X")
op_path.texture_map_index = op_clear.texture_map_index = i
row = self.layout.row(align=True)
row.operator("bim.edit_surface_style", text="Save Texture Style", icon="CHECKMARK")
row.operator("bim.disable_editing_style", text="", icon="CANCEL")
def draw_externally_defined_surface_style(self):
blenderbim.bim.helper.draw_attributes(self.props.external_style_attributes, self.layout)
row = self.layout.row(align=True)
@@ -199,24 +238,6 @@ class BIM_PT_styles(Panel):
row.operator("bim.disable_editing_style", text="", icon="CANCEL")
def draw_style_ui(self, context):
mat = context.material
props = mat.BIMMaterialProperties
style_props = mat.BIMStyleProperties
row = self.layout.row(align=True)
if not props.ifc_style_id:
row.operator("bim.add_style", icon="ADD")
return
row.prop(style_props, "active_style_type", icon="SHADING_RENDERED", text="")
row.operator("bim.update_current_style", icon="FILE_REFRESH", text="")
row = self.layout.row(align=True)
row.operator("bim.update_style_colours", icon="GREASEPENCIL")
row.operator("bim.update_style_textures", icon="TEXTURE", text="")
row.operator("bim.unlink_style", icon="UNLINKED", text="")
row.operator("bim.remove_style", icon="X", text="").style = props.ifc_style_id
class BIM_PT_style(MaterialButtonsPanel, Panel):
bl_label = "Style"
bl_idname = "BIM_PT_style"
@@ -235,11 +256,15 @@ class BIM_PT_style(MaterialButtonsPanel, Panel):
def draw(self, context):
mat = context.material
props = mat.BIMMaterialProperties
draw_style_ui(self, context)
row = self.layout.row(align=True)
if not props.ifc_style_id:
row.operator("bim.add_style", icon="ADD")
return
row = self.layout.row(align=True)
row.prop(mat, "diffuse_color", text="Viewport Color" if mat.use_nodes else "Render Color")
row.operator("bim.update_style_colours", icon="GREASEPENCIL")
row.operator("bim.update_style_textures", icon="TEXTURE", text="")
row.operator("bim.unlink_style", icon="UNLINKED", text="")
row.operator("bim.remove_style", icon="X", text="").style = props.ifc_style_id
class BIM_PT_style_attributes(Panel):
@@ -369,66 +394,3 @@ class BIM_UL_styles(UIList):
row2.label(text="", icon="LIGHT_POINT")
elif style.name == "IfcExternallyDefinedSurfaceStyle":
row2.label(text="", icon="APPEND_BLEND")
class BIM_PT_STYLE_GRAPH(Panel):
bl_idname = "BIM_PT_style_graph"
bl_space_type = "NODE_EDITOR"
bl_label = "Style Graph Settings"
bl_region_type = "UI"
bl_category = "BBIM"
@classmethod
def poll(cls, context):
return getattr(context, "material", None)
def draw(self, context):
layout = self.layout
props = context.active_object.active_material.BIMStyleProperties
draw_style_ui(self, context)
layout.separator()
box = layout.box()
box.label(text="Creating shader from this panel")
box.label(text="ensures that shader is")
box.label(text="GLTF compatible")
box.label(text="and therefore will be ")
box.label(text="stored in IFC safely.")
layout.separator()
layout.prop(props, "update_graph", text="Graph Auto Update")
layout.label(text="Reflectance Method:")
layout.prop(props, "reflectance_method", text="")
layout.prop(props, "surface_color")
layout.prop(props, "transparency")
if not (props.reflectance_method == "PHYSICAL" and props.diffuse_path) and not (
props.reflectance_method == "FLAT" and props.emissive_path
):
prop_name = "Emissive Color" if props.reflectance_method == "FLAT" else "Diffuse Color"
layout.prop(props, "diffuse_color", text=prop_name)
if props.reflectance_method == "PHYSICAL" and not props.metallic_roughness_path:
layout.prop(props, "metallic")
if props.reflectance_method not in ("PHYSICAL", "FLAT", "NOTDEFINED") or (
props.reflectance_method == "PHYSICAL" and not props.metallic_roughness_path
):
layout.prop(props, "roughness")
def add_texture_path(path_name):
row = layout.row(align=True)
row.prop(props, path_name)
op_path = row.operator("bim.choose_texture_map_path", text="", icon="FILEBROWSER")
op_clear = row.operator("bim.clear_texture_map_path", text="", icon="X")
op_path.texture_map_prop = op_clear.texture_map_prop = path_name
layout.separator()
texture_maps = TEXTURE_MAPS_BY_METHODS.get(props.reflectance_method, [])
if not texture_maps:
return
layout.prop(props, "uv_mode")
layout.label(text="Texture Maps:")
for texture_type in texture_maps:
add_texture_path(STYLE_TEXTURE_PROPS_MAP[texture_type])
+41 -29
View File
@@ -80,7 +80,7 @@ class Loader(blenderbim.core.tool.Loader):
# Transparency was added in IFC4
if transparency := surface_style.get("Transparency", None):
alpha = 1 - transparency
blender_material.diffuse_color = surface_style["SurfaceColour"][:3] + (alpha,)
blender_material.diffuse_color = surface_style["SurfaceColour"] + (alpha,)
blender_material.use_nodes = False
@classmethod
@@ -100,36 +100,39 @@ class Loader(blenderbim.core.tool.Loader):
if isinstance(surface_style, dict):
return surface_style
surface_style = surface_style.get_info()
color_to_tuple = lambda x: (x.Red, x.Green, x.Blue, 1)
color_to_tuple = lambda x: (x.Red, x.Green, x.Blue)
def convert_ifc_color_or_factor(color_or_factor):
if color_or_factor is None:
return
if color_or_factor.is_a("IfcColourRgb"):
return ("IfcColourRgb", color_to_tuple(color_or_factor))
# IfcNormalisedRatioMeasure
return ("IfcNormalisedRatioMeasure", color_or_factor.wrappedValue)
# can be only IfcColourRgb
if surface_style["SurfaceColour"]:
surface_style["SurfaceColour"] = color_to_tuple(surface_style["SurfaceColour"])
if surface_style.get("DiffuseColour", None) and surface_style["DiffuseColour"].is_a("IfcColourRgb"):
surface_style["DiffuseColour"] = ("IfcColourRgb", color_to_tuple(surface_style["DiffuseColour"]))
if surface_style["type"] == "IfcSurfaceStyleShading":
return surface_style
elif surface_style.get("DiffuseColour", None) and surface_style["DiffuseColour"].is_a(
"IfcNormalisedRatioMeasure"
):
diffuse_color_value = surface_style["DiffuseColour"].wrappedValue
diffuse_color = [v * diffuse_color_value for v in surface_style["SurfaceColour"][:3]] + [1]
surface_style["DiffuseColour"] = ("IfcNormalisedRatioMeasure", diffuse_color)
else:
surface_style["DiffuseColour"] = None
# IfcSurfaceStyleRendering
# IfcColourOrFactor
surface_style["DiffuseColour"] = convert_ifc_color_or_factor(surface_style["DiffuseColour"])
surface_style["SpecularColour"] = convert_ifc_color_or_factor(surface_style["SpecularColour"])
if surface_style.get("SpecularColour", None) and surface_style["SpecularColour"].is_a(
"IfcNormalisedRatioMeasure"
):
surface_style["SpecularColour"] = surface_style["SpecularColour"].wrappedValue
else:
surface_style["SpecularColour"] = None
if specular_highlight := surface_style["SpecularHighlight"]:
if specular_highlight.is_a("IfcSpecularRoughness"):
surface_style["SpecularHighlight"] = specular_highlight.wrappedValue
else: # discard IfcSpecularExponent value
surface_style["SpecularHighlight"] = None
# NOTE: IfcSurfaceStyleRendering also has following attributes but we ignore them
# as they're about to get deprecated:
# TransmissionColour, DiffuseTransmissionColour, ReflectionColour
if surface_style.get("SpecularHighlight", None) and surface_style["SpecularHighlight"].is_a(
"IfcSpecularRoughness"
):
surface_style["SpecularHighlight"] = surface_style["SpecularHighlight"].wrappedValue
else:
surface_style["SpecularHighlight"] = None
return surface_style
@classmethod
@@ -158,20 +161,29 @@ class Loader(blenderbim.core.tool.Loader):
print(f'WARNING. Unsupported reflectance method "{reflectance_method}" on style {surface_style}')
return
# TODO: reset pins to default values if no values passed
if reflectance_method in ["PHYSICAL", "NOTDEFINED"]:
blender_material.use_nodes = True
cls.restart_material_node_tree(blender_material)
bsdf = tool.Blender.get_material_node(blender_material, "BSDF_PRINCIPLED")
if surface_style["DiffuseColour"]:
color_type, color_value = surface_style["DiffuseColour"]
if color_type == "IfcColourRgb":
bsdf.inputs["Base Color"].default_value = color_value
elif color_type == "IfcNormalisedRatioMeasure":
bsdf.inputs["Base Color"].default_value = color_value
bsdf.inputs["Base Color"].default_value = color_value + (1,)
else: # "IfcNormalisedRatioMeasure"
color_value = [v * color_value for v in surface_style["SurfaceColour"]]
bsdf.inputs["Base Color"].default_value = color_value + (1,)
if surface_style["SpecularColour"]:
bsdf.inputs["Metallic"].default_value = surface_style["SpecularColour"]
color_type, color_value = surface_style["SpecularColour"]
if color_type == "IfcNormalisedRatioMeasure":
bsdf.inputs["Metallic"].default_value = color_value
# IfcColourRgb is ignored
if surface_style["SpecularHighlight"]:
bsdf.inputs["Roughness"].default_value = surface_style["SpecularHighlight"]
if transparency := surface_style.get("Transparency", None):
bsdf.inputs["Alpha"].default_value = 1 - transparency
blender_material.blend_method = "BLEND"
@@ -204,7 +216,7 @@ class Loader(blenderbim.core.tool.Loader):
if surface_style["DiffuseColour"]:
color_type, color_value = surface_style["DiffuseColour"]
if color_type == "IfcColourRgb":
rgb.outputs[0].default_value = color_value
rgb.outputs[0].default_value = color_value + (1,)
@classmethod
def create_surface_style_with_textures(cls, blender_material, rendering_style, texture_style):
+89 -63
View File
@@ -22,7 +22,7 @@ import ifcopenshell
import blenderbim.core.tool
import blenderbim.tool as tool
import blenderbim.bim.helper
import os.path
from mathutils import Color
# fmt: off
TEXTURE_MAPS_BY_METHODS = {
@@ -33,19 +33,11 @@ TEXTURE_MAPS_BY_METHODS = {
STYLE_PROPS_MAP = {
"reflectance_method": "ReflectanceMethod",
"diffuse_color": "DiffuseColour",
"surface_color": "SurfaceColour",
"diffuse_colour": "DiffuseColour",
"surface_colour": "SurfaceColour",
"transparency": "Transparency",
"roughness": "SpecularHighlight",
"metallic": "SpecularColour",
}
STYLE_TEXTURE_PROPS_MAP = {
"EMISSIVE": "emissive_path",
"NORMAL": "normal_path",
"METALLICROUGHNESS": "metallic_roughness_path",
"DIFFUSE": "diffuse_path",
"OCCLUSION": "occlusion_path",
"specular_highlight": "SpecularHighlight",
"specular_colour": "SpecularColour",
}
@@ -111,42 +103,60 @@ class Style(blenderbim.core.tool.Style):
return
@classmethod
def get_style_elements(cls, blender_material):
if not blender_material.BIMMaterialProperties.ifc_style_id:
return {}
style = tool.Ifc.get().by_id(blender_material.BIMMaterialProperties.ifc_style_id)
def get_style_elements(cls, blender_material_or_style):
if isinstance(blender_material_or_style, bpy.types.Material):
if not blender_material_or_style.BIMMaterialProperties.ifc_style_id:
return {}
style = tool.Ifc.get().by_id(blender_material_or_style.BIMMaterialProperties.ifc_style_id)
else:
style = blender_material_or_style
style_elements = {}
for style in style.Styles:
style_elements[style.is_a()] = style
return style_elements
@classmethod
def get_surface_style_from_props(cls, blender_material):
"""convert blender style props to ifc props"""
def get_shading_style_data_from_props(cls) -> dict:
"""returns style data from blender props in similar way to `Loader.surface_style_to_dict`
to be compatible with `Loader.create_surface_style_rendering`"""
surface_style_data = dict()
props = blender_material.BIMStyleProperties
props = bpy.context.scene.BIMStylesProperties
available_props = props.bl_rna.properties.keys()
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
surface_style_data[prop_ifc] = getattr(props, prop_blender)
if surface_style_data["ReflectanceMethod"] == "PHYSICAL" and tool.Ifc.get_schema() != "IFC4X3":
surface_style_data["ReflectanceMethod"] = "NOTDEFINED"
surface_style_data["DiffuseColour"] = ("IfcColourRgb", surface_style_data["DiffuseColour"])
class_prop_name = f"{prop_blender}_class"
# get detailed color properties if available
if class_prop_name in available_props:
prop_class = getattr(props, class_prop_name)
if prop_class == "IfcColourRgb":
prop_value = tuple(getattr(props, prop_blender))
else: # IfcNormalisedRatioMeasure
ratio_prop_name = f"{prop_blender}_ratio"
prop_value = getattr(props, ratio_prop_name)
prop_value = (prop_class, prop_value)
else:
prop_value = getattr(props, prop_blender)
if isinstance(prop_value, Color):
prop_value = tuple(prop_value)
surface_style_data[prop_ifc] = prop_value
return surface_style_data
@classmethod
def get_texture_style_from_props(cls, blender_material):
props = blender_material.BIMStyleProperties
def get_texture_style_data_from_props(cls) -> list[dict]:
"""returns style data from blender props in similar way to `Loader.surface_texture_to_dict`
to be compatible with `Loader.create_surface_style_with_textures`"""
props = bpy.context.scene.BIMStylesProperties
textures = []
texture_maps = TEXTURE_MAPS_BY_METHODS[props.reflectance_method]
for prop_mode in texture_maps:
prop_name = STYLE_TEXTURE_PROPS_MAP[prop_mode]
path = getattr(props, prop_name)
if not path:
for texture in props.textures:
if not texture.path:
continue
texture_data = {
"Mode": prop_mode,
"Mode": texture.mode,
"type": "IfcImageTexture",
"URLReference": tool.Blender.blender_path_to_posix(path),
"URLReference": texture.path,
"uv_mode": props.uv_mode,
}
textures.append(texture_data)
@@ -154,54 +164,70 @@ class Style(blenderbim.core.tool.Style):
return textures
@classmethod
def set_surface_style_props(cls, blender_material):
"""set blender style props based on current surface material"""
props = blender_material.BIMStyleProperties
def set_surface_style_props(cls):
"""set blender style props based on currently edited IfcSurfaceStyle,
reset unrelated props to default values"""
props = bpy.context.scene.BIMStylesProperties
style = tool.Ifc.get().by_id(props.is_editing_style)
# make sure won't be updating while we changing it
prev_update_graph_value = props.update_graph
props["update_graph"] = False
style_elements = tool.Style.get_style_elements(blender_material)
style_elements = tool.Style.get_style_elements(style)
surface_style = style_elements.get("IfcSurfaceStyleRendering", None)
if surface_style is None:
surface_style = style_elements.get("IfcSurfaceStyleShading", None)
style_data = tool.Loader.surface_style_to_dict(surface_style) if surface_style else {}
texture_style = style_elements.get("IfcSurfaceStyleWithTextures", None)
# in case we have just IfcSurfaceStyleShading
if not surface_style:
return
style_data = tool.Loader.surface_style_to_dict(surface_style)
if style_data["ReflectanceMethod"] == "NOTDEFINED":
style_data["ReflectanceMethod"] = "PHYSICAL"
diffuse_color = style_data["DiffuseColour"]
style_data["DiffuseColour"] = diffuse_color[1] if diffuse_color else None
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
prop_value = style_data[prop_ifc]
def set_prop(prop_blender, prop_value):
if prop_value is None:
prop_value = tool.Blender.get_blender_prop_default_value(props, prop_blender)
setattr(props, prop_blender, prop_value)
texture_maps = TEXTURE_MAPS_BY_METHODS[style_data["ReflectanceMethod"]]
unused_texture_maps = list(STYLE_TEXTURE_PROPS_MAP.keys())
available_props = props.bl_rna.properties.keys()
# fallback value for reflectance method
if style_data.get("ReflectanceMethod", None) is None:
style_data["ReflectanceMethod"] = "NOTDEFINED"
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
prop_value = style_data.get(prop_ifc, None)
is_null = prop_value is None
# set null property if available
null_prop_name = f"is_{prop_blender}_null"
if null_prop_name in available_props:
set_prop(null_prop_name, is_null)
# set detailed color properties if available
class_prop_name = f"{prop_blender}_class"
if class_prop_name in available_props:
prop_class, prop_value = prop_value or (None, None)
# set class enum
set_prop(class_prop_name, prop_class)
# set prop value
ratio_prop_name = f"{prop_blender}_ratio"
if prop_class == "IfcColourRgb":
set_prop(prop_blender, prop_value)
set_prop(ratio_prop_name, None)
else: # IfcNormalisedRatioMeasure
set_prop(ratio_prop_name, prop_value)
set_prop(prop_blender, None)
continue
set_prop(prop_blender, prop_value)
uv_mode = None
props.textures.clear()
if texture_style:
for texture in texture_style.Textures:
# we use surface_texture_to_dict as it calculates uv_mode
texture_data = tool.Loader.surface_texture_to_dict(texture)
texture_prop = props.textures.add()
texture_prop.mode = texture_data["Mode"]
texture_prop.path = texture_data["URLReference"]
uv_mode = texture_data["uv_mode"]
if texture.Mode not in texture_maps:
print(f"WARNING. Unsupported texture mode: {texture.Mode}. Supported maps: {texture_maps}")
continue
prop_blender = STYLE_TEXTURE_PROPS_MAP.get(texture.Mode, None)
setattr(props, prop_blender, texture.URLReference)
unused_texture_maps.remove(texture.Mode)
props.uv_mode = uv_mode if uv_mode else "UV"
# clear empty texture fields
for texture_mode in unused_texture_maps:
prop_blender = STYLE_TEXTURE_PROPS_MAP[texture_mode]
setattr(props, prop_blender, "")
props["update_graph"] = prev_update_graph_value
@classmethod
@@ -73,7 +73,7 @@ Scenario: Disable editing styles
And I add a material
And I press "bim.add_style"
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
When I press "bim.disable_editing_style"
When I press "bim.disable_editing_styles"
Then nothing happens
Scenario: Select by style
+7 -6
View File
@@ -48,11 +48,11 @@ class TestCreatingStyles(NewFile):
style_data = {
"ReflectanceMethod": "NOTDEFINED",
"DiffuseColour": ("IfcColourRgb", (0.5, 0.5, 0.5, 1.0)),
"SurfaceColour": (0.3, 0.3, 0.3, 1.0),
"DiffuseColour": ("IfcColourRgb", (0.5, 0.5, 0.5)),
"SurfaceColour": (0.3, 0.3, 0.3),
"Transparency": 0.3,
"SpecularHighlight": 0.4,
"SpecularColour": 0.03,
"SpecularColour": ("IfcNormalisedRatioMeasure", 0.03),
}
texture_data = [
{
@@ -71,12 +71,13 @@ class TestCreatingStyles(NewFile):
bsdf = tool.Blender.get_material_node(material, "BSDF_PRINCIPLED")
alpha = 1 - style_data["Transparency"]
diffuse_color = style_data["SurfaceColour"][:3] + (alpha,)
diffuse_color = style_data["SurfaceColour"] + (alpha,)
assert np.allclose(material.diffuse_color[:], diffuse_color)
assert np.allclose(bsdf.inputs["Base Color"].default_value[:], style_data["DiffuseColour"][1])
base_color = style_data["DiffuseColour"][1] + (1.0,)
assert np.allclose(bsdf.inputs["Base Color"].default_value[:], base_color)
assert np.isclose(bsdf.inputs["Alpha"].default_value, alpha)
assert np.isclose(bsdf.inputs["Roughness"].default_value, style_data["SpecularHighlight"])
assert np.isclose(bsdf.inputs["Metallic"].default_value, style_data["SpecularColour"])
assert np.isclose(bsdf.inputs["Metallic"].default_value, style_data["SpecularColour"][1])
image_node = tool.Blender.get_material_node(material, "TEX_IMAGE")
assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color"