Expose API + Graphing Utilities for Shader Generator Graphs #2790
Expose API + Graphing Utilities for Shader Generator Graphs #2790kwokcb wants to merge 14 commits into
Conversation
|
Thanks for putting this together, @kwokcb! I like the idea of adding functionality that allows us to visualize the generated Before we commit to a direction, though, I'd like to propose an alternative that might make this more reusable over the long term. The generated graph isn't really hidden in C++: Does that sound like a reasonable path forward to you as well? |
|
I assumed there is a reason to not expose It seems this increases the API "surface area" unduly since there has never been any request to expose the graph before. I also don't know if this would hinder longer term "visitor" refactor work so pinging @ld-kerley -- i.e. is the graph is a form that may change over time. I'm hesitant to add another construct like an iterator to hide exposure of internals. Finally this means that the same logic needs to be repeated externally for every implementation language instead of a single call. -- An alternative is to specify the output format as an argument. This leaves it open to extend later on if required without an API signature change. |
Write custom mermaid pyhon + js. Js is added as a module utility, Python is in generatesahder utility.
|
@jstone-lucasfilm, Had a rethink on this as I was using this for nestd nodegraph debugging and needed to access the graph for external validation. Thus I've added the API as you proposed and added sample utilities in JS and Python. A bit more maintenance but it's easier to maintain and enhance this way. |
| import MaterialX.PyMaterialXGenShader as mx_gen_shader | ||
|
|
||
|
|
||
| def createMermaidGraph(shader, showInputValues): |
There was a problem hiding this comment.
Externalized API usage for Mermaid graphs in Python. This could be a module level utility function instead / as well for general availabiity. (which I had to do for JS).
| (function () { | ||
| onModuleReady(function () { | ||
| // Generate a Mermaid graph string for a generated Shader using JS-side APIs. | ||
| function _mxEscapeMermaidLabel(value) { |
There was a problem hiding this comment.
Externalized API usage for Mermaid graphs in Javascript.
| .def("setAttribute", static_cast<void (mx::Shader::*)(const std::string&)>(&mx::Shader::setAttribute)) | ||
| .def("setAttribute", static_cast<void (mx::Shader::*)(const std::string&, mx::ValuePtr)>(&mx::Shader::setAttribute)); | ||
|
|
||
| py::class_<mx::ShaderNode, mx::ShaderNodePtr>(mod, "ShaderNode") |
| .def("setName", &mx::ShaderPort::setName) | ||
| .def("getName", &mx::ShaderPort::getName) | ||
| .def("getFullName", &mx::ShaderPort::getFullName) | ||
| .def("getNode", static_cast<mx::ShaderNode* (mx::ShaderPort::*)()>(&mx::ShaderPort::getNode), py::return_value_policy::reference) |
There was a problem hiding this comment.
Don't actually need to expose a graph, just get nodes in graph as that's the only interface that's required on the ShaderGraph class.
| .def("isUniform", &mx::ShaderPort::isUniform) | ||
| .def("isEmitted", &mx::ShaderPort::isEmitted); | ||
|
|
||
| py::class_<mx::ShaderInput, mx::ShaderInputPtr, mx::ShaderPort>(mod, "ShaderInput") |
There was a problem hiding this comment.
Add Input and Outputs to access connectivity.
|
|
||
|
|
||
| set(JS_LINK_FLAGS_GENSHADER "${JS_LINK_FLAGS_CORE} --preload-file ${PROJECT_SOURCE_DIR}/libraries@libraries ") | ||
| set(JS_LINK_FLAGS_GENSHADER "${JS_LINK_FLAGS_CORE} --post-js ${GENSHADER}post.js --preload-file ${PROJECT_SOURCE_DIR}/libraries@libraries ") |
There was a problem hiding this comment.
Look for all post.js files.
Test with complete and reduced interfaces to show differences.
API Exposure Change
The graphs produced by shader generation are hard to debug / visualize as they are using a different data model.
The proposed change here is to be able to create a graph diagram using Python or Javascript by
exposing more of the internal C++ API.
As an example usage Mermaid graph generation is provided as a utility.
API Modifications
ShaderNode,ShaderInputandShaderOutputShadergenerateshader.py.Tests
Sample Results
( Markdown wrappers are added as part of
generateshader.py)e.g. Velvet (no input expansion)
graph TB geomprop_Nworld["geomprop_Nworld (TEXTURE|GEOMETRIC)"] style geomprop_Nworld fill:#4B0336,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Tworld["geomprop_Tworld (TEXTURE|GEOMETRIC)"] style geomprop_Tworld fill:#4B0336,stroke:#222222,stroke-width:1px,color:#ffffff SR_velvet["SR_velvet (SHADER|SURFACE|CLOSURE)"] style SR_velvet fill:#0e7865,stroke:#222222,stroke-width:1px,color:#ffffff Velvet["Velvet (MATERIAL|SHADER|SURFACE|CLOSURE)"] style Velvet fill:#7ccba2,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Nworld --"out --> coat_normal"--> SR_velvet geomprop_Nworld --"out --> normal"--> SR_velvet geomprop_Tworld --"out --> tangent"--> SR_velvet SR_velvet --"out --> surfaceshader"--> Velvete.g. Tiled Brass (input expansion)
graph LR geomprop_Nworld["geomprop_Nworld (TEXTURE|GEOMETRIC)"] style geomprop_Nworld fill:#4B0336,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Tworld["geomprop_Tworld (TEXTURE|GEOMETRIC)"] style geomprop_Tworld fill:#4B0336,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_UV0["geomprop_UV0 (TEXTURE|GEOMETRIC)"] style geomprop_UV0 fill:#4B0336,stroke:#222222,stroke-width:1px,color:#ffffff NG_brass1/image_roughness["NG_brass1/image_roughness (TEXTURE|FILETEXTURE|SAMPLE2D)"] style NG_brass1/image_roughness fill:#be5ae6,stroke:#222222,stroke-width:1px,color:#ffffff NG_brass1/image_color["NG_brass1/image_color (TEXTURE|FILETEXTURE|SAMPLE2D)"] style NG_brass1/image_color fill:#be5ae6,stroke:#222222,stroke-width:1px,color:#ffffff image_color_out_cm["image_color_out_cm (TEXTURE)"] style image_color_out_cm fill:#c27ff8,stroke:#222222,stroke-width:1px,color:#ffffff SR_brass1["SR_brass1 (SHADER|SURFACE|CLOSURE)"] style SR_brass1 fill:#0e7865,stroke:#222222,stroke-width:1px,color:#ffffff Tiled_Brass["Tiled_Brass (MATERIAL|SHADER|SURFACE|CLOSURE)"] style Tiled_Brass fill:#7ccba2,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Nworld --"out --> coat_normal"--> SR_brass1 geomprop_Nworld --"out --> normal"--> SR_brass1 geomprop_Nworld/space["space = 2"] --> geomprop_Nworld geomprop_Tworld --"out --> tangent"--> SR_brass1 geomprop_Tworld/space["space = 2"] --> geomprop_Tworld geomprop_Tworld/index["index = 0"] --> geomprop_Tworld geomprop_UV0 --"out --> texcoord"--> NG_brass1/image_roughness geomprop_UV0 --"out --> texcoord"--> NG_brass1/image_color geomprop_UV0/index["index = 0"] --> geomprop_UV0 NG_brass1/image_roughness --"out --> specular_roughness"--> SR_brass1 NG_brass1/image_roughness --"out --> coat_roughness"--> SR_brass1 NG_brass1/image_roughness/file["file = ../../../Images/brass_roughness.jpg"] --> NG_brass1/image_roughness NG_brass1/image_roughness/default["default = 0"] --> NG_brass1/image_roughness NG_brass1/image_roughness/uvtiling["uvtiling = 1, 1"] --> NG_brass1/image_roughness NG_brass1/image_roughness/uvoffset["uvoffset = 0, 0"] --> NG_brass1/image_roughness NG_brass1/image_roughness/realworldimagesize["realworldimagesize = 1, 1"] --> NG_brass1/image_roughness NG_brass1/image_roughness/realworldtilesize["realworldtilesize = 1, 1"] --> NG_brass1/image_roughness NG_brass1/image_roughness/filtertype["filtertype = 1"] --> NG_brass1/image_roughness NG_brass1/image_roughness/frameoffset["frameoffset = 0"] --> NG_brass1/image_roughness NG_brass1/image_roughness/frameendaction["frameendaction = 0"] --> NG_brass1/image_roughness NG_brass1/image_color --"out --> in"--> image_color_out_cm NG_brass1/image_color/file["file = ../../../Images/brass_color.jpg"] --> NG_brass1/image_color NG_brass1/image_color/default["default = 0, 0, 0"] --> NG_brass1/image_color NG_brass1/image_color/uvtiling["uvtiling = 1, 1"] --> NG_brass1/image_color NG_brass1/image_color/uvoffset["uvoffset = 0, 0"] --> NG_brass1/image_color NG_brass1/image_color/realworldimagesize["realworldimagesize = 1, 1"] --> NG_brass1/image_color NG_brass1/image_color/realworldtilesize["realworldtilesize = 1, 1"] --> NG_brass1/image_color NG_brass1/image_color/filtertype["filtertype = 1"] --> NG_brass1/image_color NG_brass1/image_color/frameoffset["frameoffset = 0"] --> NG_brass1/image_color NG_brass1/image_color/frameendaction["frameendaction = 0"] --> NG_brass1/image_color image_color_out_cm --"out --> coat_color"--> SR_brass1 image_color_out_cm/in["in = 0, 0, 0"] --> image_color_out_cm SR_brass1 --"out --> surfaceshader"--> Tiled_Brass SR_brass1/base["base = 1"] --> SR_brass1 SR_brass1/base_color["base_color = 1, 1, 1"] --> SR_brass1 SR_brass1/diffuse_roughness["diffuse_roughness = 0"] --> SR_brass1 SR_brass1/metalness["metalness = 1"] --> SR_brass1 SR_brass1/specular["specular = 0"] --> SR_brass1 SR_brass1/specular_color["specular_color = 1, 1, 1"] --> SR_brass1 SR_brass1/specular_roughness["specular_roughness = 0.2"] --> SR_brass1 SR_brass1/specular_IOR["specular_IOR = 1.5"] --> SR_brass1 SR_brass1/specular_anisotropy["specular_anisotropy = 0"] --> SR_brass1 SR_brass1/specular_rotation["specular_rotation = 0"] --> SR_brass1 SR_brass1/transmission["transmission = 0"] --> SR_brass1 SR_brass1/transmission_color["transmission_color = 1, 1, 1"] --> SR_brass1 SR_brass1/transmission_depth["transmission_depth = 0"] --> SR_brass1 SR_brass1/transmission_scatter["transmission_scatter = 0, 0, 0"] --> SR_brass1 SR_brass1/transmission_scatter_anisotropy["transmission_scatter_anisotropy = 0"] --> SR_brass1 SR_brass1/transmission_dispersion["transmission_dispersion = 0"] --> SR_brass1 SR_brass1/transmission_extra_roughness["transmission_extra_roughness = 0"] --> SR_brass1 SR_brass1/subsurface["subsurface = 0"] --> SR_brass1 SR_brass1/subsurface_color["subsurface_color = 1, 1, 1"] --> SR_brass1 SR_brass1/subsurface_radius["subsurface_radius = 1, 1, 1"] --> SR_brass1 SR_brass1/subsurface_scale["subsurface_scale = 1"] --> SR_brass1 SR_brass1/subsurface_anisotropy["subsurface_anisotropy = 0"] --> SR_brass1 SR_brass1/sheen["sheen = 0"] --> SR_brass1 SR_brass1/sheen_color["sheen_color = 1, 1, 1"] --> SR_brass1 SR_brass1/sheen_roughness["sheen_roughness = 0.3"] --> SR_brass1 SR_brass1/coat["coat = 1"] --> SR_brass1 SR_brass1/coat_color["coat_color = 1, 1, 1"] --> SR_brass1 SR_brass1/coat_roughness["coat_roughness = 0.1"] --> SR_brass1 SR_brass1/coat_anisotropy["coat_anisotropy = 0"] --> SR_brass1 SR_brass1/coat_rotation["coat_rotation = 0"] --> SR_brass1 SR_brass1/coat_IOR["coat_IOR = 1.5"] --> SR_brass1 SR_brass1/coat_affect_color["coat_affect_color = 0"] --> SR_brass1 SR_brass1/coat_affect_roughness["coat_affect_roughness = 0"] --> SR_brass1 SR_brass1/thin_film_thickness["thin_film_thickness = 0"] --> SR_brass1 SR_brass1/thin_film_IOR["thin_film_IOR = 1.5"] --> SR_brass1 SR_brass1/emission["emission = 0"] --> SR_brass1 SR_brass1/emission_color["emission_color = 1, 1, 1"] --> SR_brass1 SR_brass1/opacity["opacity = 1, 1, 1"] --> SR_brass1 SR_brass1/thin_walled["thin_walled = false"] --> SR_brass1Visualize input sockets (exposed uniforms) vs internal nodes for BoomBox:
Reducedinterface (less expose uniforms)graph LR geomprop_Tworld["geomprop_Tworld (TEXTURE|GEOMETRIC)"] style geomprop_Tworld fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Nworld["geomprop_Nworld (TEXTURE|GEOMETRIC)"] style geomprop_Nworld fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_UV0["geomprop_UV0 (TEXTURE|GEOMETRIC)"] style geomprop_UV0 fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff image_basecolor["image_basecolor (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_basecolor fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_orm["image_orm (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_orm fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_normal["image_normal (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_normal fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_emission["image_emission (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_emission fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_basecolor_outcolor_cm["image_basecolor_outcolor_cm (TEXTURE)"] style image_basecolor_outcolor_cm fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff image_orm_channels["image_orm_channels (TEXTURE)"] style image_orm_channels fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff image_emission_out_cm["image_emission_out_cm (TEXTURE)"] style image_emission_out_cm fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff SR_boombox["SR_boombox (SHADER|SURFACE|CLOSURE)"] style SR_boombox fill:#0e7865,stroke:#222222,stroke-width:1px,color:#ffffff Material_boombox["Material_boombox (MATERIAL|SHADER|SURFACE|CLOSURE)"] style Material_boombox fill:#7ccba2,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Tworld --"out --> tangent"--> SR_boombox geomprop_Tworld/space["space = 2"] --"space"--> geomprop_Tworld geomprop_Tworld/index["index = 0"] --"index"--> geomprop_Tworld geomprop_Nworld --"out --> clearcoat_normal"--> SR_boombox geomprop_Nworld/space["space = 2"] --"space"--> geomprop_Nworld geomprop_UV0 --"out --> texcoord"--> image_basecolor geomprop_UV0 --"out --> texcoord"--> image_orm geomprop_UV0 --"out --> texcoord"--> image_normal geomprop_UV0 --"out --> texcoord"--> image_emission geomprop_UV0/index["index = 0"] --"index"--> geomprop_UV0 image_basecolor --"outcolor --> in"--> image_basecolor_outcolor_cm image_basecolor --"outa --> alpha"--> SR_boombox image_basecolor/file["file = image_basecolor_file"] --"file"--> image_basecolor image_basecolor/default["default = 0, 0, 0, 0"] --"default"--> image_basecolor image_basecolor/pivot["pivot = 0, 1"] --"pivot"--> image_basecolor image_basecolor/scale["scale = 1, 1"] --"scale"--> image_basecolor image_basecolor/rotate["rotate = 0"] --"rotate"--> image_basecolor image_basecolor/offset["offset = 0, 0"] --"offset"--> image_basecolor image_basecolor/operationorder["operationorder = 1"] --"operationorder"--> image_basecolor image_basecolor/uaddressmode["uaddressmode = 2"] --"uaddressmode"--> image_basecolor image_basecolor/vaddressmode["vaddressmode = 2"] --"vaddressmode"--> image_basecolor image_basecolor/filtertype["filtertype = 1"] --"filtertype"--> image_basecolor image_basecolor/color["color = 1, 1, 1, 1"] --"color"--> image_basecolor image_basecolor/geomcolor["geomcolor = 1, 1, 1, 1"] --"geomcolor"--> image_basecolor image_orm --"out --> in"--> image_orm_channels image_orm/file["file = image_orm_file"] --"file"--> image_orm image_orm/default["default = 0, 0, 0"] --"default"--> image_orm image_orm/pivot["pivot = 0, 1"] --"pivot"--> image_orm image_orm/scale["scale = 1, 1"] --"scale"--> image_orm image_orm/rotate["rotate = 0"] --"rotate"--> image_orm image_orm/offset["offset = 0, 0"] --"offset"--> image_orm image_orm/operationorder["operationorder = 0"] --"operationorder"--> image_orm image_orm/uaddressmode["uaddressmode = 2"] --"uaddressmode"--> image_orm image_orm/vaddressmode["vaddressmode = 2"] --"vaddressmode"--> image_orm image_orm/filtertype["filtertype = 1"] --"filtertype"--> image_orm image_normal --"out --> normal"--> SR_boombox image_normal/file["file = image_normal_file"] --"file"--> image_normal image_normal/default["default = 0.5, 0.5, 1"] --"default"--> image_normal image_normal/pivot["pivot = 0, 1"] --"pivot"--> image_normal image_normal/scale["scale = 1, 1"] --"scale"--> image_normal image_normal/rotate["rotate = 0"] --"rotate"--> image_normal image_normal/offset["offset = 0, 0"] --"offset"--> image_normal image_normal/operationorder["operationorder = 0"] --"operationorder"--> image_normal image_normal/uaddressmode["uaddressmode = 2"] --"uaddressmode"--> image_normal image_normal/vaddressmode["vaddressmode = 2"] --"vaddressmode"--> image_normal image_normal/filtertype["filtertype = 1"] --"filtertype"--> image_normal image_emission --"out --> in"--> image_emission_out_cm image_emission/file["file = image_emission_file"] --"file"--> image_emission image_emission/factor["factor = 1, 1, 1"] --"factor"--> image_emission image_emission/default["default = 0, 0, 0"] --"default"--> image_emission image_emission/pivot["pivot = 0, 1"] --"pivot"--> image_emission image_emission/scale["scale = 1, 1"] --"scale"--> image_emission image_emission/rotate["rotate = 0"] --"rotate"--> image_emission image_emission/offset["offset = 0, 0"] --"offset"--> image_emission image_emission/operationorder["operationorder = 0"] --"operationorder"--> image_emission image_emission/uaddressmode["uaddressmode = 2"] --"uaddressmode"--> image_emission image_emission/vaddressmode["vaddressmode = 2"] --"vaddressmode"--> image_emission image_emission/filtertype["filtertype = 1"] --"filtertype"--> image_emission image_basecolor_outcolor_cm --"out --> base_color"--> SR_boombox image_basecolor_outcolor_cm/in["image_basecolor_outcolor = 0, 0, 0"] --"in"--> image_basecolor_outcolor_cm image_orm_channels --"outx --> occlusion"--> SR_boombox image_orm_channels --"outy --> roughness"--> SR_boombox image_orm_channels --"outz --> metallic"--> SR_boombox image_orm_channels/in["image_orm_out = 0, 0, 0"] --"in"--> image_orm_channels image_emission_out_cm --"out --> emissive"--> SR_boombox image_emission_out_cm/in["image_emission_out = 0, 0, 0"] --"in"--> image_emission_out_cm SR_boombox --"out --> surfaceshader"--> Material_boombox SR_boombox/base_color["image_basecolor_outcolor_cm_out = 1, 1, 1"] --"base_color"--> SR_boombox SR_boombox/metallic["image_orm_channels_outz = 1"] --"metallic"--> SR_boombox SR_boombox/roughness["image_orm_channels_outy = 1"] --"roughness"--> SR_boombox SR_boombox/occlusion["image_orm_channels_outx = 1"] --"occlusion"--> SR_boombox SR_boombox/transmission["transmission = 0"] --"transmission"--> SR_boombox SR_boombox/specular["specular = 1"] --"specular"--> SR_boombox SR_boombox/specular_color["specular_color = 1, 1, 1"] --"specular_color"--> SR_boombox SR_boombox/ior["ior = 1.5"] --"ior"--> SR_boombox SR_boombox/alpha["image_basecolor_outa = 1"] --"alpha"--> SR_boombox SR_boombox/alpha_mode["alpha_mode = 0"] --"alpha_mode"--> SR_boombox SR_boombox/alpha_cutoff["alpha_cutoff = 0.5"] --"alpha_cutoff"--> SR_boombox SR_boombox/iridescence["iridescence = 0"] --"iridescence"--> SR_boombox SR_boombox/iridescence_ior["iridescence_ior = 1.3"] --"iridescence_ior"--> SR_boombox SR_boombox/iridescence_thickness["iridescence_thickness = 100"] --"iridescence_thickness"--> SR_boombox SR_boombox/sheen_color["sheen_color = 0, 0, 0"] --"sheen_color"--> SR_boombox SR_boombox/sheen_roughness["sheen_roughness = 0"] --"sheen_roughness"--> SR_boombox SR_boombox/clearcoat["clearcoat = 0"] --"clearcoat"--> SR_boombox SR_boombox/clearcoat_roughness["clearcoat_roughness = 0"] --"clearcoat_roughness"--> SR_boombox SR_boombox/emissive["image_emission_out_cm_out = 0, 0, 0"] --"emissive"--> SR_boombox SR_boombox/emissive_strength["emissive_strength = 1"] --"emissive_strength"--> SR_boombox SR_boombox/thickness["thickness = 0"] --"thickness"--> SR_boombox SR_boombox/attenuation_color["attenuation_color = 1, 1, 1"] --"attenuation_color"--> SR_boombox SR_boombox/anisotropy_strength["anisotropy_strength = 0"] --"anisotropy_strength"--> SR_boombox SR_boombox/anisotropy_rotation["anisotropy_rotation = 0"] --"anisotropy_rotation"--> SR_boombox SR_boombox/dispersion["dispersion = 0"] --"dispersion"--> SR_boomboxversus
Fullinterface (expose more uniforms)graph LR geomprop_Tworld["geomprop_Tworld (TEXTURE|GEOMETRIC)"] style geomprop_Tworld fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Nworld["geomprop_Nworld (TEXTURE|GEOMETRIC)"] style geomprop_Nworld fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_UV0["geomprop_UV0 (TEXTURE|GEOMETRIC)"] style geomprop_UV0 fill:#4B0349,stroke:#222222,stroke-width:1px,color:#ffffff image_basecolor["image_basecolor (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_basecolor fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_orm["image_orm (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_orm fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_normal["image_normal (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_normal fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_emission["image_emission (TEXTURE|FILETEXTURE|SAMPLE2D)"] style image_emission fill:#3d174c,stroke:#222222,stroke-width:1px,color:#ffffff image_basecolor_outcolor_cm["image_basecolor_outcolor_cm (TEXTURE)"] style image_basecolor_outcolor_cm fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff image_orm_channels["image_orm_channels (TEXTURE)"] style image_orm_channels fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff image_emission_out_cm["image_emission_out_cm (TEXTURE)"] style image_emission_out_cm fill:#6b5e76,stroke:#222222,stroke-width:1px,color:#ffffff SR_boombox["SR_boombox (SHADER|SURFACE|CLOSURE)"] style SR_boombox fill:#0e7865,stroke:#222222,stroke-width:1px,color:#ffffff Material_boombox["Material_boombox (MATERIAL|SHADER|SURFACE|CLOSURE)"] style Material_boombox fill:#7ccba2,stroke:#222222,stroke-width:1px,color:#ffffff geomprop_Tworld --"out --> tangent"--> SR_boombox geomprop_Tworld/space["space = 2"] --"space"--> geomprop_Tworld geomprop_Tworld/index["index = 0"] --"index"--> geomprop_Tworld geomprop_Nworld --"out --> clearcoat_normal"--> SR_boombox geomprop_Nworld/space["space = 2"] --"space"--> geomprop_Nworld geomprop_UV0 --"out --> texcoord"--> image_basecolor geomprop_UV0 --"out --> texcoord"--> image_orm geomprop_UV0 --"out --> texcoord"--> image_normal geomprop_UV0 --"out --> texcoord"--> image_emission geomprop_UV0/index["geomprop_UV0_index = 0 [SOCKET]"] --"index"--> geomprop_UV0 style geomprop_UV0/index fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor --"outcolor --> in"--> image_basecolor_outcolor_cm image_basecolor --"outa --> alpha"--> SR_boombox image_basecolor/file["image_basecolor_file = boombox/BoomBox_baseColor.png [SOCKET]"] --"file"--> image_basecolor style image_basecolor/file fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/default["image_basecolor_default = 0, 0, 0, 0 [SOCKET]"] --"default"--> image_basecolor style image_basecolor/default fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/pivot["image_basecolor_pivot = 0, 1 [SOCKET]"] --"pivot"--> image_basecolor style image_basecolor/pivot fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/scale["image_basecolor_scale = 1, 1 [SOCKET]"] --"scale"--> image_basecolor style image_basecolor/scale fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/rotate["image_basecolor_rotate = 0 [SOCKET]"] --"rotate"--> image_basecolor style image_basecolor/rotate fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/offset["image_basecolor_offset = 0, 0 [SOCKET]"] --"offset"--> image_basecolor style image_basecolor/offset fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/operationorder["image_basecolor_operationorder = 1 [SOCKET]"] --"operationorder"--> image_basecolor style image_basecolor/operationorder fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/uaddressmode["image_basecolor_uaddressmode = 2 [SOCKET]"] --"uaddressmode"--> image_basecolor style image_basecolor/uaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/vaddressmode["image_basecolor_vaddressmode = 2 [SOCKET]"] --"vaddressmode"--> image_basecolor style image_basecolor/vaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/filtertype["image_basecolor_filtertype = 1 [SOCKET]"] --"filtertype"--> image_basecolor style image_basecolor/filtertype fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/color["image_basecolor_color = 1, 1, 1, 1 [SOCKET]"] --"color"--> image_basecolor style image_basecolor/color fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor/geomcolor["image_basecolor_geomcolor = 1, 1, 1, 1 [SOCKET]"] --"geomcolor"--> image_basecolor style image_basecolor/geomcolor fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm --"out --> in"--> image_orm_channels image_orm/file["image_orm_file = boombox/BoomBox_occlusionRoughnessMetallic.png [SOCKET]"] --"file"--> image_orm style image_orm/file fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/default["image_orm_default = 0, 0, 0 [SOCKET]"] --"default"--> image_orm style image_orm/default fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/pivot["image_orm_pivot = 0, 1 [SOCKET]"] --"pivot"--> image_orm style image_orm/pivot fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/scale["image_orm_scale = 1, 1 [SOCKET]"] --"scale"--> image_orm style image_orm/scale fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/rotate["image_orm_rotate = 0 [SOCKET]"] --"rotate"--> image_orm style image_orm/rotate fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/offset["image_orm_offset = 0, 0 [SOCKET]"] --"offset"--> image_orm style image_orm/offset fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/operationorder["image_orm_operationorder = 0 [SOCKET]"] --"operationorder"--> image_orm style image_orm/operationorder fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/uaddressmode["image_orm_uaddressmode = 2 [SOCKET]"] --"uaddressmode"--> image_orm style image_orm/uaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/vaddressmode["image_orm_vaddressmode = 2 [SOCKET]"] --"vaddressmode"--> image_orm style image_orm/vaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_orm/filtertype["image_orm_filtertype = 1 [SOCKET]"] --"filtertype"--> image_orm style image_orm/filtertype fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal --"out --> normal"--> SR_boombox image_normal/file["image_normal_file = boombox/BoomBox_normal.png [SOCKET]"] --"file"--> image_normal style image_normal/file fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/default["image_normal_default = 0.5, 0.5, 1 [SOCKET]"] --"default"--> image_normal style image_normal/default fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/pivot["image_normal_pivot = 0, 1 [SOCKET]"] --"pivot"--> image_normal style image_normal/pivot fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/scale["image_normal_scale = 1, 1 [SOCKET]"] --"scale"--> image_normal style image_normal/scale fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/rotate["image_normal_rotate = 0 [SOCKET]"] --"rotate"--> image_normal style image_normal/rotate fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/offset["image_normal_offset = 0, 0 [SOCKET]"] --"offset"--> image_normal style image_normal/offset fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/operationorder["image_normal_operationorder = 0 [SOCKET]"] --"operationorder"--> image_normal style image_normal/operationorder fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/uaddressmode["image_normal_uaddressmode = 2 [SOCKET]"] --"uaddressmode"--> image_normal style image_normal/uaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/vaddressmode["image_normal_vaddressmode = 2 [SOCKET]"] --"vaddressmode"--> image_normal style image_normal/vaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_normal/filtertype["image_normal_filtertype = 1 [SOCKET]"] --"filtertype"--> image_normal style image_normal/filtertype fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission --"out --> in"--> image_emission_out_cm image_emission/file["image_emission_file = boombox/BoomBox_emissive.png [SOCKET]"] --"file"--> image_emission style image_emission/file fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/factor["image_emission_factor = 1, 1, 1 [SOCKET]"] --"factor"--> image_emission style image_emission/factor fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/default["image_emission_default = 0, 0, 0 [SOCKET]"] --"default"--> image_emission style image_emission/default fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/pivot["image_emission_pivot = 0, 1 [SOCKET]"] --"pivot"--> image_emission style image_emission/pivot fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/scale["image_emission_scale = 1, 1 [SOCKET]"] --"scale"--> image_emission style image_emission/scale fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/rotate["image_emission_rotate = 0 [SOCKET]"] --"rotate"--> image_emission style image_emission/rotate fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/offset["image_emission_offset = 0, 0 [SOCKET]"] --"offset"--> image_emission style image_emission/offset fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/operationorder["image_emission_operationorder = 0 [SOCKET]"] --"operationorder"--> image_emission style image_emission/operationorder fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/uaddressmode["image_emission_uaddressmode = 2 [SOCKET]"] --"uaddressmode"--> image_emission style image_emission/uaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/vaddressmode["image_emission_vaddressmode = 2 [SOCKET]"] --"vaddressmode"--> image_emission style image_emission/vaddressmode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_emission/filtertype["image_emission_filtertype = 1 [SOCKET]"] --"filtertype"--> image_emission style image_emission/filtertype fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF image_basecolor_outcolor_cm --"out --> base_color"--> SR_boombox image_basecolor_outcolor_cm/in["image_basecolor_outcolor = 0, 0, 0"] --"in"--> image_basecolor_outcolor_cm image_orm_channels --"outx --> occlusion"--> SR_boombox image_orm_channels --"outy --> roughness"--> SR_boombox image_orm_channels --"outz --> metallic"--> SR_boombox image_orm_channels/in["image_orm_out = 0, 0, 0"] --"in"--> image_orm_channels image_emission_out_cm --"out --> emissive"--> SR_boombox image_emission_out_cm/in["image_emission_out = 0, 0, 0"] --"in"--> image_emission_out_cm SR_boombox --"out --> surfaceshader"--> Material_boombox SR_boombox/base_color["image_basecolor_outcolor_cm_out = 1, 1, 1"] --"base_color"--> SR_boombox SR_boombox/metallic["image_orm_channels_outz = 1"] --"metallic"--> SR_boombox SR_boombox/roughness["image_orm_channels_outy = 1"] --"roughness"--> SR_boombox SR_boombox/occlusion["image_orm_channels_outx = 1"] --"occlusion"--> SR_boombox SR_boombox/transmission["SR_boombox_transmission = 0 [SOCKET]"] --"transmission"--> SR_boombox style SR_boombox/transmission fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/specular["SR_boombox_specular = 1 [SOCKET]"] --"specular"--> SR_boombox style SR_boombox/specular fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/specular_color["SR_boombox_specular_color = 1, 1, 1 [SOCKET]"] --"specular_color"--> SR_boombox style SR_boombox/specular_color fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/ior["SR_boombox_ior = 1.5 [SOCKET]"] --"ior"--> SR_boombox style SR_boombox/ior fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/alpha["image_basecolor_outa = 1"] --"alpha"--> SR_boombox SR_boombox/alpha_mode["SR_boombox_alpha_mode = 0 [SOCKET]"] --"alpha_mode"--> SR_boombox style SR_boombox/alpha_mode fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/alpha_cutoff["SR_boombox_alpha_cutoff = 0.5 [SOCKET]"] --"alpha_cutoff"--> SR_boombox style SR_boombox/alpha_cutoff fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/iridescence["SR_boombox_iridescence = 0 [SOCKET]"] --"iridescence"--> SR_boombox style SR_boombox/iridescence fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/iridescence_ior["SR_boombox_iridescence_ior = 1.3 [SOCKET]"] --"iridescence_ior"--> SR_boombox style SR_boombox/iridescence_ior fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/iridescence_thickness["SR_boombox_iridescence_thickness = 100 [SOCKET]"] --"iridescence_thickness"--> SR_boombox style SR_boombox/iridescence_thickness fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/sheen_color["SR_boombox_sheen_color = 0, 0, 0 [SOCKET]"] --"sheen_color"--> SR_boombox style SR_boombox/sheen_color fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/sheen_roughness["SR_boombox_sheen_roughness = 0 [SOCKET]"] --"sheen_roughness"--> SR_boombox style SR_boombox/sheen_roughness fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/clearcoat["SR_boombox_clearcoat = 0 [SOCKET]"] --"clearcoat"--> SR_boombox style SR_boombox/clearcoat fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/clearcoat_roughness["SR_boombox_clearcoat_roughness = 0 [SOCKET]"] --"clearcoat_roughness"--> SR_boombox style SR_boombox/clearcoat_roughness fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/emissive["image_emission_out_cm_out = 0, 0, 0"] --"emissive"--> SR_boombox SR_boombox/emissive_strength["SR_boombox_emissive_strength = 1 [SOCKET]"] --"emissive_strength"--> SR_boombox style SR_boombox/emissive_strength fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/thickness["SR_boombox_thickness = 0 [SOCKET]"] --"thickness"--> SR_boombox style SR_boombox/thickness fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/attenuation_color["SR_boombox_attenuation_color = 1, 1, 1 [SOCKET]"] --"attenuation_color"--> SR_boombox style SR_boombox/attenuation_color fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/anisotropy_strength["SR_boombox_anisotropy_strength = 0 [SOCKET]"] --"anisotropy_strength"--> SR_boombox style SR_boombox/anisotropy_strength fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/anisotropy_rotation["SR_boombox_anisotropy_rotation = 0 [SOCKET]"] --"anisotropy_rotation"--> SR_boombox style SR_boombox/anisotropy_rotation fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF SR_boombox/dispersion["SR_boombox_dispersion = 0 [SOCKET]"] --"dispersion"--> SR_boombox style SR_boombox/dispersion fill:#053333,stroke:#222222,stroke-width:2px,color:#FFFFFF