Hello. I have a Python script [github.com] which creates materials based on input textures. It creates a regular subnetwork and inside it creates all the MTLX node connections and whatnot automatically. Apparently, Solaris does not like those materials and will not import them no matter what. I have tried doing so using the `sceneimport` LOP node and also the `materiallibrary` LOP node. They never show up in the scene graph. If I manually create Material Builders for Karma, VEX and MTLX, those will be imported correctly, even though they are also just regular subnetworks with fancy tab filters (right? They are regular?). I can't find a way of creating those builders using Python.
Another funny discovery that I've made, but this might be my misunderstanding of Solaris: I could try and create my materials inside LOPs in a materiallibrary directly, so I won't need to import them. Again, Material Builder subnets will just show up in the scene graph. My python made, or for that matter, any `regual` subnetwork materials, have to be typed in manually and THEN Solaris recognizes them (view video [youtu.be]).
So my thesis is: VEX/Karma etc. Material Builder nodes are NOT regular subnetworks and there has to be more to it. I went so far to create two materials: A "Karma Material Builder" and a regular subnetwork. Deleted all nodes from within each and copied over all the parameters from the Karma Material Builder to the subnetwork so we work with the same base. I then used this handy script [www.sidefx.com] to extract the info for each node and compared them in the hope that I would find some difference which I could use to make Solaris recognize my materials. Nope, they are both the same apart from a few small details, which can't be the reason. But the Karma Material Builder one is being recognized by Solaris while the regular subnetwork does not. I've attached those files below if anyone wants to take a look.
I just don't understand how to make Solaris NOT discriminate my materials OR how to create the material builder nodes using Python, since that would be the easiest fix.
Solaris does not recognize Python-made Karma materials
1633 10 2- CrisDoesCG
- Member
- 12 posts
- Joined: July 2020
- Offline
- Enivob
- Member
- 2625 posts
- Joined: June 2008
- Offline
Wouldn't you need to create the materials inside a material library instead of the /mat context? Perhaps alter your hou.parent path to point to a Solaris-based node?
hou_parent = hou.node("/stage/materiallibrary1")
Edited by Enivob - May 13, 2024 10:05:39
Using Houdini Indie 20.0
Windows 11 64GB Ryzen 16 core.
nVidia 3050RTX 8BG RAM.
Windows 11 64GB Ryzen 16 core.
nVidia 3050RTX 8BG RAM.
- CrisDoesCG
- Member
- 12 posts
- Joined: July 2020
- Offline
Enivob
Wouldn't you need to create the materials inside a material library instead of the /mat context? Perhaps alter your hou.parent path to point to a Solaris-based node?hou_parent = hou.node("/stage/materiallibrary1")
It doesn't matter where the materials are located, right? The point is, that they are not being recognized, no matter if they are in /mat or in a materiallibrary. As long as they are `regular` subnetworks they won't be seen, in comparison to the material builder nodes.
- Enivob
- Member
- 2625 posts
- Joined: June 2008
- Offline
I'm no Solaris expert, but I think Solaris is built on pathing, so where things are located is highly important.
I altered your code, and it worked to create a material subnet inside a material library on stage. However, the subnet was empty in both test context. Maybe Solaris isn't recognizing it because there is no actual material in the subnet.
I altered your code, and it worked to create a material subnet inside a material library on stage. However, the subnet was empty in both test context. Maybe Solaris isn't recognizing it because there is no actual material in the subnet.
Using Houdini Indie 20.0
Windows 11 64GB Ryzen 16 core.
nVidia 3050RTX 8BG RAM.
Windows 11 64GB Ryzen 16 core.
nVidia 3050RTX 8BG RAM.
- CrisDoesCG
- Member
- 12 posts
- Joined: July 2020
- Offline
Enivob
I'm no Solaris expert, but I think Solaris is built on pathing, so where things are located is highly important.
I altered your code, and it worked to create a material subnet inside a material library on stage. However, the subnet was empty in both test context. Maybe Solaris isn't recognizing it because there is no actual material in the subnet.
Ah, I know what you mean. So the attached files are not MY script. I don't use them for generating materials. They are the output of a script that runs the
asCode()
node.type().name() = "subnet"
Edited by CrisDoesCG - May 13, 2024 11:15:11
- cdordelly
- Member
- 162 posts
- Joined: Nov. 2016
- Offline
Hi!
I haven't checked your code but, maybe you can explore the voptoolutils.py (located inside the python lib on the Houdini installation folder), you will find the code that is used to create the vanilla Karma Material Builder and the others based on subnet, maybe you can compare the code to see if something is missing in your version.
For example, this is the code use to create the Karma Material Builder subnet node:
Of course you will need to explore the functions insideand so on.
Hope that helps,
I haven't checked your code but, maybe you can explore the voptoolutils.py (located inside the python lib on the Houdini installation folder), you will find the code that is used to create the vanilla Karma Material Builder and the others based on subnet, maybe you can compare the code to see if something is missing in your version.
For example, this is the code use to create the Karma Material Builder subnet node:
import voptoolutils mask = voptoolutils.KARMAMTLX_TAB_MASK voptoolutils.createMaskedMtlXSubnet(kwargs, 'karmamaterial', mask, 'Karma Material Builder', 'kma')
Of course you will need to explore the functions inside
createMaskedMtlXSubnet()
Hope that helps,
Edited by cdordelly - May 14, 2024 19:19:59
- CrisDoesCG
- Member
- 12 posts
- Joined: July 2020
- Offline
cdordelly
Hi!
I haven't checked your code but, maybe you can explore the voptoolutils.py (located inside the python lib on the Houdini installation folder), you will find the code that is used to create the vanilla Karma Material Builder and the others based on subnet, maybe you can compare the code to see if something is missing in your version.
For example, this is the code use to create the Karma Material Builder subnet node:import voptoolutils mask = voptoolutils.KARMAMTLX_TAB_MASK voptoolutils.createMaskedMtlXSubnet(kwargs, 'karmamaterial', mask, 'Karma Material Builder', 'kma')
Of course you will need to explore the functions insideand so on.createMaskedMtlXSubnet()
Hope that helps,
Thanks Carlos!
Funny that you mention it, I have just discovered the voptoolutils.py file about two hours ago, and I have been playing around with it since then. I think I have it figured out. What I, embarrassingly, have missed, is that the render flag of the subnet has to be set to True
hou.node("/path/to/subnet").setMaterialFlag(True)
I'll post the code for the Karma Material Builder creation a bit later, one could just copy it from the voptoolutils.py, but its quite extensive there. I'll try to simplify it down a bit for casual use.
Case closed!
- Hamilton Meathouse
- Member
- 199 posts
- Joined: Nov. 2013
- Offline
Regarding the color of text in the Scene Graph Tree: https://www.sidefx.com/docs/houdini/ref/panes/scenegraphtree.html#tree [www.sidefx.com]
- CrisDoesCG
- Member
- 12 posts
- Joined: July 2020
- Offline
Ok so for the solution on how to create a Karma Material Builder using Python, there are two ways:
1. Doing it yourself, something like this (sorry for the messy code):
You will obviously need to delete the nodes that are inside the network, create the outputs and the necessary nodes. But this gives at least a base that will be recognized by Solaris when trying to import it via `sceneimport` node. Also this will give you more control in comparison to
2. Following this video [youtu.be], this works inside a LOP network, but won't work inside any other regual material network. Here is the code:
Thanks to u/EconomyAppeal1106 from this thread [www.reddit.com] who pointed me to their video.
1. Doing it yourself, something like this (sorry for the messy code):
import hou INHERIT_PARM_EXPRESSION = '''n = hou.pwd() n_hasFlag = n.isMaterialFlagSet() i = n.evalParm('inherit_ctrl') r = 'none' if i == 1 or (n_hasFlag and i == 2): r = 'inherit' return r''' destination_path = "/PATH/TO/THE/MATERIAL/DESTINATION" destination_node = hou.node(destination_path) subnetNode = destination_node.createNode("subnet","NAME_OF_YOUR_MATERIAL") subnetNode.moveToGoodPosition() subnetNode.setMaterialFlag(True) parameters = subnetNode.parmTemplateGroup() newParm_hidingFolder = hou.FolderParmTemplate("mtlxBuilder","MaterialX Builder",folder_type=hou.folderType.Collapsible) control_parm_pt = hou.IntParmTemplate('inherit_ctrl','Inherit from Class', num_components=1, default_value=(2,), menu_items=(['0','1','2']), menu_labels=(['Never','Always','Material Flag'])) newParam_tabMenu = hou.StringParmTemplate("tabmenumask", "Tab Menu Mask", 1, default_value=["MaterialX parameter constant collect null genericshader subnet subnetconnector suboutput subinput"]) class_path_pt = hou.properties.parmTemplate('vopui', 'shader_referencetype') class_path_pt.setLabel('Class Arc') class_path_pt.setDefaultExpressionLanguage((hou.scriptLanguage.Python,)) class_path_pt.setDefaultExpression((INHERIT_PARM_EXPRESSION,)) ref_type_pt = hou.properties.parmTemplate('vopui', 'shader_baseprimpath') ref_type_pt.setDefaultValue(['/__class_mtl__/`$OS`']) ref_type_pt.setLabel('Class Prim Path') newParm_hidingFolder.addParmTemplate(newParam_tabMenu) newParm_hidingFolder.addParmTemplate(control_parm_pt) newParm_hidingFolder.addParmTemplate(class_path_pt) newParm_hidingFolder.addParmTemplate(ref_type_pt) parameters.append(newParm_hidingFolder) subnetNode.setParmTemplateGroup(parameters)
You will obviously need to delete the nodes that are inside the network, create the outputs and the necessary nodes. But this gives at least a base that will be recognized by Solaris when trying to import it via `sceneimport` node. Also this will give you more control in comparison to
2. Following this video [youtu.be], this works inside a LOP network, but won't work inside any other regual material network. Here is the code:
import hou import voptoolutils mask = voptoolutils.KARMAMTLX_TAB_MASK viewer = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor) kwargs = { "pane":viewer, "autoplace":True } voptoolutils.createMaskedMtlxSubnet(kwargs,"karmamaterial",mask,"Karma Material Builder", "kma")
Thanks to u/EconomyAppeal1106 from this thread [www.reddit.com] who pointed me to their video.
Edited by CrisDoesCG - May 15, 2024 05:24:30
- slava.panther
- Member
- 1 posts
- Joined: March 2022
- Offline
CrisDoesCG
Ok so for the solution on how to create a Karma Material Builder using Python, there are two ways:
1. Doing it yourself, something like this (sorry for the messy code):import hou INHERIT_PARM_EXPRESSION = '''n = hou.pwd() n_hasFlag = n.isMaterialFlagSet() i = n.evalParm('inherit_ctrl') r = 'none' if i == 1 or (n_hasFlag and i == 2): r = 'inherit' return r''' destination_path = "/PATH/TO/THE/MATERIAL/DESTINATION" destination_node = hou.node(destination_path) subnetNode = destination_node.createNode("subnet","NAME_OF_YOUR_MATERIAL") subnetNode.moveToGoodPosition() subnetNode.setMaterialFlag(True) parameters = subnetNode.parmTemplateGroup() newParm_hidingFolder = hou.FolderParmTemplate("mtlxBuilder","MaterialX Builder",folder_type=hou.folderType.Collapsible) control_parm_pt = hou.IntParmTemplate('inherit_ctrl','Inherit from Class', num_components=1, default_value=(2,), menu_items=(['0','1','2']), menu_labels=(['Never','Always','Material Flag'])) newParam_tabMenu = hou.StringParmTemplate("tabmenumask", "Tab Menu Mask", 1, default_value=["MaterialX parameter constant collect null genericshader subnet subnetconnector suboutput subinput"]) class_path_pt = hou.properties.parmTemplate('vopui', 'shader_referencetype') class_path_pt.setLabel('Class Arc') class_path_pt.setDefaultExpressionLanguage((hou.scriptLanguage.Python,)) class_path_pt.setDefaultExpression((INHERIT_PARM_EXPRESSION,)) ref_type_pt = hou.properties.parmTemplate('vopui', 'shader_baseprimpath') ref_type_pt.setDefaultValue(['/__class_mtl__/`$OS`']) ref_type_pt.setLabel('Class Prim Path') newParm_hidingFolder.addParmTemplate(newParam_tabMenu) newParm_hidingFolder.addParmTemplate(control_parm_pt) newParm_hidingFolder.addParmTemplate(class_path_pt) newParm_hidingFolder.addParmTemplate(ref_type_pt) parameters.append(newParm_hidingFolder) subnetNode.setParmTemplateGroup(parameters)
You will obviously need to delete the nodes that are inside the network, create the outputs and the necessary nodes. But this gives at least a base that will be recognized by Solaris when trying to import it via `sceneimport` node. Also this will give you more control in comparison to
2. Following this video [youtu.be], this works inside a LOP network, but won't work inside any other regual material network. Here is the code:import hou import voptoolutils mask = voptoolutils.KARMAMTLX_TAB_MASK viewer = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor) kwargs = { "pane":viewer, "autoplace":True } voptoolutils.createMaskedMtlxSubnet(kwargs,"karmamaterial",mask,"Karma Material Builder", "kma")
Thanks to u/EconomyAppeal1106 from this thread [www.reddit.com] who pointed me to their video.
Hi, you can try using the _setupMtlXBuilderSubnet function to configure the node in your specific target path in the LOP, it also works.
import hou import voptoolutils mask = voptoolutils.KARMAMTLX_TAB_MASK sel = hou.selectedNodes()[0] root = sel.parent() materialLibrary = sel.createOutputNode("materiallibrary", "MaterialLibrary") kmaPath = materialLibrary.createNode("subnet", "karmamaterial") voptoolutils._setupMtlXBuilderSubnet(kmaPath, "karmamaterial", "karmamaterial", mask, "Karma Material Builder", "kma")
- Petfactory
- Member
- 18 posts
- Joined: Sept. 2013
- Offline
You could also us the _setupMtlXBuilderSubnet function from voptoolutils. set the subnet_node to None and give it a destination_node path.
import voptoolutils # specify the matnet you want to create the karma builder node in dst_node = hou.node('/obj/geo1/lopnet1/matnet1') subnet_node = None name = 'karmamaterial' mask = voptoolutils.KARMAMTLX_TAB_MASK folder_label= 'Karma Material Builder' render_context = "kma" mat_builder = voptoolutils._setupMtlXBuilderSubnet(subnet_node=subnet_node, destination_node=dst_node, name=name, mask=mask, folder_label=folder_label, render_context=render_context)
Edited by Petfactory - Sept. 2, 2024 06:41:53
-
- Quick Links