mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Support for import IfcSurfaceStyleWithTextures
Added UI for adding textures in BBIM shader graph generator https://imgur.com/a/BI5pOZn
This commit is contained in:
@@ -37,6 +37,7 @@ classes = (
|
|||||||
operator.UnlinkStyle,
|
operator.UnlinkStyle,
|
||||||
operator.UpdateStyleColours,
|
operator.UpdateStyleColours,
|
||||||
operator.UpdateStyleTextures,
|
operator.UpdateStyleTextures,
|
||||||
|
operator.ClearTextureMapPath,
|
||||||
prop.Style,
|
prop.Style,
|
||||||
prop.BIMStylesProperties,
|
prop.BIMStylesProperties,
|
||||||
prop.BIMStyleProperties,
|
prop.BIMStyleProperties,
|
||||||
|
|||||||
@@ -392,3 +392,25 @@ class SelectByStyle(bpy.types.Operator, tool.Ifc.Operator):
|
|||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
core.select_by_style(tool.Style, tool.Spatial, style=tool.Ifc.get().by_id(self.style))
|
core.select_by_style(tool.Style, tool.Spatial, style=tool.Ifc.get().by_id(self.style))
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
if not self.texture_map_prop:
|
||||||
|
self.report({"ERROR"}, "Provide a texture map")
|
||||||
|
return {"CANCELLED"}
|
||||||
|
props = context.material.BIMStyleProperties
|
||||||
|
setattr(props, self.texture_map_prop, "")
|
||||||
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ def update_shading_style(self, context):
|
|||||||
tool.Style.record_shading(blender_material)
|
tool.Style.record_shading(blender_material)
|
||||||
|
|
||||||
|
|
||||||
# TODO: support more more methods and also textures
|
# TODO: support more more methods
|
||||||
REFLECTANCE_METHODS = [
|
REFLECTANCE_METHODS = [
|
||||||
("PHYSICAL", "PHYSICAL", ""),
|
("PHYSICAL", "PHYSICAL", ""),
|
||||||
("FLAT", "FLAT", ""),
|
("FLAT", "FLAT", ""),
|
||||||
@@ -117,7 +117,9 @@ def update_shader_graph(self, context):
|
|||||||
|
|
||||||
material = self.id_data
|
material = self.id_data
|
||||||
style_data = tool.Style.get_surface_style_from_props(material)
|
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_rendering(material, style_data)
|
||||||
|
tool.Loader.create_surface_style_with_textures(material, style_data, textures_data)
|
||||||
|
|
||||||
|
|
||||||
def update_graph_get(self):
|
def update_graph_get(self):
|
||||||
@@ -184,3 +186,32 @@ class BIMStyleProperties(PropertyGroup):
|
|||||||
)
|
)
|
||||||
roughness: bpy.props.FloatProperty(name="Roughness", 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)
|
metallic: bpy.props.FloatProperty(name="Metallic", default=0.0, min=0.0, max=1.0, update=update_shader_graph)
|
||||||
|
normal_path: bpy.props.StringProperty(
|
||||||
|
name="NormalMap",
|
||||||
|
maxlen=1024,
|
||||||
|
default="",
|
||||||
|
subtype="FILE_PATH",
|
||||||
|
update=update_shader_graph,
|
||||||
|
)
|
||||||
|
emissive_path: bpy.props.StringProperty(
|
||||||
|
name="Emissive",
|
||||||
|
maxlen=1024,
|
||||||
|
default="",
|
||||||
|
subtype="FILE_PATH",
|
||||||
|
update=update_shader_graph,
|
||||||
|
)
|
||||||
|
metallic_roughness_path: bpy.props.StringProperty(
|
||||||
|
name="Metallic/Roughness",
|
||||||
|
maxlen=1024,
|
||||||
|
default="",
|
||||||
|
subtype="FILE_PATH",
|
||||||
|
update=update_shader_graph,
|
||||||
|
description="Green Channel = Roughness,\nBlue Channel = Metallic",
|
||||||
|
)
|
||||||
|
diffuse_path: bpy.props.StringProperty(
|
||||||
|
name="Diffuse",
|
||||||
|
maxlen=1024,
|
||||||
|
default="",
|
||||||
|
subtype="FILE_PATH",
|
||||||
|
update=update_shader_graph,
|
||||||
|
)
|
||||||
|
|||||||
@@ -251,10 +251,34 @@ class BIM_PT_STYLE_GRAPH(Panel):
|
|||||||
layout.prop(props, "reflectance_method", text="")
|
layout.prop(props, "reflectance_method", text="")
|
||||||
layout.prop(props, "surface_color")
|
layout.prop(props, "surface_color")
|
||||||
layout.prop(props, "transparency")
|
layout.prop(props, "transparency")
|
||||||
layout.prop(props, "diffuse_color")
|
|
||||||
|
|
||||||
if props.reflectance_method == "PHYSICAL":
|
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")
|
layout.prop(props, "metallic")
|
||||||
|
|
||||||
if props.reflectance_method not in ("FLAT", "NOTDEFINED"):
|
if props.reflectance_method not in ("PHYSICAL", "FLAT", "NOTDEFINED") or (
|
||||||
|
props.reflectance_method == "PHYSICAL" and not props.metallic_roughness_path
|
||||||
|
):
|
||||||
layout.prop(props, "roughness")
|
layout.prop(props, "roughness")
|
||||||
|
|
||||||
|
layout.label(text="Texture Maps:")
|
||||||
|
|
||||||
|
def add_texture_path(path_name):
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(props, path_name)
|
||||||
|
op = row.operator("bim.clear_texture_map_path", text="", icon="X")
|
||||||
|
op.texture_map_prop = path_name
|
||||||
|
|
||||||
|
if props.reflectance_method == "PHYSICAL":
|
||||||
|
add_texture_path("diffuse_path")
|
||||||
|
add_texture_path("emissive_path")
|
||||||
|
add_texture_path("normal_path")
|
||||||
|
add_texture_path("metallic_roughness_path")
|
||||||
|
|
||||||
|
if props.reflectance_method == "FLAT":
|
||||||
|
add_texture_path("emissive_path")
|
||||||
|
|||||||
@@ -69,13 +69,18 @@ def update_style_colours(ifc, style, obj=None, verbose=False):
|
|||||||
"style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleRendering", attributes=attributes
|
"style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleRendering", attributes=attributes
|
||||||
)
|
)
|
||||||
|
|
||||||
# # TODO: uncomment to support saving textures
|
# TODO: uvs?
|
||||||
# # TODO: uvs?
|
textures = ifc.run("style.add_surface_textures", material=obj)
|
||||||
# textures = ifc.run("style.add_surface_textures", material=obj)
|
if not texture_style and textures:
|
||||||
# if not texture_style and textures:
|
ifc.run(
|
||||||
# texture_style = ifc.get().createIfcSurfaceStyleWithTextures()
|
"style.add_surface_style",
|
||||||
# if texture_style:
|
style=element,
|
||||||
# texture_style.Textures = textures
|
ifc_class="IfcSurfaceStyleWithTextures",
|
||||||
|
attributes={"Textures": textures},
|
||||||
|
)
|
||||||
|
elif texture_style:
|
||||||
|
# TODO: should we remove blender images and IFCIMAGETEXTURE here if they're not used by other objects?
|
||||||
|
ifc.run("style.edit_surface_style", style=texture_style, attributes={"Textures": textures})
|
||||||
else:
|
else:
|
||||||
shading_style = style.get_surface_shading_style(obj)
|
shading_style = style.get_surface_shading_style(obj)
|
||||||
attributes = style.get_surface_shading_attributes(obj)
|
attributes = style.get_surface_shading_attributes(obj)
|
||||||
|
|||||||
@@ -110,10 +110,21 @@ class Blender:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def show_error_message(cls, text):
|
def show_error_message(cls, text):
|
||||||
"""useful for showing error messages outside blender operators"""
|
"""useful for showing error messages outside blender operators"""
|
||||||
|
|
||||||
def error(self, context):
|
def error(self, context):
|
||||||
self.layout.label(text=text)
|
self.layout.label(text=text)
|
||||||
|
|
||||||
bpy.context.window_manager.popup_menu(error, title="Error", icon="ERROR")
|
bpy.context.window_manager.popup_menu(error, title="Error", icon="ERROR")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_blender_prop_default_value(cls, props, prop_name):
|
||||||
|
prop_bl_rna = props.bl_rna.properties[prop_name]
|
||||||
|
if getattr(prop_bl_rna, "array_length", 0) > 0:
|
||||||
|
prop_value = prop_bl_rna.default_array
|
||||||
|
else:
|
||||||
|
prop_value = prop_bl_rna.default
|
||||||
|
return prop_value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_viewport_context(cls):
|
def get_viewport_context(cls):
|
||||||
"""Get viewport area context for context overriding.
|
"""Get viewport area context for context overriding.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import blenderbim.core.tool
|
|||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
import os
|
import os
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
# Progressively we'll refactor loading elements into Blender objects into this
|
# Progressively we'll refactor loading elements into Blender objects into this
|
||||||
@@ -168,31 +169,43 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
|
|
||||||
@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):
|
||||||
for texture in texture_style.Textures:
|
"""supposed to be called after `create_surface_style_rendering`"""
|
||||||
mode = getattr(texture, "Mode", None)
|
if not isinstance(texture_style, list):
|
||||||
|
textures = [t.get_info() for t in texture_style.Textures]
|
||||||
|
else:
|
||||||
|
textures = texture_style
|
||||||
|
rendering_style = cls.surface_style_to_dict(rendering_style)
|
||||||
|
|
||||||
|
reflectance_method = rendering_style["ReflectanceMethod"]
|
||||||
|
if reflectance_method not in ("PHYSICAL", "NOTDEFINED", "FLAT"):
|
||||||
|
print(f'WARNING. Unsupported reflectance method "{reflectance_method}" on style {rendering_style}')
|
||||||
|
return
|
||||||
|
|
||||||
|
for texture in textures:
|
||||||
|
mode = texture.get("Mode", None)
|
||||||
node = None
|
node = None
|
||||||
|
|
||||||
if texture.is_a("IfcImageTexture"):
|
if texture["type"] == "IfcImageTexture":
|
||||||
image_url = texture.URLReference
|
image_url = texture["URLReference"]
|
||||||
if not os.path.abspath(texture.URLReference) and tool.Ifc.get_path():
|
ifc_path = tool.Ifc.get_path()
|
||||||
image_url = os.path.join(os.path.dirname(tool.Ifc.get_path()), texture.URLReference)
|
if ifc_path:
|
||||||
|
image_url = bpy.path.abspath(image_url, start=Path(ifc_path).parent)
|
||||||
|
|
||||||
reflectance_method = rendering_style.ReflectanceMethod
|
if not os.path.exists(image_url):
|
||||||
if reflectance_method not in ("PHYSICAL", "NOTDEFINED", "FLAT"):
|
print(f"WARNING. Couldn't find texture by path {image_url}, it will be skipped.")
|
||||||
print(f'WARNING. Unsupported reflectance method "{reflectance_method}" on style {rendering_style}')
|
continue
|
||||||
return
|
|
||||||
|
|
||||||
if rendering_style.ReflectanceMethod in ["PHYSICAL", "NOTDEFINED"]:
|
if reflectance_method in ["PHYSICAL", "NOTDEFINED"]:
|
||||||
bsdf = tool.Blender.get_material_node(blender_material, "BSDF_PRINCIPLED")
|
bsdf = tool.Blender.get_material_node(blender_material, "BSDF_PRINCIPLED")
|
||||||
if mode == "NORMAL":
|
if mode == "NORMAL":
|
||||||
# add normal map node
|
# add normal map node
|
||||||
normalmap = blender_material.node_tree.nodes.new(type="ShaderNodeNormalMap")
|
normalmap = blender_material.node_tree.nodes.new(type="ShaderNodeNormalMap")
|
||||||
normalmap.location = bsdf.location - Vector((200, 0))
|
normalmap.location = bsdf.location - Vector((200, 600))
|
||||||
blender_material.node_tree.links.new(normalmap.outputs[0], bsdf.inputs["Normal"])
|
blender_material.node_tree.links.new(normalmap.outputs[0], bsdf.inputs["Normal"])
|
||||||
|
|
||||||
# add normal map sampler
|
# add normal map sampler
|
||||||
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
||||||
node.location = normalmap.location - Vector((200, 0))
|
node.location = normalmap.location - Vector((300, 0))
|
||||||
image = bpy.data.images.load(image_url)
|
image = bpy.data.images.load(image_url)
|
||||||
image.colorspace_settings.name = "Non-Color"
|
image.colorspace_settings.name = "Non-Color"
|
||||||
node.image = image
|
node.image = image
|
||||||
@@ -203,7 +216,7 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
|
|
||||||
# add "Add Shader" node
|
# add "Add Shader" node
|
||||||
add = blender_material.node_tree.nodes.new(type="ShaderNodeAddShader")
|
add = blender_material.node_tree.nodes.new(type="ShaderNodeAddShader")
|
||||||
add.location = bsdf.location + Vector((200, 0))
|
add.location = bsdf.location + Vector((200, 350))
|
||||||
blender_material.node_tree.links.new(bsdf.outputs[0], add.inputs[1])
|
blender_material.node_tree.links.new(bsdf.outputs[0], add.inputs[1])
|
||||||
blender_material.node_tree.links.new(add.outputs[0], output.inputs[0])
|
blender_material.node_tree.links.new(add.outputs[0], output.inputs[0])
|
||||||
|
|
||||||
@@ -214,19 +227,19 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
|
|
||||||
# add emission texture sampler
|
# add emission texture sampler
|
||||||
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
||||||
node.location = emission.location - Vector((200, 0))
|
node.location = emission.location - Vector((350, 0))
|
||||||
image = bpy.data.images.load(image_url)
|
image = bpy.data.images.load(image_url)
|
||||||
node.image = image
|
node.image = image
|
||||||
blender_material.node_tree.links.new(node.outputs[0], emission.inputs[0])
|
blender_material.node_tree.links.new(node.outputs[0], emission.inputs[0])
|
||||||
|
|
||||||
elif mode == "METALLICROUGHNESS":
|
elif mode == "METALLICROUGHNESS":
|
||||||
separate = blender_material.node_tree.nodes.new(type="ShaderNodeSeparateRGB")
|
separate = blender_material.node_tree.nodes.new(type="ShaderNodeSeparateRGB")
|
||||||
separate.location = bsdf.location - Vector((200, 0))
|
separate.location = bsdf.location - Vector((200, 300))
|
||||||
blender_material.node_tree.links.new(separate.outputs[1], bsdf.inputs["Roughness"])
|
blender_material.node_tree.links.new(separate.outputs[1], bsdf.inputs["Roughness"])
|
||||||
blender_material.node_tree.links.new(separate.outputs[2], bsdf.inputs["Metallic"])
|
blender_material.node_tree.links.new(separate.outputs[2], bsdf.inputs["Metallic"])
|
||||||
|
|
||||||
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
||||||
node.location = separate.location - Vector((200, 0))
|
node.location = separate.location - Vector((300, 0))
|
||||||
image = bpy.data.images.load(image_url)
|
image = bpy.data.images.load(image_url)
|
||||||
image.colorspace_settings.name = "Non-Color"
|
image.colorspace_settings.name = "Non-Color"
|
||||||
node.image = image
|
node.image = image
|
||||||
@@ -246,18 +259,23 @@ class Loader(blenderbim.core.tool.Loader):
|
|||||||
blender_material.node_tree.links.new(node.outputs[1], bsdf.inputs["Alpha"])
|
blender_material.node_tree.links.new(node.outputs[1], bsdf.inputs["Alpha"])
|
||||||
blender_material.blend_method = "BLEND"
|
blender_material.blend_method = "BLEND"
|
||||||
|
|
||||||
elif rendering_style.ReflectanceMethod == "FLAT":
|
elif reflectance_method == "FLAT":
|
||||||
bsdf = tool.Blender.get_material_node(blender_material, "MIX_SHADER")
|
bsdf = tool.Blender.get_material_node(blender_material, "MIX_SHADER")
|
||||||
if mode != "EMISSIVE":
|
if mode != "EMISSIVE":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# remove RGB node from `create_surface_style_rendering`
|
||||||
|
prev_node = bsdf.inputs[2].links[0].from_node
|
||||||
|
blender_material.node_tree.nodes.remove(prev_node)
|
||||||
|
|
||||||
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
node = blender_material.node_tree.nodes.new(type="ShaderNodeTexImage")
|
||||||
node.location = bsdf.location - Vector((200, 0))
|
node.location = bsdf.location - Vector((200, 250))
|
||||||
image = bpy.data.images.load(image_url)
|
image = bpy.data.images.load(image_url)
|
||||||
# TODO: orphaned textures after shader recreated?
|
# TODO: orphaned textures after shader recreated?
|
||||||
node.image = image
|
node.image = image
|
||||||
blender_material.node_tree.links.new(node.outputs[0], bsdf.inputs[2])
|
blender_material.node_tree.links.new(node.outputs[0], bsdf.inputs[2])
|
||||||
|
|
||||||
|
# TODO: add support for texture data not ifc elements
|
||||||
if node and getattr(texture, "IsMappedBy", None):
|
if node and getattr(texture, "IsMappedBy", None):
|
||||||
coordinates = texture.IsMappedBy[0]
|
coordinates = texture.IsMappedBy[0]
|
||||||
coord = blender_material.node_tree.nodes.new(type="ShaderNodeTexCoord")
|
coord = blender_material.node_tree.nodes.new(type="ShaderNodeTexCoord")
|
||||||
|
|||||||
@@ -22,7 +22,14 @@ 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
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
TEXTURE_MAPS_BY_METHODS = {
|
||||||
|
"PHYSICAL": ("NORMAL", "EMISSIVE", "METALLICROUGHNESS", "DIFFUSE"),
|
||||||
|
"FLAT": ("EMISSIVE",)
|
||||||
|
}
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
STYLE_PROPS_MAP = {
|
STYLE_PROPS_MAP = {
|
||||||
"reflectance_method": "ReflectanceMethod",
|
"reflectance_method": "ReflectanceMethod",
|
||||||
@@ -33,6 +40,13 @@ STYLE_PROPS_MAP = {
|
|||||||
"metallic": "SpecularColour",
|
"metallic": "SpecularColour",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STYLE_TEXTURE_PROPS_MAP = {
|
||||||
|
"EMISSIVE": "emissive_path",
|
||||||
|
"NORMAL": "normal_path",
|
||||||
|
"METALLICROUGHNESS": "metallic_roughness_path",
|
||||||
|
"DIFFUSE": "diffuse_path",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Style(blenderbim.core.tool.Style):
|
class Style(blenderbim.core.tool.Style):
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -117,6 +131,29 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
surface_style_data["DiffuseColour"] = ("IfcColourRgb", surface_style_data["DiffuseColour"])
|
surface_style_data["DiffuseColour"] = ("IfcColourRgb", surface_style_data["DiffuseColour"])
|
||||||
return surface_style_data
|
return surface_style_data
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_texture_style_from_props(cls, blender_material):
|
||||||
|
props = blender_material.BIMStyleProperties
|
||||||
|
|
||||||
|
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:
|
||||||
|
continue
|
||||||
|
if not os.path.abspath(path) and tool.Ifc.get_path():
|
||||||
|
path = os.path.join(os.path.dirname(tool.Ifc.get_path()), path)
|
||||||
|
|
||||||
|
texture_data = {
|
||||||
|
"Mode": prop_mode,
|
||||||
|
"type": "IfcImageTexture",
|
||||||
|
"URLReference": path,
|
||||||
|
}
|
||||||
|
textures.append(texture_data)
|
||||||
|
|
||||||
|
return textures
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_surface_style_props(cls, blender_material):
|
def set_surface_style_props(cls, blender_material):
|
||||||
"""set blender style props based on current surface material"""
|
"""set blender style props based on current surface material"""
|
||||||
@@ -127,6 +164,8 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
|
|
||||||
style_elements = tool.Style.get_style_elements(blender_material)
|
style_elements = tool.Style.get_style_elements(blender_material)
|
||||||
surface_style = style_elements["IfcSurfaceStyleRendering"]
|
surface_style = style_elements["IfcSurfaceStyleRendering"]
|
||||||
|
texture_style = style_elements.get("IfcSurfaceStyleWithTextures", None)
|
||||||
|
|
||||||
style_data = tool.Loader.surface_style_to_dict(surface_style)
|
style_data = tool.Loader.surface_style_to_dict(surface_style)
|
||||||
if style_data["ReflectanceMethod"] == "NOTDEFINED":
|
if style_data["ReflectanceMethod"] == "NOTDEFINED":
|
||||||
style_data["ReflectanceMethod"] = "PHYSICAL"
|
style_data["ReflectanceMethod"] = "PHYSICAL"
|
||||||
@@ -134,26 +173,49 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
|
|
||||||
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
|
for prop_blender, prop_ifc in STYLE_PROPS_MAP.items():
|
||||||
prop_value = style_data[prop_ifc]
|
prop_value = style_data[prop_ifc]
|
||||||
# TODO: set to default?
|
|
||||||
if prop_value is None:
|
if prop_value is None:
|
||||||
continue
|
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"]]
|
||||||
|
unused_texture_maps = list(STYLE_TEXTURE_PROPS_MAP.keys())
|
||||||
|
for texture in texture_style.Textures:
|
||||||
|
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)
|
||||||
|
|
||||||
|
# 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
|
||||||
def get_surface_rendering_attributes(cls, obj, verbose=True):
|
def get_surface_rendering_attributes(cls, obj, verbose=True):
|
||||||
transparency = 1 - obj.diffuse_color[3]
|
|
||||||
diffuse_color = obj.diffuse_color
|
|
||||||
|
|
||||||
report = (lambda *x: print(*x)) if verbose else (lambda *x: None)
|
report = (lambda *x: print(*x)) if verbose else (lambda *x: None)
|
||||||
|
|
||||||
viewport_color = {
|
def color_to_ifc_format(color):
|
||||||
"Name": None,
|
return {
|
||||||
"Red": obj.diffuse_color[0],
|
"Name": None,
|
||||||
"Green": obj.diffuse_color[1],
|
"Red": color[0],
|
||||||
"Blue": obj.diffuse_color[2],
|
"Green": color[1],
|
||||||
}
|
"Blue": color[2],
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_input_node(node, input_name=None, of_type=None, input_index=None):
|
||||||
|
input_pin = node.inputs[input_name] if input_index is None else node.inputs[input_index]
|
||||||
|
if of_type:
|
||||||
|
return next((l.from_node for l in input_pin.links if l.from_node.type == of_type), None)
|
||||||
|
return next((l.from_node for l in input_pin.links), None)
|
||||||
|
|
||||||
|
props = obj.BIMStyleProperties
|
||||||
|
transparency = 1 - obj.diffuse_color[3]
|
||||||
|
diffuse_color = obj.diffuse_color
|
||||||
|
viewport_color = color_to_ifc_format(obj.diffuse_color)
|
||||||
attributes = {
|
attributes = {
|
||||||
"SurfaceColour": viewport_color,
|
"SurfaceColour": viewport_color,
|
||||||
"Transparency": transparency,
|
"Transparency": transparency,
|
||||||
@@ -162,12 +224,6 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
BLUE = "\033[1;34m"
|
BLUE = "\033[1;34m"
|
||||||
R = "\033[0m" # RESET symbol
|
R = "\033[0m" # RESET symbol
|
||||||
|
|
||||||
def get_input_node(node, input_name=None, of_type=None, input_index=None):
|
|
||||||
input_pin = node.inputs[input_name] if input_index is None else node.inputs[input_index]
|
|
||||||
if of_type:
|
|
||||||
return next((l.from_node for l in input_pin.links if l.from_node.type == of_type), None)
|
|
||||||
return next((l.from_node for l in input_pin.links), None)
|
|
||||||
|
|
||||||
report("--------------------")
|
report("--------------------")
|
||||||
report("Verbose method of getting surface rendering attributes enabled.")
|
report("Verbose method of getting surface rendering attributes enabled.")
|
||||||
report("If some attribute is not mentioned below, then it won't be saved to IFC.")
|
report("If some attribute is not mentioned below, then it won't be saved to IFC.")
|
||||||
@@ -188,20 +244,31 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
if (
|
if (
|
||||||
get_input_node(mix_shader, "Fac", "LIGHT_PATH")
|
get_input_node(mix_shader, "Fac", "LIGHT_PATH")
|
||||||
and get_input_node(mix_shader, input_index=1, of_type="BSDF_TRANSPARENT")
|
and get_input_node(mix_shader, input_index=1, of_type="BSDF_TRANSPARENT")
|
||||||
and (rgb := get_input_node(mix_shader, input_index=2, of_type="RGB"))
|
and (second_input_node := get_input_node(mix_shader, input_index=2))
|
||||||
|
and second_input_node.type in ("RGB", "TEX_IMAGE")
|
||||||
):
|
):
|
||||||
report(
|
report(
|
||||||
f"Because of {BLUE}MIX_SHADER + LIGHT_PATH + BSDF_TRANSPARENT + RGB{R} node setup reflectance method identified as {BLUE}FLAT{R}"
|
f"Because of {BLUE}MIX_SHADER + LIGHT_PATH + BSDF_TRANSPARENT + RGB/TEX{R} node setup reflectance method identified as {BLUE}FLAT{R}"
|
||||||
)
|
)
|
||||||
attributes["ReflectanceMethod"] = "FLAT"
|
attributes["ReflectanceMethod"] = "FLAT"
|
||||||
attributes["SpecularHighlight"] = None
|
attributes["SpecularHighlight"] = None
|
||||||
report(f"RGB {GREEN}Color{R} saved as {GREEN}DiffuseColour{R}")
|
|
||||||
diffuse_color = rgb.outputs[0].default_value
|
|
||||||
|
|
||||||
elif surface_output and surface_output.type == "BSDF_PRINCIPLED":
|
if second_input_node.type == "RGB":
|
||||||
|
report(f"RGB {GREEN}Color{R} saved as {GREEN}DiffuseColour{R}")
|
||||||
|
diffuse_color = second_input_node.outputs[0].default_value
|
||||||
|
elif second_input_node.type == "TEX_IMAGE":
|
||||||
|
report(f"{GREEN}BBIM Panel Diffuse Color{R} saved as {GREEN}DiffuseColour{R}")
|
||||||
|
diffuse_color = props.diffuse_color
|
||||||
|
|
||||||
|
elif surface_output and (
|
||||||
|
(surface_output.type == "BSDF_PRINCIPLED" and (bsdf := surface_output))
|
||||||
|
or (
|
||||||
|
surface_output.type == "ADD_SHADER"
|
||||||
|
and (bsdf := get_input_node(surface_output, input_index=1, of_type="BSDF_PRINCIPLED"))
|
||||||
|
)
|
||||||
|
):
|
||||||
report(f"Because of {BLUE}BSDF_PRINCIPLED{R} node reflectance method identified as {BLUE}PHYSICAL{R}")
|
report(f"Because of {BLUE}BSDF_PRINCIPLED{R} node reflectance method identified as {BLUE}PHYSICAL{R}")
|
||||||
attributes["ReflectanceMethod"] = "NOTDEFINED" if tool.Ifc.get_schema() != "IFC4X3" else "PHYSICAL"
|
attributes["ReflectanceMethod"] = "NOTDEFINED" if tool.Ifc.get_schema() != "IFC4X3" else "PHYSICAL"
|
||||||
bsdf = surface_output
|
|
||||||
|
|
||||||
report(f"BSDF {GREEN}Base Color{R} saved as {GREEN}DiffuseColour{R}")
|
report(f"BSDF {GREEN}Base Color{R} saved as {GREEN}DiffuseColour{R}")
|
||||||
diffuse_color = bsdf.inputs["Base Color"].default_value
|
diffuse_color = bsdf.inputs["Base Color"].default_value
|
||||||
@@ -286,12 +353,7 @@ class Style(blenderbim.core.tool.Style):
|
|||||||
attributes["DiffuseColour"] = viewport_color
|
attributes["DiffuseColour"] = viewport_color
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
attributes["DiffuseColour"] = {
|
attributes["DiffuseColour"] = color_to_ifc_format(diffuse_color)
|
||||||
"Name": None,
|
|
||||||
"Red": diffuse_color[0],
|
|
||||||
"Green": diffuse_color[1],
|
|
||||||
"Blue": diffuse_color[2],
|
|
||||||
}
|
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user