Skip to content

Commit

Permalink
Python shader generation test + fix findRenderableElements wrapper. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
bernardkwok authored Jun 10, 2021
1 parent 84b649c commit 661dca7
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 2 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
compiler: gcc
compiler_version: "10"
python: 3.7
test_generate: ON
test_render: ON

- name: MacOS_Xcode_10_Python27
Expand All @@ -57,6 +58,7 @@ jobs:
compiler_version: "12.2"
python: 3.7
cmake_config: -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
test_generate: ON

- name: Windows_VS2017_Win32_Python27
os: windows-2016
Expand All @@ -75,6 +77,7 @@ jobs:
architecture: x64
python: 3.8
cmake_config: -G "Visual Studio 16 2019" -A "x64"
test_generate: ON

steps:
- name: Sync Repository
Expand Down Expand Up @@ -155,6 +158,14 @@ jobs:
python Scripts/mxdoc.py ../libraries/pbrlib/pbrlib_defs.mtlx
working-directory: python

- name: Generation Tests
if: matrix.test_generate == 'ON'
run: |
mkdir build/generate
python python/Scripts/generateShader.py resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx --path "." --outputPath "build_public_rel/generate/" --target "glsl"
python python/Scripts/generateShader.py resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx --path "." --outputPath "build_public_rel/generate/" --target "osl"
python python/Scripts/generateShader.py resources/Materials/Examples/StandardSurface/standard_surface_look_brass_tiled.mtlx --path "." --outputPath "build_public_rel/generate/" --target "mdl"
- name: Render Tests
if: matrix.test_render == 'ON'
run: |
Expand All @@ -175,3 +186,10 @@ jobs:
with:
name: Renders_${{ matrix.name }}
path: build/render/

- name: Upload Shaders
uses: actions/upload-artifact@v2
if: matrix.test_generate == 'ON'
with:
name: Shaders_${{ matrix.name }}
path: build/generate/
127 changes: 127 additions & 0 deletions python/Scripts/generateShader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env python
'''
Utility to generate the shader for materials found in a MaterialX document. One file will be generated
for each material / shader found. The currently supported target languages are GLSL, OSL and MDL.
'''

import sys, os, argparse
import MaterialX as mx
import MaterialX.PyMaterialXGenShader as mx_gen_shader
import MaterialX.PyMaterialXGenGlsl as mx_gen_glsl
import MaterialX.PyMaterialXGenOsl as mx_gen_osl
import MaterialX.PyMaterialXGenMdl as mx_gen_mdl

def main():
parser = argparse.ArgumentParser(description='Generate shader code for each material / shader in a document.')
parser.add_argument('--path', dest='paths', action='append', nargs='+', help='An additional absolute search path location (e.g. "/projects/MaterialX")')
parser.add_argument('--library', dest='libraries', action='append', nargs='+', help='An additional relative path to a custom data library folder (e.g. "libraries/custom")')
parser.add_argument('--target', dest='target', default='glsl', help='Target shader generator to use (e.g. "genglsl"')
parser.add_argument('--outputPath', dest='outputPath', help='File path to output shaders to.')
parser.add_argument(dest='inputFilename', help='Filename of the input document.')
opts = parser.parse_args()

doc = mx.createDocument()
try:
mx.readFromXmlFile(doc, opts.inputFilename)
except mx.ExceptionFileMissing as err:
print(err)
sys.exit(0)

stdlib = mx.createDocument()
filePath = os.path.dirname(os.path.abspath(__file__))
searchPath = mx.FileSearchPath(os.path.join(filePath, '..', '..', 'libraries'))
searchPath.append(os.path.dirname(opts.inputFilename))
libraryFolders = [ 'libraries' ]
if opts.paths:
for pathList in opts.paths:
for path in pathList:
searchPath.append(path)
if opts.libraries:
for libraryList in opts.libraries:
for library in libraryList:
libraryFolders.append(library)
mx.loadLibraries(libraryFolders, searchPath, stdlib)
doc.importLibrary(stdlib)

valid, msg = doc.validate()
if not valid:
print('Validation warnings for input document:')
print(msg)

gentarget = 'glsl'
if opts.target:
gentarget = opts.target
if gentarget == 'osl':
shadergen = mx_gen_osl.OslShaderGenerator.create()
elif gentarget == 'mdl':
shadergen = mx_gen_mdl.MdlShaderGenerator.create()
else:
shadergen = mx_gen_glsl.GlslShaderGenerator.create()
context = mx_gen_shader.GenContext(shadergen)
context.registerSourceCodeSearchPath(searchPath)
genoptions = context.getOptions()
genoptions.shaderInterfaceType = int(mx_gen_shader.ShaderInterfaceType.SHADER_INTERFACE_COMPLETE)

