Create material, apply to layer and export to rmtl file

I am using rhinocommon under Rhino 5, and I’m trying to create a new material, apply it to a layer and export the material to a rmtl file. I can do the first two, but when exporting with Rendersavematerialtofile as rmtl file it gives an error (“Invalid Instance”)

  // Create material
  int index = Rhino.RhinoDoc.ActiveDoc.Materials.Add();
  Rhino.DocObjects.Material mat = doc.Materials[index];
  mat.DiffuseColor = System.Drawing.Color.Chocolate;
  mat.SpecularColor = System.Drawing.Color.CadetBlue;
  mat.Name = "myMaterial";
  mat.CommitChanges();
  // Assign to current layer
  Rhino.DocObjects.Layer layer = Rhino.RhinoDoc.ActiveDoc.Layers.CurrentLayer;
  layer.RenderMaterialIndex = index;
  doc.Layers.Modify(layer, layer.LayerIndex, true);
  Rhino.RhinoDoc.ActiveDoc.Views.Redraw();
  // Export to rmtl
  Rhino.RhinoApp.RunScript("Rendersavematerialtofile \"myMaterial\" C:\\temp\\myMaterial.rmtl", true);

If I then try layer.RenderMaterial it says “Object reference not set to an instance of an object”, even if I have assigned a material to the layer. There is no method layer.Material…

If I create the material manually, then the command does work, but I would like to do it programatically with rhinocommon.

I wonder if it has to do with different material types in Rhino. I can see two different ones in the documentation:
Rhino.DocObjects.Material andn Rhino.Render.RenderMaterial. The colour for the first type I can modify, but for the second it seems not possible.

Thanks

If you create a Material you have to assign it to an object to, I don’t know if having it assigned to just layer is enough.

From your material you can use RenderMaterial.CreateBasicMaterial

1 Like

Perfect! I can make it work now. Thanks!

I have bumped into another related problem. I can assign a render material to a layer, but then the material sometimes appears in the materials tab and sometimes not, with weird effects explained in the code below.
However, the main issue is how to access properties like diffuse color in a render material. I can access Name and Notes, but not the other properties.
Is there a way to get a Rhino.DocObjects.Material from a render material?

  // Create material
  int index = Rhino.RhinoDoc.ActiveDoc.Materials.Add();
  Rhino.DocObjects.Material mat = doc.Materials[index];
  mat.DiffuseColor = System.Drawing.Color.Chocolate;
  mat.SpecularColor = System.Drawing.Color.CadetBlue;
  mat.Name = "myMaterial";
  mat.CommitChanges();
  
  // Create render material and assign to layer
  // I can see the materials in the layers, but not in the Materials tab
  Rhino.Render.RenderMaterial renderMat = Rhino.Render.RenderMaterial.CreateBasicMaterial(mat);
  layer.RenderMaterial = renderMat;
  layer.CommitChanges();
  
  // If I add these two lines I can see the materials in the materials tab, but then layer.RenderMaterial does not yield the render material even if it is still associated to the layer in the layers tab.
  layer.RenderMaterialIndex = index;
  Rhino.RhinoDoc.ActiveDoc.Layers.Modify(layer, layer.LayerIndex, true);
  
  // In any case, I can access the rendermaterial name, but not other properties like diffuse color
  Rhino.Render.RenderMaterial renderMat = layer.RenderMaterial;
  Rhino.RhinoApp.WriteLine("{0} render material name", renderMat.Name);

Nathan,

I was exploring options and I found this:

      Rhino.DocObjects.Material mat = new Rhino.DocObjects.Material();
      renderMat.SimulateMaterial(ref mat, true);

Could that be the solution to convert a RenderMaterial to a DocObject.Material?

For RenderMaterial instances you should use the GetParameter(). You’ll need to know the parameter names to properly be able to use them. I’ll see if I can find them.

Edit: actually, the fastest way for you to find out the names for parameters is to create a material in the material editor, set something for all settings (including textures) and save it as a .rtml. Then open the rtml file in a text editor. You should be able to find the names for the different fields (parameters).

