[python] Add hdr environment to double-sided material loaded from file

I have a double-sided material saved to an rmtl file. I want to load that in and then add an hdr environment texture to both front and back materials. I really have looked and looked and have found several examples by @jesterking , but none of the examples seems to be quite what I’m looking for (load a material from a file and add an hdr texture to it…much less to the front and back materials). To be fair, maybe one of his examples was what I was looking for, but maybe I’m just not quite smart enough to understand it, and it is all starting to making my head spin…document materials and render materials being created from each other for some reason and textures and childslots and parameters etc.

here’s an example of a base material I would like to modify…
Gem - Stylized - Amethyst.rmtl (19.9 KB)

and a code stub of what I could come up with so far…

#! python 2
import scriptcontext as sc
import Rhino.Render as rr

mtl_path = "path\\to\\my\\custom\\material\\Gem - Stylized - Amethyst.rmtl"
hdr_path = "path\\to\\any\\hdr\\will\\be\\fine.hdr"

mtl = rr.RenderContent.LoadFromFile(mtl_path)
fmtl = mtl.FindChild('front')
bmtl = mtl.FindChild('back')

# add hdr to the environment slot of the front and back materials here

sc.doc.RenderMaterials.Add(mtl) 

Once you have the front or back material you can use the RenderContent.SetChild Method (RenderContent, String) method to set the texture you need to set.

So first create a RenderTexture of type ContentUuids.HDRTextureType Property, set the file path (see example https://jesterking.github.io/rhipy/change_texture_filepath.html ), then assing to the environment-texture child slot. Remember to open your .rmtl file in a text editor so you can find out what the different child slot (parameter) names are.

1 Like

Thank you! I will try that and report back with my results.

This seemed to be what worked for me. It seems a separate texture object had to be created for the back material (I think it was simply ignored if I tried to use the same texture as was used in the front material…like something somewhere said, “Nope, you are already using that one”). No error was thrown, but the back material just didn’t get assigned any hdr texture until I created a second texture object. Or, at least, I think that was what happened.

Anyway, I also had to turn the texture on for both materials. And then it worked.

Thank you for your help!

(NOTE: In my actual code, I build the paths with os.path.join() to keep things cross-platform)

#! python 2
import scriptcontext as sc
import Rhino.Render as rr

dsmtl_path = "path\\to\\double\\sided\\material.rmtl"
hdr_path = "path\\to\\somehdr.hdr"

# load double-sided mtl, get its front and back materials
dsmtl = rr.RenderContent.LoadFromFile(dsmtl_path)
fmtl = dsmtl.FindChild('front')
bmtl = dsmtl.FindChild('back')

# create texture for front mtl
hdr_texture_type_guid = rr.ContentUuids.HDRTextureType
hdrtex1 = rr.RenderContentType.NewContentFromTypeId(hdr_texture_type_guid)
hdrtex1.Filename = hdr_path

# create texture for back mtl
hdrtex2 = rr.RenderContentType.NewContentFromTypeId(hdr_texture_type_guid)
hdrtex2.Filename = hdr_path

# set texture on front mtl, turn it on
fmtl.SetChild(hdrtex1, 'environment-texture')
fmtl.SetParameter('environment-texture-on', True)

# set texture on the back mtl, turn it on
bmtl.SetChild(hdrtex2, 'environment-texture')
bmtl.SetParameter('environment-texture-on', True)

# add double-sided mtl to doc
sc.doc.RenderMaterials.Add(dsmtl) 
1 Like

@nathanletwory

In Rhino 6, the line bmtex.Filename = bm_path is throwing an error “NativeRenderTexture object has no attribute Filename.”

Is there another way to set the image path on the texture object in Rhino 6?

    def AddBitmapTextureToMaterial(self, mtl, bm_path):
        # create tex for front mtl
        bm_texture_type_guid = rr.ContentUuids.BitmapTextureType
        bmtex = rr.RenderContentType.NewContentFromTypeId(bm_texture_type_guid)

        # ERROR in Rhino6 !!!
        bmtex.Filename = bm_path

        # set texture on mtl and turn it on
        mtl.SetChild(bmtex, 'bitmap-texture')
        mtl.SetParameter('bitmap-texture-on', True)

If you create a bitmap texture in Rhino 6, then save it to disk was an .rtex file you can open that in a text editor. You’ll find that the path is set as the parameter filename. You should be able to use the SetParameter method on RenderContent to set that.

@nathanletwory

This is what I’ve got so far, and it is adding the texture now (thank you), but it doesn’t turn it on in Rhino6. And it does seem that ‘bitmap-texture-on’ is the correct attribute according to the rmtl…unless I’m missing something.

Any ideas?

    def AddBitmapTextureToMaterial(self, mtl, bm_path):
        # create tex for front mtl
        bm_texture_type_guid = rr.ContentUuids.BitmapTextureType
        bmtex = rr.RenderContentType.NewContentFromTypeId(bm_texture_type_guid)
        
        # this works in Rhino 6, 7, and 8
        bmtex.SetParameter('filename', bm_path)

        # set texture on mtl and turn it on
        mtl.SetChild(bmtex, 'bitmap-texture')
        mtl.SetParameter('bitmap-texture-on', True)

You probably need to bracket code that makes changes to RenderContent in v6 with RenderContent.BeginChange Method and RenderContent.EndChange Method

@nathanletwory

(Sorry to keep bothering you).
This is what I’ve got now, but it’s still not turning on. Did I do it right? (it doesn’t throw any errors, but it also doesn’t turn the texture on)

    def AddBitmapTextureToMaterial(self, mtl, bm_path):
        # create tex for front mtl
        bm_texture_type_guid = rr.ContentUuids.BitmapTextureType
        bmtex = rr.RenderContentType.NewContentFromTypeId(bm_texture_type_guid)
        
        # bmtex.Filename is not available in Rhino6
        # so we use this as it works in Rhino6 and up
        bmtex.SetParameter('filename', bm_path)
        
        # set texture on mtl and turn it on
        mtl.BeginChange(rr.RenderContent.ChangeContexts.Program)
        mtl.SetChild(bmtex, 'bitmap-texture')
        mtl.SetParameter('bitmap-texture-on', True)
        mtl.EndChange()

I will have to check tomorrow when I’m back at work.

1 Like