print('- Set up CMS ...')
cms = mx_gen_shader.DefaultColorManagementSystem.create(shadergen.getTarget())
cms.loadLibrary(doc)
shadergen.setColorManagementSystem(cms)

print('- Set up Units ...')
unitsystem = mx_gen_shader.UnitSystem.create(shadergen.getTarget())
registry = mx.UnitConverterRegistry.create()
distanceTypeDef = doc.getUnitTypeDef('distance')
registry.addUnitConverter(distanceTypeDef, mx.LinearUnitConverter.create(distanceTypeDef))
angleTypeDef = doc.getUnitTypeDef('angle')
registry.addUnitConverter(angleTypeDef, mx.LinearUnitConverter.create(angleTypeDef))
unitsystem.loadLibrary(stdlib)
unitsystem.setUnitConverterRegistry(registry)
shadergen.setUnitSystem(unitsystem)
genoptions.targetDistanceUnit = 'meter'

# Look for shader nodes
shaderNodes = mx_gen_shader.findRenderableElements(doc, False)
if not shaderNodes:
materials = doc.getMaterialNodes()
for material in materials:
shaderNodes += mx.getShaderNodes(material, mx.SURFACE_SHADER_TYPE_STRING)
if not shaderNodes:
shaderNodes = doc.getNodesOfType(mx.SURFACE_SHADER_TYPE_STRING)

pathPrefix = ''
if opts.outputPath and os.path.exists(opts.outputPath):
pathPrefix = opts.outputPath + os.path.sep
print('Output path: ' + pathPrefix)

for shaderNode in shaderNodes:
# Material nodes are not supported directly for generation so find upstream
# shader nodes.
if shaderNode.getCategory() == 'surfacematerial':
shaderNodes += mx.getShaderNodes(shaderNode, mx.SURFACE_SHADER_TYPE_STRING)
continue

shaderNodeName = shaderNode.getName()
print('-- Generate code for node: ' + shaderNodeName)
shaderNodeName = mx.createValidName(shaderNodeName)
shader = shadergen.generate(shaderNodeName, shaderNode, context)
if shader:
pixelSource = shader.getSourceCode(mx_gen_shader.PIXEL_STAGE)
filename = pathPrefix + shader.getName() + "." + gentarget
print('--- Wrote pixel shader to: ' + filename)
file = open(filename, 'w+')
file.write(pixelSource)
file.close()

if gentarget == 'glsl':
vertexSource = shader.getSourceCode(mx_gen_shader.VERTEX_STAGE)
filename = pathPrefix + shader.getName() + '_vs.' + gentarget
print('--- Wrote vertex shader to: ' + filename)
file = open(filename, 'w+')
file.write(vertexSource)
file.close()
else:
print('--- Failed to generate code for: ' + shaderNode.getName())


if __name__ == '__main__':
main()
10 changes: 8 additions & 2 deletions source/PyMaterialX/PyMaterialXGenShader/PyUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@
namespace py = pybind11;
namespace mx = MaterialX;

std::vector<mx::TypedElementPtr> findRenderableElements(mx::ConstDocumentPtr doc, bool includeReferencedGraphs)
{
std::vector<mx::TypedElementPtr> elements;
mx::findRenderableElements(doc, elements, includeReferencedGraphs);
return elements;
}

void bindPyUtil(py::module& mod)
{
mod.def("isTransparentSurface", &mx::isTransparentSurface);
mod.def("mapValueToColor", &mx::mapValueToColor);
mod.def("requiresImplementation", &mx::requiresImplementation);
mod.def("elementRequiresShading", &mx::elementRequiresShading);
mod.def("findRenderableMaterialNodes", &mx::findRenderableMaterialNodes);
mod.def("findRenderableMaterialNodes", &mx::findRenderableMaterialNodes);
mod.def("findRenderableElements", &mx::findRenderableElements);
mod.def("findRenderableElements", &findRenderableElements);
mod.def("getNodeDefInput", &mx::getNodeDefInput);
mod.def("tokenSubstitution", &mx::tokenSubstitution);
mod.def("getUdimCoordinates", &mx::getUdimCoordinates);
Expand Down

0 comments on commit 661dca7

Please sign in to comment.