https://developer.rhino3d.com/5/api/RhinoCommonWin/html/M_Rhino_Render_RenderContent_GetParameter.htm

https://developer.rhino3d.com/5/api/RhinoCommonWin/html/M_Rhino_Render_RenderContent_SetParameter.htm

1 Like

Thanks JesterKing,

That’s very useful. I’m still wondering about the other question. When I create a render material and attach it to a layer…
Rhino.Render.RenderMaterial renderMat = Rhino.Render.RenderMaterial.CreateBasicMaterial(myMat);
layer.RenderMaterial = renderMat;
layer.CommitChanges();
…the material appears in the layer but not in the Materials Panel. Then, if I add…
layer.RenderMaterialIndex = index;
Rhino.RhinoDoc.ActiveDoc.Layers.Modify(layer, layer.LayerIndex, true);
…the materials appear in the Layer Panel but a call to layer.RenderMaterial says there is no material.
Finally, if I call Rhino.RhinoDoc.ActiveDoc.RenderMaterials.Count it returns “0”, or a number only for those materials created manually.
It really puzzles me. It looks like my render materials created via script are somehow incomplete.

What I am trying to achieve is:
1- Generate render materials programatically and assign them to layers based on the layer name, and add the materials to the Materials Panel.
2- Loop the layers and retrieve data from the render materials assigned.

You always need to add the content to the document - that’s the thing that adds it to the Material Editor.

doc.RenderMaterials.Add(material);

Andrew,

Is that a new feature in Rhino 6? I am working in Rhino 5 and RenderMaterialsTabel does not seem to have an Add(material) method. Is there a work around?
I thought I could use Material instead of RenderMaterial for my work, but Material does not have a Notes property, which I need :frowning:

You should absolutely be using RenderMaterial.

The V5 version is RenderContent.AddPersistentRenderContent(RhinoDoc document, RenderContent renderContent).

1 Like

Nice, that was a difficult one for me. And finally to remove a render material from the Materials Panel? In Rhino 5 there is no doc.RenderMaterials.Remove(material) either.

I thought I had made it work, but I’m having problems using these methods.

Rhino.Render.RenderMaterial renderMat = Rhino.Render.RenderMaterial.CreateBasicMaterial(mat);
var trans = renderMat.GetParameter(“transparency”);
yields Rhino.Render.Variant

If I try casting it into a double,
double trans = (double) renderMat.GetParameter(“transparency”);
I get “error: Specified cast is not valid”

Any suggestions?

///


/// Query the content instance for the value of a given named parameter.
/// If you do not support this parameter, call the base class.
///

/// Name of the parameter
/// IConvertible. Note that you can’t directly cast from object, instead you have to use the Convert mechanism.

for example:

var t = renderMat.GetParameter(“transparency”) as IConvertible;
var d = Convert.ToDouble(t);

1 Like

Perfect, that is what I needed. And to do the opposite and set a parameter?
I tried the following but it does not work:
renderMat.SetParameter(“transparency”, 0.5, Rhino.Render.RenderContent.ChangeContexts.UI);
I’m actually not sure of what Rhino.Render.RenderContent.ChangeContexts does. I tried different options to no avail.

@Goodriver
Is there any info on the SetParameter solution?

@gabor.konstanzer, what information are you looking for?

@jesterking Was curious if he could make it work, because he wrote it does not work. That’s it basically.
If there is a small sample application or tutorial on how to use it properly and what does each ChangeContext mean.

I want to read information from the RenderMaterials that are added to the project, i’m exporting the information to other softwares and currently i’m putting small rectangles down on a hidden layer and applying RenderMaterials on them, because i thought i can only read material information from the MaterialTable. Now i found this solution and maybe with this i don’t need hidden geometry to do this.

Here a simple example - I include at the beginning the contents of a Rhino Custom material saved as .rtml so you can see what the parameter possible for this particular material. I suggest you do so for all the material types that come with Rhino.

# Randomizer

