Skip to content

Commit

Permalink
Different BSDFs are now recognised for different reflectance methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
Moult committed Feb 2, 2022
1 parent 72397f3 commit 8c0b06b
Show file tree
Hide file tree
Showing 5 changed files with 562 additions and 43 deletions.
61 changes: 47 additions & 14 deletions src/blenderbim/blenderbim/core/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,22 @@
def add_style(ifc, style, obj=None):
element = ifc.run("style.add_style", name=style.get_name(obj))
ifc.link(element, obj)
ifc.run(
"style.add_surface_style",
style=element,
ifc_class="IfcSurfaceStyleRendering",
attributes=style.get_surface_rendering_attributes(obj),
)
if style.can_support_rendering_style(obj):
attributes = style.get_surface_rendering_attributes(obj)
ifc.run("style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleRendering", attributes=attributes)
else:
attributes = style.get_surface_shading_attributes(obj)
ifc.run("style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleShading", attributes=attributes)

if style.can_support_texture_style(obj):
textures = ifc.run("style.add_surface_textures", textures=style.get_surface_textures(obj))
ifc.run(
"style.add_surface_style",
style=element,
ifc_class="IfcSurfaceStyleWithTextures",
attributes={"Textures": textures},
)

material = ifc.get_entity(obj)
if material:
ifc.run("style.assign_material_style", material=material, style=element, context=style.get_context(obj))
Expand All @@ -39,16 +49,39 @@ def remove_style(ifc, style, obj=None):


def update_style_colours(ifc, style, obj=None):
rendering_style = style.get_surface_rendering_style(obj)
if rendering_style:
attributes = style.get_surface_rendering_attributes(obj)
ifc.run("style.edit_surface_style", style=rendering_style, attributes=attributes)
return
element = ifc.get_entity(obj)

shading_style = style.get_surface_shading_style(obj)
if shading_style:
if style.can_support_rendering_style(obj):
rendering_style = style.get_surface_rendering_style(obj)
attributes = style.get_surface_rendering_attributes(obj)
if rendering_style:
ifc.run("style.edit_surface_style", style=rendering_style, attributes=attributes)
else:
ifc.run(
"style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleRendering", attributes=attributes
)
else:
shading_style = style.get_surface_shading_style(obj)
attributes = style.get_surface_shading_attributes(obj)
ifc.run("style.edit_surface_style", style=shading_style, attributes=attributes)
if shading_style:
ifc.run("style.edit_surface_style", style=shading_style, attributes=attributes)
else:
ifc.run("style.add_surface_style", style=element, ifc_class="IfcSurfaceStyleShading", attributes=attributes)

texture_style = style.get_surface_texture_style(obj)
if style.can_support_texture_style(obj):
textures = ifc.run("style.add_surface_textures", textures=style.get_surface_textures(obj))
if texture_style:
ifc.run("style.edit_surface_style", style=texture_style, attributes={"Textures": textures})
else:
ifc.run(
"style.add_surface_style",
style=element,
ifc_class="IfcSurfaceStyleWithTextures",
attributes={"Textures": textures},
)
elif texture_style:
ifc.run("style.remove_style", style=texture_style)


def unlink_style(ifc, style, obj=None):
Expand Down
4 changes: 4 additions & 0 deletions src/blenderbim/blenderbim/core/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ def load_structural_analysis_models(cls): pass

@interface
class Style:
def can_support_rendering_style(cls, obj): pass
def can_support_texture_style(cls, obj): pass
def disable_editing(cls, obj): pass
def enable_editing(cls, obj): pass
def export_surface_attributes(cls, obj): pass
Expand All @@ -370,6 +372,8 @@ def get_surface_rendering_attributes(cls, obj): pass
def get_surface_rendering_style(cls, obj): pass
def get_surface_shading_attributes(cls, obj): pass
def get_surface_shading_style(cls, obj): pass
def get_surface_texture_style(cls, obj): pass
def get_surface_textures(cls, obj): pass
def import_surface_attributes(cls, style, obj): pass


Expand Down
146 changes: 134 additions & 12 deletions src/blenderbim/blenderbim/tool/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,45 @@


class Style(blenderbim.core.tool.Style):
@classmethod
def can_support_rendering_style(cls, obj):
return obj.use_nodes and hasattr(obj.node_tree, "nodes")

@classmethod
def can_support_texture_style(cls, obj):
if not obj.node_tree:
return False

output = {n.type: n for n in obj.node_tree.nodes}.get("OUTPUT_MATERIAL", None)
if not output:
return False

# For now, we assume only a single BSDF is allowed in our node tree.
try:
bsdf = output.inputs["Surface"].links[0].from_node
except:
return False

# For a quick check whether we have a compatible node tree, we check
# whether or not we have at least one image texture node that has a
# texture assigned and outputs to the bsdf.
textures = [n for n in obj.node_tree.nodes if n.type == "TEX_IMAGE" and n.image]

def does_texture_connect_to(node, target):
if node == target:
return True
try:
output = node.outputs[0].links[0].to_node
return does_texture_connect_to(output, target)
except:
return False

for texture in textures:
if does_texture_connect_to(texture, bsdf):
return True

return False

