mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-09 13:52:23 +00:00
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:
@@ -23,8 +23,9 @@ classes = (
|
|||||||
operator.ActivateExternalStyle,
|
operator.ActivateExternalStyle,
|
||||||
operator.AddPresentationStyle,
|
operator.AddPresentationStyle,
|
||||||
operator.AddStyle,
|
operator.AddStyle,
|
||||||
|
operator.AddSurfaceTexture,
|
||||||
operator.BrowseExternalStyle,
|
operator.BrowseExternalStyle,
|
||||||
operator.ClearTextureMapPath,
|
operator.RemoveTextureMap,
|
||||||
operator.ChooseTextureMapPath,
|
operator.ChooseTextureMapPath,
|
||||||
operator.DisableAddingPresentationStyle,
|
operator.DisableAddingPresentationStyle,
|
||||||
operator.DisableEditingExternalStyle,
|
operator.DisableEditingExternalStyle,
|
||||||
@@ -46,6 +47,7 @@ classes = (
|
|||||||
operator.UpdateStyleColours,
|
operator.UpdateStyleColours,
|
||||||
operator.UpdateStyleTextures,
|
operator.UpdateStyleTextures,
|
||||||
prop.Style,
|
prop.Style,
|
||||||
|
prop.Texture,
|
||||||
prop.BIMStylesProperties,
|
prop.BIMStylesProperties,
|
||||||
prop.BIMStyleProperties,
|
prop.BIMStyleProperties,
|
||||||
ui.BIM_PT_styles,
|
ui.BIM_PT_styles,
|
||||||
@@ -53,7 +55,6 @@ classes = (
|
|||||||
ui.BIM_PT_style_attributes,
|
ui.BIM_PT_style_attributes,
|
||||||
ui.BIM_PT_external_style_attributes,
|
ui.BIM_PT_external_style_attributes,
|
||||||
ui.BIM_UL_styles,
|
ui.BIM_UL_styles,
|
||||||
ui.BIM_PT_STYLE_GRAPH,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,23 @@ class StylesData:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
cls.data = {
|
cls.data = {
|
||||||
|
"styles_to_blender_material_names": cls.styles_to_blender_material_names(),
|
||||||
"style_types": cls.style_types(),
|
"style_types": cls.style_types(),
|
||||||
"total_styles": cls.total_styles(),
|
"total_styles": cls.total_styles(),
|
||||||
"reflectance_methods": cls.reflectance_methods(),
|
"reflectance_methods": cls.reflectance_methods(),
|
||||||
}
|
}
|
||||||
cls.is_loaded = True
|
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
|
@classmethod
|
||||||
def reflectance_methods(cls):
|
def reflectance_methods(cls):
|
||||||
declaration = tool.Ifc.schema().declaration_by_name("IfcReflectanceMethodEnum")
|
declaration = tool.Ifc.schema().declaration_by_name("IfcReflectanceMethodEnum")
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ import blenderbim.tool as tool
|
|||||||
import blenderbim.core.style as core
|
import blenderbim.core.style as core
|
||||||
import ifcopenshell.util.representation
|
import ifcopenshell.util.representation
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.module.style.data import StyleAttributesData
|
||||||
from blenderbim.bim.module.style.data import StylesData, StyleAttributesData
|
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
|
||||||
|
|
||||||
@@ -33,14 +32,15 @@ class UpdateStyleColours(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
bl_idname = "bim.update_style_colours"
|
bl_idname = "bim.update_style_colours"
|
||||||
bl_label = "Save Current Shading Style"
|
bl_label = "Save Current Shading Style"
|
||||||
bl_description = (
|
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"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
verbose: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
|
verbose: bpy.props.BoolProperty(default=False, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
def invoke(self, context, event):
|
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
|
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
|
||||||
if event.type == "LEFTMOUSE" and event.alt:
|
if event.type == "LEFTMOUSE" and event.alt:
|
||||||
self.verbose = True
|
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)
|
core.update_style_colours(tool.Ifc, tool.Style, obj=mat, verbose=self.verbose)
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
self.report({"INFO"}, "Check the system console to see saved style properties")
|
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):
|
class UpdateStyleTextures(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.update_style_textures"
|
bl_idname = "bim.update_style_textures"
|
||||||
bl_label = "Update Style Textures"
|
bl_label = "Update Style Textures"
|
||||||
|
bl_description = "Update IfcSurfaceStyleWithTextures based on current blender material shading graph"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
@@ -82,6 +82,7 @@ class RemoveStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class AddStyle(bpy.types.Operator, tool.Ifc.Operator):
|
class AddStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.add_style"
|
bl_idname = "bim.add_style"
|
||||||
bl_label = "Add Style"
|
bl_label = "Add Style"
|
||||||
|
bl_description = "Add IfcSurfaceStyle to the active material"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
@@ -120,6 +121,12 @@ class DisableEditingStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = bpy.context.scene.BIMStylesProperties
|
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
|
props.is_editing_style = 0
|
||||||
|
|
||||||
|
|
||||||
@@ -146,19 +153,14 @@ class UpdateCurrentStyle(bpy.types.Operator):
|
|||||||
)
|
)
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
update_all: bpy.props.BoolProperty(name="Update All", default=False, options={"SKIP_SAVE"})
|
update_all: bpy.props.BoolProperty(name="Update All", default=False, options={"SKIP_SAVE"})
|
||||||
|
style_id: bpy.props.IntProperty(default=0, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
poll = (
|
if not context.selected_objects:
|
||||||
context.active_object is not None
|
cls.poll_message_set("No objects selected")
|
||||||
and context.active_object.active_material is not None
|
return False
|
||||||
and context.active_object.active_material.BIMMaterialProperties.ifc_style_id != 0
|
return True
|
||||||
)
|
|
||||||
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
|
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
# updating all styles on shift+click
|
# updating all styles on shift+click
|
||||||
@@ -168,16 +170,18 @@ class UpdateCurrentStyle(bpy.types.Operator):
|
|||||||
return self.execute(context)
|
return self.execute(context)
|
||||||
|
|
||||||
def execute(self, 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:
|
if self.update_all:
|
||||||
context.scene.BIMStylesProperties.active_style_type = current_style_type
|
context.scene.BIMStylesProperties.active_style_type = current_style_type
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
materials = []
|
|
||||||
for obj in context.selected_objects:
|
for obj in context.selected_objects:
|
||||||
mat = obj.active_material
|
for mat in obj.data.materials:
|
||||||
if mat and mat.BIMMaterialProperties.ifc_style_id != 0:
|
if mat and mat.BIMMaterialProperties.ifc_style_id != 0:
|
||||||
mat.BIMStyleProperties.active_style_type = current_style_type
|
mat.BIMStyleProperties.active_style_type = current_style_type
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -231,7 +235,9 @@ class BrowseExternalStyle(bpy.types.Operator):
|
|||||||
description="List of objects in the .blend file",
|
description="List of objects in the .blend file",
|
||||||
items=get_data_blocks,
|
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(
|
directory: bpy.props.StringProperty(
|
||||||
name="Directory",
|
name="Directory",
|
||||||
description="Start file browsing directory",
|
description="Start file browsing directory",
|
||||||
@@ -266,11 +272,11 @@ class BrowseExternalStyle(bpy.types.Operator):
|
|||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
if self.data_block_type == "0":
|
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"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
if self.data_block == "":
|
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"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
if not os.path.exists(self.filepath):
|
if not os.path.exists(self.filepath):
|
||||||
@@ -413,10 +419,12 @@ class SelectByStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
class ChooseTextureMapPath(bpy.types.Operator):
|
class ChooseTextureMapPath(bpy.types.Operator):
|
||||||
bl_idname = "bim.choose_texture_map_path"
|
bl_idname = "bim.choose_texture_map_path"
|
||||||
bl_label = "Choose Texture Map Path"
|
bl_label = "Choose Texture Map Path"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
||||||
texture_map_prop: bpy.props.StringProperty(default="")
|
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(
|
filepath: bpy.props.StringProperty(
|
||||||
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
|
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)
|
context.window_manager.fileselect_add(self)
|
||||||
return {"RUNNING_MODAL"}
|
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):
|
def execute(self, context):
|
||||||
if not self.texture_map_prop:
|
if self.texture_map_index < 0:
|
||||||
self.report({"ERROR"}, "Provide a texture map")
|
self.report({"ERROR"}, "Provide a texture map index")
|
||||||
return {"CANCELLED"}
|
return {"CANCELLED"}
|
||||||
|
|
||||||
abs_path = Path(self.filepath)
|
abs_path = Path(self.filepath)
|
||||||
@@ -445,30 +446,26 @@ class ChooseTextureMapPath(bpy.types.Operator):
|
|||||||
else:
|
else:
|
||||||
image_filepath = abs_path
|
image_filepath = abs_path
|
||||||
|
|
||||||
props = context.material.BIMStyleProperties
|
texture = context.scene.BIMStylesProperties.textures[self.texture_map_index]
|
||||||
setattr(props, self.texture_map_prop, image_filepath.as_posix())
|
texture.path = image_filepath.as_posix()
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
class ClearTextureMapPath(bpy.types.Operator):
|
class RemoveTextureMap(bpy.types.Operator):
|
||||||
bl_idname = "bim.clear_texture_map_path"
|
bl_idname = "bim.remove_texture_map"
|
||||||
bl_label = "Clear Texture Map Path"
|
bl_label = "Remove Texture Map"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
||||||
texture_map_prop: bpy.props.StringProperty(default="")
|
texture_map_index: bpy.props.IntProperty(default=-1, options={"SKIP_SAVE"})
|
||||||
|
|
||||||
@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):
|
def execute(self, context):
|
||||||
if not self.texture_map_prop:
|
if self.texture_map_index < 0:
|
||||||
self.report({"ERROR"}, "Provide a texture map")
|
self.report({"ERROR"}, "Provide a texture map index")
|
||||||
return {"CANCELLED"}
|
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"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
@@ -546,74 +543,15 @@ class EnableEditingSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = bpy.context.scene.BIMStylesProperties
|
props = bpy.context.scene.BIMStylesProperties
|
||||||
style = tool.Ifc.get().by_id(self.style)
|
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_style = self.style
|
||||||
props.is_editing_class = self.ifc_class
|
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):
|
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.props = bpy.context.scene.BIMStylesProperties
|
||||||
self.style = tool.Ifc.get().by_id(self.props.is_editing_style)
|
self.style = tool.Ifc.get().by_id(self.props.is_editing_style)
|
||||||
|
|
||||||
self.surface_style = None
|
style_elements = tool.Style.get_style_elements(self.style)
|
||||||
self.shading_style = None
|
self.surface_style = style_elements.get(self.props.is_editing_class, None)
|
||||||
self.rendering_style = None
|
self.shading_style = style_elements.get("IfcSurfaceStyleShading", None)
|
||||||
for style2 in self.style.Styles:
|
self.rendering_style = style_elements.get("IfcSurfaceStyleRendering", None)
|
||||||
if style2.is_a() == self.props.is_editing_class:
|
self.texture_style = style_elements.get("IfcSurfaceStyleWithTextures", None)
|
||||||
self.surface_style = style2
|
|
||||||
if style2.is_a() == "IfcSurfaceStyleShading":
|
|
||||||
self.shading_style = style2
|
|
||||||
if style2.is_a() == "IfcSurfaceStyleRendering":
|
|
||||||
self.rendering_style = style2
|
|
||||||
|
|
||||||
if self.surface_style:
|
if self.surface_style:
|
||||||
self.edit_existing_style()
|
self.edit_existing_style()
|
||||||
@@ -665,8 +598,27 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
attributes=self.get_rendering_attributes(),
|
attributes=self.get_rendering_attributes(),
|
||||||
)
|
)
|
||||||
tool.Loader.create_surface_style_rendering(material, self.surface_style)
|
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":
|
elif self.surface_style.is_a() == "IfcExternallyDefinedSurfaceStyle":
|
||||||
surface_style = ifcopenshell.api.run(
|
ifcopenshell.api.run(
|
||||||
"style.edit_surface_style",
|
"style.edit_surface_style",
|
||||||
tool.Ifc.get(),
|
tool.Ifc.get(),
|
||||||
style=self.surface_style,
|
style=self.surface_style,
|
||||||
@@ -693,6 +645,30 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
attributes=self.get_rendering_attributes(),
|
attributes=self.get_rendering_attributes(),
|
||||||
)
|
)
|
||||||
tool.Loader.create_surface_style_rendering(material, surface_style)
|
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":
|
elif self.props.is_editing_class == "IfcExternallyDefinedSurfaceStyle":
|
||||||
surface_style = ifcopenshell.api.run(
|
surface_style = ifcopenshell.api.run(
|
||||||
"style.add_surface_style",
|
"style.add_surface_style",
|
||||||
@@ -726,7 +702,7 @@ class EditSurfaceStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
if self.props.is_specular_highlight_null:
|
if self.props.is_specular_highlight_null:
|
||||||
specular_highlight = None
|
specular_highlight = None
|
||||||
else:
|
else:
|
||||||
specular_highlight = {"SpecularRoughness": self.props.specular_highlight}
|
specular_highlight = {"IfcSpecularRoughness": self.props.specular_highlight}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"SurfaceColour": self.color_to_dict(self.props.surface_colour),
|
"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]}
|
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):
|
class SaveUVToStyle(bpy.types.Operator, tool.Ifc.Operator):
|
||||||
bl_idname = "bim.save_uv_to_style"
|
bl_idname = "bim.save_uv_to_style"
|
||||||
bl_label = "Save UV To Style"
|
bl_label = "Save UV To Style"
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
from blenderbim.bim.ifc import IfcStore
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
from blenderbim.bim.module.style.data import StylesData
|
from blenderbim.bim.module.style.data import StylesData
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
@@ -31,7 +31,6 @@ from bpy.props import (
|
|||||||
FloatVectorProperty,
|
FloatVectorProperty,
|
||||||
CollectionProperty,
|
CollectionProperty,
|
||||||
)
|
)
|
||||||
import blenderbim.tool as tool
|
|
||||||
|
|
||||||
|
|
||||||
def get_style_types(self, context):
|
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)
|
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):
|
class BIMStylesProperties(PropertyGroup):
|
||||||
is_adding: BoolProperty(name="Is Adding")
|
is_adding: BoolProperty(name="Is Adding")
|
||||||
is_editing: BoolProperty(name="Is Editing")
|
is_editing: BoolProperty(name="Is Editing")
|
||||||
@@ -98,31 +136,81 @@ class BIMStylesProperties(PropertyGroup):
|
|||||||
name="Surface Style Class",
|
name="Surface Style Class",
|
||||||
default="IfcSurfaceStyleShading",
|
default="IfcSurfaceStyleShading",
|
||||||
)
|
)
|
||||||
surface_colour: bpy.props.FloatVectorProperty(
|
update_graph: BoolProperty(
|
||||||
name="Surface Colour", subtype="COLOR", default=(1, 1, 1), min=0.0, max=1.0, size=3
|
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")
|
is_diffuse_colour_null: BoolProperty(name="Is Null")
|
||||||
diffuse_colour_class: EnumProperty(
|
diffuse_colour_class: EnumProperty(
|
||||||
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
|
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
|
||||||
name="Diffuse Colour Class",
|
name="Diffuse Colour Class",
|
||||||
|
update=update_shader_graph,
|
||||||
)
|
)
|
||||||
diffuse_colour: bpy.props.FloatVectorProperty(
|
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")
|
is_specular_colour_null: BoolProperty(name="Is Null")
|
||||||
specular_colour_class: EnumProperty(
|
specular_colour_class: EnumProperty(
|
||||||
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
|
items=[(x, x, "") for x in ("IfcColourRgb", "IfcNormalisedRatioMeasure")],
|
||||||
name="Specular Colour Class",
|
name="Specular Colour Class",
|
||||||
|
update=update_shader_graph,
|
||||||
|
default="IfcNormalisedRatioMeasure",
|
||||||
)
|
)
|
||||||
specular_colour: bpy.props.FloatVectorProperty(
|
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")
|
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)
|
specular_highlight: bpy.props.FloatProperty(
|
||||||
reflectance_method: EnumProperty(name="Reflectance Method", items=get_reflectance_methods)
|
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)
|
styles: CollectionProperty(name="Styles", type=Style)
|
||||||
active_style_index: IntProperty(name="Active Style Index")
|
active_style_index: IntProperty(name="Active Style Index")
|
||||||
active_style_type: EnumProperty(
|
active_style_type: EnumProperty(
|
||||||
@@ -157,54 +245,13 @@ def update_shading_style(self, context):
|
|||||||
|
|
||||||
if rendering_style and texture_style:
|
if rendering_style and texture_style:
|
||||||
tool.Loader.create_surface_style_with_textures(blender_material, rendering_style, 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)
|
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):
|
class BIMStyleProperties(PropertyGroup):
|
||||||
|
# TODO: remove, as attributes already moved to styles ui
|
||||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||||
is_editing: BoolProperty(name="Is Editing")
|
is_editing: BoolProperty(name="Is Editing")
|
||||||
|
|
||||||
external_style_attributes: CollectionProperty(name="External Style Attributes", type=Attribute)
|
external_style_attributes: CollectionProperty(name="External Style Attributes", type=Attribute)
|
||||||
is_editing_external_style: BoolProperty(name="Is Editing External Style")
|
is_editing_external_style: BoolProperty(name="Is Editing External Style")
|
||||||
|
|
||||||
@@ -215,85 +262,3 @@ class BIMStyleProperties(PropertyGroup):
|
|||||||
default="Shading",
|
default="Shading",
|
||||||
update=update_shading_style,
|
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 bpy
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
|
import blenderbim.tool as tool
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.module.style.data import StylesData, StyleAttributesData
|
from blenderbim.bim.module.style.data import StylesData, StyleAttributesData
|
||||||
from bl_ui.properties_material import MaterialButtonsPanel
|
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):
|
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")
|
self.layout.template_list("BIM_UL_styles", "", self.props, "styles", self.props, "active_style_index")
|
||||||
|
|
||||||
|
# adding a new IfcSurfaceStyle
|
||||||
if self.props.is_adding:
|
if self.props.is_adding:
|
||||||
box = self.layout.box()
|
box = self.layout.box()
|
||||||
row = box.row()
|
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.add_presentation_style", text="Save New Style", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_adding_presentation_style", text="", icon="CANCEL")
|
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):
|
if self.props.styles and self.props.active_style_index < len(self.props.styles):
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
style = self.props.styles[self.props.active_style_index]
|
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 = row.operator("bim.enable_editing_style", text="Edit Style", icon="GREASEPENCIL")
|
||||||
op.style = style.ifc_definition_id
|
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.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.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":
|
if self.props.style_type == "IfcSurfaceStyle":
|
||||||
self.layout.label(text="Surface Style Element:")
|
self.layout.label(text="Surface Style Element:")
|
||||||
col = self.layout.column(align=True)
|
col = self.layout.column(align=True)
|
||||||
@@ -109,6 +119,7 @@ class BIM_PT_styles(Panel):
|
|||||||
op.ifc_class = "IfcExternallyDefinedSurfaceStyle"
|
op.ifc_class = "IfcExternallyDefinedSurfaceStyle"
|
||||||
op.style = style.ifc_definition_id
|
op.style = style.ifc_definition_id
|
||||||
|
|
||||||
|
# display style elements props during edit
|
||||||
if self.props.is_editing_style:
|
if self.props.is_editing_style:
|
||||||
if self.props.is_editing_class == "IfcSurfaceStyle":
|
if self.props.is_editing_class == "IfcSurfaceStyle":
|
||||||
blenderbim.bim.helper.draw_attributes(self.props.attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.attributes, self.layout)
|
||||||
@@ -121,8 +132,10 @@ class BIM_PT_styles(Panel):
|
|||||||
self.draw_surface_style_rendering()
|
self.draw_surface_style_rendering()
|
||||||
elif self.props.is_editing_class == "IfcExternallyDefinedSurfaceStyle":
|
elif self.props.is_editing_class == "IfcExternallyDefinedSurfaceStyle":
|
||||||
self.draw_externally_defined_surface_style()
|
self.draw_externally_defined_surface_style()
|
||||||
|
elif self.props.is_editing_class == "IfcSurfaceStyleWithTextures":
|
||||||
|
self.draw_surface_style_with_textures()
|
||||||
else:
|
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.")
|
self.layout.label(text=f"{self.props.is_editing_class} UI is not yet supported.")
|
||||||
|
|
||||||
def draw_surface_style_shading(self):
|
def draw_surface_style_shading(self):
|
||||||
@@ -142,8 +155,12 @@ class BIM_PT_styles(Panel):
|
|||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.prop(self.props, "reflectance_method")
|
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 = 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="")
|
row.prop(self.props, "diffuse_colour_class", text="")
|
||||||
if self.props.diffuse_colour_class == "IfcColourRgb":
|
if self.props.diffuse_colour_class == "IfcColourRgb":
|
||||||
row.prop(self.props, "diffuse_colour", text="")
|
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.edit_surface_style", text="Save Rendering Style", icon="CHECKMARK")
|
||||||
row.operator("bim.disable_editing_style", text="", icon="CANCEL")
|
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):
|
def draw_externally_defined_surface_style(self):
|
||||||
blenderbim.bim.helper.draw_attributes(self.props.external_style_attributes, self.layout)
|
blenderbim.bim.helper.draw_attributes(self.props.external_style_attributes, self.layout)
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
@@ -199,24 +238,6 @@ class BIM_PT_styles(Panel):
|
|||||||
row.operator("bim.disable_editing_style", text="", icon="CANCEL")
|
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):
|
class BIM_PT_style(MaterialButtonsPanel, Panel):
|
||||||
bl_label = "Style"
|
bl_label = "Style"
|
||||||
bl_idname = "BIM_PT_style"
|
bl_idname = "BIM_PT_style"
|
||||||
@@ -235,11 +256,15 @@ class BIM_PT_style(MaterialButtonsPanel, Panel):
|
|||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
mat = context.material
|
mat = context.material
|
||||||
props = mat.BIMMaterialProperties
|
props = mat.BIMMaterialProperties
|
||||||
draw_style_ui(self, context)
|
row = self.layout.row(align=True)
|
||||||
if not props.ifc_style_id:
|
if not props.ifc_style_id:
|
||||||
|
row.operator("bim.add_style", icon="ADD")
|
||||||
return
|
return
|
||||||
row = self.layout.row(align=True)
|
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):
|
class BIM_PT_style_attributes(Panel):
|
||||||
@@ -369,66 +394,3 @@ class BIM_UL_styles(UIList):
|
|||||||
row2.label(text="", icon="LIGHT_POINT")
|
row2.label(text="", icon="LIGHT_POINT")
|
||||||
elif style.name == "IfcExternallyDefinedSurfaceStyle":
|
elif style.name == "IfcExternallyDefinedSurfaceStyle":
|
||||||
row2.label(text="", icon="APPEND_BLEND")
|
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])
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
# Transparency was added in IFC4
|
# Transparency was added in IFC4
|
||||||
if transparency := surface_style.get("Transparency", None):
|
if transparency := surface_style.get("Transparency", None):
|
||||||
alpha = 1 - transparency
|
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
|
blender_material.use_nodes = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -100,36 +100,39 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
if isinstance(surface_style, dict):
|
if isinstance(surface_style, dict):
|
||||||
return surface_style
|
return surface_style
|
||||||
surface_style = surface_style.get_info()
|
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"]:
|
if surface_style["SurfaceColour"]:
|
||||||
surface_style["SurfaceColour"] = color_to_tuple(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"):
|
if surface_style["type"] == "IfcSurfaceStyleShading":
|
||||||
surface_style["DiffuseColour"] = ("IfcColourRgb", color_to_tuple(surface_style["DiffuseColour"]))
|
return surface_style
|
||||||
|
|
||||||
elif surface_style.get("DiffuseColour", None) and surface_style["DiffuseColour"].is_a(
|
# IfcSurfaceStyleRendering
|
||||||
"IfcNormalisedRatioMeasure"
|
# IfcColourOrFactor
|
||||||
):
|
surface_style["DiffuseColour"] = convert_ifc_color_or_factor(surface_style["DiffuseColour"])
|
||||||
diffuse_color_value = surface_style["DiffuseColour"].wrappedValue
|
surface_style["SpecularColour"] = convert_ifc_color_or_factor(surface_style["SpecularColour"])
|
||||||
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
|
|
||||||
|
|
||||||
if surface_style.get("SpecularColour", None) and surface_style["SpecularColour"].is_a(
|
if specular_highlight := surface_style["SpecularHighlight"]:
|
||||||
"IfcNormalisedRatioMeasure"
|
if specular_highlight.is_a("IfcSpecularRoughness"):
|
||||||
):
|
surface_style["SpecularHighlight"] = specular_highlight.wrappedValue
|
||||||
surface_style["SpecularColour"] = surface_style["SpecularColour"].wrappedValue
|
else: # discard IfcSpecularExponent value
|
||||||
else:
|
surface_style["SpecularHighlight"] = None
|
||||||
surface_style["SpecularColour"] = 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
|
return surface_style
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -158,20 +161,29 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
print(f'WARNING. Unsupported reflectance method "{reflectance_method}" on style {surface_style}')
|
print(f'WARNING. Unsupported reflectance method "{reflectance_method}" on style {surface_style}')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# TODO: reset pins to default values if no values passed
|
||||||
if reflectance_method in ["PHYSICAL", "NOTDEFINED"]:
|
if reflectance_method in ["PHYSICAL", "NOTDEFINED"]:
|
||||||
blender_material.use_nodes = True
|
blender_material.use_nodes = True
|
||||||
cls.restart_material_node_tree(blender_material)
|
cls.restart_material_node_tree(blender_material)
|
||||||
bsdf = tool.Blender.get_material_node(blender_material, "BSDF_PRINCIPLED")
|
bsdf = tool.Blender.get_material_node(blender_material, "BSDF_PRINCIPLED")
|
||||||
|
|
||||||
if surface_style["DiffuseColour"]:
|
if surface_style["DiffuseColour"]:
|
||||||
color_type, color_value = surface_style["DiffuseColour"]
|
color_type, color_value = surface_style["DiffuseColour"]
|
||||||
if color_type == "IfcColourRgb":
|
if color_type == "IfcColourRgb":
|
||||||
bsdf.inputs["Base Color"].default_value = color_value
|
bsdf.inputs["Base Color"].default_value = color_value + (1,)
|
||||||
elif color_type == "IfcNormalisedRatioMeasure":
|
else: # "IfcNormalisedRatioMeasure"
|
||||||
bsdf.inputs["Base Color"].default_value = color_value
|
color_value = [v * color_value for v in surface_style["SurfaceColour"]]
|
||||||
|
bsdf.inputs["Base Color"].default_value = color_value + (1,)
|
||||||
|
|
||||||
if surface_style["SpecularColour"]:
|
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"]:
|
if surface_style["SpecularHighlight"]:
|
||||||
bsdf.inputs["Roughness"].default_value = surface_style["SpecularHighlight"]
|
bsdf.inputs["Roughness"].default_value = surface_style["SpecularHighlight"]
|
||||||
|
|
||||||
if transparency := surface_style.get("Transparency", None):
|
if transparency := surface_style.get("Transparency", None):
|
||||||
bsdf.inputs["Alpha"].default_value = 1 - transparency
|
bsdf.inputs["Alpha"].default_value = 1 - transparency
|
||||||
blender_material.blend_method = "BLEND"
|
blender_material.blend_method = "BLEND"
|
||||||
@@ -204,7 +216,7 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
if surface_style["DiffuseColour"]:
|
if surface_style["DiffuseColour"]:
|
||||||
color_type, color_value = surface_style["DiffuseColour"]
|
color_type, color_value = surface_style["DiffuseColour"]
|
||||||
if color_type == "IfcColourRgb":
|
if color_type == "IfcColourRgb":
|
||||||
rgb.outputs[0].default_value = color_value
|
rgb.outputs[0].default_value = color_value + (1,)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_surface_style_with_textures(cls, blender_material, rendering_style, texture_style):
|
def create_surface_style_with_textures(cls, blender_material, rendering_style, texture_style):
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import ifcopenshell
|
|||||||
import blenderbim.core.tool
|
import blenderbim.core.tool
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
import os.path
|
from mathutils import Color
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
TEXTURE_MAPS_BY_METHODS = {
|
TEXTURE_MAPS_BY_METHODS = {
|
||||||
@@ -33,19 +33,11 @@ TEXTURE_MAPS_BY_METHODS = {
|
|||||||
|
|
||||||
STYLE_PROPS_MAP = {
|
STYLE_PROPS_MAP = {
|
||||||
"reflectance_method": "ReflectanceMethod",
|
"reflectance_method": "ReflectanceMethod",
|
||||||
"diffuse_color": "DiffuseColour",
|
"diffuse_colour": "DiffuseColour",
|
||||||
"surface_color": "SurfaceColour",
|
"surface_colour": "SurfaceColour",
|
||||||
"transparency": "Transparency",
|
"transparency": "Transparency",
|
||||||
"roughness": "SpecularHighlight",
|
"specular_highlight": "SpecularHighlight",
|
||||||
"metallic": "SpecularColour",
|
"specular_colour": "SpecularColour",
|
||||||
}
|
|
||||||
|
|
||||||
STYLE_TEXTURE_PROPS_MAP = {
|
|
||||||
"EMISSIVE": "emissive_path",
|
|
||||||
"NORMAL": "normal_path",
|
|
||||||
"METALLICROUGHNESS": "metallic_roughness_path",
|
|
||||||
"DIFFUSE": "diffuse_path",
|
|
||||||
"OCCLUSION": "occlusion_path",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -111,42 +103,60 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
return
|
return
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_style_elements(cls, blender_material):
|
def get_style_elements(cls, blender_material_or_style):
|
||||||
if not blender_material.BIMMaterialProperties.ifc_style_id:
|
if isinstance(blender_material_or_style, bpy.types.Material):
|
||||||
return {}
|
if not blender_material_or_style.BIMMaterialProperties.ifc_style_id:
|
||||||
style = tool.Ifc.get().by_id(blender_material.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 = {}
|
style_elements = {}
|
||||||
for style in style.Styles:
|
for style in style.Styles:
|
||||||
style_elements[style.is_a()] = style
|
style_elements[style.is_a()] = style
|
||||||
return style_elements
|
return style_elements
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_surface_style_from_props(cls, blender_material):
|
def get_shading_style_data_from_props(cls) -> dict:
|
||||||
"""convert blender style props to ifc props"""
|
"""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()
|
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():
|
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
|
||||||
surface_style_data[prop_ifc] = getattr(props, prop_blender)
|
class_prop_name = f"{prop_blender}_class"
|
||||||
if surface_style_data["ReflectanceMethod"] == "PHYSICAL" and tool.Ifc.get_schema() != "IFC4X3":
|
|
||||||
surface_style_data["ReflectanceMethod"] = "NOTDEFINED"
|
# get detailed color properties if available
|
||||||
surface_style_data["DiffuseColour"] = ("IfcColourRgb", surface_style_data["DiffuseColour"])
|
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
|
return surface_style_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_texture_style_from_props(cls, blender_material):
|
def get_texture_style_data_from_props(cls) -> list[dict]:
|
||||||
props = blender_material.BIMStyleProperties
|
"""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 = []
|
textures = []
|
||||||
texture_maps = TEXTURE_MAPS_BY_METHODS[props.reflectance_method]
|
for texture in props.textures:
|
||||||
for prop_mode in texture_maps:
|
if not texture.path:
|
||||||
prop_name = STYLE_TEXTURE_PROPS_MAP[prop_mode]
|
|
||||||
path = getattr(props, prop_name)
|
|
||||||
if not path:
|
|
||||||
continue
|
continue
|
||||||
texture_data = {
|
texture_data = {
|
||||||
"Mode": prop_mode,
|
"Mode": texture.mode,
|
||||||
"type": "IfcImageTexture",
|
"type": "IfcImageTexture",
|
||||||
"URLReference": tool.Blender.blender_path_to_posix(path),
|
"URLReference": texture.path,
|
||||||
"uv_mode": props.uv_mode,
|
"uv_mode": props.uv_mode,
|
||||||
}
|
}
|
||||||
textures.append(texture_data)
|
textures.append(texture_data)
|
||||||
@@ -154,54 +164,70 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
return textures
|
return textures
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_surface_style_props(cls, blender_material):
|
def set_surface_style_props(cls):
|
||||||
"""set blender style props based on current surface material"""
|
"""set blender style props based on currently edited IfcSurfaceStyle,
|
||||||
props = blender_material.BIMStyleProperties
|
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
|
# make sure won't be updating while we changing it
|
||||||
prev_update_graph_value = props.update_graph
|
prev_update_graph_value = props.update_graph
|
||||||
props["update_graph"] = False
|
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)
|
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)
|
texture_style = style_elements.get("IfcSurfaceStyleWithTextures", None)
|
||||||
|
|
||||||
# in case we have just IfcSurfaceStyleShading
|
def set_prop(prop_blender, prop_value):
|
||||||
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]
|
|
||||||
if prop_value is None:
|
if prop_value is None:
|
||||||
prop_value = tool.Blender.get_blender_prop_default_value(props, prop_blender)
|
prop_value = tool.Blender.get_blender_prop_default_value(props, prop_blender)
|
||||||
setattr(props, prop_blender, prop_value)
|
setattr(props, prop_blender, prop_value)
|
||||||
|
|
||||||
texture_maps = TEXTURE_MAPS_BY_METHODS[style_data["ReflectanceMethod"]]
|
available_props = props.bl_rna.properties.keys()
|
||||||
unused_texture_maps = list(STYLE_TEXTURE_PROPS_MAP.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
|
uv_mode = None
|
||||||
|
props.textures.clear()
|
||||||
if texture_style:
|
if texture_style:
|
||||||
for texture in texture_style.Textures:
|
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_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"]
|
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"
|
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
|
props["update_graph"] = prev_update_graph_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ Scenario: Disable editing styles
|
|||||||
And I add a material
|
And I add a material
|
||||||
And I press "bim.add_style"
|
And I press "bim.add_style"
|
||||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
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
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Select by style
|
Scenario: Select by style
|
||||||
|
|||||||
@@ -48,11 +48,11 @@ class TestCreatingStyles(NewFile):
|
|||||||
|
|
||||||
style_data = {
|
style_data = {
|
||||||
"ReflectanceMethod": "NOTDEFINED",
|
"ReflectanceMethod": "NOTDEFINED",
|
||||||
"DiffuseColour": ("IfcColourRgb", (0.5, 0.5, 0.5, 1.0)),
|
"DiffuseColour": ("IfcColourRgb", (0.5, 0.5, 0.5)),
|
||||||
"SurfaceColour": (0.3, 0.3, 0.3, 1.0),
|
"SurfaceColour": (0.3, 0.3, 0.3),
|
||||||
"Transparency": 0.3,
|
"Transparency": 0.3,
|
||||||
"SpecularHighlight": 0.4,
|
"SpecularHighlight": 0.4,
|
||||||
"SpecularColour": 0.03,
|
"SpecularColour": ("IfcNormalisedRatioMeasure", 0.03),
|
||||||
}
|
}
|
||||||
texture_data = [
|
texture_data = [
|
||||||
{
|
{
|
||||||
@@ -71,12 +71,13 @@ class TestCreatingStyles(NewFile):
|
|||||||
|
|
||||||
bsdf = tool.Blender.get_material_node(material, "BSDF_PRINCIPLED")
|
bsdf = tool.Blender.get_material_node(material, "BSDF_PRINCIPLED")
|
||||||
alpha = 1 - style_data["Transparency"]
|
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(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["Alpha"].default_value, alpha)
|
||||||
assert np.isclose(bsdf.inputs["Roughness"].default_value, style_data["SpecularHighlight"])
|
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")
|
image_node = tool.Blender.get_material_node(material, "TEX_IMAGE")
|
||||||
assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color"
|
assert image_node.outputs["Color"].links[0].to_socket.name == "Base Color"
|
||||||
|
|||||||
Reference in New Issue
Block a user