Creating TexBitmaps via IronPython

I’ve written (with help from Claude.ai) a python script (Rhino 7 IronPython 2.7) that tweaks some V-Ray materials (that have already been convert from Rhino materials, with the name leaf or flower in it).

The diffuse tex is set up in a TexBitmap with the the filename XYZ_albedo.jpg

I want to create 2 new TexBitmaps, following the naming scheme: XYZ_translucency.jpg and XYZ_glossiness.jpg (with the same file location as the diffuse map), and map them to brdf.translucency_color_tex and brdf.reflect_glossiness_tex

Can someone explain how to do this?

import rhinoscriptsyntax as rs
import Rhino
import System
import rhVRay as vray

with vray.Scene.Transaction() as f:
    # Get all V-Ray materials of type MtlSingleBRDF from the scene
    vray_materials = vray.Scene.PluginsByType("MtlSingleBRDF", True)

    # Loop through each V-Ray material
    for material in vray_materials:
        material_name = material.Name

    with vray.Scene.Transaction() as t:
        for material in vray.Scene.Materials:
            brdf = vray.Scene[material.brdf]
            if brdf.Type != "BRDFVRayMtl":
                continue
            # Check if name contains "leaf" OR "flower"
            name_lower = brdf.Name.lower()
            if "leaf" not in name_lower and "flower" not in name_lower:
                continue
            print("Processing: \"{0}\" ...".format(brdf.Name))
            brdf.translucency = 6
            brdf.translucency_amount = 0.3
            brdf.refract_ior = 1.6
            brdf.fresnel_ior = 1.3
            brdf.refract_glossiness = 1
            brdf.refract_thin_walled = 1
            brdf.reflect_color = [1, 1, 1, 1.0]
            brdf.bump_amount_float = 1
            brdf.translucency_color_tex = # ..._translucency.jpg
            brdf.reflect_glossiness_tex =   #..._glossiness.jpg

print("Done!")​

Hi,
This API is pretty basic and is not meant to be used for other than querying basic information and tweaking simple parameters.
That being said creation and deletion of plugins is not exposed.

What you need, though, is not impossible, you just need a small helper file that will create the necessary plugins upon import.

I made a simple .vrmat file that contains the 3 plugins needed for the bitmap:


<vrmat>
 <Asset url="/Bitmap">
  <plugin>
   <vrayplugin name="TexBitmap" version="23" />
  </plugin>
 </Asset>
 <Asset url="/BitmapBuffer">
  <plugin>
   <vrayplugin name="BitmapBuffer" version="23" />
  </plugin>
 </Asset>
 <Asset url="/BitmapUVW">
  <plugin>
   <vrayplugin name="UVWGenChannel" version="23" />
  </plugin>
 </Asset>
</vrmat>

and added a new function to import and properly rename them.


import rhinoscriptsyntax as rs
import Rhino
import System
import rhVRay as vray

def make_bitmap(scene, parent, prefix, file):
    # import the TexBitmap
    scene.LoadSettings(r"<path_to>\TexBitmap.vrmat")

    # get /Bitmap, /BitmapBuffer and /BitmapUVW
    texBitmap = scene["/Bitmap"]
    bitmapBuffer = scene["/BitmapBuffer"]
    bitmapUVW = scene["/BitmapUVW"]

    # rename to handle the hierarchy
    texBitmap._plugin_interface.Name = "%s/%s"%(parent.Name, prefix)
    bitmapBuffer._plugin_interface.Name = "%s/Bitmap"%texBitmap.Name
    bitmapUVW._plugin_interface.Name = "%s/UVW"%texBitmap.Name

    # set properties
    texBitmap.bitmap = bitmapBuffer.Name
    texBitmap.uvwgen = bitmapUVW.Name
    bitmapBuffer.file = file

    return texBitmap

scene = vray.Scene

with scene.Transaction() as t:
    for material in scene.Materials:
        brdf = scene[material.brdf]
        if brdf and brdf.Type != "BRDFVRayMtl":
            continue
        brdfName = brdf.Name

        # Check if name contains "leaf" OR "flower"
        name_lower = brdfName.lower()
        if "leaf" not in name_lower and "flower" not in name_lower:
            continue
        print("Processing: \"{0}\" ...".format(brdfName))
        brdf.translucency = 6
        brdf.translucency_amount = 0.3
        brdf.refract_ior = 1.6
        brdf.fresnel_ior = 1.3
        brdf.refract_glossiness = 1
        brdf.refract_thin_walled = 1
        brdf.reflect_color = [1, 1, 1, 1.0]
        brdf.bump_amount_float = 1
        brdf.translucency_color_tex = make_bitmap(scene, brdf, "Translucency", r"<path_to>\translucency.jpg").Name
        brdf.reflect_glossiness_tex = make_bitmap(scene, brdf, "ReflectGlossiness", r"<path_to>\reflect_glossiness.jpg").Name

print "Done!"

and here is the result:

Also the Claude.ai put a lot of redundant code in that script, that you can safely remove

all files attached flower_leaf.zip
flower_leaf.zip (24.2 KB)

Hi Nikolay,

Thanks for the this help, really appreciate it.

I have two related questions:

1 - I’d like to do something similar with all materials with the name ‘bark’. After looking through the available parameters for a V-Ray mtl (bdrf) I notice that displacement isn’t part of them, so I assume we need to use a vrmat to import another plugin - can you guide me on how to do this? I want to add a _displacement.exr bitmap (the material already has a diffuse and bump bitmap upon import).