@classmethod
def disable_editing(cls, obj):
obj.BIMStyleProperties.is_editing = False
Expand Down Expand Up @@ -55,27 +94,59 @@ def get_style(cls, obj):
def get_surface_rendering_attributes(cls, obj):
transparency = obj.diffuse_color[3]
diffuse_color = obj.diffuse_color
if obj.use_nodes and hasattr(obj.node_tree, "nodes") and "Principled BSDF" in obj.node_tree.nodes:
bsdf = obj.node_tree.nodes["Principled BSDF"]
transparency = bsdf.inputs["Alpha"].default_value
diffuse_color = bsdf.inputs["Base Color"].default_value
transparency = 1 - transparency
return {

attributes = {
"SurfaceColour": {
"Name": None,
"Red": obj.diffuse_color[0],
"Green": obj.diffuse_color[1],
"Blue": obj.diffuse_color[2],
},
"Transparency": transparency,
"DiffuseColour": {
"Name": None,
"Red": diffuse_color[0],
"Green": diffuse_color[1],
"Blue": diffuse_color[2],
},
}

bsdfs = {n.type: n for n in obj.node_tree.nodes}
if "BSDF_GLOSSY" in bsdfs:
attributes["ReflectanceMethod"] = "METAL"
bsdf = bsdfs["BSDF_GLOSSY"]
attributes["SpecularHighlight"] = {"IfcSpecularRoughness": round(bsdf.inputs["Roughness"].default_value, 3)}
diffuse_color = bsdf.inputs["Color"].default_value
elif "BSDF_DIFFUSE" in bsdfs:
attributes["ReflectanceMethod"] = "MATT"
bsdf = bsdfs["BSDF_DIFFUSE"]
attributes["SpecularHighlight"] = {"IfcSpecularRoughness": round(bsdf.inputs["Roughness"].default_value, 3)}
diffuse_color = bsdf.inputs["Color"].default_value
elif "BSDF_GLASS" in bsdfs:
attributes["ReflectanceMethod"] = "GLASS"
bsdf = bsdfs["BSDF_GLASS"]
attributes["SpecularHighlight"] = {"IfcSpecularRoughness": round(bsdf.inputs["Roughness"].default_value, 3)}
diffuse_color = bsdf.inputs["Color"].default_value
elif "EMISSION" in bsdfs:
attributes["ReflectanceMethod"] = "FLAT"
bsdf = bsdfs["EMISSION"]
attributes["SpecularHighlight"] = None
diffuse_color = bsdf.inputs["Color"].default_value
elif "BSDF_PRINCIPLED" in bsdfs:
attributes["ReflectanceMethod"] = "NOTDEFINED"
bsdf = bsdfs["BSDF_PRINCIPLED"]
attributes["SpecularHighlight"] = {"IfcSpecularRoughness": round(bsdf.inputs["Roughness"].default_value, 3)}
diffuse_color = bsdf.inputs["Base Color"].default_value
attributes["Transparency"] = 1 - bsdf.inputs["Alpha"].default_value
else:
attributes["ReflectanceMethod"] = "NOTDEFINED"
attributes["SpecularHighlight"] = None
attributes["DiffuseColour"] = attributes["SurfaceColour"]
return attributes

attributes["DiffuseColour"] = {
"Name": None,
"Red": diffuse_color[0],
"Green": diffuse_color[1],
"Blue": diffuse_color[2],
}

return attributes

@classmethod
def get_surface_rendering_style(cls, obj):
if obj.BIMMaterialProperties.ifc_style_id:
Expand Down Expand Up @@ -107,6 +178,57 @@ def get_surface_shading_style(cls, obj):
if items:
return items[0]

@classmethod
def get_surface_texture_style(cls, obj):
if obj.BIMMaterialProperties.ifc_style_id:
style = tool.Ifc.get().by_id(obj.BIMMaterialProperties.ifc_style_id)
items = [s for s in style.Styles if s.is_a("IfcSurfaceStyleWithTextures")]
if items:
return items[0]

@classmethod
def get_surface_textures(cls, obj):
output = {n.type: n for n in obj.node_tree.nodes}.get("OUTPUT_MATERIAL", None)
bsdf = output.inputs["Surface"].links[0].from_node
node_mappings = {
"BSDF_GLOSSY": {
"DIFFUSE": "Color",
"SHININESS": "Roughness",
"NORMAL": "Normal",
},
"BSDF_DIFFUSE": {
"DIFFUSE": "Color",
"SHININESS": "Roughness",
"NORMAL": "Normal",
},
"BSDF_GLASS": {
"DIFFUSE": "Color",
"SHININESS": "Roughness",
"NORMAL": "Normal",
},
"EMISSION": {
"DIFFUSE": "Color",
},
"BSDF_PRINCIPLED": {
"DIFFUSE": "Base Color",
"SHININESS": "Roughness",
"NORMAL": "Normal",
"SPECULAR": "Specular",
"SELFILLUMINATION": "Emission Strength",
"OPACITY": "Alpha",
},
}

maps = {}
if bsdf.type not in node_mappings:
return maps

for map_type, input_name in node_mappings[bsdf.type].items():
if bsdf.inputs[input_name].links:
maps[map_type] = bsdf.inputs[input_name].links[0].from_node

return maps

@classmethod
def import_surface_attributes(cls, style, obj):
obj.BIMStyleProperties.attributes.clear()
Expand Down

0 comments on commit 8c0b06b

Please sign in to comment.