New Materials for IFC Components

Hi all. I’m new to the Sketchup API. I’m using IFC output from sketchup so I’ve been making everything into components. I need to output component material. I’m making a simple plugin that contains some custom Materials (in .skm format distributed with the plugin) and just lets the user quickly assign the custom material to their IFC component from a drop-down list. I’ve been using the attribute visualizer to learn about and see the component details. I can get the material to be assigned to the component (I assume that will also set it to the instance?) but can’t get the material to show up visually. The material seems to be loaded correctly via api but shows up as “Material not in model” in _material_error (as seen in attribute visualizer plugin). After I’ve made the materials.load call in the code, I can manually type the “My Special Material” in the component dynamic attributes and it will be correctly applied. I’m sure it’s something basic I missed. I did look at this long discussion but it seemed to do mostly with custom attributes and not a standard one like material. I found a sample that assigns a simple color as component material but it’s not quite working with a new material. Thanks for any help.

#setComponentsMaterial(selectedEntities, 'red')
#doesn't work
setComponentsMaterial(selectedEntities, 'My Special Material')

def setComponentsMaterial(selectedEntities, materialName)
	#pull the material if not already in the model
	if materialName != 'red'
		newMaterial = load_material(materialName)

	#save the values to the components
	puts "saving material to components"
	if selectedEntities.length > 0
		selectedEntities.each do |selectedEntity|
			selectedEntity_def = selectedEntity.definition
			selectedEntity_def.set_attribute('dynamic_attributes','material', materialName)
			selectedEntity_def.set_attribute('dynamic_attributes','_material_formula','"' + materialName + '"')
			#selectedEntity.material = newMaterial
			selectedEntity_def.set_attribute 'dynamic_attributes','_description_formula','Component now has material-->' + materialName
			puts "finished setting material to component"
			dcs = $dc_observers.get_latest_class

def load_material(materialName)
	mat = Sketchup.active_model.materials[materialName]
	if mat.nil?
		full_path_to_skm = File.join( $ifc_plugin_data_path, 'SketchupMaterials', materialName + '.skm')
		puts "full_path_to_skm=" + full_path_to_skm
		mat = Sketchup.active_model.materials.load(full_path_to_skm)
		if mat.nil?
			puts "error loading material from skm"
			puts "material loaded successfully:" + full_path_to_skm
	return mat

What IFC scheme are you using Ifc 2x3 or Ifc 4?
I’m not sure but I think that 2x3 doesn’t export materials.
Have you tried to export with Ifc Manager?
I always use that plugin and Insee my model in an Ifc viewer with all of materials. But I apply them with paint bucket directly to components

Do not use global variables, even if you see old examples that do.

Each of your extensions must be within a submodule, which must be within your unique top level namespace module. Therefore either use a local constant or @variable within your extension submodule.

If your plugin’s materials folder is a subfolder of your extension subfolder, where the file is loaded from, then you only need use the global Ruby method __dir__() to get that path, so

SKM_PATH ||= File.join(__dir__, 'SketchupMaterials')

def material_path(material_name)
  File.join(SKM_PATH, "#{material_name}.skm")

Only the API color names as described in the Sketchup::Color class can be used by name for #material=.

But if you create a material with a custom name, then you can get it with materials[matl_name] but to assign it to an instance you will need to use a reference you get back from materials[matl_name] or materials.load(matl_name).

Assigning a material to a ComponentDefinition does not currently have a good reason. (This only shows the instance in that material whilst it is attached to the cursor when placing it. Once placed the instance would have no material.)

So, the answer is, you must usually always meticulously “take every step” and “jump through every hoop.” Yes, you must explicitly assign a material to an ComponentInstance or a Group.

1 Like
1 Like

Sadly, I need to use 2x3 as the app I’m transferring to only uses that. I looked at ifc manager but it seemed like a lot of overkill for what I thought was a small easy task. Sketchup seems to export the material (or at least the name of the material) at least when defined in the component definition.

Thanks for the very quick responses. Understood about the globals. I changed the code to apply the material to the component instance(s) (ie. selectedEntity.material = newMaterial )and it looks fine in sketchup but even if I leave the material dynamic attribute in the component def, it now doesn’t show up in the IFC output or in the attribute viewer. That confuses me. My main goal was to have the material name in the IFC output (to communicate it to other app) and the secondary need was to have it look correct in sketchup during modeling. Is getting it in the IFC output what you pointed out with the two links? How do I do what is described in the links programmatically?

Try to view the model in another viewer like Bim Collab Zoom or Bim Vision, they read both schemas. Also try to export the same model with Ifc 2x3 and Ifc 4, view them in those viewers and find the differences.
I spoke with the developers of Bim5D software that I’m using and they say that Sketchup exports materials in a different way that Revit does (As an example… I don’t know which one is doing right…)

Not specific to IFC export.

Create a group inside the DC definition’s entities (at some level.) Create faces painted with the materials that you wish to “travel” with the DC inside the group. Set the group hidden.