2 - When converting Rhino materials to V-Ray materials, I notice that all materials with ‘leaf’ in the name come in a 2-sided v-ray materials when running Rhino.Render.Utilities.ChangeContentType(m, vrayMtlId, True) - is this intended or am I mistaken?

Hi,

1. The displacement works just like the other two properties, but mind that we are talking about material displacement here. The scene hierarchy for that is very different compared to the renderer .vrscene. Basically in the .vrscene file that material displacement is converted to a geometry displacement.
the parameter name is called “displacement” and is pointing to a GeomDisplacedMesh plugin


If you give me more details, I can enhance the script for you

2. The reason you get a Mtl2Sided for the “Leaf” material, is because the enscape compatibility option is turned on. Enscape has this behavior that if you name your material in a certain way, that material is considered to be specific material type. Like “water”, “leaf”, “metal”, “copper”, etc..
If you want the default behavior you must turn the enscape compatibility option off:

Hi Nikolay,

Thanks again for your help on this.

The steps to take take regarding displacement is pretty similar to the leaf material you heped with…

  1. Check materials with ‘trunk’ in its name (sorry, not bark as previously mentioned)
  2. Add a displacement map. The file is matched to the material name… so Material_name_trunk_01 will have a displacement file name Material_name_trunk_01_displacement.exr (note - not all materials named trunk have a _displacement.exr file - if this is the case then we can skip adding a displacement map )
  3. See below for displacement settings:
  4. Add a ​_glossiness.jpg map to reflection glossiness with the same naming scheme mentioned before
  5. Set brdf.reflect_color = [1, 1, 1, 1.0]

Thanks for explaining about about the Enscape settings too!

Hi

I believe it is pretty straightforward, just added another dummy file with GeomDisplacedMesh and that is being loaded into the material.displacement slot (not the brdf!!)
the rest is just repetition:


#! python 2
import rhinoscriptsyntax as rs
import Rhino
import System
import rhVRay as vray

def make_bitmap(scene, parent, prefix, file):
    # import the TexBitmap
    scene.LoadSettings(r"<path_to>\TexBitmap.vrmat")

    # get /Bitmap, /BitmapBuffer and /BitmapUVW
    texBitmap = scene["/Bitmap"]
    bitmapBuffer = scene["/BitmapBuffer"]
    bitmapUVW = scene["/BitmapUVW"]

    # rename to handle the hierarchy
    texBitmap.Name = "%s/%s"%(parent.Name, prefix)
    bitmapBuffer.Name = "%s/Bitmap"%texBitmap.Name
    bitmapUVW.Name = "%s/UVW"%texBitmap.Name

    # set properties
    texBitmap.bitmap = bitmapBuffer.Name
    texBitmap.uvwgen = bitmapUVW.Name
    bitmapBuffer.file = file

    return texBitmap

def make_displacement(scene, parent, prefix, file):
    # import the GeomDisplacement
    scene.LoadSettings(r"<path_to>\GeomDisplacement.vrmat")

    # get /Displacement
    geomDisplacedMesh = scene["/Displacement"]

    # rename to handle the hierarchy
    geomDisplacedMesh.Name = "%s/%s"%(parent.Name, prefix)

    # set properties
    geomDisplacedMesh.edge_length = 100
    geomDisplacedMesh.displacement_tex_color = make_bitmap(scene, geomDisplacedMesh, "Bitmap", file).Name

    return geomDisplacedMesh

def process_leafs(sceene, brdf):
    brdf.translucency = 6
    brdf.translucency_amount = 0.3
    brdf.refract_ior = 1.6
    brdf.fresnel_ior = 1.3
    brdf.refract_glossiness = 1
    brdf.refract_thin_walled = 1
    brdf.reflect_color = [1, 1, 1, 1.0]
    brdf.bump_amount_float = 1
    brdf.translucency_color_tex = make_bitmap(scene, brdf, "Translucency", r"<path_to>\translucency.jpg").Name
    brdf.reflect_glossiness_tex = make_bitmap(scene, brdf, "ReflectGlossiness", r"<path_to>\reflect_glossiness.jpg").Name

def process_barks(scene, material):
    material.displacement = make_displacement(scene, material, "Displacement", r"<path_to>\displacement.jpg").Name

scene = vray.Scene

with scene.Transaction() as t:
    for material in scene.Materials:
        if not material or material.Type != "MtlSingleBRDF":
            continue

        #process barks (set parameters on the material)
        if any(name_lower in material.Name.lower() for name_lower in ["bark"]):
            process_barks(scene, material)

        brdf = scene[material.brdf]
        if not brdf or brdf.Type != "BRDFVRayMtl":
            continue

        # process leafs and flowers (set parameters on the BRDF)
        if any(name_lower in brdf.Name.lower() for name_lower in ["leaf", "flower"]):
            process_leafs(scene, brdf)

print "Done!"

code and example attached flower_leaf_bark.zip

Note:
Mind that currently the Displacement rollout will not appear in the AssetEditor when added by a script, unless you restart it - either save and re-open your file, or release and reacquire the V-Ray license. Both will force NeUI to reset its state and the displacement rollout will be displayed for the “Bark” material
flower_leaf_bark.zip (24.4 KB)