"""
<xml>
	<material type-name="rcm-basic-material" render-engine-id="99999999-9999-9999-9999-999999999999" type-id="BA51C000-BA51-C000-BA51-C0BA51C00000" notes="" tags="" hidden="false" reference="false" auto-delete="false">
		<parameters>
			<bitmap-texture-on type="bool">false</bitmap-texture-on>
			<bitmap-texture-filter-on type="bool">true</bitmap-texture-filter-on>
			<bitmap-texture-amount type="double">1</bitmap-texture-amount>
			<bump-texture-on type="bool">false</bump-texture-on>
			<bump-texture-filter-on type="bool">true</bump-texture-filter-on>
			<bump-texture-amount type="double">1</bump-texture-amount>
			<transparency-texture-on type="bool">false</transparency-texture-on>
			<transparency-texture-filter-on type="bool">true</transparency-texture-filter-on>
			<transparency-texture-amount type="double">1</transparency-texture-amount>
			<environment-texture-on type="bool">false</environment-texture-on>
			<environment-texture-filter-on type="bool">true</environment-texture-filter-on>
			<environment-texture-amount type="double">1</environment-texture-amount>
			<version type="int">2</version>
			<diffuse type="color">0.980392158031464,0.980392158031464,0.980392158031464,0</diffuse>
			<specular type="color">1,1,1,0</specular>
			<shine type="double">1</shine>
			<transparency type="double">0</transparency>
			<reflectivity type="double">1</reflectivity>
			<ior type="double">1</ior>
			<transparency-color type="color">1,1,1,0</transparency-color>
			<reflectivity-color type="color">1,1,1,0</reflectivity-color>
			<emission type="color">0,0,0,0</emission>
			<ambient type="color">0,0,0,0</ambient>
			<flamingo-library type="string"/>
			<disable-lighting type="bool">false</disable-lighting>
			<fresnel-enabled type="bool">true</fresnel-enabled>
			<polish-amount type="double">1</polish-amount>
			<clarity-amount type="double">1</clarity-amount>
			<alpha-transparency type="bool">false</alpha-transparency>
		</parameters>
		<simulation>
			<ambient type="color">0,0,0,0</ambient>
			<diffuse type="color">0.980392158031464,0.980392158031464,0.980392158031464,0</diffuse>
			<emission type="color">0,0,0,0</emission>
			<specular type="color">1,1,1,0</specular>
			<reflection type="color">1,1,1,0</reflection>
			<shine type="double">1</shine>
			<transparency type="double">0</transparency>
			<reflectivity type="double">1</reflectivity>
			<ior type="double">1</ior>
			<fresnel-enabled type="bool">true</fresnel-enabled>
			<polish-amount type="double">1</polish-amount>
			<clarity-amount type="double">1</clarity-amount>
			<transparent type="color">1,1,1,0</transparent>
		</simulation>
	</material>
	<meta-data>
		<renderer-name>Generic</renderer-name>
		<type-name>Custom</type-name>
	</meta-data>
	<thumbnail>none</thumbnail>
</xml>
"""

import random
import scriptcontext as sc
import Rhino.Render as rr
import System.Drawing as sd

rms = [x for x in sc.doc.RenderMaterials]
if len(rms) > 0:
	rm = rms[0]
	rm.BeginChange(rr.RenderContent.ChangeContexts.Program)
	rm.SetParameter("diffuse", sd.Color.FromArgb(random.randint(0,255), random.randint(0,255), random.randint(0, 255)))
	rm.EndChange()

Run the script in a file that has one Custom material and pay attention to the color channel.

From the ChangeContexts enum for scripting purposes the only useful entries are UI, Program and Ignore. For scripts you generally use Program and Ignore, where the latter is for temporary changes.

Nathan,
I was testing your script, but I got the following error:
‘NativeRenderMaterial’ object has no attribute ‘BeginChange’
It looks like sc.doc.RenderMaterials is storing insatances of a child class of RenderMaterial that does not have some attributes. Could it be because I’m using Rhino 5?
Victor

Hmm, right. That works in v6 like that.

In v5 it should be like you wrote earlier, where the ChangeContexts is a parameter to SetParameter(). I have to say I don’t know (yet) why that doesn’t work. I’ll have to ask @andy about that (or if anybody else knows the answer, feel free to chip in).