Add RenderContent to Texture (Color) slot

Hi @nathanletwory,

i try to create a new RenderMaterial from scratch using the Custom shader type. The material should use a Blend shader in the Texture (Color) slot to which i want to assign parameters (textures) later.

From your post on how to add a double sided material here i’ve found that i should save an rmtl file and look at the guids. This worked to create the Custom material eg. like so:

# create Custom material (works)
rm = Rhino.Render.RenderContent.Create(
            System.Guid("BA51C000-BA51-C000-BA51-C0BA51C00000"),
            Rhino.Render.RenderContent.ShowContentChooserFlags.None,
            scriptcontext.doc
                                           )
rm.BeginChange(Rhino.Render.RenderContent.ChangeContexts.Program)
rm.Name = "MyMaterial"
rm.SetParameter("diffuse", Rhino.Display.Color4f(0.274, 0.274, 0.275, 1.0))
rm.EndChange()

Next i gathered the Guid of the Blend shader from the rmtl file and created it sucessfully like so:

# create Blend Texture
blend_material = Rhino.Render.RenderContent.Create(
           System.Guid("3FA30F00-4C3F-4AFE-88AB-D713B0BE2FD8"),
           rm, 
           "Blend Texture",
           Rhino.Render.RenderContent.ShowContentChooserFlags.None,
           scriptcontext.doc
           )

It creates the Blend Texture below the RenderMaterial in the materials tree, but i am unsure how i can set this as the Color Texture of the RenderMaterial ? Below is what i want to create (“CustomMaterialTest”) and what i have (“MyMaterial”) in the Materials tab as image:

grafik

The material i would like to create: CustomMaterialTest.rmtl (88.0 KB)

Is this possible using python ?

thanks,
c.

This is almost correct. Instead of "Blend Texture" you need to pass in the name of the child slot where the texture goes.

If you look in your .rtml you’ll see that the <texture> has an attribute called child-slot-name. The value for this attribute is the name you need to use, so in this case "bitmap-texture".

1 Like

Thank you! it works. I’ll try now to populate the other slots…

_
c.

Good luck. Make sure to inspect the .rmtl files, they give all the clues you need.

Hi @nathanletwory, yes indeed. I just did not scroll so far to the right where the child-slot-name="bitmap-texture" is located :wink:

btw. one follow up question. For the Blend Texture i wanted to assign a Simple Bitmap Texture (as it does not have any other controls) but this pops up a dialog to choose a file:

simple_bitmap_material = Rhino.Render.RenderContent.Create(
                System.Guid("CFB368A4-FFB2-404A-BBA9-497203B5053A"),
                blend_material,
                "blend-texture",
                Rhino.Render.RenderContent.ShowContentChooserFlags.None,
                scriptcontext.doc
                )

Is there a way to suppress this dialog ?

_
c.

I did not know it would pop up a dialog. I don’t currently know if there is a way. Lets ask @andy and @johnc.

Hi @nathanletwory, @andy and @johnc,

just checked and the problem with the popping up dialog also happens if i use a normal “Bitmap Texture” using:

bt = Rhino.Render.RenderContent.Create(
                System.Guid("57E0ED08-1907-4529-B01B-0C4A242455FD"),
                blend_material,
                "blend-texture",
                Rhino.Render.RenderContent.ShowContentChooserFlags.None,
                scriptcontext.doc
                )

instead of “Simple Bitmap Texture”. So the question is how to assign texture paths to these slots with Python programmatically:

grafik

thanks,
c.

Hi @clement,

RenderContent.Create() is a fairly high-level function which takes care of a number of things you wouldn’t normally think of, such as prompting the user for a file name. If you want to suppress this, you need to use a lower-level function. In this case, RenderContentType.NewContentFromTypeId() is that function.

I’m not very good at Python so I’ll give you the code in C# - I believe the syntax is quite similar.

    var material = Rhino.Render.RenderContent.Create(
        new Guid("BA51C000-BA51-C000-BA51-C0BA51C00000"),
        RenderContent.ShowContentChooserFlags.None, doc);

    var texture = RenderContentType.NewContentFromTypeId(
        new Guid("57E0ED08-1907-4529-B01B-0C4A242455FD"));

    material.BeginChange(RenderContent.ChangeContexts.Program);
    material.SetChild(texture, "bitmap-texture");
    material.EndChange();

Regards,

John

1 Like

Thank you @johnc , you beat me by 12 minutes i just was about to post this:

# Simple Bitmap Texture
sbt = Rhino.Render.RenderContentType.NewContentFromTypeId(
                             System.Guid("CFB368A4-FFB2-404A-BBA9-497203B5053A"), 
                             scriptcontext.doc
                             )
    
sbt.BeginChange(Rhino.Render.RenderContent.ChangeContexts.Program)
sbt.Name = "Mask"
sbt.SetParameter("filename", r"D:\Temp\Mask.png")
sbt.SetParameter("filter", False)
sbt.SetParameter("mirror-alternate-tiles", False)
sbt.EndChange()
    
# set as child to blend material 
blend_material.SetChild(sbt, "blend-texture")
blend_material.EndChange()

One thing i do not understand, if i query eg. the filename from my sbt example like this:

query = sbt.GetParameter("filename")
print "Direct query filename: {}".format(query)

i do get None. While if i do the same query on the parent object of sbt, like this:

query = blend_material.FirstChild.GetParameter("filename")
print "Parent query filename: {}".format(query)

i get a Rhino.Render.Variant object which i can extract the file path from. Why does the direct query fail and the parent query not ?

EDIT: i see now, the first query works if it is done before adding sbt as child to the blend_material. Thanks all for your help!

_
c.

@clement,

Regarding your final question, I don’t understand that either, and I also don’t understand why it would be affected by whether or not sbt is a child. In C++, that would work the way you expect. The filename parameter belongs to sbt and has nothing to do with its parent, so querying the parent for it shouldn’t work. Unless, of course, there is something special going on in the Python framework. I’ll ask my team about this because I’d like to understand it myself.

John

Hi @johnc and @nathanletwory,

i’ll just asume that there is something which is not working as expected from the python side. Please review the attached example python script and run it on the example document. It just contains a single material of type Custom to which i’ve assigned a diffuse texture.

If i query the the FirstChild directly using GetParameter like this:

print rm.FirstChild.GetParameter("filename").ToString(None)

if properly returns the file path to the assigned bitmap. However if i query using StandartChildSlot.Diffuse as slot name like this

slot_name = rm.TextureChildSlotName(Rhino.Render.RenderMaterial.StandardChildSlots.Diffuse)
print rm.GetChildSlotParameter("filename", slot_name).ToString(None)

I get a Rhino.Render.Variant which does contain NULL once i try to convert to string. (I’ve just ran into this testing backward compatibillity with RH6 SR34).

GetChildSlotParameterTest.py (572 Bytes)
GetChildSlotParameterTest.3dm (45.1 KB)

_
c.

@clement Before I do anything else I just want to mention that when I wrote this:

“so querying the parent for it shouldn’t work”

I was confused. I had missed the FirstChild. Calling from the material’s first child should work and it does. The only issue is why it didn’t work when you called it on sbt. You said:

“EDIT: i see now, the first query works if it is done before adding sbt as child to the blend_material.”

That seems to be a Python issue; it would always work before or after adding as child if done in C++.

To wrap this up, I will do the final tests you provided and get back to you.

John

Hi @clement,

Sorry for the delay. We have figured out what’s wrong with your call to rm.GetChildSlotParameter(). The problem is in the C# which Python calls into. When the C# was written, based on the C++, the function was named incorrectly. It doesn’t actually get a child slot parameter in the way you were expecting. It gets a special kind of parameter called an “extra requirement” which is used by the automatic UI.

Somehow, the documentation for this fact got lost, leaving the function looking like it does something else. The correct way to get the parameter is your original way, by calling rm.FirstChild.GetParameter().

Sorry for the confusion. I am going to properly document this to prevent similar confusion in the future.

Regards,

John

2 Likes

thank you @johnc, makes all sense now. I’ve also discovered that i can get and set things using the Fields directory which seems to be easier from Python. Not sure if there are any drawbacks using this compared to child parameter access.

I’d just want to report that making the material with all the different populated child slots seems to work on mac, though with a strange bahaviour how it is displayed in the materials tab when it is set to tree display. (I will create a new topic for that as soon as i find some time).

_
c.

Hi @clement,

Under the hood, child parameters are implemented as fields, so using the field dictionary should amount to the same thing. It’s just a different way of getting at the same data. In the rare case of materials belonging to older plug-ins that don’t use fields, child parameters would work when the field dictionary fails. But for all practical purposes you can use whichever is most convenient, especially if you are using our built-in materials (Custom, Glass, Paint etc).

If there is strange behavior in the material tree on the Mac, that would be a UI issue. Please do create a new topic when you have time with a screenshot so we can take a look.

Thanks,

John

1 Like