Materials missing

Please find attached a 3DM file written using Opennurbs. There are three materials in the file. But only one is shown in Rhino. But an audit on the file shows that all three materials are listed.


test.3dm (5.8 KB)

Is there any way to display all the materials, when opened in Rhino.

Thanks in advance.

Hi @rajeev,

It’s my understand that only used render materials appear in the Materials panel. The attached file has 3 materials but only 1 render material.

– Dale

That’s correct. But when I add extra materials (without using them) within Rhino, the materials get saved when I save the file. The materials are also displayed in the Material panel, if I open the file again.

Hi @rajeev,

If I understand, you want to do what Rhino is doing, but just with openNURBS?

– Dale

Hi @dale,
Yes, please.

Hi @rajeev,

You’ll probably need openNURBS 8, as it contains a number of new class that were once reserved for the RDK.

@johnc - perhaps you can work up a sample?

– Dale

Hi @rajeev,

I’m sorry about the long delay getting to this; I was on an extended leave of absence for several months. Anyway, if you still need help, this is how to create a render material using the latest OpenNURBs SDK:

  const wchar_t* filename = L"YOUR FILENAME HERE";

  ONX_Model model;

  // Optionally read a file in first.
  model.Read(filename);

  // Add a new render material to the model.
  model.AddRenderMaterial(L"My Material");

  // Write the model back out to the file.
  model.Write(filename);

This simple example does not check for errors and just adds a gray material. If you need help doing anything more sophisticated than this, please let me know.

Regards,

John

Hi @Johnc,

Thank you for the suggestion. I already figured that out. How do I set the parameters such as diffuse, emission etc.

I found a method to convert the ON_RenderMaterial to ON_Material. Should I use it to change the parameters and then add the resultant material to the ModelComponent. Is that the right way?

Please advise.

Hi @johnc,

I tired … could not find a way to convert ON_Material Back to ON_RenderMaterial.

Hi @rajeev,

It’s best to avoid ON_Material now that ON_RenderMaterial is available. You can do everything directly with ON_RenderMaterial. The way to do it is you put an ON_RenderMaterial on the stack, set its parameters and then add it as a model component. That way a copy of it gets added to the model. Here’s an example showing how to add a Custom Material while also setting some parameters:

  ON_RenderMaterial mat;
  const UUID uuidCustomMaterialType = { 0xba51c000, 0xba51, 0xc000,
              { 0xba, 0x51, 0xc0, 0xba, 0x51, 0xc0, 0x00, 0x00 } };
  mat.SetTypeId(uuidCustomMaterialType);
  mat.SetName(L"My Material");
  const ON_4fColor col(1.0f, 0.5f, 0.5f, 1.0f);
  mat.SetParameter(ON_MATERIAL_DIFFUSE, ON_XMLVariant(col));
  model.AddModelComponent(mat);

Regards,

John

Hi @johnc ,
Thank you very much. I am able to add Render Materials, with varios shading parameters. However, I am not able to add the rendering material as an attribute to the ModelGeometryComponent.
Setting attribute->m_material_index, does not have any effect. How can I add the attribute?
Also, is there any documentation on the UUID values that I can refer to.

Thanks in advance.

Hi @rajeev,

This is going to get a little complicated. Part of the complication is due to historical reasons and the way the material system has evolved over the last decade or two. I’ll try to explain it as simply as possible.

First, when I said it’s best to avoid ON_Material I forgot that it’s actually unavoidable when you want to assign a render material to a ModelGeometryComponent. This is because such an assignment requires the objects to be connected together by the use of an ON_Material since ModelGeometryComponent existed long before ON_RenderMaterial did and the attributes of the model component uses the component index of the ON_Material to identify the material.

The ON_Material is connected to the ON_RenderMaterial by setting two values: the unique ID of the ON_RenderMaterial and a plug-in ID. It’s necessary for the plug-in ID to be set to the ‘universal’ value (which is all 9s) because it doesn’t belong to any 3rd-party plug-in (it belongs to the RDK subsystem of Rhino). The ON_Material has a SetRdkMaterialInstanceId() method that sets the render material’s ID and a SetMaterialPlugInId() method that sets the plug-in ID.

In summary, ModelGeometryComponent attributes uses the material index of an ON_Material which in turn indicates which ON_RenderMaterial to use by specifying its unique ID.

Below is an example of how to create a new render material and assign it to the first ModelGeometryComponent in the model. First an ON_Material is added to the model, its values are set and then we just get the first ON_ModelGeometryComponent in the model and use its attributes to assign the material. The ON_Material is given an index of zero as I assume it’s the first one being added. You might need to modify that.

About the UUIDs: this conversation has highlighted an oversight. These UUIDs were originally defined in the RDK and have not been exposed to users of ‘plain’ OpenNURBS. I will need to fix that by moving them into opennurbs_render_content.h. For now, just use the UUIDs below. I will try to fix this in the next day or so.

bool CreateAndAssignMaterial(ONX_Model& model)
{
  // Create the render material, set its properties and add it to the model.
  ON_RenderMaterial render_mat;
  const ON_UUID uuidCustomMaterialType = { 0xba51c000, 0xba51, 0xc000,
              { 0xba, 0x51, 0xc0, 0xba, 0x51, 0xc0, 0x00, 0x00 } };
  render_mat.SetTypeId(uuidCustomMaterialType);
  render_mat.SetName(L"My Material");
  const ON_4fColor col(1.0f, 0.5f, 0.5f, 1.0f);
  render_mat.SetParameter(ON_MATERIAL_DIFFUSE, ON_XMLVariant(col));
  model.AddModelComponent(render_mat);

  // Create an ON_Material to use for the render material assignment and add it to the model.
  ON_Material mat;
  mat.SetIndex(0); // Assume first material.
  mat.SetRdkMaterialInstanceId(render_mat.Id());
  const ON_UUID uuidUniversal = { 0x99999999, 0x9999, 0x9999,
              { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99 } };
  mat.SetMaterialPlugInId(uuidUniversal);
  model.AddModelComponent(mat);

  // Get the first ON_ModelGeometryComponent and get its attributes.
  ONX_ModelComponentIterator it(model, ON_ModelComponent::Type::ModelGeometry);
  const auto* mgc = ON_ModelGeometryComponent::Cast(it.FirstComponent());
  if (nullptr == mgc)
    return false; // No suitable component in the model.

  auto* attr = mgc->ExclusiveAttributes(); // Get attributes allowing modification.
  if (nullptr == attr)
    return false;

  // Set the material source to 'from object'.
  attr->SetMaterialSource(ON::material_from_object);

  // Set the material index to the index of the ON_Material.
  attr->m_material_index = mat.Index();

  return true;
}

Hi @johnc,

Thank you very much… finally able to correctly assign render materials. Without your insights, I would have never guessed the solution.
It would be really helpful, if you could please include a sample code in the OpenNURBS SDK.

Thanks once again,

rajeev

Hi @rajeev,

I’m glad to be of service. Sorry for the difficulties and delay. I will try to get some samples added to the SDK.

John