From fa8cbb071dacd32ebec2374659d59510198d4147 Mon Sep 17 00:00:00 2001 From: bsavery Date: Tue, 18 Aug 2020 19:24:25 -0700 Subject: [PATCH] Merge version 1.3.0 (#321) * Optimize batch rendering (#288) First of all, track whether we are rendering in batch mode or not and if so then do not resolve framebuffers on each iteration. As the second optimization, introduce a progressive mode - whether we should update renderStats each sample or should we render at once as many samples as possible, depending on sampling mode: when uniform sampling mode is used, render all samples per one Render call; when adaptive sampling mode is used, render min samples first and then call Render for each sample progressively querying current active pixel count. As for the naming convention, I followed husk because usdrecord has none of it. I'm going to add renderMode to usdrecord. Here are some measurements: 12% performance gain (before:01:38.02-after:01:26.06) on basic0 test with adaptive sampling and 7% performance gain (before:04:28.75-after:04:10.65) with uniform sampling. * Update hdRpr installation scheme (#285) Previously the only way to use hdRpr in Houdini was to copy hdRpr package directly into Houdini. From this [post](https://www.sidefx.com/forum/topic/70623/#post-301401) I knew that Houdini (starting from 18.0.370) has functionality that allows us to avoid copying hdRpr libraries directly into Houdini. Which effectively would save users from reinstalling hdRpr every time he updates Houdini. All we need to do is to add package ([package docs](https://www.sidefx.com/docs/houdini/ref/plugins.html)) that points to hdRpr plugin. The only requirement is to have plugInfo.json under HDRPR_PACKAGE/houdini/dso/usd_plugins directory that will describe our USD plugin. On Linux and macOS hdRpr library will automatically resolve (through runpath) and load linked libraries (like libRadeonProRender). On Windows, unfortunately, users have to add the bin folder to the PATH (it can be done in the same place with HOUDINI_PATH in package file so no need for users to manually add path entry to PATH). Instead of ad-hoc FindUSD.cmake script, rely on generated (by USD) pxrConfig that specifies and links all required libraries. Though we still have to keep the same ad-hoc script to find USD that is built in the monolithic mode because USD does not generate valid pxrConfig in this mode. * Do not require the user to explicitly specify RPR_ENABLE_OPENVDB_SUPPORT, automatically skip openvdb support if the corresponding library cannot be found * The same for RPR_BUILD_AS_HOUINI_PLUGIN - automatically decide from provided info (pxr_DIR or HFS in the environment) whether we are building Houdini plugin or usdview * Ship README within the package * Improve `generatePackage.py` - now it will generate package from scratch (no need to run it from a configured project) * Fix loading of RPR menu in usdview * Expose caustics control * Use rpr::Context's mutex to sync access to RPR API (#290) The main motivation here is to stick to one mutex everywhere we use rpr::Context. Previously rpr::Context was not used anywhere except hdRpr so it was not the issue but now we need to sync RPR API access in RprInteropTask * buildmaster: version update to 1.2.3 * Add render mode render setting (#289) Add render mode render setting #289 * Fix dome light visibility (#292) Due to how is environment light creation/deletion implemented in RPR API we must remove default environment light before creating a new one * Fix hdRpr monolithic USD build (#293) * Fix hdRpr monolithic USD build * Remove global include_directories and link_directories * Do not search for python libraries Because we are not linking it explicitly * buildmaster: version update to 1.2.5 * UsdPreviewSurface: use specular workflow on refractive materials (#299) * Expose shadow and reflection catcher controls (#294) * Improve AOV system (#295) * Add support for all AOV supported by RPR core * Split color AOV Color AOV might have been tonemapped, denoised, and composed with alpha. Previously there was no way to get unmodified color output from RPR while using tonemapping/denoising/opacity. * Replace `HDRPR_DISABLE_ALPHA` env. setting with corresponding render setting to allow runtime changes * buildmaster: version update to 1.2.6 * Query UV primvar name from bound material (#296) When mesh has few UV sets or it has non-standard (`st`) UV primvar name we must query the name of the needed UV primvar from bound material * Add UDIM support (#298) (northstar only) * buildmaster: version update to 1.2.7 * Add UsdRenderVar support (#300) UsdRenderVar API allows the user to control the currently rendered AOV set. The main difference of UsdRenderVar AOV from good old well-known AOV is that it fully defines HdAovDescriptor, while "default" AOV takes its descriptor from render delegate. * buildmaster: version update to 1.2.8 * Add northstar support (#297) * Add northstar support * Disable opacity AOV when using Northstar * buildmaster: version update to 1.2.9 * Speed up basis curves creation (#302) Minimize the number of memory reallocations by precalculating the amount of required memory before converting Hydra data to RPR data. * buildmaster: version update to 1.2.10 * Fix normal input of AI denoise filter (#305) Normals should be in [0; 1] range * Rework material handling (#301) * Rework material handling - Implement nodal data-driven material generation from the given HdMaterialNetwork. - Prepare the ground for MaterialX support: * parse node definitions from the given .mtlx files * define all RPR native nodes (RPR_MATERIAL_NODE_*) as .mtlx files - Implement convenient wrapper around arithmetic nodes to simplify its usage: previously we had to keep two distinct code-paths for scalar/vector inputs and texture inputs. - Houdini: add VOP node for each RPR material node * Update Houdini packaging * Fix macOS compilation errors * macOS fixes * Fix linux compilation errors * Add MaterialX dependency as submodule * Update install instructions * Allow displacement controled via non-texture input * Fix color AOV HdFormat * Handle normal input for UsdPreviewSurface * Fix image caching in UsdUVTexture node * Register materials from RprUsdMaterialRegistry in SdrRegistry USD 20.05 Hydra forbids material nodes with unknown id. * Resolve review remarks * Add northstar specific rendering loop (#308) Account for high dependency of Northstar performance on RPR_CONTEXT_ITERATIONS: higher value gives better performance. * Allow building hdRpr for Houdini 18.5 (#309) * Parallelize texture loading (#307) Texture processing Texture loading and creation of rpr::Image is one of the most time-consuming tasks. This process consists of two key steps: Load image data from a disk Create rpr::Image from the loaded data Parallelize what can be parallelized The obvious idea here is to parallelize what can be parallelized. rpr::Image creation cannot be parallelized due to the single-threaded nature of RPR API. So the only thing left is loading from a disk. Performance measurements before and after parallelization I'm testing on the NVIDIA's USD Attic scene and the SideFX's Bar scene. The following time values are measured from the delegate creation to the beginning of the first render call (end of SyncAll) - effectively time to the first pixel minus time of the first rprContextRender. Tahoe Attic, sec Bar, sec Single-threaded 26.620 14.353 Multi-threaded 8.358 9.543 Northstar Attic, sec Bar, sec Single-threaded 26.289 13.117 Multi-threaded 8.558 8.197 As you can see, the Attic scene has a huge improvement in time in the same time the Bar scene not. More specific measurements should explain why. Performance measurements of textures processing Attic - 345 .png textures in total Single-threaded loading of textures from a disk: 20.452 sec Multi-threaded loading of textures from a disk: 02.068 sec Northstar rpr::Image creation (always single-threaded): 03.478 sec Tahoe rpr::Image creation (always single-threaded): 03.977 sec Bar scene - 3044 .exr textures in total Single-threaded loading of textures from a disk: 03.711 sec Multi-threaded loading of textures from a disk: 02.270 sec Northstar rpr::Image creation (always single-threaded): 02.072 sec Tahoe rpr::Image creation (always single-threaded): 07.809 sec Despite 10 times the difference in the number of textures, .exr wins drastically but it does not parallelize so well as .png loading. So these numbers answer why we see such a huge boost on the Attic scene when parallelizing texture loading and also they show why numbers on the Bar scene not that remarkable. But these numbers also bring at least two new questions: Why .png loading is so much slower? Why .exr loading has much lower parallelization potential? The actual code that loads images from the disk is inside of USD, or rather inside of Glf module. PNG loading PNG loading is done with stb_image library. To estimate the performance price of GlfImage abstraction and its concrete implementation that uses stb_image I've made a simple test (stbtest.zip) that uses stb_image directly and measured its performance. It showed me that the single-threaded performance of .png image loading through GlfImage abstraction is almost the same as raw stb_image loading. That means that if we want to improve .png images loading speed all we can do is improve decoder implementation. It's possible to force GlfImage to use OIIO library to load .png images. OIIO library uses libpng for .png loading. This gives such results for the Attic scene: Single-threaded loading of textures from a disk: 21.916 sec OIIO vs 20.452 sec stb_image Multi-threaded loading of textures from a disk: 02.688 sec OIIO vs 02.068 sec stb_image Short googling gave me this note in which the author compares stb_image, lodepng, libpng and libjpeg decoding performance. It says that "libpng is fastest, optimized stb_image takes about 33-40% longer" - this conclusion contradicts with my comparison stb_image vs OIIO (libpng). But the author of this note used libpng directly, probably this can explain such a result? EXR loading EXR loading is done with OIIO library (which uses openexr under the hood). I did not find any public comparisons of the currently available solutions for loading .exr images. So I will have to do it myself. But I think that the current performance of .exr images is out of the question especially when comparing to .png loading performance. RAT loading This is a native Houdini image format promoted as the best image format for texture mapping. Previously support for this format was implemented inside of hdRpr under ifdef that was enabled when compiling hdRpr as Houdini plugin. For the sake of image loading cleanliness and unification of Houdini and usdview plugin, I've moved .rat related code to the separate plugin that will be built only when Houdini's library is available. Conclusion Regardless performance of the image decoders embedded in USD, parallelization of GlfImage loading gives us tangible results - ~3.2x less time to the first pixel on the Attic scene and ~1.5x speed up for the Bar scene. * buildmaster: version update to 1.2.11 * Support SideFX-style UDIM tag (#312) * buildmaster: version update to 1.2.12 * Update to RIF SDK 1.5.4 (#314) * buildmaster: version update to 1.2.13 * Unlock alpha for northstar (#311) * Unlock alpha for northstar * Unlock alpha render setting for northstar * buildmaster: version update to 1.2.14 * Refactor render qualities handling (+ enable Northstar on macOS) (#318) * Refactor render qualities handling * Update northstar's UI name * Fix depth of field (#319) Focal length and sensor size should be in millimeters * buildmaster: version update to 1.2.15 * 1.3.0 Release (#315) * 1.3.0 Release * Update changelog * buildmaster: version update to 1.3.1 * Hotfix 1.3.0 Release (#320) * buildmaster: version update to 1.3.2 --- .gitmodules | 3 + CHANGELOG.MD | 28 + CMakeLists.txt | 35 +- INSTALL.md | 61 +- README.md | 40 +- cmake/defaults/Houdini.cmake | 40 - cmake/defaults/Options.cmake | 3 - cmake/defaults/Packages.cmake | 110 +-- cmake/defaults/ProjectDefaults.cmake | 5 + cmake/defaults/Version.cmake | 4 +- cmake/macros/Private.cmake | 68 +- cmake/macros/Public.cmake | 22 +- cmake/modules/FindGLEW.cmake | 132 --- cmake/modules/FindHoudiniUSD.cmake | 156 +++ cmake/modules/FindOpenEXR.cmake | 1 + cmake/modules/FindOpenVDB.cmake | 64 +- cmake/modules/FindRif.cmake | 10 +- cmake/modules/FindRpr.cmake | 89 +- cmake/modules/FindTBB.cmake | 219 ----- cmake/modules/FindUSD.cmake | 59 -- cmake/modules/FindUSDMonolithic.cmake | 104 ++ deps/MaterialX | 1 + deps/RIF | 2 +- deps/RPR | 2 +- pxr/imaging/CMakeLists.txt | 2 + pxr/imaging/plugin/CMakeLists.txt | 3 + pxr/imaging/plugin/glfRatImage/CMakeLists.txt | 23 + .../plugin/glfRatImage/glfRatImage.cpp | 336 +++++++ pxr/imaging/plugin/glfRatImage/plugInfo.json | 20 + pxr/imaging/plugin/hdRpr/CMakeLists.txt | 201 ++-- pxr/imaging/plugin/hdRpr/aovDescriptor.cpp | 146 +++ pxr/imaging/plugin/hdRpr/aovDescriptor.h | 123 +++ pxr/imaging/plugin/hdRpr/basisCurves.cpp | 104 +- pxr/imaging/plugin/hdRpr/basisCurves.h | 4 +- pxr/imaging/plugin/hdRpr/camera.cpp | 7 + pxr/imaging/plugin/hdRpr/camera.h | 2 + pxr/imaging/plugin/hdRpr/distantLight.cpp | 3 - pxr/imaging/plugin/hdRpr/domeLight.cpp | 25 +- pxr/imaging/plugin/hdRpr/domeLight.h | 1 - .../plugin/hdRpr/houdini/CMakeLists.txt | 2 +- pxr/imaging/plugin/hdRpr/imageCache.cpp | 103 -- pxr/imaging/plugin/hdRpr/imageCache.h | 67 -- pxr/imaging/plugin/hdRpr/light.cpp | 49 +- pxr/imaging/plugin/hdRpr/light.h | 6 +- pxr/imaging/plugin/hdRpr/material.cpp | 78 +- pxr/imaging/plugin/hdRpr/material.h | 6 +- pxr/imaging/plugin/hdRpr/materialAdapter.cpp | 895 ------------------ pxr/imaging/plugin/hdRpr/materialAdapter.h | 171 ---- pxr/imaging/plugin/hdRpr/materialFactory.cpp | 463 --------- pxr/imaging/plugin/hdRpr/materialFactory.h | 53 -- pxr/imaging/plugin/hdRpr/mesh.cpp | 44 +- pxr/imaging/plugin/hdRpr/mesh.h | 7 +- .../plugin/hdRpr/ndrDiscoveryPlugin.cpp | 57 ++ pxr/imaging/plugin/hdRpr/ndrParserPlugin.cpp | 60 ++ .../plugin/hdRpr/package/CMakeLists.txt | 67 +- .../hdRpr/package/activateHoudiniPlugin.py.in | 112 +++ .../plugin/hdRpr/package/generatePackage.py | 83 +- pxr/imaging/plugin/hdRpr/plugInfo.json | 8 + pxr/imaging/plugin/hdRpr/points.cpp | 6 +- pxr/imaging/plugin/hdRpr/points.h | 4 +- .../plugin/hdRpr/python/commonSettings.py | 15 + .../plugin/hdRpr/python/generateFiles.py | 6 +- .../python/generateRenderSettingFiles.py | 116 ++- .../plugin/hdRpr/python/houdiniDsGenerator.py | 29 +- pxr/imaging/plugin/hdRpr/renderBuffer.cpp | 11 +- pxr/imaging/plugin/hdRpr/renderBuffer.h | 4 + pxr/imaging/plugin/hdRpr/renderDelegate.cpp | 71 +- pxr/imaging/plugin/hdRpr/renderDelegate.h | 9 +- pxr/imaging/plugin/hdRpr/renderParam.cpp | 11 - pxr/imaging/plugin/hdRpr/renderParam.h | 23 +- pxr/imaging/plugin/hdRpr/rendererPlugin.cpp | 8 +- .../plugin/hdRpr/rifcpp/rifContext.cpp | 14 +- pxr/imaging/plugin/hdRpr/rifcpp/rifContext.h | 10 +- pxr/imaging/plugin/hdRpr/rifcpp/rifFilter.cpp | 9 +- pxr/imaging/plugin/hdRpr/rpr/CMakeLists.txt | 8 - pxr/imaging/plugin/hdRpr/rpr/imageHelpers.cpp | 205 ---- pxr/imaging/plugin/hdRpr/rprApi.cpp | 893 ++++++++++++----- pxr/imaging/plugin/hdRpr/rprApi.h | 22 +- pxr/imaging/plugin/hdRpr/rprApiAov.cpp | 84 +- pxr/imaging/plugin/hdRpr/rprApiAov.h | 32 +- .../plugin/hdRpr/rprApiFramebuffer.cpp | 16 +- pxr/imaging/plugin/hdRpr/rprApiFramebuffer.h | 3 +- .../plugin/hdRpr/usdviewMenu/CMakeLists.txt | 7 + .../{python => usdviewMenu}/plugInfo.json | 6 +- .../hdRpr/{python => usdviewMenu}/rpr.py | 0 pxr/imaging/plugin/rprHoudini/CMakeLists.txt | 22 + .../plugin/rprHoudini/VOP_RPRMaterial.cpp | 460 +++++++++ .../plugin/rprHoudini/VOP_RPRMaterial.h | 100 ++ pxr/imaging/plugin/rprHoudini/plugin.cpp | 31 + pxr/imaging/plugin/rprHoudini/ui/RPR.svg | 16 + pxr/imaging/rprUsd/CMakeLists.txt | 59 ++ pxr/imaging/rprUsd/api.h | 37 + .../hdRpr/rpr => rprUsd}/contextHelpers.cpp | 53 +- .../contextHelpers.h} | 21 +- .../hdRpr/rpr => rprUsd}/contextMetadata.h | 31 +- pxr/imaging/rprUsd/coreImage.cpp | 218 +++++ pxr/imaging/rprUsd/coreImage.h | 84 ++ pxr/imaging/rprUsd/debugCodes.cpp | 26 + pxr/imaging/rprUsd/debugCodes.h | 29 + .../{plugin/hdRpr/rpr => rprUsd}/error.h | 50 +- .../{plugin/hdRpr/rpr => rprUsd}/helpers.h | 14 +- pxr/imaging/rprUsd/imageCache.cpp | 213 +++++ pxr/imaging/rprUsd/imageCache.h | 83 ++ pxr/imaging/rprUsd/material.cpp | 77 ++ pxr/imaging/rprUsd/material.h | 57 ++ pxr/imaging/rprUsd/materialHelpers.h | 79 ++ pxr/imaging/rprUsd/materialMappings.cpp | 224 +++++ pxr/imaging/rprUsd/materialMappings.h | 196 ++++ .../houdiniPrincipledShaderNode.cpp | 561 +++++++++++ .../houdiniPrincipledShaderNode.h | 81 ++ .../rprUsd/materialNodes/materialNode.h | 66 ++ .../materialNodes/mtlxFiles/CMakeLists.txt | 51 + .../Patterns/rpr_checker_texture.mtlx | 7 + .../mtlxFiles/Patterns/rpr_dot_texture.mtlx | 7 + .../Patterns/rpr_gradient_texture.mtlx | 9 + .../Patterns/rpr_noise2d_texture.mtlx | 7 + .../mtlxFiles/Shaders/rpr_add.mtlx | 8 + .../mtlxFiles/Shaders/rpr_blend.mtlx | 11 + .../mtlxFiles/Shaders/rpr_diffuse.mtlx | 9 + .../Shaders/rpr_diffuse_refraction.mtlx | 9 + .../mtlxFiles/Shaders/rpr_emissive.mtlx | 7 + .../mtlxFiles/Shaders/rpr_microfacet.mtlx | 10 + ...rpr_microfacet_anisotropic_reflection.mtlx | 12 + ...rpr_microfacet_anisotropic_refraction.mtlx | 12 + .../Shaders/rpr_microfacet_beckmann.mtlx | 10 + .../Shaders/rpr_microfacet_refraction.mtlx | 11 + .../mtlxFiles/Shaders/rpr_orennayar.mtlx | 9 + .../mtlxFiles/Shaders/rpr_passthrough.mtlx | 7 + .../mtlxFiles/Shaders/rpr_phong.mtlx | 10 + .../mtlxFiles/Shaders/rpr_reflection.mtlx | 8 + .../mtlxFiles/Shaders/rpr_refraction.mtlx | 10 + .../mtlxFiles/Shaders/rpr_transparent.mtlx | 7 + .../mtlxFiles/Shaders/rpr_uber.mtlx | 63 ++ .../mtlxFiles/Shaders/rpr_volume.mtlx | 11 + .../mtlxFiles/Shaders/rpr_ward.mtlx | 11 + .../mtlxFiles/Utilities/rpr_blend_value.mtlx | 9 + .../mtlxFiles/Utilities/rpr_bump_map.mtlx | 8 + .../Utilities/rpr_constant_texture.mtlx | 7 + .../mtlxFiles/Utilities/rpr_fresnel.mtlx | 10 + .../Utilities/rpr_fresnel_schlick.mtlx | 9 + .../mtlxFiles/Utilities/rpr_hsv_to_rgb.mtlx | 7 + .../mtlxFiles/Utilities/rpr_input_lookup.mtlx | 7 + .../mtlxFiles/Utilities/rpr_normal_map.mtlx | 8 + .../mtlxFiles/Utilities/rpr_rgb_to_hsv.mtlx | 7 + .../mtlxFiles/Utilities/rpr_twosided.mtlx | 8 + .../Utilities/rpr_uv_procedural.mtlx | 12 + .../mtlxFiles/Utilities/rpr_uv_triplanar.mtlx | 11 + .../materialNodes/mtlxFiles/rpr_defs.mtlx | 9 + pxr/imaging/rprUsd/materialNodes/mtlxNode.cpp | 336 +++++++ pxr/imaging/rprUsd/materialNodes/mtlxNode.h | 86 ++ .../materialNodes/rpr/arithmeticNode.cpp | 486 ++++++++++ .../rprUsd/materialNodes/rpr/arithmeticNode.h | 63 ++ .../rprUsd/materialNodes/rpr/baseNode.cpp | 55 ++ .../rprUsd/materialNodes/rpr/baseNode.h | 54 ++ .../rprUsd/materialNodes/rpr/catcherNode.cpp | 113 +++ .../materialNodes/rpr/combineShadersNode.cpp | 121 +++ .../rprUsd/materialNodes/rpr/displaceNode.cpp | 148 +++ .../rprUsd/materialNodes/rpr/nodeInfo.h | 77 ++ pxr/imaging/rprUsd/materialNodes/usdNode.cpp | 531 +++++++++++ pxr/imaging/rprUsd/materialNodes/usdNode.h | 130 +++ pxr/imaging/rprUsd/materialRegistry.cpp | 508 ++++++++++ pxr/imaging/rprUsd/materialRegistry.h | 210 ++++ pxr/imaging/rprUsd/util.cpp | 41 + .../rpr/contextHelpers.h => rprUsd/util.h} | 16 +- 164 files changed, 8923 insertions(+), 3579 deletions(-) delete mode 100644 cmake/defaults/Houdini.cmake delete mode 100644 cmake/modules/FindGLEW.cmake create mode 100644 cmake/modules/FindHoudiniUSD.cmake delete mode 100644 cmake/modules/FindTBB.cmake delete mode 100644 cmake/modules/FindUSD.cmake create mode 100644 cmake/modules/FindUSDMonolithic.cmake create mode 160000 deps/MaterialX create mode 100644 pxr/imaging/CMakeLists.txt create mode 100644 pxr/imaging/plugin/CMakeLists.txt create mode 100644 pxr/imaging/plugin/glfRatImage/CMakeLists.txt create mode 100644 pxr/imaging/plugin/glfRatImage/glfRatImage.cpp create mode 100644 pxr/imaging/plugin/glfRatImage/plugInfo.json create mode 100644 pxr/imaging/plugin/hdRpr/aovDescriptor.cpp create mode 100644 pxr/imaging/plugin/hdRpr/aovDescriptor.h delete mode 100644 pxr/imaging/plugin/hdRpr/imageCache.cpp delete mode 100644 pxr/imaging/plugin/hdRpr/imageCache.h delete mode 100644 pxr/imaging/plugin/hdRpr/materialAdapter.cpp delete mode 100644 pxr/imaging/plugin/hdRpr/materialAdapter.h delete mode 100644 pxr/imaging/plugin/hdRpr/materialFactory.cpp delete mode 100644 pxr/imaging/plugin/hdRpr/materialFactory.h create mode 100644 pxr/imaging/plugin/hdRpr/ndrDiscoveryPlugin.cpp create mode 100644 pxr/imaging/plugin/hdRpr/ndrParserPlugin.cpp create mode 100644 pxr/imaging/plugin/hdRpr/package/activateHoudiniPlugin.py.in delete mode 100644 pxr/imaging/plugin/hdRpr/rpr/CMakeLists.txt delete mode 100644 pxr/imaging/plugin/hdRpr/rpr/imageHelpers.cpp create mode 100644 pxr/imaging/plugin/hdRpr/usdviewMenu/CMakeLists.txt rename pxr/imaging/plugin/hdRpr/{python => usdviewMenu}/plugInfo.json (74%) rename pxr/imaging/plugin/hdRpr/{python => usdviewMenu}/rpr.py (100%) create mode 100644 pxr/imaging/plugin/rprHoudini/CMakeLists.txt create mode 100644 pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.cpp create mode 100644 pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.h create mode 100644 pxr/imaging/plugin/rprHoudini/plugin.cpp create mode 100644 pxr/imaging/plugin/rprHoudini/ui/RPR.svg create mode 100644 pxr/imaging/rprUsd/CMakeLists.txt create mode 100644 pxr/imaging/rprUsd/api.h rename pxr/imaging/{plugin/hdRpr/rpr => rprUsd}/contextHelpers.cpp (84%) rename pxr/imaging/{plugin/hdRpr/rpr/imageHelpers.h => rprUsd/contextHelpers.h} (60%) rename pxr/imaging/{plugin/hdRpr/rpr => rprUsd}/contextMetadata.h (63%) create mode 100644 pxr/imaging/rprUsd/coreImage.cpp create mode 100644 pxr/imaging/rprUsd/coreImage.h create mode 100644 pxr/imaging/rprUsd/debugCodes.cpp create mode 100644 pxr/imaging/rprUsd/debugCodes.h rename pxr/imaging/{plugin/hdRpr/rpr => rprUsd}/error.h (57%) rename pxr/imaging/{plugin/hdRpr/rpr => rprUsd}/helpers.h (79%) create mode 100644 pxr/imaging/rprUsd/imageCache.cpp create mode 100644 pxr/imaging/rprUsd/imageCache.h create mode 100644 pxr/imaging/rprUsd/material.cpp create mode 100644 pxr/imaging/rprUsd/material.h create mode 100644 pxr/imaging/rprUsd/materialHelpers.h create mode 100644 pxr/imaging/rprUsd/materialMappings.cpp create mode 100644 pxr/imaging/rprUsd/materialMappings.h create mode 100644 pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.h create mode 100644 pxr/imaging/rprUsd/materialNodes/materialNode.h create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/CMakeLists.txt create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_checker_texture.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_dot_texture.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_gradient_texture.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_noise2d_texture.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_add.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_blend.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse_refraction.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_emissive.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_reflection.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_refraction.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_beckmann.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_refraction.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_orennayar.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_passthrough.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_phong.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_reflection.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_refraction.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_transparent.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_uber.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_volume.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_ward.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_blend_value.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_bump_map.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_constant_texture.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel_schlick.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_hsv_to_rgb.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_input_lookup.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_normal_map.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_rgb_to_hsv.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_twosided.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_procedural.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_triplanar.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxFiles/rpr_defs.mtlx create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/mtlxNode.h create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.h create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/baseNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/baseNode.h create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/catcherNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/combineShadersNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/displaceNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/rpr/nodeInfo.h create mode 100644 pxr/imaging/rprUsd/materialNodes/usdNode.cpp create mode 100644 pxr/imaging/rprUsd/materialNodes/usdNode.h create mode 100644 pxr/imaging/rprUsd/materialRegistry.cpp create mode 100644 pxr/imaging/rprUsd/materialRegistry.h create mode 100644 pxr/imaging/rprUsd/util.cpp rename pxr/imaging/{plugin/hdRpr/rpr/contextHelpers.h => rprUsd/util.h} (73%) diff --git a/.gitmodules b/.gitmodules index 0327b6f18..fd583a363 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "deps/RPR"] path = deps/RPR url = https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderSDK +[submodule "deps/MaterialX"] + path = deps/MaterialX + url = https://github.com/materialx/MaterialX diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 99d3ee944..ca83d2130 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,4 +1,32 @@ # Change Log + +## 1.3 Release + +hdRpr installation scheme was changed - there is no more need to copy hdRpr package directly into Houdini. More info [here](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/285). + +### New features +* Parallelize texture loading ([PR #307](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/307)) +* Expose RPR-native materials ([PR #301](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/301)) +* Add RPR 2.0 (Northstar) support ([PR #297](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/297)) +* Add UsdRenderVar support (raw AOVs only) ([PR #300](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/300)) +* Add UDIM support (Northstar only) ([PR #298](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/298)) +* Improve AOV system ([PR #295](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/295)) +* Expose shadow and reflection catcher controls ([PR #294](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/294)) +* Expose caustics control ([PR #291](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/291)) +* Add render mode render setting ([PR #289](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/289)) +* Optimize batch rendering ([PR #288](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/288)) +* BasisCurves bezier support ([PR #282](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/282)) +* Speed up basis curves creation ([PR #302](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/302)) +* Add RIF-based tone mapping filter ([PR #283](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/283)) + +### Fixes +* Fixed depth of field ([PR #319](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/319)) +* Fixed normal input of AI denoise filter ([PR #305](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/305)) +* Fixed dome light visibility ([PR #292](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/292)) +* Now UV primvar name is queried from the bound material ([PR #296](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/296)) +* Use specular workflow on refractive materials for UsdPreviewSurface ([PR #299](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/299)) + + ## 1.2 Release ### New features - Volume rework ([PR #268](https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD/pull/268)) diff --git a/CMakeLists.txt b/CMakeLists.txt index 419afb8ca..85632a91f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,11 +7,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/defaults ${CMAKE_SOURCE_DIR}/cmake/macros) include(Options) - -if(RPR_BUILD_AS_HOUDINI_PLUGIN) - include(Houdini) -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) - include(ProjectDefaults) include(Packages) @@ -34,12 +29,24 @@ include(Public) set(CMAKE_CXX_STANDARD 14) -include_directories(${USD_INCLUDE_DIR}) -link_directories(${USD_LIBRARY_DIR}) -include_directories(${RPR_INCLUDE_DIR}) -link_directories(${RPR_LIBRARY_DIR}) - -add_subdirectory(pxr/imaging/plugin/hdRpr) - -# install(FILES README.md DESTINATION .) -# install(FILES LICENSE.md DESTINATION .) +if(NOT MaterialX_FOUND) + # If MaterialX was not explicitly provided, use the one from a submodule + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + if(HoudiniUSD_FOUND AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Houdini builds with the old ABI. We need to match. + set(EXTERNAL_COMPILE_FLAGS "-D_GLIBCXX_USE_CXX11_ABI=0") + endif() + set(MATERIALX_PYTHON_LTO OFF) + set(MATERIALX_INSTALL_PYTHON OFF) + set(MATERIALX_BUILD_RENDER OFF) + set(MATERIALX_BUILD_GEN_GLSL OFF) + set(MATERIALX_BUILD_GEN_OSL OFF) + set(MATERIALX_BUILD_TESTS OFF) + add_subdirectory(deps/MaterialX) +endif() + +add_subdirectory(pxr/imaging) + +install(FILES README.md DESTINATION .) +install(FILES INSTALL.md DESTINATION .) +install(FILES LICENSE.md DESTINATION .) diff --git a/INSTALL.md b/INSTALL.md index a4a9ce848..eaf69cd5f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,37 +1,60 @@ ## Installation from a package -### Automatic installation +### Houdini plugin -Installed [**Python**](https://www.python.org/downloads/) with PATH environment variable setup is required for automatic installation. +#### Manual -> If you do not want to install python, but you have already installed Houdini with a working license, you can use hython from the Houdini package. Follow instructions under [Others](#others) subsection. +Add a new Houdini package with such configuration json: +``` +{ + "env":[ + { + "RPR":"path-to-the-package" + }, + { + "HOUDINI_PATH":"$RPR/houdini" + }, + { + "PATH":"$RPR/lib" + } + ] +} +``` +where `path-to-the-package` depends on where do you unzip hdRpr package and should point to the directory that contains INSTALL.md (this file) -#### Windows +More info here https://www.sidefx.com/docs/houdini/ref/plugins.html -Run **install.bat** +#### Automatic -#### Others +`activateHoudiniPlugin.py` script can do the same for you automatically - it will try to find your houdini preference dir and add hdRpr package that will point to the current directory. -Use the installer script **install.py**. From a terminal run: -``` -python install.py -``` -And follow the instructions from the script +### Usdview plugin + +* Add `HDRPR_PACKAGE_DIR/plugin` path entry to the `PXR_PLUGINPATH_NAME` environment variable +* Add `HDRPR_PACKAGE_DIR/lib/python` path entry to the `PYTHONPATH` environment variable +* Windows only: add the `HDRPR_PACKAGE_DIR/lib` path entry to the `PATH` environment variable -### Manual +OR -Copy content of hdRpr*.tar.gz to houdini installation directory. -Default destination path looks like: -* **Windows** `C:\Program Files\Side Effects Software\Houdini 18.0.287` -* **Ubuntu** `/opt/hfs18.0` -* **macOS** `/Applications/Houdini/Current/Frameworks/Houdini.framework/Versions/Current` +You can copy hdRpr package directories (lib and plugin) directly to the root of your USD package. ## Installation from sources -Run following command in configured cmake project: +1. Configure cmake project (more info about it in README.md) + +``` +cd RadeonProRenderUSD +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=package .. ``` -cmake --build . --config Release --target INSTALL + +2. Build cmake project ``` +cmake --build . --config Release --target install +``` + +3. Follow instructions from "Installation from package" for either "Houdini plugin" or "Usdview plugin" depending on how you configured the project on step 1. ## Feedback diff --git a/README.md b/README.md index 4c8f329c2..9c7aaec44 100644 --- a/README.md +++ b/README.md @@ -42,29 +42,22 @@ Cloning into 'RadeonProRenderUSD'... ##### Required Components -##### UsdView plugin Components +##### USD Component -As many USD users get the USD libraries from different places, or compile their own, we tried to keep this as flexible as possible. You can download USD to build yourself from [GitHub](https://www.github.com/PixarAnimationStudios/USD). UsdView plugin is build by default (```RPR_BUILD_AS_HOUDINI_PLUGIN=FALSE```). +Provide USD in one of two ways: -| Dependency Name | Description | Version | -| ------------------ |----------------------------------------------------------------------- | ------- | -| USD_ROOT | USD directory with include and lib dirs | 20.02 | - -##### Houdini plugin Components +* An installation of USD. Define pxr_DIR to point to it when running cmake, if required. You can download USD to build yourself from [GitHub](https://www.github.com/PixarAnimationStudios/USD). +* The USD which is provided with Houdini. The HFS environment variable should point to the Houdini installation (the correct way is to run cmake from Houdini's `Command Line Tools` or by sourcing `houdini_setup`). You can download Houdini installer from [Downloads | SideFX](https://www.sidefx.com/download). -To build houdini plugin set cmake flag ```RPR_BUILD_AS_HOUDINI_PLUGIN=TRUE```. `HOUDINI_ROOT` is the directory containing the `houdini_setup` file. You can download Houdini installer from [Daily Builds | SideFX](https://www.sidefx.com/download/daily-builds/#category-gold). +##### MaterialX Component -| Dependency Name | Description | Version | -| ------------------ |----------------------------------------------------------------------- | ------- | -| HOUDINI_ROOT | Houdini toolkit directory | 18 | +By default, MaterialX library will be compiled from the sources located under a MaterialX submodule `deps/MaterialX`. +You can override this behavior by providing a complete build of MaterialX to cmake. Please note, on Linux for Houdini plugin, MaterialX should be compiled with `-D_GLIBCXX_USE_CXX11_ABI=0` definition as it is required by Houdini. ##### Optional Components ##### OpenVDB -Support for OpenVDB is disabled by default, and can optionally be enabled by -specifying the cmake flag ```RPR_ENABLE_OPENVDB_SUPPORT=TRUE```. - **Following dependency required only for usdview plugin, houdini is shipped with own build of openvdb** | Dependency Name | Description | Version | @@ -83,9 +76,8 @@ then you need to specify ```RPR_SDK_PLATFORM=centos6``` cmake flag ``` mkdir build cd build -cmake -DUSD_ROOT=/data/usd_build -DCMAKE_INSTALL_PREFIX=/data/usd_build .. -make -make install +cmake -Dpxr_DIR=/data/usd_build -DCMAKE_INSTALL_PREFIX=/data/usd_build .. +cmake --build . --config Release --target install ``` Supported Platforms @@ -97,21 +89,11 @@ Supported Platforms Try it out ----------------------------- -Set the environment variables specified by the script when it finishes and -launch ```usdview``` with a sample asset. - -``` -> usdview extras/usd/tutorials/convertingLayerFormats/Sphere.usda -``` - -And select RPR as the render delegate. +Follow instruction from INSTALL.md to activate the plugin. +Launch either usdview or Houdini's Solaris viewport and select RPR as the render delegate. #### Environment Variables -* `PXR_PLUGINPATH_NAME` - - If you want the RPR menu added to USDView (allows selecting device, and render quality). Set it to ``` PXR_PLUGINPATH_NAME=${USD_ROOT}/lib/python/rpr ```, where USD_ROOT is your USD install directory. - * `HDRPR_ENABLE_TRACING` Instruct Radeon ProRender to generate trace files for debugging purposes. The tracing will record all RPR commands with a memory dump of the data used. By default, RPR tracing is disabled. To enable it set `HDRPR_ENABLE_TRACING` to 1. diff --git a/cmake/defaults/Houdini.cmake b/cmake/defaults/Houdini.cmake deleted file mode 100644 index e19c8c8ee..000000000 --- a/cmake/defaults/Houdini.cmake +++ /dev/null @@ -1,40 +0,0 @@ -if(NOT DEFINED HOUDINI_ROOT) - if (NOT DEFINED ENV{HOUDINI_ROOT}) - message(FATAL_ERROR "Specify HOUDINI_ROOT") - endif() - set(HOUDINI_ROOT $ENV{HOUDINI_ROOT}) -endif() - -get_filename_component(HOUDINI_ROOT "${HOUDINI_ROOT}" REALPATH) - -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - message(STATUS "Setting CMAKE_INSTALL_PREFIX to HOUDINI_ROOT - ${HOUDINI_ROOT}") - set(HOUDINI_INSTALL_PREFIX ${HOUDINI_ROOT}) - if(APPLE) - set(HOUDINI_INSTALL_PREFIX ${HOUDINI_ROOT}/..) - endif() - set(CMAKE_INSTALL_PREFIX "${HOUDINI_INSTALL_PREFIX}" CACHE PATH "..." FORCE) -endif() - -find_program(HYTHON_EXECUTABLE hython - PATHS ${HOUDINI_ROOT}/bin) -if(NOT HYTHON_EXECUTABLE) - message(FATAL "Could not find hython executable. Please check HOUDINI_ROOT: ${HOUDINI_ROOT}") -endif() - -set(HOUDINI_INCLUDE_DIR ${HOUDINI_ROOT}/toolkit/include) -set(HOUDINI_RESOURCE_DIR_RELPATH ".") -if(WIN32) - set(HOUDINI_PLUGIN_INSTALL_RELPATH bin) - set(HOUDINI_LIB ${HOUDINI_ROOT}/custom/houdini/dsolib) -elseif(APPLE) - set(HOUDINI_PLUGIN_INSTALL_RELPATH Libraries) - set(HOUDINI_LIB ${HOUDINI_ROOT}/../Libraries) - set(HOUDINI_RESOURCE_DIR_RELPATH "Resources") -else() - set(HOUDINI_PLUGIN_INSTALL_RELPATH dsolib) - set(HOUDINI_LIB ${HOUDINI_ROOT}/dsolib) -endif() -add_definitions(-DBUILD_AS_HOUDINI_PLUGIN) - -list(APPEND CMAKE_PREFIX_PATH ${HOUDINI_LIB} ${HOUDINI_INCLUDE_DIR}) diff --git a/cmake/defaults/Options.cmake b/cmake/defaults/Options.cmake index ac77a61b2..fdc3c0d88 100644 --- a/cmake/defaults/Options.cmake +++ b/cmake/defaults/Options.cmake @@ -29,9 +29,6 @@ option(PXR_ENABLE_NAMESPACES "Enable C++ namespaces." ON) option(PXR_SYMLINK_HEADER_FILES "Symlink the header files from, ie, pxr/base/lib/tf to CMAKE_DIR/pxr/base/tf, instead of copying; ensures that you may edit the header file in either location, and improves experience in IDEs which find normally the \"copied\" header, ie, CLion; has no effect on windows" OFF) -option(RPR_BUILD_AS_HOUDINI_PLUGIN "Build RadeonProRender Houdini plugin" OFF) -option(RPR_ENABLE_OPENVDB_SUPPORT "Enable OpenVDB" ${RPR_BUILD_AS_HOUDINI_PLUGIN}) - # Precompiled headers are a win on Windows, not on gcc. set(pxr_enable_pch "OFF") if(MSVC) diff --git a/cmake/defaults/Packages.cmake b/cmake/defaults/Packages.cmake index 38ff40e75..7c764dbbd 100644 --- a/cmake/defaults/Packages.cmake +++ b/cmake/defaults/Packages.cmake @@ -30,7 +30,30 @@ set(build_shared_libs "${BUILD_SHARED_LIBS}") # USD Arnold Requirements # ---------------------------------------------- -find_package(USD REQUIRED) +# Try to find monolithic USD +find_package(USDMonolithic QUIET) + +if(NOT USDMonolithic_FOUND) + find_package(pxr CONFIG) + + if(NOT pxr_FOUND) + # Try to find USD as part of Houdini. + find_package(HoudiniUSD) + + if(HoudiniUSD_FOUND) + message(STATUS "Configuring Houdini plugin") + endif() + else() + message(STATUS "Configuring usdview plugin") + endif() +else() + message(STATUS "Configuring usdview plugin: monolithic USD") +endif() + +if(NOT pxr_FOUND AND NOT HoudiniUSD_FOUND AND NOT USDMonolithic_FOUND) + message(FATAL_ERROR "Required: USD install or Houdini with included USD.") +endif() + find_package(Rpr REQUIRED) find_package(Rif REQUIRED) @@ -44,91 +67,38 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) set(PXR_THREAD_LIBS "${CMAKE_THREAD_LIBS_INIT}") -if(RPR_BUILD_AS_HOUDINI_PLUGIN) +if(HoudiniUSD_FOUND) + set(HOUDINI_ROOT "$ENV{HFS}" CACHE PATH "Houdini installation dir") find_package(Houdini REQUIRED CONFIG PATHS ${HOUDINI_ROOT}/toolkit/cmake) - if(WIN32) - set(PYTHON_INCLUDE_DIRS ${HOUDINI_ROOT}/python27/include) - set(PYTHON_LIBRARY ${HOUDINI_ROOT}/python27/libs/python27.lib) - endif() - - find_package(PythonLibs 2.7 REQUIRED) + set(OPENEXR_LOCATION ${Houdini_USD_INCLUDE_DIR}) + set(OPENEXR_LIB_LOCATION ${Houdini_LIB_DIR}) +else() + # We are using python to generate source files find_package(PythonInterp 2.7 REQUIRED) - - set(TBB_INCLUDE_DIR ${HOUDINI_INCLUDE_DIR}) - set(TBB_LIBRARY ${HOUDINI_LIB}) - - set(GLEW_LOCATION ${HOUDINI_LIB}) - set(GLEW_INCLUDE_DIR ${HOUDINI_INCLUDE_DIR}) - - set(Boost_INCLUDE_DIRS ${HOUDINI_INCLUDE_DIR}) - find_library(Boost_LIBRARIES - NAMES libhboost_python libhboost_python-mt hboost_python hboost_python-mt - PATHS "${HOUDINI_LIB}" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH) -else(RPR_BUILD_AS_HOUDINI_PLUGIN) - # --Python. - if(PXR_USE_PYTHON_3) - find_package(PythonInterp 3.0 REQUIRED) - find_package(PythonLibs 3.0 REQUIRED) - else() - find_package(PythonInterp 2.7 REQUIRED) - find_package(PythonLibs 2.7 REQUIRED) - endif() - - # Set up a version string for comparisons. This is available - # as Boost_VERSION_STRING in CMake 3.14+ - set(boost_version_string "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") - - if (((${boost_version_string} VERSION_GREATER_EQUAL "1.67") AND - (${boost_version_string} VERSION_LESS "1.70")) OR - ((${boost_version_string} VERSION_GREATER_EQUAL "1.70") AND - Boost_NO_BOOST_CMAKE)) - # As of boost 1.67 the boost_python component name includes the - # associated Python version (e.g. python27, python36). After boost 1.70 - # the built-in cmake files will deal with this. If we are using boost - # that does not have working cmake files, or we are using a new boost - # and not using cmake's boost files, we need to do the below. - # - # Find the component under the versioned name and then set the generic - # Boost_PYTHON_LIBRARY variable so that we don't have to duplicate this - # logic in each library's CMakeLists.txt. - set(python_version_nodot "${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") - find_package(Boost - COMPONENTS - python${python_version_nodot} - REQUIRED - ) - set(Boost_PYTHON_LIBRARY "${Boost_PYTHON${python_version_nodot}_LIBRARY}") - else() - find_package(Boost - COMPONENTS - python - REQUIRED - ) - endif() endif() -find_package(TBB REQUIRED COMPONENTS tbb) -add_definitions(${TBB_DEFINITIONS}) - -find_package(OpenGL REQUIRED) -find_package(GLEW REQUIRED) - if (NOT PXR_MALLOC_LIBRARY) if (NOT WIN32) message(STATUS "Using default system allocator because PXR_MALLOC_LIBRARY is unspecified") endif() endif() +find_package(MaterialX QUIET) # Third Party Plugin Package Requirements # ---------------------------------------------- -if(RPR_ENABLE_OPENVDB_SUPPORT) - find_package(OpenVDB REQUIRED) +if(HoudiniUSD_FOUND) + find_package(OpenVDB REQUIRED) +else() + find_package(OpenVDB QUIET) +endif() + +if(OpenVDB_FOUND) find_package(OpenEXR REQUIRED COMPONENTS Half) +else() + message(STATUS "Skipping OpenVDB support") endif() # ---------------------------------------------- diff --git a/cmake/defaults/ProjectDefaults.cmake b/cmake/defaults/ProjectDefaults.cmake index 06cd70741..6205a72ce 100644 --- a/cmake/defaults/ProjectDefaults.cmake +++ b/cmake/defaults/ProjectDefaults.cmake @@ -67,3 +67,8 @@ execute_process( WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE) add_definitions(-DRPR_GIT_SHORT_HASH="${RPR_GIT_SHORT_HASH}") + +if(MSVC) + # Allow running INSTALL target + set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +endif() \ No newline at end of file diff --git a/cmake/defaults/Version.cmake b/cmake/defaults/Version.cmake index 5b3e8c2b5..2d3bd757c 100644 --- a/cmake/defaults/Version.cmake +++ b/cmake/defaults/Version.cmake @@ -23,5 +23,5 @@ # # Versioning information set(HD_RPR_MAJOR_VERSION "1") -set(HD_RPR_MINOR_VERSION "2") -set(HD_RPR_PATCH_VERSION "3") +set(HD_RPR_MINOR_VERSION "3") +set(HD_RPR_PATCH_VERSION "2") diff --git a/cmake/macros/Private.cmake b/cmake/macros/Private.cmake index 330d545dd..8a1b973e2 100644 --- a/cmake/macros/Private.cmake +++ b/cmake/macros/Private.cmake @@ -51,7 +51,7 @@ function(_copy_headers LIBRARY_NAME) OUTPUT ${outfile} COMMAND ${CMAKE_COMMAND} -E make_directory "${dir_to_create}" COMMAND ${CMAKE_COMMAND} -Dinfile="${infile}" -Doutfile="${outfile}" -P "${PROJECT_SOURCE_DIR}/cmake/macros/copyHeaderForBuild.cmake" - MAIN_DEPENDENCY "${infile}" + DEPENDS "${infile}" COMMENT "Copying ${f} ..." VERBATIM ) @@ -619,29 +619,32 @@ function(_pxr_add_rpath rpathRef target) endfunction() function(_pxr_install_rpath rpathRef NAME) - if(APPLE) - set(final "@loader_path/.") - else() - # Get and remove the origin. - list(GET ${rpathRef} 0 origin) - set(rpath ${${rpathRef}}) - list(REMOVE_AT rpath 0) - - set(final "") - # Canonicalize and uniquify paths. - foreach(path ${rpath}) - # Strip trailing slashes. - string(REGEX REPLACE "/+$" "" path "${path}") - - # Ignore paths we already have. - if (NOT ";${final};" MATCHES ";${path};") - list(APPEND final "${path}") + # Get and remove the origin. + list(GET ${rpathRef} 0 origin) + set(rpath ${${rpathRef}}) + list(REMOVE_AT rpath 0) + + # Canonicalize and uniquify paths. + set(final "") + foreach(path ${rpath}) + if(APPLE) + if("${path}/" MATCHES "^[$]ORIGIN/") + # Replace with origin path. + string(REPLACE "$ORIGIN/" "@loader_path/" path "${path}/") endif() - endforeach() - endif() + endif() + + # Strip trailing slashes. + string(REGEX REPLACE "/+$" "" path "${path}") + + # Ignore paths we already have. + if (NOT ";${final};" MATCHES ";${path};") + list(APPEND final "${path}") + endif() + endforeach() set_target_properties(${NAME} - PROPERTIES + PROPERTIES INSTALL_RPATH_USE_LINK_PATH FALSE INSTALL_RPATH "${final}" ) @@ -1142,15 +1145,11 @@ function(_pxr_library NAME) _get_install_dir("include/${PXR_PREFIX}/${NAME}" headerInstallPrefix) _get_install_dir("lib" libInstallPrefix) if(isPlugin) - if(RPR_BUILD_AS_HOUDINI_PLUGIN) - _get_install_dir("${HOUDINI_PLUGIN_INSTALL_RELPATH}" pluginInstallPrefix) - else(RPR_BUILD_AS_HOUDINI_PLUGIN) - _get_install_dir("plugin" pluginInstallPrefix) - if(NOT PXR_INSTALL_SUBDIR) - # XXX -- Why this difference? - _get_install_dir("plugin/usd" pluginInstallPrefix) - endif() - endif(RPR_BUILD_AS_HOUDINI_PLUGIN) + _get_install_dir("plugin" pluginInstallPrefix) + if(NOT PXR_INSTALL_SUBDIR) + # XXX -- Why this difference? + _get_install_dir("plugin/usd" pluginInstallPrefix) + endif() if(NOT isObject) # A plugin embedded in the monolithic library is found in @@ -1260,10 +1259,9 @@ function(_pxr_library NAME) ${PXR_PREFIX} ) target_include_directories(${NAME} - PRIVATE + PUBLIC "${CMAKE_BINARY_DIR}/include" "${CMAKE_BINARY_DIR}/${PXR_INSTALL_SUBDIR}/include" - PUBLIC ${args_INCLUDE_DIRS} ) @@ -1271,11 +1269,7 @@ function(_pxr_library NAME) _pxr_target_link_libraries(${NAME} ${args_LIBRARIES}) _pxr_init_rpath(rpath "${libInstallPrefix}") - if(RPR_BUILD_AS_HOUDINI_PLUGIN) - _pxr_add_rpath(rpath "${HOUDINI_LIB}") - else() - _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") - endif() + _pxr_add_rpath(rpath "${CMAKE_INSTALL_PREFIX}/lib") _pxr_install_rpath(rpath ${NAME}) # diff --git a/cmake/macros/Public.cmake b/cmake/macros/Public.cmake index 1cc9e1556..3f3b78e72 100644 --- a/cmake/macros/Public.cmake +++ b/cmake/macros/Public.cmake @@ -23,6 +23,24 @@ # include(Private) +function(GroupSources target) + get_target_property(${target}_SOURCES ${target} SOURCES) + foreach(FILE ${${target}_SOURCES}) + get_filename_component(ABS_FILE ${FILE} ABSOLUTE) + file(RELATIVE_PATH relPath ${CMAKE_CURRENT_SOURCE_DIR} ${ABS_FILE}) + + string(FIND "${relPath}" ".." out) + if("${out}" EQUAL 0) + source_group("external" FILES "${FILE}") + else() + get_filename_component(PARENT_DIR "${FILE}" DIRECTORY) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}") + string(REPLACE "/" "\\" GROUP "${GROUP}") + source_group("${GROUP}" FILES "${FILE}") + endif() + endforeach() +endfunction() + macro(GetAppDataPath retVal) if(WIN32) if(DEFINED ENV{PROGRAMDATA}) @@ -274,10 +292,6 @@ function(pxr_library NAME) set(prefix "") set(suffix ${CMAKE_SHARED_LIBRARY_SUFFIX}) - if(RPR_BUILD_AS_HOUDINI_PLUGIN) - set(subdir "usd_plugins") - endif() - # Katana plugins install into a specific sub directory structure. # In particular, shared objects install into plugin/Libs if(args_KATANA_PLUGIN) diff --git a/cmake/modules/FindGLEW.cmake b/cmake/modules/FindGLEW.cmake deleted file mode 100644 index bf2d41e91..000000000 --- a/cmake/modules/FindGLEW.cmake +++ /dev/null @@ -1,132 +0,0 @@ -# -# Copyright 2016 Pixar -# -# Licensed under the Apache License, Version 2.0 (the "Apache License") -# with the following modification; you may not use this file except in -# compliance with the Apache License and the following modification to it: -# Section 6. Trademarks. is deleted and replaced with: -# -# 6. Trademarks. This License does not grant permission to use the trade -# names, trademarks, service marks, or product names of the Licensor -# and its affiliates, except as required to comply with Section 4(c) of -# the License and to reproduce the content of the NOTICE file. -# -# You may obtain a copy of the Apache License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the Apache License with the above modification is -# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the Apache License for the specific -# language governing permissions and limitations under the Apache License. -# -# Try to find GLEW library and include path. -# Once done this will define -# -# GLEW_FOUND -# GLEW_INCLUDE_DIR -# GLEW_LIBRARY -# - -include(FindPackageHandleStandardArgs) - -if (WIN32) - find_path(GLEW_INCLUDE_DIR - NAMES - GL/glew.h - HINTS - "${GLEW_LOCATION}/include" - "$ENV{GLEW_LOCATION}/include" - "${GLEW_INCLUDEDIR}" - PATHS - "$ENV{PROGRAMFILES}/GLEW/include" - "${PROJECT_SOURCE_DIR}/extern/glew/include" - DOC "The directory where GL/glew.h resides" ) - - if ("${CMAKE_GENERATOR}" MATCHES "[Ww]in64") - set(ARCH x64) - else() - set(ARCH x86) - endif() - - find_library(GLEW_LIBRARY - NAMES - glew GLEW glew32 glew32s - HINTS - "${GLEW_LOCATION}/lib" - "$ENV{GLEW_LOCATION}/lib" - PATHS - "$ENV{PROGRAMFILES}/GLEW/lib" - "${PROJECT_SOURCE_DIR}/extern/glew/bin" - "${PROJECT_SOURCE_DIR}/extern/glew/lib" - PATH_SUFFIXES - Release/${ARCH} - DOC "The GLEW library") -endif () - -if (${CMAKE_HOST_UNIX}) - find_path( GLEW_INCLUDE_DIR - NAMES - GL/glew.h - HINTS - "${GLEW_LOCATION}/include" - "$ENV{GLEW_LOCATION}/include" - "${GLEW_INCLUDEDIR}" - PATHS - /usr/include - /usr/local/include - /sw/include - /opt/local/include - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH - DOC "The directory where GL/glew.h resides" - ) - find_library( GLEW_LIBRARY - NAMES - GLEW glew - HINTS - "${GLEW_LOCATION}/lib" - "$ENV{GLEW_LOCATION}/lib" - PATHS - "${GLEW_LOCATION}/lib" - /usr/lib64 - /usr/lib - /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} - /usr/local/lib64 - /usr/local/lib - /sw/lib - /opt/local/lib - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH - DOC "The GLEW library") -endif () - - -if (GLEW_INCLUDE_DIR AND EXISTS "${GLEW_INCLUDE_DIR}/GL/glew.h") - - file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" GLEW_4_2 REGEX "^#define GL_VERSION_4_2.*$") - if (GLEW_4_2) - set(OPENGL_4_2_FOUND TRUE) - else () - message(WARNING - "glew-1.7.0 or newer needed for supporting OpenGL 4.2 dependent features" - ) - endif () - - file(STRINGS "${GLEW_INCLUDE_DIR}/GL/glew.h" GLEW_4_3 REGEX "^#define GL_VERSION_4_3.*$") - if (GLEW_4_3) - SET(OPENGL_4_3_FOUND TRUE) - else () - message(WARNING - "glew-1.9.0 or newer needed for supporting OpenGL 4.3 dependent features" - ) - endif () - -endif () - -find_package_handle_standard_args(GLEW - REQUIRED_VARS - GLEW_INCLUDE_DIR - GLEW_LIBRARY -) diff --git a/cmake/modules/FindHoudiniUSD.cmake b/cmake/modules/FindHoudiniUSD.cmake new file mode 100644 index 000000000..9d7afe997 --- /dev/null +++ b/cmake/modules/FindHoudiniUSD.cmake @@ -0,0 +1,156 @@ +# This finds Pixar USD which is part of a Houdini installation. + +set(HOUDINI_ROOT $ENV{HFS} CACHE PATH "Houdini installation directory") + +set(HUSD_REQ_VARS "") + +find_path(Houdini_USD_INCLUDE_DIR + "pxr/pxr.h" + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES "toolkit/include" + NO_DEFAULT_PATH) +list(APPEND HUSD_REQ_VARS "Houdini_USD_INCLUDE_DIR") + +find_path(Houdini_USD_LIB_DIR + "libpxr_tf${CMAKE_SHARED_LIBRARY_SUFFIX}" + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES + "dsolib" # Linux and Windows + "../Libraries" # macOS + "bin" # Windows (dll) + NO_DEFAULT_PATH) +list(APPEND HUSD_REQ_VARS "Houdini_USD_LIB_DIR") + +if(WIN32) + find_path(Houdini_USD_IMPLIB_DIR + "libpxr_tf.lib" + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES "custom/houdini/dsolib" # Windows (import lib) + NO_DEFAULT_PATH) + list(APPEND HUSD_REQ_VARS "Houdini_USD_IMPLIB_DIR") +endif() + +if(APPLE) + find_library(Houdini_TBB_LIB + NAMES tbb + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES "../Libraries" + NO_DEFAULT_PATH) +endif(APPLE) + +find_path(Houdini_Python_INCLUDE_DIR + "pyconfig.h" + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES + "toolkit/include/python2.7" + NO_DEFAULT_PATH) +list(APPEND HUSD_REQ_VARS "Houdini_Python_INCLUDE_DIR") + +find_file( + Houdini_Python_LIB + NAMES + "libpython2.7${CMAKE_SHARED_LIBRARY_SUFFIX}" # Unix + "python27.lib" # Windows (import lib) + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES + "python/lib" # Linux + "../../../../Python.framework/Versions/Current/lib" # macOS + "python27/libs" # Windows (import lib) + NO_DEFAULT_PATH) +list(APPEND HUSD_REQ_VARS "Houdini_Python_LIB") + +find_file( + Houdini_Boostpython_LIB + "libhboost_python-mt${CMAKE_SHARED_LIBRARY_SUFFIX}" # Unix + "libhboost_python27-mt-x64${CMAKE_SHARED_LIBRARY_SUFFIX}" # Unix + "hboost_python-mt.lib" # Windows (import lib) + "hboost_python27-mt-x64.lib" # Windows Houdini 18.5 + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES + "dsolib" # Linux + "../Libraries" # macOS + #"bin" # Windows + "custom/houdini/dsolib" # Windows (import lib) + NO_DEFAULT_PATH) +list(APPEND HUSD_REQ_VARS "Houdini_Boostpython_LIB") + +find_program(HYTHON_EXECUTABLE hython + PATHS ${HOUDINI_ROOT} + PATH_SUFFIXES bin) +if(NOT HYTHON_EXECUTABLE) + message(FATAL "Could not find hython executable") +endif() +list(APPEND HUSD_REQ_VARS "HYTHON_EXECUTABLE") + +if(WIN32) + set(Houdini_LIB_DIR ${HOUDINI_ROOT}/custom/houdini/dsolib) +elseif(APPLE) + set(Houdini_LIB_DIR ${HOUDINI_ROOT}/../Libraries) +else() + set(Houdini_LIB_DIR ${HOUDINI_ROOT}/dsolib) +endif() + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + "HoudiniUSD" + REQUIRED_VARS ${HUSD_REQ_VARS}) + +if(HoudiniUSD_FOUND) + message(STATUS " Houdini USD includes: ${Houdini_USD_INCLUDE_DIR}") + message(STATUS " Houdini USD libs: ${Houdini_USD_LIB_DIR}") + message(STATUS " Houdini Python includes: ${Houdini_Python_INCLUDE_DIR}") + message(STATUS " Houdini Python lib: ${Houdini_Python_LIB}") + message(STATUS " Houdini Boost.Python lib: ${Houdini_Boostpython_LIB}") +endif() + +if(HoudiniUSD_FOUND AND NOT TARGET hd) + # Generic creation of the usd targets. This is not meant to be perfect. The + # criteria is "does it work for our use". Also, these names match the ones + # of the USD distribution so we can use either without many conditions. + # We're missing the interlib dependencies here so the plugin has to link a + # bit more stuff explicitly. + foreach(targetName + arch tf gf js trace work plug vt ar kind sdf ndr sdr pcp usd usdGeom + usdVol usdLux usdMedia usdShade usdRender usdHydra usdRi usdSkel usdUI + usdUtils garch hf hio cameraUtil pxOsd glf hgi hgiGL hd hdSt hdx + usdImaging usdImagingGL usdRiImaging usdSkelImaging usdVolImaging + usdAppUtils usdviewq) + add_library(${targetName} SHARED IMPORTED) + set_target_properties(${targetName} PROPERTIES + IMPORTED_LOCATION "${Houdini_USD_LIB_DIR}/libpxr_${targetName}${CMAKE_SHARED_LIBRARY_SUFFIX}" + INTERFACE_INCLUDE_DIRECTORIES ${Houdini_USD_INCLUDE_DIR}) + if(MSVC) + set_target_properties(${targetName} PROPERTIES + IMPORTED_IMPLIB "${Houdini_USD_IMPLIB_DIR}/libpxr_${targetName}.lib") + endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Houdini builds with the old ABI. We need to match. + target_compile_definitions(${targetName} + INTERFACE "_GLIBCXX_USE_CXX11_ABI=0") + endif() + if(WIN32) + # Shut up compiler about warnings from USD. + target_compile_options(${targetName} INTERFACE + "/wd4506" "/wd4244" "/wd4305" "/wd4267") + # For automatically linked libraries (python, tbb) + target_link_directories(${targetName} + INTERFACE "${HOUDINI_ROOT}/custom/houdini/dsolib") + endif() + endforeach() + # Add python to tf, usdImagingGL targets. + target_include_directories(tf INTERFACE ${Houdini_Python_INCLUDE_DIR}) + target_link_libraries(tf INTERFACE ${Houdini_Python_LIB}) + target_include_directories(usdImagingGL INTERFACE + ${Houdini_Python_INCLUDE_DIR}) + target_link_libraries(usdImagingGL INTERFACE ${Houdini_Python_LIB}) + # Add Boost.Python to tf, vt. Should actually be in many more but that's + # more than enough to get it linked in for us. + target_link_libraries(tf INTERFACE ${Houdini_Boostpython_LIB}) + target_link_libraries(vt INTERFACE ${Houdini_Boostpython_LIB}) + if(APPLE) + target_link_libraries(tf INTERFACE ${Houdini_TBB_LIB}) + endif(APPLE) + # By default Boost links libraries implicitly for the user via pragma's, we do not want this + target_compile_definitions(tf INTERFACE -DHBOOST_ALL_NO_LIB) +endif() diff --git a/cmake/modules/FindOpenEXR.cmake b/cmake/modules/FindOpenEXR.cmake index 4454e69aa..595edfb4c 100644 --- a/cmake/modules/FindOpenEXR.cmake +++ b/cmake/modules/FindOpenEXR.cmake @@ -76,6 +76,7 @@ foreach(OPENEXR_LIB ${OpenEXR_FIND_COMPONENTS}) HINTS "${OPENEXR_LOCATION}" "$ENV{OPENEXR_LOCATION}" + "${OPENEXR_LIB_LOCATION}" PATH_SUFFIXES lib/ DOC diff --git a/cmake/modules/FindOpenVDB.cmake b/cmake/modules/FindOpenVDB.cmake index 208219716..b53ad296c 100644 --- a/cmake/modules/FindOpenVDB.cmake +++ b/cmake/modules/FindOpenVDB.cmake @@ -15,10 +15,10 @@ FIND_PACKAGE( PackageHandleStandardArgs ) set(OPENVDB_VERSION_FILE_RELPATH include/openvdb/version.h) set(OPENVDB_FIND_PATH "${OPENVDB_ROOT}" "$ENV{OPENVDB_ROOT}") -if(RPR_BUILD_AS_HOUDINI_PLUGIN) +if(HoudiniUSD_FOUND) set(OPENVDB_VERSION_FILE_RELPATH openvdb/version.h) - set(OPENVDB_FIND_PATH ${HOUDINI_INCLUDE_DIR}) -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) + set(OPENVDB_FIND_PATH ${Houdini_USD_INCLUDE_DIR}) +endif(HoudiniUSD_FOUND) FIND_PATH( OPENVDB_LOCATION ${OPENVDB_VERSION_FILE_RELPATH} ${OPENVDB_FIND_PATH} @@ -26,15 +26,15 @@ FIND_PATH( OPENVDB_LOCATION ${OPENVDB_VERSION_FILE_RELPATH} NO_SYSTEM_ENVIRONMENT_PATH ) -if(RPR_BUILD_AS_HOUDINI_PLUGIN) - set(OpenVDB_INCLUDE_DIR ${HOUDINI_INCLUDE_DIR}) - set(OpenVDB_LIBRARY_DIR ${HOUDINI_LIB}) +if(HoudiniUSD_FOUND) + set(OpenVDB_INCLUDE_DIR ${Houdini_USD_INCLUDE_DIR}) + set(OpenVDB_LIBRARY_DIR ${Houdini_LIB_DIR}) set(OPENVDB_LIBRARY_NAME openvdb_sesi) -else() +else(HoudiniUSD_FOUND) set(OpenVDB_INCLUDE_DIR ${OPENVDB_LOCATION}/include) set(OpenVDB_LIBRARY_DIR ${OPENVDB_LOCATION}/lib) set(OPENVDB_LIBRARY_NAME openvdb) -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) +endif(HoudiniUSD_FOUND) FIND_LIBRARY( OpenVDB_OPENVDB_LIBRARY ${OPENVDB_LIBRARY_NAME} PATHS "${OpenVDB_LIBRARY_DIR}" @@ -42,32 +42,34 @@ FIND_LIBRARY( OpenVDB_OPENVDB_LIBRARY ${OPENVDB_LIBRARY_NAME} NO_SYSTEM_ENVIRONMENT_PATH ) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenVDB + REQUIRED_VARS OPENVDB_LOCATION OpenVDB_OPENVDB_LIBRARY + ) + SET( OpenVDB_LIBRARIES "") LIST( APPEND OpenVDB_LIBRARIES "${OpenVDB_OPENVDB_LIBRARY}" ) -SET( OPENVDB_VERSION_FILE "${OpenVDB_INCLUDE_DIR}/openvdb/version.h" ) +if(OpenVDB_FOUND) + SET( OPENVDB_VERSION_FILE "${OpenVDB_INCLUDE_DIR}/openvdb/version.h" ) -FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_major_version_str - REGEX "^#define[\t ]+OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER[\t ]+.*") -FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_minor_version_str - REGEX "^#define[\t ]+OPENVDB_LIBRARY_MINOR_VERSION_NUMBER[\t ]+.*") -FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_patch_version_str - REGEX "^#define[\t ]+OPENVDB_LIBRARY_PATCH_VERSION_NUMBER[\t ]+.*") + FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_major_version_str + REGEX "^#define[\t ]+OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER[\t ]+.*") + FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_minor_version_str + REGEX "^#define[\t ]+OPENVDB_LIBRARY_MINOR_VERSION_NUMBER[\t ]+.*") + FILE( STRINGS "${OPENVDB_VERSION_FILE}" openvdb_patch_version_str + REGEX "^#define[\t ]+OPENVDB_LIBRARY_PATCH_VERSION_NUMBER[\t ]+.*") -STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" - _openvdb_major_version_number "${openvdb_major_version_str}") -STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_MINOR_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" - _openvdb_minor_version_number "${openvdb_minor_version_str}") -STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_PATCH_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" - _openvdb_patch_version_number "${openvdb_patch_version_str}") + STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_MAJOR_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" + _openvdb_major_version_number "${openvdb_major_version_str}") + STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_MINOR_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" + _openvdb_minor_version_number "${openvdb_minor_version_str}") + STRING( REGEX REPLACE "^.*OPENVDB_LIBRARY_PATCH_VERSION_NUMBER[\t ]+([0-9]*).*$" "\\1" + _openvdb_patch_version_number "${openvdb_patch_version_str}") -SET( OpenVDB_MAJOR_VERSION ${_openvdb_major_version_number} - CACHE STRING "OpenVDB major version number" ) -SET( OpenVDB_MINOR_VERSION ${_openvdb_minor_version_number} - CACHE STRING "OpenVDB minor version number" ) -SET( OpenVDB_PATCH_VERSION ${_openvdb_patch_version_number} - CACHE STRING "OpenVDB patch version number" ) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS( OpenVDB - REQUIRED_VARS OPENVDB_LOCATION OpenVDB_OPENVDB_LIBRARY - ) \ No newline at end of file + SET( OpenVDB_MAJOR_VERSION ${_openvdb_major_version_number} + CACHE STRING "OpenVDB major version number" ) + SET( OpenVDB_MINOR_VERSION ${_openvdb_minor_version_number} + CACHE STRING "OpenVDB minor version number" ) + SET( OpenVDB_PATCH_VERSION ${_openvdb_patch_version_number} + CACHE STRING "OpenVDB patch version number" ) +endif() diff --git a/cmake/modules/FindRif.cmake b/cmake/modules/FindRif.cmake index 55ac8294a..0561786b7 100644 --- a/cmake/modules/FindRif.cmake +++ b/cmake/modules/FindRif.cmake @@ -38,16 +38,16 @@ if(WIN32) set(RIF_BINARIES ${RIF_LOCATION_LIB}/MIOpen.dll ${RIF_LOCATION_LIB}/RadeonImageFilters.dll - ${RIF_LOCATION_LIB}/RadeonML-MIOpen.dll - ${RIF_LOCATION_LIB}/RadeonML-DirectML.dll) + ${RIF_LOCATION_LIB}/RadeonML_MIOpen.dll + ${RIF_LOCATION_LIB}/RadeonML_DirectML.dll) else(WIN32) if(APPLE) set(RIF_DEPENDENCY_LIBRARIES - ${RIF_LOCATION_LIB}/libRadeonML-MPS.dylib) + ${RIF_LOCATION_LIB}/libRadeonML_MPS.dylib) else() set(RIF_DEPENDENCY_LIBRARIES ${RIF_LOCATION_LIB}/libMIOpen.so - ${RIF_LOCATION_LIB}/libRadeonML-MIOpen.so) + ${RIF_LOCATION_LIB}/libRadeonML_MIOpen.so) endif(APPLE) endif(WIN32) @@ -55,7 +55,7 @@ if(NOT DEFINED RIF_MODELS_DIR) set(RIF_MODELS_DIR "${RIF_LOCATION}/models") endif() -set(RIF_VERSION_FILE "${RIF_LOCATION_INCLUDE}/version.h") +set(RIF_VERSION_FILE "${RIF_LOCATION_INCLUDE}/RadeonImageFilters_version.h") if(NOT EXISTS ${RIF_VERSION_FILE}) message(FATAL_ERROR "Invalid RIF SDK: missing ${RIF_VERSION_FILE} file") endif() diff --git a/cmake/modules/FindRpr.cmake b/cmake/modules/FindRpr.cmake index f8da296c2..63f92ab38 100644 --- a/cmake/modules/FindRpr.cmake +++ b/cmake/modules/FindRpr.cmake @@ -1,3 +1,7 @@ +if(TARGET rpr) + return() +endif() + if(NOT RPR_LOCATION) set(RPR_LOCATION ${PROJECT_SOURCE_DIR}/deps/RPR/RadeonProRender) endif() @@ -16,6 +20,9 @@ if(APPLE) SET_RPR_VARIABLES(binMacOS) elseif(WIN32) SET_RPR_VARIABLES(libWin64) + if(NOT RPR_BIN_LOCATION) + set(RPR_BIN_LOCATION ${RPR_LOCATION}/binWin64) + endif() elseif(RPR_SDK_PLATFORM STREQUAL "ubuntu18.04") SET_RPR_VARIABLES(binUbuntu18) elseif(RPR_SDK_PLATFORM STREQUAL "centos7") @@ -44,53 +51,33 @@ find_library(RPR_LOADSTORE_LIBRARY NO_SYSTEM_ENVIRONMENT_PATH ) -if(WIN32) - if(NOT RPR_BIN_LOCATION) - set(RPR_BIN_LOCATION ${RPR_LOCATION}/binWin64) - endif() +foreach(entry "Tahoe64;TAHOE" "Northstar64;NORTHSTAR" "Hybrid;HYBRID") + list(GET entry 0 libName) + list(GET entry 1 libId) - if (EXISTS "${RPR_BIN_LOCATION}/Tahoe64.dll") - set(RPR_TAHOE_BINARY ${RPR_BIN_LOCATION}/Tahoe64.dll) + if(WIN32) + set(libPath ${RPR_BIN_LOCATION}/${libName}.dll) + if (EXISTS "${libPath}") + set(RPR_${libId}_BINARY ${libPath}) + endif() + else() + find_library(RPR_${libId}_BINARY + NAMES ${libName} + PATHS + "${RPR_LOCATION_LIB}" + DOC + "Radeon ProRender ${libName} library path" + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + ) endif() - if (EXISTS "${RPR_BIN_LOCATION}/Hybrid.dll") - set(RPR_HYBRID_BINARY ${RPR_BIN_LOCATION}/Hybrid.dll) + if(RPR_${libId}_BINARY) + set(RPR_PLUGINS ${RPR_PLUGINS} ${RPR_${libId}_BINARY}) endif() +endforeach() - set(RPR_BINARIES - ${RPR_BIN_LOCATION}/RadeonProRender64.dll - ${RPR_BIN_LOCATION}/RprLoadStore64.dll - ${RPR_TAHOE_BINARY} - ${RPR_HYBRID_BINARY}) -else() - find_library(RPR_HYBRID_BINARY - NAMES Hybrid${CMAKE_SHARED_LIBRARY_SUFFIX} - PATHS - "${RPR_LOCATION_LIB}" - DOC - "Radeon ProRender hybrid library path" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - ) - if(RPR_HYBRID_BINARY) - set(RPR_PLUGIN_LIBRARIES ${RPR_HYBRID_BINARY}) - endif() - - find_library(RPR_TAHOE_BINARY - NAMES libTahoe64 Tahoe64 - PATHS - "${RPR_LOCATION_LIB}" - DOC - "Radeon ProRender tahoe library path" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH - ) - if(RPR_TAHOE_BINARY) - set(RPR_PLUGIN_LIBRARIES ${RPR_PLUGIN_LIBRARIES} ${RPR_TAHOE_BINARY}) - endif() -endif(WIN32) - -if(NOT RPR_TAHOE_BINARY AND NOT RPR_HYBRID_BINARY) +if(NOT RPR_PLUGINS) message(FATAL_ERROR "At least one RPR plugin required") endif() @@ -106,3 +93,21 @@ find_package_handle_standard_args(Rpr RPR_LOADSTORE_LIBRARY RPR_LIBRARY ) + +add_library(rpr INTERFACE) +target_include_directories(rpr INTERFACE ${RPR_LOCATION_INCLUDE}) +target_link_libraries(rpr INTERFACE ${RPR_LIBRARY} ${RPR_LOADSTORE_LIBRARY}) + +if(NOT DEFINED RPR_CPP_WRAPPER_LOCATION) + set(RPR_CPP_WRAPPER_LOCATION ${RPR_TOOLS_LOCATION}) +endif() + +add_library(cpprpr STATIC + ${RPR_CPP_WRAPPER_LOCATION}/RadeonProRender.hpp + ${RPR_CPP_WRAPPER_LOCATION}/RadeonProRenderCpp.cpp) +set_target_properties(cpprpr PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_include_directories(cpprpr PUBLIC ${RPR_CPP_WRAPPER_LOCATION}) +target_link_libraries(cpprpr PUBLIC rpr) +target_compile_definitions(cpprpr PUBLIC + RPR_CPPWRAPER_DISABLE_MUTEXLOCK + RPR_API_USE_HEADER_V2) diff --git a/cmake/modules/FindTBB.cmake b/cmake/modules/FindTBB.cmake deleted file mode 100644 index 4c2d7f1ff..000000000 --- a/cmake/modules/FindTBB.cmake +++ /dev/null @@ -1,219 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2015 Justus Calvin -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# -# FindTBB -# ------- -# -# Find TBB include directories and libraries. -# -# Usage: -# -# find_package(TBB [major[.minor]] [EXACT] -# [QUIET] [REQUIRED] -# [[COMPONENTS] [components...]] -# [OPTIONAL_COMPONENTS components...]) -# -# where the allowed components are tbbmalloc and tbb_preview. Users may modify -# the behavior of this module with the following variables: -# -# * TBB_ROOT_DIR - The base directory the of TBB installation. -# * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. -# * TBB_LIBRARY - The directory that contains the TBB library files. -# * TBB__LIBRARY - The path of the TBB the corresponding TBB library. -# These libraries, if specified, override the -# corresponding library search results, where -# may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, -# tbb_preview, or tbb_preview_debug. -# * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will -# be used instead of the release version. -# -# Users may modify the behavior of this module with the following environment -# variables: -# -# * TBB_INSTALL_DIR -# * TBBROOT -# * LIBRARY_PATH -# -# This module will set the following variables: -# -# * TBB_FOUND - Set to false, or undefined, if we haven’t found, or -# don’t want to use TBB. -# * TBB__FOUND - If False, optional part of TBB sytem is -# not available. -# * TBB_VERSION - The full version string -# * TBB_VERSION_MAJOR - The major version -# * TBB_VERSION_MINOR - The minor version -# * TBB_INTERFACE_VERSION - The interface version number defined in -# tbb/tbb_stddef.h. -# * TBB__LIBRARY_RELEASE - The path of the TBB release version of -# , where may be tbb, tbb_debug, -# tbbmalloc, tbbmalloc_debug, tbb_preview, or -# tbb_preview_debug. -# * TBB__LIBRARY_DEGUG - The path of the TBB release version of -# , where may be tbb, tbb_debug, -# tbbmalloc, tbbmalloc_debug, tbb_preview, or -# tbb_preview_debug. -# -# The following varibles should be used to build and link with TBB: -# -# * TBB_INCLUDE_DIRS - The include directory for TBB. -# * TBB_LIBRARIES - The libraries to link against to use TBB. -# * TBB_DEFINITIONS - Definitions to use when compiling code that uses TBB. - -include(FindPackageHandleStandardArgs) - -if(NOT TBB_FOUND) - - ################################## - # Check the build type - ################################## - - if(NOT DEFINED TBB_USE_DEBUG_BUILD) - if(CMAKE_BUILD_TYPE MATCHES "Debug|DEBUG|debug") - set(TBB_USE_DEBUG_BUILD TRUE) - else() - set(TBB_USE_DEBUG_BUILD FALSE) - endif() - endif() - - ################################## - # Set the TBB search directories - ################################## - - # Define search paths based on user input and environment variables - set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT}) - - # Define the search directories based on the current platform - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" - "C:/Program Files (x86)/Intel/TBB") - # TODO: Set the proper suffix paths based on compiler introspection. - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - # OS X - set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") - - # TODO: Check to see which C++ library is being used by the compiler. - if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) - # The default C++ library on OS X 10.9 and later is libc++ - set(TBB_LIB_PATH_SUFFIX "lib/libc++") - else() - set(TBB_LIB_PATH_SUFFIX "lib") - endif() - elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - # Linux - set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") - - # TODO: Check compiler version to see the suffix should be /gcc4.1 or - # /gcc4.1. For now, assume that the compiler is more recent than - # gcc 4.4.x or later. - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") - set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") - endif() - endif() - - ################################## - # Find the TBB include dir - ################################## - - find_path(TBB_INCLUDE_DIRS tbb/tbb.h - HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} - PATH_SUFFIXES include) - - ################################## - # Find TBB components - ################################## - - # Find each component - foreach(_comp tbb_preview tbbmalloc tbb) - # Search for the libraries - find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp} - HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} - PATH_SUFFIXES "${TBB_LIB_PATH_SUFFIX}") - - find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug - HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH - PATH_SUFFIXES "${TBB_LIB_PATH_SUFFIX}") - - - # Set the library to be used for the component - if(NOT TBB_${_comp}_LIBRARY) - if(TBB_USE_DEBUG_BUILD AND TBB_${_comp}_LIBRARY_DEBUG) - set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_DEBUG}") - elseif(TBB_${_comp}_LIBRARY_RELEASE) - set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_RELEASE}") - elseif(TBB_${_comp}_LIBRARY_DEBUG) - set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_DEBUG}") - endif() - endif() - - # Set the TBB library list and component found variables - if(TBB_${_comp}_LIBRARY) - list(APPEND TBB_LIBRARIES "${TBB_${_comp}_LIBRARY}") - set(TBB_${_comp}_FOUND TRUE) - else() - set(TBB_${_comp}_FOUND FALSE) - endif() - - mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) - mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) - mark_as_advanced(TBB_${_comp}_LIBRARY) - - endforeach() - - ################################## - # Set compile flags - ################################## - - if(TBB_tbb_LIBRARY MATCHES "debug") - set(TBB_DEFINITIONS "-DTBB_USE_DEBUG=1") - endif() - - ################################## - # Set version strings - ################################## - - if(TBB_INCLUDE_DIRS) - file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) - string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" - TBB_VERSION_MAJOR "${_tbb_version_file}") - string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" - TBB_VERSION_MINOR "${_tbb_version_file}") - string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_INTERFACE_VERSION "${_tbb_version_file}") - set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") - endif() - - find_package_handle_standard_args(TBB - REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES - HANDLE_COMPONENTS - VERSION_VAR TBB_VERSION) - - mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) - -endif() diff --git a/cmake/modules/FindUSD.cmake b/cmake/modules/FindUSD.cmake deleted file mode 100644 index 2c3f9dc67..000000000 --- a/cmake/modules/FindUSD.cmake +++ /dev/null @@ -1,59 +0,0 @@ -# Simple module to find USD. - -if(RPR_BUILD_AS_HOUDINI_PLUGIN) - set(USD_INCLUDE_DIR ${HOUDINI_INCLUDE_DIR}) - set(USD_LIBRARY_DIR ${HOUDINI_LIB}) - set(PXR_LIB_PREFIX pxr_) - if(WIN32) - set(PXR_LIB_PREFIX libpxr_) - endif() - set(USD_LIBRARY_MONOLITHIC FALSE) -else(RPR_BUILD_AS_HOUDINI_PLUGIN) - find_path(USD_INCLUDE_DIR pxr/pxr.h - PATHS ${USD_ROOT}/include - $ENV{USD_ROOT}/include - DOC "USD Include directory" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH) - - find_path(USD_LIBRARY_DIR - NAMES "${PXR_LIB_PREFIX}usd${CMAKE_SHARED_LIBRARY_SUFFIX}" - PATHS ${USD_ROOT}/lib - $ENV{USD_ROOT}/lib - DOC "USD Libraries directory" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH) - set(USD_LIBRARY_MONOLITHIC FALSE) - - if(NOT USD_LIBRARY_DIR) - find_path(USD_LIBRARY_DIR - NAMES "${PXR_LIB_PREFIX}usd_ms${CMAKE_SHARED_LIBRARY_SUFFIX}" - PATHS ${USD_ROOT}/lib - $ENV{USD_ROOT}/lib - DOC "USD Libraries directory" - NO_DEFAULT_PATH - NO_SYSTEM_ENVIRONMENT_PATH) - set(USD_LIBRARY_MONOLITHIC TRUE) - endif() -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) - -if(USD_INCLUDE_DIR AND EXISTS "${USD_INCLUDE_DIR}/pxr/pxr.h") - foreach(_usd_comp MAJOR MINOR PATCH) - file(STRINGS - "${USD_INCLUDE_DIR}/pxr/pxr.h" - _usd_tmp - REGEX "#define PXR_${_usd_comp}_VERSION .*$") - string(REGEX MATCHALL "[0-9]+" USD_${_usd_comp}_VERSION ${_usd_tmp}) - endforeach() - set(USD_VERSION ${USD_MAJOR_VERSION}.${USD_MINOR_VERSION}.${USD_PATCH_VERSION}) -endif() - -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args( - USD - REQUIRED_VARS - USD_INCLUDE_DIR - USD_LIBRARY_DIR - VERSION_VAR - USD_VERSION) diff --git a/cmake/modules/FindUSDMonolithic.cmake b/cmake/modules/FindUSDMonolithic.cmake new file mode 100644 index 000000000..1d8078eea --- /dev/null +++ b/cmake/modules/FindUSDMonolithic.cmake @@ -0,0 +1,104 @@ +# USD 20.05 does not generate cmake config for the monolithic library as it does for the default mode +# So we have to handle monolithic USD in a special way + +find_path(USD_INCLUDE_DIR pxr/pxr.h + PATHS ${pxr_DIR}/include + $ENV{pxr_DIR}/include + DOC "USD Include directory" + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH) + +find_path(USD_LIBRARY_DIR + NAMES "${PXR_LIB_PREFIX}usd_ms${CMAKE_SHARED_LIBRARY_SUFFIX}" + PATHS ${pxr_DIR}/lib + $ENV{pxr_DIR}/lib + DOC "USD Libraries directory" + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH) + +find_library(USD_MONOLITHIC_LIBRARY + NAMES ${PXR_LIB_PREFIX}usd_ms + PATHS ${USD_LIBRARY_DIR} + NO_DEFAULT_PATH + NO_SYSTEM_ENVIRONMENT_PATH) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(USDMonolithic + USD_INCLUDE_DIR + USD_LIBRARY_DIR + USD_MONOLITHIC_LIBRARY) + +if(USDMonolithic_FOUND) + list(APPEND CMAKE_PREFIX_PATH ${pxr_DIR}) + + # --Python. + if(PXR_USE_PYTHON_3) + find_package(PythonInterp 3.0 REQUIRED) + find_package(PythonLibs 3.0 REQUIRED) + else() + find_package(PythonInterp 2.7 REQUIRED) + find_package(PythonLibs 2.7 REQUIRED) + endif() + + # Set up a version string for comparisons. This is available + # as Boost_VERSION_STRING in CMake 3.14+ + set(boost_version_string "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") + + if (((${boost_version_string} VERSION_GREATER_EQUAL "1.67") AND + (${boost_version_string} VERSION_LESS "1.70")) OR + ((${boost_version_string} VERSION_GREATER_EQUAL "1.70") AND + Boost_NO_BOOST_CMAKE)) + # As of boost 1.67 the boost_python component name includes the + # associated Python version (e.g. python27, python36). After boost 1.70 + # the built-in cmake files will deal with this. If we are using boost + # that does not have working cmake files, or we are using a new boost + # and not using cmake's boost files, we need to do the below. + # + # Find the component under the versioned name and then set the generic + # Boost_PYTHON_LIBRARY variable so that we don't have to duplicate this + # logic in each library's CMakeLists.txt. + set(python_version_nodot "${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}") + find_package(Boost + COMPONENTS + python${python_version_nodot} + REQUIRED + ) + set(Boost_PYTHON_LIBRARY "${Boost_PYTHON${python_version_nodot}_LIBRARY}") + else() + find_package(Boost + COMPONENTS + python + REQUIRED + ) + endif() + + add_library(usd_ms SHARED IMPORTED) + set_property(TARGET usd_ms APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + + target_compile_definitions(usd_ms INTERFACE + -DPXR_PYTHON_ENABLED=1) + target_link_libraries(usd_ms INTERFACE + ${USD_MONOLITHIC_LIBRARY} + ${Boost_LIBRARIES} + ${PYTHON_LIBRARIES}) + target_link_directories(usd_ms INTERFACE + ${USD_LIBRARY_DIR}) + target_include_directories(usd_ms INTERFACE + ${USD_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS}) + set_target_properties(usd_ms PROPERTIES + IMPORTED_IMPLIB_RELEASE "${USD_MONOLITHIC_LIBRARY}" + IMPORTED_LOCATION_RELEASE "${USD_LIBRARY_DIR}/${PXR_LIB_PREFIX}usd_ms${CMAKE_SHARED_LIBRARY_SUFFIX}" + ) + + foreach(targetName + arch tf gf js trace work plug vt ar kind sdf ndr sdr pcp usd usdGeom + usdVol usdLux usdMedia usdShade usdRender usdHydra usdRi usdSkel usdUI + usdUtils garch hf hio cameraUtil pxOsd glf hgi hgiGL hd hdSt hdx + usdImaging usdImagingGL usdRiImaging usdSkelImaging usdVolImaging + usdAppUtils usdviewq) + add_library(${targetName} INTERFACE) + target_link_libraries(${targetName} INTERFACE usd_ms) + endforeach() +endif() diff --git a/deps/MaterialX b/deps/MaterialX new file mode 160000 index 000000000..8af3920a3 --- /dev/null +++ b/deps/MaterialX @@ -0,0 +1 @@ +Subproject commit 8af3920a34acaa8090afa50c10c2d0789ce90aa3 diff --git a/deps/RIF b/deps/RIF index cfc91b070..32643c48c 160000 --- a/deps/RIF +++ b/deps/RIF @@ -1 +1 @@ -Subproject commit cfc91b0709b96ee300060a94f1efca7bb144f225 +Subproject commit 32643c48c4d3bb21793c135efb5d532fac94fdd2 diff --git a/deps/RPR b/deps/RPR index f67815953..7eeecd58f 160000 --- a/deps/RPR +++ b/deps/RPR @@ -1 +1 @@ -Subproject commit f678159530ca64f9dd90783bd3a83b10ee346fa6 +Subproject commit 7eeecd58fa616b97fd5a783b2c7a8a6c36d0e0d0 diff --git a/pxr/imaging/CMakeLists.txt b/pxr/imaging/CMakeLists.txt new file mode 100644 index 000000000..b76b9f0ae --- /dev/null +++ b/pxr/imaging/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(rprUsd) +add_subdirectory(plugin) diff --git a/pxr/imaging/plugin/CMakeLists.txt b/pxr/imaging/plugin/CMakeLists.txt new file mode 100644 index 000000000..6c787ec1e --- /dev/null +++ b/pxr/imaging/plugin/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(hdRpr) +add_subdirectory(glfRatImage) +add_subdirectory(rprHoudini) diff --git a/pxr/imaging/plugin/glfRatImage/CMakeLists.txt b/pxr/imaging/plugin/glfRatImage/CMakeLists.txt new file mode 100644 index 000000000..03354266b --- /dev/null +++ b/pxr/imaging/plugin/glfRatImage/CMakeLists.txt @@ -0,0 +1,23 @@ +if(NOT TARGET Houdini) + return() +endif() + +set(PXR_PREFIX pxr/imaging) +set(PXR_PACKAGE glfRatImage) + +pxr_plugin(glfRatImage + DISABLE_PRECOMPILED_HEADERS + LIBRARIES + tf + glf + arch + Houdini + + CPPFILES + glfRatImage.cpp + + RESOURCE_FILES + plugInfo.json +) + +GroupSources(glfRatImage) diff --git a/pxr/imaging/plugin/glfRatImage/glfRatImage.cpp b/pxr/imaging/plugin/glfRatImage/glfRatImage.cpp new file mode 100644 index 000000000..73a086707 --- /dev/null +++ b/pxr/imaging/plugin/glfRatImage/glfRatImage.cpp @@ -0,0 +1,336 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/glf/glew.h" +#include "pxr/imaging/glf/image.h" +#include "pxr/imaging/glf/utils.h" + +#include +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class Glf_RatImage : public GlfImage { +public: + typedef GlfImage Base; + + Glf_RatImage(); + ~Glf_RatImage() override = default; + + std::string const& GetFilename() const override { return m_filename; } + int GetWidth() const override { return m_width; } + int GetHeight() const override { return m_height; } + GLenum GetFormat() const override; + GLenum GetType() const override { return m_outputType; } + int GetBytesPerPixel() const override; + int GetNumMipLevels() const override; + + bool IsColorSpaceSRGB() const override; + + bool GetMetadata(TfToken const& key, VtValue * value) const override { /* TODO */ return false; } + bool GetSamplerMetadata(GLenum pname, VtValue * param) const override { /* TODO */ return false; } + + bool Read(StorageSpec const& storage) override; + bool ReadCropped(int const cropTop, + int const cropBottom, + int const cropLeft, + int const cropRight, + StorageSpec const& storage) override; + + bool Write(StorageSpec const& storage, + VtDictionary const& metadata) override { /* TODO */ return false; } + +protected: + bool _OpenForReading(std::string const& filename, int subimage, + int mip, bool suppressErrors) override; + bool _OpenForWriting(std::string const& filename) override { /* TODO */ return false; } + +private: + bool _IsValidCrop(int cropTop, int cropBottom, int cropLeft, int cropRight); + bool _CropAndResize(void const *sourceData, int const cropTop, + int const cropBottom, + int const cropLeft, + int const cropRight, + bool resizeNeeded, + StorageSpec const& storage); + + std::string m_filename; + int m_width; + int m_height; + float m_gamma; + + //GL_UNSIGNED_BYTE, GL_FLOAT + GLenum m_outputType; + + int m_nchannels; +}; + +TF_REGISTRY_FUNCTION(TfType) { + TfType t = TfType::Define>(); + t.SetFactory>(); +} + +/// Returns the bpc (bits per channel) based on the GLType stored in storage +static int +_GetBytesPerChannelFromType(GLenum const& type) { + switch(type) { + case GL_UNSIGNED_BYTE: + return 1; + case GL_FLOAT: + return 4; + default: + TF_CODING_ERROR("Unsupported type"); + return 4; + } +} + +static int +_GetNumElements(GLenum format) { + switch (format) { + case GL_DEPTH_COMPONENT: + case GL_COLOR_INDEX: + case GL_ALPHA: + case GL_LUMINANCE: + case GL_RED: + return 1; + case GL_LUMINANCE_ALPHA: + case GL_RG: + return 2; + case GL_RGB: + return 3; + case GL_RGBA: + return 4; + default: + TF_CODING_ERROR("Unsupported format"); + return 1; + } +} + +bool Glf_RatImage::_IsValidCrop(int cropTop, int cropBottom, int cropLeft, int cropRight) { + int cropImageWidth = m_width - (cropLeft + cropRight); + int cropImageHeight = m_height - (cropTop + cropBottom); + return (cropTop >= 0 && + cropBottom >= 0 && + cropLeft >= 0 && + cropRight >= 0 && + cropImageWidth > 0 && + cropImageHeight > 0); +} + + Glf_RatImage::Glf_RatImage() + : m_width(0) + , m_height(0) + , m_gamma(0.0f) + , m_nchannels(0) { + +} + +GLenum Glf_RatImage::GetFormat() const { + switch (m_nchannels) { + case 1: + return GL_RED; + case 2: + return GL_RG; + case 3: + return GL_RGB; + case 4: + return GL_RGBA; + default: + TF_CODING_ERROR("Unsupported numComponents"); + return 1; + } +} + +int Glf_RatImage::GetBytesPerPixel() const { + return _GetBytesPerChannelFromType(m_outputType) * m_nchannels; +} + +bool Glf_RatImage::IsColorSpaceSRGB() const { + const float gamma_epsilon = 0.1f; + + // If we found gamma in the texture, use it to decide if we are sRGB + bool isSRGB = ( fabs(m_gamma-0.45455f) < gamma_epsilon); + if (isSRGB) { + return true; + } + + bool isLinear = ( fabs(m_gamma-1) < gamma_epsilon); + if (isLinear) { + return false; + } + + if (m_gamma > 0) { + TF_WARN("Unsupported gamma encoding in: %s", m_filename.c_str()); + } + + // Texture had no (recognized) gamma hint, make a reasonable guess + return ((m_nchannels == 3 || m_nchannels == 4) && + GetType() == GL_UNSIGNED_BYTE); +} + +int Glf_RatImage::GetNumMipLevels() const { + return 1; +} + +bool Glf_RatImage::_OpenForReading( + std::string const& filename, int subimage, + int mip, bool suppressErrors) { + if (mip != 0 || subimage != 0) { + /* TODO */ + return false; + } + + m_filename = filename; + + auto imageFile = std::unique_ptr(IMG_File::open(m_filename.c_str())); + if (!imageFile) { + return false; + } + + auto& stat = imageFile->getStat(); + + if (stat.getNumPlanes() < 1) { + return false; + } + auto plane = stat.getPlane(); + + m_width = stat.getXres(); + m_height = stat.getYres(); + if (m_width <= 0 || m_height <= 0) { + return false; + } + + m_nchannels = stat.getComponentCount(); + if (m_nchannels == 0) { + return false; + } + + m_gamma = plane->getColorSpaceGamma(); + + if (plane->getDataType() == IMG_UCHAR) { + m_outputType = GL_UNSIGNED_BYTE; + } else if (plane->getDataType() == IMG_HALF) { + m_outputType = GL_HALF_FLOAT; + } else if (plane->getDataType() == IMG_FLOAT) { + m_outputType = GL_FLOAT; + } else { + return false; + } + + return true; +} + +bool Glf_RatImage::Read(StorageSpec const& storage) { + return ReadCropped(0, 0, 0, 0, storage); +} + +bool Glf_RatImage::ReadCropped( + int const cropTop, + int const cropBottom, + int const cropLeft, + int const cropRight, + StorageSpec const& storage) { + if (cropTop || cropBottom || cropLeft || cropRight) { + // TODO: implement cropping + return false; + } + + std::unique_ptr imageFile(IMG_File::open(m_filename.c_str())); + if (!imageFile) { + return false; + } + + UT_Array rasters; + if (!imageFile->readImages(rasters) || rasters.isEmpty()) { + return false; + } + + // TODO: find out what to do with other images + std::unique_ptr raster(rasters[0]); + if (rasters.size() > 1) { + TF_WARN("Using only first raster from %s", m_filename.c_str()); + for (size_t i = 1; i < rasters.size(); ++i) { + delete rasters[i]; + } + } + + int numChannels; + if (raster->getPacking() == PACK_SINGLE) { + numChannels = 1; + } else if (raster->getPacking() == PACK_DUAL) { + numChannels = 2; + } else if (raster->getPacking() == PACK_RGB) { + numChannels = 3; + } else if (raster->getPacking() == PACK_RGBA) { + numChannels = 4; + } else { + TF_RUNTIME_ERROR("Failed to load image %s: unsupported RAT packing - %u", m_filename.c_str(), raster->getPacking()); + return false; + } + + if (numChannels != _GetNumElements(storage.format)) { + TF_RUNTIME_ERROR("Failed to load image %s: number of channels do not match - expected=%d, got=%d", m_filename.c_str(), m_nchannels, numChannels); + return false; + } + + GLenum format; + int bytesPerChannel; + if (raster->getFormat() == PXL_INT8) { + format = GL_UNSIGNED_BYTE; + bytesPerChannel = 1; + } else if (raster->getFormat() == PXL_FLOAT16) { + format = GL_HALF_FLOAT; + bytesPerChannel = 2; + } else if (raster->getFormat() == PXL_FLOAT32) { + format = GL_FLOAT; + bytesPerChannel = 4; + } else { + TF_RUNTIME_ERROR("Failed to load image %s: unsupported RAT format - %u", m_filename.c_str(), raster->getFormat()); + return false; + } + + if (format != m_outputType) { + TF_RUNTIME_ERROR("Failed to load image %s: format do not match - expected=%#x, got=%#x", m_filename.c_str(), m_outputType, format); + return false; + } + + if (raster->getXres() != storage.width || + raster->getYres() != storage.height) { + TF_RUNTIME_ERROR("Failed to load image %s: resolution do not match - expected=%dx%d, got=%ldx%ld", + m_filename.c_str(), m_width, m_height, raster->getXres(), raster->getYres()); + return false; + } + + auto srcPixels = reinterpret_cast(raster->getPixels()); + auto srcStride = raster->getStride(); + auto dstPixels = reinterpret_cast(storage.data); + auto dstStride = storage.width * numChannels * bytesPerChannel; + for (int y = 0; y < storage.height; ++y) { + int lineIndex = y; + if (!storage.flipped) { + // RAT image is flipped in Y axis so we flip the data when storage requires no flip + lineIndex = storage.height - 1 - y; + } + + auto dstData = dstPixels + dstStride * lineIndex; + auto srcData = srcPixels + srcStride * y; + + std::memcpy(dstData, srcData, dstStride); + } + + return true; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/glfRatImage/plugInfo.json b/pxr/imaging/plugin/glfRatImage/plugInfo.json new file mode 100644 index 000000000..b6cb18572 --- /dev/null +++ b/pxr/imaging/plugin/glfRatImage/plugInfo.json @@ -0,0 +1,20 @@ +{ + "Plugins": [ + { + "Info": { + "Types": { + "Glf_RatImage" : { + "bases": ["GlfImage"], + "imageTypes": ["rat"], + "precedence": 0 + } + } + }, + "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", + "Name": "ratImage", + "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@", + "Root": "@PLUG_INFO_ROOT@", + "Type": "library" + } + ] +} diff --git a/pxr/imaging/plugin/hdRpr/CMakeLists.txt b/pxr/imaging/plugin/hdRpr/CMakeLists.txt index eea3d0ead..a502c826d 100644 --- a/pxr/imaging/plugin/hdRpr/CMakeLists.txt +++ b/pxr/imaging/plugin/hdRpr/CMakeLists.txt @@ -7,65 +7,26 @@ set(OptBin ${ARGN}) set(OptIncludeDir ${ARGN}) set(OptClass${ARGN}) -if(RPR_ENABLE_OPENVDB_SUPPORT) +if(OpenVDB_FOUND) add_definitions(-DUSE_VOLUME -DOPENVDB_DLL) set(OptLibs ${OptLibs} ${OpenVDB_LIBRARIES}) set(OptBin ${OptBin} ${OpenVDB_BINARIES}) set(OptIncludeDir ${OptIncludeDir} ${OpenVDB_INCLUDE_DIR}) set(OptClass ${OptClass} field volume) -endif(RPR_ENABLE_OPENVDB_SUPPORT) - -set(USD_LIBRARIES - ar - arch - sdf - trace - plug - tf - vt - gf - glf - work - hf - hd - hdSt - hdx - usdVol - usdLux - usdUtils - usdRender - usdGeom - usdImaging - pxOsd - cameraUtil) -if(${USD_LIBRARY_MONOLITHIC}) - set(USD_LIBRARIES usd_ms) -endif() - -set(_libPrefix ${PXR_LIB_PREFIX}) -# UNIX compilers adding "lib" prefix implicitly -if(NOT WIN32) - string(REGEX REPLACE "^lib" "" _libPrefix "${PXR_LIB_PREFIX}") -endif() - -set(_prefixedUsdLibraries "") -foreach(name ${USD_LIBRARIES}) - list(APPEND _prefixedUsdLibraries "${_libPrefix}${name}") -endforeach() -set(USD_LIBRARIES "${_prefixedUsdLibraries}") +endif(OpenVDB_FOUND) set(_sep ${PXR_RESOURCE_FILE_SRC_DST_SEPARATOR}) -if(RPR_BUILD_AS_HOUDINI_PLUGIN) +if(HoudiniUSD_FOUND) list(APPEND OptLibs Houdini) - add_definitions(-DENABLE_RAT) + add_definitions(-DBUILD_AS_HOUDINI_PLUGIN) add_definitions(-DHDRPR_DEFAULT_MATERIAL_NETWORK_SELECTOR="karma") set(RESTART_REQUIRED_RESOURCE_FILE images/restartRequired_Houdini.png${_sep}images/restartRequired.png) -else(RPR_BUILD_AS_HOUDINI_PLUGIN) +else(HoudiniUSD_FOUND) add_definitions(-DENABLE_PREFERENCES_FILE) add_definitions(-DHDRPR_DEFAULT_MATERIAL_NETWORK_SELECTOR="rpr") set(RESTART_REQUIRED_RESOURCE_FILE images/restartRequired_Usdview.png${_sep}images/restartRequired.png) -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) +endif(HoudiniUSD_FOUND) set(GEN_SCRIPT_PYTHON ${PYTHON_EXECUTABLE}) set(GENERATION_SCRIPTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/python) @@ -79,7 +40,7 @@ set(GENERATION_DEPENDENT_FILES ${GEN_SCRIPT} ${GENERATION_SCRIPTS_DIR}/generateLightSettingFiles.py ${GENERATION_SCRIPTS_DIR}/generateRenderSettingFiles.py ${GENERATION_SCRIPTS_DIR}/generateGeometrySettingFiles.py) -if(RPR_BUILD_AS_HOUDINI_PLUGIN) +if(HoudiniUSD_FOUND) set(GEN_SCRIPT_PYTHON ${HYTHON_EXECUTABLE}) set(GEN_SCRIPT_ARGS --houdini_root \"${HOUDINI_ROOT}\" ${GEN_SCRIPT_ARGS}) set(GENERATED_FILES ${GENERATED_FILES} @@ -88,6 +49,33 @@ if(RPR_BUILD_AS_HOUDINI_PLUGIN) ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Geometry.ds) set(GENERATION_DEPENDENT_FILES ${GENERATION_DEPENDENT_FILES} ${GENERATION_SCRIPTS_DIR}/houdiniDsGenerator.py) + + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Light.ds + ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Global.ds + ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Geometry.ds + DESTINATION "houdini/soho/parameters") + install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/houdini/rpr_exportRpr1.hda + DESTINATION "houdini/otls") + + install( + CODE + "FILE(WRITE \"${CMAKE_INSTALL_PREFIX}/houdini/dso/usd_plugins/plugInfo.json\" + \"{ + \\\"Includes\\\": [ \\\"../../../plugin/\\\" ] + }\")") +endif() + +if(NOT RPR_NORTHSTAR_BINARY) + set(HIDDEN_RENDER_QUALITIES ${HIDDEN_RENDER_QUALITIES} Northstar) +endif() +if(NOT RPR_HYBRID_BINARY) + set(HIDDEN_RENDER_QUALITIES ${HIDDEN_RENDER_QUALITIES} Low Medium High) +endif() +if(HIDDEN_RENDER_QUALITIES) + set(GEN_SCRIPT_ARGS --hidden-render-qualities "\"${HIDDEN_RENDER_QUALITIES}\"" ${GEN_SCRIPT_ARGS}) endif() add_custom_command( @@ -105,32 +93,31 @@ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/rif_models.version ${RIF_VERSION_STRING}) list(APPEND RIF_MODEL_RESOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/rif_models.version${_sep}rif_models/rif_models.version") -if(NOT DEFINED RPR_CPP_WRAPPER_LOCATION) - set(RPR_CPP_WRAPPER_LOCATION ${RPR_TOOLS_LOCATION}) -endif() - pxr_plugin(hdRpr LIBRARIES - ${USD_LIBRARIES} - ${RPR_LIBRARY} - ${RPR_LOADSTORE_LIBRARY} + ar + trace + plug + tf + gf + hf + ndr + usdVol + usdLux + usdUtils + usdRender + usdGeom + usdImaging + pxOsd + cameraUtil + rprUsd ${RIF_LIBRARY} - ${Boost_LIBRARIES} - ${TBB_tbb_LIBRARY} - ${GLEW_LIBRARY} - ${OPENGL_LIBRARIES} - ${PYTHON_LIBRARIES} ${OPENEXR_LIBRARIES} ${OptLibs} INCLUDE_DIRS - ${RPR_LOCATION_INCLUDE} - ${RPR_CPP_WRAPPER_LOCATION} ${RIF_LOCATION_INCLUDE} - ${Boost_INCLUDE_DIRS} - ${TBB_INCLUDE_DIRS} - ${GLEW_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty ${OPENEXR_INCLUDE_DIRS} @@ -138,6 +125,7 @@ pxr_plugin(hdRpr ${OptIncludeDir} PRIVATE_CLASSES + aovDescriptor rendererPlugin renderDelegate renderPass @@ -149,14 +137,11 @@ pxr_plugin(hdRpr mesh instancer material - materialFactory - materialAdapter domeLight distantLight light renderBuffer basisCurves - imageCache camera debugCodes primvarUtil @@ -175,6 +160,8 @@ pxr_plugin(hdRpr CPPFILES ${CMAKE_CURRENT_BINARY_DIR}/config.cpp + ndrDiscoveryPlugin.cpp + ndrParserPlugin.cpp ) target_sources(hdRpr PRIVATE @@ -190,80 +177,32 @@ else() ${CMAKE_CURRENT_SOURCE_DIR}/notify/message.cpp) endif() -target_compile_definitions(hdRpr PRIVATE - RPR_CPPWRAPER_DISABLE_MUTEXLOCK - RPR_API_USE_HEADER_V2) - -target_sources(hdRpr PRIVATE - ${RPR_CPP_WRAPPER_LOCATION}/RadeonProRender.hpp - ${RPR_CPP_WRAPPER_LOCATION}/RadeonProRenderCpp.cpp) - -add_subdirectory(rpr) add_subdirectory(rifcpp) add_subdirectory(houdini) +if(NOT HoudiniUSD_FOUND) + add_subdirectory(usdviewMenu) +endif() -get_target_property(hdRpr_SOURCES hdRpr SOURCES) -foreach(FILE ${hdRpr_SOURCES}) - get_filename_component(ABS_FILE ${FILE} ABSOLUTE) - file(RELATIVE_PATH relPath ${CMAKE_CURRENT_SOURCE_DIR} ${ABS_FILE}) - - string(FIND "${relPath}" ".." out) - if("${out}" EQUAL 0) - source_group("external" FILES "${FILE}") - else() - get_filename_component(PARENT_DIR "${FILE}" DIRECTORY) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" GROUP "${PARENT_DIR}") - string(REPLACE "/" "\\" GROUP "${GROUP}") - - source_group("${GROUP}" FILES "${FILE}") - endif() -endforeach() - -if(RPR_BUILD_AS_HOUDINI_PLUGIN) - install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Light.ds - ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Global.ds - ${CMAKE_CURRENT_BINARY_DIR}/HdRprPlugin_Geometry.ds - DESTINATION "${HOUDINI_RESOURCE_DIR_RELPATH}/houdini/soho/parameters") - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/houdini/rpr_exportRpr1.hda - DESTINATION "${HOUDINI_RESOURCE_DIR_RELPATH}/houdini/otls") -else(RPR_BUILD_AS_HOUDINI_PLUGIN) - _get_install_dir(lib/python/rpr installPrefix) - - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/python/rpr.py - DESTINATION ${installPrefix} - RENAME "__init__.py") +GroupSources(hdRpr) - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/python/plugInfo.json - DESTINATION ${installPrefix}) - install( - CODE - "FILE(WRITE \"${CMAKE_INSTALL_PREFIX}/plugin/usd/plugInfo.json\" - \" - { - \\\"Includes\\\": [ \\\"*/resources/\\\" ] - } - \")") -endif(RPR_BUILD_AS_HOUDINI_PLUGIN) +install( + CODE + "FILE(WRITE \"${CMAKE_INSTALL_PREFIX}/plugin/plugInfo.json\" + \"{ + \\\"Includes\\\": [ \\\"usd/*/resources/\\\" ] +}\")") if(WIN32) + set(RPR_BINARIES + ${RPR_BIN_LOCATION}/RadeonProRender64.dll + ${RPR_BIN_LOCATION}/RprLoadStore64.dll) install( - FILES ${RPR_BINARIES} ${RIF_BINARIES} ${OptBin} - DESTINATION bin) + FILES ${RPR_BINARIES} ${RPR_PLUGINS} ${RIF_BINARIES} ${OptBin} + DESTINATION lib) else(WIN32) - if(RPR_BUILD_AS_HOUDINI_PLUGIN) - _get_install_dir("${HOUDINI_PLUGIN_INSTALL_RELPATH}" installPrefix) - else() - _get_install_dir("lib" installPrefix) - endif() - # install() does not follow symlinks, so we do it manually set(RESOLVED_LIBRARIES "") - foreach (file ${RPR_LIBRARY} ${RPR_LOADSTORE_LIBRARY} ${RPR_PLUGIN_LIBRARIES} ${RIF_LIBRARY} ${RIF_DEPENDENCY_LIBRARIES}) + foreach (file ${RPR_LIBRARY} ${RPR_LOADSTORE_LIBRARY} ${RPR_PLUGINS} ${RIF_LIBRARY} ${RIF_DEPENDENCY_LIBRARIES}) while(IS_SYMLINK ${file}) file(READ_SYMLINK ${file} symfile) if(NOT IS_ABSOLUTE "${symfile}") @@ -278,7 +217,7 @@ else(WIN32) install( FILES ${RESOLVED_LIBRARIES} - DESTINATION ${installPrefix}) + DESTINATION lib) endif(WIN32) add_subdirectory(package) diff --git a/pxr/imaging/plugin/hdRpr/aovDescriptor.cpp b/pxr/imaging/plugin/hdRpr/aovDescriptor.cpp new file mode 100644 index 000000000..b5c6d5d74 --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/aovDescriptor.cpp @@ -0,0 +1,146 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "aovDescriptor.h" + +#include "pxr/base/tf/instantiateSingleton.h" + +#include "pxr/imaging/hd/tokens.h" + +PXR_NAMESPACE_OPEN_SCOPE + +const HdRprAovDescriptor kInvalidDesc; + +TF_INSTANTIATE_SINGLETON(HdRprAovRegistry); +TF_DEFINE_PUBLIC_TOKENS(HdRprAovTokens, HDRPR_AOV_TOKENS); + +HdRprAovRegistry::HdRprAovRegistry() { + const auto rprAovMax = RPR_AOV_COLOR_RIGHT + 1; + const GfVec4f idClearValue(255.0f, 255.0f, 255.0f, 0.0f); + + m_aovDescriptors.resize(rprAovMax); + m_aovDescriptors[RPR_AOV_COLOR] = HdRprAovDescriptor(RPR_AOV_COLOR); + m_aovDescriptors[RPR_AOV_DIFFUSE_ALBEDO] = HdRprAovDescriptor(RPR_AOV_DIFFUSE_ALBEDO); // XXX: RPR's albedo can be noisy in some cases, so we left it as multisampled + m_aovDescriptors[RPR_AOV_VARIANCE] = HdRprAovDescriptor(RPR_AOV_VARIANCE); + m_aovDescriptors[RPR_AOV_OPACITY] = HdRprAovDescriptor(RPR_AOV_OPACITY); + m_aovDescriptors[RPR_AOV_EMISSION] = HdRprAovDescriptor(RPR_AOV_EMISSION); + m_aovDescriptors[RPR_AOV_DIRECT_ILLUMINATION] = HdRprAovDescriptor(RPR_AOV_DIRECT_ILLUMINATION); + m_aovDescriptors[RPR_AOV_INDIRECT_ILLUMINATION] = HdRprAovDescriptor(RPR_AOV_INDIRECT_ILLUMINATION); + m_aovDescriptors[RPR_AOV_AO] = HdRprAovDescriptor(RPR_AOV_AO); + m_aovDescriptors[RPR_AOV_DIRECT_DIFFUSE] = HdRprAovDescriptor(RPR_AOV_DIRECT_DIFFUSE); + m_aovDescriptors[RPR_AOV_DIRECT_REFLECT] = HdRprAovDescriptor(RPR_AOV_DIRECT_REFLECT); + m_aovDescriptors[RPR_AOV_INDIRECT_DIFFUSE] = HdRprAovDescriptor(RPR_AOV_INDIRECT_DIFFUSE); + m_aovDescriptors[RPR_AOV_INDIRECT_REFLECT] = HdRprAovDescriptor(RPR_AOV_INDIRECT_REFLECT); + m_aovDescriptors[RPR_AOV_REFRACT] = HdRprAovDescriptor(RPR_AOV_REFRACT); + m_aovDescriptors[RPR_AOV_VOLUME] = HdRprAovDescriptor(RPR_AOV_VOLUME); + m_aovDescriptors[RPR_AOV_LIGHT_GROUP0] = HdRprAovDescriptor(RPR_AOV_LIGHT_GROUP0); + m_aovDescriptors[RPR_AOV_LIGHT_GROUP1] = HdRprAovDescriptor(RPR_AOV_LIGHT_GROUP1); + m_aovDescriptors[RPR_AOV_LIGHT_GROUP2] = HdRprAovDescriptor(RPR_AOV_LIGHT_GROUP2); + m_aovDescriptors[RPR_AOV_LIGHT_GROUP3] = HdRprAovDescriptor(RPR_AOV_LIGHT_GROUP3); + m_aovDescriptors[RPR_AOV_COLOR_RIGHT] = HdRprAovDescriptor(RPR_AOV_COLOR_RIGHT); + m_aovDescriptors[RPR_AOV_SHADOW_CATCHER] = HdRprAovDescriptor(RPR_AOV_SHADOW_CATCHER); + m_aovDescriptors[RPR_AOV_REFLECTION_CATCHER] = HdRprAovDescriptor(RPR_AOV_REFLECTION_CATCHER); + + m_aovDescriptors[RPR_AOV_DEPTH] = HdRprAovDescriptor(RPR_AOV_DEPTH, false, HdFormatFloat32, GfVec4f(std::numeric_limits::infinity())); + m_aovDescriptors[RPR_AOV_UV] = HdRprAovDescriptor(RPR_AOV_UV, false, HdFormatFloat32Vec3); + m_aovDescriptors[RPR_AOV_SHADING_NORMAL] = HdRprAovDescriptor(RPR_AOV_SHADING_NORMAL, false, HdFormatFloat32Vec3); + m_aovDescriptors[RPR_AOV_GEOMETRIC_NORMAL] = HdRprAovDescriptor(RPR_AOV_GEOMETRIC_NORMAL, false); + m_aovDescriptors[RPR_AOV_OBJECT_ID] = HdRprAovDescriptor(RPR_AOV_OBJECT_ID, false, HdFormatInt32, idClearValue); + m_aovDescriptors[RPR_AOV_MATERIAL_IDX] = HdRprAovDescriptor(RPR_AOV_MATERIAL_IDX, false, HdFormatInt32, idClearValue); + m_aovDescriptors[RPR_AOV_OBJECT_GROUP_ID] = HdRprAovDescriptor(RPR_AOV_OBJECT_GROUP_ID, false, HdFormatInt32, idClearValue); + m_aovDescriptors[RPR_AOV_WORLD_COORDINATE] = HdRprAovDescriptor(RPR_AOV_WORLD_COORDINATE, false); + m_aovDescriptors[RPR_AOV_BACKGROUND] = HdRprAovDescriptor(RPR_AOV_BACKGROUND, false); + m_aovDescriptors[RPR_AOV_VELOCITY] = HdRprAovDescriptor(RPR_AOV_VELOCITY, false); + m_aovDescriptors[RPR_AOV_VIEW_SHADING_NORMAL] = HdRprAovDescriptor(RPR_AOV_VIEW_SHADING_NORMAL, false); + + m_computedAovDescriptors.resize(kComputedAovsCount); + m_computedAovDescriptors[kNdcDepth] = HdRprAovDescriptor(kNdcDepth, false, HdFormatFloat32, GfVec4f(std::numeric_limits::infinity()), true); + m_computedAovDescriptors[kColorAlpha] = HdRprAovDescriptor(kColorAlpha, true, HdFormatFloat32Vec4, GfVec4f(0.0f), true); + + auto addAovNameLookup = [this](TfToken const& name, HdRprAovDescriptor const& descriptor) { + auto status = m_aovNameLookup.emplace(name, AovNameLookupValue(descriptor.id, descriptor.computed)); + if (!status.second) { + TF_CODING_ERROR("AOV lookup name should be unique"); + } + }; + + addAovNameLookup(HdAovTokens->color, m_computedAovDescriptors[kColorAlpha]); + addAovNameLookup(HdAovTokens->normal, m_aovDescriptors[RPR_AOV_SHADING_NORMAL]); + addAovNameLookup(HdAovTokens->primId, m_aovDescriptors[RPR_AOV_OBJECT_ID]); + addAovNameLookup(HdAovTokens->Neye, m_aovDescriptors[RPR_AOV_VIEW_SHADING_NORMAL]); + addAovNameLookup(HdAovTokens->depth, m_computedAovDescriptors[kNdcDepth]); + addAovNameLookup(HdRprGetCameraDepthAovName(), m_aovDescriptors[RPR_AOV_DEPTH]); + + addAovNameLookup(HdRprAovTokens->rawColor, m_aovDescriptors[RPR_AOV_COLOR]); + addAovNameLookup(HdRprAovTokens->albedo, m_aovDescriptors[RPR_AOV_DIFFUSE_ALBEDO]); + addAovNameLookup(HdRprAovTokens->variance, m_aovDescriptors[RPR_AOV_VARIANCE]); + addAovNameLookup(HdRprAovTokens->opacity, m_aovDescriptors[RPR_AOV_OPACITY]); + addAovNameLookup(HdRprAovTokens->emission, m_aovDescriptors[RPR_AOV_EMISSION]); + addAovNameLookup(HdRprAovTokens->directIllumination, m_aovDescriptors[RPR_AOV_DIRECT_ILLUMINATION]); + addAovNameLookup(HdRprAovTokens->indirectIllumination, m_aovDescriptors[RPR_AOV_INDIRECT_ILLUMINATION]); + addAovNameLookup(HdRprAovTokens->ao, m_aovDescriptors[RPR_AOV_AO]); + addAovNameLookup(HdRprAovTokens->directDiffuse, m_aovDescriptors[RPR_AOV_DIRECT_DIFFUSE]); + addAovNameLookup(HdRprAovTokens->directReflect, m_aovDescriptors[RPR_AOV_DIRECT_REFLECT]); + addAovNameLookup(HdRprAovTokens->indirectDiffuse, m_aovDescriptors[RPR_AOV_INDIRECT_DIFFUSE]); + addAovNameLookup(HdRprAovTokens->indirectReflect, m_aovDescriptors[RPR_AOV_INDIRECT_REFLECT]); + addAovNameLookup(HdRprAovTokens->refract, m_aovDescriptors[RPR_AOV_REFRACT]); + addAovNameLookup(HdRprAovTokens->volume, m_aovDescriptors[RPR_AOV_VOLUME]); + addAovNameLookup(HdRprAovTokens->lightGroup0, m_aovDescriptors[RPR_AOV_LIGHT_GROUP0]); + addAovNameLookup(HdRprAovTokens->lightGroup1, m_aovDescriptors[RPR_AOV_LIGHT_GROUP1]); + addAovNameLookup(HdRprAovTokens->lightGroup2, m_aovDescriptors[RPR_AOV_LIGHT_GROUP2]); + addAovNameLookup(HdRprAovTokens->lightGroup3, m_aovDescriptors[RPR_AOV_LIGHT_GROUP3]); + addAovNameLookup(HdRprAovTokens->colorRight, m_aovDescriptors[RPR_AOV_COLOR_RIGHT]); + addAovNameLookup(HdRprAovTokens->materialIdx, m_aovDescriptors[RPR_AOV_MATERIAL_IDX]); + addAovNameLookup(HdRprAovTokens->objectGroupId, m_aovDescriptors[RPR_AOV_OBJECT_GROUP_ID]); + addAovNameLookup(HdRprAovTokens->geometricNormal, m_aovDescriptors[RPR_AOV_GEOMETRIC_NORMAL]); + addAovNameLookup(HdRprAovTokens->worldCoordinate, m_aovDescriptors[RPR_AOV_WORLD_COORDINATE]); + addAovNameLookup(HdRprAovTokens->primvarsSt, m_aovDescriptors[RPR_AOV_UV]); + addAovNameLookup(HdRprAovTokens->shadowCatcher, m_aovDescriptors[RPR_AOV_SHADOW_CATCHER]); + addAovNameLookup(HdRprAovTokens->reflectionCatcher, m_aovDescriptors[RPR_AOV_REFLECTION_CATCHER]); + addAovNameLookup(HdRprAovTokens->background, m_aovDescriptors[RPR_AOV_BACKGROUND]); + addAovNameLookup(HdRprAovTokens->velocity, m_aovDescriptors[RPR_AOV_VELOCITY]); + addAovNameLookup(HdRprAovTokens->viewShadingNormal, m_aovDescriptors[RPR_AOV_VIEW_SHADING_NORMAL]); +} + +HdRprAovDescriptor const& HdRprAovRegistry::GetAovDesc(TfToken const& name) { + auto it = m_aovNameLookup.find(name); + if (it == m_aovNameLookup.end()) { + return kInvalidDesc; + } + + return GetAovDesc(it->second.id, it->second.isComputed); +} + +HdRprAovDescriptor const& HdRprAovRegistry::GetAovDesc(uint32_t id, bool computed) { + size_t descsSize = computed ? m_computedAovDescriptors.size() : m_aovDescriptors.size(); + if (id < 0 || id >= descsSize) { + TF_RUNTIME_ERROR("Invalid arguments: %#x (computed=%d)", id, int(computed)); + return kInvalidDesc; + } + + if (computed) { + return m_computedAovDescriptors[id]; + } else { + return m_aovDescriptors[id]; + } +} + +TfToken const& HdRprGetCameraDepthAovName() { +#if PXR_VERSION < 2002 + return HdAovTokens->linearDepth; +#else + return HdAovTokens->cameraDepth; +#endif +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/aovDescriptor.h b/pxr/imaging/plugin/hdRpr/aovDescriptor.h new file mode 100644 index 000000000..80894835a --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/aovDescriptor.h @@ -0,0 +1,123 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef HDRPR_AOV_DESCRIPTOR_H +#define HDRPR_AOV_DESCRIPTOR_H + +#include "pxr/base/tf/singleton.h" +#include "pxr/base/tf/staticTokens.h" +#include "pxr/base/gf/vec4f.h" + +#include "pxr/imaging/hd/types.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +#define HDRPR_AOV_TOKENS \ + (rawColor) \ + (albedo) \ + (variance) \ + (worldCoordinate) \ + (opacity) \ + ((primvarsSt, "primvars:st")) \ + (materialIdx) \ + (geometricNormal) \ + (objectGroupId) \ + (shadowCatcher) \ + (background) \ + (emission) \ + (velocity) \ + (directIllumination) \ + (indirectIllumination) \ + (ao) \ + (directDiffuse) \ + (directReflect) \ + (indirectDiffuse) \ + (indirectReflect) \ + (refract) \ + (volume) \ + (lightGroup0) \ + (lightGroup1) \ + (lightGroup2) \ + (lightGroup3) \ + (viewShadingNormal) \ + (reflectionCatcher) \ + (colorRight) + +TF_DECLARE_PUBLIC_TOKENS(HdRprAovTokens, HDRPR_AOV_TOKENS); + +const rpr::Aov kAovNone = static_cast(-1); + +enum ComputedAovs { + kNdcDepth = 0, + kColorAlpha, + kComputedAovsCount +}; + +struct HdRprAovDescriptor { + uint32_t id; + HdFormat format; + bool multiSampled; + bool computed; + GfVec4f clearValue; + + HdRprAovDescriptor(uint32_t id = kAovNone, bool multiSampled = true, HdFormat format = HdFormatFloat32Vec4, GfVec4f clearValue = GfVec4f(0.0f), bool computed = false) + : id(id), format(format), multiSampled(multiSampled), computed(computed), clearValue(clearValue) { + + } +}; + +class HdRprAovRegistry { +public: + static HdRprAovRegistry& GetInstance() { + return TfSingleton::GetInstance(); + } + + HdRprAovDescriptor const& GetAovDesc(TfToken const& name); + HdRprAovDescriptor const& GetAovDesc(uint32_t id, bool computed); + + HdRprAovRegistry(HdRprAovRegistry const&) = delete; + HdRprAovRegistry& operator=(HdRprAovRegistry const&) = delete; + HdRprAovRegistry(HdRprAovRegistry&&) = delete; + HdRprAovRegistry& operator=(HdRprAovRegistry&&) = delete; + +private: + HdRprAovRegistry(); + ~HdRprAovRegistry() = default; + + friend class TfSingleton; + +private: + struct AovNameLookupValue { + uint32_t id; + bool isComputed; + + AovNameLookupValue(uint32_t id, bool isComputed = false) + : id(id), isComputed(isComputed) { + + } + }; + std::map m_aovNameLookup; + + std::vector m_aovDescriptors; + std::vector m_computedAovDescriptors; +}; + +TfToken const& HdRprGetCameraDepthAovName(); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // HDRPR_AOV_DESCRIPTOR_H diff --git a/pxr/imaging/plugin/hdRpr/basisCurves.cpp b/pxr/imaging/plugin/hdRpr/basisCurves.cpp index da9643615..f5a208f1c 100644 --- a/pxr/imaging/plugin/hdRpr/basisCurves.cpp +++ b/pxr/imaging/plugin/hdRpr/basisCurves.cpp @@ -12,13 +12,12 @@ limitations under the License. ************************************************************************/ #include "basisCurves.h" -#include "materialAdapter.h" #include "material.h" #include "renderParam.h" #include "primvarUtil.h" #include "rprApi.h" -#include "pxr/usd/usdUtils/pipeline.h" +#include "pxr/imaging/rprUsd/material.h" PXR_NAMESPACE_OPEN_SCOPE @@ -94,12 +93,24 @@ void HdRprBasisCurves::Sync(HdSceneDelegate* sceneDelegate, newCurve = true; } + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + m_cachedMaterial = static_cast(sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, sceneDelegate->GetMaterialId(id))); + } + bool isVisibilityMaskDirty = false; if (*dirtyBits & HdChangeTracker::DirtyPrimvar) { HdRprFillPrimvarDescsPerInterpolation(sceneDelegate, id, &primvarDescsPerInterpolation); - auto stToken = UsdUtilsGetPrimaryUVSetName(); - if (HdRprIsPrimvarExists(stToken, primvarDescsPerInterpolation, &m_uvsInterpolation)) { - m_uvs = sceneDelegate->Get(id, stToken).Get(); + + static TfToken st("st", TfToken::Immortal); + TfToken const* uvPrimvarName = &st; + if (m_cachedMaterial) { + if (auto rprMaterial = m_cachedMaterial->GetRprMaterialObject()) { + uvPrimvarName = &rprMaterial->GetUvPrimvarName(); + } + } + + if (HdRprIsPrimvarExists(*uvPrimvarName, primvarDescsPerInterpolation, &m_uvsInterpolation)) { + m_uvs = sceneDelegate->Get(id, *uvPrimvarName).Get(); } else { m_uvs = VtVec2fArray(); } @@ -120,10 +131,6 @@ void HdRprBasisCurves::Sync(HdSceneDelegate* sceneDelegate, newCurve = true; } - if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { - m_cachedMaterial = static_cast(sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, sceneDelegate->GetMaterialId(id))); - } - if (*dirtyBits & HdChangeTracker::DirtyVisibility) { _sharedData.visible = sceneDelegate->GetVisible(id); } @@ -191,9 +198,7 @@ void HdRprBasisCurves::Sync(HdSceneDelegate* sceneDelegate, } } - MaterialAdapter matAdapter(EMaterialType::COLOR, MaterialParams{{HdRprMaterialTokens->color, VtValue(color)}}); - m_fallbackMaterial = rprApi->CreateMaterial(matAdapter); - + m_fallbackMaterial = rprApi->CreateDiffuseMaterial(color); rprApi->SetCurveMaterial(m_rprCurve, m_fallbackMaterial); } } @@ -259,6 +264,10 @@ rpr::Curve* HdRprBasisCurves::CreateLinearRprCurve(HdRprApi* rprApi) { auto& curveCounts = m_topology.GetCurveVertexCounts(); rprSegmentPerCurve.reserve(curveCounts.size()); + // Validate Hydra curve data and calculate amount of required memory. + // + size_t numRadiuses = 0; + size_t numIndices = 0; int curveSegmentOffset = 0; int curveIndicesOffset = 0; for (size_t iCurve = 0; iCurve < curveCounts.size(); ++iCurve) { @@ -281,12 +290,41 @@ rpr::Curve* HdRprBasisCurves::CreateLinearRprCurve(HdRprApi* rprApi) { return nullptr; } - int numNewRprIndices = numSegments * kNumPointsPerSegment; if (isCurveTapered) { - rprRadiuses.reserve(rprRadiuses.size() + numNewRprIndices); - numNewRprIndices *= 2; + numRadiuses += numSegments * 2; + numIndices += numSegments * 4; + } else { + if (m_widthsInterpolation == HdInterpolationUniform || + m_widthsInterpolation == HdInterpolationConstant) { + ++numRadiuses; + } + numIndices += numSegments * 2; + + // RPR requires curves to consist only of segments of kRprNumPointsPerSegment length + auto numPointsInCurve = (numVertices - 1) * 2; + auto numTrailingPoints = numPointsInCurve % kRprNumPointsPerSegment; + if (numTrailingPoints > 0) { + numIndices += kRprNumPointsPerSegment - numTrailingPoints; + } + } + + curveSegmentOffset += numSegments; + curveIndicesOffset += numVertices; + } + rprRadiuses.reserve(numRadiuses); + rprIndices.reserve(numIndices); + + // Convert Hydra curve data to RPR data. + // + curveIndicesOffset = 0; + for (size_t iCurve = 0; iCurve < curveCounts.size(); ++iCurve) { + auto numVertices = curveCounts[iCurve]; + if (numVertices < 2) { + continue; } - rprIndices.reserve(rprIndices.size() + numNewRprIndices); + + int numSegments = (numVertices - (kNumPointsPerSegment - kVstep)) / kVstep; + if (periodic) numSegments++; if (isCurveTapered) { rprSegmentPerCurve.push_back(numVertices - 1); @@ -336,7 +374,6 @@ rpr::Curve* HdRprBasisCurves::CreateLinearRprCurve(HdRprApi* rprApi) { rprSegmentPerCurve.push_back((numPointsInCurve + extraPoints) / kRprNumPointsPerSegment); } - curveSegmentOffset += numSegments; curveIndicesOffset += numVertices; } @@ -391,6 +428,10 @@ rpr::Curve* HdRprBasisCurves::CreateBezierRprCurve(HdRprApi* rprApi) { indexSampler = [this](int idx) { return m_indices.cdata()[idx]; }; } + // Validate Hydra curve data and calculate amount of required memory. + // + size_t numRadiuses = 0; + size_t numIndices = 0; int curveSegmentOffset = 0; int curveIndicesOffset = 0; for (size_t iCurve = 0; iCurve < curveCounts.size(); ++iCurve) { @@ -406,7 +447,6 @@ rpr::Curve* HdRprBasisCurves::CreateBezierRprCurve(HdRprApi* rprApi) { return nullptr; } - int numSegments = (numVertices - (kNumPointsPerSegment - kVstep)) / kVstep; if (periodic) numSegments++; @@ -416,11 +456,34 @@ rpr::Curve* HdRprBasisCurves::CreateBezierRprCurve(HdRprApi* rprApi) { return nullptr; } - rprIndices.reserve(rprIndices.size() + numSegments * kNumPointsPerSegment); + numIndices += numSegments * kNumPointsPerSegment; if (isCurveTapered) { - rprRadiuses.reserve(rprRadiuses.size() + numSegments * 2); + numRadiuses += numSegments * 2; + } else { + if (m_widthsInterpolation == HdInterpolationUniform || + m_widthsInterpolation == HdInterpolationConstant) { + numRadiuses++; + } } + curveSegmentOffset += numSegments; + curveIndicesOffset += numVertices; + } + rprRadiuses.reserve(numRadiuses); + rprIndices.reserve(numIndices); + + // Convert Hydra curve data to RPR data. + // + curveIndicesOffset = 0; + for (size_t iCurve = 0; iCurve < curveCounts.size(); ++iCurve) { + auto numVertices = curveCounts[iCurve]; + if (numVertices < kNumPointsPerSegment) { + continue; + } + + int numSegments = (numVertices - (kNumPointsPerSegment - kVstep)) / kVstep; + if (periodic) numSegments++; + rprSegmentPerCurve.push_back(numSegments); for (int iSegment = 0; iSegment < numSegments; ++iSegment) { @@ -452,7 +515,6 @@ rpr::Curve* HdRprBasisCurves::CreateBezierRprCurve(HdRprApi* rprApi) { } } - curveSegmentOffset += numSegments; curveIndicesOffset += numVertices; } diff --git a/pxr/imaging/plugin/hdRpr/basisCurves.h b/pxr/imaging/plugin/hdRpr/basisCurves.h index 8f82c6ef1..38adee45f 100644 --- a/pxr/imaging/plugin/hdRpr/basisCurves.h +++ b/pxr/imaging/plugin/hdRpr/basisCurves.h @@ -23,7 +23,7 @@ namespace rpr { class Curve; } PXR_NAMESPACE_OPEN_SCOPE class HdRprApi; -struct HdRprApiMaterial; +class RprUsdMaterial; class HdRprMaterial; @@ -56,7 +56,7 @@ class HdRprBasisCurves : public HdBasisCurves { private: rpr::Curve* m_rprCurve = nullptr; - HdRprApiMaterial* m_fallbackMaterial = nullptr; + RprUsdMaterial* m_fallbackMaterial = nullptr; HdRprMaterial const* m_cachedMaterial; diff --git a/pxr/imaging/plugin/hdRpr/camera.cpp b/pxr/imaging/plugin/hdRpr/camera.cpp index 3082b273c..d5415d8ff 100644 --- a/pxr/imaging/plugin/hdRpr/camera.cpp +++ b/pxr/imaging/plugin/hdRpr/camera.cpp @@ -18,6 +18,10 @@ limitations under the License. PXR_NAMESPACE_OPEN_SCOPE +TF_DEFINE_PRIVATE_TOKENS(HdRprCameraTokens, + (apertureBlades) +); + namespace { template @@ -60,6 +64,7 @@ HdRprCamera::HdRprCamera(SdfPath const& id) m_focalLength(std::numeric_limits::quiet_NaN()), m_fStop(std::numeric_limits::quiet_NaN()), m_focusDistance(std::numeric_limits::quiet_NaN()), + m_apertureBlades(0), m_shutterOpen(std::numeric_limits::quiet_NaN()), m_shutterClose(std::numeric_limits::quiet_NaN()), m_clippingRange(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()) { @@ -95,6 +100,8 @@ void HdRprCamera::Sync(HdSceneDelegate* sceneDelegate, EvalCameraParam(&m_clippingRange, HdCameraTokens->clippingRange, sceneDelegate, id, GfRange1f(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN())); EvalCameraParam(&m_projectionType, UsdGeomTokens->projection, sceneDelegate, id, TfToken()); + + EvalCameraParam(&m_apertureBlades, HdRprCameraTokens->apertureBlades, sceneDelegate, id, 16); } if (*dirtyBits & HdCamera::DirtyViewMatrix) { diff --git a/pxr/imaging/plugin/hdRpr/camera.h b/pxr/imaging/plugin/hdRpr/camera.h index d06ffbd6f..db498d74f 100644 --- a/pxr/imaging/plugin/hdRpr/camera.h +++ b/pxr/imaging/plugin/hdRpr/camera.h @@ -45,6 +45,7 @@ class HdRprCamera : public HdCamera { bool GetClippingRange(GfRange1f* value) const; bool GetProjectionType(TfToken* value) const; HdTimeSampleArray const& GetTransformSamples() const { return m_transform; } + int GetApertureBlades() const { return m_apertureBlades; } HdDirtyBits GetDirtyBits() const { return m_rprDirtyBits; } void CleanDirtyBits() const { m_rprDirtyBits = HdCamera::Clean; } @@ -57,6 +58,7 @@ class HdRprCamera : public HdCamera { float m_focalLength; float m_fStop; float m_focusDistance; + int m_apertureBlades; double m_shutterOpen; double m_shutterClose; GfRange1f m_clippingRange; diff --git a/pxr/imaging/plugin/hdRpr/distantLight.cpp b/pxr/imaging/plugin/hdRpr/distantLight.cpp index 86460da2e..4e4070723 100644 --- a/pxr/imaging/plugin/hdRpr/distantLight.cpp +++ b/pxr/imaging/plugin/hdRpr/distantLight.cpp @@ -61,7 +61,6 @@ void HdRprDistantLight::Sync(HdSceneDelegate* sceneDelegate, *dirtyBits = HdLight::Clean; return; } - rprRenderParam->AddLight(); } float angle = sceneDelegate->GetLightParamValue(id, UsdLuxTokens->angle).Get(); @@ -88,8 +87,6 @@ void HdRprDistantLight::Finalize(HdRenderParam* renderParam) { auto rprRenderParam = static_cast(renderParam); rprRenderParam->AcquireRprApiForEdit()->Release(m_rprLight); m_rprLight = nullptr; - - rprRenderParam->RemoveLight(); } HdSprim::Finalize(renderParam); diff --git a/pxr/imaging/plugin/hdRpr/domeLight.cpp b/pxr/imaging/plugin/hdRpr/domeLight.cpp index 1e788fe29..c1fc8cd78 100644 --- a/pxr/imaging/plugin/hdRpr/domeLight.cpp +++ b/pxr/imaging/plugin/hdRpr/domeLight.cpp @@ -63,7 +63,20 @@ void HdRprDomeLight::Sync(HdSceneDelegate* sceneDelegate, bool newLight = false; if (bits & HdLight::DirtyParams) { - m_rprLight = nullptr; + if (m_rprLight) { + rprApi->Release(m_rprLight); + m_rprLight = nullptr; + } + + bool isVisible = sceneDelegate->GetVisible(id); + if (!isVisible) { + // Invisible light does not produces any emission on a scene. + // So we simply keep light primitive empty in that case. + // We can do it in such a way because Hydra releases light object + // whenever it changed and creates it from scratch + *dirtyBits = HdLight::Clean; + return; + } float intensity = sceneDelegate->GetLightParamValue(id, HdLightTokens->intensity).Get(); float exposure = sceneDelegate->GetLightParamValue(id, HdLightTokens->exposure).Get(); @@ -108,11 +121,6 @@ void HdRprDomeLight::Sync(HdSceneDelegate* sceneDelegate, rprApi->SetTransform(m_rprLight, m_transform); } - if (newLight && !m_created) { - m_created = true; - rprRenderParam->AddLight(); - } - *dirtyBits = HdLight::Clean; } @@ -128,11 +136,6 @@ void HdRprDomeLight::Finalize(HdRenderParam* renderParam) { m_rprLight = nullptr; } - if (m_created) { - rprRenderParam->RemoveLight(); - m_created = false; - } - HdSprim::Finalize(renderParam); } diff --git a/pxr/imaging/plugin/hdRpr/domeLight.h b/pxr/imaging/plugin/hdRpr/domeLight.h index 4398ced5e..1218b8937 100644 --- a/pxr/imaging/plugin/hdRpr/domeLight.h +++ b/pxr/imaging/plugin/hdRpr/domeLight.h @@ -42,7 +42,6 @@ class HdRprDomeLight : public HdSprim { protected: HdRprApiEnvironmentLight* m_rprLight = nullptr; GfMatrix4f m_transform; - bool m_created = false; }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/houdini/CMakeLists.txt b/pxr/imaging/plugin/hdRpr/houdini/CMakeLists.txt index 4022a3f00..be4c23dab 100644 --- a/pxr/imaging/plugin/hdRpr/houdini/CMakeLists.txt +++ b/pxr/imaging/plugin/hdRpr/houdini/CMakeLists.txt @@ -1,4 +1,4 @@ -if(RPR_ENABLE_OPENVDB_SUPPORT) +if(OpenVDB_FOUND) set(HOUDINI_OPENVDB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/openvdb.h ${CMAKE_CURRENT_SOURCE_DIR}/openvdb.cpp) diff --git a/pxr/imaging/plugin/hdRpr/imageCache.cpp b/pxr/imaging/plugin/hdRpr/imageCache.cpp deleted file mode 100644 index 1d7057a82..000000000 --- a/pxr/imaging/plugin/hdRpr/imageCache.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#include "imageCache.h" -#include "rpr/helpers.h" -#include "rpr/imageHelpers.h" - -#include "pxr/base/arch/fileSystem.h" - -PXR_NAMESPACE_OPEN_SCOPE - -ImageCache::ImageCache(rpr::Context* context) - : m_context(context) { - -} - -std::shared_ptr ImageCache::GetImage(std::string const& path, bool forceLinearSpace) { - ImageMetadata md(path); - - auto cacheKey = path; - - static const char* kForceLinearSpaceCacheKeySuffix = "?l"; - if (forceLinearSpace) { - cacheKey += kForceLinearSpaceCacheKeySuffix; - } - - auto it = m_cache.find(cacheKey); - if (it != m_cache.end() && it->second.IsMetadataEqual(md)) { - if (auto image = it->second.handle.lock()) { - return image; - } - } - - auto image = std::shared_ptr(rpr::CreateImage(m_context, path.c_str(), forceLinearSpace)); - if (image) { - md.handle = image; - m_cache.emplace(cacheKey, md); - - auto gammaFromFile = rpr::GetInfo(image.get(), RPR_IMAGE_GAMMA_FROM_FILE); - if (std::abs(gammaFromFile - 1.0f) < 0.01f) { - // Image is in linear space, we can cache the same image for both variants of forceLinearSpace - if (forceLinearSpace) { - m_cache.emplace(path, md); - } else { - m_cache.emplace(path + kForceLinearSpaceCacheKeySuffix, md); - } - } - } - return image; -} - -void ImageCache::RequireGarbageCollection() { - m_garbageCollectionRequired = true; -} - -void ImageCache::GarbageCollectIfNeeded() { - if (!m_garbageCollectionRequired) { - return; - } - - auto it = m_cache.begin(); - while (it != m_cache.end()) { - if (it->second.handle.expired()) { - it = m_cache.erase(it); - } else { - ++it; - } - } - - m_garbageCollectionRequired = false; -} - -ImageCache::ImageMetadata::ImageMetadata(std::string const& path) { - double time; - if (!ArchGetModificationTime(path.c_str(), &time)) { - return; - } - - int64_t size = ArchGetFileLength(path.c_str()); - if (size == -1) { - return; - } - - m_modificationTime = time; - m_size = static_cast(size); -} - -bool ImageCache::ImageMetadata::IsMetadataEqual(ImageMetadata const& md) { - return m_modificationTime == md.m_modificationTime && - m_size == md.m_size; -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/imageCache.h b/pxr/imaging/plugin/hdRpr/imageCache.h deleted file mode 100644 index d6ca96715..000000000 --- a/pxr/imaging/plugin/hdRpr/imageCache.h +++ /dev/null @@ -1,67 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#ifndef HDRPR_IMAGE_CACHE_H -#define HDRPR_IMAGE_CACHE_H - -#include "pxr/pxr.h" - -#include -#include -#include - -namespace rpr { - -class Context; -class Image; - -} // namespace rpr - -PXR_NAMESPACE_OPEN_SCOPE - -class ImageCache { -public: - ImageCache(rpr::Context* context); - - std::shared_ptr GetImage(std::string const& path, bool forceLinearSpace = false); - - void RequireGarbageCollection(); - void GarbageCollectIfNeeded(); - - rpr::Context* GetContext() { return m_context; } - -private: - class ImageMetadata { - public: - ImageMetadata() = default; - ImageMetadata(std::string const& path); - - bool IsMetadataEqual(ImageMetadata const& md); - - public: - std::weak_ptr handle; - - private: - size_t m_size = 0u; - double m_modificationTime = 0.0; - }; - -private: - rpr::Context* m_context; - std::unordered_map m_cache; - bool m_garbageCollectionRequired = false; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // HDRPR_IMAGE_CACHE_H diff --git a/pxr/imaging/plugin/hdRpr/light.cpp b/pxr/imaging/plugin/hdRpr/light.cpp index aaa8a35af..c890682f6 100644 --- a/pxr/imaging/plugin/hdRpr/light.cpp +++ b/pxr/imaging/plugin/hdRpr/light.cpp @@ -13,7 +13,6 @@ limitations under the License. #include "light.h" #include "renderParam.h" -#include "materialAdapter.h" #include "primvarUtil.h" #include "rprApi.h" @@ -326,12 +325,14 @@ void HdRprLight::Sync(HdSceneDelegate* sceneDelegate, return; } + bool newLight = false; auto iesFile = sceneDelegate->GetLightParamValue(id, UsdLuxTokens->shapingIesFile); if (iesFile.IsHolding()) { auto& path = iesFile.UncheckedGet(); if (!path.GetResolvedPath().empty()) { if (auto light = rprApi->CreateIESLight(path.GetResolvedPath())) { m_light = light; + newLight = true; } } } else { @@ -340,13 +341,16 @@ void HdRprLight::Sync(HdSceneDelegate* sceneDelegate, if (coneAngle.IsHolding() && coneSoftness.IsHolding()) { if (auto light = rprApi->CreateSpotLight(coneAngle.UncheckedGet(), coneSoftness.UncheckedGet())) { m_light = light; + newLight = true; } } else if (sceneDelegate->GetLightParamValue(id, UsdLuxTokens->treatAsPoint).GetWithDefault(false)) { if (auto light = rprApi->CreatePointLight()) { m_light = light; + newLight = true; } } else { CreateAreaLightMesh(rprApi, sceneDelegate); + newLight = true; } } @@ -372,10 +376,10 @@ void HdRprLight::Sync(HdSceneDelegate* sceneDelegate, } auto emissionColor = color * intensity; - bool isEmissionColorDirty = m_emisionColor != emissionColor; + bool isEmissionColorDirty = newLight || m_emisionColor != emissionColor; if (isEmissionColorDirty) { m_emisionColor = emissionColor; } - struct LightParameterSetter : public BOOST_NS::static_visitor { + struct LightParameterSetter : public BOOST_NS::static_visitor { HdRprApi* rprApi; GfVec3f const& emissionColor; bool emissionColorIsDirty; @@ -385,43 +389,36 @@ void HdRprLight::Sync(HdSceneDelegate* sceneDelegate, } - bool operator()(LightVariantEmpty) const { return false; } - bool operator()(AreaLight* light) const { + void operator()(LightVariantEmpty) const { /*no-op*/ } + void operator()(AreaLight* light) const { if (emissionColorIsDirty || !light->material) { - MaterialAdapter matAdapter(EMaterialType::EMISSIVE, MaterialParams{{HdLightTokens->color, VtValue(emissionColor)}}); - light->material = std::move(rprApi->CreateMaterial(matAdapter)); + if (light->material) { + rprApi->ReleaseGeometryLightMaterial(light->material); + } + light->material = rprApi->CreateGeometryLightMaterial(emissionColor); } if (light->material) { for (auto& mesh : light->meshes) { - rprApi->SetMeshMaterial(mesh, light->material, false, false); + rprApi->SetMeshMaterial(mesh, light->material, false); } - return true; } - - return false; } - bool operator()(rpr::SpotLight* light) const { + void operator()(rpr::SpotLight* light) const { if (emissionColorIsDirty) { rprApi->SetLightColor(light, emissionColor); } - return true; } - bool operator()(rpr::PointLight* light) const { + void operator()(rpr::PointLight* light) const { if (emissionColorIsDirty) { rprApi->SetLightColor(light, emissionColor); } - return true; } - bool operator()(rpr::IESLight* light) const { + void operator()(rpr::IESLight* light) const { if (emissionColorIsDirty) { rprApi->SetLightColor(light, emissionColor); } - return true; } }; - if (BOOST_NS::apply_visitor(LightParameterSetter{rprApi, emissionColor, isEmissionColorDirty}, m_light) && !m_created) { - m_created = true; - rprRenderParam->AddLight(); - } + BOOST_NS::apply_visitor(LightParameterSetter{rprApi, emissionColor, isEmissionColorDirty}, m_light); } if (bits & (DirtyTransform | DirtyParams)) { @@ -472,7 +469,7 @@ void HdRprLight::ReleaseLight(HdRprApi* rprApi) { for (auto& mesh : light->meshes) { rprApi->Release(mesh); } - rprApi->Release(light->material); + rprApi->ReleaseGeometryLightMaterial(light->material); delete light; } }; @@ -482,13 +479,7 @@ void HdRprLight::ReleaseLight(HdRprApi* rprApi) { } void HdRprLight::Finalize(HdRenderParam* renderParam) { - auto rprRenderParam = static_cast(renderParam); - if (m_created) { - m_created = false; - rprRenderParam->RemoveLight(); - } - - auto rprApi = rprRenderParam->AcquireRprApiForEdit(); + auto rprApi = static_cast(renderParam)->AcquireRprApiForEdit(); ReleaseLight(rprApi); HdLight::Finalize(renderParam); diff --git a/pxr/imaging/plugin/hdRpr/light.h b/pxr/imaging/plugin/hdRpr/light.h index b9bb26a02..6a1e52af8 100644 --- a/pxr/imaging/plugin/hdRpr/light.h +++ b/pxr/imaging/plugin/hdRpr/light.h @@ -26,7 +26,7 @@ namespace rpr { class Shape; class PointLight; class SpotLight; class IESLight; PXR_NAMESPACE_OPEN_SCOPE class HdRprApi; -struct HdRprApiMaterial; +class RprUsdMaterial; class HdRprLight : public HdLight { public: @@ -63,7 +63,7 @@ class HdRprLight : public HdLight { const TfToken m_lightType; struct AreaLight { - HdRprApiMaterial* material = nullptr; + RprUsdMaterial* material = nullptr; std::vector meshes; GfMatrix4f localTransform; }; @@ -81,8 +81,6 @@ class HdRprLight : public HdLight { GfVec3f m_emisionColor = GfVec3f(0.0f); GfMatrix4f m_transform; - - bool m_created = false; }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/material.cpp b/pxr/imaging/plugin/hdRpr/material.cpp index 2b85bb25c..c3b3232cd 100644 --- a/pxr/imaging/plugin/hdRpr/material.cpp +++ b/pxr/imaging/plugin/hdRpr/material.cpp @@ -12,66 +12,12 @@ limitations under the License. ************************************************************************/ #include "material.h" -#include "materialAdapter.h" #include "renderParam.h" #include "rprApi.h" -#include "pxr/usd/sdf/assetPath.h" - PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_PRIVATE_TOKENS(_tokens, - ((infoSourceAsset, "info:sourceAsset")) \ - ((infoImplementationSource, "info:implementationSource")) \ - (sourceAsset) -); - -static bool GetMaterialNetwork( - TfToken const& terminal, HdSceneDelegate* delegate, HdMaterialNetworkMap const& networkMap, HdRprRenderParam const& renderParam, - EMaterialType* out_materialType, HdMaterialNetwork const** out_network) { - auto mapIt = networkMap.map.find(terminal); - if (mapIt == networkMap.map.end()) { - return false; - } - - auto& network = mapIt->second; - if (network.nodes.empty()) { - return false; - } - - *out_network = &network; - - for (auto& node : network.nodes) { - if (node.identifier == HdRprMaterialTokens->UsdPreviewSurface) { - *out_materialType = EMaterialType::USD_PREVIEW_SURFACE; - return true; - } else { - if (renderParam.GetMaterialNetworkSelector() == HdRprMaterialNetworkSelectorTokens->karma) { - auto implementationSource = delegate->Get(node.path, _tokens->infoImplementationSource); - if (implementationSource.IsHolding() && - implementationSource.UncheckedGet() == _tokens->sourceAsset) { - auto nodeAsset = delegate->Get(node.path, _tokens->infoSourceAsset); - if (nodeAsset.IsHolding()) { - auto& asset = nodeAsset.UncheckedGet(); - if (!asset.GetAssetPath().empty()) { - static const std::string kPrincipledShaderDef = "opdef:/Vop/principledshader::2.0"; - if (asset.GetAssetPath().compare(0, kPrincipledShaderDef.size(), kPrincipledShaderDef.c_str())) { - return false; - } - - *out_materialType = EMaterialType::HOUDINI_PRINCIPLED_SHADER; - return true; - } - } - } - } - } - } - - return false; -} - HdRprMaterial::HdRprMaterial(SdfPath const& id) : HdMaterial(id) { } @@ -87,25 +33,7 @@ void HdRprMaterial::Sync(HdSceneDelegate* sceneDelegate, VtValue vtMat = sceneDelegate->GetMaterialResource(GetId()); if (vtMat.IsHolding()) { auto& networkMap = vtMat.UncheckedGet(); - - EMaterialType surfaceType = EMaterialType::NONE; - HdMaterialNetwork const* surface = nullptr; - - EMaterialType displacementType = EMaterialType::NONE; - HdMaterialNetwork const* displacement = nullptr; - - if (GetMaterialNetwork(HdMaterialTerminalTokens->surface, sceneDelegate, networkMap, *rprRenderParam, &surfaceType, &surface)) { - if (GetMaterialNetwork(HdMaterialTerminalTokens->displacement, sceneDelegate, networkMap, *rprRenderParam, &displacementType, &displacement)) { - if (displacementType != surfaceType) { - displacement = nullptr; - } - } - - MaterialAdapter matAdapter(surfaceType, *surface, displacement ? *displacement : HdMaterialNetwork{}); - m_rprMaterial = rprApi->CreateMaterial(matAdapter); - } else { - TF_CODING_WARNING("Material type not supported"); - } + m_rprMaterial = rprApi->CreateMaterial(sceneDelegate, networkMap); } } @@ -117,7 +45,7 @@ HdDirtyBits HdRprMaterial::GetInitialDirtyBitsMask() const { } void HdRprMaterial::Reload() { - // no-op + // possibly we can use it to reload .mtlx definition if it's changed but I don't know when and how Reload is actually called } void HdRprMaterial::Finalize(HdRenderParam* renderParam) { @@ -127,7 +55,7 @@ void HdRprMaterial::Finalize(HdRenderParam* renderParam) { HdMaterial::Finalize(renderParam); } -HdRprApiMaterial const* HdRprMaterial::GetRprMaterialObject() const { +RprUsdMaterial const* HdRprMaterial::GetRprMaterialObject() const { return m_rprMaterial; } diff --git a/pxr/imaging/plugin/hdRpr/material.h b/pxr/imaging/plugin/hdRpr/material.h index 38c44d757..ddb25461a 100644 --- a/pxr/imaging/plugin/hdRpr/material.h +++ b/pxr/imaging/plugin/hdRpr/material.h @@ -18,7 +18,7 @@ limitations under the License. PXR_NAMESPACE_OPEN_SCOPE -struct HdRprApiMaterial; +class RprUsdMaterial; class HdRprMaterial final : public HdMaterial { public: @@ -37,10 +37,10 @@ class HdRprMaterial final : public HdMaterial { /// Get pointer to RPR material /// In case material сreation failure return nullptr - HdRprApiMaterial const* GetRprMaterialObject() const; + RprUsdMaterial const* GetRprMaterialObject() const; private: - HdRprApiMaterial* m_rprMaterial = nullptr; + RprUsdMaterial* m_rprMaterial = nullptr; }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/materialAdapter.cpp b/pxr/imaging/plugin/hdRpr/materialAdapter.cpp deleted file mode 100644 index f318f902e..000000000 --- a/pxr/imaging/plugin/hdRpr/materialAdapter.cpp +++ /dev/null @@ -1,895 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#include "materialAdapter.h" - -#include "pxr/imaging/hd/tokens.h" -#include "pxr/imaging/hd/material.h" - -#include "pxr/base/gf/vec3f.h" -#include "pxr/base/gf/vec2f.h" -#include "pxr/usd/sdf/assetPath.h" -#include "pxr/usd/ar/resolver.h" -#include "pxr/usd/usdUtils/pipeline.h" - -#include -#include - -PXR_NAMESPACE_OPEN_SCOPE - -TF_DEFINE_PUBLIC_TOKENS(HdRprMaterialTokens, HDRPR_MATERIAL_TOKENS); - -TF_DEFINE_PRIVATE_TOKENS(HdRprTextureChannelToken, - (rgba) - (rgb) - (r) - (g) - (b) - (a) -); - -GfVec4f VtValToVec4f(const VtValue val) { - if (val.IsHolding()) { - return GfVec4f(val.Get()); - } else if (val.IsHolding()) { - GfVec3f temp = val.Get(); - return GfVec4f(temp[0], temp[1], temp[2], 1.0f); - } if (val.IsHolding()) { - return GfVec4f(val.Get()); - } else { - return val.Get(); - } -} - -bool IsColorBlack(GfVec4f color) { - return color[0] <= FLT_EPSILON && color[1] <= FLT_EPSILON && color[2] <= FLT_EPSILON; -} - -bool GetNode(const TfToken& type, const HdMaterialNetwork& materialNetwork, HdMaterialNode& out_node) { - TF_FOR_ALL(it, materialNetwork.nodes) { - if (it->identifier == type) { - out_node = *it; - return true; - } - } - - return false; -} - -bool GetParam(const TfToken& type, const HdMaterialNode& node, VtValue& out_param) { - out_param = VtValue(); - - auto& params = node.parameters; - - auto finded = params.find(type); - - if (finded == params.end()) { - return false; - } - - out_param = finded->second; - return true; -} - -EColorChannel GetChannel(TfToken channel) { - if (HdRprTextureChannelToken->rgba == channel) { - return EColorChannel::RGBA; - } else if (HdRprTextureChannelToken->rgb == channel) { - return EColorChannel::RGB; - } else if (HdRprTextureChannelToken->r == channel) { - return EColorChannel::R; - } else if (HdRprTextureChannelToken->g == channel) { - return EColorChannel::G; - } else if (HdRprTextureChannelToken->b == channel) { - return EColorChannel::B; - } else if (HdRprTextureChannelToken->a == channel) { - return EColorChannel::A; - } - - return EColorChannel::NONE; -} - -EWrapMode GetWrapMode(const TfToken type, const HdMaterialNode& node) { - VtValue param; - GetParam(type, node, param); - if (!param.IsHolding()) { - return EWrapMode::NONE; - } - - TfToken WrapModeType = param.Get(); - if (WrapModeType == HdRprMaterialTokens->black) { - return EWrapMode::BLACK; - } else if (WrapModeType == HdRprMaterialTokens->clamp) { - return EWrapMode::CLAMP; - } else if (WrapModeType == HdRprMaterialTokens->mirror) { - return EWrapMode::MIRROR; - } else if (WrapModeType == HdRprMaterialTokens->repeat) { - return EWrapMode::REPEAT; - } - - return EWrapMode::NONE; -} - -void GetParameters(const HdMaterialNetwork& materialNetwork, const HdMaterialNode& previewNode, MaterialParams& out_materialParams) { - out_materialParams.clear(); - out_materialParams.insert(previewNode.parameters.begin(), previewNode.parameters.end()); -} - -void GetTextures(const HdMaterialNetwork& materialNetwork, MaterialTextures& out_materialTextures) { - out_materialTextures.clear(); - - auto stToken = UsdUtilsGetPrimaryUVSetName(); - - for (auto& textureRel : materialNetwork.relationships) { - auto nodeIter = std::find_if(materialNetwork.nodes.begin(), materialNetwork.nodes.end(), - [&textureRel](HdMaterialNode const& node) { - return node.path == textureRel.inputId; - }); - if (nodeIter == materialNetwork.nodes.end()) { - TF_RUNTIME_ERROR("Invalid material network. Relationship %s does not match to any node", textureRel.outputName.GetText()); - continue; - } - if (nodeIter->identifier != HdRprMaterialTokens->UsdUVTexture) { - continue; - } - - MaterialTexture materialNode; - VtValue param; - - // Find out which node produces UV for look up - for (auto& stRel : materialNetwork.relationships) { - if (stRel.outputName != stToken || - stRel.outputId != textureRel.inputId) { - continue; - } - - auto stNodeIter = std::find_if(materialNetwork.nodes.begin(), materialNetwork.nodes.end(), - [&stRel](HdMaterialNode const& node) { - return node.path == stRel.inputId; - }); - if (stNodeIter == materialNetwork.nodes.end()) { - TF_RUNTIME_ERROR("Invalid material network. Relationship %s does not match to any node", stRel.outputName.GetText()); - continue; - } - // Actually some much more complex node graph could exists - // But we support only direct UsdUvTexture<->UsdTransform2d relationship for now - if (stNodeIter->identifier == HdRprMaterialTokens->UsdTransform2d) { - float rotationDegrees = 0.0f; - GfVec2f scale(1.0f); - GfVec2f translation(0.0f); - - GetParam(HdRprMaterialTokens->rotation, *stNodeIter, param); - if (param.IsHolding()) { - rotationDegrees = param.UncheckedGet(); - } - - GetParam(HdRprMaterialTokens->scale, *stNodeIter, param); - if (param.IsHolding()) { - scale = param.UncheckedGet(); - } - - GetParam(HdRprMaterialTokens->translation, *stNodeIter, param); - if (param.IsHolding()) { - translation = param.UncheckedGet(); - } - - float rotation = GfDegreesToRadians(rotationDegrees); - float rotCos = std::cos(rotation); - float rotSin = std::sin(rotation); - - // XXX (Houdini): Proposal of UsdPreviewSurface states that rotation is - // "Counter-clockwise rotation in degrees around the origin", - // by default, the origin is the zero point on the UV coordinate system - // but Houdini's Karma uses origin = (0.5, 0.5). We stick with it right now - GfVec2f origin(0.5f); - - materialNode.uvTransform = GfMatrix3f(1.0, 0.0, -origin[0], - 0.0, 1.0, -origin[1], - 0.0, 0.0, 1.0); - - materialNode.uvTransform = GfMatrix3f(scale[0], 0.0, 0.0, - 0.0, scale[1], 0.0, - 0.0, 0.0, 1.0) * materialNode.uvTransform; - materialNode.uvTransform = GfMatrix3f(rotCos, -rotSin, 0.0, - rotSin, rotCos, 0.0, - 0.0f, 0.0f, 1.0f) * materialNode.uvTransform; - materialNode.uvTransform[0][2] += translation[0] + origin[0]; - materialNode.uvTransform[1][2] += translation[1] + origin[1]; - } - break; - } - - auto& node = *nodeIter; - - GetParam(HdRprMaterialTokens->file, node, param); - - // Get image path - if (param.IsHolding()) { - auto& assetPath = param.UncheckedGet(); - if (assetPath.GetResolvedPath().empty()) { - materialNode.path = ArGetResolver().Resolve(assetPath.GetAssetPath()); - } else { - materialNode.path = assetPath.GetResolvedPath(); - } - } else { - continue; - } - - // Get channel - // The input name descripe channel(s) required - materialNode.channel = GetChannel(textureRel.inputName); - - // Get Wrap Modes - auto wrapS = GetWrapMode(HdRprMaterialTokens->wrapS, node); - auto wrapT = GetWrapMode(HdRprMaterialTokens->wrapT, node); - if (wrapS != wrapT) { - TF_RUNTIME_ERROR("RPR renderer does not support different WrapS and WrapT modes"); - } - materialNode.wrapMode = wrapS; - - // Get Scale - GetParam(HdRprMaterialTokens->scale, node, param); - if (param.IsHolding()) { - materialNode.scale = param.Get(); - } - - // Get Bias - GetParam(HdRprMaterialTokens->bias, node, param); - if (param.IsHolding()) { - materialNode.bias = param.Get(); - } - - out_materialTextures[textureRel.outputName] = materialNode; - } -} - -MaterialAdapter::MaterialAdapter(EMaterialType type, const MaterialParams& params) : m_type(type) { - switch (type) { - case EMaterialType::COLOR: { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR] = GfVec4f(0.18f); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT] = GfVec4f(1.0f); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT] = GfVec4f(0.0f); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT] = GfVec4f(0.0f); - - for (auto& entry : params) { - if (entry.first == HdRprMaterialTokens->color) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR] = VtValToVec4f(entry.second); - } - } - break; - } - case EMaterialType::EMISSIVE: - PopulateEmissive(params); - break; - case EMaterialType::TRANSPERENT: - PopulateTransparent(params); - break; - case EMaterialType::USD_PREVIEW_SURFACE: - PopulateUsdPreviewSurface(params, {}); - break; - default: - break; - } -} - -MaterialAdapter::MaterialAdapter(EMaterialType type, const HdMaterialNetwork& surfaceNetwork, HdMaterialNetwork const& displacementNetwork) - : m_type(type), m_doublesided(true) { - switch (type) { - case EMaterialType::USD_PREVIEW_SURFACE: { - HdMaterialNode previewNode; - if (!GetNode(HdRprMaterialTokens->UsdPreviewSurface, surfaceNetwork, previewNode)) { - break; - } - - MaterialParams materialParameters; - GetParameters(surfaceNetwork, previewNode, materialParameters); - - auto setFallbackValue = [&materialParameters](TfToken const& name, VtValue value) { - // TODO: change to try_emplace when it will be available - materialParameters.emplace(name, value); - }; - setFallbackValue(HdRprMaterialTokens->diffuseColor, VtValue(GfVec3f(0.18f))); - setFallbackValue(HdRprMaterialTokens->emissiveColor, VtValue(GfVec3f(0.0f))); - setFallbackValue(HdRprMaterialTokens->useSpecularWorkflow, VtValue(0)); - setFallbackValue(HdRprMaterialTokens->specularColor, VtValue(GfVec3f(0.0f))); - setFallbackValue(HdRprMaterialTokens->metallic, VtValue(0.0f)); - setFallbackValue(HdRprMaterialTokens->roughness, VtValue(0.5f)); - setFallbackValue(HdRprMaterialTokens->clearcoat, VtValue(0.0f)); - setFallbackValue(HdRprMaterialTokens->clearcoatRoughness, VtValue(0.01f)); - setFallbackValue(HdRprMaterialTokens->opacity, VtValue(1.0f)); - setFallbackValue(HdRprMaterialTokens->opacityThreshold, VtValue(0.0f)); - setFallbackValue(HdRprMaterialTokens->ior, VtValue(1.5f)); - setFallbackValue(HdRprMaterialTokens->opacityThreshold, VtValue(0.0f)); - - MaterialTextures materialTextures; - GetTextures(surfaceNetwork, materialTextures); - - PopulateUsdPreviewSurface(materialParameters, materialTextures); - break; - } - case EMaterialType::HOUDINI_PRINCIPLED_SHADER: { - PopulateHoudiniPrincipledShader(surfaceNetwork, displacementNetwork); - break; - } - default: - break; - } -} - -void MaterialAdapter::PopulateRprColor(const MaterialParams& params) { - for (MaterialParams::const_iterator param = params.begin(); param != params.end(); ++param) { - const TfToken& paramName = param->first; - const VtValue& paramValue = param->second; - - if (paramName == HdRprMaterialTokens->color) { - m_vec4fRprParams.insert({RPR_MATERIAL_INPUT_COLOR, VtValToVec4f(paramValue)}); - } - } -} - -void MaterialAdapter::PopulateEmissive(const MaterialParams& params) { - PopulateRprColor(params); -} - -void MaterialAdapter::PopulateTransparent(const MaterialParams& params) { - PopulateRprColor(params); -} - -void MaterialAdapter::PopulateUsdPreviewSurface(const MaterialParams& params, const MaterialTextures& textures) { - // initial params - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT] = GfVec4f(1.0f); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR] = GfVec4f(1.0f); - - int useSpecular = 0; - GfVec4f albedoColor = GfVec4f(1.0f); - MaterialTexture albedoTex; - bool isAlbedoTexture = false; - - GfVec4f reflectionColor = GfVec4f(1.0f); - MaterialTexture reflectionTex; - bool isReflectionTexture = false; - - for (MaterialParams::const_iterator param = params.begin(); param != params.end(); ++param) { - const TfToken& paramName = param->first; - const VtValue& paramValue = param->second; - - if (paramName == HdRprMaterialTokens->diffuseColor) { - albedoColor = VtValToVec4f(paramValue); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR] = albedoColor; - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR] = albedoColor; - } else if (paramName == HdRprMaterialTokens->emissiveColor) { - GfVec4f emmisionColor = VtValToVec4f(paramValue); - if (!IsColorBlack(emmisionColor)) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT] = GfVec4f(1.0f); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR] = emmisionColor; - } - } else if (paramName == HdRprMaterialTokens->useSpecularWorkflow) { - useSpecular = paramValue.Get(); - } else if (paramName == HdRprMaterialTokens->specularColor) { - reflectionColor = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->metallic) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS] = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->roughness) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS] = VtValToVec4f(paramValue); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS] = VtValToVec4f(paramValue); - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS] = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->clearcoat) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT] = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->clearcoatRoughness) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS] = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->ior) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR] = VtValToVec4f(paramValue); - } else if (paramName == HdRprMaterialTokens->opacity) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT] = VtValToVec4f(paramValue); - auto refractionWeight = GfVec4f(1.0f) - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT]; - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT] = refractionWeight; - - if (refractionWeight[0] != 0.0f || refractionWeight[1] != 0.0f || refractionWeight[2] != 0.0f) { - m_doublesided = false; - } - } - } - - for (auto textureEntry : textures) { - auto const& paramName = textureEntry.first; - auto& materialTexture = textureEntry.second; - if (paramName == HdRprMaterialTokens->diffuseColor) { - isAlbedoTexture = true; - albedoTex = materialTexture; - m_texRpr[RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR] = materialTexture; - } else if (paramName == HdRprMaterialTokens->emissiveColor) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT] = GfVec4f(1.0f); - m_texRpr[RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR] = materialTexture; - } else if (paramName == HdRprMaterialTokens->specularColor) { - isReflectionTexture = true; - reflectionTex = materialTexture; - } else if (paramName == HdRprMaterialTokens->metallic) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS] = materialTexture; - } else if (paramName == HdRprMaterialTokens->roughness) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS] = materialTexture; - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS] = materialTexture; - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS] = materialTexture; - } else if (paramName == HdRprMaterialTokens->clearcoat) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT] = materialTexture; - } else if (paramName == HdRprMaterialTokens->clearcoatRoughness) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS] = materialTexture; - } else if (paramName == HdRprMaterialTokens->ior) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR] = materialTexture; - } else if (paramName == HdRprMaterialTokens->opacity) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT] = materialTexture; - - // refractionWeight == 1 - diffuseWeight - // UsdUvTexture has scale and bias: color = scale * textureValue + bias - // We use it to inverse diffuse weight, so refractionWeight = 1 - diffuseWeightColor = 1 - (scale * textureValue + bias) = - // = (1 - bias) + (-1 * scale) * textureValue, where (1 - bias) = newBias, (-1 * scale) = newScale - materialTexture.bias = GfVec4f(1.0f) - materialTexture.bias; - materialTexture.scale *= -1.0f; - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT] = materialTexture; - - m_doublesided = false; - } else if (paramName == HdRprMaterialTokens->normal) { - NormalMapParam param; - param.texture = materialTexture; - param.texture.forceLinearSpace = true; - m_normalMapParams.emplace_back(std::vector{RPR_MATERIAL_INPUT_UBER_DIFFUSE_NORMAL, RPR_MATERIAL_INPUT_UBER_REFLECTION_NORMAL}, param); - } else if (paramName == HdRprMaterialTokens->displacement) { - m_displacementTexture = materialTexture; - } - - } - - if (useSpecular) { - m_uRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE] = RPR_UBER_MATERIAL_IOR_MODE_PBR; - - if (isReflectionTexture) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR] = reflectionTex; - } else { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR] = reflectionColor; - } - - } else { - m_uRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE] = RPR_UBER_MATERIAL_IOR_MODE_METALNESS; - - if (isAlbedoTexture) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR] = albedoTex; - } else { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR] = albedoColor; - } - } -} - -TF_DEFINE_PRIVATE_TOKENS(HoudiniPrincipledShaderTokens, - (basecolor) \ - (albedomult) \ - (ior) \ - ((roughness, "rough")) \ - ((anisotropy, "aniso")) \ - ((anisotropyDirection, "anisodir")) \ - (metallic) \ - ((reflectivity, "reflect")) \ - ((reflectTint, "reflecttint")) \ - (coat) \ - ((coatRoughness, "coatrough")) \ - (transparency) \ - ((transmissionColor, "transcolor")) \ - ((transmissionDistance, "transdist")) \ - ((subsurface, "sss")) \ - ((subsurfaceDistance, "sssdist")) \ - ((subsurfaceModel, "sssmodel")) \ - ((subsurfaceColor, "ssscolor")) \ - ((subsurfacePhase, "sssphase")) \ - (sheen) \ - ((sheenTint, "sheentint")) \ - ((emissionColor, "emitcolor")) \ - ((emissionIntensity, "emitint")) \ - ((opacity, "opac")) \ - ((opacityColor, "opaccolor")) \ - (baseNormal) \ - ((baseNormalScale, "baseNormal_scale")) \ - (coatNormal) \ - ((coatNormalScale, "coatNormal_scale")) \ - ((baseNormalEnable, "baseBumpAndNormal_enable")) \ - ((baseNormalType, "baseBumpAndNormal_type")) \ - (separateCoatNormals) \ - ((doubleSided, "frontface")) \ - ((displacementEnable, "dispTex_enable")) \ - ((displacementTexture, "dispTex_texture")) \ - ((displacementOffset, "dispTex_offset")) \ - ((displacementScale, "dispTex_scale")) \ - ((displacementColorSpace, "dispTex_colorSpace")) \ - ((displacementChannel, "dispTex_channel")) \ - ((displacementWrap, "dispTex_wrap")) \ - ((displacementType, "dispTex_type")) -); - -std::map g_houdiniPrincipledShaderParameterDefaultValues = { - {HoudiniPrincipledShaderTokens->basecolor, VtValue(0.2f)}, - {HoudiniPrincipledShaderTokens->ior, VtValue(1.5f)}, - {HoudiniPrincipledShaderTokens->roughness, VtValue(0.3f)}, - {HoudiniPrincipledShaderTokens->anisotropy, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->anisotropyDirection, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->metallic, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->reflectivity, VtValue(1.0f)}, - {HoudiniPrincipledShaderTokens->reflectTint, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->coat, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->coatRoughness, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->transparency, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->transmissionColor, VtValue(1.0f)}, - {HoudiniPrincipledShaderTokens->transmissionDistance, VtValue(0.1f)}, - {HoudiniPrincipledShaderTokens->subsurface, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->subsurfaceDistance, VtValue(0.1f)}, - {HoudiniPrincipledShaderTokens->subsurfaceColor, VtValue(1.0f)}, - {HoudiniPrincipledShaderTokens->sheen, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->sheenTint, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->emissionColor, VtValue(0.0f)}, - {HoudiniPrincipledShaderTokens->opacityColor, VtValue(1.0f)}, -}; - -template -T GetParameter(TfToken const& name, std::map const& parameters, T defaultValue = T()) { - auto parameterIt = parameters.find(name); - if (parameterIt != parameters.end() && - parameterIt->second.IsHolding()) { - return parameterIt->second.UncheckedGet(); - } - - return defaultValue; -} - -EColorChannel HoudiniChannelToRpr(int channel, EColorChannel rprDefault) { - if (channel == 1) { - return EColorChannel::R; - } else if (channel == 2) { - return EColorChannel::G; - } else if (channel == 3) { - return EColorChannel::B; - } else { - return rprDefault; - } -} - -EWrapMode HoudiniWrapModeToRpr(std::string const& wrapMode) { - if (wrapMode == "streak") { - return EWrapMode::CLAMP; - } else if (wrapMode == "decal") { - return EWrapMode::BLACK; - } else { - return EWrapMode::REPEAT; - } -} - -void MaterialAdapter::PopulateHoudiniPrincipledShader(HdMaterialNetwork const& surfaceNetwork, HdMaterialNetwork const& displacementNetwork) { - auto& params = surfaceNetwork.nodes[0].parameters; - - m_doublesided = GetParameter(HoudiniPrincipledShaderTokens->doubleSided, params, 1) == 1; - - // XXX: unused parameters: - // reflectTint - // reflectivity - - auto albedoMultiplier = GetParameter(HoudiniPrincipledShaderTokens->albedomult, params, 1.0f); - auto opacity = GetParameter(HoudiniPrincipledShaderTokens->opacity, params, 1.0f); - auto emissionIntensity = GetParameter(HoudiniPrincipledShaderTokens->emissionIntensity, params, 1.0f); - auto subsurfaceModel = GetParameter(HoudiniPrincipledShaderTokens->subsurfaceModel, params, std::string("full")); - auto iorMode = RPR_UBER_MATERIAL_IOR_MODE_PBR; - bool useBaseColorTextureAlpha = false; - - auto getMaterialTexture = [&](TfToken const& baseParameter) -> MaterialTexture { - MaterialTexture texture; - texture.wrapMode = EWrapMode::REPEAT; - - // Each parameter (e.g. basecolor) may have set of properties in the form: - // paramName_propertyName (e.g. basecolor_texture) - // but parameter itself may be missing in input params - - bool useTexture = false; - for (auto it = params.lower_bound(baseParameter); it != params.end(); ++it) { - // check that this property corresponds to our base parameter - if (it->first.GetString().compare(0, baseParameter.size(), baseParameter.GetText())) { - break; - } - - // skip paramName - auto propertyName = it->first.GetText() + baseParameter.size(); - - if (*propertyName != '_') { - continue; - } - ++propertyName; - - if (std::strncmp(propertyName, "texture", sizeof("texture") - 1) == 0) { - auto texturePropertyName = propertyName + (sizeof("texture") - 1); - if (*texturePropertyName == '\0') { - if (it->second.IsHolding()) { - auto& assetPath = it->second.UncheckedGet(); - texture.path = assetPath.GetResolvedPath(); - } - } else if (std::strcmp(texturePropertyName, "Intensity") == 0) { - if (it->second.IsHolding()) { - texture.scale = GfVec4f(it->second.UncheckedGet()); - } - } else if (std::strcmp(texturePropertyName, "ColorSpace") == 0) { - if (it->second.IsHolding()) { - texture.forceLinearSpace = it->second.UncheckedGet() == "linear"; - } - } else if (std::strcmp(texturePropertyName, "Wrap") == 0) { - if (it->second.IsHolding()) { - texture.wrapMode = HoudiniWrapModeToRpr(it->second.UncheckedGet()); - } - } - } else if (std::strncmp(propertyName, "useTexture", sizeof("useTexture") - 1) == 0) { - auto useTexturePropertyName = propertyName + sizeof("useTexture") - 1; - if (*useTexturePropertyName == '\0') { - if (it->second.IsHolding()) { - useTexture = static_cast(it->second.UncheckedGet()); - if (!useTexture) { - return MaterialTexture{}; - } - } - } else if (std::strcmp(useTexturePropertyName, "Alpha") == 0) { - if (it->second.IsHolding() && - it->second.UncheckedGet() == 1) { - useBaseColorTextureAlpha = true; - } - } - } else if (std::strcmp(propertyName, "monoChannel") == 0) { - if (it->second.IsHolding()) { - texture.channel = HoudiniChannelToRpr(it->second.UncheckedGet(), EColorChannel::NONE); - } - } - } - - if (baseParameter == HoudiniPrincipledShaderTokens->baseNormal) { - // baseNormal's texture enabled by baseBumpAndNormal_enable parameter unlike all other textures by *_useTexture - useTexture = true; - } - - if (useTexture) { - if (baseParameter != HoudiniPrincipledShaderTokens->basecolor && - baseParameter != HoudiniPrincipledShaderTokens->transmissionColor && - baseParameter != HoudiniPrincipledShaderTokens->subsurfaceColor && - baseParameter != HoudiniPrincipledShaderTokens->baseNormal && - baseParameter != HoudiniPrincipledShaderTokens->coatNormal && - texture.channel == EColorChannel::NONE) { - texture.channel = EColorChannel::LUMINANCE; - } - - return texture; - } - - return MaterialTexture(); - }; - - auto setMaterialTexture = [&](rpr::MaterialNodeInput rprInput, MaterialTexture const& texture) { - if (rprInput == RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT] = GfVec4f(1.0f); - - auto emissionTexture = texture; - emissionTexture.scale = GfVec4f(emissionIntensity); - m_texRpr[rprInput] = emissionTexture; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_TRANSPARENCY) { - auto transparencyTex = texture; - transparencyTex.bias = GfVec4f(1.0f) - transparencyTex.bias; - transparencyTex.scale *= -1.0f * opacity; - m_texRpr[rprInput] = transparencyTex; - m_doublesided = false; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT] = texture; - m_uRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_CAUSTICS] = 1; - - auto diffuseWeightTex = texture; - // Inverse logic of UsdPreviewSurface opacity texture - diffuseWeightTex.bias = GfVec4f(1.0f) - diffuseWeightTex.bias; - diffuseWeightTex.scale *= -1.0f; - m_texRpr[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT] = diffuseWeightTex; - - m_doublesided = false; - } else if (albedoMultiplier != 1.0f && - (rprInput == RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_COATING_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_COATING_TRANSMISSION_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_SHEEN)) { - auto premultipliedTexture = texture; - premultipliedTexture.scale *= albedoMultiplier; - m_texRpr[rprInput] = texture; - } else { - if (rprInput == RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS) { - iorMode = RPR_UBER_MATERIAL_IOR_MODE_METALNESS; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_COATING_THICKNESS) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT] = GfVec4f(1.0f); - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_SSS_WEIGHT) { - m_texRpr[RPR_MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT] = texture; - } - - m_texRpr[rprInput] = texture; - } - }; - - auto populateRprParameter = [&](std::vector rprInputs, TfToken const& paramName) -> bool { - bool isAuthored = false; - - VtValue value; - - auto parameterIt = params.find(paramName); - if (parameterIt != params.end()) { - value = parameterIt->second; - isAuthored = true; - } else { - parameterIt = g_houdiniPrincipledShaderParameterDefaultValues.find(paramName); - if (parameterIt == g_houdiniPrincipledShaderParameterDefaultValues.end()) { - return isAuthored; - } - - value = parameterIt->second; - } - - auto texture = getMaterialTexture(paramName); - if (!texture.path.empty()) { - for (auto rprInput : rprInputs) { - setMaterialTexture(rprInput, texture); - } - - return true; - } - - auto vec = VtValToVec4f(value); - for (auto rprInput : rprInputs) { - if (rprInput == RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR) { - if (IsColorBlack(vec * emissionIntensity)) { - continue; - } - - m_vec4fRprParams[rprInput] = vec * emissionIntensity; - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT] = GfVec4f(1.0f); - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_TRANSPARENCY) { - auto transparency = GfVec4f(1.0f) - vec * opacity; - m_vec4fRprParams[rprInput] = transparency; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT) { - m_vec4fRprParams[rprInput] = vec; - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT] = GfVec4f(1.0f) - vec; - - if (!IsColorBlack(vec)) { - m_uRprParams[RPR_MATERIAL_INPUT_UBER_REFRACTION_CAUSTICS] = 1; - m_doublesided = false; - } - } else { - if (rprInput == RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS && - !IsColorBlack(vec)) { - iorMode = RPR_UBER_MATERIAL_IOR_MODE_METALNESS; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_COATING_THICKNESS && - !IsColorBlack(vec)) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT] = GfVec4f(1.0f); - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_SSS_WEIGHT) { - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT] = vec; - } else if (rprInput == RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_COATING_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_COATING_TRANSMISSION_COLOR || - rprInput == RPR_MATERIAL_INPUT_UBER_SHEEN) { - vec *= albedoMultiplier; - } - - m_vec4fRprParams[rprInput] = vec; - } - } - - return isAuthored; - }; - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR, RPR_MATERIAL_INPUT_UBER_COATING_COLOR, RPR_MATERIAL_INPUT_UBER_COATING_TRANSMISSION_COLOR, RPR_MATERIAL_INPUT_UBER_SHEEN}, HoudiniPrincipledShaderTokens->basecolor); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR, RPR_MATERIAL_INPUT_UBER_COATING_IOR}, HoudiniPrincipledShaderTokens->ior); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS, RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS, RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS}, HoudiniPrincipledShaderTokens->roughness); - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY}, HoudiniPrincipledShaderTokens->anisotropy); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY_ROTATION}, HoudiniPrincipledShaderTokens->anisotropyDirection); - - bool hasTransparency = false; - hasTransparency |= populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT}, HoudiniPrincipledShaderTokens->transparency); - if (useBaseColorTextureAlpha) { - auto baseColorTextureIt = m_texRpr.find(RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR); - if (baseColorTextureIt != m_texRpr.end()) { - MaterialTexture opacityTexture = baseColorTextureIt->second; - opacityTexture.channel = EColorChannel::A; - opacityTexture.scale = GfVec4f(1.0f); - opacityTexture.bias = GfVec4f(0.0f); - opacityTexture.forceLinearSpace = true; - - setMaterialTexture(RPR_MATERIAL_INPUT_UBER_TRANSPARENCY, opacityTexture); - hasTransparency = true; - } else { - useBaseColorTextureAlpha = false; - } - } - - if (!useBaseColorTextureAlpha) { - hasTransparency |= populateRprParameter({RPR_MATERIAL_INPUT_UBER_TRANSPARENCY}, HoudiniPrincipledShaderTokens->opacityColor); - } - - if (!hasTransparency) { - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS, RPR_MATERIAL_INPUT_UBER_COATING_METALNESS}, HoudiniPrincipledShaderTokens->metallic); - } - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_COATING_THICKNESS}, HoudiniPrincipledShaderTokens->coat); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS}, HoudiniPrincipledShaderTokens->coatRoughness); - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT}, HoudiniPrincipledShaderTokens->transparency); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR, RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_COLOR}, HoudiniPrincipledShaderTokens->transmissionColor); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_DISTANCE}, HoudiniPrincipledShaderTokens->transmissionDistance); - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SSS_WEIGHT}, HoudiniPrincipledShaderTokens->subsurface); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DISTANCE}, HoudiniPrincipledShaderTokens->subsurfaceDistance); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_COLOR, RPR_MATERIAL_INPUT_UBER_BACKSCATTER_COLOR}, HoudiniPrincipledShaderTokens->subsurfaceColor); - if (subsurfaceModel == "full") { - m_uRprParams[RPR_MATERIAL_INPUT_UBER_SSS_MULTISCATTER] = 1; - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DIRECTION] = GfVec4f(0.0); - } else { - m_uRprParams[RPR_MATERIAL_INPUT_UBER_SSS_MULTISCATTER] = 0; - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DIRECTION}, HoudiniPrincipledShaderTokens->subsurfacePhase); - } - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SHEEN_WEIGHT}, HoudiniPrincipledShaderTokens->sheen); - populateRprParameter({RPR_MATERIAL_INPUT_UBER_SHEEN_TINT}, HoudiniPrincipledShaderTokens->sheenTint); - - populateRprParameter({RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR}, HoudiniPrincipledShaderTokens->emissionColor); - - if (GetParameter(HoudiniPrincipledShaderTokens->baseNormalEnable, params, 0)) { - NormalMapParam baseNormalMapParam; - baseNormalMapParam.texture = getMaterialTexture(HoudiniPrincipledShaderTokens->baseNormal); - - std::vector rprInputs = {RPR_MATERIAL_INPUT_UBER_DIFFUSE_NORMAL, RPR_MATERIAL_INPUT_UBER_REFLECTION_NORMAL, RPR_MATERIAL_INPUT_UBER_REFRACTION_NORMAL}; - - if (GetParameter(HoudiniPrincipledShaderTokens->separateCoatNormals, params, 0)) { - NormalMapParam coatNormalMapParam; - coatNormalMapParam.texture = getMaterialTexture(HoudiniPrincipledShaderTokens->coatNormal); - if (!coatNormalMapParam.texture.path.empty()) { - coatNormalMapParam.effectScale = GetParameter(HoudiniPrincipledShaderTokens->coatNormalScale, params, 1.0f); - coatNormalMapParam.texture.forceLinearSpace = true; - m_normalMapParams.emplace_back(std::vector{RPR_MATERIAL_INPUT_UBER_COATING_NORMAL}, coatNormalMapParam); - } - } else { - rprInputs.push_back(RPR_MATERIAL_INPUT_UBER_COATING_NORMAL); - } - - if (!baseNormalMapParam.texture.path.empty()) { - baseNormalMapParam.effectScale = GetParameter(HoudiniPrincipledShaderTokens->baseNormalScale, params, 1.0f); - baseNormalMapParam.texture.forceLinearSpace = true; - m_normalMapParams.emplace_back(rprInputs, baseNormalMapParam); - } - } - - m_vec4fRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT] = GfVec4f(1.0f); - - m_uRprParams[RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE] = iorMode; - - if (!displacementNetwork.nodes.empty()) { - auto& dispParams = displacementNetwork.nodes[0].parameters; - - if (GetParameter(HoudiniPrincipledShaderTokens->displacementEnable, dispParams, 0)) { - auto dispType = GetParameter(HoudiniPrincipledShaderTokens->displacementType, dispParams); - if (dispType == "vectordisp") { - TF_RUNTIME_ERROR("Vector displacement unsupported"); - } else { - auto dispTexturePath = GetParameter(HoudiniPrincipledShaderTokens->displacementTexture, dispParams); - if (!dispTexturePath.GetResolvedPath().empty()) { - m_displacementTexture.path = dispTexturePath.GetResolvedPath(); - m_displacementTexture.scale = GfVec4f(GetParameter(HoudiniPrincipledShaderTokens->displacementScale, dispParams, 0.05f)); - m_displacementTexture.bias = GfVec4f(GetParameter(HoudiniPrincipledShaderTokens->displacementOffset, dispParams, -0.5f)); - m_displacementTexture.wrapMode = HoudiniWrapModeToRpr(GetParameter(HoudiniPrincipledShaderTokens->displacementWrap, dispParams)); - m_displacementTexture.channel = HoudiniChannelToRpr(GetParameter(HoudiniPrincipledShaderTokens->displacementChannel, dispParams, 0), EColorChannel::LUMINANCE); - m_displacementTexture.forceLinearSpace = GetParameter(HoudiniPrincipledShaderTokens->displacementColorSpace, dispParams, std::string("linear")) == "linear"; - } - } - } - } -} - -PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/materialAdapter.h b/pxr/imaging/plugin/hdRpr/materialAdapter.h deleted file mode 100644 index 5a3a3c1ee..000000000 --- a/pxr/imaging/plugin/hdRpr/materialAdapter.h +++ /dev/null @@ -1,171 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#ifndef HDRPR_MATERIAL_ADAPTER_H -#define HDRPR_MATERIAL_ADAPTER_H - -#include "pxr/base/tf/token.h" -#include "pxr/base/vt/value.h" -#include "pxr/base/gf/vec4f.h" -#include "pxr/base/gf/matrix3f.h" -#include "pxr/imaging/hd/material.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -#define HDRPR_MATERIAL_TOKENS \ - (bxdf) \ - (file) \ - (scale) \ - (bias) \ - (wrapS) \ - (wrapT) \ - (black) \ - (clamp) \ - (repeat) \ - (mirror) \ - (UsdPreviewSurface) \ - (UsdUVTexture) \ - (UsdTransform2d) \ - (color) \ - (diffuseColor) \ - (emissiveColor) \ - (useSpecularWorkflow) \ - (specularColor) \ - (metallic) \ - (roughness) \ - (clearcoat) \ - (clearcoatRoughness) \ - (opacity) \ - (opacityThreshold) \ - (ior) \ - (normal) \ - (displacement) \ - (transparency) \ - (rotation) \ - (translation) - -TF_DECLARE_PUBLIC_TOKENS(HdRprMaterialTokens, HDRPR_MATERIAL_TOKENS); - -enum class EWrapMode { - NONE = -1 - , BLACK - , CLAMP - , REPEAT - , MIRROR -}; - -enum class EColorChannel { - NONE = -1 - , RGBA - , RGB - , R - , G - , B - , A - , LUMINANCE -}; - -struct MaterialTexture { - std::string path; - - EColorChannel channel = EColorChannel::NONE; - - EWrapMode wrapMode = EWrapMode::NONE; - - GfVec4f scale = GfVec4f(1.0f); - GfVec4f bias = GfVec4f(0.0f); - - GfMatrix3f uvTransform = GfMatrix3f(1.0f); - - bool forceLinearSpace = false; -}; - -typedef std::map MaterialParams; -typedef std::map MaterialTextures; - -typedef std::map MaterialRprParamsVec4f; -typedef std::map MaterialRprParamsU; -typedef std::map MaterialRprParamsTexture; - -struct NormalMapParam { - MaterialTexture texture; - float effectScale = 1.0f; -}; -using MaterialRprParamsNormalMap = std::vector, NormalMapParam>>; - -enum class EMaterialType : int32_t { - NONE = -1 - , COLOR = 0 - , EMISSIVE - , TRANSPERENT - , USD_PREVIEW_SURFACE - , HOUDINI_PRINCIPLED_SHADER -}; - -class MaterialAdapter { -public: - MaterialAdapter(EMaterialType type, MaterialParams const& params); - - MaterialAdapter(EMaterialType type, HdMaterialNetwork const& surfaceNetwork, HdMaterialNetwork const& displacementNetwork); - - EMaterialType GetType() const { - return m_type; - } - - const MaterialRprParamsVec4f& GetVec4fRprParams() const { - return m_vec4fRprParams; - } - - const MaterialRprParamsU& GetURprParams() const { - return m_uRprParams; - } - - const MaterialRprParamsTexture& GetTexRprParams() const { - return m_texRpr; - } - - const MaterialTexture& GetDisplacementTexture() const { - return m_displacementTexture; - } - - const MaterialRprParamsNormalMap& GetNormalMapParams() const { - return m_normalMapParams; - } - - bool IsDoublesided() const { - return m_doublesided; - } - -private: - void PopulateRprColor(const MaterialParams& params); - void PopulateEmissive(const MaterialParams& params); - void PopulateTransparent(const MaterialParams& params); - void PopulateUsdPreviewSurface(const MaterialParams& params, const MaterialTextures& textures); - void PopulateHoudiniPrincipledShader(HdMaterialNetwork const& surfaceNetwork, HdMaterialNetwork const& displacementNetwork); - - EMaterialType m_type; - - MaterialRprParamsVec4f m_vec4fRprParams; - MaterialRprParamsU m_uRprParams; - MaterialRprParamsTexture m_texRpr; - MaterialRprParamsNormalMap m_normalMapParams; - - MaterialTexture m_displacementTexture; - bool m_doublesided = false; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // HDRPR_MATERIAL_ADAPTER_H diff --git a/pxr/imaging/plugin/hdRpr/materialFactory.cpp b/pxr/imaging/plugin/hdRpr/materialFactory.cpp deleted file mode 100644 index fdf493628..000000000 --- a/pxr/imaging/plugin/hdRpr/materialFactory.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#include "materialFactory.h" -#include "imageCache.h" - -#include "rpr/error.h" - -#include - -PXR_NAMESPACE_OPEN_SCOPE - -namespace { - -bool GfIsEqual(GfVec4f const& v1, GfVec4f const& v2, float tolerance = 1e-5f) { - return std::abs(v1[0] - v2[0]) <= tolerance && - std::abs(v1[1] - v2[1]) <= tolerance && - std::abs(v1[2] - v2[2]) <= tolerance && - std::abs(v1[3] - v2[3]) <= tolerance; -} - -bool GfIsEqual(GfMatrix3f const& m1, GfMatrix3f const& m2, float tolerance = 1e-5f) { - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - if (std::abs(m1[i][j] - m2[i][j]) >= tolerance) { - return false; - } - } - } - return true; -} - -bool GetWrapType(const EWrapMode& wrapMode, rpr_image_wrap_type& rprWrapType) { - switch (wrapMode) { - case EWrapMode::BLACK: - rprWrapType = RPR_IMAGE_WRAP_TYPE_CLAMP_ZERO; - return true; - case EWrapMode::CLAMP: - rprWrapType = RPR_IMAGE_WRAP_TYPE_CLAMP_TO_EDGE; - return true; - case EWrapMode::MIRROR: - rprWrapType = RPR_IMAGE_WRAP_TYPE_MIRRORED_REPEAT; - return true; - case EWrapMode::REPEAT: - rprWrapType = RPR_IMAGE_WRAP_TYPE_REPEAT; - return true; - default: - break; - } - return false; -} - -bool GetSelectedChannel(const EColorChannel& colorChannel, rpr_int& out_selectedChannel) { - switch (colorChannel) { - case EColorChannel::R: - out_selectedChannel = RPR_MATERIAL_NODE_OP_SELECT_X; - return true; - case EColorChannel::G: - out_selectedChannel = RPR_MATERIAL_NODE_OP_SELECT_Y; - return true; - case EColorChannel::B: - out_selectedChannel = RPR_MATERIAL_NODE_OP_SELECT_Z; - return true; - case EColorChannel::A: - out_selectedChannel = RPR_MATERIAL_NODE_OP_SELECT_W; - return true; - default: - break; - } - return false; -} - -} // namespace anonymous - -RprMaterialFactory::RprMaterialFactory(ImageCache* imageCache) - : m_imageCache(imageCache) { - -} - -HdRprApiMaterial* RprMaterialFactory::CreatePointsMaterial(VtVec3fArray const& colors) { - auto context = m_imageCache->GetContext(); - - auto setupPointsMaterial = [&colors, context](HdRprApiMaterial* material) -> bool { - rpr::Status status; - auto rootMaterialNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_UBERV2, &status); - if (!rootMaterialNode) { - return !RPR_ERROR_CHECK(status, "Failed to create material node"); - } - material->rootMaterial = rootMaterialNode; - - rpr::BufferDesc bufferDesc; - bufferDesc.nb_element = colors.size(); - bufferDesc.element_type = RPR_BUFFER_ELEMENT_TYPE_FLOAT32; - bufferDesc.element_channel_size = 3; - - auto colorsBuffer = context->CreateBuffer(bufferDesc, colors.data(), &status); - if (!colorsBuffer) { - return !RPR_ERROR_CHECK(status, "Failed to create colors buffer"); - } - material->auxiliaryObjects.push_back(colorsBuffer); - - auto lookupIndex = context->CreateMaterialNode(RPR_MATERIAL_NODE_INPUT_LOOKUP, &status); - if (!lookupIndex) { - return !RPR_ERROR_CHECK(status, "Failed to create input lookup node"); - } - material->auxiliaryObjects.push_back(lookupIndex); - if (RPR_ERROR_CHECK(lookupIndex->SetInput(RPR_MATERIAL_INPUT_VALUE, RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID), "Failed to set lookup node input value")) { - return false; - } - - auto bufferSampler = context->CreateMaterialNode(RPR_MATERIAL_NODE_BUFFER_SAMPLER, &status); - if (!bufferSampler) { - return !RPR_ERROR_CHECK(status, "Failed to create buffer sampler node"); - } - material->auxiliaryObjects.push_back(bufferSampler); - - if (RPR_ERROR_CHECK(bufferSampler->SetInput(RPR_MATERIAL_INPUT_DATA, colorsBuffer), "Failed to set buffer sampler node input data") || - RPR_ERROR_CHECK(bufferSampler->SetInput(RPR_MATERIAL_INPUT_UV, lookupIndex), "Failed to set buffer sampler node input uv") || - RPR_ERROR_CHECK(rootMaterialNode->SetInput(RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, bufferSampler), "Failed to set root material diffuse color")) { - return false; - } - - return true; - }; - - auto material = new HdRprApiMaterial; - if (!setupPointsMaterial(material)) { - Release(material); - material = nullptr; - } - - return material; -} - -HdRprApiMaterial* RprMaterialFactory::CreateMaterial(EMaterialType type, const MaterialAdapter& materialAdapter) { - rpr::MaterialNodeType materialType; - - switch (type) { - case EMaterialType::EMISSIVE: - materialType = RPR_MATERIAL_NODE_EMISSIVE; - break; - case EMaterialType::TRANSPERENT: - materialType = RPR_MATERIAL_NODE_TRANSPARENT; - break; - case EMaterialType::COLOR: - case EMaterialType::USD_PREVIEW_SURFACE: - case EMaterialType::HOUDINI_PRINCIPLED_SHADER: - materialType = RPR_MATERIAL_NODE_UBERV2; - break; - default: - return nullptr; - } - - auto context = m_imageCache->GetContext(); - - rpr::Status status; - auto rootMaterialNode = context->CreateMaterialNode(materialType, &status); - if (!rootMaterialNode) { - RPR_ERROR_CHECK(status, "Failed to create material node"); - return nullptr; - } - - auto material = new HdRprApiMaterial; - material->rootMaterial = rootMaterialNode; - - if (materialAdapter.IsDoublesided()) { - material->twosidedNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_TWOSIDED, &status); - if (!material->twosidedNode) { - RPR_ERROR_CHECK(status, "Failed to create twosided node"); - } else { - RPR_ERROR_CHECK(material->twosidedNode->SetInput(RPR_MATERIAL_INPUT_FRONTFACE, rootMaterialNode), "Failed to set front face input of twosided node"); - } - } - - for (auto const& param : materialAdapter.GetVec4fRprParams()) { - auto& paramId = param.first; - auto& paramValue = param.second; - - if (materialAdapter.GetTexRprParams().count(paramId)) { - continue; - } - RPR_ERROR_CHECK(material->rootMaterial->SetInput(paramId, paramValue[0], paramValue[1], paramValue[2], paramValue[3]), "Failed to set material node vec4 input"); - } - - for (auto param : materialAdapter.GetURprParams()) { - auto& paramId = param.first; - auto& paramValue = param.second; - - RPR_ERROR_CHECK(material->rootMaterial->SetInput(paramId, paramValue), "Failed to set material node uint input"); - } - - auto getTextureMaterialNode = [&material](ImageCache* imageCache, MaterialTexture const& matTex) -> rpr::MaterialNode* { - if (matTex.path.empty()) { - return nullptr; - } - - auto image = imageCache->GetImage(matTex.path, matTex.forceLinearSpace); - if (!image) { - return nullptr; - } - auto rprImage = image.get(); - material->materialImages.push_back(std::move(image)); - - rpr::ImageWrapType rprWrapType; - if (GetWrapType(matTex.wrapMode, rprWrapType)) { - RPR_ERROR_CHECK(rprImage->SetWrap(rprWrapType), "Failed to set image wrap mode"); - } - - rpr::Status status; - auto context = imageCache->GetContext(); - - rpr::MaterialNode* materialNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_IMAGE_TEXTURE, &status); - if (!materialNode) { - RPR_ERROR_CHECK(status, "Failed to create image texture material node"); - return nullptr; - } - - RPR_ERROR_CHECK(materialNode->SetInput(RPR_MATERIAL_INPUT_DATA, rprImage), "Failed to set material node image data input"); - material->auxiliaryObjects.push_back(materialNode); - - if (!GfIsEqual(matTex.uvTransform, GfMatrix3f(1.0f))) { - rpr::MaterialNode* uvLookupNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_INPUT_LOOKUP, &status); - if (uvLookupNode) { - RPR_ERROR_CHECK(uvLookupNode->SetInput(RPR_MATERIAL_INPUT_VALUE, rpr_uint(RPR_MATERIAL_NODE_LOOKUP_UV)), "Failed to set material node uint input"); - - rpr::MaterialNode* transformUvNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (transformUvNode) { - // XXX (RPR): due to missing functionality to set explicitly third component of UV vector to 1 - // third component set to 1 using addition - rpr::MaterialNode* setZtoOneNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (setZtoOneNode) { - RPR_ERROR_CHECK(setZtoOneNode->SetInput(RPR_MATERIAL_INPUT_OP, rpr_uint(RPR_MATERIAL_NODE_OP_ADD)), "Failed to set material node uint input"); - RPR_ERROR_CHECK(setZtoOneNode->SetInput(RPR_MATERIAL_INPUT_COLOR0, 0.0f, 0.0f, 1.0f, 0.0f), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(setZtoOneNode->SetInput(RPR_MATERIAL_INPUT_COLOR1, uvLookupNode), "Failed to set material node node input"); - - RPR_ERROR_CHECK(transformUvNode->SetInput(RPR_MATERIAL_INPUT_OP, RPR_MATERIAL_NODE_OP_MAT_MUL), "Failed to set material node uint input"); - RPR_ERROR_CHECK(transformUvNode->SetInput(RPR_MATERIAL_INPUT_COLOR0, matTex.uvTransform[0][0], matTex.uvTransform[0][1], matTex.uvTransform[0][2], 0.0f), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(transformUvNode->SetInput(RPR_MATERIAL_INPUT_COLOR1, matTex.uvTransform[1][0], matTex.uvTransform[1][1], matTex.uvTransform[1][2], 0.0f), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(transformUvNode->SetInput(RPR_MATERIAL_INPUT_COLOR2, matTex.uvTransform[2][0], matTex.uvTransform[2][1], matTex.uvTransform[2][2], 0.0f), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(transformUvNode->SetInput(RPR_MATERIAL_INPUT_COLOR3, setZtoOneNode), "Failed to set material node node input"); - - RPR_ERROR_CHECK(materialNode->SetInput(RPR_MATERIAL_INPUT_UV, transformUvNode), "Failed to set material node node input"); - - material->auxiliaryObjects.push_back(transformUvNode); - material->auxiliaryObjects.push_back(setZtoOneNode); - material->auxiliaryObjects.push_back(uvLookupNode); - } else { - RPR_ERROR_CHECK(status, "Failed to create arithmetic material node"); - delete uvLookupNode; - delete transformUvNode; - } - } else { - RPR_ERROR_CHECK(status, "Failed to create arithmetic material node"); - delete uvLookupNode; - } - } else { - RPR_ERROR_CHECK(status, "Failed to create uv lookup material node"); - } - } - - if (!GfIsEqual(matTex.scale, GfVec4f(1.0f))) { - rpr::MaterialNode* arithmetic = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (arithmetic) { - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_OP, RPR_MATERIAL_NODE_OP_MUL), "Failed to set material node uint input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR0, materialNode), "Failed to set material node node input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR1, matTex.scale[0], matTex.scale[1], matTex.scale[2], matTex.scale[3]), "Failed to set material node vec4 input"); - material->auxiliaryObjects.push_back(arithmetic); - - materialNode = arithmetic; - } else { - RPR_ERROR_CHECK(status, "Failed to set material node vec4 input"); - } - } - - if (!GfIsEqual(matTex.bias, GfVec4f(0.0f))) { - rpr::MaterialNode* arithmetic = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (arithmetic) { - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_OP, rpr_uint(RPR_MATERIAL_NODE_OP_ADD)), "Failed to set material node uint input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR0, materialNode), "Failed to set material node node input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR1, matTex.bias[0], matTex.bias[1], matTex.bias[2], matTex.bias[3]), "Failed to set material node vec4 input"); - material->auxiliaryObjects.push_back(arithmetic); - - materialNode = arithmetic; - } else { - RPR_ERROR_CHECK(status, "Failed to create arithmetic material node"); - - } - } - - rpr::MaterialNode* outTexture = nullptr; - if (matTex.channel != EColorChannel::NONE) { - rpr_int selectedChannel = 0; - - if (GetSelectedChannel(matTex.channel, selectedChannel)) { - rpr::MaterialNode* arithmetic = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (arithmetic) { - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR0, materialNode), "Failed to set material node node input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR1, 0.0, 0.0, 0.0, 0.0), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_OP, selectedChannel), "Failed to set material node uint input"); - material->auxiliaryObjects.push_back(arithmetic); - - outTexture = arithmetic; - } else { - RPR_ERROR_CHECK(status, "Failed to create arithmetic material node"); - } - } else if (matTex.channel == EColorChannel::LUMINANCE) { - rpr::MaterialNode* arithmetic = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (arithmetic) { - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR0, materialNode), "Failed to set material node node input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_COLOR1, 0.2126, 0.7152, 0.0722, 0.0), "Failed to set material node vec4 input"); - RPR_ERROR_CHECK(arithmetic->SetInput(RPR_MATERIAL_INPUT_OP, RPR_MATERIAL_NODE_OP_DOT3), "Failed to set material node uint input"); - material->auxiliaryObjects.push_back(arithmetic); - - outTexture = arithmetic; - } else { - RPR_ERROR_CHECK(status, "Failed to create arithmetic material node"); - } - } else { - outTexture = materialNode; - } - } else { - outTexture = materialNode; - } - - return outTexture; - }; - - rpr::MaterialNode* emissionColorNode = nullptr; - - for (auto const& texParam : materialAdapter.GetTexRprParams()) { - auto& paramId = texParam.first; - auto& matTex = texParam.second; - - auto outNode = getTextureMaterialNode(m_imageCache, matTex); - if (!outNode) { - continue; - } - - if (paramId == RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR) { - emissionColorNode = outNode; - } - - material->rootMaterial->SetInput(paramId, outNode); - } - - for (auto const& normalMapParam : materialAdapter.GetNormalMapParams()) { - auto textureNode = getTextureMaterialNode(m_imageCache, normalMapParam.second.texture); - if (!textureNode) { - continue; - } - - auto normalMapNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_NORMAL_MAP, &status); - if (normalMapNode) { - material->auxiliaryObjects.push_back(normalMapNode); - RPR_ERROR_CHECK(normalMapNode->SetInput(RPR_MATERIAL_INPUT_COLOR, textureNode), "Failed to set material node node input"); - - auto s = normalMapParam.second.effectScale; - RPR_ERROR_CHECK(normalMapNode->SetInput(RPR_MATERIAL_INPUT_SCALE, s, s, s, s), "Failed to set material node node input"); - - for (auto paramId : normalMapParam.first) { - RPR_ERROR_CHECK(material->rootMaterial->SetInput(paramId, normalMapNode), "Failed to set normal map node"); - } - } else { - RPR_ERROR_CHECK(status, "Failed to create normal map material node"); - } - } - - if (emissionColorNode) { - auto averageNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (averageNode) { - averageNode->SetInput(RPR_MATERIAL_INPUT_OP, RPR_MATERIAL_NODE_OP_AVERAGE_XYZ); - averageNode->SetInput(RPR_MATERIAL_INPUT_COLOR0, emissionColorNode); - - auto isBlackColorNode = context->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status); - if (isBlackColorNode) { - material->auxiliaryObjects.push_back(averageNode); - material->auxiliaryObjects.push_back(isBlackColorNode); - - isBlackColorNode->SetInput(RPR_MATERIAL_INPUT_OP, RPR_MATERIAL_NODE_OP_GREATER); - isBlackColorNode->SetInput(RPR_MATERIAL_INPUT_COLOR0, averageNode); - isBlackColorNode->SetInput(RPR_MATERIAL_INPUT_COLOR1, 0.0f, 0.0f, 0.0f, 0.0f); - - material->rootMaterial->SetInput(RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT, isBlackColorNode); - } else { - RPR_ERROR_CHECK(status, "Failed to create isBlackColor node"); - delete averageNode; - } - } else { - RPR_ERROR_CHECK(status, "Failed to create averaging node"); - } - } - - material->displacementMaterial = getTextureMaterialNode(m_imageCache, materialAdapter.GetDisplacementTexture()); - - return material; -} - -void RprMaterialFactory::Release(HdRprApiMaterial* material) { - if (!material) { - return; - } - - if (!material->materialImages.empty()) { - m_imageCache->RequireGarbageCollection(); - } - - delete material->rootMaterial; - delete material->twosidedNode; - for (auto node : material->auxiliaryObjects) { - delete node; - } - delete material; -} - -void RprMaterialFactory::AttachMaterial(rpr::Shape* mesh, HdRprApiMaterial const* material, bool doublesided, bool displacementEnabled) { - if (material) { - if (material->twosidedNode) { - RPR_ERROR_CHECK(material->twosidedNode->SetInput(RPR_MATERIAL_INPUT_BACKFACE, doublesided ? material->rootMaterial : nullptr), "Failed to set back face input of twosided node"); - RPR_ERROR_CHECK(mesh->SetMaterial(material->twosidedNode), "Failed to set shape material"); - } else { - RPR_ERROR_CHECK(mesh->SetMaterial(material->rootMaterial), "Failed to set shape material"); - } - - if (displacementEnabled && material->displacementMaterial) { - size_t dummy; - int subdFactor; - if (RPR_ERROR_CHECK(mesh->GetInfo(RPR_SHAPE_SUBDIVISION_FACTOR, sizeof(subdFactor), &subdFactor, &dummy), "Failed to query mesh subdivision factor")) { - subdFactor = 0; - } - - if (subdFactor == 0) { - TF_WARN("Displacement material requires subdivision to be enabled. The subdivision will be enabled with refine level of 1"); - if (!RPR_ERROR_CHECK(mesh->SetSubdivisionFactor(1), "Failed to set mesh subdividion")) { - subdFactor = 1; - } - } - if (subdFactor > 0) { - RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(material->displacementMaterial), "Failed to set shape displacement material"); - } - } else { - RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(nullptr), "Failed to unset shape displacement material"); - } - } else { - RPR_ERROR_CHECK(mesh->SetMaterial(nullptr), "Failed to unset shape material"); - RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(nullptr), "Failed to unset shape displacement material"); - } -} - -void RprMaterialFactory::AttachMaterial(rpr::Curve* curve, HdRprApiMaterial const* material) { - RPR_ERROR_CHECK(curve->SetMaterial(material ? material->rootMaterial : nullptr), "Failed to set curve material"); -} - -PXR_NAMESPACE_CLOSE_SCOPE \ No newline at end of file diff --git a/pxr/imaging/plugin/hdRpr/materialFactory.h b/pxr/imaging/plugin/hdRpr/materialFactory.h deleted file mode 100644 index 5d9efb6e7..000000000 --- a/pxr/imaging/plugin/hdRpr/materialFactory.h +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#ifndef HDRPR_MATERIAL_FACTORY_H -#define HDRPR_MATERIAL_FACTORY_H - -#include "pxr/pxr.h" -#include "materialAdapter.h" - -#include - -namespace rpr { class MaterialNode; class Image; class Shape; class Curve; } - -PXR_NAMESPACE_OPEN_SCOPE - -struct HdRprApiMaterial { - rpr::MaterialNode* rootMaterial = nullptr; - rpr::MaterialNode* twosidedNode = nullptr; - rpr::MaterialNode* displacementMaterial = nullptr; - std::vector auxiliaryObjects; - std::vector> materialImages; -}; - -class ImageCache; - -class RprMaterialFactory { -public: - RprMaterialFactory(ImageCache* imageCache); - - HdRprApiMaterial* CreateMaterial(EMaterialType type, MaterialAdapter const& materialAdapter); - HdRprApiMaterial* CreatePointsMaterial(VtVec3fArray const& colors); - void Release(HdRprApiMaterial* material); - - void AttachMaterial(rpr::Shape* mesh, HdRprApiMaterial const* material, bool doublesided, bool displacementEnabled); - void AttachMaterial(rpr::Curve* mesh, HdRprApiMaterial const* material); - -private: - ImageCache* m_imageCache; -}; - -PXR_NAMESPACE_CLOSE_SCOPE - -#endif // HDRPR_MATERIAL_FACTORY_H diff --git a/pxr/imaging/plugin/hdRpr/mesh.cpp b/pxr/imaging/plugin/hdRpr/mesh.cpp index 34d78049d..4d4cede7b 100644 --- a/pxr/imaging/plugin/hdRpr/mesh.cpp +++ b/pxr/imaging/plugin/hdRpr/mesh.cpp @@ -15,10 +15,11 @@ limitations under the License. #include "instancer.h" #include "renderParam.h" #include "material.h" -#include "materialAdapter.h" #include "primvarUtil.h" #include "rprApi.h" +#include "pxr/imaging/rprUsd/material.h" + #include "pxr/imaging/pxOsd/tokens.h" #include "pxr/imaging/pxOsd/subdivTags.h" @@ -30,8 +31,6 @@ limitations under the License. #include "pxr/base/gf/matrix4f.h" #include "pxr/base/gf/vec4f.h" -#include "pxr/usd/usdUtils/pipeline.h" - PXR_NAMESPACE_OPEN_SCOPE HdRprMesh::HdRprMesh(SdfPath const& id, SdfPath const& instancerId) @@ -107,7 +106,7 @@ bool HdRprMesh::GetPrimvarData(TfToken const& name, template bool HdRprMesh::GetPrimvarData(TfToken const&, HdSceneDelegate*, std::map, VtArray&, VtIntArray&); template bool HdRprMesh::GetPrimvarData(TfToken const&, HdSceneDelegate*, std::map, VtArray&, VtIntArray&); -HdRprApiMaterial const* HdRprMesh::GetFallbackMaterial(HdSceneDelegate* sceneDelegate, HdRprApi* rprApi, HdDirtyBits dirtyBits) { +RprUsdMaterial const* HdRprMesh::GetFallbackMaterial(HdSceneDelegate* sceneDelegate, HdRprApi* rprApi, HdDirtyBits dirtyBits) { if (m_fallbackMaterial && (dirtyBits & HdChangeTracker::DirtyPrimvar)) { rprApi->Release(m_fallbackMaterial); m_fallbackMaterial = nullptr; @@ -134,8 +133,7 @@ HdRprApiMaterial const* HdRprMesh::GetFallbackMaterial(HdSceneDelegate* sceneDel } } - auto matAdapter = MaterialAdapter(EMaterialType::COLOR, MaterialParams{ {HdRprMaterialTokens->color, VtValue(color)} }); - m_fallbackMaterial = rprApi->CreateMaterial(matAdapter); + m_fallbackMaterial = rprApi->CreateDiffuseMaterial(color); } return m_fallbackMaterial; @@ -214,23 +212,29 @@ void HdRprMesh::Sync(HdSceneDelegate* sceneDelegate, newMesh = true; } - auto stToken = UsdUtilsGetPrimaryUVSetName(); - if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, stToken)) { - GetPrimvarData(stToken, sceneDelegate, primvarDescsPerInterpolation, m_uvs, m_uvIndices); - - newMesh = true; - } - if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { m_cachedMaterialId = sceneDelegate->GetMaterialId(id); } - if (*dirtyBits & HdChangeTracker::DirtyVisibility) { - _sharedData.visible = sceneDelegate->GetVisible(id); + auto material = static_cast(sceneDelegate->GetRenderIndex().GetSprim(HdPrimTypeTokens->material, m_cachedMaterialId)); + if (material && material->GetRprMaterialObject()) { + auto rprMaterial = material->GetRprMaterialObject(); + + auto uvPrimvarName = &rprMaterial->GetUvPrimvarName(); + if (uvPrimvarName->IsEmpty()) { + static TfToken st("st", TfToken::Immortal); + uvPrimvarName = &st; + } + + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, *uvPrimvarName)) { + GetPrimvarData(*uvPrimvarName, sceneDelegate, primvarDescsPerInterpolation, m_uvs, m_uvIndices); + + newMesh = true; + } } - if (*dirtyBits & HdChangeTracker::DirtyDoubleSided) { - m_doublesided = sceneDelegate->GetDoubleSided(id); + if (*dirtyBits & HdChangeTracker::DirtyVisibility) { + _sharedData.visible = sceneDelegate->GetVisible(id); } //////////////////////////////////////////////////////////////////////// @@ -305,6 +309,7 @@ void HdRprMesh::Sync(HdSceneDelegate* sceneDelegate, m_geomSubsets = m_topology.GetGeomSubsets(); if (m_geomSubsets.empty()) { if (auto rprMesh = rprApi->CreateMesh(m_points, m_faceVertexIndices, m_normals, m_normalIndices, m_uvs, m_uvIndices, m_faceVertexCounts, m_topology.GetOrientation())) { + rprApi->SetMeshId(rprMesh, GetPrimId()); m_rprMeshes.push_back(rprMesh); } } else { @@ -431,6 +436,7 @@ void HdRprMesh::Sync(HdSceneDelegate* sceneDelegate, } if (auto rprMesh = rprApi->CreateMesh(subsetPoints, subsetIndexes, subsetNormals, subsetNormalIndices, subsetUv, subsetUvIndices, subsetVertexPerFace, m_topology.GetOrientation())) { + rprApi->SetMeshId(rprMesh, GetPrimId()); m_rprMeshes.push_back(rprMesh); ++it; } else { @@ -497,13 +503,13 @@ void HdRprMesh::Sync(HdSceneDelegate* sceneDelegate, if (m_geomSubsets.empty()) { auto material = getMeshMaterial(m_cachedMaterialId); for (auto& mesh : m_rprMeshes) { - rprApi->SetMeshMaterial(mesh, material, m_doublesided, m_displayStyle.displacementEnabled); + rprApi->SetMeshMaterial(mesh, material, m_displayStyle.displacementEnabled); } } else { if (m_geomSubsets.size() == m_rprMeshes.size()) { for (int i = 0; i < m_rprMeshes.size(); ++i) { auto material = getMeshMaterial(m_geomSubsets[i].materialId); - rprApi->SetMeshMaterial(m_rprMeshes[i], material, m_doublesided, m_displayStyle.displacementEnabled); + rprApi->SetMeshMaterial(m_rprMeshes[i], material, m_displayStyle.displacementEnabled); } } else { TF_CODING_ERROR("Unexpected number of meshes"); diff --git a/pxr/imaging/plugin/hdRpr/mesh.h b/pxr/imaging/plugin/hdRpr/mesh.h index a551d61a8..a6c6da2e5 100644 --- a/pxr/imaging/plugin/hdRpr/mesh.h +++ b/pxr/imaging/plugin/hdRpr/mesh.h @@ -25,7 +25,7 @@ namespace rpr { class Shape; } PXR_NAMESPACE_OPEN_SCOPE class HdRprApi; -struct HdRprApiMaterial; +class RprUsdMaterial; class HdRprMesh final : public HdMesh { public: @@ -56,12 +56,12 @@ class HdRprMesh final : public HdMesh { VtArray& out_data, VtIntArray& out_indices); - HdRprApiMaterial const* GetFallbackMaterial(HdSceneDelegate* sceneDelegate, HdRprApi* rprApi, HdDirtyBits dirtyBits); + RprUsdMaterial const* GetFallbackMaterial(HdSceneDelegate* sceneDelegate, HdRprApi* rprApi, HdDirtyBits dirtyBits); private: std::vector m_rprMeshes; std::vector> m_rprMeshInstances; - HdRprApiMaterial* m_fallbackMaterial = nullptr; + RprUsdMaterial* m_fallbackMaterial = nullptr; SdfPath m_cachedMaterialId; static constexpr int kDefaultNumTimeSamples = 2; @@ -88,7 +88,6 @@ class HdRprMesh final : public HdMesh { HdDisplayStyle m_displayStyle; int m_refineLevel = 0; - bool m_doublesided = false; uint32_t m_visibilityMask; }; diff --git a/pxr/imaging/plugin/hdRpr/ndrDiscoveryPlugin.cpp b/pxr/imaging/plugin/hdRpr/ndrDiscoveryPlugin.cpp new file mode 100644 index 000000000..f33ea34e5 --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/ndrDiscoveryPlugin.cpp @@ -0,0 +1,57 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/usd/ndr/discoveryPlugin.h" +#include "pxr/imaging/rprUsd/materialRegistry.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class HdRprNdrDiscoveryPlugin +/// +/// Enumerates materials from RprUsdMaterialRegistry. +/// +class HdRprNdrDiscoveryPlugin final : public NdrDiscoveryPlugin { +public: + NdrNodeDiscoveryResultVec DiscoverNodes(const Context& ctx) override { + static TfToken rpr("rpr", TfToken::Immortal); + + NdrNodeDiscoveryResultVec ret; + for (auto& nodeDesc : RprUsdMaterialRegistry::GetInstance().GetRegisteredNodes()) { + if (!nodeDesc.info) continue; + + ret.emplace_back( + /* identifier = */ TfToken(nodeDesc.info->GetName()), + /* version = */ NdrVersion(1), + /* name = */ nodeDesc.info->GetName(), + /* family = */ TfToken(nodeDesc.info->GetUIFolder()), + /* discoveryType = */ rpr, + /* sourceType = */ rpr, + /* uri = */ std::string(), + /* resolvedUri = */ std::string(), + /* sourceCode = */ std::string(), + /* metadata = */ NdrTokenMap(), + /* blindData = */ std::string() + ); + } + return ret; + } + + const NdrStringVec& GetSearchURIs() const override { + static NdrStringVec s_searchURIs; + return s_searchURIs; + } +}; + +NDR_REGISTER_DISCOVERY_PLUGIN(HdRprNdrDiscoveryPlugin); + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/ndrParserPlugin.cpp b/pxr/imaging/plugin/hdRpr/ndrParserPlugin.cpp new file mode 100644 index 000000000..bc08e4fe9 --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/ndrParserPlugin.cpp @@ -0,0 +1,60 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/usd/ndr/node.h" +#include "pxr/usd/ndr/parserPlugin.h" +#include "pxr/usd/ndr/nodeDiscoveryResult.h" + +#include "pxr/base/tf/staticTokens.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS(_tokens, (rpr)); + +/// \class HdRprNdrParserPlugin +/// +/// This does the minimal amount of work so Hydra will let us have our shaders. +/// +class HdRprNdrParserPlugin final : public NdrParserPlugin { +public: + NdrNodeUniquePtr Parse(const NdrNodeDiscoveryResult& discoveryResult) override { + return std::make_unique( + /* identifier = */ discoveryResult.identifier, + /* version = */ discoveryResult.version, + /* name = */ discoveryResult.name, + /* family = */ discoveryResult.family, + /* context = */ _tokens->rpr, + /* sourceType = */ _tokens->rpr, + /* uri = */ discoveryResult.uri, +#if PXR_VERSION > 1911 + /* resolvedUri = */ discoveryResult.resolvedUri, +#endif + /* properties = */ NdrPropertyUniquePtrVec{}, + /* metadata = */ discoveryResult.metadata, + /* sourceCode = */ discoveryResult.sourceCode + ); + } + + const NdrTokenVec& GetDiscoveryTypes() const override { + static NdrTokenVec s_discoveryTypes{_tokens->rpr}; + return s_discoveryTypes; + } + + const TfToken& GetSourceType() const override { + return _tokens->rpr; + } +}; + +NDR_REGISTER_PARSER_PLUGIN(HdRprNdrParserPlugin); + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/package/CMakeLists.txt b/pxr/imaging/plugin/hdRpr/package/CMakeLists.txt index 556b6be43..37efaeac6 100644 --- a/pxr/imaging/plugin/hdRpr/package/CMakeLists.txt +++ b/pxr/imaging/plugin/hdRpr/package/CMakeLists.txt @@ -1,31 +1,50 @@ -set(HOMEPAGE "https://github.com/GPUOpen-LibrariesAndSDKs/RadeonProRenderUSD") - -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Radeon ProRender USD Hydra rendering delegate") -set(CPACK_PACKAGE_VENDOR "AMD") -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE.md") -if(RPR_BUILD_AS_HOUDINI_PLUGIN) - set(CPACK_INSTALL_TARGET "Houdini-${Houdini_VERSION}") -else() - set(CPACK_INSTALL_TARGET "USD-${USD_MINOR_VERSION}.${USD_PATCH_VERSION}") +if(HoudiniUSD_FOUND) + set(HOUDINI_MAJOR_MINOR_VERSION "${Houdini_VERSION_MAJOR}.${Houdini_VERSION_MINOR}") + configure_file(activateHoudiniPlugin.py.in ${CMAKE_CURRENT_BINARY_DIR}/activateHoudiniPlugin.py) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/activateHoudiniPlugin.py DESTINATION .) endif() -set(CPACK_PACKAGE_NAME hdRpr) -if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") - set(CPACK_PACKAGE_NAME ${CPACK_PACKAGE_NAME}-${CMAKE_BUILD_TYPE}) + +set(USD_MINOR_VERSION "0") +set(USD_MAJOR_VERSION "0") +get_target_property(USD_INCLUDE_DIRS ar INTERFACE_INCLUDE_DIRECTORIES) +if(USD_INCLUDE_DIRS) + foreach(dir ${USD_INCLUDE_DIRS}) + if(EXISTS "${dir}/pxr/pxr.h") + foreach(_usd_comp MAJOR MINOR PATCH) + file(STRINGS + "${dir}/pxr/pxr.h" + _usd_tmp + REGEX "#define PXR_${_usd_comp}_VERSION .*$") + string(REGEX MATCHALL "[0-9]+" USD_${_usd_comp}_VERSION ${_usd_tmp}) + endforeach() + break() + endif() + endforeach() endif() -set(CPACK_PACKAGE_VERSION "${HD_RPR_MAJOR_VERSION}.${HD_RPR_MINOR_VERSION}.${HD_RPR_PATCH_VERSION}") -set(CPACK_GENERATOR "TGZ") +if(DUMP_PACKAGE_FILE_NAME) + if(APPLE) + set(PACKAGE_PLATFORM "macOS") + elseif(WIN32) + set(PACKAGE_PLATFORM "Windows") + else() + set(PACKAGE_PLATFORM "${RPR_SDK_PLATFORM}") + endif() -set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) + set(PACKAGE_NAME hdRpr) + if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") + set(PACKAGE_NAME ${PACKAGE_NAME}-${CMAKE_BUILD_TYPE}) + endif() -if(APPLE) - set(CPACK_SYSTEM_NAME "macOS") -elseif(WIN32) - set(CPACK_SYSTEM_NAME "Windows") -else() - set(CPACK_SYSTEM_NAME "${RPR_SDK_PLATFORM}") -endif() + set(PACKAGE_VERSION "${HD_RPR_MAJOR_VERSION}.${HD_RPR_MINOR_VERSION}.${HD_RPR_PATCH_VERSION}") -set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_INSTALL_TARGET}-${CPACK_SYSTEM_NAME}") + if(HoudiniUSD_FOUND) + set(TARGET "Houdini-${Houdini_VERSION}") + else() + set(TARGET "USD-${USD_MINOR_VERSION}.${USD_PATCH_VERSION}") + endif() -include(CPack) + set(PACKAGE_FILE_NAME "${PACKAGE_NAME}-${PACKAGE_VERSION}-${TARGET}-${PACKAGE_PLATFORM}") + + message(STATUS "PACKAGE_FILE_NAME: ${PACKAGE_FILE_NAME}") +endif() diff --git a/pxr/imaging/plugin/hdRpr/package/activateHoudiniPlugin.py.in b/pxr/imaging/plugin/hdRpr/package/activateHoudiniPlugin.py.in new file mode 100644 index 000000000..123bdca14 --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/package/activateHoudiniPlugin.py.in @@ -0,0 +1,112 @@ +# Copyright 2020 Advanced Micro Devices, Inc +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# http://www.apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +import re +import json +import glob +import argparse +import platform + +def get_houdini_user_pref_dir(hver): + houdini_user_pref_dir = os.getenv('HOUDINI_USER_PREF_DIR') + if houdini_user_pref_dir: + if '__HVER__' in houdini_user_pref_dir: + houdini_user_pref_dir.replace(' __HVER__', hver) + return houdini_user_pref_dir + else: + print('Invalid HOUDINI_USER_PREF_DIR specified') + exit(1) + + def get_houdini_user_pref_dir_from_parent_dir(parent_dir): + pref_dir = os.path.join(parent_dir, 'houdini' + hver) + if os.path.exists(pref_dir): + return pref_dir + return None + + home = os.getenv('HOME') + if home: + houdini_user_pref_dir = get_houdini_user_pref_dir_from_parent_dir(home) + if houdini_user_pref_dir: + return houdini_user_pref_dir + + if platform.system() == 'Windows': + userprofile = os.getenv('USERPROFILE') + if not userprofile: + print('Set HOUDINI_USER_PREF_DIR environment variable') + exit(1) + + documents_dir = os.path.join(userprofile, 'documents') + houdini_user_pref_dir = get_houdini_user_pref_dir_from_parent_dir(documents_dir) + if houdini_user_pref_dir: + return houdini_user_pref_dir + elif platform.system() == 'Darwin': + if home: + macos_fallback_dir = '{}/Library/Preferences/houdini/{}'.format(home, hver) + if os.path.exists(macos_fallback_dir): + return macos_fallback_dir + + print('Can not determine HOUDINI_USER_PREF_DIR. Please check your environment and specify HOUDINI_USER_PREF_DIR') + exit(1) + + +parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('-d', '--deactivate', default=False, action='store_true') +parser.add_argument('-p', '--plugin_path', type=str, + help='Path to RPR plugin for Houdini. If not set, the plugin will be automatically found in the current working directory') + +args = parser.parse_args() + +houdini_user_pref_dir = get_houdini_user_pref_dir('@HOUDINI_MAJOR_MINOR_VERSION@') + +houdini_packages_dir = os.path.join(houdini_user_pref_dir, 'packages') +os.makedirs(houdini_packages_dir, exist_ok=True) + +package_desc_filepath = os.path.join(houdini_packages_dir, 'RPR_for_Houdini.json') + +if args.deactivate: + if os.path.exists(package_desc_filepath): + os.remove(package_desc_filepath) + print('RPR plugin for Houdini has been deactivated') + else: + print('RPR plugin for Houdini is not active') +else: + def is_valid_plugin_dir(path): + plugin_info_path = os.path.join(path, 'plugin/usd/hdRpr/resources/plugInfo.json') + return os.path.isfile(plugin_info_path) + + if args.plugin_path: + if not is_valid_plugin_dir(args.plugin_path): + print('Invalid plugin path') + exit(1) + + plugin_dir = args.plugin_path + else: + if is_valid_plugin_dir('.'): + plugin_dir = '.' + else: + print('Cannot find RPR plugin for Houdini. Specify --plugin_path explicitly') + exit(1) + + plugin_dir = os.path.abspath(plugin_dir) + plugin_dir = plugin_dir.replace('\\', '/') + + env = [ + {"RPR": plugin_dir}, + {"HOUDINI_PATH": "$RPR/houdini"} + ] + if platform.system() == 'Windows': + env += [{"PATH": "$RPR/lib"}] + + with open(package_desc_filepath, 'w') as desc_file: + desc_file.write(json.dumps({"env":env})) + print('RPR plugin for Houdini has been activated') diff --git a/pxr/imaging/plugin/hdRpr/package/generatePackage.py b/pxr/imaging/plugin/hdRpr/package/generatePackage.py index bcc92930e..4f9964b7f 100644 --- a/pxr/imaging/plugin/hdRpr/package/generatePackage.py +++ b/pxr/imaging/plugin/hdRpr/package/generatePackage.py @@ -12,7 +12,9 @@ import os import re import sys +import shlex import shutil +import tarfile import platform import argparse import subprocess @@ -42,67 +44,46 @@ def current_working_directory(dir): try: yield finally: os.chdir(curdir) -def get_package_path(build_dir, config): - with current_working_directory(build_dir): - subprocess.call(['cmake', '--build', '.', '--config', config, '--', format_multi_procs(get_cpu_count())]) - output = subprocess.check_output(['cpack', '-C', config]) - print(output) - - pattern = re.compile(r'CPack:\ -\ package:\ (?P.*?)\ generated.', re.VERBOSE) - for line in str(output).split('\n'): - match = pattern.match(line.rstrip()) - if match: - package_path = match.group('package_path') - return package_path - self_dir = os.path.abspath(self_path()) hdrpr_root_path = os.path.abspath(os.path.join(self_path(), '../../../../..')) parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) -parser.add_argument('-b', '--build_dir', type=str, default='{}/build'.format(hdrpr_root_path)) -parser.add_argument('-o', '--output_package_path', type=str, default=None) +parser.add_argument('-i', '--src_dir', type=str, default=hdrpr_root_path) +parser.add_argument('-o', '--output_dir', type=str, default='.') parser.add_argument('-c', '--config', type=str, default='Release') +parser.add_argument('--cmake_options', type=str, default='') +parser.add_argument('--disable_auto_cleanup', default=False, action='store_true') args = parser.parse_args() -package_path = get_package_path(args.build_dir, args.config) -if package_path: - package_basename = os.path.basename(package_path) +output_dir = os.path.abspath(args.output_dir) + +package_dir = '_package' +cmake_configure_cmd = ['cmake', '-DCMAKE_INSTALL_PREFIX='+package_dir, '-DDUMP_PACKAGE_FILE_NAME=ON'] +cmake_configure_cmd += shlex.split(args.cmake_options) +if platform.system() == 'Windows': + cmake_configure_cmd += ['-G', 'Visual Studio 15 2017 Win64'] +cmake_configure_cmd += ['..'] - output_package_path = args.output_package_path - if not output_package_path: - package_name = package_basename - package_ext = '.tar.gz' - if package_basename.endswith(package_ext): - package_name = package_basename[:-len(package_ext)] - output_package_path = '{}-package.zip'.format(package_name) +build_dir = 'build_generatePackage_tmp_dir' +os.makedirs(build_dir, exist_ok=True) - if not os.path.exists('tmp_dir'): - os.mkdir('tmp_dir') - with current_working_directory('tmp_dir'): - if platform.system() != 'Linux': - installer_content = 'python install.py\n' - if platform.system() == "Windows": - installer_ext = 'bat' - installer_content = 'pushd %~dp0\n' + installer_content - installer_content += 'pause\n' - if platform.system() == "Darwin": - installer_content = 'cd $(dirname $0)\n' + installer_content - installer_ext = 'command' - install_file_path = 'install.' + installer_ext - install_file = open(install_file_path, 'w') - install_file.write(installer_content) - install_file.close() +with current_working_directory(build_dir): + configure_output = subprocess.check_output(cmake_configure_cmd).decode() + print(configure_output) - if platform.system() == 'Darwin': - os.chmod(install_file_path, 0o755) + package_name = 'hdRpr' + for line in reversed(configure_output.splitlines()): + if line.startswith('-- PACKAGE_FILE_NAME'): + package_name = line[len('-- PACKAGE_FILE_NAME: '):] + break - shutil.copyfile(package_path, package_basename) - shutil.copyfile(self_dir + '/install.py', 'install.py') - shutil.copyfile(hdrpr_root_path + '/INSTALL.md', 'INSTALL.md') - shutil.copyfile(hdrpr_root_path + '/LICENSE.md', 'LICENSE.md') + subprocess.call(['cmake', '--build', '.', '--config', args.config, '--target', 'install', '--', format_multi_procs(get_cpu_count())]) - shutil.make_archive('tmp_package', 'zip', 'tmp_dir', './') - shutil.copyfile('tmp_package.zip', output_package_path) + with tarfile.open('tmpPackage.tar.gz', 'w:gz') as tar: + tar.add(package_dir, package_name) + output_package = os.path.join(output_dir, package_name+'.tar.gz') + shutil.copyfile('tmpPackage.tar.gz', output_package) +print('{} has been created'.format(os.path.relpath(output_package))) - shutil.rmtree('tmp_dir') - os.remove('tmp_package.zip') +if not args.disable_auto_cleanup: + shutil.rmtree(build_dir) diff --git a/pxr/imaging/plugin/hdRpr/plugInfo.json b/pxr/imaging/plugin/hdRpr/plugInfo.json index 2811c833e..5fae003f0 100644 --- a/pxr/imaging/plugin/hdRpr/plugInfo.json +++ b/pxr/imaging/plugin/hdRpr/plugInfo.json @@ -9,6 +9,14 @@ ], "displayName": "RPR", "priority": 99 + }, + "HdRprNdrDiscoveryPlugin": { + "bases": ["NdrDiscoveryPlugin"], + "displayName": "RPR Node Discovery" + }, + "HdRprNdrParserPlugin": { + "bases": ["NdrParserPlugin"], + "displayName": "RPR Node Parser" } } }, diff --git a/pxr/imaging/plugin/hdRpr/points.cpp b/pxr/imaging/plugin/hdRpr/points.cpp index df10f2211..c9bff4a7b 100644 --- a/pxr/imaging/plugin/hdRpr/points.cpp +++ b/pxr/imaging/plugin/hdRpr/points.cpp @@ -15,7 +15,6 @@ limitations under the License. #include "rprApi.h" #include "primvarUtil.h" #include "renderParam.h" -#include "materialAdapter.h" #include "pxr/imaging/hd/extComputationUtils.h" #include "pxr/usdImaging/usdImaging/implicitSurfaceMeshUtils.h" @@ -128,8 +127,7 @@ void HdRprPoints::Sync( if (m_colorsInterpolation == HdInterpolationVertex) { m_material = rprApi->CreatePointsMaterial(m_colors); } else if (!m_colors.empty()) { - auto matAdapter = MaterialAdapter(EMaterialType::COLOR, MaterialParams{{HdRprMaterialTokens->color, VtValue(m_colors[0])}}); - m_material = rprApi->CreateMaterial(matAdapter); + m_material = rprApi->CreateDiffuseMaterial(m_colors[0]); } } @@ -199,7 +197,7 @@ void HdRprPoints::Sync( if (dirtyDisplayColors || dirtyInstances) { for (size_t i = 0; i < m_instances.size(); ++i) { - rprApi->SetMeshMaterial(m_instances[i], m_material, false, false); + rprApi->SetMeshMaterial(m_instances[i], m_material, false); } } diff --git a/pxr/imaging/plugin/hdRpr/points.h b/pxr/imaging/plugin/hdRpr/points.h index 8ef6a304f..032a98f43 100644 --- a/pxr/imaging/plugin/hdRpr/points.h +++ b/pxr/imaging/plugin/hdRpr/points.h @@ -22,7 +22,7 @@ namespace rpr { class Shape; } PXR_NAMESPACE_OPEN_SCOPE -struct HdRprApiMaterial; +class RprUsdMaterial; class HdRprPoints : public HdPoints { public: @@ -48,7 +48,7 @@ class HdRprPoints : public HdPoints { private: rpr::Shape* m_prototypeMesh = nullptr; std::vector m_instances; - HdRprApiMaterial* m_material = nullptr; + RprUsdMaterial* m_material = nullptr; GfMatrix4f m_transform; diff --git a/pxr/imaging/plugin/hdRpr/python/commonSettings.py b/pxr/imaging/plugin/hdRpr/python/commonSettings.py index 03cca88b5..a1a445125 100644 --- a/pxr/imaging/plugin/hdRpr/python/commonSettings.py +++ b/pxr/imaging/plugin/hdRpr/python/commonSettings.py @@ -73,3 +73,18 @@ 'defaultValue': True } ] + +class SettingValue(object): + def __init__(self, key, ui_name=None): + self.key = key + self._ui_name = ui_name + + def __eq__(self, obj): + return self.key == obj + + def __ne__(self, obj): + return not self == obj + + def get_ui_name(self): + return self._ui_name if self._ui_name else self.key + diff --git a/pxr/imaging/plugin/hdRpr/python/generateFiles.py b/pxr/imaging/plugin/hdRpr/python/generateFiles.py index 6f45a97ae..d61034734 100644 --- a/pxr/imaging/plugin/hdRpr/python/generateFiles.py +++ b/pxr/imaging/plugin/hdRpr/python/generateFiles.py @@ -19,6 +19,7 @@ p.add_argument('scripts_dir', help="Directory with scripts") p.add_argument("install", help="The install root for generated files.") p.add_argument("--houdini_root", help="The install root for generated files.") + p.add_argument('--hidden-render-qualities', default='', type=str) args = p.parse_args() generate_ds_files = [] @@ -29,5 +30,8 @@ os.environ['PYTHONPATH'] = os.environ.get('PYTHONPATH', '') + os.pathsep + os.path.join(os.path.join(args.houdini_root, 'houdini'), 'python2.7libs') subprocess.check_call([sys.executable, os.path.join(args.scripts_dir, 'generateLightSettingFiles.py'), args.install] + generate_ds_files) - subprocess.check_call([sys.executable, os.path.join(args.scripts_dir, 'generateRenderSettingFiles.py'), args.install] + generate_ds_files) subprocess.check_call([sys.executable, os.path.join(args.scripts_dir, 'generateGeometrySettingFiles.py'), args.install] + generate_ds_files) + subprocess.check_call([ + sys.executable, os.path.join(args.scripts_dir, 'generateRenderSettingFiles.py'), + '--hidden-render-qualities', args.hidden_render_qualities, + args.install] + generate_ds_files) diff --git a/pxr/imaging/plugin/hdRpr/python/generateRenderSettingFiles.py b/pxr/imaging/plugin/hdRpr/python/generateRenderSettingFiles.py index 8f2016970..7a2d3925a 100644 --- a/pxr/imaging/plugin/hdRpr/python/generateRenderSettingFiles.py +++ b/pxr/imaging/plugin/hdRpr/python/generateRenderSettingFiles.py @@ -15,41 +15,89 @@ import platform from houdiniDsGenerator import generate_houdini_ds +from commonSettings import SettingValue + +def get_render_setting(render_setting_categories, category_name, name): + for category in render_setting_categories: + if category['name'] != category_name: + continue + + for setting in category['settings']: + if setting['name'] == name: + return setting + +def hidewhen_not_ambient_occlusion_mode(render_setting_categories): + renderMode = get_render_setting(render_setting_categories, 'RenderMode', 'renderMode') + return 'renderMode != {}'.format(renderMode['values'].index('Ambient Occlusion')) render_setting_categories = [ { 'name': 'RenderQuality', - 'disabled_platform': ['Darwin'], 'settings': [ { 'name': 'renderQuality', 'ui_name': 'Render Quality', 'help': 'Render restart might be required', - 'defaultValue': 3, + 'defaultValue': 'Full', 'values': [ - "Low", - "Medium", - "High", - "Full" + SettingValue('Low'), + SettingValue('Medium'), + SettingValue('High'), + SettingValue('Full'), + SettingValue('Northstar', 'Full 2.0 (Beta)') ] } ] }, + { + 'name': 'RenderMode', + 'settings': [ + { + 'name': 'renderMode', + 'ui_name': 'Render Mode', + 'defaultValue': 'Global Illumination', + 'values': [ + SettingValue('Global Illumination'), + SettingValue('Direct Illumination'), + SettingValue('Wireframe'), + SettingValue('Material Index'), + SettingValue('Position'), + SettingValue('Normal'), + SettingValue('Texcoord'), + SettingValue('Ambient Occlusion'), + SettingValue('Diffuse') + ] + }, + { + 'name': 'aoRadius', + 'ui_name': 'Ambient Occlusion Radius', + 'defaultValue': 1.0, + 'minValue': 0.0, + 'maxValue': 100.0, + 'houdini': { + 'hidewhen': hidewhen_not_ambient_occlusion_mode + } + } + ], + 'houdini': { + 'hidewhen': 'renderQuality < 3' + } + }, { 'name': 'Device', 'houdini': { - 'hidewhen': 'renderQuality != 3' + 'hidewhen': 'renderQuality < 3' }, 'settings': [ { 'name': 'renderDevice', 'ui_name': 'Render Device', 'help': 'Restart required.', - 'defaultValue': 1, + 'defaultValue': 'GPU', 'values': [ - "CPU", - "GPU", - # "CPU+GPU" + SettingValue('CPU'), + SettingValue('GPU'), + # SettingValue('CPU+GPU') ] } ] @@ -91,7 +139,7 @@ { 'name': 'AdaptiveSampling', 'houdini': { - 'hidewhen': 'renderQuality != 3' + 'hidewhen': 'renderQuality < 3' }, 'settings': [ { @@ -115,7 +163,7 @@ { 'name': 'Quality', 'houdini': { - 'hidewhen': 'renderQuality != 3' + 'hidewhen': 'renderQuality < 3' }, 'settings': [ { @@ -252,6 +300,19 @@ } ] }, + { + 'name': 'Alpha', + 'settings': [ + { + 'name': 'enableAlpha', + 'ui_name': 'Enable Color Alpha', + 'defaultValue': True, + 'houdini': { + 'hidewhen': 'renderQuality < 3' + } + } + ] + }, { 'name': 'UsdNativeCamera', 'settings': [ @@ -427,7 +488,7 @@ class HdRprConfig {{ if (FILE* f = fopen(rprPreferencePath.c_str(), "rb")) {{ if (!fread(this, sizeof(PrefData), 1, f)) {{ - TF_CODING_ERROR("Fail to read rpr preferences dat file"); + TF_RUNTIME_ERROR("Fail to read rpr preferences dat file"); }} fclose(f); return IsValid(); @@ -518,9 +579,11 @@ class HdRprConfig {{ setting['maxValue'] = len(setting['values']) - 1 rs_mapped_values_enum += 'enum {name_title}Type {{\n'.format(name_title=name_title) for value in setting['values']: - rs_mapped_values_enum += ' k{name_title}{value},\n'.format(name_title=name_title, value=value) + rs_mapped_values_enum += ' k{name_title}{value},\n'.format(name_title=name_title, value=value.key.replace(' ', '')) rs_mapped_values_enum += '};\n' + default_value = setting['values'].index(default_value) type_str = '{name_title}Type'.format(name_title=name_title) + c_type_str = type(default_value).__name__ rs_get_set_method_declarations += ' void Set{}({} {});\n'.format(name_title, c_type_str, name) rs_get_set_method_declarations += ' {} Get{}() const {{ return m_prefData.{}; }}\n\n'.format(type_str, name_title, name) @@ -550,6 +613,13 @@ class HdRprConfig {{ rs_validate_values += '\n' rs_range_definitions += '\n' + if 'hidden_values' in setting: + set_validation += ' switch ({name}) {{\n'.format(name=name) + for value in setting['hidden_values']: + set_validation += ' case k{name_title}{value}:\n'.format(name_title=name_title, value=value.replace(' ', '')) + set_validation += ' return;\n'.format(name_title=name_title, value=value.replace(' ', '')) + set_validation += ' default: break;}\n' + if 'ui_name' in setting: rs_list_initialization += ' settingDescs.push_back({{"{}", HdRprRenderSettingsTokens->{}, VtValue(k{}Default)}});\n'.format(setting['ui_name'], name, name_title) @@ -599,6 +669,22 @@ class HdRprConfig {{ p = argparse.ArgumentParser() p.add_argument("install", help="The install root for generated files.") p.add_argument("--generate_ds_files", default=False, action='store_true') + p.add_argument('--hidden-render-qualities', default='', type=str) args = p.parse_args() + if args.hidden_render_qualities: + for category in render_setting_categories: + if category['name'] == 'RenderQuality': + for setting in category['settings']: + if setting['name'] == 'renderQuality': + hidden_render_qualities = args.hidden_render_qualities.split() + for render_quality in hidden_render_qualities: + if not render_quality in setting['values']: + print('Unknown render quality: {}'.format(render_quality)) + sys.exit(1) + + setting['hidden_values'] = hidden_render_qualities + break + break + generate_render_setting_files(args.install, args.generate_ds_files) diff --git a/pxr/imaging/plugin/hdRpr/python/houdiniDsGenerator.py b/pxr/imaging/plugin/hdRpr/python/houdiniDsGenerator.py index 4d1e48d65..e6418eb0d 100644 --- a/pxr/imaging/plugin/hdRpr/python/houdiniDsGenerator.py +++ b/pxr/imaging/plugin/hdRpr/python/houdiniDsGenerator.py @@ -61,20 +61,22 @@ def generate_houdini_ds(install_path, ds_name, settings): if not 'ui_name' in setting: continue - category_hidewhen = None + houdini_hidewhen_conditions = [] if 'houdini' in category: - category_hidewhen = category['houdini'].get('hidewhen') + houdini_hidewhen_conditions.append(category['houdini'].get('hidewhen')) houdini_settings = setting.get('houdini', {}) houdini_param_label = setting['ui_name'] - houdini_hidewhen_conditions = [] - if 'hidewhen' in houdini_settings or category_hidewhen: - houdini_hidewhen_conditions.append(houdini_settings.get('hidewhen', category_hidewhen)) + if 'hidewhen' in houdini_settings: + houdini_hidewhen_conditions.append(houdini_settings.get('hidewhen')) houdini_hidewhen = '' if houdini_hidewhen_conditions: houdini_hidewhen += 'hidewhen "' for condition in houdini_hidewhen_conditions: - houdini_hidewhen += '{{ {} }} '.format(condition) + if condition: + if callable(condition): + condition = condition(settings) + houdini_hidewhen += '{{ {} }} '.format(condition) houdini_hidewhen += '"' def CreateHoudiniParam(name, label, htype, default, values=[], hints=[], tags=[], disablewhen_conditions=[], size=None, valid_range=None, help_msg=None): @@ -130,9 +132,20 @@ def CreateHoudiniParam(name, label, htype, default, values=[], hints=[], tags=[] render_param_type = 'toggle' render_param_default = 1 if default_value else 0 elif 'values' in setting: + if 'hidden_values' in setting: + values = list() + for value in setting['values']: + if not value in setting['hidden_values']: + values.append(value) + else: + values = setting['values'] + + default_value = values.index(default_value) + render_param_default = default_value + c_type_str = type(default_value).__name__ render_param_type = 'ordinal' - for value in setting['values']: - render_param_values.append((len(render_param_values), value)) + for value in values: + render_param_values.append((len(render_param_values), value.get_ui_name())) render_param_range = None if 'minValue' in setting and 'maxValue' in setting and not 'values' in setting: diff --git a/pxr/imaging/plugin/hdRpr/renderBuffer.cpp b/pxr/imaging/plugin/hdRpr/renderBuffer.cpp index 4ea2be946..9714abec7 100644 --- a/pxr/imaging/plugin/hdRpr/renderBuffer.cpp +++ b/pxr/imaging/plugin/hdRpr/renderBuffer.cpp @@ -49,7 +49,6 @@ void HdRprRenderBuffer::Finalize(HdRenderParam* renderParam) { bool HdRprRenderBuffer::Allocate(GfVec3i const& dimensions, HdFormat format, bool multiSampled) { - TF_VERIFY(!IsMapped()); TF_UNUSED(multiSampled); if (dimensions[2] != 1) { @@ -69,8 +68,6 @@ bool HdRprRenderBuffer::Allocate(GfVec3i const& dimensions, } void HdRprRenderBuffer::_Deallocate() { - TF_VERIFY(!IsMapped()); - m_width = 0u; m_height = 0u; m_format = HdFormatInvalid; @@ -80,11 +77,15 @@ void HdRprRenderBuffer::_Deallocate() { } void* HdRprRenderBuffer::Map() { + if (!m_isValid) return nullptr; + ++m_numMappers; return m_mappedBuffer.data(); } void HdRprRenderBuffer::Unmap() { + if (!m_isValid) return; + // XXX We could consider clearing _mappedBuffer here to free RAM. // For now we assume that Map() will be called frequently so we prefer // to avoid the cost of clearing the buffer over memory savings. @@ -109,4 +110,8 @@ void HdRprRenderBuffer::SetConverged(bool converged) { return m_isConverged.store(converged); } +void HdRprRenderBuffer::SetStatus(bool isValid) { + m_isValid = isValid; +} + PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/renderBuffer.h b/pxr/imaging/plugin/hdRpr/renderBuffer.h index edd9ad2ae..25b595d9f 100644 --- a/pxr/imaging/plugin/hdRpr/renderBuffer.h +++ b/pxr/imaging/plugin/hdRpr/renderBuffer.h @@ -55,6 +55,8 @@ class HdRprRenderBuffer final : public HdRenderBuffer { void SetConverged(bool converged); + void SetStatus(bool isValid); + protected: void _Deallocate() override; @@ -66,6 +68,8 @@ class HdRprRenderBuffer final : public HdRenderBuffer { std::vector m_mappedBuffer; std::atomic m_numMappers; std::atomic m_isConverged; + + bool m_isValid = true; }; PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/renderDelegate.cpp b/pxr/imaging/plugin/hdRpr/renderDelegate.cpp index a5396e3b6..1700a9d18 100644 --- a/pxr/imaging/plugin/hdRpr/renderDelegate.cpp +++ b/pxr/imaging/plugin/hdRpr/renderDelegate.cpp @@ -12,9 +12,10 @@ limitations under the License. ************************************************************************/ #include "renderDelegate.h" +#include "aovDescriptor.h" -#include"pxr/imaging/hd/extComputation.h" - +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/imaging/hd/extComputation.h" #include "pxr/base/tf/diagnosticMgr.h" #include "pxr/base/tf/getenv.h" @@ -116,7 +117,10 @@ class HdRprDiagnosticMgrDelegate : public TfDiagnosticMgr::Delegate { TF_DEFINE_PRIVATE_TOKENS(_tokens, (openvdbAsset) \ - (percentDone) + (percentDone) \ + (renderMode) \ + (batch) \ + (progressive) ); const TfTokenVector HdRprDelegate::SUPPORTED_RPRIM_TYPES = { @@ -147,7 +151,14 @@ const TfTokenVector HdRprDelegate::SUPPORTED_BPRIM_TYPES = { HdPrimTypeTokens->renderBuffer }; -HdRprDelegate::HdRprDelegate() { +HdRprDelegate::HdRprDelegate(HdRenderSettingsMap const& renderSettings) { + for (auto& entry : renderSettings) { + SetRenderSetting(entry.first, entry.second); + } + + m_isBatch = GetRenderSetting(_tokens->renderMode) == _tokens->batch; + m_isProgressive = GetRenderSetting(_tokens->progressive).GetWithDefault(true); + m_rprApi.reset(new HdRprApi(this)); g_rprApi = m_rprApi.get(); @@ -187,11 +198,11 @@ HdRenderParam* HdRprDelegate::GetRenderParam() const { void HdRprDelegate::CommitResources(HdChangeTracker* tracker) { // CommitResources() is called after prim sync has finished, but before any // tasks (such as draw tasks) have run. - + m_rprApi->CommitResources(); } TfToken HdRprDelegate::GetMaterialNetworkSelector() const { - return m_renderParam->GetMaterialNetworkSelector(); + return RprUsdMaterialRegistry::GetInstance().GetMaterialNetworkSelector(); } TfTokenVector const& HdRprDelegate::GetSupportedRprimTypes() const { @@ -324,42 +335,14 @@ void HdRprDelegate::DestroyBprim(HdBprim* bPrim) { } HdAovDescriptor HdRprDelegate::GetDefaultAovDescriptor(TfToken const& name) const { - HdParsedAovToken aovId(name); - if (name != HdAovTokens->color && - name != HdAovTokens->normal && - name != HdAovTokens->primId && - name != HdAovTokens->depth && - name != HdRprUtilsGetCameraDepthName() && - !(aovId.isPrimvar && aovId.name == "st")) { - // TODO: implement support for instanceId and elementId aov - return HdAovDescriptor(); - } + auto& rprAovDesc = HdRprAovRegistry::GetInstance().GetAovDesc(name); - if (!m_rprApi->IsAovFormatConversionAvailable()) { - if (name == HdAovTokens->primId) { - // Integer images required, no way to support it - return HdAovDescriptor(); - } - // Only native RPR format can be used for AOVs when there is no support for AOV format conversion - return HdAovDescriptor(HdFormatFloat32Vec4, false, VtValue(GfVec4f(0.0f))); - } - - HdFormat format = HdFormatInvalid; - - float clearColorValue = 0.0f; - if (name == HdAovTokens->depth || - name == HdRprUtilsGetCameraDepthName()) { - clearColorValue = name == HdRprUtilsGetCameraDepthName() ? 0.0f : 1.0f; - format = HdFormatFloat32; - } else if (name == HdAovTokens->color) { - format = HdFormatFloat32Vec4; - } else if (name == HdAovTokens->primId) { - format = HdFormatInt32; - } else { - format = HdFormatFloat32Vec3; - } + HdAovDescriptor hdAovDesc; + hdAovDesc.format = rprAovDesc.format; + hdAovDesc.multiSampled = rprAovDesc.multiSampled; + hdAovDesc.clearValue = VtValue(rprAovDesc.clearValue); - return HdAovDescriptor(format, false, VtValue(GfVec4f(clearColorValue))); + return hdAovDesc; } HdRenderSettingDescriptorList HdRprDelegate::GetRenderSettingDescriptors() const { @@ -420,14 +403,6 @@ bool HdRprDelegate::Restart() { #endif // PXR_VERSION >= 2005 -TfToken const& HdRprUtilsGetCameraDepthName() { -#if PXR_VERSION < 2002 - return HdAovTokens->linearDepth; -#else - return HdAovTokens->cameraDepth; -#endif -} - PXR_NAMESPACE_CLOSE_SCOPE void SetHdRprRenderDevice(int renderDevice) { diff --git a/pxr/imaging/plugin/hdRpr/renderDelegate.h b/pxr/imaging/plugin/hdRpr/renderDelegate.h index 1037562cb..78cf5236a 100644 --- a/pxr/imaging/plugin/hdRpr/renderDelegate.h +++ b/pxr/imaging/plugin/hdRpr/renderDelegate.h @@ -28,7 +28,7 @@ class HdRprApi; class HdRprDelegate final : public HdRenderDelegate { public: - HdRprDelegate(); + HdRprDelegate(HdRenderSettingsMap const& renderSettings); ~HdRprDelegate() override; HdRprDelegate(const HdRprDelegate&) = delete; @@ -85,11 +85,17 @@ class HdRprDelegate final : public HdRenderDelegate { bool Restart() override; #endif // PXR_VERSION >= 2005 + bool IsBatch() const { return m_isBatch; } + bool IsProgressive() const { return m_isProgressive; } + private: static const TfTokenVector SUPPORTED_RPRIM_TYPES; static const TfTokenVector SUPPORTED_SPRIM_TYPES; static const TfTokenVector SUPPORTED_BPRIM_TYPES; + bool m_isBatch; + bool m_isProgressive; + std::unique_ptr m_rprApi; std::unique_ptr m_renderParam; HdRenderSettingDescriptorList m_settingDescriptors; @@ -99,7 +105,6 @@ class HdRprDelegate final : public HdRenderDelegate { DiagnostMgrDelegatePtr m_diagnosticMgrDelegate; }; -TfToken const& HdRprUtilsGetCameraDepthName(); PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/renderParam.cpp b/pxr/imaging/plugin/hdRpr/renderParam.cpp index f682aaa2f..8dd6e5816 100644 --- a/pxr/imaging/plugin/hdRpr/renderParam.cpp +++ b/pxr/imaging/plugin/hdRpr/renderParam.cpp @@ -14,21 +14,10 @@ limitations under the License. #include "renderParam.h" #include "volume.h" -#include "pxr/base/tf/envSetting.h" - #include "pxr/imaging/hd/sceneDelegate.h" PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_PUBLIC_TOKENS(HdRprMaterialNetworkSelectorTokens, HDRPR_MATERIAL_NETWORK_SELECTOR_TOKENS); - -TF_DEFINE_ENV_SETTING(HDRPR_MATERIAL_NETWORK_SELECTOR, HDRPR_DEFAULT_MATERIAL_NETWORK_SELECTOR, - "Material network selector to be used in hdRpr"); - -void HdRprRenderParam::InitializeEnvParameters() { - m_materialNetworkSelector = TfToken(TfGetEnvSetting(HDRPR_MATERIAL_NETWORK_SELECTOR)); -} - HdRprVolumeFieldSubscription HdRprRenderParam::SubscribeVolumeForFieldUpdates( HdRprVolume* volume, SdfPath const& fieldId) { auto sub = HdRprVolumeFieldSubscription(volume, [](HdRprVolume* volume) {}); diff --git a/pxr/imaging/plugin/hdRpr/renderParam.h b/pxr/imaging/plugin/hdRpr/renderParam.h index 1e3590dc2..6ae63531d 100644 --- a/pxr/imaging/plugin/hdRpr/renderParam.h +++ b/pxr/imaging/plugin/hdRpr/renderParam.h @@ -20,12 +20,6 @@ limitations under the License. PXR_NAMESPACE_OPEN_SCOPE -#define HDRPR_MATERIAL_NETWORK_SELECTOR_TOKENS \ - (rpr) \ - (karma) - -TF_DECLARE_PUBLIC_TOKENS(HdRprMaterialNetworkSelectorTokens, HDRPR_MATERIAL_NETWORK_SELECTOR_TOKENS); - class HdRprApi; class HdRprVolume; @@ -36,10 +30,7 @@ class HdRprRenderParam final : public HdRenderParam { public: HdRprRenderParam(HdRprApi* rprApi, HdRprRenderThread* renderThread) : m_rprApi(rprApi) - , m_renderThread(renderThread) { - m_numLights.store(0); - InitializeEnvParameters(); - } + , m_renderThread(renderThread) {} ~HdRprRenderParam() override = default; HdRprApi const* GetRprApi() const { return m_rprApi; } @@ -50,12 +41,6 @@ class HdRprRenderParam final : public HdRenderParam { HdRprRenderThread* GetRenderThread() { return m_renderThread; } - void AddLight() { ++m_numLights; } - void RemoveLight() { --m_numLights; } - bool HasLights() const { return m_numLights != 0; } - - TfToken const& GetMaterialNetworkSelector() const { return m_materialNetworkSelector; } - // Hydra does not mark HdVolume as changed if HdField used by it is changed // We implement this volume-to-field dependency by ourself until it's implemented in Hydra // More info: https://groups.google.com/forum/#!topic/usd-interest/pabUE0B_5X4 @@ -66,15 +51,9 @@ class HdRprRenderParam final : public HdRenderParam { bool IsRenderShouldBeRestarted() { return m_restartRender.exchange(false); } private: - void InitializeEnvParameters(); - HdRprApi* m_rprApi; HdRprRenderThread* m_renderThread; - std::atomic m_numLights; - - TfToken m_materialNetworkSelector; - std::mutex m_subscribedVolumesMutex; std::map> m_subscribedVolumes; diff --git a/pxr/imaging/plugin/hdRpr/rendererPlugin.cpp b/pxr/imaging/plugin/hdRpr/rendererPlugin.cpp index 84a1d124d..18d27e747 100644 --- a/pxr/imaging/plugin/hdRpr/rendererPlugin.cpp +++ b/pxr/imaging/plugin/hdRpr/rendererPlugin.cpp @@ -46,15 +46,11 @@ TF_REGISTRY_FUNCTION(TfType) { } HdRenderDelegate* HdRprPlugin::CreateRenderDelegate() { - return new HdRprDelegate(); + return new HdRprDelegate(HdRenderSettingsMap()); } HdRenderDelegate* HdRprPlugin::CreateRenderDelegate(HdRenderSettingsMap const& settingsMap) { - auto renderDelegate = new HdRprDelegate(); - for (auto& entry : settingsMap) { - renderDelegate->SetRenderSetting(entry.first, entry.second); - } - return renderDelegate; + return new HdRprDelegate(settingsMap); } void HdRprPlugin::DeleteRenderDelegate(HdRenderDelegate* renderDelegate) { diff --git a/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.cpp b/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.cpp index 7ec8e2ff0..1e1ed51c9 100644 --- a/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.cpp +++ b/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.cpp @@ -15,8 +15,8 @@ limitations under the License. #include "rifError.h" #include "rprApiFramebuffer.h" -#include "rpr/contextMetadata.h" -#include "rpr/helpers.h" +#include "pxr/imaging/rprUsd/contextMetadata.h" +#include "pxr/imaging/rprUsd/helpers.h" #include #include @@ -146,7 +146,7 @@ std::unique_ptr ContextOpenCL::CreateImage(HdRprApiFramebuffer* rprFrameB } auto rifImageDesc = GetRifImageDesc(rprFrameBuffer); - RIF_ERROR_CHECK_THROW(rifContextCreateImageFromOpenClMemory(m_context, &rifImageDesc, clMem, false, &rifImage), "Failed to create RIF image from OpenCL memory"); + RIF_ERROR_CHECK_THROW(rifContextCreateImageFromOpenClMemory(m_context, &rifImageDesc, clMem, &rifImage), "Failed to create RIF image from OpenCL memory"); return std::unique_ptr(new Image(rifImage)); } @@ -268,6 +268,7 @@ ContextMetal::ContextMetal(rpr::Context* rprContext, std::string const& modelPat } std::unique_ptr ContextMetal::CreateImage(HdRprApiFramebuffer* rprFrameBuffer) { +#ifdef __APPLE__ if (!rprFrameBuffer) { return nullptr; } @@ -296,6 +297,9 @@ std::unique_ptr ContextMetal::CreateImage(HdRprApiFramebuffer* rprFrameBu RIF_ERROR_CHECK_THROW(rifContextCreateImageFromMetalMemory(m_context, &desc, clMem, size, &rifImage), "Failed to create RIF image from metal memory"); return std::unique_ptr(new Image(rifImage)); +#else + return nullptr; +#endif } bool HasGpuContext(rpr_creation_flags contextFlags) { @@ -312,7 +316,7 @@ bool HasGpuContext(rpr_creation_flags contextFlags) { } // namespace anonymous -std::unique_ptr Context::Create(rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, std::string const& modelPath) { +std::unique_ptr Context::Create(rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, std::string const& modelPath) { if (!rprContext) { return nullptr; } @@ -325,7 +329,7 @@ std::unique_ptr Context::Create(rpr::Context* rprContext, rpr::ContextM try { std::unique_ptr rifContext; if (HasGpuContext(contextFlags) && - rprContextMetadata.pluginType != rpr::kPluginHybrid && + rprContextMetadata.pluginType == kPluginTahoe && !(contextFlags & RPR_CREATION_FLAGS_ENABLE_METAL)) { rifContext.reset(new ContextOpenCL(rprContext, modelPath)); } else { diff --git a/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.h b/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.h index 0d1634ac3..e0990d01f 100644 --- a/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.h +++ b/pxr/imaging/plugin/hdRpr/rifcpp/rifContext.h @@ -19,22 +19,18 @@ limitations under the License. #include #include -namespace rpr { - -class Context; -struct ContextMetadata; - -} // namespace rpr +namespace rpr { class Context; } PXR_NAMESPACE_OPEN_SCOPE +struct RprUsdContextMetadata; class HdRprApiFramebuffer; namespace rif { class Context { public: - static std::unique_ptr Create(rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, std::string const& modelPath); + static std::unique_ptr Create(rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, std::string const& modelPath); virtual ~Context(); diff --git a/pxr/imaging/plugin/hdRpr/rifcpp/rifFilter.cpp b/pxr/imaging/plugin/hdRpr/rifcpp/rifFilter.cpp index 29f071060..75a1da8ef 100644 --- a/pxr/imaging/plugin/hdRpr/rifcpp/rifFilter.cpp +++ b/pxr/imaging/plugin/hdRpr/rifcpp/rifFilter.cpp @@ -23,10 +23,12 @@ namespace { class FilterAIDenoise final : public Filter { enum { RemapDepthFilter, + RemapNormalFilter, AuxFilterMax }; enum { RemappedDepthImage, + RemappedNormalImage, AuxImageMax }; public: @@ -82,26 +84,31 @@ FilterAIDenoise::FilterAIDenoise(Context* rifContext, std::uint32_t width, std:: // auxillary filters m_auxFilters.resize(AuxFilterMax, nullptr); m_auxFilters[RemapDepthFilter] = rifContext->CreateImageFilter(RIF_IMAGE_FILTER_REMAP_RANGE); + m_auxFilters[RemapNormalFilter] = rifContext->CreateImageFilter(RIF_IMAGE_FILTER_REMAP_RANGE); // setup remapping filters RIF_ERROR_CHECK_THROW(rifImageFilterSetParameter1f(m_auxFilters[RemapDepthFilter], "dstLo", 0.0f), "Failed to set filter parameter"); RIF_ERROR_CHECK_THROW(rifImageFilterSetParameter1f(m_auxFilters[RemapDepthFilter], "dstHi", 1.0f), "Failed to set filter parameter"); + RIF_ERROR_CHECK_THROW(rifImageFilterSetParameter1f(m_auxFilters[RemapNormalFilter], "dstLo", 0.0f), "Failed to set filter parameter"); + RIF_ERROR_CHECK_THROW(rifImageFilterSetParameter1f(m_auxFilters[RemapNormalFilter], "dstHi", 1.0f), "Failed to set filter parameter"); // auxillary rif images auto desc = Image::GetDesc(width, height, HdFormatFloat32Vec4); m_auxImages.resize(AuxImageMax); m_auxImages[RemappedDepthImage] = rifContext->CreateImage(desc); + m_auxImages[RemappedNormalImage] = rifContext->CreateImage(desc); } void FilterAIDenoise::AttachFilter(rif_image inputImage) { // setup inputs - RIF_ERROR_CHECK_THROW(rifImageFilterSetParameterImage(m_rifFilter, "normalsImg", m_inputs.at(Normal).rifImage), "Failed to set filter parameter"); + RIF_ERROR_CHECK_THROW(rifImageFilterSetParameterImage(m_rifFilter, "normalsImg", m_auxImages[RemappedNormalImage]->GetHandle()), "Failed to set filter parameter"); RIF_ERROR_CHECK_THROW(rifImageFilterSetParameterImage(m_rifFilter, "depthImg", m_auxImages[RemappedDepthImage]->GetHandle()), "Failed to set filter parameter"); RIF_ERROR_CHECK_THROW(rifImageFilterSetParameterImage(m_rifFilter, "colorImg", m_inputs.at(Color).rifImage), "Failed to set filter parameter"); RIF_ERROR_CHECK_THROW(rifImageFilterSetParameterImage(m_rifFilter, "albedoImg", m_inputs.at(Albedo).rifImage), "Failed to set filter parameter"); m_rifContext->AttachFilter(m_auxFilters[RemapDepthFilter], m_inputs.at(LinearDepth).rifImage, m_auxImages[RemappedDepthImage]->GetHandle()); + m_rifContext->AttachFilter(m_auxFilters[RemapNormalFilter], m_inputs.at(Normal).rifImage, m_auxImages[RemappedNormalImage]->GetHandle()); Filter::AttachFilter(inputImage); } diff --git a/pxr/imaging/plugin/hdRpr/rpr/CMakeLists.txt b/pxr/imaging/plugin/hdRpr/rpr/CMakeLists.txt deleted file mode 100644 index 39e9b9fc2..000000000 --- a/pxr/imaging/plugin/hdRpr/rpr/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -target_sources(hdRpr PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/error.h - ${CMAKE_CURRENT_SOURCE_DIR}/contextMetadata.h - ${CMAKE_CURRENT_SOURCE_DIR}/contextHelpers.h - ${CMAKE_CURRENT_SOURCE_DIR}/contextHelpers.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/imageHelpers.h - ${CMAKE_CURRENT_SOURCE_DIR}/imageHelpers.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/helpers.h) \ No newline at end of file diff --git a/pxr/imaging/plugin/hdRpr/rpr/imageHelpers.cpp b/pxr/imaging/plugin/hdRpr/rpr/imageHelpers.cpp deleted file mode 100644 index 1630e72dc..000000000 --- a/pxr/imaging/plugin/hdRpr/rpr/imageHelpers.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/************************************************************************ -Copyright 2020 Advanced Micro Devices, Inc -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -************************************************************************/ - -#include "imageHelpers.h" -#include "helpers.h" - -#include "pxr/imaging/glf/glew.h" -#include "pxr/imaging/glf/uvTextureData.h" -#include "pxr/imaging/glf/image.h" -#include "pxr/base/arch/fileSystem.h" - -#ifdef ENABLE_RAT -#include -#include -#endif - -#include -#include -#include - -namespace rpr { - -namespace { - -ImageDesc GetRprImageDesc(ImageFormat format, uint32_t width, uint32_t height, uint32_t depth = 1) { - int bytesPerComponent = 1; - if (format.type == RPR_COMPONENT_TYPE_FLOAT16) { - bytesPerComponent = 2; - } else if (format.type == RPR_COMPONENT_TYPE_FLOAT32) { - bytesPerComponent = 4; - } - - ImageDesc desc = {}; - desc.image_width = width; - desc.image_height = height; - desc.image_depth = depth; - desc.image_row_pitch = width * format.num_components * bytesPerComponent; - desc.image_slice_pitch = desc.image_row_pitch * height; - - return desc; -} - -} // namespace anonymous - -Image* CreateImage(Context* context, uint32_t width, uint32_t height, ImageFormat format, void const* data, rpr::Status* status) { - return context->CreateImage(format, GetRprImageDesc(format, width, height), data, status); -} - -Image* CreateImage(Context* context, char const* path, bool forceLinearSpace) { - PXR_NAMESPACE_USING_DIRECTIVE - -#ifdef ENABLE_RAT - auto dot = strrchr(path, '.'); - if (dot && strcmp(dot, ".rat") == 0) { - auto ratImage = std::unique_ptr(IMG_File::open(path)); - if (!ratImage) { - TF_RUNTIME_ERROR("Failed to load image %s", path); - } - - UT_Array images; - std::shared_ptr deferImagesRelease(nullptr, [&images](...) { - for (auto image : images) { - delete image; - } - }); - if (!ratImage->readImages(images) || - images.isEmpty()) { - TF_RUNTIME_ERROR("Failed to load image %s", path); - } - - // XXX: use the only first image, find out what to do with other images - auto image = images[0]; - - rpr_image_format format = {}; - if (image->getPacking() == PACK_SINGLE) { - format.num_components = 1; - } else if (image->getPacking() == PACK_DUAL) { - format.num_components = 2; - } else if (image->getPacking() == PACK_RGB) { - format.num_components = 3; - } else if (image->getPacking() == PACK_RGBA) { - format.num_components = 4; - } else { - TF_RUNTIME_ERROR("Failed to load image %s: unsupported RAT packing", path); - } - - if (image->getFormat() == PXL_INT8) { - format.type = RPR_COMPONENT_TYPE_UINT8; - } else if (image->getFormat() == PXL_FLOAT16) { - format.type = RPR_COMPONENT_TYPE_FLOAT16; - } else if (image->getFormat() == PXL_FLOAT32) { - format.type = RPR_COMPONENT_TYPE_FLOAT32; - } else { - TF_RUNTIME_ERROR("Failed to load image %s: unsupported RAT format", path); - } - - ImageDesc desc = GetRprImageDesc(format, image->getXres(), image->getYres()); - if (desc.image_height < 1 || - desc.image_width < 1) { - TF_RUNTIME_ERROR("Failed to load image %s: incorrect dimensions", path); - } - - // RAT image is flipped in Y axis - std::vector flippedImage; - flippedImage.reserve(image->getStride() * desc.image_height); - for (int y = 0; y < desc.image_height; ++y) { - auto srcData = reinterpret_cast(image->getPixels()) + image->getStride() * y; - auto dstData = &flippedImage[image->getStride() * (desc.image_height - 1 - y)]; - std::memcpy(dstData, srcData, image->getStride()); - } - - rpr::Status status; - auto rprImage = context->CreateImage(format, desc, flippedImage.data(), &status); - if (!rprImage) { - RPR_ERROR_CHECK(status, "Failed to create image from data", context); - return nullptr; - } - - if (!forceLinearSpace && - (image->getColorSpace() == PXL_CS_LINEAR || - image->getColorSpace() == PXL_CS_GAMMA2_2 || - image->getColorSpace() == PXL_CS_CUSTOM_GAMMA)) { - RPR_ERROR_CHECK(rprImage->SetGamma(image->getColorSpaceGamma()), "Failed to set image gamma", context); - } - - return rprImage; - } -#endif - - if (GlfImage::IsSupportedImageFile(path)) { - auto textureData = GlfUVTextureData::New(path, INT_MAX, 0, 0, 0, 0); - if (textureData && textureData->Read(0, false)) { - ImageFormat format = {}; - switch (textureData->GLType()) { - case GL_UNSIGNED_BYTE: - format.type = RPR_COMPONENT_TYPE_UINT8; - break; - case GL_HALF_FLOAT: - format.type = RPR_COMPONENT_TYPE_FLOAT16; - break; - case GL_FLOAT: - format.type = RPR_COMPONENT_TYPE_FLOAT32; - break; - default: - TF_RUNTIME_ERROR("Failed to create image %s. Unsupported pixel data GLtype: %#x", path, textureData->GLType()); - } - - switch (textureData->GLFormat()) { - case GL_RED: - format.num_components = 1; - break; - case GL_RGB: - format.num_components = 3; - break; - case GL_RGBA: - format.num_components = 4; - break; - default: - TF_RUNTIME_ERROR("Failed to create image %s. Unsupported pixel data GLformat: %#x", path, textureData->GLFormat()); - } - ImageDesc desc = GetRprImageDesc(format, textureData->ResizedWidth(), textureData->ResizedHeight()); - - rpr::Status status; - auto rprImage = context->CreateImage(format, desc, textureData->GetRawBuffer(), &status); - if (!rprImage) { - RPR_ERROR_CHECK(status, "Failed to create image from data", context); - return nullptr; - } - - auto internalFormat = textureData->GLInternalFormat(); - if (!forceLinearSpace && - (internalFormat == GL_SRGB || - internalFormat == GL_SRGB8 || - internalFormat == GL_SRGB_ALPHA || - internalFormat == GL_SRGB8_ALPHA8)) { - // XXX(RPR): sRGB formula is different from straight pow decoding, but it's the best we can do right now - RPR_ERROR_CHECK(rprImage->SetGamma(2.2f), "Failed to set image gamma"); - } - - return rprImage; - } - } - - return context->CreateImageFromFile(path); -} - -ImageFormat GetImageFormat(Image* image) { - return GetInfo(image, RPR_IMAGE_FORMAT); -} - -ImageDesc GetImageDesc(Image* image) { - return GetInfo(image, RPR_IMAGE_DESC); -} - -} // namespace rpr diff --git a/pxr/imaging/plugin/hdRpr/rprApi.cpp b/pxr/imaging/plugin/hdRpr/rprApi.cpp index fd6db4cd7..206790f13 100644 --- a/pxr/imaging/plugin/hdRpr/rprApi.cpp +++ b/pxr/imaging/plugin/hdRpr/rprApi.cpp @@ -13,7 +13,7 @@ limitations under the License. #include "rprApi.h" #include "rprApiAov.h" -#include "materialFactory.h" +#include "aovDescriptor.h" #include "rifcpp/rifFilter.h" #include "rifcpp/rifImage.h" @@ -21,12 +21,22 @@ limitations under the License. #include "config.h" #include "camera.h" -#include "imageCache.h" -#include "materialAdapter.h" #include "renderDelegate.h" #include "renderBuffer.h" #include "renderParam.h" +#include "pxr/imaging/glf/glew.h" +#include "pxr/imaging/glf/uvTextureData.h" + +#include "pxr/imaging/rprUsd/error.h" +#include "pxr/imaging/rprUsd/helpers.h" +#include "pxr/imaging/rprUsd/coreImage.h" +#include "pxr/imaging/rprUsd/imageCache.h" +#include "pxr/imaging/rprUsd/material.h" +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/imaging/rprUsd/contextMetadata.h" +#include "pxr/imaging/rprUsd/contextHelpers.h" + #include "pxr/base/gf/math.h" #include "pxr/base/gf/vec2f.h" #include "pxr/base/gf/rotation.h" @@ -34,16 +44,10 @@ limitations under the License. #include "pxr/base/plug/plugin.h" #include "pxr/base/plug/thisPlugin.h" #include "pxr/imaging/pxOsd/tokens.h" -#include "pxr/imaging/glf/glew.h" -#include "pxr/imaging/glf/uvTextureData.h" #include "pxr/usd/usdRender/tokens.h" #include "pxr/usd/usdGeom/tokens.h" #include "pxr/base/tf/envSetting.h" -#include "rpr/contextHelpers.h" -#include "rpr/imageHelpers.h" -#include "rpr/error.h" - #include "notify/message.h" #include @@ -63,21 +67,9 @@ limitations under the License. PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_ENV_SETTING(HDRPR_DISABLE_ALPHA, false, - "Disable alpha in color AOV. All alpha values would be 1.0"); - -TF_DEFINE_PRIVATE_TOKENS(HdRprAovTokens, - (albedo) \ - (variance) \ - (worldCoordinate) \ - (opacity) \ - ((primvarsSt, "primvars:st")) -); - namespace { -using RecursiveLockGuard = std::lock_guard; -std::recursive_mutex g_rprAccessMutex; +using LockGuard = std::lock_guard; bool ArchCreateDirectory(const char* path) { #ifdef WIN32 @@ -93,8 +85,101 @@ struct RenderSetting { bool isDirty; }; +GfVec4f ToVec4(GfVec3f const& vec, float w) { + return GfVec4f(vec[0], vec[1], vec[2], w); +} + +RprUsdRenderDeviceType ToRprUsd(RenderDeviceType configDeviceType) { + if (configDeviceType == kRenderDeviceCPU) { + return RprUsdRenderDeviceType::CPU; + } else if (configDeviceType == kRenderDeviceGPU) { + return RprUsdRenderDeviceType::GPU; + } else { + return RprUsdRenderDeviceType::Invalid; + } +} + } // namespace anonymous +HdFormat ConvertUsdRenderVarDataType(TfToken const& format) { + static std::map s_mapping = []() { + std::map ret; + + auto addMappingEntry = [&ret](std::string name, HdFormat format) { + ret[TfToken(name, TfToken::Immortal)] = format; + }; + + addMappingEntry("int", HdFormatInt32); + addMappingEntry("half", HdFormatFloat16); + addMappingEntry("half3", HdFormatFloat16Vec3); + addMappingEntry("half4", HdFormatFloat16Vec4); + addMappingEntry("float", HdFormatFloat32); + addMappingEntry("float3", HdFormatFloat32Vec3); + addMappingEntry("float4", HdFormatFloat32Vec4); + addMappingEntry("point3f", HdFormatFloat32Vec3); + addMappingEntry("vector3f", HdFormatFloat32Vec3); + addMappingEntry("normal3f", HdFormatFloat32Vec3); + addMappingEntry("color3f", HdFormatFloat32Vec3); + + return ret; + }(); + static std::string s_supportedFormats = []() { + std::string ret; + auto it = s_mapping.begin(); + for (size_t i = 0; i < s_mapping.size(); ++i, ++it) { + ret += it->first.GetString(); + if (i + 1 != s_mapping.size()) { + ret += ", "; + } + } + return ret; + }(); + + auto it = s_mapping.find(format); + if (it == s_mapping.end()) { + TF_RUNTIME_ERROR("Unsupported UsdRenderVar format. Supported formats: %s", s_supportedFormats.c_str()); + return HdFormatInvalid; + } + return it->second; +} + +class HdRprApiRawMaterial : public RprUsdMaterial { +public: + static HdRprApiRawMaterial* Create( + rpr::Context* rprContext, + rpr::MaterialNodeType nodeType, + std::vector> const& inputs) { + + rpr::Status status; + auto rprNode = rprContext->CreateMaterialNode(nodeType, &status); + if (!rprNode) { + RPR_ERROR_CHECK(status, "Failed to create material node", rprContext); + return nullptr; + } + + for (auto& input : inputs) { + auto& c = input.second; + if (RPR_ERROR_CHECK(rprNode->SetInput(input.first, c[0], c[1], c[2], c[3]), "Failed to set material input")) { + delete rprNode; + return nullptr; + } + }; + + return new HdRprApiRawMaterial(rprNode); + } + + ~HdRprApiRawMaterial() final = default; + +private: + HdRprApiRawMaterial(rpr::MaterialNode* surfaceNode) + : m_retainedSurfaceNode(surfaceNode) { + m_surfaceNode = surfaceNode; + } + +private: + std::unique_ptr m_retainedSurfaceNode; +}; + struct HdRprApiVolume { std::unique_ptr heteroVolume; std::unique_ptr volumeMaterial; @@ -102,13 +187,13 @@ struct HdRprApiVolume { std::unique_ptr densityGrid; std::unique_ptr emissionGrid; std::unique_ptr cubeMesh; - std::unique_ptr cubeMeshMaterial; + std::unique_ptr cubeMeshMaterial; GfMatrix4f voxelsTransform; }; struct HdRprApiEnvironmentLight { std::unique_ptr light; - std::unique_ptr image; + std::unique_ptr image; enum { kDetached, @@ -117,22 +202,9 @@ struct HdRprApiEnvironmentLight { } state = kDetached; }; -static const std::map kAovTokenToRprAov = { - {HdAovTokens->color, RPR_AOV_COLOR}, - {HdAovTokens->depth, RPR_AOV_DEPTH}, - {HdAovTokens->primId, RPR_AOV_OBJECT_ID}, - {HdAovTokens->normal, RPR_AOV_SHADING_NORMAL}, - {HdRprUtilsGetCameraDepthName(), RPR_AOV_DEPTH}, - {HdRprAovTokens->albedo, RPR_AOV_DIFFUSE_ALBEDO}, - {HdRprAovTokens->variance, RPR_AOV_VARIANCE}, - {HdRprAovTokens->worldCoordinate, RPR_AOV_WORLD_COORDINATE}, - {HdRprAovTokens->primvarsSt, RPR_AOV_UV}, - {HdRprAovTokens->opacity, RPR_AOV_OPACITY}, -}; - class HdRprApiImpl { public: - HdRprApiImpl(HdRenderDelegate* delegate) + HdRprApiImpl(HdRprDelegate* delegate) : m_delegate(delegate) { // Postpone initialization as further as possible to allow Hydra user to set custom render settings before creating a context //InitIfNeeded(); @@ -143,7 +215,8 @@ class HdRprApiImpl { return; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + static std::mutex s_rprInitMutex; + LockGuard lock(s_rprInitMutex); if (m_state != kStateUninitialized) { return; @@ -154,15 +227,13 @@ class HdRprApiImpl { InitRif(); InitScene(); InitCamera(); + InitAovs(); m_state = kStateRender; - } catch (rpr::Error& e) { - TF_RUNTIME_ERROR("%s", e.what()); - m_state = kStateInvalid; - } catch (rif::Error& e) { + } catch (RprUsdError& e) { TF_RUNTIME_ERROR("%s", e.what()); m_state = kStateInvalid; - } + } UpdateRestartRequiredMessageStatus(); } @@ -181,7 +252,7 @@ class HdRprApiImpl { VtIntArray newNormalIndexes; if (normals.empty()) { - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + if (m_rprContextMetadata.pluginType == kPluginHybrid) { // XXX (Hybrid): we need to generate geometry normals by ourself normals.reserve(newVpf.size()); newNormalIndexes.clear(); @@ -219,7 +290,7 @@ class HdRprApiImpl { VtIntArray newUvIndexes; if (uvs.empty()) { - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + if (m_rprContextMetadata.pluginType == kPluginHybrid) { newUvIndexes = newIndexes; uvs = VtVec2fArray(points.size(), GfVec2f(0.0f)); } @@ -242,7 +313,7 @@ class HdRprApiImpl { uvIndicesData = nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); rpr::Status status; auto mesh = m_rprContext->CreateShape( @@ -271,7 +342,7 @@ class HdRprApiImpl { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); rpr::Status status; auto mesh = m_rprContext->CreateShapeInstance(prototype, &status); @@ -293,12 +364,12 @@ class HdRprApiImpl { return; } - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + if (m_rprContextMetadata.pluginType == kPluginHybrid) { // Not supported return; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); bool dirty = true; @@ -319,7 +390,7 @@ class HdRprApiImpl { return; } - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + if (m_rprContextMetadata.pluginType == kPluginHybrid) { // Not supported return; } @@ -328,7 +399,7 @@ class HdRprApiImpl { RPR_SUBDIV_BOUNDARY_INTERFOP_TYPE_EDGE_AND_CORNER : RPR_SUBDIV_BOUNDARY_INTERFOP_TYPE_EDGE_ONLY; - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); bool dirty = true; @@ -344,21 +415,21 @@ class HdRprApiImpl { } } - void SetMeshMaterial(rpr::Shape* mesh, HdRprApiMaterial const* material, bool doublesided, bool displacementEnabled) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - m_materialFactory->AttachMaterial(mesh, material, doublesided, displacementEnabled); + void SetMeshMaterial(rpr::Shape* mesh, RprUsdMaterial const* material, bool displacementEnabled) { + LockGuard rprLock(m_rprContext->GetMutex()); + material->AttachTo(mesh, displacementEnabled); m_dirtyFlags |= ChangeTracker::DirtyScene; } - void SetCurveMaterial(rpr::Curve* curve, HdRprApiMaterial const* material) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - m_materialFactory->AttachMaterial(curve, material); + void SetCurveMaterial(rpr::Curve* curve, RprUsdMaterial const* material) { + LockGuard rprLock(m_rprContext->GetMutex()); + material->AttachTo(curve); m_dirtyFlags |= ChangeTracker::DirtyScene; } void SetCurveVisibility(rpr::Curve* curve, uint32_t visibilityMask) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + LockGuard rprLock(m_rprContext->GetMutex()); + if (m_rprContextMetadata.pluginType == kPluginHybrid) { // XXX (Hybrid): rprCurveSetVisibility not supported, emulate visibility using attach/detach if (visibilityMask) { m_scene->Attach(curve); @@ -382,7 +453,7 @@ class HdRprApiImpl { void Release(rpr::Curve* curve) { if (curve) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); if (!RPR_ERROR_CHECK(m_scene->Detach(curve), "Failed to detach curve from scene")) { m_dirtyFlags |= ChangeTracker::DirtyScene; @@ -393,7 +464,7 @@ class HdRprApiImpl { void Release(rpr::Shape* shape) { if (shape) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); if (!RPR_ERROR_CHECK(m_scene->Detach(shape), "Failed to detach mesh from scene")) { m_dirtyFlags |= ChangeTracker::DirtyScene; @@ -403,8 +474,8 @@ class HdRprApiImpl { } void SetMeshVisibility(rpr::Shape* mesh, uint32_t visibilityMask) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + LockGuard rprLock(m_rprContext->GetMutex()); + if (m_rprContextMetadata.pluginType == kPluginHybrid) { // XXX (Hybrid): rprShapeSetVisibility not supported, emulate visibility using attach/detach if (visibilityMask) { m_scene->Attach(mesh); @@ -428,7 +499,7 @@ class HdRprApiImpl { } void SetMeshId(rpr::Shape* mesh, uint32_t id) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); RPR_ERROR_CHECK(mesh->SetObjectID(id), "Failed to set mesh id"); } @@ -454,7 +525,7 @@ class HdRprApiImpl { creationFlags |= rpr::kCurveCreationFlagTapered; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); rpr::Status status; auto curve = m_rprContext->CreateCurve( @@ -480,7 +551,7 @@ class HdRprApiImpl { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); rpr::Status status; auto light = creator(&status); @@ -495,6 +566,7 @@ class HdRprApiImpl { } m_dirtyFlags |= ChangeTracker::DirtyScene; + m_numLights++; return light; } @@ -540,7 +612,7 @@ class HdRprApiImpl { } void SetDirectionalLightAttributes(rpr::DirectionalLight* light, GfVec3f const& color, float shadowSoftnessAngle) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); RPR_ERROR_CHECK(light->SetRadiantPower(color[0], color[1], color[2]), "Failed to set directional light color"); RPR_ERROR_CHECK(light->SetShadowSoftnessAngle(GfClamp(shadowSoftnessAngle, 0.0f, float(M_PI_4))), "Failed to set directional light color"); @@ -548,23 +620,44 @@ class HdRprApiImpl { template void SetLightColor(Light* light, GfVec3f const& color) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); RPR_ERROR_CHECK(light->SetRadiantPower(color[0], color[1], color[2]), "Failed to set light color"); } void Release(rpr::Light* light) { if (light) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); if (!RPR_ERROR_CHECK(m_scene->Detach(light), "Failed to detach light from scene")) { m_dirtyFlags |= ChangeTracker::DirtyScene; } delete light; + m_numLights--; + } + } + + RprUsdMaterial* CreateGeometryLightMaterial(GfVec3f const& emissionColor) { + LockGuard rprLock(m_rprContext->GetMutex()); + + auto material = HdRprApiRawMaterial::Create(m_rprContext.get(), RPR_MATERIAL_NODE_EMISSIVE, { + {RPR_MATERIAL_INPUT_COLOR, ToVec4(emissionColor, 1.0f)} + }); + if (material) m_numLights++; + return material; + } + + void ReleaseGeometryLightMaterial(RprUsdMaterial* material) { + if (material) { + m_numLights--; + Release(material); } } - HdRprApiEnvironmentLight* CreateEnvironmentLight(std::unique_ptr&& image, float intensity) { + HdRprApiEnvironmentLight* CreateEnvironmentLight(std::unique_ptr&& image, float intensity) { + // XXX (RPR): default environment light should be removed before creating a new one - RPR limitation + RemoveDefaultLight(); + auto envLight = new HdRprApiEnvironmentLight; rpr::Status status; @@ -572,14 +665,14 @@ class HdRprApiImpl { envLight->image = std::move(image); if (!envLight || - RPR_ERROR_CHECK(envLight->light->SetImage(envLight->image.get()), "Failed to set env light image", m_rprContext.get()) || + RPR_ERROR_CHECK(envLight->light->SetImage(envLight->image->GetRootImage()), "Failed to set env light image", m_rprContext.get()) || RPR_ERROR_CHECK(envLight->light->SetIntensityScale(intensity), "Failed to set env light intensity", m_rprContext.get())) { RPR_ERROR_CHECK(status, "Failed to create environment light"); delete envLight; return nullptr; } - if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + if (m_rprContextMetadata.pluginType == kPluginHybrid) { if ((status = m_scene->SetEnvironmentLight(envLight->light.get())) == RPR_SUCCESS) { envLight->state = HdRprApiEnvironmentLight::kAttachedAsEnvLight; } @@ -595,12 +688,13 @@ class HdRprApiImpl { } m_dirtyFlags |= ChangeTracker::DirtyScene; + m_numLights++; return envLight; } void Release(HdRprApiEnvironmentLight* envLight) { if (envLight) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); rpr::Status status; if (envLight->state == HdRprApiEnvironmentLight::kAttachedAsEnvLight) { @@ -613,6 +707,7 @@ class HdRprApiImpl { m_dirtyFlags |= ChangeTracker::DirtyScene; } delete envLight; + m_numLights--; } } @@ -621,9 +716,9 @@ class HdRprApiImpl { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); - auto image = std::unique_ptr(rpr::CreateImage(m_rprContext.get(), path.c_str())); + auto image = std::unique_ptr(RprUsdCoreImage::Create(m_rprContext.get(), path)); if (!image) { return nullptr; } @@ -638,11 +733,13 @@ class HdRprApiImpl { std::array backgroundColor = {color[0], color[1], color[2]}; rpr_image_format format = {3, RPR_COMPONENT_TYPE_FLOAT32}; - rpr_uint imageSize = m_rprContextMetadata.pluginType == rpr::kPluginHybrid ? 64 : 1; + rpr_uint imageSize = m_rprContextMetadata.pluginType == kPluginHybrid ? 64 : 1; std::vector> imageData(imageSize * imageSize, backgroundColor); + LockGuard rprLock(m_rprContext->GetMutex()); + rpr::Status status; - auto image = std::unique_ptr(rpr::CreateImage(m_rprContext.get(), imageSize, imageSize, format, imageData.data(), &status)); + auto image = std::unique_ptr(RprUsdCoreImage::Create(m_rprContext.get(), imageSize, imageSize, format, imageData.data(), &status)); if (!image) { RPR_ERROR_CHECK(status, "Failed to create image", m_rprContext.get()); return nullptr; @@ -652,7 +749,7 @@ class HdRprApiImpl { } void SetTransform(rpr::SceneObject* object, GfMatrix4f const& transform) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); if (!RPR_ERROR_CHECK(object->SetTransform(transform.GetArray(), false), "Fail set object transform")) { m_dirtyFlags |= ChangeTracker::DirtyScene; } @@ -771,7 +868,7 @@ class HdRprApiImpl { auto rprStartTransform = GfMatrix4f(startTransform); - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); RPR_ERROR_CHECK(shape->SetTransform(rprStartTransform.GetArray(), false), "Fail set shape transform"); RPR_ERROR_CHECK(shape->SetLinearMotion(linearMotion[0], linearMotion[1], linearMotion[2]), "Fail to set shape linear motion"); @@ -780,28 +877,95 @@ class HdRprApiImpl { m_dirtyFlags |= ChangeTracker::DirtyScene; } - HdRprApiMaterial* CreateMaterial(const MaterialAdapter& MaterialAdapter) { + RprUsdMaterial* CreateMaterial(HdSceneDelegate* sceneDelegate, HdMaterialNetworkMap const& materialNetwork) { + if (!m_rprContext) { + return nullptr; + } + + LockGuard rprLock(m_rprContext->GetMutex()); + return RprUsdMaterialRegistry::GetInstance().CreateMaterial(sceneDelegate, materialNetwork, m_rprContext.get(), m_imageCache.get()); + } + + RprUsdMaterial* CreatePointsMaterial(VtVec3fArray const& colors) { if (!m_rprContext) { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); - return m_materialFactory->CreateMaterial(MaterialAdapter.GetType(), MaterialAdapter); + LockGuard rprLock(m_rprContext->GetMutex()); + + class HdRprApiPointsMaterial : public RprUsdMaterial { + public: + HdRprApiPointsMaterial(VtVec3fArray const& colors, rpr::Context* context) { + rpr::Status status; + + rpr::BufferDesc bufferDesc; + bufferDesc.nb_element = colors.size(); + bufferDesc.element_type = RPR_BUFFER_ELEMENT_TYPE_FLOAT32; + bufferDesc.element_channel_size = 3; + + m_colorsBuffer.reset(context->CreateBuffer(bufferDesc, colors.data(), &status)); + if (!m_colorsBuffer) { + RPR_ERROR_CHECK_THROW(status, "Failed to create colors buffer"); + } + + m_objectIdLookupNode.reset(context->CreateMaterialNode(RPR_MATERIAL_NODE_INPUT_LOOKUP, &status)); + if (!m_objectIdLookupNode) { + RPR_ERROR_CHECK_THROW(status, "Failed to create objectId lookup node"); + } + + status = m_objectIdLookupNode->SetInput(RPR_MATERIAL_INPUT_VALUE, RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID); + if (status != RPR_SUCCESS) { + RPR_ERROR_CHECK_THROW(status, "Failed to set lookup node input value"); + } + + m_bufferSamplerNode.reset(context->CreateMaterialNode(RPR_MATERIAL_NODE_BUFFER_SAMPLER, &status)); + if (!m_bufferSamplerNode) { + RPR_ERROR_CHECK_THROW(status, "Failed to create buffer sampler node"); + } + RPR_ERROR_CHECK_THROW(m_bufferSamplerNode->SetInput(RPR_MATERIAL_INPUT_DATA, m_colorsBuffer.get()), "Failed to set buffer sampler node input data"); + RPR_ERROR_CHECK_THROW(m_bufferSamplerNode->SetInput(RPR_MATERIAL_INPUT_UV, m_objectIdLookupNode.get()), "Failed to set buffer sampler node input uv"); + + m_uberNode.reset(context->CreateMaterialNode(RPR_MATERIAL_NODE_UBERV2, &status)); + if (!m_uberNode) { + RPR_ERROR_CHECK_THROW(status, "Failed to create uber node"); + } + RPR_ERROR_CHECK_THROW(m_uberNode->SetInput(RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, m_bufferSamplerNode.get()), "Failed to set root material diffuse color"); + + m_surfaceNode = m_uberNode.get(); + } + + ~HdRprApiPointsMaterial() final = default; + + private: + std::unique_ptr m_colorsBuffer; + std::unique_ptr m_objectIdLookupNode; + std::unique_ptr m_bufferSamplerNode; + std::unique_ptr m_uberNode; + }; + + try { + return new HdRprApiPointsMaterial(colors, m_rprContext.get()); + } catch (RprUsdError& e) { + TF_RUNTIME_ERROR("Failed to create points material: %s", e.what()); + return nullptr; + } } - HdRprApiMaterial* CreatePointsMaterial(VtVec3fArray const& colors) { + RprUsdMaterial* CreateRawMaterial( + rpr::MaterialNodeType nodeType, + std::vector> const& inputs) { if (!m_rprContext) { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); - return m_materialFactory->CreatePointsMaterial(colors); + LockGuard rprLock(m_rprContext->GetMutex()); + return HdRprApiRawMaterial::Create(m_rprContext.get(), nodeType, inputs); } - void Release(HdRprApiMaterial* material) { + void Release(RprUsdMaterial* material) { if (material) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - m_materialFactory->Release(material); + LockGuard rprLock(m_rprContext->GetMutex()); + delete material; } } @@ -813,14 +977,19 @@ class HdRprApiImpl { return nullptr; } - RecursiveLockGuard rprLock(g_rprAccessMutex); + auto cubeMesh = CreateCubeMesh(1.0f, 1.0f, 1.0f); + if (!cubeMesh) { + return nullptr; + } + + LockGuard rprLock(m_rprContext->GetMutex()); auto rprApiVolume = new HdRprApiVolume; - MaterialAdapter matAdapter(EMaterialType::TRANSPERENT, - MaterialParams{{HdPrimvarRoleTokens->color, VtValue(GfVec4f(1.0f))}}); - rprApiVolume->cubeMeshMaterial.reset(CreateMaterial(matAdapter)); - rprApiVolume->cubeMesh.reset(CreateCubeMesh(1.0f, 1.0f, 1.0f)); + rprApiVolume->cubeMeshMaterial.reset(HdRprApiRawMaterial::Create(m_rprContext.get(), RPR_MATERIAL_NODE_TRANSPARENT, { + {RPR_MATERIAL_INPUT_COLOR, GfVec4f(1.0f)} + })); + rprApiVolume->cubeMesh.reset(cubeMesh); rpr::Status densityGridStatus; rprApiVolume->densityGrid.reset(m_rprContext->CreateGrid(gridSize[0], gridSize[1], gridSize[2], @@ -863,7 +1032,10 @@ class HdRprApiImpl { RPR_ERROR_CHECK(albedoGridStatus, "Failed to create albedo grid"); RPR_ERROR_CHECK(emissionGridStatus, "Failed to create emission grid"); RPR_ERROR_CHECK(status, "Failed to create hetero volume"); + + m_scene->Detach(rprApiVolume->heteroVolume.get()); delete rprApiVolume; + return nullptr; } @@ -892,7 +1064,7 @@ class HdRprApiImpl { if (rprApiVolume->volumeMaterial) { RPR_ERROR_CHECK(rprApiVolume->cubeMesh->SetVolumeMaterial(rprApiVolume->volumeMaterial.get()), "Failed to set volume material"); } - SetMeshMaterial(rprApiVolume->cubeMesh.get(), rprApiVolume->cubeMeshMaterial.get(), true, false); + rprApiVolume->cubeMeshMaterial->AttachTo(rprApiVolume->cubeMesh.get(), false); rprApiVolume->voxelsTransform = GfMatrix4f(1.0f); rprApiVolume->voxelsTransform.SetScale(GfCompMult(voxelSize, gridSize)); @@ -904,7 +1076,7 @@ class HdRprApiImpl { void SetTransform(HdRprApiVolume* volume, GfMatrix4f const& transform) { auto t = transform * volume->voxelsTransform; - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); RPR_ERROR_CHECK(volume->cubeMesh->SetTransform(t.data(), false), "Failed to set cubeMesh transform"); RPR_ERROR_CHECK(volume->heteroVolume->SetTransform(t.data(), false), "Failed to set heteroVolume transform"); m_dirtyFlags |= ChangeTracker::DirtyScene; @@ -912,7 +1084,7 @@ class HdRprApiImpl { void Release(HdRprApiVolume* volume) { if (volume) { - RecursiveLockGuard rprLock(g_rprAccessMutex); + LockGuard rprLock(m_rprContext->GetMutex()); m_scene->Detach(volume->heteroVolume.get()); delete volume; @@ -928,8 +1100,6 @@ class HdRprApiImpl { return; } - RecursiveLockGuard rprLock(g_rprAccessMutex); - if (m_hdCamera != hdRprCamera) { m_hdCamera = hdRprCamera; m_dirtyFlags |= ChangeTracker::DirtyHdCamera; @@ -953,15 +1123,11 @@ class HdRprApiImpl { } void SetViewportSize(GfVec2i const& size) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - m_viewportSize = size; m_dirtyFlags |= ChangeTracker::DirtyViewport; } void SetAovBindings(HdRenderPassAovBindingVector const& aovBindings) { - RecursiveLockGuard rprLock(g_rprAccessMutex); - m_aovBindings = aovBindings; m_dirtyFlags |= ChangeTracker::DirtyAOVBindings; } @@ -970,43 +1136,50 @@ class HdRprApiImpl { return m_aovBindings; } - void ResolveFramebuffers(std::vector> const& outputRenderBuffers) { + void ResolveFramebuffers(bool* firstResolve) { + std::vector> computedAovsToResolve; for (auto& aovEntry : m_aovRegistry) { auto aov = aovEntry.second.lock(); if (TF_VERIFY(aov)) { - aov->Resolve(); + if (*firstResolve || aov->GetDesc().multiSampled) { + if (aov->GetDesc().computed) { + // Computed AOVs depend on raw AOVs + computedAovsToResolve.push_back(aov); + } else { + aov->Resolve(); + } + } } } + for (auto& aov : computedAovsToResolve) { + aov->Resolve(); + } if (m_rifContext) { m_rifContext->ExecuteCommandQueue(); } - for (int i = 0; i < m_aovBindings.size(); ++i) { - if (outputRenderBuffers[i].first) { - auto aovIter = m_boundAovs.find(m_aovBindings[i].aovName); - if (aovIter != m_boundAovs.end()) { - aovIter->second->GetData(outputRenderBuffers[i].first, outputRenderBuffers[i].second); - } + for (auto& outRb : m_outputRenderBuffers) { + if (!outRb.mappedData) { + continue; + } + + if (*firstResolve || outRb.rprAov->GetDesc().multiSampled) { + outRb.rprAov->GetData(outRb.mappedData, outRb.mappedDataSize); } } + + *firstResolve = false; } void Update() { - RecursiveLockGuard rprLock(g_rprAccessMutex); - - m_imageCache->GarbageCollectIfNeeded(); - auto rprRenderParam = static_cast(m_delegate->GetRenderParam()); // In case there is no Lights in scene - create default - if (!rprRenderParam->HasLights()) { - if (!m_defaultLightObject) { - const GfVec3f k_defaultLightColor(0.5f, 0.5f, 0.5f); - m_defaultLightObject.reset(CreateEnvironmentLight(k_defaultLightColor, 1.f)); - } + if (m_numLights == 0) { + AddDefaultLight(); } else { - m_defaultLightObject = nullptr; + RemoveDefaultLight(); } bool clearAovs = false; @@ -1041,17 +1214,16 @@ class HdRprApiImpl { config->IsDirty(HdRprConfig::DirtyRenderQuality)) { bool restartRequired = false; if (config->IsDirty(HdRprConfig::DirtyDevice)) { - if (int(m_rprContextMetadata.renderDeviceType) != config->GetRenderDevice()) { + if (m_rprContextMetadata.renderDeviceType != ToRprUsd(config->GetRenderDevice())) { restartRequired = true; } } if (config->IsDirty(HdRprConfig::DirtyRenderQuality)) { auto quality = config->GetRenderQuality(); - + auto newPlugin = GetPluginType(quality); auto activePlugin = m_rprContextMetadata.pluginType; - if ((activePlugin == rpr::kPluginTahoe && quality < kRenderQualityFull) || - (activePlugin == rpr::kPluginHybrid && quality == kRenderQualityFull)) { + if (newPlugin != activePlugin) { restartRequired = true; } } @@ -1061,8 +1233,10 @@ class HdRprApiImpl { if (m_state == kStateRender && config->IsDirty(HdRprConfig::DirtyRenderQuality)) { RenderQualityType currentRenderQuality; - if (m_rprContextMetadata.pluginType == rpr::kPluginTahoe) { + if (m_rprContextMetadata.pluginType == kPluginTahoe) { currentRenderQuality = kRenderQualityFull; + } else if (m_rprContextMetadata.pluginType == kPluginNorthstar) { + currentRenderQuality = kRenderQualityNorthstar; } else { rpr_uint currentHybridQuality = RPR_RENDER_QUALITY_HIGH; size_t dummy; @@ -1085,11 +1259,30 @@ class HdRprApiImpl { } } + rpr_uint GetRprRenderMode(RenderModeType mode) { + static std::map s_mapping = { + {kRenderModeGlobalIllumination, RPR_RENDER_MODE_GLOBAL_ILLUMINATION}, + {kRenderModeDirectIllumination, RPR_RENDER_MODE_DIRECT_ILLUMINATION}, + {kRenderModeWireframe, RPR_RENDER_MODE_WIREFRAME}, + {kRenderModeMaterialIndex, RPR_RENDER_MODE_MATERIAL_INDEX}, + {kRenderModePosition, RPR_RENDER_MODE_POSITION}, + {kRenderModeNormal, RPR_RENDER_MODE_NORMAL}, + {kRenderModeTexcoord, RPR_RENDER_MODE_TEXCOORD}, + {kRenderModeAmbientOcclusion, RPR_RENDER_MODE_AMBIENT_OCCLUSION}, + {kRenderModeDiffuse, RPR_RENDER_MODE_DIFFUSE}, + }; + + auto it = s_mapping.find(mode); + if (it == s_mapping.end()) return RPR_RENDER_MODE_GLOBAL_ILLUMINATION; + return it->second; + } + void UpdateTahoeSettings(HdRprConfig const& preferences, bool force) { if (preferences.IsDirty(HdRprConfig::DirtyAdaptiveSampling) || force) { m_varianceThreshold = preferences.GetVarianceThreshold(); + m_minSamples = preferences.GetMinAdaptiveSamples(); RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_ADAPTIVE_SAMPLING_THRESHOLD, m_varianceThreshold), "Failed to set as.threshold"); - RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_ADAPTIVE_SAMPLING_MIN_SPP, preferences.GetMinAdaptiveSamples()), "Failed to set as.minspp"); + RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_ADAPTIVE_SAMPLING_MIN_SPP, m_minSamples), "Failed to set as.minspp"); if (m_varianceThreshold > 0.0f) { if (!m_internalAovs.count(HdRprAovTokens->variance)) { @@ -1122,11 +1315,20 @@ class HdRprApiImpl { } if (preferences.IsDirty(HdRprConfig::DirtyInteractiveMode)) { - bool is_interactive = preferences.GetInteractiveMode(); - auto maxRayDepth = is_interactive ? preferences.GetInteractiveMaxRayDepth() : preferences.GetMaxRayDepth(); + m_isInteractive = preferences.GetInteractiveMode(); + auto maxRayDepth = m_isInteractive ? preferences.GetInteractiveMaxRayDepth() : preferences.GetMaxRayDepth(); RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_MAX_RECURSION, maxRayDepth), "Failed to set max recursion"); - RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_PREVIEW, int(is_interactive)), "Failed to set preview mode"); + RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_PREVIEW, uint32_t(m_isInteractive)), "Failed to set preview mode"); + + m_dirtyFlags |= ChangeTracker::DirtyScene; + } + if (preferences.IsDirty(HdRprConfig::DirtyRenderMode)) { + auto renderMode = preferences.GetRenderMode(); + RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_RENDER_MODE, GetRprRenderMode(renderMode)), "Failed to set render mode"); + if (renderMode == kRenderModeAmbientOcclusion) { + RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_AO_RAY_LENGTH, preferences.GetAoRadius()), "Failed to set ambient occlusion radius"); + } m_dirtyFlags |= ChangeTracker::DirtyScene; } } @@ -1143,17 +1345,24 @@ class HdRprApiImpl { void UpdateSettings(HdRprConfig const& preferences, bool force = false) { if (preferences.IsDirty(HdRprConfig::DirtySampling) || force) { m_maxSamples = preferences.GetMaxSamples(); - if (m_maxSamples < m_iter) { + if (m_maxSamples < m_numSamples) { // Force framebuffers clear to render required number of samples m_dirtyFlags |= ChangeTracker::DirtyScene; } } + if (preferences.IsDirty(HdRprConfig::DirtyAlpha) || force) { + m_isAlphaEnabled = preferences.GetEnableAlpha(); + + UpdateColorAlpha(); + } + m_currentRenderQuality = preferences.GetRenderQuality(); - if (m_rprContextMetadata.pluginType == rpr::kPluginTahoe) { + if (m_rprContextMetadata.pluginType == kPluginTahoe || + m_rprContextMetadata.pluginType == kPluginNorthstar) { UpdateTahoeSettings(preferences, force); - } else if (m_rprContextMetadata.pluginType == rpr::kPluginHybrid) { + } else if (m_rprContextMetadata.pluginType == kPluginHybrid) { UpdateHybridSettings(preferences, force); } } @@ -1264,47 +1473,115 @@ class HdRprApiImpl { float fstop = 0.0f; m_hdCamera->GetFStop(&fstop); - if (fstop == 0.0f) { fstop = std::numeric_limits::max(); } + bool dofEnabled = fstop != 0.0f && fstop != std::numeric_limits::max(); + + if (dofEnabled) { + int apertureBlades = m_hdCamera->GetApertureBlades(); + if (apertureBlades < 4 || apertureBlades > 32) { + apertureBlades = 16; + } + RPR_ERROR_CHECK(m_camera->SetApertureBlades(apertureBlades), "Failed to set camera aperture blades"); + } else { + fstop = std::numeric_limits::max(); + } RPR_ERROR_CHECK(m_camera->SetFStop(fstop), "Failed to set camera FStop"); + // Convert to millimeters + focalLength *= 1e3f; + sensorWidth *= 1e3f; + sensorHeight *= 1e3f; + RPR_ERROR_CHECK(m_camera->SetFocalLength(focalLength), "Fail to set camera focal length"); RPR_ERROR_CHECK(m_camera->SetSensorSize(sensorWidth, sensorHeight), "Failed to set camera sensor size"); } } + VtValue GetAovSetting(TfToken const& settingName, HdRenderPassAovBinding const& aovBinding) { + auto settingsIt = aovBinding.aovSettings.find(settingName); + if (settingsIt == aovBinding.aovSettings.end()) { + return VtValue(); + } + return settingsIt->second; + } + + bool GetAovBindingInfo(HdRenderPassAovBinding const& aovBinding, TfToken* aovName, HdFormat* format) { + // Check for UsdRenderVar: take aovName from `sourceName`, format from `dataType` + auto sourceType = GetAovSetting(UsdRenderTokens->sourceType, aovBinding); + if (sourceType == UsdRenderTokens->raw) { + auto name = TfToken(GetAovSetting(UsdRenderTokens->sourceName, aovBinding).Get()); + auto& aovDesc = HdRprAovRegistry::GetInstance().GetAovDesc(name); + if (aovDesc.id != kAovNone && aovDesc.format != HdFormatInvalid) { + *aovName = name; + *format = ConvertUsdRenderVarDataType(GetAovSetting(UsdRenderTokens->dataType, aovBinding).Get()); + return *format != HdFormatInvalid; + } else { + TF_RUNTIME_ERROR("Unsupported UsdRenderVar sourceName: %s", name.GetText()); + } + } + + // Default AOV: aovName from `aovBinding.aovName`, format is controlled by HdRenderBuffer + auto& aovDesc = HdRprAovRegistry::GetInstance().GetAovDesc(aovBinding.aovName); + if (aovDesc.id != kAovNone && aovDesc.format != HdFormatInvalid) { + *aovName = aovBinding.aovName; + *format = aovBinding.renderBuffer->GetFormat(); + return true; + } + + return false; + } + void UpdateAovs(HdRprRenderParam* rprRenderParam, RenderSetting enableDenoise, RenderSetting tonemap, bool clearAovs) { if (m_dirtyFlags & ChangeTracker::DirtyAOVBindings) { - auto retainedBoundAovs = std::move(m_boundAovs); - for (auto& aovBinding : m_aovBindings) { - if (auto rb = aovBinding.renderBuffer) { - auto boundAovIter = retainedBoundAovs.find(aovBinding.aovName); - if (boundAovIter == retainedBoundAovs.end()) { - if (auto aov = CreateAov(aovBinding.aovName, rb->GetWidth(), rb->GetHeight(), rb->GetFormat())) { - m_boundAovs[aovBinding.aovName] = aov; - } - } else { - m_boundAovs[aovBinding.aovName] = boundAovIter->second; + auto retainedOutputRenderBuffers = std::move(m_outputRenderBuffers); + auto registerAovBinding = [&retainedOutputRenderBuffers, this](HdRenderPassAovBinding const& aovBinding) { + TfToken aovName; + HdFormat aovFormat; + if (!GetAovBindingInfo(aovBinding, &aovName, &aovFormat)) { + return false; + } - // Update underlying format if needed - boundAovIter->second->Resize(rb->GetWidth(), rb->GetHeight(), rb->GetFormat()); - } + OutputRenderBuffer outRb; + outRb.aovName = aovName; + outRb.aovBinding = &aovBinding; + + auto outputRenderBufferIt = std::find_if(retainedOutputRenderBuffers.begin(), retainedOutputRenderBuffers.end(), + [&aovName](OutputRenderBuffer const& buffer) { + return buffer.aovName == aovName; + }); + if (outputRenderBufferIt == retainedOutputRenderBuffers.end()) { + // Create new RPR AOV + outRb.rprAov = CreateAov(aovName, aovBinding.renderBuffer->GetWidth(), aovBinding.renderBuffer->GetHeight(), aovFormat); + } else { + // Reuse previously created RPR AOV + std::swap(outRb.rprAov, outputRenderBufferIt->rprAov); + // Update underlying format if needed + outRb.rprAov->Resize(aovBinding.renderBuffer->GetWidth(), aovBinding.renderBuffer->GetHeight(), aovFormat); } + + if (!outRb.rprAov) return false; + + m_outputRenderBuffers.push_back(std::move(outRb)); + return true; + }; + + for (auto& aovBinding : m_aovBindings) { + if (!aovBinding.renderBuffer) { + continue; + } + auto rprRenderBuffer = static_cast(aovBinding.renderBuffer); + rprRenderBuffer->SetStatus(registerAovBinding(aovBinding)); } } if (m_dirtyFlags & ChangeTracker::DirtyViewport) { - for (auto& aovEntry : m_internalAovs) { - aovEntry.second->Resize(m_viewportSize[0], m_viewportSize[1], aovEntry.second->GetFormat()); - } - for (auto& aovBinding : m_aovBindings) { - if (auto rb = aovBinding.renderBuffer) { - auto boundAovIter = m_boundAovs.find(aovBinding.aovName); - if (boundAovIter != m_boundAovs.end()) { - boundAovIter->second->Resize(rb->GetWidth(), rb->GetHeight(), rb->GetFormat()); - } + for (auto it = m_aovRegistry.begin(); it != m_aovRegistry.end();) { + if (auto aov = it->second.lock()) { + aov->Resize(m_viewportSize[0], m_viewportSize[1], aov->GetFormat()); + ++it; + } else { + it = m_aovRegistry.erase(it); } } - // Size of bound AOVs controled by aovBinding's renderBuffer } if (m_dirtyFlags & ChangeTracker::DirtyScene || @@ -1337,7 +1614,7 @@ class HdRprApiImpl { } if (clearAovs) { - m_iter = 0; + m_numSamples = 0; m_activePixels = -1; } } @@ -1358,24 +1635,41 @@ class HdRprApiImpl { } rif::FilterType filterType = rif::FilterType::EawDenoise; - if (m_rprContextMetadata.renderDeviceType == rpr::kRenderDeviceGPU) { + if (m_rprContextMetadata.renderDeviceType == RprUsdRenderDeviceType::GPU) { filterType = rif::FilterType::AIDenoise; } if (filterType == rif::FilterType::EawDenoise) { colorAov->EnableEAWDenoise(m_internalAovs.at(HdRprAovTokens->albedo), m_internalAovs.at(HdAovTokens->normal), - m_internalAovs.at(HdRprUtilsGetCameraDepthName()), + m_internalAovs.at(HdRprGetCameraDepthAovName()), m_internalAovs.at(HdAovTokens->primId), m_internalAovs.at(HdRprAovTokens->worldCoordinate)); } else { colorAov->EnableAIDenoise(m_internalAovs.at(HdRprAovTokens->albedo), m_internalAovs.at(HdAovTokens->normal), - m_internalAovs.at(HdRprUtilsGetCameraDepthName())); + m_internalAovs.at(HdRprGetCameraDepthAovName())); } } - void RenderImpl(HdRprRenderThread* renderThread, std::vector> const& outputRenderBuffers) { + void RenderImpl(HdRprRenderThread* renderThread) { + int numSamplesPerIter = 1; + + const bool isBatch = m_delegate->IsBatch(); + // XXX(RPR): until FIR-1681 is not resolved we should stick to progressive renders otherwise singlesampled AOV output will be broken + const bool isProgressive = true /*m_delegate->IsProgressive()*/; + if (isBatch && !isProgressive) { + // Render as many samples as possible per Render call + if (m_varianceThreshold > 0.0f) { + numSamplesPerIter = m_minSamples; + } else { + numSamplesPerIter = m_maxSamples; + } + } + m_rprContext->SetParameter(RPR_CONTEXT_ITERATIONS, numSamplesPerIter); + + int frameCount = 0; + bool firstResolve = true; bool stopRequested = false; while (!IsConverged() || stopRequested) { renderThread->WaitUntilPaused(); @@ -1384,36 +1678,51 @@ class HdRprApiImpl { break; } - if (m_rprContextMetadata.pluginType != rpr::kPluginHybrid) { - RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_FRAMECOUNT, m_iter), "Failed to set framecount"); + if (m_rprContextMetadata.pluginType != kPluginHybrid) { + RPR_ERROR_CHECK(m_rprContext->SetParameter(RPR_CONTEXT_FRAMECOUNT, frameCount++), "Failed to set framecount"); } auto status = m_rprContext->Render(); if (status == RPR_ERROR_ABORTED || - RPR_ERROR_CHECK(status, "Fail contex render framebuffer")) { + RPR_ERROR_CHECK(status, "Fail context render framebuffer", m_rprContext.get())) { stopRequested = true; break; } - m_iter++; + m_numSamples += numSamplesPerIter; if (m_varianceThreshold > 0.0f) { + if (isBatch && !isProgressive && m_numSamples == m_minSamples) { + numSamplesPerIter = 1; + m_rprContext->SetParameter(RPR_CONTEXT_ITERATIONS, numSamplesPerIter); + } + if (RPR_ERROR_CHECK(m_rprContext->GetInfo(RPR_CONTEXT_ACTIVE_PIXEL_COUNT, sizeof(m_activePixels), &m_activePixels, NULL), "Failed to query active pixels")) { m_activePixels = -1; } + } else if (!isBatch && !m_isInteractive && + m_rprContextMetadata.pluginType == kPluginNorthstar && m_numSamples > 1) { + // Progressively increase RPR_CONTEXT_ITERATIONS because it highly improves Northstar's performance + numSamplesPerIter *= 2; + + // But do not oversample the image + int numSamplesLeft = m_maxSamples - m_numSamples; + numSamplesPerIter = std::min(numSamplesPerIter, numSamplesLeft); + + m_rprContext->SetParameter(RPR_CONTEXT_ITERATIONS, numSamplesPerIter); } - if (!IsConverged()) { + if (!isBatch && !IsConverged()) { // Last framebuffer resolve will be called after "while" in case framebuffer is converged. // We do not resolve framebuffers in case user requested render stop - ResolveFramebuffers(outputRenderBuffers); + ResolveFramebuffers(&firstResolve); } stopRequested = renderThread->IsStopRequested(); } if (!stopRequested) { - ResolveFramebuffers(outputRenderBuffers); + ResolveFramebuffers(&firstResolve); } } @@ -1449,23 +1758,22 @@ class HdRprApiImpl { } } - std::vector> outputRenderBuffers; - for (auto& aovBinding : m_aovBindings) { - if (auto rb = static_cast(aovBinding.renderBuffer)) { + for (auto& outRb : m_outputRenderBuffers) { + if (auto rb = static_cast(outRb.aovBinding->renderBuffer)) { if (rb->GetWidth() != m_viewportSize[0] || rb->GetHeight() != m_viewportSize[1]) { TF_RUNTIME_ERROR("%s renderBuffer has inconsistent render buffer size: %ux%u. Expected: %dx%d", - aovBinding.aovName.GetText(), rb->GetWidth(), rb->GetHeight(), m_viewportSize[0], m_viewportSize[1]); - outputRenderBuffers.emplace_back(nullptr, 0u); + outRb.aovName.GetText(), rb->GetWidth(), rb->GetHeight(), m_viewportSize[0], m_viewportSize[1]); + outRb.mappedData = nullptr; } else { - size_t size = rb->GetWidth() * rb->GetHeight() * HdDataSizeOfFormat(rb->GetFormat()); - outputRenderBuffers.emplace_back(rb->Map(), size); + outRb.mappedData = rb->Map(); + outRb.mappedDataSize = HdDataSizeOfFormat(outRb.rprAov->GetFormat()) * rb->GetWidth() * rb->GetHeight(); } } } if (m_state == kStateRender) { try { - RenderImpl(renderThread, outputRenderBuffers); + RenderImpl(renderThread); } catch (std::runtime_error const& e) { TF_RUNTIME_ERROR("Failed to render frame: %s", e.what()); } @@ -1500,6 +1808,14 @@ Don't show this message again? } } + void CommitResources() { + if (!m_rprContext) { + return; + } + + RprUsdMaterialRegistry::GetInstance().CommitResources(m_imageCache.get()); + } + void Render(HdRprRenderThread* renderThread) { RenderFrame(renderThread); @@ -1517,7 +1833,7 @@ Don't show this message again? } int GetNumCompletedSamples() const { - return m_iter; + return m_numSamples; } int GetNumActivePixels() const { @@ -1545,22 +1861,18 @@ Don't show this message again? bool IsConverged() const { if (m_currentRenderQuality < kRenderQualityHigh) { - return m_iter == 1; + return m_numSamples == 1; } - return m_iter >= m_maxSamples || m_activePixels == 0; + return m_numSamples >= m_maxSamples || m_activePixels == 0; } bool IsGlInteropEnabled() const { return m_rprContext && m_rprContextMetadata.isGlInteropEnabled; } - bool IsAovFormatConversionAvailable() const { - return m_rifContext != nullptr; - } - bool IsArbitraryShapedLightSupported() const { - return m_rprContextMetadata.pluginType != rpr::kPluginHybrid; + return m_rprContextMetadata.pluginType != kPluginHybrid; } int GetCurrentRenderQuality() const { @@ -1573,6 +1885,16 @@ Don't show this message again? } private: + static RprUsdPluginType GetPluginType(RenderQualityType renderQuality) { + if (renderQuality == kRenderQualityFull) { + return kPluginTahoe; + } else if (renderQuality == kRenderQualityNorthstar) { + return kPluginNorthstar; + } else { + return kPluginHybrid; + } + } + void InitRpr() { RenderQualityType renderQuality; { @@ -1582,12 +1904,12 @@ Don't show this message again? config->Sync(m_delegate); renderQuality = config->GetRenderQuality(); - m_rprContextMetadata.renderDeviceType = static_cast(config->GetRenderDevice()); + m_rprContextMetadata.renderDeviceType = ToRprUsd(config->GetRenderDevice()); } - m_rprContextMetadata.pluginType = renderQuality == kRenderQualityFull ? rpr::kPluginTahoe : rpr::kPluginHybrid; + m_rprContextMetadata.pluginType = GetPluginType(renderQuality); auto cachePath = HdRprApi::GetCachePath(); - m_rprContext.reset(rpr::CreateContext(cachePath.c_str(), &m_rprContextMetadata)); + m_rprContext.reset(RprUsdCreateContext(cachePath.c_str(), &m_rprContextMetadata)); if (!m_rprContext) { RPR_THROW_ERROR_MSG("Failed to create RPR context"); } @@ -1600,8 +1922,7 @@ Don't show this message again? UpdateSettings(*config, true); } - m_imageCache.reset(new ImageCache(m_rprContext.get())); - m_materialFactory.reset(new RprMaterialFactory(m_imageCache.get())); + m_imageCache.reset(new RprUsdImageCache(m_rprContext.get())); } bool ValidateRifModels(std::string const& modelsPath) { @@ -1628,32 +1949,25 @@ Don't show this message again? } m_rifContext = rif::Context::Create(m_rprContext.get(), m_rprContextMetadata, modelsPath); - if (!m_rifContext) { - return; - } + } + void InitAovs() { auto initInternalAov = [this](TfToken const& name) { - if (auto aov = CreateAov(name)) { + auto& aovDesc = HdRprAovRegistry::GetInstance().GetAovDesc(name); + if (auto aov = CreateAov(name, 0, 0, aovDesc.format)) { m_internalAovs.emplace(name, std::move(aov)); } }; - // In case we have RIF we can use it to combine opacity and color AOVs - // into image that can be used for alpha compositing, - // without it color AOV always have 1.0 in alpha channel - if (!TfGetEnvSetting(HDRPR_DISABLE_ALPHA)) { - initInternalAov(HdRprAovTokens->opacity); - } - // We create separate AOVs needed for denoising ASAP // In such a way, when user enables denoising it will not require to rerender // but it requires more memory, obviously, it should be taken into an account rif::FilterType filterType = rif::FilterType::EawDenoise; - if (m_rprContextMetadata.renderDeviceType == rpr::kRenderDeviceGPU) { + if (m_rprContextMetadata.renderDeviceType == RprUsdRenderDeviceType::GPU) { filterType = rif::FilterType::AIDenoise; } - initInternalAov(HdRprUtilsGetCameraDepthName()); + initInternalAov(HdRprGetCameraDepthAovName()); initInternalAov(HdRprAovTokens->albedo); initInternalAov(HdAovTokens->color); initInternalAov(HdAovTokens->normal); @@ -1700,6 +2014,26 @@ Don't show this message again? m_showRestartRequiredWarning = !fileExists; } + void AddDefaultLight() { + if (!m_defaultLightObject) { + const GfVec3f k_defaultLightColor(0.5f, 0.5f, 0.5f); + m_defaultLightObject = CreateEnvironmentLight(k_defaultLightColor, 1.f); + + // Do not count default light object + m_numLights--; + } + } + + void RemoveDefaultLight() { + if (m_defaultLightObject) { + Release(m_defaultLightObject); + m_defaultLightObject = nullptr; + + // Do not count default light object + m_numLights++; + } + } + void SplitPolygons(const VtIntArray& indexes, const VtIntArray& vpf, VtIntArray& out_newIndexes, VtIntArray& out_newVpf) { out_newIndexes.clear(); out_newVpf.clear(); @@ -1862,6 +2196,35 @@ Don't show this message again? return CreateMesh(position, indexes, normals, VtIntArray(), VtVec2fArray(), VtIntArray(), vpf); } + void UpdateColorAlpha(HdRprApiColorAov* colorAov = nullptr) { + if (!colorAov) { + colorAov = GetColorAov(); + if (!colorAov) return; + } + + if (m_isAlphaEnabled) { + auto opacityAov = GetAov(HdRprAovTokens->opacity, m_viewportSize[0], m_viewportSize[1], HdFormatFloat32Vec4); + if (opacityAov) { + colorAov->SetOpacityAov(opacityAov); + } else { + TF_WARN("Cannot enable alpha"); + } + } else { + colorAov->SetOpacityAov(nullptr); + } + } + + std::shared_ptr GetAov(TfToken const& aovName, int width, int height, HdFormat format) { + std::shared_ptr aov; + auto aovIter = m_aovRegistry.find(aovName); + if (aovIter == m_aovRegistry.end() || + !(aov = aovIter->second.lock())) { + + aov = CreateAov(aovName, width, height, format); + } + return aov; + } + std::shared_ptr CreateAov(TfToken const& aovName, int width = 0, int height = 0, HdFormat format = HdFormatFloat32Vec4) { if (!m_rprContext || width < 0 || height < 0 || @@ -1869,8 +2232,9 @@ Don't show this message again? return nullptr; } - auto rprAovIt = kAovTokenToRprAov.find(aovName); - if (rprAovIt == kAovTokenToRprAov.end()) { + auto& aovDesc = HdRprAovRegistry::GetInstance().GetAovDesc(aovName); + if (aovDesc.id == kAovNone || + aovDesc.format == HdFormatInvalid) { TF_WARN("Unsupported aov type: %s", aovName.GetText()); return nullptr; } @@ -1885,31 +2249,33 @@ Don't show this message again? try { if (!aov) { if (aovName == HdAovTokens->color) { - auto colorAov = std::make_shared(width, height, format, m_rprContext.get(), m_rprContextMetadata); - - auto opacityAovIter = m_aovRegistry.find(HdRprAovTokens->opacity); - if (opacityAovIter != m_aovRegistry.end()) { - if (auto opacityAov = opacityAovIter->second.lock()) { - colorAov->SetOpacityAov(opacityAov); - } + auto rawColorAov = GetAov(HdRprAovTokens->rawColor, width, height, HdFormatFloat32Vec4); + if (!rawColorAov) { + TF_RUNTIME_ERROR("Failed to create color AOV: can't create rawColor AOV"); + return nullptr; } + auto colorAov = std::make_shared(format, std::move(rawColorAov), m_rprContext.get(), m_rprContextMetadata); + UpdateColorAlpha(colorAov.get()); + aov = colorAov; } else if (aovName == HdAovTokens->normal) { aov = std::make_shared(width, height, format, m_rprContext.get(), m_rprContextMetadata, m_rifContext.get()); } else if (aovName == HdAovTokens->depth) { - auto worldCoordinateAovIter = m_internalAovs.find(HdRprAovTokens->worldCoordinate); - if (worldCoordinateAovIter == m_internalAovs.end()) { - if (auto worldCoordinateAov = CreateAov(HdRprAovTokens->worldCoordinate, width, height, HdFormatFloat32Vec4)) { - worldCoordinateAovIter = m_internalAovs.emplace(HdRprAovTokens->worldCoordinate, worldCoordinateAov).first; - } else { - TF_CODING_ERROR("Failed to create depth AOV: can't create worldCoordinate AOV"); - return nullptr; - } + auto worldCoordinateAov = GetAov(HdRprAovTokens->worldCoordinate, width, height, HdFormatFloat32Vec4); + if (!worldCoordinateAov) { + TF_RUNTIME_ERROR("Failed to create depth AOV: can't create worldCoordinate AOV"); + return nullptr; } - aov = std::make_shared(format, worldCoordinateAovIter->second, m_rprContext.get(), m_rprContextMetadata, m_rifContext.get()); + + aov = std::make_shared(format, std::move(worldCoordinateAov), m_rprContext.get(), m_rprContextMetadata, m_rifContext.get()); } else { - aov = std::make_shared(rprAovIt->second, width, height, format, m_rprContext.get(), m_rprContextMetadata, m_rifContext.get()); + if (!aovDesc.computed) { + aov = std::make_shared(rpr::Aov(aovDesc.id), width, height, format, m_rprContext.get(), m_rprContextMetadata, m_rifContext.get()); + } else { + TF_CODING_ERROR("Failed to create %s AOV: unprocessed computed AOV", aovName.GetText()); + return nullptr; + } } m_aovRegistry[aovName] = aov; @@ -1942,11 +2308,11 @@ Don't show this message again? return false; } - auto colorAovBinding = std::find_if(m_aovBindings.begin(), m_aovBindings.end(), [](HdRenderPassAovBinding const& binding) { - return binding.aovName == HdAovTokens->color; + auto colorOutputRb = std::find_if(m_outputRenderBuffers.begin(), m_outputRenderBuffers.end(), [](OutputRenderBuffer const& outRb) { + return outRb.aovName == HdAovTokens->color; }); - if (colorAovBinding == m_aovBindings.end() || - !colorAovBinding->renderBuffer) { + + if (colorOutputRb == m_outputRenderBuffers.end()) { return false; } @@ -1995,7 +2361,7 @@ Don't show this message again? std::memcpy(mappedData, textureData->GetRawBuffer(), imageSize); RIF_ERROR_CHECK(rifImageUnmap(rifImage->GetHandle(), mappedData), "Failed to unmap rif image"); - auto colorRb = colorAovBinding->renderBuffer; + auto colorRb = colorOutputRb->aovBinding->renderBuffer; try { auto blitFilter = rif::Filter::CreateCustom(RIF_IMAGE_FILTER_USER_DEFINED, m_rifContext.get()); @@ -2025,7 +2391,7 @@ Don't show this message again? )"); blitFilter->SetInput("srcImage", rifImage->GetHandle()); blitFilter->SetParam("code", blitKernelCode); - blitFilter->SetOutput(rif::Image::GetDesc(colorRb->GetWidth(), colorRb->GetHeight(), colorRb->GetFormat())); + blitFilter->SetOutput(rif::Image::GetDesc(colorRb->GetWidth(), colorRb->GetHeight(), colorOutputRb->rprAov->GetFormat())); blitFilter->SetInput(rif::Color, blitFilter->GetOutput()); blitFilter->Update(); @@ -2034,7 +2400,7 @@ Don't show this message again? if (RIF_ERROR_CHECK(rifImageMap(blitFilter->GetOutput(), RIF_IMAGE_MAP_READ, &mappedData), "Failed to map rif image") || !mappedData) { return false; } - size_t size = HdDataSizeOfFormat(colorRb->GetFormat()) * colorRb->GetWidth() * colorRb->GetHeight(); + size_t size = HdDataSizeOfFormat(colorOutputRb->rprAov->GetFormat()) * colorRb->GetWidth() * colorRb->GetHeight(); std::memcpy(colorRb->Map(), mappedData, size); colorRb->Unmap(); @@ -2078,7 +2444,7 @@ Don't show this message again? } private: - HdRenderDelegate* m_delegate; + HdRprDelegate* m_delegate; enum ChangeTracker : uint32_t { Clean = 0, @@ -2092,29 +2458,42 @@ Don't show this message again? uint32_t m_dirtyFlags = ChangeTracker::AllDirty; std::unique_ptr m_rprContext; - rpr::ContextMetadata m_rprContextMetadata; + RprUsdContextMetadata m_rprContextMetadata; std::unique_ptr m_rifContext; std::unique_ptr m_scene; std::unique_ptr m_camera; - std::unique_ptr m_imageCache; - std::unique_ptr m_materialFactory; + std::unique_ptr m_imageCache; std::map> m_aovRegistry; - std::map> m_boundAovs; std::map> m_internalAovs; HdRenderPassAovBindingVector m_aovBindings; + struct OutputRenderBuffer { + HdRenderPassAovBinding const* aovBinding; + TfToken aovName; + + std::shared_ptr rprAov; + + void* mappedData; + size_t mappedDataSize; + }; + std::vector m_outputRenderBuffers; + GfVec2i m_viewportSize = GfVec2i(0); GfMatrix4d m_cameraProjectionMatrix = GfMatrix4d(1.f); - HdRprCamera const* m_hdCamera; + HdRprCamera const* m_hdCamera = nullptr; + bool m_isAlphaEnabled; - std::unique_ptr m_defaultLightObject; + std::atomic m_numLights{0}; + HdRprApiEnvironmentLight* m_defaultLightObject = nullptr; - int m_iter = 0; + bool m_isInteractive = false; + int m_numSamples = 0; int m_activePixels = -1; int m_maxSamples = 0; + int m_minSamples = 0; float m_varianceThreshold = 0.0f; RenderQualityType m_currentRenderQuality = kRenderQualityFull; @@ -2132,7 +2511,7 @@ Don't show this message again? std::string m_rprSceneExportPath; }; -HdRprApi::HdRprApi(HdRenderDelegate* delegate) : m_impl(new HdRprApiImpl(delegate)) { +HdRprApi::HdRprApi(HdRprDelegate* delegate) : m_impl(new HdRprApiImpl(delegate)) { } @@ -2216,6 +2595,14 @@ void HdRprApi::SetLightColor(rpr::IESLight* light, GfVec3f const& color) { m_impl->SetLightColor(light, color); } +RprUsdMaterial* HdRprApi::CreateGeometryLightMaterial(GfVec3f const& emissionColor) { + return m_impl->CreateGeometryLightMaterial(emissionColor); +} + +void HdRprApi::ReleaseGeometryLightMaterial(RprUsdMaterial* material) { + return m_impl->ReleaseGeometryLightMaterial(material); +} + HdRprApiVolume* HdRprApi::CreateVolume( VtUIntArray const& densityCoords, VtFloatArray const& densityValues, VtVec3fArray const& densityLUT, float densityScale, VtUIntArray const& albedoCoords, VtFloatArray const& albedoValues, VtVec3fArray const& albedoLUT, float albedoScale, @@ -2229,16 +2616,24 @@ HdRprApiVolume* HdRprApi::CreateVolume( gridSize, voxelSize, gridBBLow, materialParams); } -HdRprApiMaterial* HdRprApi::CreateMaterial(MaterialAdapter& MaterialAdapter) { +RprUsdMaterial* HdRprApi::CreateMaterial(HdSceneDelegate* sceneDelegate, HdMaterialNetworkMap const& materialNetwork) { m_impl->InitIfNeeded(); - return m_impl->CreateMaterial(MaterialAdapter); + return m_impl->CreateMaterial(sceneDelegate, materialNetwork); } -HdRprApiMaterial* HdRprApi::CreatePointsMaterial(VtVec3fArray const& colors) { +RprUsdMaterial* HdRprApi::CreatePointsMaterial(VtVec3fArray const& colors) { m_impl->InitIfNeeded(); return m_impl->CreatePointsMaterial(colors); } +RprUsdMaterial* HdRprApi::CreateDiffuseMaterial(GfVec3f const& color) { + m_impl->InitIfNeeded(); + + return m_impl->CreateRawMaterial(RPR_MATERIAL_NODE_UBERV2, { + {RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, ToVec4(color, 1.0f)} + }); +} + void HdRprApi::SetMeshRefineLevel(rpr::Shape* mesh, int level) { m_impl->SetMeshRefineLevel(mesh, level); } @@ -2247,8 +2642,8 @@ void HdRprApi::SetMeshVertexInterpolationRule(rpr::Shape* mesh, TfToken boundary m_impl->SetMeshVertexInterpolationRule(mesh, boundaryInterpolation); } -void HdRprApi::SetMeshMaterial(rpr::Shape* mesh, HdRprApiMaterial const* material, bool doublesided, bool displacementEnabled) { - m_impl->SetMeshMaterial(mesh, material, doublesided, displacementEnabled); +void HdRprApi::SetMeshMaterial(rpr::Shape* mesh, RprUsdMaterial const* material, bool displacementEnabled) { + m_impl->SetMeshMaterial(mesh, material, displacementEnabled); } void HdRprApi::SetMeshVisibility(rpr::Shape* mesh, uint32_t visibilityMask) { @@ -2259,7 +2654,7 @@ void HdRprApi::SetMeshId(rpr::Shape* mesh, uint32_t id) { m_impl->SetMeshId(mesh, id); } -void HdRprApi::SetCurveMaterial(rpr::Curve* curve, HdRprApiMaterial const* material) { +void HdRprApi::SetCurveMaterial(rpr::Curve* curve, RprUsdMaterial const* material) { m_impl->SetCurveMaterial(curve, material); } @@ -2271,7 +2666,7 @@ void HdRprApi::Release(HdRprApiEnvironmentLight* envLight) { m_impl->Release(envLight); } -void HdRprApi::Release(HdRprApiMaterial* material) { +void HdRprApi::Release(RprUsdMaterial* material) { m_impl->Release(material); } @@ -2324,6 +2719,10 @@ HdRenderPassAovBindingVector HdRprApi::GetAovBindings() const { return m_impl->GetAovBindings(); } +void HdRprApi::CommitResources() { + m_impl->CommitResources(); +} + void HdRprApi::Render(HdRprRenderThread* renderThread) { m_impl->Render(renderThread); } @@ -2348,10 +2747,6 @@ bool HdRprApi::IsGlInteropEnabled() const { return m_impl->IsGlInteropEnabled(); } -bool HdRprApi::IsAovFormatConversionAvailable() const { - return m_impl->IsAovFormatConversionAvailable(); -} - bool HdRprApi::IsArbitraryShapedLightSupported() const { m_impl->InitIfNeeded(); return m_impl->IsArbitraryShapedLightSupported(); diff --git a/pxr/imaging/plugin/hdRpr/rprApi.h b/pxr/imaging/plugin/hdRpr/rprApi.h index 0eac0e7e4..d92e63c1e 100644 --- a/pxr/imaging/plugin/hdRpr/rprApi.h +++ b/pxr/imaging/plugin/hdRpr/rprApi.h @@ -24,6 +24,7 @@ limitations under the License. #include "pxr/base/tf/staticTokens.h" #include "pxr/imaging/hd/types.h" #include "pxr/imaging/hd/camera.h" +#include "pxr/imaging/hd/material.h" #include "pxr/imaging/hd/renderPassState.h" #include "pxr/imaging/hd/renderDelegate.h" @@ -35,13 +36,14 @@ limitations under the License. PXR_NAMESPACE_OPEN_SCOPE +class HdRprDelegate; class HdRprRenderThread; class MaterialAdapter; class HdRprApiImpl; +class RprUsdMaterial; struct HdRprApiVolume; -struct HdRprApiMaterial; struct HdRprApiEnvironmentLight; template @@ -65,7 +67,7 @@ const uint32_t kInvisible = 0u; class HdRprApi final { public: - HdRprApi(HdRenderDelegate* delegate); + HdRprApi(HdRprDelegate* delegate); ~HdRprApi(); HdRprApiEnvironmentLight* CreateEnvironmentLight(const std::string& pathTotexture, float intensity); @@ -85,6 +87,9 @@ class HdRprApi final { void Release(rpr::Light* light); + RprUsdMaterial* CreateGeometryLightMaterial(GfVec3f const& emissionColor); + void ReleaseGeometryLightMaterial(RprUsdMaterial* material); + struct VolumeMaterialParameters { GfVec3f scatteringColor = GfVec3f(1.0f); GfVec3f transmissionColor = GfVec3f(1.0f); @@ -100,21 +105,22 @@ class HdRprApi final { void SetTransform(HdRprApiVolume* volume, GfMatrix4f const& transform); void Release(HdRprApiVolume* volume); - HdRprApiMaterial* CreateMaterial(MaterialAdapter& materialAdapter); - HdRprApiMaterial* CreatePointsMaterial(VtVec3fArray const& colors); - void Release(HdRprApiMaterial* material); + RprUsdMaterial* CreateMaterial(HdSceneDelegate* sceneDelegate, HdMaterialNetworkMap const& materialNetwork); + RprUsdMaterial* CreatePointsMaterial(VtVec3fArray const& colors); + RprUsdMaterial* CreateDiffuseMaterial(GfVec3f const& color); + void Release(RprUsdMaterial* material); rpr::Shape* CreateMesh(const VtVec3fArray& points, const VtIntArray& pointIndexes, const VtVec3fArray& normals, const VtIntArray& normalIndexes, const VtVec2fArray& uv, const VtIntArray& uvIndexes, const VtIntArray& vpf, TfToken const& polygonWinding); rpr::Shape* CreateMeshInstance(rpr::Shape* prototypeMesh); void SetMeshRefineLevel(rpr::Shape* mesh, int level); void SetMeshVertexInterpolationRule(rpr::Shape* mesh, TfToken boundaryInterpolation); - void SetMeshMaterial(rpr::Shape* mesh, HdRprApiMaterial const* material, bool doublesided, bool displacementEnabled); + void SetMeshMaterial(rpr::Shape* mesh, RprUsdMaterial const* material, bool displacementEnabled); void SetMeshVisibility(rpr::Shape* mesh, uint32_t visibilityMask); void SetMeshId(rpr::Shape* mesh, uint32_t id); void Release(rpr::Shape* shape); rpr::Curve* CreateCurve(VtVec3fArray const& points, VtIntArray const& indices, VtFloatArray const& radiuses, VtVec2fArray const& uvs, VtIntArray const& segmentPerCurve); - void SetCurveMaterial(rpr::Curve* curve, HdRprApiMaterial const* material); + void SetCurveMaterial(rpr::Curve* curve, RprUsdMaterial const* material); void SetCurveVisibility(rpr::Curve* curve, uint32_t visibilityMask); void Release(rpr::Curve* curve); @@ -137,12 +143,12 @@ class HdRprApi final { // returns -1 if adaptive sampling is not used int GetNumActivePixels() const; + void CommitResources(); void Render(HdRprRenderThread* renderThread); void AbortRender(); bool IsChanged() const; bool IsGlInteropEnabled() const; - bool IsAovFormatConversionAvailable() const; bool IsArbitraryShapedLightSupported() const; int GetCurrentRenderQuality() const; void ExportRprSceneOnNextRender(const char* exportPath); diff --git a/pxr/imaging/plugin/hdRpr/rprApiAov.cpp b/pxr/imaging/plugin/hdRpr/rprApiAov.cpp index 4f942f7cb..b5de85886 100644 --- a/pxr/imaging/plugin/hdRpr/rprApiAov.cpp +++ b/pxr/imaging/plugin/hdRpr/rprApiAov.cpp @@ -15,7 +15,9 @@ limitations under the License. #include "rprApi.h" #include "rprApiFramebuffer.h" #include "rifcpp/rifError.h" -#include "rpr/error.h" + +#include "pxr/imaging/rprUsd/contextMetadata.h" +#include "pxr/imaging/rprUsd/error.h" PXR_NAMESPACE_OPEN_SCOPE @@ -52,28 +54,25 @@ bool ReadRifImage(rif_image image, void* dstBuffer, size_t dstBufferSize) { } // namespace anonymous HdRprApiAov::HdRprApiAov(rpr_aov rprAovType, int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, std::unique_ptr filter) - : m_format(format), - m_filter(std::move(filter)) { - auto componentType = HdGetComponentFormat(format); - if (componentType != HdFormatUNorm8 && - componentType != HdFormatFloat16 && - componentType != HdFormatFloat32) { - TF_CODING_ERROR("Unsupported component type: %d", componentType); - m_format = HdFormatFloat32Vec4; + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, std::unique_ptr filter) + : m_aovDescriptor(HdRprAovRegistry::GetInstance().GetAovDesc(rprAovType, false)) + , m_filter(std::move(filter)) + , m_format(format) { + if (rif::Image::GetDesc(0, 0, format).type == 0) { + RIF_THROW_ERROR_MSG("Unsupported format: " + TfEnum::GetName(format)); } m_aov = pxr::make_unique(rprContext, width, height); m_aov->AttachAs(rprAovType); // XXX (Hybrid): Hybrid plugin does not support framebuffer resolving (rprContextResolveFrameBuffer) - if (rprContextMetadata.pluginType != rpr::kPluginHybrid) { + if (rprContextMetadata.pluginType != kPluginHybrid) { m_resolved = pxr::make_unique(rprContext, width, height); } } HdRprApiAov::HdRprApiAov(rpr_aov rprAovType, int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext) + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext) : HdRprApiAov(rprAovType, width, height, format, rprContext, rprContextMetadata, [format, rifContext]() -> std::unique_ptr { if (format == HdFormatFloat32Vec4) { // RPR framebuffers by default with such format @@ -81,9 +80,11 @@ HdRprApiAov::HdRprApiAov(rpr_aov rprAovType, int width, int height, HdFormat for } auto filter = rif::Filter::CreateCustom(RIF_IMAGE_FILTER_RESAMPLE, rifContext); - if (filter) { - filter->SetParam("interpOperator", RIF_IMAGE_INTERPOLATION_NEAREST); + if (!filter) { + RPR_THROW_ERROR_MSG("Failed to create resample filter"); } + + filter->SetParam("interpOperator", RIF_IMAGE_INTERPOLATION_NEAREST); return filter; }()) { @@ -101,7 +102,8 @@ void HdRprApiAov::Resolve() { void HdRprApiAov::Clear() { if (m_aov) { - m_aov->Clear(); + auto& v = m_aovDescriptor.clearValue; + m_aov->Clear(v[0], v[1], v[2], v[3]); } } @@ -193,8 +195,9 @@ void HdRprApiAov::OnSizeChange(rif::Context* rifContext) { } } -HdRprApiColorAov::HdRprApiColorAov(int width, int height, HdFormat format, rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata) - : HdRprApiAov(RPR_AOV_COLOR, width, height, format, rprContext, rprContextMetadata, nullptr) { +HdRprApiColorAov::HdRprApiColorAov(HdFormat format, std::shared_ptr rawColorAov, rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata) + : HdRprApiAov(HdRprAovRegistry::GetInstance().GetAovDesc(rpr::Aov(kColorAlpha), true), format) + , m_retainedRawColor(std::move(rawColorAov)) { } @@ -213,7 +216,7 @@ void HdRprApiColorAov::SetFilter(Filter filter, bool enable) { void HdRprApiColorAov::SetOpacityAov(std::shared_ptr opacity) { if (m_retainedOpacity != opacity) { m_retainedOpacity = opacity; - SetFilter(kFilterComposeOpacity, m_retainedOpacity != nullptr); + SetFilter(kFilterComposeOpacity, CanComposeAlpha()); } } @@ -308,6 +311,21 @@ void HdRprApiColorAov::SetTonemapFilterParams(rif::Filter* filter) { filter->SetParam("gamma", m_tonemap.gamma); } +bool HdRprApiColorAov::CanComposeAlpha() { + // Compositing alpha into framebuffer with less than 4 components is a no-op + return HdGetComponentCount(m_format) == 4 && m_retainedOpacity; +} + +void HdRprApiColorAov::Resize(int width, int height, HdFormat format) { + if (m_width != width || m_height != height) { + m_width = width; + m_height = height; + m_dirtyBits |= ChangeTracker::DirtySize; + } + + HdRprApiAov::Resize(width, height, format); +} + void HdRprApiColorAov::Update(HdRprApi const* rprApi, rif::Context* rifContext) { if (m_dirtyBits & ChangeTracker::DirtyFormat) { OnFormatChange(rifContext); @@ -344,7 +362,7 @@ void HdRprApiColorAov::Update(HdRprApi const* rprApi, rif::Context* rifContext) if ((m_enabledFilters & kFilterAIDenoise) || (m_enabledFilters & kFilterEAWDenoise)) { auto denoiseFilterType = (m_enabledFilters & kFilterAIDenoise) ? rif::FilterType::AIDenoise : rif::FilterType::EawDenoise; - auto fbDesc = m_aov->GetDesc(); + auto fbDesc = m_retainedRawColor->GetAovFb()->GetDesc(); auto type = (m_enabledFilters & kFilterAIDenoise) ? kFilterAIDenoise : kFilterEAWDenoise; auto filter = rif::Filter::Create(denoiseFilterType, rifContext, fbDesc.fb_width, fbDesc.fb_height); @@ -366,6 +384,7 @@ void HdRprApiColorAov::Update(HdRprApi const* rprApi, rif::Context* rifContext) } else if (m_enabledFilters & kFilterResample) { m_filter = rif::Filter::CreateCustom(RIF_IMAGE_FILTER_RESAMPLE, rifContext); m_filter->SetParam("interpOperator", RIF_IMAGE_INTERPOLATION_NEAREST); + m_mainFilterType = kFilterResample; } // Signal to update inputs @@ -385,6 +404,18 @@ void HdRprApiColorAov::Update(HdRprApi const* rprApi, rif::Context* rifContext) } } +bool HdRprApiColorAov::GetData(void* dstBuffer, size_t dstBufferSize) { + if (!m_filter) { + if (auto resolvedRawColorFb = m_retainedRawColor->GetResolvedFb()) { + return resolvedRawColorFb->GetData(dstBuffer, dstBufferSize); + } else { + return false; + } + } else { + return HdRprApiAov::GetData(dstBuffer, dstBufferSize); + } +} + void HdRprApiColorAov::Resolve() { HdRprApiAov::Resolve(); @@ -395,6 +426,7 @@ void HdRprApiColorAov::Resolve() { void HdRprApiColorAov::OnFormatChange(rif::Context* rifContext) { SetFilter(kFilterResample, m_format != HdFormatFloat32Vec4); + SetFilter(kFilterComposeOpacity, CanComposeAlpha()); m_dirtyBits |= ChangeTracker::DirtySize; } @@ -424,15 +456,15 @@ void HdRprApiColorAov::OnSizeChange(rif::Context* rifContext) { return; } - auto fbDesc = m_aov->GetDesc(); + auto fbDesc = m_retainedRawColor->GetAovFb()->GetDesc(); if (m_auxFilters.empty()) { - ResizeFilter(fbDesc.fb_width, fbDesc.fb_height, m_mainFilterType, m_filter.get(), GetResolvedFb()); + ResizeFilter(fbDesc.fb_width, fbDesc.fb_height, m_mainFilterType, m_filter.get(), m_retainedRawColor->GetResolvedFb()); } else { // Ideally we would use "Filter combining" functionality, but it does not work with user-defined filter // So we attach each filter separately auto filter = m_auxFilters.front().second.get(); - ResizeFilter(fbDesc.fb_width, fbDesc.fb_height, m_auxFilters.front().first, filter, GetResolvedFb()); + ResizeFilter(fbDesc.fb_width, fbDesc.fb_height, m_auxFilters.front().first, filter, m_retainedRawColor->GetResolvedFb()); for (int i = 1; i < m_auxFilters.size(); ++i) { auto filterInput = m_auxFilters[i - 1].second->GetOutput(); ResizeFilter(fbDesc.fb_width, fbDesc.fb_height, m_auxFilters[i].first, m_auxFilters[i].second.get(), filterInput); @@ -443,7 +475,7 @@ void HdRprApiColorAov::OnSizeChange(rif::Context* rifContext) { HdRprApiNormalAov::HdRprApiNormalAov( int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext) + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext) : HdRprApiAov(RPR_AOV_SHADING_NORMAL, width, height, format, rprContext, rprContextMetadata, rif::Filter::CreateCustom(RIF_IMAGE_FILTER_REMAP_RANGE, rifContext)) { if (!rifContext) { RPR_THROW_ERROR_MSG("Can not create normal AOV: RIF context required"); @@ -468,8 +500,9 @@ void HdRprApiNormalAov::OnSizeChange(rif::Context* rifContext) { HdRprApiDepthAov::HdRprApiDepthAov( HdFormat format, std::shared_ptr worldCoordinateAov, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext) - : m_retainedWorldCoordinateAov(worldCoordinateAov) { + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext) + : HdRprApiAov(HdRprAovRegistry::GetInstance().GetAovDesc(rpr::Aov(kNdcDepth), true), format) + , m_retainedWorldCoordinateAov(worldCoordinateAov) { if (!rifContext) { RPR_THROW_ERROR_MSG("Can not create depth AOV: RIF context required"); } @@ -493,7 +526,6 @@ HdRprApiDepthAov::HdRprApiDepthAov( auto fbDesc = m_retainedWorldCoordinateAov->GetAovFb()->GetDesc(); m_width = fbDesc.fb_width; m_height = fbDesc.fb_height; - m_format = format; } void HdRprApiDepthAov::Update(HdRprApi const* rprApi, rif::Context* rifContext) { diff --git a/pxr/imaging/plugin/hdRpr/rprApiAov.h b/pxr/imaging/plugin/hdRpr/rprApiAov.h index cb63020f3..750f2c450 100644 --- a/pxr/imaging/plugin/hdRpr/rprApiAov.h +++ b/pxr/imaging/plugin/hdRpr/rprApiAov.h @@ -14,46 +14,52 @@ limitations under the License. #ifndef HDRPR_RPR_API_AOV_H #define HDRPR_RPR_API_AOV_H +#include "aovDescriptor.h" #include "rprApiFramebuffer.h" #include "rifcpp/rifFilter.h" -#include "rpr/contextMetadata.h" #include "pxr/base/gf/matrix4f.h" #include "pxr/imaging/hd/types.h" PXR_NAMESPACE_OPEN_SCOPE class HdRprApi; +struct RprUsdContextMetadata; class HdRprApiAov { public: HdRprApiAov(rpr_aov rprAovType, int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, std::unique_ptr filter); + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, std::unique_ptr filter); HdRprApiAov(rpr_aov rprAovType, int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext); + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext); virtual ~HdRprApiAov() = default; virtual void Resize(int width, int height, HdFormat format); virtual void Update(HdRprApi const* rprApi, rif::Context* rifContext); virtual void Resolve(); - bool GetData(void* dstBuffer, size_t dstBufferSize); + virtual bool GetData(void* dstBuffer, size_t dstBufferSize); void Clear(); HdFormat GetFormat() const { return m_format; } + HdRprAovDescriptor const& GetDesc() const { return m_aovDescriptor; } + HdRprApiFramebuffer* GetAovFb() { return m_aov.get(); }; HdRprApiFramebuffer* GetResolvedFb(); protected: - HdRprApiAov() = default; + HdRprApiAov(HdRprAovDescriptor const& aovDescriptor, HdFormat format) + : m_aovDescriptor(aovDescriptor), m_format(format) {}; virtual void OnFormatChange(rif::Context* rifContext); virtual void OnSizeChange(rif::Context* rifContext); protected: + HdRprAovDescriptor const& m_aovDescriptor; + HdFormat m_format; + std::unique_ptr m_aov; std::unique_ptr m_resolved; std::unique_ptr m_filter; - HdFormat m_format = HdFormatInvalid; enum ChangeTracker { Clean = 0, @@ -69,10 +75,12 @@ class HdRprApiAov { class HdRprApiColorAov : public HdRprApiAov { public: - HdRprApiColorAov(int width, int height, HdFormat format, rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata); + HdRprApiColorAov(HdFormat format, std::shared_ptr rawColorAov, rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata); ~HdRprApiColorAov() override = default; + void Resize(int width, int height, HdFormat format) override; void Update(HdRprApi const* rprApi, rif::Context* rifContext) override; + bool GetData(void* dstBuffer, size_t dstBufferSize) override; void Resolve() override; void SetOpacityAov(std::shared_ptr opacity); @@ -126,7 +134,10 @@ class HdRprApiColorAov : public HdRprApiAov { void SetTonemapFilterParams(rif::Filter* filter); + bool CanComposeAlpha(); + private: + std::shared_ptr m_retainedRawColor; std::shared_ptr m_retainedOpacity; std::shared_ptr m_retainedDenoiseInputs[rif::MaxInput]; @@ -137,12 +148,15 @@ class HdRprApiColorAov : public HdRprApiAov { bool m_isEnabledFiltersDirty = true; TonemapParams m_tonemap; + + int m_width = 0; + int m_height = 0; }; class HdRprApiNormalAov : public HdRprApiAov { public: HdRprApiNormalAov(int width, int height, HdFormat format, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext); + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext); ~HdRprApiNormalAov() override = default; protected: void OnFormatChange(rif::Context* rifContext) override; @@ -153,7 +167,7 @@ class HdRprApiDepthAov : public HdRprApiAov { public: HdRprApiDepthAov(HdFormat format, std::shared_ptr worldCoordinateAov, - rpr::Context* rprContext, rpr::ContextMetadata const& rprContextMetadata, rif::Context* rifContext); + rpr::Context* rprContext, RprUsdContextMetadata const& rprContextMetadata, rif::Context* rifContext); ~HdRprApiDepthAov() override = default; void Update(HdRprApi const* rprApi, rif::Context* rifContext) override; diff --git a/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.cpp b/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.cpp index 9b80a8d4d..b5fbd2cc6 100644 --- a/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.cpp +++ b/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.cpp @@ -12,7 +12,9 @@ limitations under the License. ************************************************************************/ #include "rprApiFramebuffer.h" -#include "rpr/helpers.h" +#include "aovDescriptor.h" + +#include "pxr/imaging/rprUsd/helpers.h" PXR_NAMESPACE_OPEN_SCOPE @@ -63,11 +65,19 @@ void HdRprApiFramebuffer::AttachAs(rpr::Aov aov) { m_aov = aov; } -void HdRprApiFramebuffer::Clear() { +void HdRprApiFramebuffer::Clear(float r, float g, float b, float a) { if (m_width == 0 || m_height == 0) { return; } RPR_ERROR_CHECK(m_rprFb->Clear(), "Failed to clear framebuffer"); + + // XXX (FIR-1681): We can not rely on clear values because every AOV in RPR is multisampled, i.e. + // value of singlesampled AOV (any ID AOV, worldCoordinate, etc) is always equals to `clearValue + renderedValue` + /*if (r == 0.0f && g == 0.0f && b == 0.0f && a == 0.0f) { + RPR_ERROR_CHECK(m_rprFb->Clear(), "Failed to clear framebuffer"); + } else { + RPR_ERROR_CHECK(m_rprFb->FillWithColor(r, g, b, a), "Failed to clear framebuffer"); + }*/ } void HdRprApiFramebuffer::Resolve(HdRprApiFramebuffer* dstFrameBuffer) { @@ -123,7 +133,7 @@ rpr_cl_mem HdRprApiFramebuffer::GetCLMem() { return nullptr; } - return rpr::GetInfo(m_rprFb, rpr_framebuffer_info(RPR_CL_MEM_OBJECT)); + return RprUsdGetInfo(m_rprFb, rpr_framebuffer_info(RPR_CL_MEM_OBJECT)); } void HdRprApiFramebuffer::Create(uint32_t width, uint32_t height) { diff --git a/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.h b/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.h index 08af8e501..dbd0174be 100644 --- a/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.h +++ b/pxr/imaging/plugin/hdRpr/rprApiFramebuffer.h @@ -23,7 +23,6 @@ PXR_NAMESPACE_OPEN_SCOPE class HdRprApiFramebuffer { public: - static constexpr rpr::Aov kAovNone = static_cast(-1); static constexpr uint32_t kNumChannels = 4; HdRprApiFramebuffer(rpr::Context* context, uint32_t width, uint32_t height); @@ -33,7 +32,7 @@ class HdRprApiFramebuffer { HdRprApiFramebuffer& operator=(HdRprApiFramebuffer&& fb) noexcept; void AttachAs(rpr::Aov aov); - void Clear(); + void Clear(float r, float g, float b, float a); void Resolve(HdRprApiFramebuffer* dstFrameBuffer); /// Return true if framebuffer was actually resized bool Resize(uint32_t width, uint32_t height); diff --git a/pxr/imaging/plugin/hdRpr/usdviewMenu/CMakeLists.txt b/pxr/imaging/plugin/hdRpr/usdviewMenu/CMakeLists.txt new file mode 100644 index 000000000..25312e6fe --- /dev/null +++ b/pxr/imaging/plugin/hdRpr/usdviewMenu/CMakeLists.txt @@ -0,0 +1,7 @@ +install( + FILES rpr.py + DESTINATION lib/python/rprUsdviewMenu + RENAME "__init__.py") +install( + FILES plugInfo.json + DESTINATION plugin/usd/rprUsdviewMenu/resources) diff --git a/pxr/imaging/plugin/hdRpr/python/plugInfo.json b/pxr/imaging/plugin/hdRpr/usdviewMenu/plugInfo.json similarity index 74% rename from pxr/imaging/plugin/hdRpr/python/plugInfo.json rename to pxr/imaging/plugin/hdRpr/usdviewMenu/plugInfo.json index 0c1712079..798ab4432 100644 --- a/pxr/imaging/plugin/hdRpr/python/plugInfo.json +++ b/pxr/imaging/plugin/hdRpr/usdviewMenu/plugInfo.json @@ -2,12 +2,12 @@ "Plugins": [ { "Type": "python", - "Name": "rpr", + "Name": "rprUsdviewMenu", "Info": { "Types": { - "rpr.RprPluginContainer": { + "rprUsdviewMenu.RprPluginContainer": { "bases": ["pxr.Usdviewq.plugin.PluginContainer"], - "displayName": "Usdview Radeon ProRender Plugin" + "displayName": "Usdview Radeon ProRender Plugin Menu" } } } diff --git a/pxr/imaging/plugin/hdRpr/python/rpr.py b/pxr/imaging/plugin/hdRpr/usdviewMenu/rpr.py similarity index 100% rename from pxr/imaging/plugin/hdRpr/python/rpr.py rename to pxr/imaging/plugin/hdRpr/usdviewMenu/rpr.py diff --git a/pxr/imaging/plugin/rprHoudini/CMakeLists.txt b/pxr/imaging/plugin/rprHoudini/CMakeLists.txt new file mode 100644 index 000000000..847249001 --- /dev/null +++ b/pxr/imaging/plugin/rprHoudini/CMakeLists.txt @@ -0,0 +1,22 @@ +if(NOT TARGET Houdini) + return() +endif() + +add_library(RPR_for_Houdini SHARED + plugin.cpp + VOP_RPRMaterial.h + VOP_RPRMaterial.cpp) + +target_link_libraries(RPR_for_Houdini + rprUsd + Houdini) + +install( + FILES + ui/RPR.svg + DESTINATION + houdini/config/Icons) + +GroupSources(RPR_for_Houdini) + +houdini_configure_target(RPR_for_Houdini "INSTDIR" "${CMAKE_INSTALL_PREFIX}/houdini/dso") diff --git a/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.cpp b/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.cpp new file mode 100644 index 000000000..c99235dc9 --- /dev/null +++ b/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.cpp @@ -0,0 +1,460 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "VOP_RPRMaterial.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/base/tf/stringUtils.h" + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/** + Simple identity macro that does nothing but helps to identify allocations of + memory that will never be deleted, until we find a way to do so. +*/ +#define LEAKED(ptr) ptr + +static VOP_Type GetVOPType(RprUsdMaterialNodeInput::Type rprType) { + switch (rprType) { + case RprUsdMaterialNodeElement::kAngle: + case RprUsdMaterialNodeElement::kFloat: + return VOP_TYPE_FLOAT; + case RprUsdMaterialNodeElement::kVector3: + return VOP_TYPE_VECTOR; + case RprUsdMaterialNodeElement::kVector2: + return VOP_TYPE_VECTOR2; + case RprUsdMaterialNodeElement::kColor3: + return VOP_TYPE_COLOR; + case RprUsdMaterialNodeElement::kNormal: + return VOP_TYPE_NORMAL; + case RprUsdMaterialNodeElement::kBoolean: + case RprUsdMaterialNodeElement::kInteger: + return VOP_TYPE_INTEGER; + case RprUsdMaterialNodeElement::kToken: + return VOP_TYPE_STRING; + case RprUsdMaterialNodeElement::kVolumeShader: + return VOP_ATMOSPHERE_SHADER; + case RprUsdMaterialNodeElement::kSurfaceShader: + return VOP_SURFACE_SHADER; + case RprUsdMaterialNodeElement::kDisplacementShader: + return VOP_DISPLACEMENT_SHADER; + default: + return VOP_TYPE_UNDEF; + } +} + +static PRM_Type const& GetPRMType(RprUsdMaterialNodeInput::Type rprType) { + switch (rprType) { + case RprUsdMaterialNodeElement::kFloat: + return PRM_FLT; + case RprUsdMaterialNodeElement::kAngle: + return PRM_ANGLE; + case RprUsdMaterialNodeElement::kVector2: + case RprUsdMaterialNodeElement::kVector3: + case RprUsdMaterialNodeElement::kNormal: + return PRM_XYZ; + case RprUsdMaterialNodeElement::kColor3: + return PRM_RGB; + case RprUsdMaterialNodeElement::kInteger: + return PRM_INT; + case RprUsdMaterialNodeElement::kBoolean: + return PRM_TOGGLE; + case RprUsdMaterialNodeElement::kToken: + return PRM_ORD_E; + default: + return PRM_LIST_TERMINATOR; + } +} + +static PRM_Range* NewPRMRange(RprUsdMaterialNodeInput const* input) { + if (input->GetType() == RprUsdMaterialNodeElement::kFloat || + input->GetType() == RprUsdMaterialNodeElement::kInteger) { + bool isRangeSet = false; + float min = std::numeric_limits::lowest(); + float max = std::numeric_limits::max(); + auto minFlag = PRM_RANGE_UI; + auto maxFlag = PRM_RANGE_UI; + + auto uiMinString = input->GetUIMin(); + auto uiMinSoftString = input->GetUISoftMin(); + + auto uiMaxString = input->GetUIMax(); + auto uiMaxSoftString = input->GetUISoftMax(); + + if (uiMinString) { + min = std::stof(uiMinString); + minFlag = PRM_RANGE_RESTRICTED; + isRangeSet = true; + } else if (uiMinSoftString) { + min = std::stof(uiMinSoftString); + isRangeSet = true; + } + + if (uiMaxString) { + max = std::stof(uiMaxString); + maxFlag = PRM_RANGE_RESTRICTED; + isRangeSet = true; + } else if (uiMaxSoftString) { + max = std::stof(uiMaxSoftString); + isRangeSet = true; + } + + if (isRangeSet) { + return new PRM_Range(minFlag, min, maxFlag, max); + } + } + + return nullptr; +} + +static PRM_Default* NewPRMDefault( + RprUsdMaterialNodeInput const* input, + unsigned i_nb_defaults, + PRM_ChoiceList** choiceListPtr) { + auto valueStr = input->GetValueString(); + if (!valueStr) { + return nullptr; + } + + std::vector values; + + if (input->GetType() == RprUsdMaterialNodeElement::kBoolean) { + if (std::strcmp(valueStr, "true") == 0) { + values.push_back(1.0f); + } else if (std::strcmp(valueStr, "false") == 0) { + values.push_back(0.0f); + } + } else if (input->GetType() == RprUsdMaterialNodeElement::kFloat || + input->GetType() == RprUsdMaterialNodeElement::kAngle || + input->GetType() == RprUsdMaterialNodeElement::kInteger || + input->GetType() == RprUsdMaterialNodeElement::kVector3 || + input->GetType() == RprUsdMaterialNodeElement::kVector2 || + input->GetType() == RprUsdMaterialNodeElement::kColor3 || + input->GetType() == RprUsdMaterialNodeElement::kNormal) { + auto valueStrings = TfStringTokenize(valueStr, ", \t"); + if (valueStrings.size() == i_nb_defaults) { + for (size_t i = 0; i < valueStrings.size(); ++i) { + values.push_back(std::stof(valueStrings[i])); + } + } + } else if (input->GetType() == RprUsdMaterialNodeElement::kToken) { + auto defau1t = LEAKED(new PRM_Default(0, LEAKED(strdup(valueStr)))); + auto items = LEAKED(new std::vector); + + for (auto& value : input->GetTokenValues()) { + items->push_back(PRM_Item(LEAKED(strdup(value.GetText())))); + } + items->push_back(PRM_Item()); + + auto& choiceList = *choiceListPtr; + auto choiceListType = PRM_ChoiceListType(PRM_CHOICELIST_SINGLE | PRM_CHOICELIST_USE_TOKEN); + choiceList = LEAKED(new PRM_ChoiceList(choiceListType, items->data())); + + return defau1t; + } + + if (values.size() == i_nb_defaults) { + auto def = new PRM_Default[i_nb_defaults]; + for (unsigned i = 0; i < i_nb_defaults; ++i) { + def[i] = PRM_Default(values[i]); + } + return def; + } + + return nullptr; +} + +static unsigned GetNumChannels(RprUsdMaterialNodeInput const* input) { + if (input->GetType() == RprUsdMaterialNodeElement::kColor3 || + input->GetType() == RprUsdMaterialNodeElement::kVector3 || + input->GetType() == RprUsdMaterialNodeElement::kNormal) { + return 3; + } else if (input->GetType() == RprUsdMaterialNodeElement::kVector2) { + return 2; + } + + return 1; +} + +/* +static void AddSubPageHeading( + std::vector* templates, + std::string const& headingName) { + std::string identifier = headingName + "_heading"; + std::replace(identifier.begin(), identifier.end(), ' ', '_'); + char* label_name = LEAKED(strdup(identifier.c_str())); + char* label_string = LEAKED(strdup(headingName.c_str())); + PRM_Name* name = LEAKED(new PRM_Name(label_name, label_string)); + templates->push_back(PRM_Template(PRM_HEADING, 0, name)); +} +*/ + +OP_Node* VOP_RPRMaterial::Create(OP_Network* net, const char* name, OP_Operator* entry) { + auto rpr_entry = dynamic_cast(entry); + return new VOP_RPRMaterial(net, name, rpr_entry); +} + +PRM_Template* VOP_RPRMaterial::GetTemplates(RprUsdMaterialNodeInfo const* shaderInfo) { + /* + The templates and their components (names and such) are dynamically + allocated here but never deleted, since they're expected to be valid for + the duration of the process. It's not that different from allocating + them as static variables, which is the usual way to do this when only + one type of operator is defined. Allocating them dynamically allows + multiple operator types, each with an arbitrary number of parameters, to + be created. + It could be interesting to keep them around in VOP_RPRMaterialOperator + and delete them when its destructor is called. Unfortunately, even + VOP_Operator's destructor doesn't seem to even be called, so we simply + use the LEAKED macro to mark them until we find out what we should do. + */ + auto templates = LEAKED(new std::vector); + + // Scan inputs for UI folders, we create tab for each of them + std::vector tabNames; + std::map> inputsPerTab; + for (size_t i = 0; i < shaderInfo->GetNumInputs(); ++i) { + auto input = shaderInfo->GetInput(i); + + std::string uiFolder; + if (input->GetUIFolder()) { + uiFolder = input->GetUIFolder(); + } + + auto tabIt = inputsPerTab.find(uiFolder); + if (tabIt == inputsPerTab.end()) { + tabNames.push_back(uiFolder); + inputsPerTab[uiFolder] = {input}; + } else { + tabIt->second.push_back(input); + } + } + + auto tabs = LEAKED(new std::vector); + for (auto& tabName : tabNames) { + if (tabName.empty()) { + continue; + } + auto inputsIt = inputsPerTab.find(tabName); + auto numInputsInTab = static_cast(inputsIt->second.size()); + tabs->push_back(PRM_Default(numInputsInTab, LEAKED(strdup(tabName.c_str())))); + } + + if (!tabs->empty()) { + static PRM_Name tabsName("tabs"); + templates->push_back(PRM_Template(PRM_SWITCHER, tabs->size(), &tabsName, tabs->data())); + } + + for (auto& tabName : tabNames) { + auto inputsIt = inputsPerTab.find(tabName); + for (auto input : inputsIt->second) { + auto numChannels = GetNumChannels(input); + auto uiName = input->GetUIName(); + if (!uiName) { + continue; + } + + auto docString = input->GetDocString(); + const char* doc = docString ? LEAKED(strdup(docString)) : nullptr; + + auto name = LEAKED(new PRM_Name(PRM_Name::COPY, input->GetName(), uiName)); + auto& type = GetPRMType(input->GetType()); + auto range = LEAKED(NewPRMRange(input)); + PRM_ChoiceList* choiceList = nullptr; + auto defau1t = LEAKED(NewPRMDefault(input, numChannels, &choiceList)); + + PRM_ConditionalBase* conditionalBase = nullptr; + PRM_SpareData* spareData = nullptr; + PRM_Callback callback = nullptr; + int paramGroup = 1; + + templates->push_back(PRM_Template(type, numChannels, name, defau1t, choiceList, range, callback, spareData, paramGroup, doc, conditionalBase)); + } + } + + templates->push_back(PRM_Template()); + return &templates->at(0); +} + +VOP_RPRMaterial::VOP_RPRMaterial(OP_Network* parent, const char* name, VOP_RPRMaterialOperator* entry) + : VOP_Node(parent, name, entry) + , m_shaderInfo(entry->shaderInfo) { + for (size_t i = 0; i < m_shaderInfo->GetNumOutputs(); ++i) { + auto output = m_shaderInfo->GetOutput(i); + + if (output->GetType() == RprUsdMaterialNodeElement::kVolumeShader || + output->GetType() == RprUsdMaterialNodeElement::kDisplacementShader || + output->GetType() == RprUsdMaterialNodeElement::kSurfaceShader) { + + if (output->GetType() == RprUsdMaterialNodeElement::kVolumeShader) { + m_shaderType = VOP_ATMOSPHERE_SHADER; + } else if (output->GetType() == RprUsdMaterialNodeElement::kSurfaceShader) { + m_shaderType = VOP_SURFACE_SHADER; + } else if (output->GetType() == RprUsdMaterialNodeElement::kDisplacementShader) { + m_shaderType = VOP_DISPLACEMENT_SHADER; + } + + setMaterialFlag(true); + break; + } + } +} + +const char* VOP_RPRMaterial::inputLabel(unsigned i_idx) const { + return m_shaderInfo->GetInput(i_idx)->GetName(); +} + +const char* VOP_RPRMaterial::outputLabel(unsigned i_idx) const { + return m_shaderInfo->GetOutput(i_idx)->GetName(); +} + +unsigned VOP_RPRMaterial::minInputs() const { + return 0; +} + +unsigned VOP_RPRMaterial::getNumVisibleInputs() const { + return m_shaderInfo->GetNumInputs(); +} + +unsigned VOP_RPRMaterial::orderedInputs() const { + return m_shaderInfo->GetNumInputs(); +} + +#if HDK_API_VERSION >= 18000000 + +UT_StringHolder VOP_RPRMaterial::getShaderName( + VOP_ShaderNameStyle style, + VOP_Type shader_type) const { + /* This name is what becomes the shader id in USD land. Our Hydra plugin + will use it to find the correct shader. */ + if (style == VOP_ShaderNameStyle::PLAIN) { + return m_shaderInfo->GetName(); + } + + return VOP_Node::getShaderName(style, shader_type); +} + +VOP_Type VOP_RPRMaterial::getShaderType() const { + return m_shaderType; +} + +#endif + +void VOP_RPRMaterial::getInputNameSubclass(UT_String &in, int i_idx) const { + in = inputLabel(i_idx); +} + +int VOP_RPRMaterial::getInputFromNameSubclass(const UT_String &in) const { + for (size_t idx = 0; idx < m_shaderInfo->GetNumInputs(); ++idx) { + if (m_shaderInfo->GetInput(idx)->GetName() == in) { + return static_cast(idx); + } + } + return -1; +} + +void VOP_RPRMaterial::getInputTypeInfoSubclass( + VOP_TypeInfo &o_type_info, + int i_idx) { + o_type_info.setType(GetVOPType(m_shaderInfo->GetInput(i_idx)->GetType())); +} + +void VOP_RPRMaterial::getAllowedInputTypeInfosSubclass( + unsigned i_idx, + VOP_VopTypeInfoArray &o_type_infos) { + VOP_TypeInfo info; + getInputTypeInfoSubclass(info, i_idx); + o_type_infos.append(info); +} + +void VOP_RPRMaterial::getOutputNameSubclass(UT_String &out, int i_idx) const { + out = outputLabel(i_idx); +} + +void VOP_RPRMaterial::getOutputTypeInfoSubclass( + VOP_TypeInfo &o_type_info, + int i_idx) { + o_type_info.setType(GetVOPType(m_shaderInfo->GetOutput(i_idx)->GetType())); +} + +static const char* GetUIName(RprUsdMaterialNodeInfo const* shaderInfo) { + if (shaderInfo->GetUIName()) return shaderInfo->GetUIName(); + + // If UI name is not given, try to use name + std::string name = shaderInfo->GetName(); + + std::string rprPrefix("rpr_"); + auto rprPos = name.find(rprPrefix); + if (TfStringStartsWith(name, rprPrefix)) { + for (size_t i = 0; i < rprPrefix.size() - 1; ++i) { + name[rprPos + i] = std::toupper(name[rprPos + i]); + } + } + + bool isWord = false; + for (size_t i = 0; i < name.size(); ++i) { + if (std::isalpha(name[i])) { + if (!isWord) { + isWord = true; + name[i] = std::toupper(name[i]); + } + } else { + isWord = false; + } + + if (strchr("_", name[i])) { + name[i] = ' '; + } + } + + return LEAKED(strdup(name.c_str())); +} + +VOP_RPRMaterialOperator::VOP_RPRMaterialOperator(RprUsdMaterialNodeInfo const* shaderInfo) + : VOP_Operator( + TfStringPrintf("RPR::%s", shaderInfo->GetName()).c_str(), + GetUIName(shaderInfo), + VOP_RPRMaterial::Create, + VOP_RPRMaterial::GetTemplates(shaderInfo), + VOP_RPRMaterial::theChildTableName, + shaderInfo->GetNumInputs(), shaderInfo->GetNumInputs(), + // Put rpr here so Houdini's Material Builder won't see our VOPs + "rpr", + nullptr, + OP_FLAG_OUTPUT, + shaderInfo->GetNumOutputs()) + , shaderInfo(shaderInfo) { + + std::string subMenuPath("RPR"); + if (shaderInfo->GetUIFolder()) { + subMenuPath += "/"; + subMenuPath += shaderInfo->GetUIFolder(); + } + setOpTabSubMenuPath(subMenuPath.c_str()); + + setIconName("RPR"); + + /* + The RenderMask is what ends up being the MaterialNetworkSelector in + Hydra. If we don't set it, the default translator will not provide + networks at all. And if it does not match the Hydra plugin, we won't + see the networks there. + */ + auto vop_info = static_cast(getOpSpecificData()); + vop_info->setRenderMask("rpr"); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.h b/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.h new file mode 100644 index 000000000..de5b6d7ba --- /dev/null +++ b/pxr/imaging/plugin/rprHoudini/VOP_RPRMaterial.h @@ -0,0 +1,100 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPR_VOPS_MATERIAL_H +#define RPR_VOPS_MATERIAL_H + +#include "pxr/pxr.h" + +#include +#include +#include + +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdMaterialNodeInfo; + +struct VOP_RPRMaterialOperator : public VOP_Operator { + VOP_RPRMaterialOperator(RprUsdMaterialNodeInfo const* shaderInfo); + + RprUsdMaterialNodeInfo const* shaderInfo; +}; + +class VOP_RPRMaterial : public VOP_Node { +public: + /// Adds an instance of VOP_RPRMaterial to a network. + static OP_Node* Create(OP_Network* net, const char* name, OP_Operator* entry); + + /// Returns the templates for the shader's input parameters + static PRM_Template* GetTemplates(RprUsdMaterialNodeInfo const* shaderInfo); + + /// Returns the label for input port at index i_idx + const char* inputLabel(unsigned i_idx) const override; + /// Returns the label for output port at index i_idx + const char* outputLabel(unsigned i_idx) const override; + + /// Minimum inputs that must be connected to a node for it to cook. + unsigned minInputs() const override; + + /// Returns the number input ports that should be visible + unsigned getNumVisibleInputs() const override; + + /// Returns the number of ordered (ie : non-indexed) inputs + unsigned orderedInputs() const override; + +#if HDK_API_VERSION >= 18000000 + /// From VOP_Node + UT_StringHolder getShaderName( + VOP_ShaderNameStyle style, + VOP_Type shader_type) const override; + + VOP_Type getShaderType() const override; +#endif + +protected: + VOP_RPRMaterial(OP_Network* parent, const char* name, VOP_RPRMaterialOperator* entry); + + /// Returns the internal name of an input parameter. + void getInputNameSubclass(UT_String &in, int i_idx) const override; + /// Returns the index of the named input + int getInputFromNameSubclass(const UT_String &in) const override; + /// Fills the info about the source of an input parameter + void getInputTypeInfoSubclass( + VOP_TypeInfo &o_type_info, + int i_idx) override; + /** + Fills the info about the acceptable types for the source of an input + parameter. + */ + void getAllowedInputTypeInfosSubclass( + unsigned i_idx, + VOP_VopTypeInfoArray &o_type_infos) override; + + /// Returns the internal name of an output parameter. + void getOutputNameSubclass(UT_String &out, int i_idx) const override; + /// Fills the info about an output parameter + void getOutputTypeInfoSubclass( + VOP_TypeInfo &o_type_info, + int i_idx) override; + +private: + RprUsdMaterialNodeInfo const* m_shaderInfo; + VOP_Type m_shaderType = VOP_SURFACE_SHADER; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPR_VOPS_MATERIAL_H diff --git a/pxr/imaging/plugin/rprHoudini/plugin.cpp b/pxr/imaging/plugin/rprHoudini/plugin.cpp new file mode 100644 index 000000000..237691575 --- /dev/null +++ b/pxr/imaging/plugin/rprHoudini/plugin.cpp @@ -0,0 +1,31 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "VOP_RPRMaterial.h" +#include "pxr/imaging/rprUsd/materialRegistry.h" + +#include +#include + +void newVopOperator(OP_OperatorTable* io_table) { + PXR_NAMESPACE_USING_DIRECTIVE + for (auto& nodeDesc : RprUsdMaterialRegistry::GetInstance().GetRegisteredNodes()) { + if (!nodeDesc.info) continue; + + try { + io_table->addOperator(new VOP_RPRMaterialOperator(nodeDesc.info)); + } catch (std::exception& e) { + fprintf(stderr, "Failed to add %s VOP", nodeDesc.info->GetName()); + } + } +} diff --git a/pxr/imaging/plugin/rprHoudini/ui/RPR.svg b/pxr/imaging/plugin/rprHoudini/ui/RPR.svg new file mode 100644 index 000000000..1c6d9f1ce --- /dev/null +++ b/pxr/imaging/plugin/rprHoudini/ui/RPR.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/CMakeLists.txt b/pxr/imaging/rprUsd/CMakeLists.txt new file mode 100644 index 000000000..fecc6506d --- /dev/null +++ b/pxr/imaging/rprUsd/CMakeLists.txt @@ -0,0 +1,59 @@ +set(PXR_PREFIX pxr/imaging) +set(PXR_PACKAGE rprUsd) + +pxr_library(rprUsd + DISABLE_PRECOMPILED_HEADERS + + LIBRARIES + gf + tf + vt + hd + glf + sdf + arch + work + cpprpr + MaterialXCore + MaterialXFormat + + PUBLIC_CLASSES + util + contextHelpers + coreImage + debugCodes + imageCache + material + materialMappings + materialRegistry + + PUBLIC_HEADERS + api.h + contextMetadata.h + error.h + helpers.h + materialHelpers.h + + RESOURCE_FILES +) + +target_sources(rprUsd PRIVATE + materialNodes/materialNode.h + materialNodes/usdNode.h + materialNodes/usdNode.cpp + materialNodes/mtlxNode.h + materialNodes/mtlxNode.cpp + materialNodes/rpr/baseNode.h + materialNodes/rpr/baseNode.cpp + materialNodes/rpr/nodeInfo.h + materialNodes/rpr/catcherNode.cpp + materialNodes/rpr/displaceNode.cpp + materialNodes/rpr/arithmeticNode.h + materialNodes/rpr/arithmeticNode.cpp + materialNodes/rpr/combineShadersNode.cpp + materialNodes/houdiniPrincipledShaderNode.h + materialNodes/houdiniPrincipledShaderNode.cpp) + +add_subdirectory(materialNodes/mtlxFiles) + +GroupSources(rprUsd) diff --git a/pxr/imaging/rprUsd/api.h b/pxr/imaging/rprUsd/api.h new file mode 100644 index 000000000..bce8830c4 --- /dev/null +++ b/pxr/imaging/rprUsd/api.h @@ -0,0 +1,37 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef PXR_IMAGING_RPR_USD_API_H +#define PXR_IMAGING_RPR_USD_API_H + +#include "pxr/base/arch/export.h" + +#if defined(PXR_STATIC) +# define RPRUSD_API +# define RPRUSD_API_TEMPLATE_CLASS(...) +# define RPRUSD_API_TEMPLATE_STRUCT(...) +# define RPRUSD_LOCAL +#else +# if defined(RPRUSD_EXPORTS) +# define RPRUSD_API ARCH_EXPORT +# define RPRUSD_API_TEMPLATE_CLASS(...) ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) +# define RPRUSD_API_TEMPLATE_STRUCT(...) ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) +# else +# define RPRUSD_API ARCH_IMPORT +# define RPRUSD_API_TEMPLATE_CLASS(...) ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) +# define RPRUSD_API_TEMPLATE_STRUCT(...) ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) +# endif +# define RPRUSD_LOCAL ARCH_HIDDEN +#endif + +#endif // PXR_IMAGING_RPR_USD_API_H diff --git a/pxr/imaging/plugin/hdRpr/rpr/contextHelpers.cpp b/pxr/imaging/rprUsd/contextHelpers.cpp similarity index 84% rename from pxr/imaging/plugin/hdRpr/rpr/contextHelpers.cpp rename to pxr/imaging/rprUsd/contextHelpers.cpp index 340ab3ef8..726c4a9ca 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/contextHelpers.cpp +++ b/pxr/imaging/rprUsd/contextHelpers.cpp @@ -11,9 +11,10 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#include "contextHelpers.h" -#include "error.h" -#include "debugCodes.h" +#include "pxr/imaging/rprUsd/contextHelpers.h" +#include "pxr/imaging/rprUsd/contextMetadata.h" +#include "pxr/imaging/rprUsd/debugCodes.h" +#include "pxr/imaging/rprUsd/error.h" #include "pxr/imaging/glf/glew.h" #include "pxr/base/arch/env.h" @@ -33,16 +34,12 @@ limitations under the License. #include #define PRINT_CONTEXT_CREATION_DEBUG_INFO(format, ...) \ - if (!PXR_NS::TfDebug::IsEnabled(PXR_NS::HD_RPR_DEBUG_CONTEXT_CREATION)) /* empty */; else PXR_NS::TfDebug::Helper().Msg(format, ##__VA_ARGS__) + if (!TfDebug::IsEnabled(RPR_USD_DEBUG_CORE_UNSUPPORTED_ERROR)) /* empty */; else TfDebug::Helper().Msg(format, ##__VA_ARGS__) PXR_NAMESPACE_OPEN_SCOPE -TF_DEFINE_ENV_SETTING(HDRPR_ENABLE_TRACING, false, "Enable tracing of RPR core"); -TF_DEFINE_ENV_SETTING(HDRPR_TRACING_DIR, "", "Where to store RPR core tracing files. Must be a path to valid directory"); - -PXR_NAMESPACE_CLOSE_SCOPE - -namespace rpr { +TF_DEFINE_ENV_SETTING(RPRUSD_ENABLE_TRACING, false, "Enable tracing of RPR core"); +TF_DEFINE_ENV_SETTING(RPRUSD_TRACING_DIR, "", "Where to store RPR core tracing files. Must be a path to valid directory"); namespace { @@ -100,10 +97,10 @@ std::string GetRprSdkPath() { } void SetupRprTracing() { - if (PXR_NS::TfGetEnvSetting(PXR_NS::HDRPR_ENABLE_TRACING)) { + if (TfGetEnvSetting(RPRUSD_ENABLE_TRACING)) { RPR_ERROR_CHECK(rprContextSetParameterByKey1u(nullptr, RPR_CONTEXT_TRACING_ENABLED, 1), "Failed to set context tracing parameter"); - auto tracingDir = PXR_NS::TfGetEnvSetting(PXR_NS::HDRPR_TRACING_DIR); + auto tracingDir = TfGetEnvSetting(RPRUSD_TRACING_DIR); if (!tracingDir.empty()) { printf("RPR tracing directory: %s\n", tracingDir.c_str()); } @@ -111,16 +108,17 @@ void SetupRprTracing() { } } -const std::map kPluginLibNames = { +const std::map kPluginLibNames = { #ifdef WIN32 {kPluginTahoe, "Tahoe64.dll"}, - {kPluginNorthStar, "Northstar64.dll"}, + {kPluginNorthstar, "Northstar64.dll"}, {kPluginHybrid, "Hybrid.dll"}, #elif defined __linux__ {kPluginTahoe, "libTahoe64.so"}, {kPluginHybrid, "Hybrid.so"}, #elif defined __APPLE__ {kPluginTahoe, "libTahoe64.dylib"}, + {kPluginNorthstar, "libNorthstar64.dylib"}, #endif }; @@ -148,6 +146,7 @@ rpr::CreationFlags getAllCompatibleGpuFlags(rpr_int pluginID, const char* cacheP } if (infoStatus != RPR_SUCCESS) { PRINT_CONTEXT_CREATION_DEBUG_INFO("Failed to query device name: %d\n", infoStatus); + return false; } rprObjectDelete(temporaryContext); @@ -187,14 +186,14 @@ rpr::CreationFlags getAllCompatibleGpuFlags(rpr_int pluginID, const char* cacheP return creationFlags; } -rpr::CreationFlags getRprCreationFlags(RenderDeviceType renderDevice, rpr_int pluginID, const char* cachePath) { +rpr::CreationFlags getRprCreationFlags(RprUsdRenderDeviceType renderDevice, rpr_int pluginID, const char* cachePath) { rpr::CreationFlags flags = 0x0; - if (kRenderDeviceCPU == renderDevice) { - PRINT_CONTEXT_CREATION_DEBUG_INFO("hdRpr CPU context\n"); + if (RprUsdRenderDeviceType::CPU == renderDevice) { + PRINT_CONTEXT_CREATION_DEBUG_INFO("RPR CPU context\n"); flags = RPR_CREATION_FLAGS_ENABLE_CPU; - } else if (kRenderDeviceGPU == renderDevice) { - PRINT_CONTEXT_CREATION_DEBUG_INFO("hdRpr GPU context\n"); + } else if (RprUsdRenderDeviceType::GPU == renderDevice) { + PRINT_CONTEXT_CREATION_DEBUG_INFO("RPR GPU context\n"); flags = getAllCompatibleGpuFlags(pluginID, cachePath); } else { return 0x0; @@ -209,7 +208,7 @@ rpr::CreationFlags getRprCreationFlags(RenderDeviceType renderDevice, rpr_int pl } // namespace anonymous -Context* CreateContext(char const* cachePath, ContextMetadata* metadata) { +rpr::Context* RprUsdCreateContext(char const* cachePath, RprUsdContextMetadata* metadata) { SetupRprTracing(); auto pluginLibNameIter = kPluginLibNames.find(metadata->pluginType); @@ -238,9 +237,9 @@ Context* CreateContext(char const* cachePath, ContextMetadata* metadata) { } else { flags = getRprCreationFlags(metadata->renderDeviceType, pluginID, cachePath); if (!flags) { - bool isGpuIncompatible = metadata->renderDeviceType == kRenderDeviceGPU; + bool isGpuIncompatible = metadata->renderDeviceType == RprUsdRenderDeviceType::GPU; PRINT_CONTEXT_CREATION_DEBUG_INFO("%s is not compatible", isGpuIncompatible ? "GPU" : "CPU"); - metadata->renderDeviceType = isGpuIncompatible ? kRenderDeviceCPU : kRenderDeviceGPU; + metadata->renderDeviceType = isGpuIncompatible ? RprUsdRenderDeviceType::CPU : RprUsdRenderDeviceType::GPU; flags = getRprCreationFlags(metadata->renderDeviceType, pluginID, cachePath); if (!flags) { PRINT_CONTEXT_CREATION_DEBUG_INFO("Could not find compatible device"); @@ -252,10 +251,10 @@ Context* CreateContext(char const* cachePath, ContextMetadata* metadata) { } if (metadata->isGlInteropEnabled) { - if (metadata->renderDeviceType == kRenderDeviceCPU || metadata->pluginType == kPluginHybrid) { + if (metadata->renderDeviceType == RprUsdRenderDeviceType::CPU || metadata->pluginType == kPluginHybrid) { PRINT_CONTEXT_CREATION_DEBUG_INFO("GL interop could not be used with CPU rendering or Hybrid plugin"); metadata->isGlInteropEnabled = false; - } else if (!PXR_NS::GlfGlewInit()) { + } else if (!GlfGlewInit()) { PRINT_CONTEXT_CREATION_DEBUG_INFO("Failed to init GLEW. Disabling GL interop"); metadata->isGlInteropEnabled = false; } else { @@ -267,8 +266,8 @@ Context* CreateContext(char const* cachePath, ContextMetadata* metadata) { flags |= RPR_CREATION_FLAGS_ENABLE_GL_INTEROP; } - Status status; - auto context = Context::Create(RPR_API_VERSION, &pluginID, 1, flags, nullptr, cachePath, &status); + rpr::Status status; + auto context = rpr::Context::Create(RPR_API_VERSION, &pluginID, 1, flags, nullptr, cachePath, &status); if (context) { if (RPR_ERROR_CHECK(context->SetActivePlugin(pluginID), "Failed to set active plugin")) { delete context; @@ -281,4 +280,4 @@ Context* CreateContext(char const* cachePath, ContextMetadata* metadata) { return context; } -} // namespace rpr +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/rpr/imageHelpers.h b/pxr/imaging/rprUsd/contextHelpers.h similarity index 60% rename from pxr/imaging/plugin/hdRpr/rpr/imageHelpers.h rename to pxr/imaging/rprUsd/contextHelpers.h index 8b3cbdbfa..f07d36188 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/imageHelpers.h +++ b/pxr/imaging/rprUsd/contextHelpers.h @@ -11,19 +11,20 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#ifndef HDRPR_CORE_IMAGE_HELPERS_H -#define HDRPR_CORE_IMAGE_HELPERS_H +#ifndef PXR_IMAGING_RPR_USD_CONTEXT_HELPERS_H +#define PXR_IMAGING_RPR_USD_CONTEXT_HELPERS_H -#include +#include "pxr/imaging/rprUsd/api.h" -namespace rpr { +namespace rpr { class Context; } -Image* CreateImage(Context* context, char const* path, bool forceLinearSpace = false); -Image* CreateImage(Context* context, uint32_t width, uint32_t height, ImageFormat format, void const* data, rpr::Status* status = nullptr); +PXR_NAMESPACE_OPEN_SCOPE -ImageFormat GetImageFormat(Image* image); -ImageDesc GetImageDesc(Image* image); +struct RprUsdContextMetadata; -} // namespace rpr +RPRUSD_API +rpr::Context* RprUsdCreateContext(char const* cachePath, RprUsdContextMetadata* metadata); -#endif // HDRPR_CORE_IMAGE_HELPERS_H +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // PXR_IMAGING_RPR_USD_CONTEXT_HELPERS_H diff --git a/pxr/imaging/plugin/hdRpr/rpr/contextMetadata.h b/pxr/imaging/rprUsd/contextMetadata.h similarity index 63% rename from pxr/imaging/plugin/hdRpr/rpr/contextMetadata.h rename to pxr/imaging/rprUsd/contextMetadata.h index 9852d5bcb..9d3e03919 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/contextMetadata.h +++ b/pxr/imaging/rprUsd/contextMetadata.h @@ -11,32 +11,33 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#ifndef HDRPR_CORE_CONTEXT_METADATA_H -#define HDRPR_CORE_CONTEXT_METADATA_H +#ifndef PXR_IMAGING_RPR_USD_CONTEXT_METADATA_H +#define PXR_IMAGING_RPR_USD_CONTEXT_METADATA_H -namespace rpr { +#include "pxr/pxr.h" -enum PluginType { +PXR_NAMESPACE_OPEN_SCOPE + +enum RprUsdPluginType { kPluginInvalid = -1, kPluginTahoe, - kPluginNorthStar, + kPluginNorthstar, kPluginHybrid, kPluginsCount }; -enum RenderDeviceType { - kRenderDeviceInvalid = -1, - kRenderDeviceCPU, - kRenderDeviceGPU, - kRenderDevicesCount +enum class RprUsdRenderDeviceType { + Invalid, + CPU, + GPU, }; -struct ContextMetadata { - PluginType pluginType = kPluginInvalid; - RenderDeviceType renderDeviceType = kRenderDeviceInvalid; +struct RprUsdContextMetadata { + RprUsdPluginType pluginType = kPluginInvalid; + RprUsdRenderDeviceType renderDeviceType = RprUsdRenderDeviceType::Invalid; bool isGlInteropEnabled = false; }; -} // namespace rpr +PXR_NAMESPACE_CLOSE_SCOPE -#endif // HDRPR_CORE_CONTEXT_METADATA_H +#endif // PXR_IMAGING_RPR_USD_CONTEXT_METADATA_H diff --git a/pxr/imaging/rprUsd/coreImage.cpp b/pxr/imaging/rprUsd/coreImage.cpp new file mode 100644 index 000000000..6827a9beb --- /dev/null +++ b/pxr/imaging/rprUsd/coreImage.cpp @@ -0,0 +1,218 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/glf/glew.h" + +#include "pxr/imaging/rprUsd/coreImage.h" +#include "pxr/imaging/rprUsd/helpers.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +rpr::ImageDesc GetRprImageDesc(rpr::ImageFormat format, uint32_t width, uint32_t height, uint32_t depth = 1) { + int bytesPerComponent = 1; + if (format.type == RPR_COMPONENT_TYPE_FLOAT16) { + bytesPerComponent = 2; + } else if (format.type == RPR_COMPONENT_TYPE_FLOAT32) { + bytesPerComponent = 4; + } + + rpr::ImageDesc desc = {}; + desc.image_width = width; + desc.image_height = height; + desc.image_depth = depth; + desc.image_row_pitch = width * format.num_components * bytesPerComponent; + desc.image_slice_pitch = desc.image_row_pitch * height; + + return desc; +} + +rpr::Image* CreateRprImage(rpr::Context* context, GlfUVTextureData* textureData) { + rpr::ImageFormat format = {}; + switch (textureData->GLType()) { + case GL_UNSIGNED_BYTE: + format.type = RPR_COMPONENT_TYPE_UINT8; + break; + case GL_HALF_FLOAT: + format.type = RPR_COMPONENT_TYPE_FLOAT16; + break; + case GL_FLOAT: + format.type = RPR_COMPONENT_TYPE_FLOAT32; + break; + default: + TF_RUNTIME_ERROR("Unsupported pixel data GLtype: %#x", textureData->GLType()); + return nullptr; + } + + switch (textureData->GLFormat()) { + case GL_RED: + format.num_components = 1; + break; + case GL_RGB: + format.num_components = 3; + break; + case GL_RGBA: + format.num_components = 4; + break; + default: + TF_RUNTIME_ERROR("Unsupported pixel data GLformat: %#x", textureData->GLFormat()); + return nullptr; + } + rpr::ImageDesc desc = GetRprImageDesc(format, textureData->ResizedWidth(), textureData->ResizedHeight()); + + rpr::Status status; + auto rprImage = context->CreateImage(format, desc, textureData->GetRawBuffer(), &status); + if (!rprImage) { + RPR_ERROR_CHECK(status, "Failed to create image from data", context); + return nullptr; + } + + return rprImage; +} + +} // namespace anonymous + +RprUsdCoreImage* RprUsdCoreImage::Create(rpr::Context* context, std::string const& path) { + auto textureData = GlfUVTextureData::New(path, INT_MAX, 0, 0, 0, 0); + if (!textureData || !textureData->Read(0, false)) { + return nullptr; + } + + return Create(context, {{0, textureData.operator->()}}); +} + +RprUsdCoreImage* RprUsdCoreImage::Create(rpr::Context* context, uint32_t width, uint32_t height, rpr::ImageFormat format, void const* data, rpr::Status* status) { + auto rootImage = context->CreateImage(format, GetRprImageDesc(format, width, height), data, status); + if (!rootImage) { + return nullptr; + } + + return new RprUsdCoreImage(rootImage); +} + +RprUsdCoreImage* RprUsdCoreImage::Create( + rpr::Context* context, + std::vector const& tiles) { + + if (tiles.empty()) { + return nullptr; + } + + if (tiles.size() == 1 && tiles[0].id == 0) { + // Single non-UDIM tile + auto rprImage = CreateRprImage(context, tiles[0].textureData); + if (!rprImage) { + return nullptr; + } + + return new RprUsdCoreImage(rprImage); + } else { + // Process UDIM + RprUsdCoreImage* coreImage = nullptr; + + for (auto tile : tiles) { + if (tile.id < 1001 || tile.id > 1100) { + TF_RUNTIME_ERROR("Invalid UDIM tile id - %u", tile.id); + continue; + } + + auto rprImage = CreateRprImage(context, tile.textureData); + if (!rprImage) { + continue; + } + + if (!coreImage) { + coreImage = new RprUsdCoreImage; + + rpr::ImageFormat rootImageFormat = {}; + rootImageFormat.num_components = 0; + rootImageFormat.type = RPR_COMPONENT_TYPE_UINT8; + rpr::ImageDesc rootImageDesc = {}; + + rpr::Status status; + coreImage->m_rootImage = context->CreateImage(rootImageFormat, rootImageDesc, nullptr, &status); + if (!coreImage->m_rootImage) { + delete coreImage; + delete rprImage; + RPR_ERROR_CHECK(status, "Failed to create UDIM root image", context); + return nullptr; + } + } + + RPR_ERROR_CHECK(coreImage->m_rootImage->SetUDIM(tile.id, rprImage), "Failed to set UDIM"); + coreImage->m_subImages.push_back(rprImage); + } + + return coreImage; + } +} + +RprUsdCoreImage::~RprUsdCoreImage() { + delete m_rootImage; + for (auto image : m_subImages) { + delete image; + } + + m_rootImage = nullptr; + m_subImages.clear(); +} + +rpr::Image* RprUsdCoreImage::GetBaseImage() { + return m_subImages.empty() ? m_rootImage : m_subImages[0]; +} + +template +rpr::Status RprUsdCoreImage::ForEachImage(F f) { + if (m_subImages.empty()) { + return f(m_rootImage); + } else { + for (auto image : m_subImages) { + auto status = f(image); + if (status != RPR_SUCCESS) { + return status; + } + } + return RPR_SUCCESS; + } +} + +rpr::ImageFormat RprUsdCoreImage::GetFormat() { + return RprUsdGetInfo(GetBaseImage(), RPR_IMAGE_FORMAT); +} + +rpr::ImageDesc RprUsdCoreImage::GetDesc() { + return RprUsdGetInfo(GetBaseImage(), RPR_IMAGE_DESC); +} + +rpr::Status RprUsdCoreImage::GetInfo(rpr::ImageInfo imageInfo, size_t size, void* data, size_t* size_ret) { + return GetBaseImage()->GetInfo(imageInfo, size, data, size_ret); +} + +rpr::Status RprUsdCoreImage::SetWrap(rpr::ImageWrapType type) { + return ForEachImage([type](rpr::Image* image) { return image->SetWrap(type); }); +} + +rpr::Status RprUsdCoreImage::SetGamma(float gamma) { + return ForEachImage([gamma](rpr::Image* image) { return image->SetGamma(gamma); }); +} + +rpr::Status RprUsdCoreImage::SetMipmapEnabled(bool enabled) { + return ForEachImage([enabled](rpr::Image* image) { return image->SetMipmapEnabled(enabled); }); +} + +rpr::Status RprUsdCoreImage::SetFilter(rpr::ImageFilterType type) { + return ForEachImage([type](rpr::Image* image) { return image->SetFilter(type); }); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/coreImage.h b/pxr/imaging/rprUsd/coreImage.h new file mode 100644 index 000000000..80ccf0d63 --- /dev/null +++ b/pxr/imaging/rprUsd/coreImage.h @@ -0,0 +1,84 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef PXR_IMAGING_RPR_USD_CORE_IMAGE_H +#define PXR_IMAGING_RPR_USD_CORE_IMAGE_H + +#include "pxr/imaging/rprUsd/api.h" +#include "pxr/imaging/glf/uvTextureData.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdCoreImage { +public: + RPRUSD_API + static RprUsdCoreImage* Create(rpr::Context* context, std::string const& path); + + struct UDIMTile { + uint32_t id; + GlfUVTextureData* textureData; + + UDIMTile(uint32_t id, GlfUVTextureData* textureData) : id(id), textureData(textureData) {} + }; + RPRUSD_API + static RprUsdCoreImage* Create(rpr::Context* context, std::vector const& textureData); + + RPRUSD_API + static RprUsdCoreImage* Create(rpr::Context* context, uint32_t width, uint32_t height, rpr::ImageFormat format, void const* data, rpr::Status* status = nullptr); + + RPRUSD_API + ~RprUsdCoreImage(); + + RPRUSD_API + rpr::Image* GetRootImage() { return m_rootImage; } + + RPRUSD_API + rpr::ImageFormat GetFormat(); + + RPRUSD_API + rpr::ImageDesc GetDesc(); + + RPRUSD_API + rpr::Status GetInfo(rpr::ImageInfo imageInfo, size_t size, void* data, size_t* size_ret); + + RPRUSD_API + rpr::Status SetWrap(rpr::ImageWrapType type); + + RPRUSD_API + rpr::Status SetGamma(float gamma); + + RPRUSD_API + rpr::Status SetMipmapEnabled(bool enabled); + + RPRUSD_API + rpr::Status SetFilter(rpr::ImageFilterType type); + +private: + RprUsdCoreImage(rpr::Image* rootImage = nullptr) : m_rootImage(rootImage) {}; + rpr::Image* GetBaseImage(); + + template + rpr::Status ForEachImage(F f); + +private: + rpr::Image* m_rootImage = nullptr; + std::vector m_subImages; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // PXR_IMAGING_RPR_USD_CORE_IMAGE_H diff --git a/pxr/imaging/rprUsd/debugCodes.cpp b/pxr/imaging/rprUsd/debugCodes.cpp new file mode 100644 index 000000000..7eea2ed6d --- /dev/null +++ b/pxr/imaging/rprUsd/debugCodes.cpp @@ -0,0 +1,26 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/rprUsd/debugCodes.h" + +#include "pxr/base/tf/debug.h" +#include "pxr/base/tf/registryManager.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_REGISTRY_FUNCTION(TfDebug) { + TF_DEBUG_ENVIRONMENT_SYMBOL(RPR_USD_DEBUG_CORE_UNSUPPORTED_ERROR, "signal about unsupported errors"); + TF_DEBUG_ENVIRONMENT_SYMBOL(RPR_USD_DEBUG_DUMP_MATERIALS, "Dump material networks to the files in the current working directory") +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/debugCodes.h b/pxr/imaging/rprUsd/debugCodes.h new file mode 100644 index 000000000..fd4467519 --- /dev/null +++ b/pxr/imaging/rprUsd/debugCodes.h @@ -0,0 +1,29 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef PXR_IMAGING_RPR_USD_DEBUG_CODES_H +#define PXR_IMAGING_RPR_USD_DEBUG_CODES_H + +#include "pxr/pxr.h" +#include "pxr/base/tf/debug.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEBUG_CODES( + RPR_USD_DEBUG_CORE_UNSUPPORTED_ERROR, + RPR_USD_DEBUG_DUMP_MATERIALS +); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // PXR_IMAGING_RPR_USD_DEBUG_CODES_H diff --git a/pxr/imaging/plugin/hdRpr/rpr/error.h b/pxr/imaging/rprUsd/error.h similarity index 57% rename from pxr/imaging/plugin/hdRpr/rpr/error.h rename to pxr/imaging/rprUsd/error.h index 055da3ed5..e13dac002 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/error.h +++ b/pxr/imaging/rprUsd/error.h @@ -11,10 +11,10 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#ifndef HDRPR_CORE_ERROR_H -#define HDRPR_CORE_ERROR_H +#ifndef PXR_IMAGING_RPR_USD_ERROR_H +#define PXR_IMAGING_RPR_USD_ERROR_H -#include "debugCodes.h" +#include "pxr/imaging/rprUsd/debugCodes.h" #include "pxr/base/arch/functionLite.h" #include "pxr/base/tf/stringUtils.h" @@ -29,22 +29,22 @@ limitations under the License. auto st = status; \ if (st != RPR_SUCCESS) { \ assert(false); \ - throw rpr::Error(st, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__); \ + throw RprUsdError(st, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__); \ } \ } while(0); #define RPR_ERROR_CHECK(status, msg, ...) \ - rpr::IsErrorCheck(status, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__) + RprUsdFailed(status, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__) #define RPR_GET_ERROR_MESSAGE(status, msg, ...) \ - rpr::ConstructErrorMessage(status, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__) + RprUsdConstructErrorMessage(status, msg, __ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, ##__VA_ARGS__) #define RPR_THROW_ERROR_MSG(fmt, ...) \ - rpr::ThrowErrorMsg(__ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, fmt, ##__VA_ARGS__); + RprUsdThrowErrorMsg(__ARCH_FILE__, __ARCH_FUNCTION__, __LINE__, fmt, ##__VA_ARGS__); -namespace rpr { +PXR_NAMESPACE_OPEN_SCOPE -inline std::string ConstructErrorMessage(rpr_status errorStatus, std::string const& messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) { +inline std::string RprUsdConstructErrorMessage(rpr::Status errorStatus, std::string const& messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) { auto rprErrorString = [errorStatus, context]() -> std::string { if (context) { size_t lastErrorMessageSize = 0; @@ -71,52 +71,52 @@ inline std::string ConstructErrorMessage(rpr_status errorStatus, std::string con return "error code - " + std::to_string(errorStatus); }; - auto suffix = PXR_NS::TfStringPrintf(" in %s at line %zu of %s", function, line, file); + auto suffix = TfStringPrintf(" in %s at line %zu of %s", function, line, file); #ifdef RPR_GIT_SHORT_HASH - suffix += PXR_NS::TfStringPrintf("(%s)", RPR_GIT_SHORT_HASH); + suffix += TfStringPrintf("(%s)", RPR_GIT_SHORT_HASH); #endif // RPR_GIT_SHORT_HASH if (errorStatus == RPR_SUCCESS) { - return PXR_NS::TfStringPrintf("[RPR ERROR] %s%s", messageOnFail.c_str(), suffix.c_str()); + return TfStringPrintf("[RPR ERROR] %s%s", messageOnFail.c_str(), suffix.c_str()); } else { auto errorStr = rprErrorString(); - return PXR_NS::TfStringPrintf("[RPR ERROR] %s -- %s%s", messageOnFail.c_str(), errorStr.c_str(), suffix.c_str()); + return TfStringPrintf("[RPR ERROR] %s -- %s%s", messageOnFail.c_str(), errorStr.c_str(), suffix.c_str()); } } -inline bool IsErrorCheck(rpr_status status, const std::string& messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) { +inline bool RprUsdFailed(rpr::Status status, const char* messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) { if (RPR_SUCCESS == status) { return false; } - if ((status == RPR_ERROR_UNSUPPORTED || status == RPR_ERROR_UNIMPLEMENTED) && !PXR_NS::TfDebug::IsEnabled(PXR_NS::HD_RPR_DEBUG_CORE_UNSUPPORTED_ERROR)) { + if ((status == RPR_ERROR_UNSUPPORTED || status == RPR_ERROR_UNIMPLEMENTED) && !TfDebug::IsEnabled(RPR_USD_DEBUG_CORE_UNSUPPORTED_ERROR)) { return true; } - auto errorMessage = ConstructErrorMessage(status, messageOnFail.c_str(), file, function, line, context); + auto errorMessage = RprUsdConstructErrorMessage(status, messageOnFail, file, function, line, context); fprintf(stderr, "%s\n", errorMessage.c_str()); return true; } -class Error : public std::runtime_error { +class RprUsdError : public std::runtime_error { public: - Error(rpr_status errorStatus, const char* messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) - : std::runtime_error(ConstructErrorMessage(errorStatus, messageOnFail, file, function, line, context)) { + RprUsdError(rpr::Status errorStatus, const char* messageOnFail, char const* file, char const* function, size_t line, rpr::Context* context = nullptr) + : std::runtime_error(RprUsdConstructErrorMessage(errorStatus, messageOnFail, file, function, line, context)) { } - Error(std::string const& errorMesssage) + RprUsdError(std::string const& errorMesssage) : std::runtime_error(errorMesssage) { } }; -inline void ThrowErrorMsg(char const* file, char const* function, size_t line, const char* fmt, ...) { +inline void RprUsdThrowErrorMsg(char const* file, char const* function, size_t line, const char* fmt, ...) { va_list ap; va_start(ap, fmt); - auto messageOnFail = PXR_NS::TfVStringPrintf(fmt, ap); + auto messageOnFail = TfVStringPrintf(fmt, ap); va_end(ap); - throw Error(ConstructErrorMessage(RPR_SUCCESS, messageOnFail, file, function, line)); + throw RprUsdError(RprUsdConstructErrorMessage(RPR_SUCCESS, messageOnFail, file, function, line)); } -} // namespace rpr +PXR_NAMESPACE_CLOSE_SCOPE -#endif // HDRPR_CORE_ERROR_H +#endif // PXR_IMAGING_RPR_USD_ERROR_H diff --git a/pxr/imaging/plugin/hdRpr/rpr/helpers.h b/pxr/imaging/rprUsd/helpers.h similarity index 79% rename from pxr/imaging/plugin/hdRpr/rpr/helpers.h rename to pxr/imaging/rprUsd/helpers.h index 513b1bdf3..3ebc8e630 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/helpers.h +++ b/pxr/imaging/rprUsd/helpers.h @@ -11,21 +11,21 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#ifndef HDRPR_CORE_HELPERS_H -#define HDRPR_CORE_HELPERS_H +#ifndef PXR_IMAGING_RPR_USD_HELPERS_H +#define PXR_IMAGING_RPR_USD_HELPERS_H -#include "error.h" +#include "pxr/imaging/rprUsd/error.h" -namespace rpr { +PXR_NAMESPACE_OPEN_SCOPE template -T GetInfo(U* object, R info) { +T RprUsdGetInfo(U* object, R info) { T value = {}; size_t dummy; RPR_ERROR_CHECK_THROW(object->GetInfo(info, sizeof(value), &value, &dummy), "Failed to get object info"); return value; } -} // namespace rpr +PXR_NAMESPACE_CLOSE_SCOPE -#endif // HDRPR_CORE_HELPERS_H +#endif // PXR_IMAGING_RPR_USD_HELPERS_H diff --git a/pxr/imaging/rprUsd/imageCache.cpp b/pxr/imaging/rprUsd/imageCache.cpp new file mode 100644 index 000000000..d5fe88905 --- /dev/null +++ b/pxr/imaging/rprUsd/imageCache.cpp @@ -0,0 +1,213 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/glf/glew.h" +#include "pxr/imaging/rprUsd/imageCache.h" +#include "pxr/imaging/rprUsd/coreImage.h" +#include "pxr/imaging/rprUsd/helpers.h" +#include "pxr/imaging/rprUsd/util.h" +#include "pxr/base/arch/fileSystem.h" +#include "pxr/base/tf/diagnostic.h" + +PXR_NAMESPACE_OPEN_SCOPE + +template +size_t GetHash(T const& value) { + return std::hash{}(value); +} + +bool RprUsdImageCache::InitCacheKey( + std::string const& path, + std::vector const& tiles, + CacheKey* key) { + + key->path = path; + key->hash = GetHash(path); + + auto processTile = [key](std::string const& path) -> bool { + double modificationTime; + if (!ArchGetModificationTime(path.c_str(), &modificationTime)) return false; + + int64_t sizeInt = ArchGetFileLength(path.c_str()); + if (sizeInt == -1) return false; + + key->tiles.emplace_back(size_t(sizeInt), modificationTime); + key->hash ^= size_t(sizeInt) ^ GetHash(modificationTime); + + return true; + }; + + if (tiles.size() != 1 || tiles[0].id != 0) { + // UDIM tiles + std::string formatString; + if (!RprUsdGetUDIMFormatString(path, &formatString)) { + return false; + } + + for (auto& tile : tiles) { + if (!processTile(TfStringPrintf(formatString.c_str(), tile.id))) { + return false; + } + } + } else { + if (!processTile(path)) { + return false; + } + } + + return true; +} + +bool RprUsdImageCache::InitCacheEntryDesc( + GlfUVTextureData* data, + rpr::ImageWrapType wrapType, + bool forceLinearSpace, + CacheEntry::Desc* desc) { + if (!data) return false; + + auto internalFormat = data->GLInternalFormat(); + if (!forceLinearSpace && + (internalFormat == GL_SRGB || + internalFormat == GL_SRGB8 || + internalFormat == GL_SRGB_ALPHA || + internalFormat == GL_SRGB8_ALPHA8)) { + // XXX(RPR): sRGB formula is different from straight pow decoding, but it's the best we can do right now + desc->gamma = 2.2f; + } else { + desc->gamma = 1.0f; + } + + if (!wrapType) { + wrapType = RPR_IMAGE_WRAP_TYPE_REPEAT; + } + desc->wrapType = wrapType; + + return true; +} + +RprUsdImageCache::RprUsdImageCache(rpr::Context* context) + : m_context(context) { + +} + +std::shared_ptr +RprUsdImageCache::GetImage( + std::string const& path, + bool forceLinearSpace, + rpr::ImageWrapType wrapType, + std::vector const& tiles) { + if (tiles.empty()) { + return nullptr; + } + + CacheKey key; + CacheEntry::Desc desc; + if (!InitCacheKey(path, tiles, &key) || + !InitCacheEntryDesc(tiles[0].textureData, wrapType, forceLinearSpace, &desc)) { + return nullptr; + } + + auto it = m_cache.find(key); + if (it != m_cache.end()) { + auto& entries = it->second; + for (size_t i = 0; i < entries.size(); ++i) { + auto& entry = entries[i]; + if (entry.desc == desc) { + if (auto image = entry.handle.lock()) { + return image; + } else { + TF_CODING_ERROR("Expired cache entry was not removed"); + + if (i + 1 != entries.size()) { + std::swap(entry, entries.back()); + } + entries.pop_back(); + + break; + } + } + } + } + + auto coreImage = RprUsdCoreImage::Create(m_context, tiles); + if (!coreImage) { + return nullptr; + } + + RPR_ERROR_CHECK(coreImage->SetGamma(desc.gamma), "Failed to set image gamma"); + RPR_ERROR_CHECK(coreImage->SetWrap(desc.wrapType), "Failed to set image wrap type"); + + if (it == m_cache.end()) { + it = m_cache.emplace(key, CacheValue()).first; + } + + std::shared_ptr cachedImage(coreImage, + [this, key, desc](RprUsdCoreImage* coreImage) { + delete coreImage; + PopCacheEntry(key, desc); + } + ); + + CacheEntry cacheEntry; + cacheEntry.desc = desc; + cacheEntry.handle = cachedImage; + it->second.push_back(std::move(cacheEntry)); + + return cachedImage; +} + +void RprUsdImageCache::PopCacheEntry( + CacheKey const& key, + CacheEntry::Desc const& desc) { + + auto it = m_cache.find(key); + if (it == m_cache.end()) { + TF_CODING_ERROR("Failed to release cache entry: no entry with such key - path=%s", key.path.c_str()); + return; + } + + auto& entries = it->second; + + for (size_t i = 0; i < entries.size(); ++i) { + auto& entry = entries[i]; + if (entry.desc == desc) { + if (entries.size() == 1) { + // if this is the latest entry, remove whole key-value pair + m_cache.erase(it); + } else { + // avoid removing from the middle by swapping with the end element + if (i + 1 != entries.size()) { + std::swap(entry, entries.back()); + } + entries.pop_back(); + } + return; + } + } + + TF_CODING_ERROR("Failed to release cache entry: no entry with such desc - path=%s, gamma=%g, wrapType=%u", + key.path.c_str(), desc.gamma, desc.wrapType); +} + +bool RprUsdImageCache::CacheKey::Equal::operator()(CacheKey const& lhs, CacheKey const& rhs) const { + return lhs.tiles == rhs.tiles && + lhs.path == rhs.path; +} + +bool RprUsdImageCache::CacheEntry::Desc::operator==(Desc const& rhs) const { + constexpr static float kGammaEpsilon = 0.1f; + return wrapType == rhs.wrapType && + std::abs(gamma - rhs.gamma) < kGammaEpsilon; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/imageCache.h b/pxr/imaging/rprUsd/imageCache.h new file mode 100644 index 000000000..67f22f0aa --- /dev/null +++ b/pxr/imaging/rprUsd/imageCache.h @@ -0,0 +1,83 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_IMAGE_CACHE_H +#define RPRUSD_IMAGE_CACHE_H + +#include "pxr/imaging/rprUsd/coreImage.h" + +#include +#include +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdImageCache { +public: + RPRUSD_API + RprUsdImageCache(rpr::Context* context); + + RPRUSD_API + std::shared_ptr GetImage( + std::string const& path, + bool forceLinearSpace, + rpr::ImageWrapType wrapType, + std::vector const& data); + +private: + rpr::Context* m_context; + + struct CacheKey { + std::string path; + struct TileMetadata { + size_t size; + double modificationTime; + + TileMetadata(size_t size, double modificationTime) + : size(size), modificationTime(modificationTime) { + } + bool operator==(TileMetadata const& rhs) const { + return size == rhs.size && modificationTime == rhs.modificationTime; + } + }; + std::vector tiles; + + size_t hash; + + struct Equal { bool operator()(CacheKey const& lhs, CacheKey const& rhs) const; }; + struct Hash { size_t operator()(CacheKey const& key) const { return key.hash; }; }; + }; + bool InitCacheKey(std::string const& path, std::vector const&, CacheKey*); + + struct CacheEntry { + struct Desc { + float gamma; + rpr::ImageWrapType wrapType; + + bool operator==(Desc const& rhs) const; + }; + Desc desc; + std::weak_ptr handle; + }; + bool InitCacheEntryDesc(GlfUVTextureData*, rpr::ImageWrapType, bool forceLinearSpace, CacheEntry::Desc*); + + using CacheValue = std::vector; + std::unordered_map m_cache; + +private: + void PopCacheEntry(CacheKey const& key, CacheEntry::Desc const& desc); +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_IMAGE_CACHE_H diff --git a/pxr/imaging/rprUsd/material.cpp b/pxr/imaging/rprUsd/material.cpp new file mode 100644 index 000000000..eec48e536 --- /dev/null +++ b/pxr/imaging/rprUsd/material.cpp @@ -0,0 +1,77 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/rprUsd/material.h" +#include "pxr/imaging/rprUsd/error.h" + +#include "pxr/base/gf/vec2f.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +bool RprUsdMaterial::AttachTo(rpr::Shape* mesh, bool displacementEnabled) const { + bool fail = RPR_ERROR_CHECK(mesh->SetMaterial(m_surfaceNode), "Failed to set shape material"); + + fail |= RPR_ERROR_CHECK(mesh->SetVolumeMaterial(m_volumeNode), "Failed to set shape volume material"); + + if (displacementEnabled && m_displacementNode) { + size_t dummy; + int subdFactor; + if (RPR_ERROR_CHECK(mesh->GetInfo(RPR_SHAPE_SUBDIVISION_FACTOR, sizeof(subdFactor), &subdFactor, &dummy), "Failed to query mesh subdivision factor")) { + subdFactor = 0; + } + + if (subdFactor == 0) { + TF_WARN("Displacement material requires subdivision to be enabled. The subdivision will be enabled with refine level of 1"); + if (!RPR_ERROR_CHECK(mesh->SetSubdivisionFactor(1), "Failed to set mesh subdividion")) { + subdFactor = 1; + } + } + if (subdFactor > 0) { + fail |= RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(m_displacementNode), "Failed to set shape displacement material"); + + GfVec2f displacementScale(0.0f, 1.0f); + if (m_displacementScale.IsHolding()) { + displacementScale = m_displacementScale.UncheckedGet(); + } + + fail |= RPR_ERROR_CHECK(mesh->SetDisplacementScale(displacementScale[0], displacementScale[1]), "Failed to set shape displacement scale"); + } + } else { + fail |= RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(nullptr), "Failed to unset shape displacement material"); + } + + fail |= RPR_ERROR_CHECK(mesh->SetShadowCatcher(m_isShadowCatcher), "Failed to set shape shadow catcher"); + fail |= RPR_ERROR_CHECK(mesh->SetReflectionCatcher(m_isReflectionCatcher), "Failed to set shape reflection catcher"); + + return !fail; +} + +bool RprUsdMaterial::AttachTo(rpr::Curve* curve) const { + return !RPR_ERROR_CHECK(curve->SetMaterial(m_surfaceNode), "Failed to set curve material"); +} + +void RprUsdMaterial::DetachFrom(rpr::Shape* mesh) { + RPR_ERROR_CHECK(mesh->SetMaterial(nullptr), "Failed to unset shape material"); + RPR_ERROR_CHECK(mesh->SetVolumeMaterial(nullptr), "Failed to unset shape volume material"); + RPR_ERROR_CHECK(mesh->SetDisplacementMaterial(nullptr), "Failed to unset shape displacement material"); + RPR_ERROR_CHECK(mesh->SetShadowCatcher(false), "Failed to unset shape shadow catcher"); + RPR_ERROR_CHECK(mesh->SetReflectionCatcher(false), "Failed to unset shape reflection catcher"); +} + +void RprUsdMaterial::DetachFrom(rpr::Curve* curve) { + RPR_ERROR_CHECK(curve->SetMaterial(nullptr), "Failed to unset curve material"); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/material.h b/pxr/imaging/rprUsd/material.h new file mode 100644 index 000000000..b53b4bdc7 --- /dev/null +++ b/pxr/imaging/rprUsd/material.h @@ -0,0 +1,57 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_H +#define RPRUSD_MATERIAL_H + +#include "pxr/imaging/rprUsd/api.h" +#include "pxr/base/vt/value.h" +#include "pxr/base/tf/token.h" + +namespace rpr { class Shape; class Curve; class MaterialNode; } + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdMaterial { +public: + RPRUSD_API + virtual ~RprUsdMaterial() = default; + + RPRUSD_API + TfToken const& GetUvPrimvarName() const { return m_uvPrimvarName; } + + RPRUSD_API + bool AttachTo(rpr::Shape* mesh, bool displacementEnabled) const; + + RPRUSD_API + bool AttachTo(rpr::Curve* curve) const; + + RPRUSD_API + static void DetachFrom(rpr::Shape* mesh); + + RPRUSD_API + static void DetachFrom(rpr::Curve* curve); + +protected: + rpr::MaterialNode* m_surfaceNode = nullptr; + rpr::MaterialNode* m_displacementNode = nullptr; + rpr::MaterialNode* m_volumeNode = nullptr; + bool m_isShadowCatcher = false; + bool m_isReflectionCatcher = false; + TfToken m_uvPrimvarName; + VtValue m_displacementScale; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_H diff --git a/pxr/imaging/rprUsd/materialHelpers.h b/pxr/imaging/rprUsd/materialHelpers.h new file mode 100644 index 000000000..e28a69587 --- /dev/null +++ b/pxr/imaging/rprUsd/materialHelpers.h @@ -0,0 +1,79 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_HELPERS_H +#define RPRUSD_MATERIAL_HELPERS_H + +#include "pxr/base/vt/value.h" +#include "pxr/base/gf/vec2f.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/vec4f.h" +#include "pxr/imaging/rprUsd/error.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +using RprMaterialNodePtr = std::shared_ptr; + +inline bool SetRprInput(rpr::MaterialNode* node, rpr::MaterialNodeInput input, VtValue const& value) { + if (value.IsHolding()) { + return !RPR_ERROR_CHECK(node->SetInput(input, value.UncheckedGet()), "Failed to set material uint32_t input"); + } else if (value.IsHolding()) { + return !RPR_ERROR_CHECK(node->SetInput(input, rpr_uint(value.UncheckedGet())), "Failed to set material int input"); + } else if (value.IsHolding()) { + rpr_uint v = value.UncheckedGet() ? 1 : 0; + return !RPR_ERROR_CHECK(node->SetInput(input, v), "Failed to set material bool input"); + } else if (value.IsHolding()) { + auto v = value.UncheckedGet(); + return !RPR_ERROR_CHECK(node->SetInput(input, v, v, v, v), "Failed to set material float input"); + } else if (value.IsHolding()) { + auto& v = value.UncheckedGet(); + return !RPR_ERROR_CHECK(node->SetInput(input, v[0], v[1], v[2], 1.0f), "Failed to set material GfVec3f input"); + } else if (value.IsHolding()) { + auto& v = value.UncheckedGet(); + return !RPR_ERROR_CHECK(node->SetInput(input, v[0], v[1], 1.0f, 1.0f), "Failed to set material GfVec2f input"); + } else if (value.IsHolding()) { + auto& v = value.UncheckedGet(); + return !RPR_ERROR_CHECK(node->SetInput(input, v[0], v[1], v[2], v[3]), "Failed to set material GfVec4f input"); + } else if (value.IsHolding()) { + return !RPR_ERROR_CHECK(node->SetInput(input, value.UncheckedGet().get()), "Failed to set material RprMaterialNodePtr input"); + } else { + TF_RUNTIME_ERROR("Failed to set node input: unknown VtValue type - %s", value.GetTypeName().c_str()); + return false; + } +} + +inline GfVec4f GetRprFloat(VtValue const& value) { + if (value.IsHolding()) { + return GfVec4f(value.Get()); + } else if (value.IsHolding()) { + GfVec3f v = value.Get(); + return GfVec4f(v[0], v[1], v[2], 1.0f); + } if (value.IsHolding()) { + return GfVec4f(value.Get()); + } else { + return value.Get(); + } +} + +inline bool GfIsEqual(GfVec4f const& v1, GfVec4f const& v2, float tolerance = 1e-5f) { + return std::abs(v1[0] - v2[0]) <= tolerance && + std::abs(v1[1] - v2[1]) <= tolerance && + std::abs(v1[2] - v2[2]) <= tolerance && + std::abs(v1[3] - v2[3]) <= tolerance; +} + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_HELPERS_H diff --git a/pxr/imaging/rprUsd/materialMappings.cpp b/pxr/imaging/rprUsd/materialMappings.cpp new file mode 100644 index 000000000..801b5ba1a --- /dev/null +++ b/pxr/imaging/rprUsd/materialMappings.cpp @@ -0,0 +1,224 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/rprUsd/materialMappings.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PUBLIC_TOKENS(RprUsdMaterialNodeInputTokens, RPRUSD_MATERIAL_NODE_INPUT_TOKENS); +TF_DEFINE_PUBLIC_TOKENS(RprUsdMaterialNodeTypeTokens, RPRUSD_MATERIAL_NODE_TYPE_TOKENS); +TF_DEFINE_PUBLIC_TOKENS(RprUsdMaterialInputModeTokens, RPRUSD_MATERIAL_INPUT_MODE_TOKENS); + +bool ToRpr(TfToken const& id, rpr::MaterialNodeType* out, bool pedantic) { + static const std::map s_mapping = { + {RprUsdMaterialNodeTypeTokens->diffuse, RPR_MATERIAL_NODE_DIFFUSE}, + {RprUsdMaterialNodeTypeTokens->microfacet, RPR_MATERIAL_NODE_MICROFACET}, + {RprUsdMaterialNodeTypeTokens->reflection, RPR_MATERIAL_NODE_REFLECTION}, + {RprUsdMaterialNodeTypeTokens->refraction, RPR_MATERIAL_NODE_REFRACTION}, + {RprUsdMaterialNodeTypeTokens->microfacet_refraction, RPR_MATERIAL_NODE_MICROFACET_REFRACTION}, + {RprUsdMaterialNodeTypeTokens->transparent, RPR_MATERIAL_NODE_TRANSPARENT}, + {RprUsdMaterialNodeTypeTokens->emissive, RPR_MATERIAL_NODE_EMISSIVE}, + {RprUsdMaterialNodeTypeTokens->ward, RPR_MATERIAL_NODE_WARD}, + {RprUsdMaterialNodeTypeTokens->add, RPR_MATERIAL_NODE_ADD}, + {RprUsdMaterialNodeTypeTokens->blend, RPR_MATERIAL_NODE_BLEND}, + {RprUsdMaterialNodeTypeTokens->arithmetic, RPR_MATERIAL_NODE_ARITHMETIC}, + {RprUsdMaterialNodeTypeTokens->fresnel, RPR_MATERIAL_NODE_FRESNEL}, + {RprUsdMaterialNodeTypeTokens->normal_map, RPR_MATERIAL_NODE_NORMAL_MAP}, + {RprUsdMaterialNodeTypeTokens->image_texture, RPR_MATERIAL_NODE_IMAGE_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->noise2d_texture, RPR_MATERIAL_NODE_NOISE2D_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->dot_texture, RPR_MATERIAL_NODE_DOT_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->gradient_texture, RPR_MATERIAL_NODE_GRADIENT_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->checker_texture, RPR_MATERIAL_NODE_CHECKER_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->constant_texture, RPR_MATERIAL_NODE_CONSTANT_TEXTURE}, + {RprUsdMaterialNodeTypeTokens->input_lookup, RPR_MATERIAL_NODE_INPUT_LOOKUP}, + {RprUsdMaterialNodeTypeTokens->blend_value, RPR_MATERIAL_NODE_BLEND_VALUE}, + {RprUsdMaterialNodeTypeTokens->passthrough, RPR_MATERIAL_NODE_PASSTHROUGH}, + {RprUsdMaterialNodeTypeTokens->orennayar, RPR_MATERIAL_NODE_ORENNAYAR}, + {RprUsdMaterialNodeTypeTokens->fresnel_schlick, RPR_MATERIAL_NODE_FRESNEL_SCHLICK}, + {RprUsdMaterialNodeTypeTokens->diffuse_refraction, RPR_MATERIAL_NODE_DIFFUSE_REFRACTION}, + {RprUsdMaterialNodeTypeTokens->bump_map, RPR_MATERIAL_NODE_BUMP_MAP}, + {RprUsdMaterialNodeTypeTokens->volume, RPR_MATERIAL_NODE_VOLUME}, + {RprUsdMaterialNodeTypeTokens->microfacet_anisotropic_reflection, RPR_MATERIAL_NODE_MICROFACET_ANISOTROPIC_REFLECTION}, + {RprUsdMaterialNodeTypeTokens->microfacet_anisotropic_refraction, RPR_MATERIAL_NODE_MICROFACET_ANISOTROPIC_REFRACTION}, + {RprUsdMaterialNodeTypeTokens->twosided, RPR_MATERIAL_NODE_TWOSIDED}, + {RprUsdMaterialNodeTypeTokens->uv_procedural, RPR_MATERIAL_NODE_UV_PROCEDURAL}, + {RprUsdMaterialNodeTypeTokens->microfacet_beckmann, RPR_MATERIAL_NODE_MICROFACET_BECKMANN}, + {RprUsdMaterialNodeTypeTokens->phong, RPR_MATERIAL_NODE_PHONG}, + {RprUsdMaterialNodeTypeTokens->buffer_sampler, RPR_MATERIAL_NODE_BUFFER_SAMPLER}, + {RprUsdMaterialNodeTypeTokens->uv_triplanar, RPR_MATERIAL_NODE_UV_TRIPLANAR}, + {RprUsdMaterialNodeTypeTokens->ao_map, RPR_MATERIAL_NODE_AO_MAP}, + {RprUsdMaterialNodeTypeTokens->user_texture_0, RPR_MATERIAL_NODE_USER_TEXTURE_0}, + {RprUsdMaterialNodeTypeTokens->user_texture_1, RPR_MATERIAL_NODE_USER_TEXTURE_1}, + {RprUsdMaterialNodeTypeTokens->user_texture_2, RPR_MATERIAL_NODE_USER_TEXTURE_2}, + {RprUsdMaterialNodeTypeTokens->user_texture_3, RPR_MATERIAL_NODE_USER_TEXTURE_3}, + {RprUsdMaterialNodeTypeTokens->uberv2, RPR_MATERIAL_NODE_UBERV2}, + {RprUsdMaterialNodeTypeTokens->transform, RPR_MATERIAL_NODE_TRANSFORM}, + {RprUsdMaterialNodeTypeTokens->rgb_to_hsv, RPR_MATERIAL_NODE_RGB_TO_HSV}, + {RprUsdMaterialNodeTypeTokens->hsv_to_rgb, RPR_MATERIAL_NODE_HSV_TO_RGB}, + }; + + auto it = s_mapping.find(id); + if (it == s_mapping.end()) { + if (pedantic) { + TF_CODING_ERROR("Invalid rpr::MaterialNodeType id: %s", id.GetText()); + } + return false; + } + + *out = it->second; + return true; +} + +bool ToRpr(TfToken const& id, rpr::MaterialNodeInput* out, bool pedantic) { + static const std::map s_mapping = { + {RprUsdMaterialNodeInputTokens->color, RPR_MATERIAL_INPUT_COLOR}, + {RprUsdMaterialNodeInputTokens->color0, RPR_MATERIAL_INPUT_COLOR0}, + {RprUsdMaterialNodeInputTokens->color1, RPR_MATERIAL_INPUT_COLOR1}, + {RprUsdMaterialNodeInputTokens->normal, RPR_MATERIAL_INPUT_NORMAL}, + {RprUsdMaterialNodeInputTokens->uv, RPR_MATERIAL_INPUT_UV}, + {RprUsdMaterialNodeInputTokens->data, RPR_MATERIAL_INPUT_DATA}, + {RprUsdMaterialNodeInputTokens->roughness, RPR_MATERIAL_INPUT_ROUGHNESS}, + {RprUsdMaterialNodeInputTokens->ior, RPR_MATERIAL_INPUT_IOR}, + {RprUsdMaterialNodeInputTokens->roughness_x, RPR_MATERIAL_INPUT_ROUGHNESS_X}, + {RprUsdMaterialNodeInputTokens->roughness_y, RPR_MATERIAL_INPUT_ROUGHNESS_Y}, + {RprUsdMaterialNodeInputTokens->rotation, RPR_MATERIAL_INPUT_ROTATION}, + {RprUsdMaterialNodeInputTokens->weight, RPR_MATERIAL_INPUT_WEIGHT}, + {RprUsdMaterialNodeInputTokens->op, RPR_MATERIAL_INPUT_OP}, + {RprUsdMaterialNodeInputTokens->invec, RPR_MATERIAL_INPUT_INVEC}, + {RprUsdMaterialNodeInputTokens->uv_scale, RPR_MATERIAL_INPUT_UV_SCALE}, + {RprUsdMaterialNodeInputTokens->value, RPR_MATERIAL_INPUT_VALUE}, + {RprUsdMaterialNodeInputTokens->reflectance, RPR_MATERIAL_INPUT_REFLECTANCE}, + {RprUsdMaterialNodeInputTokens->scale, RPR_MATERIAL_INPUT_SCALE}, + {RprUsdMaterialNodeInputTokens->scattering, RPR_MATERIAL_INPUT_SCATTERING}, + {RprUsdMaterialNodeInputTokens->absorption, RPR_MATERIAL_INPUT_ABSORBTION}, + {RprUsdMaterialNodeInputTokens->emission, RPR_MATERIAL_INPUT_EMISSION}, + {RprUsdMaterialNodeInputTokens->g, RPR_MATERIAL_INPUT_G}, + {RprUsdMaterialNodeInputTokens->multiscatter, RPR_MATERIAL_INPUT_MULTISCATTER}, + {RprUsdMaterialNodeInputTokens->color2, RPR_MATERIAL_INPUT_COLOR2}, + {RprUsdMaterialNodeInputTokens->color3, RPR_MATERIAL_INPUT_COLOR3}, + {RprUsdMaterialNodeInputTokens->anisotropic, RPR_MATERIAL_INPUT_ANISOTROPIC}, + {RprUsdMaterialNodeInputTokens->frontface, RPR_MATERIAL_INPUT_FRONTFACE}, + {RprUsdMaterialNodeInputTokens->backface, RPR_MATERIAL_INPUT_BACKFACE}, + {RprUsdMaterialNodeInputTokens->origin, RPR_MATERIAL_INPUT_ORIGIN}, + {RprUsdMaterialNodeInputTokens->zaxis, RPR_MATERIAL_INPUT_ZAXIS}, + {RprUsdMaterialNodeInputTokens->xaxis, RPR_MATERIAL_INPUT_XAXIS}, + {RprUsdMaterialNodeInputTokens->threshold, RPR_MATERIAL_INPUT_THRESHOLD}, + {RprUsdMaterialNodeInputTokens->offset, RPR_MATERIAL_INPUT_OFFSET}, + {RprUsdMaterialNodeInputTokens->uv_type, RPR_MATERIAL_INPUT_UV_TYPE}, + {RprUsdMaterialNodeInputTokens->radius, RPR_MATERIAL_INPUT_RADIUS}, + {RprUsdMaterialNodeInputTokens->side, RPR_MATERIAL_INPUT_SIDE}, + {RprUsdMaterialNodeInputTokens->caustics, RPR_MATERIAL_INPUT_CAUSTICS}, + {RprUsdMaterialNodeInputTokens->transmission_color, RPR_MATERIAL_INPUT_TRANSMISSION_COLOR}, + {RprUsdMaterialNodeInputTokens->thickness, RPR_MATERIAL_INPUT_THICKNESS}, + {RprUsdMaterialNodeInputTokens->input0, RPR_MATERIAL_INPUT_0}, + {RprUsdMaterialNodeInputTokens->input1, RPR_MATERIAL_INPUT_1}, + {RprUsdMaterialNodeInputTokens->input2, RPR_MATERIAL_INPUT_2}, + {RprUsdMaterialNodeInputTokens->input3, RPR_MATERIAL_INPUT_3}, + {RprUsdMaterialNodeInputTokens->input4, RPR_MATERIAL_INPUT_4}, + {RprUsdMaterialNodeInputTokens->schlick_approximation, RPR_MATERIAL_INPUT_SCHLICK_APPROXIMATION}, + {RprUsdMaterialNodeInputTokens->applysurface, RPR_MATERIAL_INPUT_APPLYSURFACE}, + {RprUsdMaterialNodeInputTokens->uber_diffuse_color, RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_diffuse_weight, RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_diffuse_roughness, RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS}, + {RprUsdMaterialNodeInputTokens->uber_diffuse_normal, RPR_MATERIAL_INPUT_UBER_DIFFUSE_NORMAL}, + {RprUsdMaterialNodeInputTokens->uber_reflection_color, RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_reflection_weight, RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_reflection_roughness, RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS}, + {RprUsdMaterialNodeInputTokens->uber_reflection_anisotropy, RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY}, + {RprUsdMaterialNodeInputTokens->uber_reflection_anisotropy_rotation, RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY_ROTATION}, + {RprUsdMaterialNodeInputTokens->uber_reflection_mode, RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE}, + {RprUsdMaterialNodeInputTokens->uber_reflection_ior, RPR_MATERIAL_INPUT_UBER_REFLECTION_IOR}, + {RprUsdMaterialNodeInputTokens->uber_reflection_metalness, RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS}, + {RprUsdMaterialNodeInputTokens->uber_reflection_normal, RPR_MATERIAL_INPUT_UBER_REFLECTION_NORMAL}, + {RprUsdMaterialNodeInputTokens->uber_refraction_color, RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_refraction_weight, RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_refraction_roughness, RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS}, + {RprUsdMaterialNodeInputTokens->uber_refraction_ior, RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR}, + {RprUsdMaterialNodeInputTokens->uber_refraction_normal, RPR_MATERIAL_INPUT_UBER_REFRACTION_NORMAL}, + {RprUsdMaterialNodeInputTokens->uber_refraction_thin_surface, RPR_MATERIAL_INPUT_UBER_REFRACTION_THIN_SURFACE}, + {RprUsdMaterialNodeInputTokens->uber_refraction_absorption_color, RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_refraction_absorption_distance, RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_DISTANCE}, + {RprUsdMaterialNodeInputTokens->uber_refraction_caustics, RPR_MATERIAL_INPUT_UBER_REFRACTION_CAUSTICS}, + {RprUsdMaterialNodeInputTokens->uber_coating_color, RPR_MATERIAL_INPUT_UBER_COATING_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_coating_weight, RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_coating_roughness, RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS}, + {RprUsdMaterialNodeInputTokens->uber_coating_mode, RPR_MATERIAL_INPUT_UBER_COATING_MODE}, + {RprUsdMaterialNodeInputTokens->uber_coating_ior, RPR_MATERIAL_INPUT_UBER_COATING_IOR}, + {RprUsdMaterialNodeInputTokens->uber_coating_metalness, RPR_MATERIAL_INPUT_UBER_COATING_METALNESS}, + {RprUsdMaterialNodeInputTokens->uber_coating_normal, RPR_MATERIAL_INPUT_UBER_COATING_NORMAL}, + {RprUsdMaterialNodeInputTokens->uber_coating_transmission_color, RPR_MATERIAL_INPUT_UBER_COATING_TRANSMISSION_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_coating_thickness, RPR_MATERIAL_INPUT_UBER_COATING_THICKNESS}, + {RprUsdMaterialNodeInputTokens->uber_sheen, RPR_MATERIAL_INPUT_UBER_SHEEN}, + {RprUsdMaterialNodeInputTokens->uber_sheen_tint, RPR_MATERIAL_INPUT_UBER_SHEEN_TINT}, + {RprUsdMaterialNodeInputTokens->uber_sheen_weight, RPR_MATERIAL_INPUT_UBER_SHEEN_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_emission_color, RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_emission_weight, RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_emission_mode, RPR_MATERIAL_INPUT_UBER_EMISSION_MODE}, + {RprUsdMaterialNodeInputTokens->uber_transparency, RPR_MATERIAL_INPUT_UBER_TRANSPARENCY}, + {RprUsdMaterialNodeInputTokens->uber_sss_scatter_color, RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_sss_scatter_distance, RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DISTANCE}, + {RprUsdMaterialNodeInputTokens->uber_sss_scatter_direction, RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DIRECTION}, + {RprUsdMaterialNodeInputTokens->uber_sss_weight, RPR_MATERIAL_INPUT_UBER_SSS_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_sss_multiscatter, RPR_MATERIAL_INPUT_UBER_SSS_MULTISCATTER}, + {RprUsdMaterialNodeInputTokens->uber_backscatter_weight, RPR_MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT}, + {RprUsdMaterialNodeInputTokens->uber_backscatter_color, RPR_MATERIAL_INPUT_UBER_BACKSCATTER_COLOR}, + {RprUsdMaterialNodeInputTokens->uber_fresnel_schlick_approximation, RPR_MATERIAL_INPUT_UBER_FRESNEL_SCHLICK_APPROXIMATION}, + }; + + auto it = s_mapping.find(id); + if (it == s_mapping.end()) { + if (pedantic) { + TF_CODING_ERROR("Invalid rpr::MaterialNodeInput id: %s", id.GetText()); + } + return false; + } + + *out = it->second; + return true; +} + +bool ToRpr(TfToken const& id, uint32_t* out, bool pedantic) { + static const std::map s_mapping = { + {RprUsdMaterialInputModeTokens->pbr, RPR_UBER_MATERIAL_IOR_MODE_PBR}, + {RprUsdMaterialInputModeTokens->metalness, RPR_UBER_MATERIAL_IOR_MODE_METALNESS}, + {RprUsdMaterialInputModeTokens->singlesided, RPR_UBER_MATERIAL_EMISSION_MODE_SINGLESIDED}, + {RprUsdMaterialInputModeTokens->doublesided, RPR_UBER_MATERIAL_EMISSION_MODE_DOUBLESIDED}, + {RprUsdMaterialInputModeTokens->uv, RPR_MATERIAL_NODE_LOOKUP_UV}, + {RprUsdMaterialInputModeTokens->normal, RPR_MATERIAL_NODE_LOOKUP_N}, + {RprUsdMaterialInputModeTokens->position, RPR_MATERIAL_NODE_LOOKUP_P}, + {RprUsdMaterialInputModeTokens->invec, RPR_MATERIAL_NODE_LOOKUP_INVEC}, + {RprUsdMaterialInputModeTokens->outvec, RPR_MATERIAL_NODE_LOOKUP_OUTVEC}, + {RprUsdMaterialInputModeTokens->localPosition, RPR_MATERIAL_NODE_LOOKUP_P_LOCAL}, + {RprUsdMaterialInputModeTokens->shapeRandomColor, RPR_MATERIAL_NODE_LOOKUP_SHAPE_RANDOM_COLOR}, + {RprUsdMaterialInputModeTokens->objectId, RPR_MATERIAL_NODE_LOOKUP_OBJECT_ID}, + {RprUsdMaterialInputModeTokens->planar, RPR_MATERIAL_NODE_UVTYPE_PLANAR}, + {RprUsdMaterialInputModeTokens->cylindical, RPR_MATERIAL_NODE_UVTYPE_CYLINDICAL}, + {RprUsdMaterialInputModeTokens->spherical, RPR_MATERIAL_NODE_UVTYPE_SPHERICAL}, + {RprUsdMaterialInputModeTokens->project, RPR_MATERIAL_NODE_UVTYPE_PROJECT}, + }; + + auto it = s_mapping.find(id); + if (it == s_mapping.end()) { + if (pedantic) { + TF_CODING_ERROR("Invalid rpr mode id: %s", id.GetText()); + } + return false; + } + + *out = it->second; + return true; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialMappings.h b/pxr/imaging/rprUsd/materialMappings.h new file mode 100644 index 000000000..0bf03a1f8 --- /dev/null +++ b/pxr/imaging/rprUsd/materialMappings.h @@ -0,0 +1,196 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_MAPPINGS_H +#define RPRUSD_MATERIAL_MAPPINGS_H + +#include "pxr/base/tf/staticTokens.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// \p pedantic controls whether function should trigger TF errors +bool ToRpr(TfToken const& id, rpr::MaterialNodeType* out, bool pedantic = true); +bool ToRpr(TfToken const& id, rpr::MaterialNodeInput* out, bool pedantic = true); +bool ToRpr(TfToken const& id, uint32_t* out, bool pedantic = true); + +#define RPRUSD_MATERIAL_NODE_INPUT_TOKENS \ + (color) \ + (color0) \ + (color1) \ + (normal) \ + (uv) \ + (data) \ + (roughness) \ + (ior) \ + (roughness_x) \ + (roughness_y) \ + (rotation) \ + (weight) \ + (op) \ + (invec) \ + (uv_scale) \ + (value) \ + (reflectance) \ + (scale) \ + (scattering) \ + (absorption) \ + (emission) \ + (g) \ + (multiscatter) \ + (color2) \ + (color3) \ + (anisotropic) \ + (frontface) \ + (backface) \ + (origin) \ + (zaxis) \ + (xaxis) \ + (threshold) \ + (offset) \ + (uv_type) \ + (radius) \ + (side) \ + (caustics) \ + (transmission_color) \ + (thickness) \ + ((input0, "0")) \ + ((input1, "1")) \ + ((input2, "2")) \ + ((input3, "3")) \ + ((input4, "4")) \ + (schlick_approximation) \ + (applysurface) \ + (uber_diffuse_color) \ + (uber_diffuse_weight) \ + (uber_diffuse_roughness) \ + (uber_diffuse_normal) \ + (uber_reflection_color) \ + (uber_reflection_weight) \ + (uber_reflection_roughness) \ + (uber_reflection_anisotropy) \ + (uber_reflection_anisotropy_rotation) \ + (uber_reflection_mode) \ + (uber_reflection_ior) \ + (uber_reflection_metalness) \ + (uber_reflection_normal) \ + (uber_refraction_color) \ + (uber_refraction_weight) \ + (uber_refraction_roughness) \ + (uber_refraction_ior) \ + (uber_refraction_normal) \ + (uber_refraction_thin_surface) \ + (uber_refraction_absorption_color) \ + (uber_refraction_absorption_distance) \ + (uber_refraction_caustics) \ + (uber_coating_color) \ + (uber_coating_weight) \ + (uber_coating_roughness) \ + (uber_coating_mode) \ + (uber_coating_ior) \ + (uber_coating_metalness) \ + (uber_coating_normal) \ + (uber_coating_transmission_color) \ + (uber_coating_thickness) \ + (uber_sheen) \ + (uber_sheen_tint) \ + (uber_sheen_weight) \ + (uber_emission_color) \ + (uber_emission_weight) \ + (uber_emission_mode) \ + (uber_transparency) \ + (uber_sss_scatter_color) \ + (uber_sss_scatter_distance) \ + (uber_sss_scatter_direction) \ + (uber_sss_weight) \ + (uber_sss_multiscatter) \ + (uber_backscatter_weight) \ + (uber_backscatter_color) \ + (uber_fresnel_schlick_approximation) + +#define RPRUSD_MATERIAL_NODE_TYPE_TOKENS \ + (diffuse) \ + (microfacet) \ + (reflection) \ + (refraction) \ + (microfacet_refraction) \ + (transparent) \ + (emissive) \ + (ward) \ + (add) \ + (blend) \ + (arithmetic) \ + (fresnel) \ + (normal_map) \ + (image_texture) \ + (noise2d_texture) \ + (dot_texture) \ + (gradient_texture) \ + (checker_texture) \ + (constant_texture) \ + (input_lookup) \ + (blend_value) \ + (passthrough) \ + (orennayar) \ + (fresnel_schlick) \ + (diffuse_refraction) \ + (bump_map) \ + (volume) \ + (microfacet_anisotropic_reflection) \ + (microfacet_anisotropic_refraction) \ + (twosided) \ + (uv_procedural) \ + (microfacet_beckmann) \ + (phong) \ + (buffer_sampler) \ + (uv_triplanar) \ + (ao_map) \ + (user_texture_0) \ + (user_texture_1) \ + (user_texture_2) \ + (user_texture_3) \ + (uberv2) \ + (transform) \ + (rgb_to_hsv) \ + (hsv_to_rgb) + +#define RPRUSD_MATERIAL_INPUT_MODE_TOKENS \ + /* IOR mode */ \ + ((pbr, "PBR")) \ + ((metalness, "Metalness")) \ + /* Emission mode */ \ + ((singlesided, "Singlesided")) \ + ((doublesided, "Doublesided")) \ + /* Lookup value */ \ + ((uv, "UV")) \ + ((normal, "Normal")) \ + ((position, "Position")) \ + ((invec, "Incoming ray direction")) \ + ((outvec, "Outgoing ray direction")) \ + ((localPosition, "Local Position")) \ + ((shapeRandomColor, "Shape Random Color")) \ + ((objectId, "Object Id")) \ + /* UV Type */ \ + ((planar, "Flat Plane")) \ + ((cylindical, "Cylinder (in xy direction)")) \ + ((spherical, "Spherical")) \ + ((project, "Projected from a camera position")) \ + +TF_DECLARE_PUBLIC_TOKENS(RprUsdMaterialNodeInputTokens, RPRUSD_MATERIAL_NODE_INPUT_TOKENS); +TF_DECLARE_PUBLIC_TOKENS(RprUsdMaterialNodeTypeTokens, RPRUSD_MATERIAL_NODE_TYPE_TOKENS); +TF_DECLARE_PUBLIC_TOKENS(RprUsdMaterialInputModeTokens, RPRUSD_MATERIAL_INPUT_MODE_TOKENS); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_MAPPINGS_H diff --git a/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.cpp b/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.cpp new file mode 100644 index 000000000..c366f1ad5 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.cpp @@ -0,0 +1,561 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "houdiniPrincipledShaderNode.h" +#include "rpr/arithmeticNode.h" +#include "usdNode.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/imaging/rprUsd/materialMappings.h" +#include "pxr/imaging/rprUsd/materialHelpers.h" +#include "pxr/base/tf/staticTokens.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS(HoudiniPrincipledShaderTokens, + (basecolor) + (albedomult) + (ior) + ((roughness, "rough")) + ((anisotropy, "aniso")) + ((anisotropyDirection, "anisodir")) + (metallic) + ((reflectivity, "reflect")) + ((reflectTint, "reflecttint")) + (coat) + ((coatRoughness, "coatrough")) + (transparency) + ((transmissionColor, "transcolor")) + ((transmissionDistance, "transdist")) + ((subsurface, "sss")) + ((subsurfaceDistance, "sssdist")) + ((subsurfaceModel, "sssmodel")) + ((subsurfaceColor, "ssscolor")) + ((subsurfacePhase, "sssphase")) + (sheen) + ((sheenTint, "sheentint")) + ((emissionColor, "emitcolor")) + ((emissionIntensity, "emitint")) + ((opacity, "opac")) + ((opacityColor, "opaccolor")) + (baseNormal) + ((baseNormalScale, "baseNormal_scale")) + (coatNormal) + ((coatNormalScale, "coatNormal_scale")) + ((baseNormalEnable, "baseBumpAndNormal_enable")) + ((baseNormalType, "baseBumpAndNormal_type")) + (separateCoatNormals) + ((doubleSided, "frontface")) + ((displacementEnable, "dispTex_enable")) + ((displacementTexture, "dispTex_texture")) + ((displacementOffset, "dispTex_offset")) + ((displacementScale, "dispTex_scale")) + ((displacementColorSpace, "dispTex_colorSpace")) + ((displacementChannel, "dispTex_channel")) + ((displacementWrap, "dispTex_wrap")) + ((displacementType, "dispTex_type")) + ((infoSourceAsset, "info:sourceAsset")) + ((infoImplementationSource, "info:implementationSource")) + (sourceAsset) + (karma) +); + +namespace { + +std::map g_houdiniPrincipledShaderParameterDefaultValues = { + {HoudiniPrincipledShaderTokens->basecolor, VtValue(0.2f)}, + {HoudiniPrincipledShaderTokens->ior, VtValue(1.5f)}, + {HoudiniPrincipledShaderTokens->roughness, VtValue(0.3f)}, + {HoudiniPrincipledShaderTokens->anisotropy, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->anisotropyDirection, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->metallic, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->reflectivity, VtValue(1.0f)}, + {HoudiniPrincipledShaderTokens->reflectTint, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->coat, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->coatRoughness, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->transparency, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->transmissionColor, VtValue(1.0f)}, + {HoudiniPrincipledShaderTokens->transmissionDistance, VtValue(0.1f)}, + {HoudiniPrincipledShaderTokens->subsurface, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->subsurfaceDistance, VtValue(0.1f)}, + {HoudiniPrincipledShaderTokens->subsurfaceColor, VtValue(1.0f)}, + {HoudiniPrincipledShaderTokens->sheen, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->sheenTint, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->emissionColor, VtValue(0.0f)}, + {HoudiniPrincipledShaderTokens->opacityColor, VtValue(1.0f)}, +}; + +template +T GetParameter(TfToken const& name, std::map const& parameters, T defaultValue = T()) { + auto parameterIt = parameters.find(name); + if (parameterIt != parameters.end() && + parameterIt->second.IsHolding()) { + return parameterIt->second.UncheckedGet(); + } + + return defaultValue; +} + +TfToken ToUsdUVTextureWrapMode(std::string const& mode) { + if (mode == "streak") { + return RprUsd_UsdUVTextureTokens->clamp; + } else if (mode == "decal") { + return RprUsd_UsdUVTextureTokens->black; + } else { + return RprUsd_UsdUVTextureTokens->repeat; + } +} + +TfToken ToUsdUVTextureOutputId(int channel) { + if (channel == 1) { + return RprUsd_UsdUVTextureTokens->r; + } else if (channel == 2) { + return RprUsd_UsdUVTextureTokens->g; + } else if (channel == 3) { + return RprUsd_UsdUVTextureTokens->b; + } else { + return TfToken(); + } +} + +} // namespace anonymous + +RprUsd_HoudiniPrincipledNode::RprUsd_HoudiniPrincipledNode( + RprUsd_MaterialBuilderContext* ctx, + std::map const& params, + std::map const* dispParamsPtr) + : RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_UBERV2, ctx) { + + // XXX: unused parameters: + // reflectTint + // reflectivity + + bool useBaseColorTextureAlpha = false; + + auto getTextureValue = [&](TfToken const& baseParameter, bool forceLinearSpace = false) -> VtValue { + // Each parameter (e.g. basecolor) may have set of properties in the form: + // paramName_propertyName (e.g. basecolor_texture) + // but parameter itself may be missing in input params + + SdfAssetPath fileAsset; + std::string wrapMode; + float scale = 1.0f; + TfToken textureOutputId; + + bool useTexture = false; + for (auto it = params.lower_bound(baseParameter); it != params.end(); ++it) { + // check that this property corresponds to our base parameter + if (it->first.GetString().compare(0, baseParameter.size(), baseParameter.GetText())) { + break; + } + + // skip paramName + auto propertyName = it->first.GetText() + baseParameter.size(); + + if (*propertyName != '_') { + continue; + } + ++propertyName; + + if (std::strncmp(propertyName, "texture", sizeof("texture") - 1) == 0) { + auto texturePropertyName = propertyName + (sizeof("texture") - 1); + if (*texturePropertyName == '\0') { + if (it->second.IsHolding()) { + auto& assetPath = it->second.UncheckedGet(); + + std::string const* filepath; + if (assetPath.GetResolvedPath().empty()) { + filepath = &assetPath.GetAssetPath(); + } else { + filepath = &assetPath.GetResolvedPath(); + } + + if (filepath->empty()) { + return VtValue(); + } + + fileAsset = assetPath; + } + } else if (std::strcmp(texturePropertyName, "Intensity") == 0) { + if (it->second.IsHolding()) { + scale = it->second.UncheckedGet(); + } + } else if (std::strcmp(texturePropertyName, "ColorSpace") == 0) { + if (it->second.IsHolding()) { + forceLinearSpace = it->second.UncheckedGet() == "linear"; + } + } else if (std::strcmp(texturePropertyName, "Wrap") == 0) { + if (it->second.IsHolding()) { + wrapMode = it->second.UncheckedGet(); + } + } + } else if (std::strncmp(propertyName, "useTexture", sizeof("useTexture") - 1) == 0) { + auto useTexturePropertyName = propertyName + sizeof("useTexture") - 1; + if (*useTexturePropertyName == '\0') { + if (it->second.IsHolding()) { + useTexture = static_cast(it->second.UncheckedGet()); + if (!useTexture) { + return VtValue(); + } + } + } else if (std::strcmp(useTexturePropertyName, "Alpha") == 0) { + if (it->second.IsHolding() && + it->second.UncheckedGet() == 1) { + useBaseColorTextureAlpha = true; + } + } + } else if (std::strcmp(propertyName, "monoChannel") == 0) { + if (it->second.IsHolding()) { + textureOutputId = ToUsdUVTextureOutputId(it->second.UncheckedGet()); + } + } + } + + if (baseParameter == HoudiniPrincipledShaderTokens->baseNormal) { + // baseNormal's texture enabled by baseBumpAndNormal_enable parameter unlike all other textures by *_useTexture + useTexture = true; + } + + if (!useTexture) { + return VtValue(); + } + + RprUsd_MaterialNode** uvTexture = nullptr; + + if (baseParameter == HoudiniPrincipledShaderTokens->basecolor || + baseParameter == HoudiniPrincipledShaderTokens->transmissionColor || + baseParameter == HoudiniPrincipledShaderTokens->subsurfaceColor || + baseParameter == HoudiniPrincipledShaderTokens->baseNormal || + baseParameter == HoudiniPrincipledShaderTokens->coatNormal) { + if (textureOutputId.IsEmpty()) { + textureOutputId = RprUsd_UsdUVTextureTokens->rgba; + } + if (baseParameter == HoudiniPrincipledShaderTokens->basecolor) { + uvTexture = &m_baseColorNode; + } + } + + return GetTextureOutput(fileAsset, wrapMode, scale, 0.0f, forceLinearSpace, textureOutputId, uvTexture); + }; + + struct ParameterValue { + VtValue value; + bool isDefault; + + bool IsAuthored() { + return !isDefault && !value.IsEmpty(); + } + }; + auto getParameterValue = [&](TfToken const& paramName) -> ParameterValue { + ParameterValue param; + param.isDefault = false; + + param.value = getTextureValue(paramName); + + // Check for plain parameter + if (param.value.IsEmpty()) { + auto parameterIt = params.find(paramName); + if (parameterIt != params.end()) { + param.value = parameterIt->second; + } + } + + // Check for default parameter + if (param.value.IsEmpty()) { + auto parameterIt = g_houdiniPrincipledShaderParameterDefaultValues.find(paramName); + if (parameterIt != g_houdiniPrincipledShaderParameterDefaultValues.end()) { + param.value = parameterIt->second; + param.isDefault = true; + } + } + + return param; + }; + + auto setInputs = [this](VtValue const& value, std::vector const& rprInputs) { + for (auto rprInput : rprInputs) { + SetRprInput(m_rprNode.get(), rprInput, value); + } + }; + + auto populateParameter = [&](TfToken const& paramName, std::vector const& rprInputs) { + auto param = getParameterValue(paramName); + if (!param.value.IsEmpty()) { + setInputs(param.value, rprInputs); + } + }; + + auto basecolorParam = getParameterValue(HoudiniPrincipledShaderTokens->basecolor); + if (!basecolorParam.value.IsEmpty()) { + auto albedoMultiplyNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_MUL, m_ctx)); + albedoMultiplyNode->SetInput(0, VtValue(GetParameter(HoudiniPrincipledShaderTokens->albedomult, params, 1.0f))); + albedoMultiplyNode->SetInput(1, basecolorParam.value); + setInputs(albedoMultiplyNode->GetOutput(), {RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR, RPR_MATERIAL_INPUT_UBER_COATING_COLOR, RPR_MATERIAL_INPUT_UBER_COATING_TRANSMISSION_COLOR, RPR_MATERIAL_INPUT_UBER_SHEEN}); + } + + populateParameter(HoudiniPrincipledShaderTokens->ior, {RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR, RPR_MATERIAL_INPUT_UBER_COATING_IOR}); + populateParameter(HoudiniPrincipledShaderTokens->roughness, {RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS, RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS, RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS}); + + populateParameter(HoudiniPrincipledShaderTokens->anisotropy, {RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY}); + populateParameter(HoudiniPrincipledShaderTokens->anisotropyDirection, {RPR_MATERIAL_INPUT_UBER_REFLECTION_ANISOTROPY_ROTATION}); + + populateParameter(HoudiniPrincipledShaderTokens->coatRoughness, {RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS}); + auto coatParam = getParameterValue(HoudiniPrincipledShaderTokens->coat); + if (!coatParam.value.IsEmpty()) { + auto coatingWeightNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_GREATER, m_ctx)); + coatingWeightNode->SetInput(0, coatParam.value); + coatingWeightNode->SetInput(1, VtValue(0.0f)); + + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT, coatingWeightNode->GetOutput()); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_COATING_THICKNESS, coatParam.value); + } + + auto subsurfaceParam = getParameterValue(HoudiniPrincipledShaderTokens->subsurface); + if (!subsurfaceParam.value.IsEmpty()) { + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_SSS_WEIGHT, subsurfaceParam.value); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_BACKSCATTER_WEIGHT, subsurfaceParam.value); + } + populateParameter(HoudiniPrincipledShaderTokens->subsurfaceDistance, {RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DISTANCE}); + populateParameter(HoudiniPrincipledShaderTokens->subsurfaceColor, {RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_COLOR, RPR_MATERIAL_INPUT_UBER_BACKSCATTER_COLOR}); + + auto subsurfaceModel = GetParameter(HoudiniPrincipledShaderTokens->subsurfaceModel, params, std::string("full")); + if (subsurfaceModel == "full") { + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_SSS_MULTISCATTER, 1u), "Failed to set sss multiscatter input"); + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DIRECTION, 0, 0, 0, 0), "Failed to set sss multiscatter input"); + } else { + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_SSS_MULTISCATTER, 0u), "Failed to set sss multiscatter input"); + populateParameter(HoudiniPrincipledShaderTokens->subsurfacePhase, {RPR_MATERIAL_INPUT_UBER_SSS_SCATTER_DIRECTION}); + } + + populateParameter(HoudiniPrincipledShaderTokens->sheen, {RPR_MATERIAL_INPUT_UBER_SHEEN_WEIGHT}); + populateParameter(HoudiniPrincipledShaderTokens->sheenTint, {RPR_MATERIAL_INPUT_UBER_SHEEN_TINT}); + + auto emissionColorParam = getParameterValue(HoudiniPrincipledShaderTokens->emissionColor); + if (!emissionColorParam.value.IsEmpty()) { + auto emissiveWeightNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_GREATER, m_ctx)); + emissiveWeightNode->SetInput(0, emissionColorParam.value); + emissiveWeightNode->SetInput(1, VtValue(0.0f)); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT, emissiveWeightNode->GetOutput()); + + auto emissiveIntensityNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_MUL, m_ctx)); + emissiveIntensityNode->SetInput(0, emissionColorParam.value); + emissiveIntensityNode->SetInput(1, VtValue(GetParameter(HoudiniPrincipledShaderTokens->emissionIntensity, params, 1.0f))); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR, emissiveIntensityNode->GetOutput()); + } + + m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT, 1, 1, 1, 1); + + if (GetParameter(HoudiniPrincipledShaderTokens->baseNormalEnable, params, 0)) { + std::vector rprInputs = {RPR_MATERIAL_INPUT_UBER_DIFFUSE_NORMAL, RPR_MATERIAL_INPUT_UBER_REFLECTION_NORMAL, RPR_MATERIAL_INPUT_UBER_REFRACTION_NORMAL}; + + if (GetParameter(HoudiniPrincipledShaderTokens->separateCoatNormals, params, 0)) { + auto coatNormal = getTextureValue(HoudiniPrincipledShaderTokens->coatNormal, true); + if (!coatNormal.IsEmpty()) { + auto normalMapNode = AddAuxiliaryNode(std::make_unique(RPR_MATERIAL_NODE_NORMAL_MAP, m_ctx)); + normalMapNode->SetInput(RprUsdMaterialNodeInputTokens->color, coatNormal); + normalMapNode->SetInput(RprUsdMaterialNodeInputTokens->scale, VtValue(GetParameter(HoudiniPrincipledShaderTokens->coatNormalScale, params, 1.0f))); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_COATING_NORMAL, normalMapNode->GetOutput(TfToken())); + } + } else { + rprInputs.push_back(RPR_MATERIAL_INPUT_UBER_COATING_NORMAL); + } + + auto baseNormal = getTextureValue(HoudiniPrincipledShaderTokens->baseNormal, true); + if (!baseNormal.IsEmpty()) { + auto normalMapNode = AddAuxiliaryNode(std::make_unique(RPR_MATERIAL_NODE_NORMAL_MAP, m_ctx)); + normalMapNode->SetInput(RprUsdMaterialNodeInputTokens->color, baseNormal); + normalMapNode->SetInput(RprUsdMaterialNodeInputTokens->scale, VtValue(GetParameter(HoudiniPrincipledShaderTokens->baseNormalScale, params, 1.0f))); + auto normalMap = normalMapNode->GetOutput(TfToken()); + for (auto rprInput : rprInputs) { + SetRprInput(m_rprNode.get(), rprInput, normalMap); + } + } + } + + bool hasTransparency = false; + + auto transparencyParam = getParameterValue(HoudiniPrincipledShaderTokens->transparency); + if (!transparencyParam.value.IsEmpty()) { + if (transparencyParam.IsAuthored()) { + hasTransparency = true; + } + + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFRACTION_CAUSTICS, 1), "Failed to set caustics input"); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT, transparencyParam.value); + + auto diffuseWeightNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_SUB, m_ctx)); + diffuseWeightNode->SetInput(0, VtValue(1.0f)); + diffuseWeightNode->SetInput(1, transparencyParam.value); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT, diffuseWeightNode->GetOutput()); + } + populateParameter(HoudiniPrincipledShaderTokens->transmissionColor, {RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR, RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_COLOR}); + populateParameter(HoudiniPrincipledShaderTokens->transmissionDistance, {RPR_MATERIAL_INPUT_UBER_REFRACTION_ABSORPTION_DISTANCE}); + + if (useBaseColorTextureAlpha) { + VtValue opacity; + if (m_baseColorNode) { + opacity = m_baseColorNode->GetOutput(RprUsd_UsdUVTextureTokens->a); + hasTransparency = true; + } else { + auto opacityParam = getParameterValue(HoudiniPrincipledShaderTokens->opacityColor); + if (opacityParam.IsAuthored()) { + hasTransparency = true; + } + opacity = opacityParam.value; + } + + if (!opacity.IsEmpty()) { + auto transparencyNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_MUL, m_ctx)); + transparencyNode->SetInput(0, opacity); + transparencyNode->SetInput(1, VtValue(GetParameter(HoudiniPrincipledShaderTokens->opacity, params, 1.0f))); + auto transparency = transparencyNode->GetOutput(); + + transparencyNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_SUB, m_ctx)); + transparencyNode->SetInput(0, VtValue(1.0f)); + transparencyNode->SetInput(1, transparency); + transparency = transparencyNode->GetOutput(); + + if (SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_TRANSPARENCY, transparency)) { + hasTransparency = true; + } + } + } + + auto iorMode = RPR_UBER_MATERIAL_IOR_MODE_PBR; + if (!hasTransparency) { + iorMode = RPR_UBER_MATERIAL_IOR_MODE_METALNESS; + populateParameter(HoudiniPrincipledShaderTokens->metallic, {RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS, RPR_MATERIAL_INPUT_UBER_COATING_METALNESS}); + } + + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE, iorMode), "Failed to set ior mode input"); + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_COATING_MODE, iorMode), "Failed to set ior mode input"); + + if (dispParamsPtr) { + auto& dispParams = *dispParamsPtr; + if (GetParameter(HoudiniPrincipledShaderTokens->displacementEnable, dispParams, 0)) { + auto dispType = GetParameter(HoudiniPrincipledShaderTokens->displacementType, dispParams); + if (dispType == "vectordisp") { + TF_RUNTIME_ERROR("Vector displacement unsupported"); + } else { + auto dispTexturePath = GetParameter(HoudiniPrincipledShaderTokens->displacementTexture, dispParams); + if (!dispTexturePath.GetResolvedPath().empty()) { + m_displacementOutput = GetTextureOutput( + dispTexturePath, + GetParameter(HoudiniPrincipledShaderTokens->displacementWrap, dispParams), + GetParameter(HoudiniPrincipledShaderTokens->displacementScale, dispParams, 0.05f), + GetParameter(HoudiniPrincipledShaderTokens->displacementOffset, dispParams, -0.5f), + GetParameter(HoudiniPrincipledShaderTokens->displacementColorSpace, dispParams, std::string("linear")) == "linear", + ToUsdUVTextureOutputId(GetParameter(HoudiniPrincipledShaderTokens->displacementChannel, dispParams, 0))); + } + } + } + } +} + +VtValue RprUsd_HoudiniPrincipledNode::GetOutput(TfToken const& outputId) { + if (outputId == HdMaterialTerminalTokens->displacement) { + return m_displacementOutput; + } else { + return RprUsd_BaseRuntimeNode::GetOutput(outputId); + } +} + +VtValue RprUsd_HoudiniPrincipledNode::GetTextureOutput( + SdfAssetPath const& path, + std::string const& wrapMode, + float scale, float bias, + bool forceLinearSpace, + TfToken const& outputId, + RprUsd_MaterialNode** out_uvTextureNode) { + if (path.GetResolvedPath().empty() && + path.GetAssetPath().empty()) { + return VtValue(); + } + + std::map uvTextureParams = { + {RprUsd_UsdUVTextureTokens->file, VtValue(path)}, + {RprUsd_UsdUVTextureTokens->wrapS, VtValue(ToUsdUVTextureWrapMode(wrapMode))}, + }; + + if (forceLinearSpace) { + uvTextureParams.emplace(RprUsd_UsdUVTextureTokens->colorSpace, RprUsd_UsdUVTextureTokens->linear); + } + + if (scale != 1.0f) { + uvTextureParams.emplace(RprUsd_UsdUVTextureTokens->scale, VtValue(GfVec4f(scale))); + } + + if (bias != 0.0f) { + uvTextureParams.emplace(RprUsd_UsdUVTextureTokens->bias, VtValue(GfVec4f(bias))); + } + + RprUsd_MaterialNode* uvTexture; + try { + uvTexture = AddAuxiliaryNode(std::make_unique(m_ctx, uvTextureParams)); + } catch (RprUsd_NodeError& e) { + TF_RUNTIME_ERROR("Failed to create texture node: %s", e.what()); + return VtValue(); + } + + if (out_uvTextureNode) { + *out_uvTextureNode = uvTexture; + } + + if (outputId.IsEmpty()) { + // Output luminance + auto output = uvTexture->GetOutput(RprUsd_UsdUVTextureTokens->rgba); + + auto luminanceNode = AddAuxiliaryNode(RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_DOT3, m_ctx)); + luminanceNode->SetInput(0, output); + luminanceNode->SetInput(1, VtValue(GfVec4f(0.2126, 0.7152, 0.0722, 0.0))); + return luminanceNode->GetOutput(); + } else { + return uvTexture->GetOutput(outputId); + } +} + +bool IsHoudiniPrincipledShaderHydraNode(HdSceneDelegate* delegate, SdfPath const& nodePath, bool* isSurface) { + // Houdini's principled shader is hidden under `karma` namespace. + // If HdRprRenderDelegate uses some other network selector that is not + // a `karma` one then Hydra will never feed us a definition of the principled shader. + if (RprUsdMaterialRegistry::GetInstance().GetMaterialNetworkSelector() != HoudiniPrincipledShaderTokens->karma) { + return false; + } + + auto implementationSource = delegate->Get(nodePath, HoudiniPrincipledShaderTokens->infoImplementationSource); + if (implementationSource.IsHolding() && + implementationSource.UncheckedGet() == HoudiniPrincipledShaderTokens->sourceAsset) { + auto nodeAsset = delegate->Get(nodePath, HoudiniPrincipledShaderTokens->infoSourceAsset); + if (nodeAsset.IsHolding()) { + auto& asset = nodeAsset.UncheckedGet(); + if (!asset.GetAssetPath().empty()) { + std::string principledShaderDef = "opdef:/Vop/principledshader::2.0?"; + if (asset.GetAssetPath().compare(0, principledShaderDef.size(), principledShaderDef.c_str()) == 0) { + auto vexCodeType = asset.GetAssetPath().substr(principledShaderDef.size()); + if (vexCodeType == "SurfaceVexCode") { + *isSurface = true; + } else if (vexCodeType == "DisplacementVexCode") { + *isSurface = false; + } else { + return false; + } + return true; + } + } + } + } + + return false; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.h b/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.h new file mode 100644 index 000000000..6542dd0ff --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/houdiniPrincipledShaderNode.h @@ -0,0 +1,81 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_HOUDINI_PRINCIPLED_SHADER_NODE_H +#define RPRUSD_MATERIAL_NODES_HOUDINI_PRINCIPLED_SHADER_NODE_H + +#include "rpr/baseNode.h" + +#include "pxr/usd/sdf/assetPath.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class RprUsd_HoudiniPrincipledNode +/// +/// The node that implements Houdini's principled node +/// (https://www.sidefx.com/docs/houdini/nodes/vop/principledshader.html) +/// +/// Before expecting this node to work you need to make sure that +/// `RPRUSD_MATERIAL_NETWORK_SELECTOR` environment variable is set to `karma`. +/// If it's not set to `karma`, Hydra will ignore houdini's principled node and +/// its data will not be present in `HdMaterialNetwork` passed to hdRpr. +/// +/// Support of the principled shader is limited to the node without any connected nodes. +/// This is due to the fact that the principled shader node input parameters listed as +/// HdMaterialNode::parameters only if there are no connected nodes. If principled shader +/// node has any node connected to it, Houdini will automatically convert its +/// implementation to VEX code that is not supported. +/// +class RprUsd_HoudiniPrincipledNode : public RprUsd_BaseRuntimeNode { +public: + RprUsd_HoudiniPrincipledNode( + RprUsd_MaterialBuilderContext* ctx, + std::map const& surfaceParameters, + std::map const* displacementParameters); + ~RprUsd_HoudiniPrincipledNode() override = default; + + VtValue GetOutput(TfToken const& outputId) override; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override { + return false; + } + +private: + template + T* AddAuxiliaryNode(std::unique_ptr node) { + T* ret = node.get(); + m_auxiliaryNodes.push_back(std::move(node)); + return ret; + } + + VtValue GetTextureOutput( + SdfAssetPath const& path, + std::string const& wrapMode, + float scale, float bias, + bool forceLinearSpace, + TfToken const& outputId, + RprUsd_MaterialNode** uvTextureNode = nullptr); + +private: + std::vector> m_auxiliaryNodes; + RprUsd_MaterialNode* m_baseColorNode = nullptr; + VtValue m_displacementOutput; +}; + +bool IsHoudiniPrincipledShaderHydraNode(HdSceneDelegate* delegate, SdfPath const& nodePath, bool* isSurface); + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_HOUDINI_PRINCIPLED_SHADER_NODE_H diff --git a/pxr/imaging/rprUsd/materialNodes/materialNode.h b/pxr/imaging/rprUsd/materialNodes/materialNode.h new file mode 100644 index 000000000..00ea0b7b6 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/materialNode.h @@ -0,0 +1,66 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_MATERIAL_NODE_H +#define RPRUSD_MATERIAL_NODES_MATERIAL_NODE_H + +#include "pxr/imaging/hd/material.h" + +namespace rpr { class Context; } + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdImageCache; + +struct RprUsd_MaterialBuilderContext { + rpr::Context* rprContext; + RprUsdImageCache* imageCache; + + TfToken uvPrimvarName; + bool isShadowCatcher; + bool isReflectionCatcher; + + VtValue displacementScale; +}; + +class RprUsd_MaterialNode { +public: + virtual ~RprUsd_MaterialNode() = default; + + virtual VtValue GetOutput( + TfToken const& outputId) = 0; + + virtual bool SetInput( + TfToken const& inputId, + VtValue const& value) = 0; +}; + +class RprUsd_NodeError : public std::exception { +public: + RprUsd_NodeError(std::string errorMessage) : m_msg(std::move(errorMessage)) {} + ~RprUsd_NodeError() override = default; + + const char* what() const noexcept override { return m_msg.c_str(); } + +private: + std::string m_msg; +}; + +/// Thrown when node is empty. +/// There is no point to keep a node in memory when all it does is propagates inputs to outputs. +class RprUsd_NodeEmpty : public std::exception { +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_MATERIAL_NODE_H diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/CMakeLists.txt b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/CMakeLists.txt new file mode 100644 index 000000000..6b4a5c418 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/CMakeLists.txt @@ -0,0 +1,51 @@ +set(MTLX_FILES + Patterns/rpr_noise2d_texture.mtlx + Patterns/rpr_checker_texture.mtlx + Patterns/rpr_gradient_texture.mtlx + Patterns/rpr_dot_texture.mtlx + + Utilities/rpr_bump_map.mtlx + Utilities/rpr_normal_map.mtlx + Utilities/rpr_twosided.mtlx + Utilities/rpr_blend_value.mtlx + Utilities/rpr_constant_texture.mtlx + + Utilities/rpr_rgb_to_hsv.mtlx + Utilities/rpr_hsv_to_rgb.mtlx + + Utilities/rpr_input_lookup.mtlx + + Utilities/rpr_uv_triplanar.mtlx + Utilities/rpr_uv_procedural.mtlx + + Utilities/rpr_fresnel.mtlx + Utilities/rpr_fresnel_schlick.mtlx + + Shaders/rpr_add.mtlx + Shaders/rpr_blend.mtlx + + Shaders/rpr_uber.mtlx + Shaders/rpr_diffuse.mtlx + Shaders/rpr_diffuse_refraction.mtlx + Shaders/rpr_emissive.mtlx + Shaders/rpr_microfacet.mtlx + Shaders/rpr_microfacet_anisotropic_reflection.mtlx + Shaders/rpr_microfacet_anisotropic_refraction.mtlx + Shaders/rpr_microfacet_beckmann.mtlx + Shaders/rpr_microfacet_refraction.mtlx + Shaders/rpr_orennayar.mtlx + Shaders/rpr_passthrough.mtlx + Shaders/rpr_phong.mtlx + Shaders/rpr_reflection.mtlx + Shaders/rpr_refraction.mtlx + Shaders/rpr_transparent.mtlx + Shaders/rpr_volume.mtlx + Shaders/rpr_ward.mtlx +) + +foreach(mtlx ${MTLX_FILES}) + get_filename_component(dir ${mtlx} DIRECTORY) + install( + FILES ${mtlx} + DESTINATION materials/${dir}) +endforeach() diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_checker_texture.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_checker_texture.mtlx new file mode 100644 index 000000000..7efffddb9 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_checker_texture.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_dot_texture.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_dot_texture.mtlx new file mode 100644 index 000000000..71236ca6e --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_dot_texture.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_gradient_texture.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_gradient_texture.mtlx new file mode 100644 index 000000000..849aa56bb --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_gradient_texture.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_noise2d_texture.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_noise2d_texture.mtlx new file mode 100644 index 000000000..f697c892a --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Patterns/rpr_noise2d_texture.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_add.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_add.mtlx new file mode 100644 index 000000000..f490c483c --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_add.mtlx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_blend.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_blend.mtlx new file mode 100644 index 000000000..ea9bf069b --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_blend.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse.mtlx new file mode 100644 index 000000000..ba47887eb --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse_refraction.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse_refraction.mtlx new file mode 100644 index 000000000..bed07f6c2 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_diffuse_refraction.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_emissive.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_emissive.mtlx new file mode 100644 index 000000000..37c0ebb57 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_emissive.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet.mtlx new file mode 100644 index 000000000..ebd1a78e9 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_reflection.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_reflection.mtlx new file mode 100644 index 000000000..fff2dd503 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_reflection.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_refraction.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_refraction.mtlx new file mode 100644 index 000000000..48da8544e --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_anisotropic_refraction.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_beckmann.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_beckmann.mtlx new file mode 100644 index 000000000..bc97daa07 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_beckmann.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_refraction.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_refraction.mtlx new file mode 100644 index 000000000..4bdd0c31d --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_microfacet_refraction.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_orennayar.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_orennayar.mtlx new file mode 100644 index 000000000..3d5e46c12 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_orennayar.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_passthrough.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_passthrough.mtlx new file mode 100644 index 000000000..2c9c65fa4 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_passthrough.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_phong.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_phong.mtlx new file mode 100644 index 000000000..0b8632e43 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_phong.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_reflection.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_reflection.mtlx new file mode 100644 index 000000000..15beb2c76 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_reflection.mtlx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_refraction.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_refraction.mtlx new file mode 100644 index 000000000..dee6efb86 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_refraction.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_transparent.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_transparent.mtlx new file mode 100644 index 000000000..cb857f505 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_transparent.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_uber.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_uber.mtlx new file mode 100644 index 000000000..166f3ffba --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_uber.mtlx @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_volume.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_volume.mtlx new file mode 100644 index 000000000..9e9788121 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_volume.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_ward.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_ward.mtlx new file mode 100644 index 000000000..7e41d6b5f --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Shaders/rpr_ward.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_blend_value.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_blend_value.mtlx new file mode 100644 index 000000000..915d31b7d --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_blend_value.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_bump_map.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_bump_map.mtlx new file mode 100644 index 000000000..604321e6a --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_bump_map.mtlx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_constant_texture.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_constant_texture.mtlx new file mode 100644 index 000000000..7c9881179 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_constant_texture.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel.mtlx new file mode 100644 index 000000000..3d137e361 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel.mtlx @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel_schlick.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel_schlick.mtlx new file mode 100644 index 000000000..21ef03dff --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_fresnel_schlick.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_hsv_to_rgb.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_hsv_to_rgb.mtlx new file mode 100644 index 000000000..9b4b5b8f2 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_hsv_to_rgb.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_input_lookup.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_input_lookup.mtlx new file mode 100644 index 000000000..9f5a635df --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_input_lookup.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_normal_map.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_normal_map.mtlx new file mode 100644 index 000000000..ab067b61e --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_normal_map.mtlx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_rgb_to_hsv.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_rgb_to_hsv.mtlx new file mode 100644 index 000000000..e180575f0 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_rgb_to_hsv.mtlx @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_twosided.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_twosided.mtlx new file mode 100644 index 000000000..5f24ad7d8 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_twosided.mtlx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_procedural.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_procedural.mtlx new file mode 100644 index 000000000..82ec86a94 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_procedural.mtlx @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_triplanar.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_triplanar.mtlx new file mode 100644 index 000000000..f7de5fb41 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/Utilities/rpr_uv_triplanar.mtlx @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxFiles/rpr_defs.mtlx b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/rpr_defs.mtlx new file mode 100644 index 000000000..d75b48686 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxFiles/rpr_defs.mtlx @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxNode.cpp b/pxr/imaging/rprUsd/materialNodes/mtlxNode.cpp new file mode 100644 index 000000000..4a9275d1b --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxNode.cpp @@ -0,0 +1,336 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "mtlxNode.h" +#include "rpr/baseNode.h" + +#include "pxr/imaging/rprUsd/material.h" +#include "pxr/imaging/rprUsd/materialMappings.h" +#include "pxr/base/gf/vec2f.h" + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + +void ParseMtlxBoolValue(std::string const& valueString, VtValue* value) { + if (valueString == "true") { + *value = true; + } else if (valueString == "false") { + *value = false; + } else { + TF_RUNTIME_ERROR("Invalid Mtlx boolean value: %s", valueString.c_str()); + } +} + +void ParseMtlxFloatValue(std::string const& valueString, VtValue* value) { + try { + *value = std::stof(valueString); + } catch (std::logic_error& e) { + TF_RUNTIME_ERROR("Invalid Mtlx float value: %s - %s", valueString.c_str(), e.what()); + } +} + +void ParseMtlxIntValue(std::string const& valueString, VtValue* value) { + try { + *value = std::stoi(valueString); + } catch (std::logic_error& e) { + TF_RUNTIME_ERROR("Invalid Mtlx int value: %s - %s", valueString.c_str(), e.what()); + } +} + +template +void ParseMtlxVecValue(std::string const& valueString, VtValue* value) { + auto tokens = TfStringTokenize(valueString, ", \t"); + if (tokens.size() != VecType::dimension) { + TF_RUNTIME_ERROR("Invalid Mtlx value: %s - expected %zu components, got %zu", + valueString.c_str(), VecType::dimension, tokens.size()); + return; + } + + try { + VecType vec; + for (size_t i = 0; i < tokens.size(); ++i) { + vec.data()[i] = std::stof(tokens[i]); + } + *value = vec; + } catch (std::logic_error& e) { + TF_RUNTIME_ERROR("Invalid Mtlx value: %s - %s", valueString.c_str(), e.what()); + } +} + +VtValue ParseMtlxValue(RprUsd_MtlxNodeElement const& input) { + VtValue ret; + if (auto valueString = input.GetValueString()) { + if (input.GetType() == RprUsdMaterialNodeElement::kBoolean) { + ParseMtlxBoolValue(valueString, &ret); + } else if (input.GetType() == RprUsdMaterialNodeElement::kInteger) { + ParseMtlxIntValue(valueString, &ret); + } else if (input.GetType() == RprUsdMaterialNodeElement::kFloat || + input.GetType() == RprUsdMaterialNodeElement::kAngle) { + ParseMtlxFloatValue(valueString, &ret); + } else if (input.GetType() == RprUsdMaterialNodeElement::kVector3 || + input.GetType() == RprUsdMaterialNodeElement::kColor3) { + ParseMtlxVecValue(valueString, &ret); + } else if (input.GetType() == RprUsdMaterialNodeElement::kVector2) { + ParseMtlxVecValue(valueString, &ret); + } + } + return ret; +} + +struct TokenParameterMapping { + rpr::MaterialNodeInput rprInput; + std::vector values; +}; + +bool GetTokenParameterMapping( + TfToken const& inputId, + const char* defaultValue, + TfTokenVector const& tokenValues, + int* out_defaultIndex, + TokenParameterMapping* out_mappings) { + *out_defaultIndex = -1; + + bool isValid = true; + + if (ToRpr(inputId, &out_mappings->rprInput)) { + out_mappings->values.reserve(tokenValues.size()); + for (size_t i = 0; i < tokenValues.size(); ++i) { + uint32_t value; + if (!ToRpr(tokenValues[i], &value)) { + isValid = false; + break; + } + + out_mappings->values.push_back(value); + + if (tokenValues[i] == defaultValue) { + *out_defaultIndex = i; + } + } + } else { + isValid = false; + } + + if (*out_defaultIndex == -1) { + TF_RUNTIME_ERROR("Invalid .mtlx definition: no default value"); + isValid = false; + } + + return isValid; +} + +VtValue RemapTokenInput(VtValue const& input, TokenParameterMapping const& mapping) { + if (!input.IsHolding()) { + return VtValue(); + } + + int idx = input.UncheckedGet(); + if (idx < 0 || size_t(idx) >= mapping.values.size()) { + return VtValue(); + } + + return VtValue(idx); +} + +} // namespace anonymous + +//------------------------------------------------------------------------------ +// RprUsd_MtlxNodeInfo +//------------------------------------------------------------------------------ + +namespace { + +RprUsdMaterialNodeInput::Type RprUsd_GetMaterialNodeElementType(MaterialX::TypedElementPtr const& element) { + static std::map s_mapping = { + {"boolean", RprUsdMaterialNodeElement::kBoolean}, + {"color3", RprUsdMaterialNodeElement::kColor3}, + {"float", RprUsdMaterialNodeElement::kFloat}, + {"angle", RprUsdMaterialNodeElement::kAngle}, + {"integer", RprUsdMaterialNodeElement::kInteger}, + {"volumeshader", RprUsdMaterialNodeElement::kVolumeShader}, + {"surfaceshader", RprUsdMaterialNodeElement::kSurfaceShader}, + {"displacementshader", RprUsdMaterialNodeElement::kDisplacementShader}, + {"vector3", RprUsdMaterialNodeElement::kVector3}, + {"vector2", RprUsdMaterialNodeElement::kVector2}, + {"string", RprUsdMaterialNodeElement::kToken}, + }; + + auto it = s_mapping.find(element->getType()); + if (it == s_mapping.end()) return RprUsdMaterialNodeElement::kInvalid; + + if (it->second == RprUsdMaterialNodeElement::kToken) { + // enum attribute is required + auto& enumAttr = element->getAttribute(MaterialX::ValueElement::ENUM_ATTRIBUTE); + if (enumAttr.empty()) return RprUsdMaterialNodeElement::kInvalid; + } + + return it->second; +} + +RprUsdMaterialNodeInput::Type RprUsd_GetMaterialNodeElementType(MaterialX::InputPtr const& input) { + if (input->getDefaultGeomPropString() == "Nworld") { + return RprUsdMaterialNodeElement::kNormal; + } else { + return RprUsd_GetMaterialNodeElementType(MaterialX::TypedElementPtr(input)); + } +} + +} // namespace anonymous + +RprUsd_MtlxNodeInfo::RprUsd_MtlxNodeInfo( + MaterialX::DocumentPtr const& mtlxDoc, + MaterialX::NodeDefPtr const& mtlxNodeDef, + std::string const& uiFolder) + : m_uiFolder(uiFolder) + , m_mtlxDoc(mtlxDoc) + , m_mtlxNodeDef(mtlxNodeDef) { + + auto mtlxInputs = m_mtlxNodeDef->getInputs(); + m_mtlxInputs.reserve(mtlxInputs.size()); + for (auto& input : mtlxInputs) { + auto inputType = RprUsd_GetMaterialNodeElementType(input); + if (inputType != RprUsdMaterialNodeElement::kInvalid) { + m_mtlxInputs.emplace_back(std::move(input), inputType); + } + } + + auto mtlxOutputs = m_mtlxNodeDef->getOutputs(); + m_mtlxOutputs.reserve(mtlxOutputs.size()); + for (auto& output : mtlxOutputs) { + auto outputType = RprUsd_GetMaterialNodeElementType(output); + if (outputType != RprUsdMaterialNodeElement::kInvalid) { + m_mtlxOutputs.emplace_back(std::move(output), outputType); + } + } +} + +RprUsdMaterialNodeFactoryFnc RprUsd_MtlxNodeInfo::GetFactory() const { + static const std::string kRprPrefix("rpr_"); + + // Check if node definition matches to the one of rpr native nodes + auto& nodeDefName = m_mtlxNodeDef->getNodeString(); + if (TfStringStartsWith(nodeDefName, kRprPrefix)) { + TfToken rprNodeId(nodeDefName.substr(kRprPrefix.size())); + + rpr::MaterialNodeType rprNodeType; + if (ToRpr(rprNodeId, &rprNodeType, false)) { + std::vector> rprNodeDefaultParameters; + + // Token parameter has strict list of possible values. + // Houdini converts such paramaters to int type. + // We build lookup table for such parameters to workaround this behavior + std::map tokenParamMappings; + for (auto& input : m_mtlxInputs) { + if (input.GetType() == RprUsdMaterialNodeElement::kToken) { + TfToken inputId(input.GetName()); + + int defaultIndex; + TokenParameterMapping mapping; + if (GetTokenParameterMapping(inputId, input.GetValueString(), input.GetTokenValues(), + &defaultIndex, &mapping)) { + + tokenParamMappings[inputId] = mapping; + rprNodeDefaultParameters.emplace_back(inputId, VtValue(defaultIndex)); + } + } else { + auto value = ParseMtlxValue(input); + if (!value.IsEmpty()) { + rprNodeDefaultParameters.emplace_back(TfToken(input.GetName()), std::move(value)); + } + } + } + + return [rprNodeType, rprNodeDefaultParameters, tokenParamMappings]( + RprUsd_MaterialBuilderContext* context, + std::map const& parameters) -> RprUsd_MaterialNode* { + + class RprUsd_MtlxNode : public RprUsd_BaseRuntimeNode { + public: + RprUsd_MtlxNode( + rpr::MaterialNodeType type, + RprUsd_MaterialBuilderContext* ctx, + std::map const& tokenParamMappings) + : RprUsd_BaseRuntimeNode(type, ctx) + , m_tokenParamMappings(tokenParamMappings) { + + } + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override { + auto tokenParamIt = m_tokenParamMappings.find(inputId); + if (tokenParamIt != m_tokenParamMappings.end()) { + auto& mapping = tokenParamIt->second; + + auto remappedValue = RemapTokenInput(value, mapping); + if (remappedValue.IsEmpty()) { + TF_RUNTIME_ERROR("Failed to remap token parameter %s - %s", inputId.GetText(), value.GetTypeName().c_str()); + return false; + } + + return RprUsd_BaseRuntimeNode::SetInput(mapping.rprInput, remappedValue); + } + + return RprUsd_BaseRuntimeNode::SetInput(inputId, value); + } + + private: + std::map const& m_tokenParamMappings; + }; + + auto rprNode = new RprUsd_MtlxNode(rprNodeType, context, tokenParamMappings); + + bool validInput = true; + for (auto& entry : rprNodeDefaultParameters) { + auto it = parameters.find(entry.first); + if (it != parameters.end()) { + validInput = rprNode->SetInput(entry.first, it->second); + } else { + validInput = rprNode->SetInput(entry.first, entry.second); + } + + if (!validInput) { + break; + } + } + + if (!validInput) { + delete rprNode; + return nullptr; + } + + return rprNode; + }; + } + } + + TF_WARN("Nodes with custom implementation are not supported (yet)"); + return nullptr; +} + +RprUsd_MtlxNodeElement::RprUsd_MtlxNodeElement( + MaterialX::ValueElementPtr element, + RprUsdMaterialNodeElement::Type type) + : RprUsdMaterialNodeInput(type) + , m_mtlx(std::move(element)) { + if (m_type == kToken) { + auto& enumValues = m_mtlx->getAttribute(MaterialX::ValueElement::ENUM_ATTRIBUTE); + auto values = TfStringTokenize(enumValues, ","); + for (auto& value : values) { + m_tokenValues.emplace_back(value, TfToken::Immortal); + } + } +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/mtlxNode.h b/pxr/imaging/rprUsd/materialNodes/mtlxNode.h new file mode 100644 index 000000000..8fb70e0cb --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/mtlxNode.h @@ -0,0 +1,86 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_MTLX_NODE_H +#define RPRUSD_MATERIAL_NODES_MTLX_NODE_H + +#include "pxr/imaging/rprUsd/materialRegistry.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsd_MtlxNodeElement : public RprUsdMaterialNodeInput { +public: + RprUsd_MtlxNodeElement( + MaterialX::ValueElementPtr element, + RprUsdMaterialNodeElement::Type type); + ~RprUsd_MtlxNodeElement() override = default; + + const char* GetName() const override { return GetCStr(m_mtlx->getName()); } + const char* GetUIName() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_NAME_ATTRIBUTE)); } + const char* GetUIMin() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_MIN_ATTRIBUTE)); } + const char* GetUISoftMin() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_SOFT_MIN_ATTRIBUTE)); } + const char* GetUIMax() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_MAX_ATTRIBUTE)); } + const char* GetUISoftMax() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_SOFT_MAX_ATTRIBUTE)); } + const char* GetUIFolder() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::UI_FOLDER_ATTRIBUTE)); } + const char* GetDocString() const override { return GetCStr(m_mtlx->getAttribute(MaterialX::ValueElement::DOC_ATTRIBUTE)); } + const char* GetValueString() const override { return GetCStr(m_mtlx->getValueString()); } + std::vector const& GetTokenValues() const override { return m_tokenValues; } + +private: + MaterialX::ValueElementPtr m_mtlx; + std::vector m_tokenValues; +}; + +/// \class RprUsd_MtlxNodeInfo +/// +/// RprUsd_MtlxNodeInfo describes the node that is defined by .mtlx file. +/// Right now, we support only those .mtlx definitions that corresponds to +/// the native RPR material node (RPR_MATERIAL_NODE_*). +/// In the future, obviously, we would like to be able to process custom +/// nodes that are implemented as MaterialX implementation graphs. +/// +class RprUsd_MtlxNodeInfo : public RprUsdMaterialNodeInfo { +public: + RprUsd_MtlxNodeInfo( + MaterialX::DocumentPtr const& mtlxDoc, + MaterialX::NodeDefPtr const& mtlxNodeDef, + std::string const& uiFolder); + ~RprUsd_MtlxNodeInfo() override = default; + + const char* GetName() const override { return GetCStr(m_mtlxNodeDef->getNodeString()); } + const char* GetUIName() const override { return GetCStr(m_mtlxNodeDef->getAttribute(MaterialX::ValueElement::UI_NAME_ATTRIBUTE)); } + const char* GetUIFolder() const override { return GetCStr(m_uiFolder); } + + size_t GetNumInputs() const override { return m_mtlxInputs.size(); } + RprUsdMaterialNodeInput const* GetInput(size_t idx) const override { return &m_mtlxInputs[idx]; } + + size_t GetNumOutputs() const override { return m_mtlxOutputs.size(); } + RprUsdMaterialNodeElement const* GetOutput(size_t idx) const override { return &m_mtlxOutputs[idx]; } + + RprUsdMaterialNodeFactoryFnc GetFactory() const; + +private: + std::string m_uiFolder; + MaterialX::DocumentPtr m_mtlxDoc; + MaterialX::NodeDefPtr m_mtlxNodeDef; + std::vector m_mtlxInputs; + std::vector m_mtlxOutputs; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_MTLX_NODE_H diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.cpp b/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.cpp new file mode 100644 index 000000000..e14c3dbae --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.cpp @@ -0,0 +1,486 @@ +#include "arithmeticNode.h" +#include "nodeInfo.h" + +#include "pxr/imaging/rprUsd/materialHelpers.h" +#include "pxr/imaging/rprUsd/materialMappings.h" +#include "pxr/base/tf/instantiateSingleton.h" +#include "pxr/base/arch/attributes.h" +#include "pxr/base/gf/matrix3f.h" + +PXR_NAMESPACE_OPEN_SCOPE + +template +RprUsd_MaterialNode* RprUsd_CreateRprNode( + RprUsd_MaterialBuilderContext* ctx, + std::map const& parameters) { + return new T(ctx, parameters); +} + +template +RprUsd_RprNodeInfo* GetNodeInfo() { + auto ret = new RprUsd_RprNodeInfo; + auto& nodeInfo = *ret; + + // Take `RPR_MATERIAL_NODE_OP_OPERATION`-like name and convert it into `operation` + std::string name(Node::kOpName + sizeof("RPR_MATERIAL_NODE_OP")); + for (size_t i = 0; i < name.size(); ++i) { + name[i] = std::tolower(name[i], std::locale()); + } + + nodeInfo.name = "rpr_arithmetic_" + name; + nodeInfo.uiName = std::string("RPR ") + Node::kUiName; + nodeInfo.uiFolder = "Arithmetics"; + + for (int i = 0; i < Node::kArity; ++i) { + RprUsd_RprNodeInput input(RprUsd_RprNodeInput::kColor3); + input.name = TfStringPrintf("color%d", i); + input.uiName = TfStringPrintf("Color %d", i); + input.valueString = "0,0,0"; + input.uiSoftMin = "0"; + input.uiSoftMax = "1"; + nodeInfo.inputs.push_back(std::move(input)); + } + + RprUsd_RprNodeOutput output(RprUsdMaterialNodeElement::kColor3); + output.name = "out"; + output.uiName = "out"; + nodeInfo.outputs.push_back(std::move(output)); + + return ret; +} + +/// \class RprUsd_RprArithmeticNodeRegistry +/// +/// Each arithmetic node is registered in RprUsd_RprArithmeticNodeRegistry. +/// In such a way we can easily create an arithmetic node for particular operation +/// from the code (e.g. RprUsd_UsdPreviewSurface, RprUsd_HoudiniPrincipledNode). +class RprUsd_RprArithmeticNodeRegistry { +public: + static RprUsd_RprArithmeticNodeRegistry& GetInstance() { + return TfSingleton::GetInstance(); + } + + template + void Register(rpr::MaterialNodeArithmeticOperation op) { + if (m_lookupOp.count(op)) { + TF_CODING_ERROR("Attempt to define the same arithmetic node twice: %u", op); + return; + } + + m_lookupOp[op] = m_descs.size(); + m_descs.emplace_back(); + auto& desc = m_descs.back(); + desc.factory = &RprUsd_CreateRprNode; + desc.info = GetNodeInfo(); + + // Register this node in the general node registry + RprUsdMaterialRegistry::GetInstance().Register( + TfToken(desc.info->name), + desc.factory, + desc.info); + } + + RprUsd_RprArithmeticNode* Create( + rpr::MaterialNodeArithmeticOperation op, + RprUsd_MaterialBuilderContext* ctx, + std::map const& parameters) { + auto it = m_lookupOp.find(op); + if (it != m_lookupOp.end()) { + return static_cast(m_descs[it->second].factory(ctx, parameters)); + } + + TF_CODING_ERROR("Unknown arithmetic node or not implemented: %u", op); + return nullptr; + } + +private: + friend class TfSingleton; + +private: + using FactoryFnc = std::function const&)>; + struct NodeDesc { + RprUsd_RprNodeInfo* info; + FactoryFnc factory; + }; + + std::vector m_descs; + std::unordered_map m_lookupOp; +}; + +TF_INSTANTIATE_SINGLETON(RprUsd_RprArithmeticNodeRegistry); + +namespace { + +/// There are roughly 42 arithmetic operations, each of them defines a C++ class. +/// The following define allows us to minimize code required to define these classes. +/// +/// Depending on inputs, arithmetic node output can be calculated at time of +/// material graph construction or it will be calculated in RPR engine (rpr::MaterialNode). +/// The output can be calculated at the time of material graph construction when all inputs +/// are of trivial type (float, vectors, etc). If one of the inputs is a rpr::MaterialNode +/// then arithmetic node's output will be a rpr::MaterialNode. +/// This behavior allows to implement one uniform code-path for some complex logic over material +/// node inputs (for example, see Houdini's principled node implementation of emissive color). +#define DEFINE_ARITHMETIC_NODE(op, arity, eval, uiName, doc) \ +class RprUsd_ ## op ## Node : public RprUsd_RprArithmeticNode { \ +public: \ + RprUsd_ ## op ## Node( \ + RprUsd_MaterialBuilderContext* ctx, \ + std::map const& parameters) : RprUsd_RprArithmeticNode(ctx) { \ + for (auto& entry : parameters) SetInput(entry.first, entry.second); \ + } \ + static constexpr int kArity = arity; \ + static constexpr rpr::MaterialNodeArithmeticOperation kOp = op; \ + static constexpr const char* kOpName = #op; \ + static constexpr const char* kUiName = uiName; \ + /*static constexpr const char* kDoc = doc;*/ \ +protected: \ + int GetNumArguments() const final { return kArity; } \ + rpr::MaterialNodeArithmeticOperation GetOp() const final { return kOp; } \ + VtValue EvalOperation() const final { eval } \ +}; \ +ARCH_CONSTRUCTOR(RprUsd_InitArithmeticNode ## op, 255, void) { \ + RprUsd_RprArithmeticNodeRegistry::GetInstance().Register(op); \ +} + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SUB, 2, { + return VtValue(GetRprFloat(m_args[0]) - GetRprFloat(m_args[1])); +}, "Subtraction", "Subtraction."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_ADD, 2, { + return VtValue(GetRprFloat(m_args[0]) + GetRprFloat(m_args[1])); +}, "Addition", "Addition."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_MUL, 2, { + return VtValue(GfCompMult(GetRprFloat(m_args[0]), GetRprFloat(m_args[1]))); +}, "Multiplication", "Multiplication."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_DIV, 2, { + auto lhs = GetRprFloat(m_args[0]); + auto rhs = GetRprFloat(m_args[1]); + decltype(lhs) out; + for (size_t i = 0; i < out.dimension; ++i) { + out[i] = lhs[i] / rhs[i]; + } + return VtValue(out); +}, "Division", "Division."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_NORMALIZE3, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec3f(in[0], in[1], in[2]).GetNormalized()); +}, "Normalize", "Normalize output of color0"); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_LENGTH3, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec3f(in[0], in[1], in[2]).GetLength()); +}, "Length", "Length of color0"); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_DOT3, 2, { + auto in0 = GetRprFloat(m_args[0]); + auto in1 = GetRprFloat(m_args[1]); + return VtValue(GfDot(GfVec3f(in0.data()), GfVec3f(in1.data()))); +}, "Dot", "Dot product of two rgb vectors."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_DOT4, 2, { + auto in0 = GetRprFloat(m_args[0]); + auto in1 = GetRprFloat(m_args[1]); + return VtValue(GfDot(in0, in1)); +}, "Dot4", "Dot product of two rgba vectors."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_CROSS3, 2, { + auto in0 = GetRprFloat(m_args[0]); + auto in1 = GetRprFloat(m_args[1]); + return VtValue(GfCross(GfVec3f(in0.data()), GfVec3f(in1.data()))); +}, "Cross", "Cross product."); + +#define PER_COMPONENT_UNARY_IMPL(mathFunc) \ + auto in = GetRprFloat(m_args[0]); \ + for (size_t i = 0; i < in.dimension; ++i) in[i] = mathFunc(in[i]); \ + return VtValue(in); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SIN, 1, { + PER_COMPONENT_UNARY_IMPL(std::sin); +}, "Sin", "Trigometric sine (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_COS, 1, { + PER_COMPONENT_UNARY_IMPL(std::cos); +}, "Cos", "Trigometric cosine (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_TAN, 1, { + PER_COMPONENT_UNARY_IMPL(std::tan); +}, "Tan", "Trigometric tangent (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_LOG, 1, { + PER_COMPONENT_UNARY_IMPL(std::log); +}, "Log", "Log() function."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_ATAN, 1, { + PER_COMPONENT_UNARY_IMPL(std::atan); +}, "Atan", "Trigometric arctangent (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_ASIN, 1, { + PER_COMPONENT_UNARY_IMPL(std::asin); +}, "Asin", "Trigometric arcsine (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_ACOS, 1, { + PER_COMPONENT_UNARY_IMPL(std::acos); +}, "Acos", "Trigometric arccosine (in radians)."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_ABS, 1, { + PER_COMPONENT_UNARY_IMPL(std::abs); +}, "Abs", "Absolute value."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_FLOOR, 1, { + PER_COMPONENT_UNARY_IMPL(std::floor); +}, "Floor", "Mathematical floor value of color0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_AVERAGE_XYZ, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec4f((in[0] + in[1] + in[2]) / 3.0f)); +}, "Average XYZ", "Average of color0 RGB values."); + +#define PER_COMPONENT_BINARY_IMPL(mathFunc) \ + auto in0 = GetRprFloat(m_args[0]); \ + auto in1 = GetRprFloat(m_args[1]); \ + decltype(in0) out; \ + for (size_t i = 0; i < in0.dimension; ++i) out[i] = mathFunc(in0[i], in1[i]); \ + return VtValue(out); + +static float GetAverage(float v0, float v1) { return 0.5f * (v0 + v1); } + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_AVERAGE, 2, { + PER_COMPONENT_BINARY_IMPL(GetAverage); +}, "Average", "Average of color0 and color1."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_MIN, 2, { + PER_COMPONENT_BINARY_IMPL(std::min); +}, "Min", "Minimum of two inputs."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_MAX, 2, { + PER_COMPONENT_BINARY_IMPL(std::max); +}, "Max", "Maximum of two inputs."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_MOD, 2, { + PER_COMPONENT_BINARY_IMPL(std::fmod); +}, "Mod", "Modulus of two values."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_POW, 2, { + PER_COMPONENT_BINARY_IMPL(std::pow); +}, "Pow", "Power (color0 ^ color1)."); + +#define LOGICAL_OPERATION_IMPL(OP) \ + auto lhs = GetRprFloat(m_args[0]); \ + auto rhs = GetRprFloat(m_args[1]); \ + decltype(lhs) out; \ + for (size_t i = 0; i < lhs.dimension; ++i) { \ + out[i] = (lhs[i] OP rhs[i]) ? 1.0f : 0.0f; \ + } \ + return VtValue(out); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_LOWER_OR_EQUAL, 2, { + LOGICAL_OPERATION_IMPL(<=); +}, "Lower or Equal", "Return 1 if color0 <= color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_LOWER, 2, { + LOGICAL_OPERATION_IMPL(<); +}, "Lower", "Return 1 if color0 < color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_GREATER_OR_EQUAL, 2, { + LOGICAL_OPERATION_IMPL(>=); +}, "Greater or Equal", "Return 1 if color0 >= color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_GREATER, 2, { + LOGICAL_OPERATION_IMPL(>); +}, "Greater", "Return 1 if color0 > color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_EQUAL, 2, { + LOGICAL_OPERATION_IMPL(==); +}, "Equal", "Return 1 if color0 == color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_NOT_EQUAL, 2, { + LOGICAL_OPERATION_IMPL(!=); +}, "Not Equal", "Return 1 if color0 != color1 else 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_AND, 2, { + LOGICAL_OPERATION_IMPL(&&); +}, "And", "Return 1 if color0 and color1 are not 0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_OR, 2, { + LOGICAL_OPERATION_IMPL(||); +}, "Or", "Return 1 if color0 or color1 are not 0"); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_TERNARY, 3, { + auto in0 = GetRprFloat(m_args[0]); + auto in1 = GetRprFloat(m_args[1]); + auto in2 = GetRprFloat(m_args[2]); + decltype(in0) out; + for (size_t i = 0; i < in0.dimension; ++i) { + out[i] = in0[i] ? in1[i] : in2[i]; + } + return VtValue(out); +}, "Ternary", "Return color1 if color0 is 0 else color2."); + +#define SELECT_OPERATION_IMPL(component_index) \ + auto value = GetRprFloat(m_args[0]); \ + return VtValue(GfVec4f(value[component_index])); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SELECT_X, 1, { + SELECT_OPERATION_IMPL(0); +}, "Select X", "Select the X component."); +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SELECT_Y, 1, { + SELECT_OPERATION_IMPL(1); +}, "Select Y", "Select the Y component."); +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SELECT_Z, 1, { + SELECT_OPERATION_IMPL(2); +}, "Select Z", "Select the Z component."); +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SELECT_W, 1, { + SELECT_OPERATION_IMPL(3); +}, "Select W", "Select the W component."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SHUFFLE_YZWX, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec4f(in[1], in[2], in[3], in[0])); +}, "Shuffle YZWX", "Shuffle channels of color0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SHUFFLE_ZWXY, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec4f(in[2], in[3], in[0], in[1])); +}, "Shuffle ZWXY", "Shuffle channels of color0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_SHUFFLE_WXYZ, 1, { + auto in = GetRprFloat(m_args[0]); + return VtValue(GfVec4f(in[3], in[0], in[1], in[2])); +}, "Shuffle WXYZ", "Shuffle channels of color0."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_MAT_MUL, 4, { + GfMatrix3f mat; + for (size_t i = 0; i < mat.numRows; ++i) { + auto input = GetRprFloat(m_args[i]); + for (size_t j = 0; j < mat.numColumns; ++j) { + mat[i][j] = input[j]; + } + } + + auto input = GetRprFloat(m_args[3]); + + GfVec3f vec(input.data()); + return VtValue(mat * vec); +}, "Matrix multiply", "color0,1,2 make a 3x3 matrix, multiply by color3."); + +DEFINE_ARITHMETIC_NODE(RPR_MATERIAL_NODE_OP_COMBINE, 4, { + auto in0 = GetRprFloat(m_args[0]); + auto in1 = GetRprFloat(m_args[1]); + auto in2 = GetRprFloat(m_args[2]); + decltype(in0) out(in0[0], in1[1], in2[2], 1.0f); + + if (!m_args[3].IsEmpty()) { + auto in3 = GetRprFloat(m_args[3]); + out[3] = in3[3]; + } + return VtValue(out); +}, "Combine", "Combine to (color0.r, color1.g, color2.b, 1) with three inputs. Combine to (color0.r, color1.g, color2.b, color3.a) with four inputs."); + +} // namespace anonymous + +std::unique_ptr RprUsd_RprArithmeticNode::Create( + rpr::MaterialNodeArithmeticOperation operation, + RprUsd_MaterialBuilderContext* ctx, + std::map const& parameters) { + auto node = RprUsd_RprArithmeticNodeRegistry::GetInstance().Create(operation, ctx, parameters); + return std::unique_ptr(node); +} + +bool RprUsd_RprArithmeticNode::SetInput( + TfToken const& inputId, + VtValue const& value) { + int argIndex; + if (inputId == RprUsdMaterialNodeInputTokens->color0) { + argIndex = 0; + } else if (inputId == RprUsdMaterialNodeInputTokens->color1) { + argIndex = 1; + } else if (inputId == RprUsdMaterialNodeInputTokens->color2) { + argIndex = 2; + } else if (inputId == RprUsdMaterialNodeInputTokens->color3) { + argIndex = 3; + } else { + TF_CODING_ERROR("Unexpected input for arithmetic node: %s", inputId.GetText()); + return false; + } + + return SetInput(argIndex, value); +} + +bool RprUsd_RprArithmeticNode::SetInput( + int index, + VtValue const& value) { + if (index < 0 || index > 3) { + TF_CODING_ERROR("Invalid index: %d", index); + return false; + } + + // Output is invalidated when input changes + m_output = VtValue(); + + m_args[index] = value; + return true; +} + +VtValue RprUsd_RprArithmeticNode::GetOutput() { + if (m_output.IsEmpty()) { + // If all inputs are of trivial type (uint or float, GfVec3f, etc) we can + // evaluate the output value on the CPU + bool isInputsTrivial = true; + + int numArgs = GetNumArguments(); + for (int i = 0; i < numArgs; ++i) { + if (m_args[i].IsHolding()) { + isInputsTrivial = false; + break; + } + } + + if (isInputsTrivial) { + m_output = EvalOperation(); + } else { + // Otherwise, we setup rpr::MaterialNode that calculates the value in runtime + RprMaterialNodePtr rprNode; + + rpr::Status status; + rprNode.reset(m_ctx->rprContext->CreateMaterialNode(RPR_MATERIAL_NODE_ARITHMETIC, &status)); + + if (rprNode) { + if (RPR_ERROR_CHECK(rprNode->SetInput(RPR_MATERIAL_INPUT_OP, GetOp()), "Failed to set arithmetic node operation")) { + return m_output; + } + + static const rpr::MaterialNodeInput s_arithmeticNodeInputs[] = { + RPR_MATERIAL_INPUT_COLOR0, + RPR_MATERIAL_INPUT_COLOR1, + RPR_MATERIAL_INPUT_COLOR2, + RPR_MATERIAL_INPUT_COLOR3, + }; + for (int i = 0; i < numArgs; ++i) { + if (m_args[i].IsEmpty()) { + if (RPR_ERROR_CHECK(rprNode->SetInput(s_arithmeticNodeInputs[i], 0.0f, 0.0f, 0.0f, 0.0f), "Failed to set arithmetic node input")) { + return m_output; + } + } else { + if (!SetRprInput(rprNode.get(), s_arithmeticNodeInputs[i], m_args[i])) { + return m_output; + } + } + } + + m_output = VtValue(rprNode); + } else { + TF_RUNTIME_ERROR("%s", RPR_GET_ERROR_MESSAGE(status, "Failed to create arithmetic material node", m_ctx->rprContext).c_str()); + } + } + } + + return m_output; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.h b/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.h new file mode 100644 index 000000000..a517c56ed --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/arithmeticNode.h @@ -0,0 +1,63 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_RPR_ARITHMETIC_NODE_H +#define RPRUSD_MATERIAL_NODES_RPR_ARITHMETIC_NODE_H + +#include "../materialNode.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class RprUsd_RprArithmeticNode +/// +/// Wrapper over RPR_MATERIAL_NODE_ARITHMETIC +class RprUsd_RprArithmeticNode : public RprUsd_MaterialNode { +public: + static std::unique_ptr Create( + rpr::MaterialNodeArithmeticOperation operation, + RprUsd_MaterialBuilderContext* ctx, + std::map const& parameters = {}); + + ~RprUsd_RprArithmeticNode() override = default; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; + + VtValue GetOutput(TfToken const& outputId) override { return GetOutput(); } + + /// Arithmetic node has only one output + VtValue GetOutput(); + + /// Arithmetic node has up to four arguments (\p index in range [0; 3]) + bool SetInput(int index, VtValue const& value); + +protected: + RprUsd_RprArithmeticNode(RprUsd_MaterialBuilderContext* ctx) : m_ctx(ctx) {} + + // Provided by concrete operation node + virtual int GetNumArguments() const = 0; + virtual VtValue EvalOperation() const = 0; + virtual rpr::MaterialNodeArithmeticOperation GetOp() const = 0; + +protected: + RprUsd_MaterialBuilderContext* m_ctx; + VtValue m_args[4]; + VtValue m_output; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_RPR_ARITHMETIC_NODE_H diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.cpp b/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.cpp new file mode 100644 index 000000000..a49b24e26 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.cpp @@ -0,0 +1,55 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "baseNode.h" + +#include "pxr/imaging/rprUsd/materialMappings.h" +#include "pxr/imaging/rprUsd/materialHelpers.h" +#include "pxr/imaging/rprUsd/error.h" + +PXR_NAMESPACE_OPEN_SCOPE + +RprUsd_BaseRuntimeNode::RprUsd_BaseRuntimeNode( + rpr::MaterialNodeType type, + RprUsd_MaterialBuilderContext* ctx) + : m_ctx(ctx) { + + rpr::Status status; + m_rprNode.reset(ctx->rprContext->CreateMaterialNode(type, &status)); + + if (!m_rprNode) { + throw RprUsd_NodeError(RPR_GET_ERROR_MESSAGE(status, "Failed to create material node", ctx->rprContext)); + } +} + +bool RprUsd_BaseRuntimeNode::SetInput( + TfToken const& inputId, + VtValue const& value) { + rpr::MaterialNodeInput rprInput; + if (ToRpr(inputId, &rprInput)) { + return SetInput(rprInput, value); + } + return false; +} + +bool RprUsd_BaseRuntimeNode::SetInput( + rpr::MaterialNodeInput input, + VtValue const& value) { + return SetRprInput(m_rprNode.get(), input, value); +} + +VtValue RprUsd_BaseRuntimeNode::GetOutput(TfToken const& outputId) { + return VtValue(m_rprNode); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.h b/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.h new file mode 100644 index 000000000..d65f171da --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/baseNode.h @@ -0,0 +1,54 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_RPR_BASE_NODE_H +#define RPRUSD_MATERIAL_NODES_RPR_BASE_NODE_H + +#include "../materialNode.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" + +#include + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class RprUsd_BaseRuntimeNode +/// +/// The node output of which is always rpr::MaterialNode*. +class RprUsd_BaseRuntimeNode : public RprUsd_MaterialNode { +public: + RprUsd_BaseRuntimeNode( + rpr::MaterialNodeType type, + RprUsd_MaterialBuilderContext* ctx); + + ~RprUsd_BaseRuntimeNode() override = default; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; + bool SetInput( + rpr::MaterialNodeInput input, + VtValue const& value); + + VtValue GetOutput(TfToken const& outputId) override; + +protected: + RprUsd_MaterialBuilderContext* m_ctx; + std::shared_ptr m_rprNode; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_RPR_BASE_NODE_H diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/catcherNode.cpp b/pxr/imaging/rprUsd/materialNodes/rpr/catcherNode.cpp new file mode 100644 index 000000000..5ba58719f --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/catcherNode.cpp @@ -0,0 +1,113 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "../materialNode.h" +#include "nodeInfo.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/base/arch/attributes.h" +#include "pxr/base/gf/vec2f.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS(RprUsdRprCatcherNodeTokens, + (in) + (enable) +); + +/// \class RprUsd_RprCatcherNode +/// +/// The node that allows the user to enable either shadow catcher or reflection +/// catcher (depending on how this node is constructed). +/// +/// This node has two inputs: +/// 1) boolean input that enables or disables catcher mode. +/// 2) surface shader input that is simply transmitted to the surface output. +/// This automatically means that this node can not be created without +/// existing material that outputs the real surface shader. +class RprUsd_RprCatcherNode : public RprUsd_MaterialNode { +public: + RprUsd_RprCatcherNode(bool* catcherToggle) + : m_catcherToggle(catcherToggle) { + // true by default + *m_catcherToggle = true; + } + ~RprUsd_RprCatcherNode() override = default; + + VtValue GetOutput(TfToken const& outputId) override { return m_output; } + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override { + if (inputId == RprUsdRprCatcherNodeTokens->in) { + m_output = value; + return true; + } else if (inputId == RprUsdRprCatcherNodeTokens->enable) { + if (value.IsHolding()) { + *m_catcherToggle = value.UncheckedGet() != 0; + return true; + } + } + + return false; + } + + static RprUsd_RprNodeInfo* GetInfo(std::string catcherType) { + auto ret = new RprUsd_RprNodeInfo; + auto& nodeInfo = *ret; + + nodeInfo.uiName = "RPR " + catcherType + " Catcher"; + nodeInfo.uiFolder = "Shaders"; + catcherType[0] = std::tolower(catcherType[0], std::locale()); + nodeInfo.name = "rpr_" + catcherType + "_catcher"; + + RprUsd_RprNodeInput in(RprUsdMaterialNodeElement::kSurfaceShader); + in.name = "in"; + nodeInfo.inputs.push_back(in); + + RprUsd_RprNodeInput enable(RprUsdMaterialNodeElement::kBoolean); + enable.name = "enable"; + enable.uiName = "Enable"; + enable.valueString = "true"; + nodeInfo.inputs.push_back(enable); + + RprUsd_RprNodeOutput surface(RprUsdMaterialNodeElement::kSurfaceShader); + surface.name = "surface"; + nodeInfo.outputs.push_back(surface); + + return ret; + } + +private: + bool* m_catcherToggle; + VtValue m_output; +}; + +#define REGISTER_CATCHER_NODE(CATCHER_TYPE) \ +ARCH_CONSTRUCTOR(RprUsd_Init ## CATCHER_TYPE ## CatcherNode, 255, void) { \ + auto nodeInfo = RprUsd_RprCatcherNode::GetInfo(#CATCHER_TYPE); \ + RprUsdMaterialRegistry::GetInstance().Register( \ + TfToken(nodeInfo->name, TfToken::Immortal), \ + [](RprUsd_MaterialBuilderContext* context, \ + std::map const& parameters) { \ + auto node = new RprUsd_RprCatcherNode(&context->is ## CATCHER_TYPE ## Catcher); \ + for (auto& entry : parameters) node->SetInput(entry.first, entry.second); \ + return node; \ + }, \ + nodeInfo); \ +} + +REGISTER_CATCHER_NODE(Shadow); +REGISTER_CATCHER_NODE(Reflection); + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/combineShadersNode.cpp b/pxr/imaging/rprUsd/materialNodes/rpr/combineShadersNode.cpp new file mode 100644 index 000000000..7335443a0 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/combineShadersNode.cpp @@ -0,0 +1,121 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "../materialNode.h" +#include "nodeInfo.h" + +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/base/arch/attributes.h" + +PXR_NAMESPACE_OPEN_SCOPE + +/// \class RprUsd_RprCombineShadersNode +/// +/// Convenience node to allow combination of nodes of different type. +/// +/// A bit more about why we need this node. +/// In USD you can bind only one material to the mesh. +/// But what if you want apply both displacement and surface shaders on the mesh? +/// You have two options: +/// a) add `displacement` component to the all surface shaders +/// b) take outputs of `surface` node and `displacement` and combine them into one node +/// This node implements the second option +/// +class RprUsd_RprCombineShadersNode : public RprUsd_MaterialNode { +public: + RprUsd_RprCombineShadersNode() = default; + ~RprUsd_RprCombineShadersNode() override = default; + + VtValue GetOutput(TfToken const& outputId) override { + auto it = m_outputs.find(outputId); + if (it != m_outputs.end()) { + return it->second; + } + return VtValue(); + } + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override { + if (inputId == HdMaterialTerminalTokens->volume || + inputId == HdMaterialTerminalTokens->surface || + inputId == HdMaterialTerminalTokens->displacement) { + if (value.IsHolding>()) { + m_outputs[inputId] = value; + return true; + } else { + TF_RUNTIME_ERROR("Invalid input for Combine Shaders node: must be of shader type, type=%s", value.GetTypeName().c_str()); + } + } else { + TF_RUNTIME_ERROR("Invalid input for Combine Shaders node: must be `surface` or `displacement` or `volume`, inputId=%s", inputId.GetText()); + } + + return false; + } + + static RprUsd_RprNodeInfo* GetInfo() { + auto ret = new RprUsd_RprNodeInfo; + auto& nodeInfo = *ret; + + nodeInfo.name = "rpr_combine"; + nodeInfo.uiName = "RPR Combine Shaders"; + nodeInfo.uiFolder = "Shaders"; + + RprUsd_RprNodeInput surfaceInput(RprUsdMaterialNodeElement::kSurfaceShader); + surfaceInput.name = "surface"; + surfaceInput.uiName = "Surface Shader"; + nodeInfo.inputs.push_back(surfaceInput); + + RprUsd_RprNodeInput displacementInput(RprUsdMaterialNodeElement::kDisplacementShader); + displacementInput.name = "displacement"; + displacementInput.uiName = "Displacement Shader"; + nodeInfo.inputs.push_back(displacementInput); + + RprUsd_RprNodeInput volumeInput(RprUsdMaterialNodeElement::kVolumeShader); + volumeInput.name = "volume"; + volumeInput.uiName = "Volume Shader"; + nodeInfo.inputs.push_back(volumeInput); + + RprUsd_RprNodeOutput outputSurface(RprUsdMaterialNodeElement::kSurfaceShader); + outputSurface.name = "surface"; + nodeInfo.outputs.push_back(outputSurface); + + RprUsd_RprNodeOutput outputDisplacement(RprUsdMaterialNodeElement::kDisplacementShader); + outputDisplacement.name = "displacement"; + nodeInfo.outputs.push_back(outputDisplacement); + + RprUsd_RprNodeOutput outputVolume(RprUsdMaterialNodeElement::kVolumeShader); + outputVolume.name = "volume"; + nodeInfo.outputs.push_back(outputVolume); + + return ret; + } + +private: + std::map m_outputs; +}; + +ARCH_CONSTRUCTOR(RprUsd_InitCombineShadersNode, 255, void) { + auto nodeInfo = RprUsd_RprCombineShadersNode::GetInfo(); + RprUsdMaterialRegistry::GetInstance().Register( + TfToken(nodeInfo->name, TfToken::Immortal), + [](RprUsd_MaterialBuilderContext* context, + std::map const& parameters) { + auto node = new RprUsd_RprCombineShadersNode(); + for (auto& entry : parameters) node->SetInput(entry.first, entry.second); + return node; + }, + nodeInfo); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/displaceNode.cpp b/pxr/imaging/rprUsd/materialNodes/rpr/displaceNode.cpp new file mode 100644 index 000000000..79c2867f1 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/displaceNode.cpp @@ -0,0 +1,148 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "baseNode.h" +#include "nodeInfo.h" + +#include "pxr/imaging/rprUsd/materialHelpers.h" +#include "pxr/base/arch/attributes.h" +#include "pxr/base/gf/vec2f.h" + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS(RprUsdRprDisplaceNodeTokens, + (minscale) + (maxscale) + (in) +); + +/// \class RprUsd_RprDisplaceNode +/// +/// The node that maps RPR displacement functionality one-to-one: +/// - `in` expects rpr::MaterialNode as input and corresponds to `rprShapeSetDisplacementMaterial` +/// - `minscale` and `maxscale` inputs are expected to be of float type and correspond to `rprShapeSetDisplacementScale` +/// +class RprUsd_RprDisplaceNode : public RprUsd_MaterialNode { +public: + RprUsd_RprDisplaceNode( + RprUsd_MaterialBuilderContext* ctx) + : m_ctx(ctx) + , m_displacementScale(0, 1) { + + } + ~RprUsd_RprDisplaceNode() override = default; + + VtValue GetOutput(TfToken const& outputId) override { + if (m_output.IsEmpty()) { + return VtValue(); + } + + m_ctx->displacementScale = VtValue(m_displacementScale); + return m_output; + } + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override { + if (inputId == RprUsdRprDisplaceNodeTokens->minscale) { + if (value.IsHolding()) { + m_displacementScale[0] = value.UncheckedGet(); + } else { + TF_RUNTIME_ERROR("Input `minscale` has invalid type: %s, expected - float", value.GetTypeName().c_str()); + m_displacementScale[0] = 0.0f; + return false; + } + } else if (inputId == RprUsdRprDisplaceNodeTokens->maxscale) { + if (value.IsHolding()) { + m_displacementScale[1] = value.UncheckedGet(); + } else { + TF_RUNTIME_ERROR("Input `maxscale` has invalid type: %s, expected - float", value.GetTypeName().c_str()); + m_displacementScale[1] = 1.0f; + return false; + } + } else if (inputId == RprUsdRprDisplaceNodeTokens->in) { + if (value.IsHolding>()) { + m_output = value; + } else { + auto vec = GetRprFloat(value); + if (!GfIsEqual(vec, GfVec4f(0.0f))) { + if (!m_scalarDisplaceNode) { + m_scalarDisplaceNode.reset(new RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_CONSTANT_TEXTURE, m_ctx)); + } + + m_scalarDisplaceNode->SetInput(RPR_MATERIAL_INPUT_VALUE, value); + m_output = VtValue(m_scalarDisplaceNode); + } else { + m_scalarDisplaceNode = nullptr; + m_output = VtValue(); + } + } + } + + return true; + } + + static RprUsd_RprNodeInfo* GetInfo() { + auto ret = new RprUsd_RprNodeInfo; + auto& nodeInfo = *ret; + + nodeInfo.name = "rpr_displace"; + nodeInfo.uiName = "RPR Displace"; + nodeInfo.uiFolder = "Shaders"; + + RprUsd_RprNodeInput input(RprUsdMaterialNodeElement::kFloat); + input.uiSoftMin = "0"; + input.uiSoftMax = "1"; + + input.name = "in"; + input.uiName = "Displacement"; + input.valueString = "0"; + nodeInfo.inputs.push_back(input); + + input.name = "minscale"; + input.uiName = "Minimum Scale"; + nodeInfo.inputs.push_back(input); + + input.name = "maxscale"; + input.uiName = "Maximum Scale"; + input.valueString = "1"; + nodeInfo.inputs.push_back(input); + + RprUsd_RprNodeOutput output(RprUsdMaterialNodeElement::kDisplacementShader); + output.name = "displacement"; + nodeInfo.outputs.push_back(output); + + return ret; + } + +private: + RprUsd_MaterialBuilderContext* m_ctx; + GfVec2f m_displacementScale; + std::shared_ptr m_scalarDisplaceNode; + VtValue m_output; +}; + +ARCH_CONSTRUCTOR(RprUsd_InitDisplaceNode, 255, void) { + auto nodeInfo = RprUsd_RprDisplaceNode::GetInfo(); + RprUsdMaterialRegistry::GetInstance().Register( + TfToken(nodeInfo->name, TfToken::Immortal), + [](RprUsd_MaterialBuilderContext* context, + std::map const& parameters) { + auto node = new RprUsd_RprDisplaceNode(context); + for (auto& entry : parameters) node->SetInput(entry.first, entry.second); + return node; + }, + nodeInfo); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/rpr/nodeInfo.h b/pxr/imaging/rprUsd/materialNodes/rpr/nodeInfo.h new file mode 100644 index 000000000..5364a904a --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/rpr/nodeInfo.h @@ -0,0 +1,77 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_RPR_NODE_INFO_H +#define RPRUSD_MATERIAL_NODES_RPR_NODE_INFO_H + +#include "pxr/imaging/rprUsd/materialRegistry.h" + +PXR_NAMESPACE_OPEN_SCOPE + +struct RprUsd_RprNodeInput : public RprUsdMaterialNodeInput { + RprUsd_RprNodeInput(RprUsdMaterialNodeInput::Type type) : RprUsdMaterialNodeInput(type) {} + const char* GetName() const override { return GetCStr(name); } + const char* GetUIName() const override { return GetCStr(uiName); } + const char* GetUIMin() const override { return GetCStr(uiMin); } + const char* GetUISoftMin() const override { return GetCStr(uiSoftMin); } + const char* GetUIMax() const override { return GetCStr(uiMax); } + const char* GetUISoftMax() const override { return GetCStr(uiSoftMax); } + const char* GetUIFolder() const override { return GetCStr(uiFolder); } + const char* GetDocString() const override { return GetCStr(docString); } + const char* GetValueString() const override { return GetCStr(valueString); } + std::vector const& GetTokenValues() const override { return m_tokenValues; } + + std::string name; + std::string uiName; + std::string uiMin; + std::string uiSoftMin; + std::string uiMax; + std::string uiSoftMax; + std::string uiFolder; + std::string docString; + std::string valueString; + std::vector m_tokenValues; +}; + +struct RprUsd_RprNodeOutput : public RprUsdMaterialNodeElement { + RprUsd_RprNodeOutput(RprUsdMaterialNodeElement::Type type) : RprUsdMaterialNodeElement(type) {} + const char* GetName() const override { return !name.empty() ? name.c_str() : nullptr; }; + const char* GetUIName() const override { return !uiName.empty() ? uiName.c_str() : nullptr; }; + const char* GetDocString() const override { return !docString.empty() ? docString.c_str() : nullptr; }; + + std::string name; + std::string uiName; + std::string docString; +}; + +struct RprUsd_RprNodeInfo : public RprUsdMaterialNodeInfo { + const char* GetName() const override { return GetCStr(name); } + const char* GetUIName() const override { return GetCStr(uiName); } + const char* GetUIFolder() const override { return GetCStr(uiFolder); } + + size_t GetNumInputs() const override { return inputs.size(); } + RprUsdMaterialNodeInput const* GetInput(size_t idx) const override { return &inputs[idx]; } + + size_t GetNumOutputs() const override { return outputs.size(); } + RprUsdMaterialNodeElement const* GetOutput(size_t idx) const override { return &outputs[idx]; } + + std::string name; + std::string uiName; + std::string uiFolder; + std::vector inputs; + std::vector outputs; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_RPR_NODE_INFO_H diff --git a/pxr/imaging/rprUsd/materialNodes/usdNode.cpp b/pxr/imaging/rprUsd/materialNodes/usdNode.cpp new file mode 100644 index 000000000..4faf55de9 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/usdNode.cpp @@ -0,0 +1,531 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "usdNode.h" +#include "rpr/arithmeticNode.h" + +#include "pxr/imaging/rprUsd/materialHelpers.h" +#include "pxr/imaging/rprUsd/materialMappings.h" +#include "pxr/imaging/rprUsd/imageCache.h" +#include "pxr/imaging/rprUsd/coreImage.h" +#include "pxr/imaging/rprUsd/error.h" +#include "pxr/base/arch/attributes.h" +#include "pxr/base/tf/staticTokens.h" +#include "pxr/usd/sdf/assetPath.h" +#include "pxr/base/gf/matrix3f.h" +#include "pxr/base/gf/vec2f.h" + +PXR_NAMESPACE_OPEN_SCOPE + +//------------------------------------------------------------------------------ +// RprUsd_UsdPreviewSurface +//------------------------------------------------------------------------------ + +TF_DEFINE_PRIVATE_TOKENS(UsdPreviewSurfaceTokens, + (diffuseColor) + (emissiveColor) + (useSpecularWorkflow) + (specularColor) + (metallic) + (roughness) + (clearcoat) + (clearcoatRoughness) + (opacity) + (opacityThreshold) + (ior) + (displacement) + (normal) +); + +RprUsd_UsdPreviewSurface::RprUsd_UsdPreviewSurface( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters) + : RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_UBERV2, ctx) { + + m_albedo = VtValue(GfVec4f(1.0f)); + m_reflection = VtValue(GfVec4f(1.0f)); + + auto setInput = [&hydraParameters, this](TfToken const& id, VtValue defaultValue) { + auto it = hydraParameters.find(id); + if (it == hydraParameters.end()) { + SetInput(id, defaultValue); + } else { + SetInput(id, it->second); + } + }; + setInput(UsdPreviewSurfaceTokens->diffuseColor, VtValue(GfVec3f(0.18f))); + setInput(UsdPreviewSurfaceTokens->emissiveColor, VtValue(GfVec3f(0.0f))); + setInput(UsdPreviewSurfaceTokens->useSpecularWorkflow, VtValue(0)); + setInput(UsdPreviewSurfaceTokens->specularColor, VtValue(GfVec3f(0.0f))); + setInput(UsdPreviewSurfaceTokens->metallic, VtValue(0.0f)); + setInput(UsdPreviewSurfaceTokens->roughness, VtValue(0.5f)); + setInput(UsdPreviewSurfaceTokens->clearcoat, VtValue(0.0f)); + setInput(UsdPreviewSurfaceTokens->clearcoatRoughness, VtValue(0.01f)); + setInput(UsdPreviewSurfaceTokens->opacity, VtValue(1.0f)); + setInput(UsdPreviewSurfaceTokens->opacityThreshold, VtValue(0.0f)); + setInput(UsdPreviewSurfaceTokens->ior, VtValue(1.5f)); + setInput(UsdPreviewSurfaceTokens->displacement, VtValue(0.0f)); + + m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFLECTION_WEIGHT, 1.0f, 1.0f, 1.0f, 1.0f); +} + +bool RprUsd_UsdPreviewSurface::SetInput( + TfToken const& inputId, + VtValue const& value) { + if (UsdPreviewSurfaceTokens->diffuseColor == inputId) { + m_albedo = value; + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_DIFFUSE_COLOR, value) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFRACTION_COLOR, value); + } else if (UsdPreviewSurfaceTokens->emissiveColor == inputId) { + if (!m_emissiveWeightNode) { + m_emissiveWeightNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_GREATER, m_ctx); + } + m_emissiveWeightNode->SetInput(0, value); + m_emissiveWeightNode->SetInput(1, VtValue(GfVec4f(0.0f))); + auto emissionWeight = m_emissiveWeightNode->GetOutput(); + + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_EMISSION_WEIGHT, emissionWeight) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_EMISSION_COLOR, value); + } else if (UsdPreviewSurfaceTokens->useSpecularWorkflow == inputId) { + m_useSpecular = value.Get(); + } else if (UsdPreviewSurfaceTokens->specularColor == inputId) { + m_reflection = value; + } else if (UsdPreviewSurfaceTokens->metallic == inputId) { + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFLECTION_METALNESS, value); + } else if (UsdPreviewSurfaceTokens->roughness == inputId) { + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_DIFFUSE_ROUGHNESS, value) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFLECTION_ROUGHNESS, value) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFRACTION_ROUGHNESS, value); + } else if (UsdPreviewSurfaceTokens->clearcoat == inputId) { + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_COATING_WEIGHT, value); + } else if (UsdPreviewSurfaceTokens->clearcoatRoughness == inputId) { + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_COATING_ROUGHNESS, value); + } else if (UsdPreviewSurfaceTokens->opacity == inputId) { + if (!m_refractionWeightNode) { + m_refractionWeightNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_SUB, m_ctx); + } + m_refractionWeightNode->SetInput(0, VtValue(GfVec4f(1.0f))); + m_refractionWeightNode->SetInput(1, value); + auto refractionWeight = m_refractionWeightNode->GetOutput(); + + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_DIFFUSE_WEIGHT, value) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFRACTION_WEIGHT, refractionWeight); + } else if (UsdPreviewSurfaceTokens->opacityThreshold == inputId) { + + } else if (UsdPreviewSurfaceTokens->ior == inputId) { + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFRACTION_IOR, value); + } else if (UsdPreviewSurfaceTokens->displacement == inputId) { + if (value.IsHolding()) { + m_displacementOutput = value; + } else { + auto vec = GetRprFloat(value); + if (!GfIsEqual(vec, GfVec4f(0.0f))) { + if (!m_displaceNode) { + m_displaceNode.reset(new RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_CONSTANT_TEXTURE, m_ctx)); + } + + m_displaceNode->SetInput(RPR_MATERIAL_INPUT_VALUE, value); + m_displacementOutput = VtValue(m_displaceNode); + } else { + m_displaceNode = nullptr; + m_displacementOutput = VtValue(); + } + } + } else if (UsdPreviewSurfaceTokens->normal == inputId) { + if (value.IsHolding()) { + if (!m_normalMapNode) { + m_normalMapNode.reset(new RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_NORMAL_MAP, m_ctx)); + } + m_normalMapNode->SetInput(RPR_MATERIAL_INPUT_COLOR, value); + + auto normalMapOutput = m_normalMapNode->GetOutput(TfToken()); + return SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_DIFFUSE_NORMAL, normalMapOutput) && + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFLECTION_NORMAL, normalMapOutput); + } else { + TF_RUNTIME_ERROR("`normal` input should be of material node type - %s", value.GetTypeName().c_str()); + return false; + } + } else { + TF_CODING_ERROR("Unknown UsdPreviewSurface parameter %s: %s", inputId.GetText(), value.GetTypeName().c_str()); + return false; + } + + return true; +} + +VtValue RprUsd_UsdPreviewSurface::GetOutput(TfToken const& outputId) { + if (HdMaterialTerminalTokens->surface == outputId) { + if (m_useSpecular) { + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE, RPR_UBER_MATERIAL_IOR_MODE_PBR), "Failed to set material input"); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR, m_reflection); + } else { + RPR_ERROR_CHECK(m_rprNode->SetInput(RPR_MATERIAL_INPUT_UBER_REFLECTION_MODE, RPR_UBER_MATERIAL_IOR_MODE_METALNESS), "Failed to set material input"); + SetRprInput(m_rprNode.get(), RPR_MATERIAL_INPUT_UBER_REFLECTION_COLOR, m_albedo); + } + + return RprUsd_BaseRuntimeNode::GetOutput(outputId); + } else if (HdMaterialTerminalTokens->displacement == outputId) { + return m_displacementOutput; + } + + return VtValue(); +} + +//------------------------------------------------------------------------------ +// RprUsd_UsdUVTexture +//------------------------------------------------------------------------------ + +TF_DEFINE_PUBLIC_TOKENS(RprUsd_UsdUVTextureTokens, RPRUSD_USD_UV_TEXTURE_TOKENS); + +namespace { + +rpr::ImageWrapType GetWrapType(VtValue const& value) { + if (value.IsHolding()) { + auto& id = value.UncheckedGet(); + if (id == RprUsd_UsdUVTextureTokens->black) { + return RPR_IMAGE_WRAP_TYPE_CLAMP_ZERO; + } else if (id == RprUsd_UsdUVTextureTokens->clamp) { + return RPR_IMAGE_WRAP_TYPE_CLAMP_TO_EDGE; + } else if (id == RprUsd_UsdUVTextureTokens->mirror) { + return RPR_IMAGE_WRAP_TYPE_MIRRORED_REPEAT; + } else if (id == RprUsd_UsdUVTextureTokens->repeat) { + return RPR_IMAGE_WRAP_TYPE_REPEAT; + } else { + TF_CODING_ERROR("Unknown image wrap type: %s", id.GetText()); + } + } + + return {}; +} + +} // namespace anonymous + +RprUsd_UsdUVTexture::RprUsd_UsdUVTexture( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters) + : m_ctx(ctx) { + + auto fileIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->file); + if (fileIt == hydraParameters.end()) { + throw RprUsd_NodeError("UsdUVTexture requires file parameter"); + } + + RprUsdMaterialRegistry::TextureCommit textureCommit = {}; + + if (fileIt->second.IsHolding()) { + auto& assetPath = fileIt->second.UncheckedGet(); + if (assetPath.GetResolvedPath().empty()) { + textureCommit.filepath = assetPath.GetAssetPath(); + } else { + textureCommit.filepath = assetPath.GetResolvedPath(); + } + } + + if (textureCommit.filepath.empty()) { + throw RprUsd_NodeError("UsdUVTexture: empty file path"); + } + + auto colorSpaceIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->colorSpace); + if (colorSpaceIt != hydraParameters.end() && + colorSpaceIt->second.Get() == RprUsd_UsdUVTextureTokens->linear) { + textureCommit.forceLinearSpace = true; + } + + rpr::ImageWrapType wrapS = {}; + auto wrapSIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->wrapS); + if (wrapSIt != hydraParameters.end()) wrapS = GetWrapType(wrapSIt->second); + + rpr::ImageWrapType wrapT = {}; + auto wrapTIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->wrapT); + if (wrapTIt != hydraParameters.end()) wrapT = GetWrapType(wrapTIt->second); + + if (wrapS || wrapT) { + if (wrapS != wrapT) { + TF_RUNTIME_ERROR("RPR renderer does not support different wrapS and wrapT modes"); + } + + textureCommit.wrapType = wrapS ? wrapS : wrapT; + } + + rpr::Status status; + m_imageNode.reset(ctx->rprContext->CreateMaterialNode(RPR_MATERIAL_NODE_IMAGE_TEXTURE, &status)); + if (!m_imageNode) { + throw RprUsd_NodeError(RPR_GET_ERROR_MESSAGE(status, "Failed to create image texture material node")); + } + m_outputs[RprUsd_UsdUVTextureTokens->rgba] = VtValue(m_imageNode); + + textureCommit.setTextureCallback = [this](std::shared_ptr const& image) { + if (!image) return; + + if (!RPR_ERROR_CHECK(m_imageNode->SetInput(RPR_MATERIAL_INPUT_DATA, image->GetRootImage()), "Failed to set material node image data input")) { + m_image = image; + } + }; + + // Texture loading is postponed to allow multi-threading loading. + // + RprUsdMaterialRegistry::GetInstance().CommitTexture(std::move(textureCommit)); + + auto scaleIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->scale); + if (scaleIt != hydraParameters.end() && + scaleIt->second.IsHolding()) { + auto& scale = scaleIt->second.UncheckedGet(); + if (!GfIsEqual(scale, GfVec4f(1.0f))) { + m_scaleNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_MUL, m_ctx); + if (m_scaleNode) { + if (!m_scaleNode->SetInput(0, m_outputs[RprUsd_UsdUVTextureTokens->rgba]) || + !m_scaleNode->SetInput(1, scaleIt->second) || + m_scaleNode->GetOutput().IsEmpty()) { + m_scaleNode = nullptr; + } else { + m_outputs[RprUsd_UsdUVTextureTokens->rgba] = m_scaleNode->GetOutput(); + } + } + } + } + + auto biasIt = hydraParameters.find(RprUsd_UsdUVTextureTokens->bias); + if (biasIt != hydraParameters.end() && + biasIt->second.IsHolding()) { + auto& bias = biasIt->second.UncheckedGet(); + if (!GfIsEqual(bias, GfVec4f(0.0f))) { + m_biasNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_ADD, m_ctx); + if (m_biasNode) { + if (!m_biasNode->SetInput(0, m_outputs[RprUsd_UsdUVTextureTokens->rgba]) || + !m_biasNode->SetInput(1, biasIt->second) || + m_biasNode->GetOutput().IsEmpty()) { + m_biasNode = nullptr; + } else { + m_outputs[RprUsd_UsdUVTextureTokens->rgba] = m_biasNode->GetOutput(); + } + } + } + } +} + +VtValue RprUsd_UsdUVTexture::GetOutput(TfToken const& outputId) { + if (outputId == RprUsd_UsdUVTextureTokens->rgb) { + return GetOutput(RprUsd_UsdUVTextureTokens->rgba); + } + + auto outputIt = m_outputs.find(outputId); + if (outputIt != m_outputs.end()) { + return outputIt->second; + } + + rpr::MaterialNodeArithmeticOperation channel; + if (outputId == RprUsd_UsdUVTextureTokens->r) { + channel = RPR_MATERIAL_NODE_OP_SELECT_X; + } else if (outputId == RprUsd_UsdUVTextureTokens->g) { + channel = RPR_MATERIAL_NODE_OP_SELECT_Y; + } else if (outputId == RprUsd_UsdUVTextureTokens->b) { + channel = RPR_MATERIAL_NODE_OP_SELECT_Z; + } else if (outputId == RprUsd_UsdUVTextureTokens->a) { + channel = RPR_MATERIAL_NODE_OP_SELECT_W; + } else { + TF_CODING_ERROR("Invalid outputId requested: %s", outputId.GetText()); + return VtValue(); + } + + auto selectChannelNode = RprUsd_RprArithmeticNode::Create(channel, m_ctx); + if (selectChannelNode) { + if (selectChannelNode->SetInput(0, m_outputs[RprUsd_UsdUVTextureTokens->rgba]) && + !selectChannelNode->GetOutput().IsEmpty()) { + auto output = selectChannelNode->GetOutput(); + m_outputs[outputId] = output; + return output; + } else { + TF_RUNTIME_ERROR("Failed to set select node inputs"); + } + } else { + TF_RUNTIME_ERROR("Failed to create select node"); + } + + return VtValue(); +} + +bool RprUsd_UsdUVTexture::SetInput( + TfToken const& inputId, + VtValue const& value) { + if (inputId == RprUsd_UsdUVTextureTokens->st) { + return SetRprInput(m_imageNode.get(), RPR_MATERIAL_INPUT_UV, value); + } else { + TF_CODING_ERROR("UsdUVTexture accepts only `st` input"); + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +// RprUsd_UsdPrimvarReader +//------------------------------------------------------------------------------ + +TF_DEFINE_PRIVATE_TOKENS(UsdPrimvarReaderTokens, + (varname) +); + +RprUsd_UsdPrimvarReader::RprUsd_UsdPrimvarReader( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters) + : RprUsd_BaseRuntimeNode(RPR_MATERIAL_NODE_INPUT_LOOKUP, ctx) { + // Primvar reader node is a node that allows the user to read arbitrary primvar. + // There is no such functionality in RPR, at least the one exposed in the same expressive manner. + // + // TODO: I think that we can use buffer sampler node to fully implement primvar reader but this is only an idea + // + // For now, we allow the creation of float2 primvar reader only + // and we use it only for one purpose - control over mesh UVs. + // + // We are using this node to get the name of the primvar that should be interpreted as UVs. + // Also, from the node logic standpoint, this node is fully correct - + // it outputs actual UVs so that the user can manipulate it in any way. + + auto varnameNameIt = hydraParameters.find(UsdPrimvarReaderTokens->varname); + if (varnameNameIt != hydraParameters.end() && + varnameNameIt->second.IsHolding()) { + auto& varname = varnameNameIt->second.UncheckedGet(); + if (!varname.IsEmpty()) { + ctx->uvPrimvarName = varname; + } + } + + auto status = m_rprNode->SetInput(RPR_MATERIAL_INPUT_VALUE, RPR_MATERIAL_NODE_LOOKUP_UV); + if (status != RPR_SUCCESS) { + throw RprUsd_NodeError(RPR_GET_ERROR_MESSAGE(status, "Failed to set lookup node input", ctx->rprContext)); + } +} + +bool RprUsd_UsdPrimvarReader::SetInput( + TfToken const& inputId, + VtValue const& value) { + TF_RUNTIME_ERROR("No inputs supported. Got %s", inputId.GetText()); + return false; +} + +//------------------------------------------------------------------------------ +// RprUsd_UsdTransform2d +//------------------------------------------------------------------------------ + +TF_DEFINE_PRIVATE_TOKENS(UsdTransform2dTokens, + (rotation) + (scale) + (translation) +); + +RprUsd_UsdTransform2d::RprUsd_UsdTransform2d( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters) + : m_ctx(ctx) { + + float rotationDegrees = 0.0f; + GfVec2f scale(1.0f); + GfVec2f translation(0.0f); + + auto rotationIt = hydraParameters.find(UsdTransform2dTokens->rotation); + if (rotationIt != hydraParameters.end() && + rotationIt->second.IsHolding()) { + rotationDegrees = rotationIt->second.UncheckedGet(); + } + + auto scaleIt = hydraParameters.find(UsdTransform2dTokens->scale); + if (scaleIt != hydraParameters.end() && + scaleIt->second.IsHolding()) { + scale = scaleIt->second.UncheckedGet(); + } + + auto translationIt = hydraParameters.find(UsdTransform2dTokens->translation); + if (translationIt != hydraParameters.end() && + translationIt->second.IsHolding()) { + translation = translationIt->second.UncheckedGet(); + } + + if (rotationDegrees == 0.0f && + scale == GfVec2f(1.0f) && + translation == GfVec2f(0.0f)) { + throw RprUsd_NodeEmpty(); + } + + float rotation = GfDegreesToRadians(rotationDegrees); + float rotCos = std::cos(rotation); + float rotSin = std::sin(rotation); + + // XXX (Houdini): Proposal of UsdPreviewSurface states that rotation is + // "Counter-clockwise rotation in degrees around the origin", + // by default, the origin is the zero point on the UV coordinate system + // but Houdini's Karma uses origin = (0.5, 0.5). We do the same right now + GfVec2f origin(0.5f); + + GfMatrix3f uvTransform( + 1.0, 0.0, -origin[0], + 0.0, 1.0, -origin[1], + 0.0, 0.0, 1.0); + uvTransform = GfMatrix3f( + scale[0], 0.0, 0.0, + 0.0, scale[1], 0.0, + 0.0, 0.0, 1.0) * uvTransform; + uvTransform = GfMatrix3f( + rotCos, -rotSin, 0.0, + rotSin, rotCos, 0.0, + 0.0f, 0.0f, 1.0f) * uvTransform; + uvTransform[0][2] += translation[0] + origin[0]; + uvTransform[1][2] += translation[1] + origin[1]; + + m_setZToOneNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_ADD, m_ctx); + m_transformNode = RprUsd_RprArithmeticNode::Create(RPR_MATERIAL_NODE_OP_MAT_MUL, m_ctx); + + if (!m_setZToOneNode || !m_transformNode) { + throw RprUsd_NodeError("Failed to create required arithmetic nodes"); + } + + auto& m = uvTransform; + if (!m_setZToOneNode->SetInput(0, VtValue(GfVec4f(0.0f, 0.0f, 1.0f, 0.0f))) || + !m_transformNode->SetInput(0, VtValue(GfVec4f(m[0][0], m[0][1], m[0][2], 0.0f))) || + !m_transformNode->SetInput(1, VtValue(GfVec4f(m[1][0], m[1][1], m[1][2], 0.0f))) || + !m_transformNode->SetInput(2, VtValue(GfVec4f(m[2][0], m[2][1], m[2][2], 0.0f)))) { + throw RprUsd_NodeError("Failed to set arithmetic node inputs"); + } +} + +VtValue RprUsd_UsdTransform2d::GetOutput(TfToken const& outputId) { + return m_transformNode->GetOutput(); +} + +bool RprUsd_UsdTransform2d::SetInput( + TfToken const& inputId, + VtValue const& value) { + return m_setZToOneNode->SetInput(1, value) && m_transformNode->SetInput(3, m_setZToOneNode->GetOutput()); +} + +template +RprUsd_MaterialNode* RprUsd_CreateUsdNode( + RprUsd_MaterialBuilderContext* ctx, + std::map const& params) { + return new T(ctx, params); +} + +template +void RprUsd_RegisterUsdNode(const char* id) { + RprUsdMaterialRegistry::GetInstance().Register( + TfToken(id, TfToken::Immortal), + &RprUsd_CreateUsdNode); +} + +ARCH_CONSTRUCTOR(RprUsd_RegisterUsdNodes, 255, void) { + RprUsd_RegisterUsdNode("UsdPreviewSurface"); + RprUsd_RegisterUsdNode("UsdPrimvarReader_float2"); + RprUsd_RegisterUsdNode("UsdTransform2d"); + RprUsd_RegisterUsdNode("UsdUVTexture"); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialNodes/usdNode.h b/pxr/imaging/rprUsd/materialNodes/usdNode.h new file mode 100644 index 000000000..119a8d313 --- /dev/null +++ b/pxr/imaging/rprUsd/materialNodes/usdNode.h @@ -0,0 +1,130 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_NODES_USD_NODE_H +#define RPRUSD_MATERIAL_NODES_USD_NODE_H + +#include "rpr/baseNode.h" + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdCoreImage; +class RprUsd_RprArithmeticNode; + +class RprUsd_UsdPreviewSurface : public RprUsd_BaseRuntimeNode { +public: + RprUsd_UsdPreviewSurface( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters); + ~RprUsd_UsdPreviewSurface() override = default; + + VtValue GetOutput(TfToken const& outputId) override; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; + +private: + bool m_useSpecular; + VtValue m_albedo; + VtValue m_reflection; + + std::unique_ptr m_emissiveWeightNode; + std::unique_ptr m_refractionWeightNode; + std::unique_ptr m_normalMapNode; + + std::shared_ptr m_displaceNode; + VtValue m_displacementOutput; +}; + +#define RPRUSD_USD_UV_TEXTURE_TOKENS \ + (file) \ + (scale) \ + (bias) \ + (wrapS) \ + (wrapT) \ + (black) \ + (clamp) \ + (mirror) \ + (repeat) \ + (colorSpace) \ + (linear) \ + (st) \ + (rgba) \ + (rgb) \ + (r) \ + (g) \ + (b) \ + (a) + +TF_DECLARE_PUBLIC_TOKENS(RprUsd_UsdUVTextureTokens, RPRUSD_USD_UV_TEXTURE_TOKENS); + +class RprUsd_UsdUVTexture : public RprUsd_MaterialNode { +public: + RprUsd_UsdUVTexture( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters); + ~RprUsd_UsdUVTexture() override = default; + + VtValue GetOutput(TfToken const& outputId) override; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; + +private: + RprUsd_MaterialBuilderContext* m_ctx; + + std::shared_ptr m_image; + std::shared_ptr m_imageNode; + std::shared_ptr m_scaleNode; + std::shared_ptr m_biasNode; + + std::map m_outputs; +}; + +class RprUsd_UsdPrimvarReader : public RprUsd_BaseRuntimeNode { +public: + RprUsd_UsdPrimvarReader( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters); + ~RprUsd_UsdPrimvarReader() override = default; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; +}; + +class RprUsd_UsdTransform2d : public RprUsd_MaterialNode { +public: + RprUsd_UsdTransform2d( + RprUsd_MaterialBuilderContext* ctx, + std::map const& hydraParameters); + ~RprUsd_UsdTransform2d() override = default; + + VtValue GetOutput(TfToken const& outputId) override; + + bool SetInput( + TfToken const& inputId, + VtValue const& value) override; + +private: + RprUsd_MaterialBuilderContext* m_ctx; + + std::unique_ptr m_setZToOneNode; + std::shared_ptr m_transformNode; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_NODES_USD_NODE_H diff --git a/pxr/imaging/rprUsd/materialRegistry.cpp b/pxr/imaging/rprUsd/materialRegistry.cpp new file mode 100644 index 000000000..86bf79c7d --- /dev/null +++ b/pxr/imaging/rprUsd/materialRegistry.cpp @@ -0,0 +1,508 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "pxr/imaging/glf/glew.h" +#include "pxr/imaging/glf/uvTextureData.h" +#include "pxr/imaging/glf/image.h" +#include "pxr/imaging/rprUsd/materialRegistry.h" +#include "pxr/imaging/rprUsd/imageCache.h" +#include "pxr/imaging/rprUsd/debugCodes.h" +#include "pxr/imaging/rprUsd/material.h" +#include "pxr/imaging/rprUsd/util.h" +#include "pxr/base/tf/instantiateSingleton.h" +#include "pxr/base/tf/staticTokens.h" +#include "pxr/base/tf/envSetting.h" +#include "pxr/base/tf/pathUtils.h" +#include "pxr/base/tf/getenv.h" +#include "pxr/base/work/loops.h" + +#include "materialNodes/usdNode.h" +#include "materialNodes/houdiniPrincipledShaderNode.h" + +#include "materialNodes/mtlxNode.h" +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_INSTANTIATE_SINGLETON(RprUsdMaterialRegistry); + +TF_DEFINE_ENV_SETTING(RPRUSD_MATERIAL_NETWORK_SELECTOR, "rpr", + "Material network selector to be used in hdRpr"); + +RprUsdMaterialRegistry::RprUsdMaterialRegistry() + : m_materialNetworkSelector(TfGetEnvSetting(RPRUSD_MATERIAL_NETWORK_SELECTOR)) { + +} + +std::vector const& +RprUsdMaterialRegistry::GetRegisteredNodes() { + if (m_mtlxDefsDirty) { + m_mtlxDefsDirty = false; + + auto RPR = TfGetenv("RPR"); + if (RPR.empty()) { + TF_WARN("RPR environment variable is not set"); + return m_registeredNodes; + } + + auto rprMaterialsPath = TfAbsPath(TfNormPath(RPR + "/materials")); + + auto materialFiles = TfGlob(TfNormPath(rprMaterialsPath + "/*/*.mtlx"), ARCH_GLOB_DEFAULT | ARCH_GLOB_NOSORT); + if (materialFiles.empty()) { + TF_WARN("No materials found"); + } + + for (auto& file : materialFiles) { + // UI Folder corresponds to subsections on UI + // e.g. $RPR/Patterns/material.mtlx corresponds to Pattern UI folder + auto uiFolder = file.substr(rprMaterialsPath.size() + 1); + uiFolder = TfNormPath(TfGetPathName(uiFolder)); + if (uiFolder == ".") { + uiFolder = std::string(); + } + + try { + auto mtlxDoc = MaterialX::createDocument(); + MaterialX::readFromXmlFile(mtlxDoc, file); + + auto nodeDefs = mtlxDoc->getNodeDefs(); + if (nodeDefs.size() == 0) { + TF_WARN("\"%s\" file has no node definitions", file.c_str()); + } else { + for (auto& nodeDef : nodeDefs) { + auto shaderInfo = std::make_unique(mtlxDoc, nodeDef, uiFolder); + if (auto factory = shaderInfo->GetFactory()) { + Register(TfToken(shaderInfo->GetName()), factory, shaderInfo.get()); + m_mtlxInfos.push_back(std::move(shaderInfo)); + } + } + } + } catch (MaterialX::Exception& e) { + TF_RUNTIME_ERROR("Error on parsing of \"%s\": materialX error - %s", file.c_str(), e.what()); + } + } + } + + return m_registeredNodes; +} + +void RprUsdMaterialRegistry::CommitResources( + RprUsdImageCache* imageCache) { + if (m_textureCommits.empty()) { + return; + } + + using CommitUniqueTextureIndices = std::vector; + auto uniqueTextureIndicesPerCommit = std::make_unique(m_textureCommits.size()); + + struct UniqueTextureInfo { + std::string path; + uint32_t udimTileId; + + GlfUVTextureDataRefPtr data; + + UniqueTextureInfo(std::string const& path, uint32_t udimTileId) + : path(path), udimTileId(udimTileId), data(nullptr) {} + }; + std::vector uniqueTextures; + std::map uniqueTexturesMapping; + auto getUniqueTextureIndex = [&uniqueTexturesMapping, &uniqueTextures](std::string const& path, uint32_t udimTileId = 0) { + auto status = uniqueTexturesMapping.emplace(path, uniqueTexturesMapping.size()); + if (status.second) { + uniqueTextures.emplace_back(path, udimTileId); + } + return status.first->second; + }; + + // Iterate over all texture commits and collect unique textures including UDIM tiles + // + std::string formatString; + for (size_t i = 0; i < m_textureCommits.size(); ++i) { + auto& commit = m_textureCommits[i]; + auto& commitTexIndices = uniqueTextureIndicesPerCommit[i]; + + if (RprUsdGetUDIMFormatString(commit.filepath, &formatString)) { + constexpr uint32_t kStartTile = 1001; + constexpr uint32_t kEndTile = 1100; + + for (uint32_t tileId = kStartTile; tileId <= kEndTile; ++tileId) { + auto tilePath = TfStringPrintf(formatString.c_str(), tileId); + if (ArchFileAccess(tilePath.c_str(), F_OK) == 0) { + commitTexIndices.push_back(getUniqueTextureIndex(tilePath, tileId)); + } + } + } else { + commitTexIndices.push_back(getUniqueTextureIndex(commit.filepath)); + } + } + + // Read all textures from disk from multi threads + // + WorkParallelForN(uniqueTextures.size(), + [&uniqueTextures](size_t begin, size_t end) { + for (size_t i = begin; i < end; ++i) { + auto textureData = GlfUVTextureData::New(uniqueTextures[i].path, INT_MAX, 0, 0, 0, 0); + if (textureData && textureData->Read(0, false)) { + uniqueTextures[i].data = textureData; + } + } + } + ); + + // Create rpr::Image for each previously read unique texture + // XXX(RPR): so as RPR API is single-threaded we cannot parallelize this + // + for (size_t i = 0; i < m_textureCommits.size(); ++i) { + auto& commitTexIndices = uniqueTextureIndicesPerCommit[i]; + if (commitTexIndices.empty()) continue; + + std::vector tiles; + tiles.reserve(commitTexIndices.size()); + for (auto uniqueTextureIdx : commitTexIndices) { + auto& texture = uniqueTextures[uniqueTextureIdx]; + if (!texture.data) continue; + + tiles.emplace_back(texture.udimTileId, texture.data.operator->()); + } + + auto& commit = m_textureCommits[i]; + auto coreImage = imageCache->GetImage(commit.filepath, commit.forceLinearSpace, commit.wrapType, tiles); + commit.setTextureCallback(coreImage); + } + + m_textureCommits.clear(); +} + +namespace { + +void DumpMaterialNetwork(HdMaterialNetworkMap const& networkMap) { + SdfPath const* primitivePath = nullptr; + if (!networkMap.terminals.empty()) { + primitivePath = &networkMap.terminals[0]; + } else if (!networkMap.map.empty()) { + auto& network = networkMap.map.begin()->second; + if (!network.nodes.empty()) { + primitivePath = &network.nodes[0].path; + } + } + + bool closeFile = false; + FILE* file = stdout; + if (primitivePath) { + auto materialPath = primitivePath->GetParentPath(); + std::string filepath = materialPath.GetString(); + for (size_t i = 0; i < filepath.size(); ++i) { + if (std::strchr("/\\", filepath[i])) { + filepath[i] = '_'; + } + } + file = fopen(filepath.c_str(), "w"); + if (!file) { + file = stdout; + } else { + closeFile = true; + } + } + + fprintf(file, "terminals: [\n"); + for (auto& terminal : networkMap.terminals) { + fprintf(file, " \"%s\",\n", terminal.GetText()); + } + fprintf(file, "]\n"); + + fprintf(file, "map: {\n"); + for (auto& entry : networkMap.map) { + fprintf(file, " \"%s\": {\n", entry.first.GetText()); + + auto& network = entry.second; + fprintf(file, " relationships: [\n"); + for (auto& rel : network.relationships) { + SdfPath inputId; + TfToken inputName; + SdfPath outputId; + TfToken outputName; + fprintf(file, " {\n"); + fprintf(file, " inputId=%s\n", rel.inputId.GetText()); + fprintf(file, " inputName=%s\n", rel.inputName.GetText()); + fprintf(file, " outputId=%s\n", rel.outputId.GetText()); + fprintf(file, " outputName=%s\n", rel.outputName.GetText()); + fprintf(file, " },\n"); + } + fprintf(file, " ],\n"); + + fprintf(file, " primvars: [\n"); + for (auto& primvar : network.primvars) { + fprintf(file, " %s,\n", primvar.GetText()); + } + fprintf(file, " ]\n"); + + fprintf(file, " nodes: [\n"); + for (auto& node : network.nodes) { + fprintf(file, " {\n"); + fprintf(file, " path=%s\n", node.path.GetText()); + fprintf(file, " identifier=%s\n", node.identifier.GetText()); + fprintf(file, " parameters: {\n"); + for (auto& param : node.parameters) { + fprintf(file, " {%s: %s", param.first.GetText(), param.second.GetTypeName().c_str()); + if (param.second.IsHolding()) { + fprintf(file, "(\"%s\")", param.second.UncheckedGet().GetText()); + } else if (param.second.IsHolding()) { + fprintf(file, "(\"%s\")", param.second.UncheckedGet().GetResolvedPath().c_str()); + } else if (param.second.IsHolding()) { + auto& v = param.second.UncheckedGet(); + fprintf(file, "(%g, %g, %g, %g)", v[0], v[1], v[2], v[3]); + } + fprintf(file, "},\n"); + } + fprintf(file, " }\n"); + fprintf(file, " },\n"); + } + fprintf(file, " ]\n"); + + fprintf(file, " }\n"); + } + fprintf(file, "}\n"); + + if (closeFile) { + fclose(file); + } +} + +// Structures are taken from hdSt/materialNetwork.cpp + +struct RprUsd_MaterialNetwork { + struct Connection { + SdfPath upstreamNode; + TfToken upstreamOutputName; + }; + + struct Node { + TfToken nodeTypeId; + std::map parameters; + std::map inputConnections; + }; + + std::map nodes; + std::map terminals; +}; + +void ConvertLegacyHdMaterialNetwork( + HdMaterialNetworkMap const& hdNetworkMap, + RprUsd_MaterialNetwork *result) { + + for (auto& entry : hdNetworkMap.map) { + auto& terminalName = entry.first; + auto& hdNetwork = entry.second; + + // Transfer over individual nodes + for (auto& node : hdNetwork.nodes) { + // Check if this node is a terminal + auto termIt = std::find(hdNetworkMap.terminals.begin(), hdNetworkMap.terminals.end(), node.path); + if (termIt != hdNetworkMap.terminals.end()) { + result->terminals.emplace( + terminalName, + RprUsd_MaterialNetwork::Connection{node.path, terminalName}); + } + + if (result->nodes.count(node.path)) { + continue; + } + + auto& newNode = result->nodes[node.path]; + newNode.nodeTypeId = node.identifier; + newNode.parameters = node.parameters; + } + + // Transfer relationships to inputConnections on receiving/downstream nodes. + for (HdMaterialRelationship const& rel : hdNetwork.relationships) { + // outputId (in hdMaterial terms) is the input of the receiving node + auto const& iter = result->nodes.find(rel.outputId); + // skip connection if the destination node doesn't exist + if (iter == result->nodes.end()) { + continue; + } + auto &connection = iter->second.inputConnections[rel.outputName]; + connection.upstreamNode = rel.inputId; + connection.upstreamOutputName = rel.inputName; + } + + // Currently unused + // Transfer primvars: + //result->primvars.insert(hdNetwork.primvars.begin(), hdNetwork.primvars.end()); + } +} + +} // namespace anonymous + +RprUsdMaterial* RprUsdMaterialRegistry::CreateMaterial( + HdSceneDelegate* sceneDelegate, + HdMaterialNetworkMap const& legacyNetworkMap, + rpr::Context* rprContext, + RprUsdImageCache* imageCache) const { + + if (TfDebug::IsEnabled(RPR_USD_DEBUG_DUMP_MATERIALS)) { + DumpMaterialNetwork(legacyNetworkMap); + } + + // HdMaterialNetworkMap is deprecated, + // convert HdMaterialNetwork over to the new description + // so we do not have to redo all the code when new description comes in Hd + RprUsd_MaterialNetwork network; + ConvertLegacyHdMaterialNetwork(legacyNetworkMap, &network); + + RprUsd_MaterialBuilderContext context = {}; + context.rprContext = rprContext; + context.imageCache = imageCache; + + // The simple wrapper to retain material nodes that are used to build terminal outputs + struct RprUsdGraphBasedMaterial : public RprUsdMaterial { + std::map> materialNodes; + + bool Finalize(RprUsd_MaterialBuilderContext& context, + VtValue const& surfaceOutput, + VtValue const& displacementOutput, + VtValue const& volumeOutput) { + + auto getTerminalRprNode = [](VtValue const& terminalOutput) -> rpr::MaterialNode* { + if (!terminalOutput.IsEmpty()) { + if (terminalOutput.IsHolding>()) { + return terminalOutput.UncheckedGet>().get(); + } else { + TF_RUNTIME_ERROR("Terminal node should output material node"); + } + } + + return nullptr; + }; + + m_volumeNode = getTerminalRprNode(volumeOutput); + m_surfaceNode = getTerminalRprNode(surfaceOutput); + m_displacementNode = getTerminalRprNode(displacementOutput); + + m_isShadowCatcher = context.isShadowCatcher; + m_isReflectionCatcher = context.isReflectionCatcher; + m_uvPrimvarName = std::move(context.uvPrimvarName); + m_displacementScale = std::move(context.displacementScale); + + return m_volumeNode || m_surfaceNode || m_displacementNode; + } + }; + + auto out = std::make_unique(); + + // Houdini's principled shader node does not have a valid nodeTypeId + // So we find both surface and displacement nodes and then create one material node + bool isSurfaceNode; + SdfPath const* houdiniPrincipledShaderNodePath = nullptr; + std::map const* houdiniPrincipledShaderSurfaceParams = nullptr; + std::map const* houdiniPrincipledShaderDispParams = nullptr; + + // Create RprUsd_MaterialNode for each Hydra node + auto& materialNodes = out->materialNodes; + for (auto& entry : network.nodes) { + auto& nodePath = entry.first; + auto& node = entry.second; + + try { + // Check if we have registered node that match nodeTypeId + auto nodeLookupIt = m_registeredNodesLookup.find(node.nodeTypeId); + if (nodeLookupIt != m_registeredNodesLookup.end()) { + if (auto materialNode = m_registeredNodes[nodeLookupIt->second].factory(&context, node.parameters)) { + materialNodes[nodePath].reset(materialNode); + } + } else if (IsHoudiniPrincipledShaderHydraNode(sceneDelegate, nodePath, &isSurfaceNode)) { + if (isSurfaceNode) { + houdiniPrincipledShaderNodePath = &nodePath; + houdiniPrincipledShaderSurfaceParams = &node.parameters; + } else { + houdiniPrincipledShaderDispParams = &node.parameters; + } + } else { + TF_WARN("Unknown node type: id=%s", node.nodeTypeId.GetText()); + } + } catch (RprUsd_NodeError& e) { + TF_RUNTIME_ERROR("Failed to create %s(%s): %s", nodePath.GetText(), node.nodeTypeId.GetText(), e.what()); + } catch (RprUsd_NodeEmpty&) { + TF_WARN("Empty node: %s", nodePath.GetText()); + } + } + + if (houdiniPrincipledShaderNodePath) { + auto materialNode = new RprUsd_HoudiniPrincipledNode(&context, *houdiniPrincipledShaderSurfaceParams, houdiniPrincipledShaderDispParams); + materialNodes[*houdiniPrincipledShaderNodePath].reset(materialNode); + } + + std::set visited; + std::function getNodeOutput = + [&materialNodes, &network, &getNodeOutput, &visited] + (RprUsd_MaterialNetwork::Connection const& nodeConnection) -> VtValue { + auto& nodePath = nodeConnection.upstreamNode; + + auto nodeIt = network.nodes.find(nodePath); + if (nodeIt == network.nodes.end()) { + TF_CODING_ERROR("Invalid connection: %s", nodePath.GetText()); + return VtValue(); + } + auto& node = nodeIt->second; + + auto materialNodeIt = materialNodes.find(nodePath); + if (materialNodeIt != materialNodes.end()) { + auto materialNode = materialNodeIt->second.get(); + + // Set node inputs only once + if (visited.count(nodePath) == 0) { + visited.insert(nodePath); + + for (auto& inputConnection : node.inputConnections) { + auto& connection = inputConnection.second; + + auto nodeOutput = getNodeOutput(connection); + if (!nodeOutput.IsEmpty()) { + auto& inputId = inputConnection.first; + materialNode->SetInput(inputId, nodeOutput); + } + } + } + + return materialNode->GetOutput(nodeConnection.upstreamOutputName); + } else { + // Rpr node can be missing in two cases: + // a) we failed to create the node + // b) this node has no effect on the input + // In such a case, we simply interpret the output of the + // first connection as the output of the current node + if (node.inputConnections.empty()) { + return VtValue(); + } else { + return getNodeOutput(node.inputConnections.begin()->second); + } + } + }; + + auto getTerminalOutput = [&network, &getNodeOutput](TfToken const& terminalName) { + auto terminalIt = network.terminals.find(terminalName); + if (terminalIt == network.terminals.end()) { + return VtValue(); + } + + return getNodeOutput(terminalIt->second); + }; + + auto volumeOutput = getTerminalOutput(HdMaterialTerminalTokens->volume); + auto surfaceOutput = getTerminalOutput(HdMaterialTerminalTokens->surface); + auto displacementOutput = getTerminalOutput(HdMaterialTerminalTokens->displacement); + + return out->Finalize(context, surfaceOutput, displacementOutput, volumeOutput) ? out.release() : nullptr; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/rprUsd/materialRegistry.h b/pxr/imaging/rprUsd/materialRegistry.h new file mode 100644 index 000000000..8ab035431 --- /dev/null +++ b/pxr/imaging/rprUsd/materialRegistry.h @@ -0,0 +1,210 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#ifndef RPRUSD_MATERIAL_REGISTRY_H +#define RPRUSD_MATERIAL_REGISTRY_H + +#include "pxr/imaging/rprUsd/api.h" +#include "pxr/imaging/hd/material.h" +#include "pxr/base/arch/demangle.h" +#include "pxr/base/tf/singleton.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class RprUsdImageCache; +class RprUsdCoreImage; +class RprUsdMaterial; +class RprUsdMaterialNodeInfo; + +class RprUsd_MaterialNode; +class RprUsd_MtlxNodeInfo; +struct RprUsd_MaterialBuilderContext; + +using RprUsdMaterialNodeFactoryFnc = std::function< + RprUsd_MaterialNode*( + RprUsd_MaterialBuilderContext* context, + std::map const& parameters)>; + +struct RprUsdMaterialNodeDesc { + RprUsdMaterialNodeFactoryFnc factory; + RprUsdMaterialNodeInfo const* info; +}; + +/// \class RprUsdMaterialRegistry +/// +/// Interface for the material resolution system. An RPR materials library is +/// responsible for resolving material node definitions and may create materials +/// from HdMaterialNetworkMap that are ready for use in hdRpr. +/// +class RprUsdMaterialRegistry { +public: + RPRUSD_API + static RprUsdMaterialRegistry& GetInstance() { + return TfSingleton::GetInstance(); + } + + RPRUSD_API + RprUsdMaterial* CreateMaterial( + HdSceneDelegate* sceneDelegate, + HdMaterialNetworkMap const& networkMap, + rpr::Context* rprContext, + RprUsdImageCache* imageCache) const; + + RPRUSD_API + TfToken const& GetMaterialNetworkSelector(); + + RPRUSD_API + std::vector const& GetRegisteredNodes(); + + /// Register implementation of the Node with \p id + RPRUSD_API + void Register( + TfToken const& id, + RprUsdMaterialNodeFactoryFnc factory, + RprUsdMaterialNodeInfo const* info = nullptr); + + struct TextureCommit { + std::string filepath; + bool forceLinearSpace; + rpr::ImageWrapType wrapType; + + std::function const&)> setTextureCallback; + }; + + RPRUSD_API + void CommitTexture(TextureCommit commit); + + RPRUSD_API + void CommitResources(RprUsdImageCache* imageCache); + +private: + friend class TfSingleton; + RprUsdMaterialRegistry(); + +private: + /// Material network selector for the current session, controlled via env variable + TfToken m_materialNetworkSelector; + + std::vector m_registeredNodes; + std::map m_registeredNodesLookup; + + std::vector> m_mtlxInfos; + bool m_mtlxDefsDirty = true; + + std::vector m_textureCommits; +}; + +class RprUsdMaterialNodeInput; +class RprUsdMaterialNodeElement; + +/// \class RprUsdMaterialNodeInfo +/// +/// Describes resolved node, its name, inputs, outputs, etc +/// +class RprUsdMaterialNodeInfo { +public: + virtual ~RprUsdMaterialNodeInfo() = default; + + virtual const char* GetName() const = 0; + + virtual size_t GetNumInputs() const = 0; + virtual RprUsdMaterialNodeInput const* GetInput(size_t idx) const = 0; + + virtual size_t GetNumOutputs() const = 0; + virtual RprUsdMaterialNodeElement const* GetOutput(size_t idx) const = 0; + + virtual const char* GetUIName() const = 0; + virtual const char* GetUIFolder() const { return nullptr; }; +}; + +class RprUsdMaterialNodeElement { +public: + virtual ~RprUsdMaterialNodeElement() = default; + + virtual const char* GetName() const = 0; + virtual const char* GetUIName() const = 0; + virtual const char* GetDocString() const = 0; + + enum Type { + kInvalid, + kFloat, + kAngle, + kVector2, + kVector3, + kColor3, + kNormal, + kBoolean, + kInteger, + kToken, + kVolumeShader, + kSurfaceShader, + kDisplacementShader, + }; + Type GetType() const { return m_type; } + +protected: + RprUsdMaterialNodeElement(Type type) : m_type(type) {} + +protected: + Type m_type; +}; + +class RprUsdMaterialNodeInput : public RprUsdMaterialNodeElement { +public: + ~RprUsdMaterialNodeInput() override = default; + + virtual const char* GetUIMin() const = 0; + virtual const char* GetUISoftMin() const = 0; + virtual const char* GetUIMax() const = 0; + virtual const char* GetUISoftMax() const = 0; + virtual const char* GetUIFolder() const = 0; + virtual const char* GetValueString() const = 0; + virtual std::vector const& GetTokenValues() const = 0; + +protected: + RprUsdMaterialNodeInput(Type type) : RprUsdMaterialNodeElement(type) {} +}; + +inline TfToken const& RprUsdMaterialRegistry::GetMaterialNetworkSelector() { + return m_materialNetworkSelector; +} + +inline void RprUsdMaterialRegistry::Register( + TfToken const& id, + RprUsdMaterialNodeFactoryFnc factory, + RprUsdMaterialNodeInfo const* info) { + RprUsdMaterialNodeDesc desc = {}; + desc.factory = std::move(factory); + desc.info = info; + + auto status = m_registeredNodesLookup.emplace(id, m_registeredNodes.size()); + if (!status.second) { + TF_CODING_ERROR("Failed to register %s: already registered", id.GetText()); + } else { + m_registeredNodes.push_back(std::move(desc)); + } +} + +inline void RprUsdMaterialRegistry::CommitTexture(TextureCommit commit) { + m_textureCommits.push_back(std::move(commit)); +} + +inline const char* GetCStr(std::string const& str) { + return !str.empty() ? str.c_str() : nullptr; +} + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // RPRUSD_MATERIAL_REGISTRY_H diff --git a/pxr/imaging/rprUsd/util.cpp b/pxr/imaging/rprUsd/util.cpp new file mode 100644 index 000000000..ec5d55c94 --- /dev/null +++ b/pxr/imaging/rprUsd/util.cpp @@ -0,0 +1,41 @@ +/************************************************************************ +Copyright 2020 Advanced Micro Devices, Inc +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +************************************************************************/ + +#include "util.h" + +#include "pxr/base/tf/staticTokens.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +TF_DEFINE_PRIVATE_TOKENS( + RprUsdUDIMTags, + ((arnoldTag, "")) + ((sidefxTag, "%(UDIM)d")) +); + +bool RprUsdGetUDIMFormatString(std::string const& filepath, std::string* out_formatString) { + for (auto& udimTag : RprUsdUDIMTags->allTokens) { + auto idx = filepath.rfind(udimTag.GetString()); + if (idx != std::string::npos) { + *out_formatString = filepath; + out_formatString->replace(idx, udimTag.size(), "%i"); + return true; + } + } + + return false; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/imaging/plugin/hdRpr/rpr/contextHelpers.h b/pxr/imaging/rprUsd/util.h similarity index 73% rename from pxr/imaging/plugin/hdRpr/rpr/contextHelpers.h rename to pxr/imaging/rprUsd/util.h index d9daee1a4..9b5e6a0ae 100644 --- a/pxr/imaging/plugin/hdRpr/rpr/contextHelpers.h +++ b/pxr/imaging/rprUsd/util.h @@ -11,17 +11,17 @@ See the License for the specific language governing permissions and limitations under the License. ************************************************************************/ -#ifndef HDRPR_CORE_CONTEXT_HELPERS_H -#define HDRPR_CORE_CONTEXT_HELPERS_H +#ifndef RPRUSD_UTIL_H +#define RPRUSD_UTIL_H -#include "contextMetadata.h" +#include "pxr/pxr.h" -namespace rpr { +#include -class Context; +PXR_NAMESPACE_OPEN_SCOPE -Context* CreateContext(char const* cachePath, ContextMetadata* metadata); +bool RprUsdGetUDIMFormatString(std::string const& filepath, std::string* out_formatString); -} // namespace rpr +PXR_NAMESPACE_CLOSE_SCOPE -#endif // HDRPR_CORE_CONTEXT_HELPERS_H +#endif // RPRUSD_UTIL_H