├── .clang-format ├── .github ├── issue_template.md └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── Config.cmake.in ├── Defaults.cmake ├── Export.cmake ├── Options.cmake ├── Packages.cmake ├── USDPluginTools.cmake └── packages │ └── FindTBB.cmake ├── images └── triangle_in_viewport.png └── src ├── CMakeLists.txt ├── __init__.py ├── hdTri ├── CMakeLists.txt ├── debugCodes.cpp ├── debugCodes.h ├── plugInfo.json ├── renderBuffer.cpp ├── renderBuffer.h ├── renderDelegate.cpp ├── renderDelegate.h ├── renderParam.cpp ├── renderParam.h ├── renderPass.cpp ├── renderPass.h ├── renderer.cpp ├── renderer.h ├── rendererPlugin.cpp └── rendererPlugin.h ├── plugInfo.json ├── usdTri ├── CMakeLists.txt ├── __init__.py ├── api.h ├── generatedSchema.usda ├── module.cpp ├── moduleDeps.cpp ├── plugInfo.json ├── scenes │ ├── expandingTriangle.usda │ └── triangle.usda ├── schema.usda ├── tests │ ├── CMakeLists.txt │ ├── testTriangle.cpp │ └── testTriangle.py ├── tokens.cpp ├── tokens.h ├── triangle.cpp ├── triangle.h ├── triangleCounter.cpp ├── wrapTokens.cpp └── wrapTriangle.cpp ├── usdTriFileFormat ├── CMakeLists.txt ├── fileFormat.cpp ├── fileFormat.h ├── plugInfo.json ├── scenes │ ├── empty.triangle │ └── triangle.usda └── tests │ ├── CMakeLists.txt │ └── testFileFormat.py ├── usdTriImaging ├── CMakeLists.txt ├── debugCodes.cpp ├── debugCodes.h ├── plugInfo.json ├── triangleAdapter.cpp └── triangleAdapter.h ├── usdTriImagingHd2 ├── CMakeLists.txt ├── dataSourceTri.cpp ├── dataSourceTri.h ├── debugCodes.cpp ├── debugCodes.h ├── plugInfo.json ├── triangleAdapter.cpp └── triangleAdapter.h └── usdviewTri ├── CMakeLists.txt ├── __init__.py └── plugInfo.json /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Mozilla 2 | AccessModifierOffset: -4 3 | IndentWidth: 4 4 | ContinuationIndentWidth: 4 5 | IndentPPDirectives: AfterHash 6 | SortIncludes: false 7 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Description of Issue 2 | 3 | ### Steps to Reproduce 4 | 1. 5 | 6 | ### System Information (OS, Hardware) 7 | 8 | ### Build Flags 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | # Run the jobs for pushes and pull requests targetting main branch. 4 | on: 5 | push: 6 | branches: 7 | - main 8 | paths-ignore: 9 | - '**.md' 10 | - 'LICENSE' 11 | - 'images/**' 12 | pull_request: 13 | branches: 14 | - main 15 | paths-ignore: 16 | - '**.md' 17 | - 'LICENSE' 18 | - 'images/**' 19 | 20 | jobs: 21 | 22 | # A build job matrix based on pre-built USD binaries provided by NVIDIA. 23 | # nvidia-usd-binaries-linux-build: 24 | # strategy: 25 | # matrix: 26 | # usdVersion: 27 | # - 21.05 28 | # include: 29 | # - usdVersion: 21.05 30 | # usdVersionUrl: 21-05 31 | # pythonVersion: 3.6 32 | # buildType: Release 33 | # buildTests: 'ON' 34 | # runs-on: ubuntu-18.04 35 | # name: 'Ubuntu 18.04 NVIDIA Pre-built Binaries 36 | # ' 40 | # steps: 41 | # - name: Install dependencies (Linux) 42 | # run: sudo apt-get install cmake python${{ matrix.pythonVersion }} python${{ matrix.pythonVersion }}-dev 43 | # - uses: actions/checkout@v2 44 | # - name: Download and extract pre-built USD binaries 45 | # run: | 46 | # curl -L -o /tmp/usd-${{ matrix.usdVersion }}.7z https://developer.nvidia.com/usd-${{ matrix.usdVersionUrl }}-binary-linux-python-${{ matrix.pythonVersion }} 47 | # mkdir -p /tmp/usd-${{ matrix.usdVersion }} 48 | # 7z x /tmp/usd-${{ matrix.usdVersion }}.7z -o/tmp/usd-${{ matrix.usdVersion }} 49 | # - name: Create build directories 50 | # run: | 51 | # mkdir _build 52 | # mkdir _install 53 | # - name: Configure 54 | # run: | 55 | # cmake -DUSD_ROOT="/tmp/usd-${{ matrix.usdVersion }}/" \ 56 | # -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} \ 57 | # -DBUILD_TESTING=${{ matrix.buildTests }} \ 58 | # -DCMAKE_CXX_FLAGS="-D_GLIBCXX_USE_CXX11_ABI=0" \ 59 | # -DCMAKE_INSTALL_PREFIX=../_install \ 60 | # .. 61 | # working-directory: _build 62 | # - name: Build 63 | # run: | 64 | # cmake --build . \ 65 | # --verbose \ 66 | # --target install \ 67 | # --config ${{ matrix.buildType }} 68 | # working-directory: _build 69 | # - name: Test 70 | # run: ctest -VV --output-on-failure -C ${{ matrix.buildType }} 71 | # working-directory: _build 72 | 73 | 74 | # A build job matrix based on pre-built USD binaries provided by NVIDIA on Windows. 75 | # nvidia-usd-binaries-windows-build: 76 | # strategy: 77 | # matrix: 78 | # usdVersion: 79 | # - 21.05 80 | # include: 81 | # - usdVersion: 21.05 82 | # usdVersionUrl: 21-05 83 | # pythonVersion: 3.6 84 | # buildType: Release 85 | # buildTests: ON 86 | # runs-on: windows-2016 87 | # name: 'Windows 2016 NVIDIA Pre-built Binaries 88 | # ' 92 | # steps: 93 | # - uses: actions/checkout@v2 94 | # - name: Set up Python ${{ matrix.pythonVersion }} 95 | # uses: actions/setup-python@v2 96 | # with: 97 | # python-version: ${{ matrix.pythonVersion }} 98 | # - name: Download and extract pre-built USD binaries 99 | # run: | 100 | # Invoke-WebRequest https://developer.nvidia.com/usd-${{ matrix.usdVersionUrl }}-binary-windows-python-${{ matrix.pythonVersion }} -OutFile $env:TEMP/usd-${{ matrix.usdVersion }}.zip 101 | # mkdir -Force $env:TEMP/usd-${{ matrix.usdVersion }} 102 | # 7z x $env:TEMP/usd-${{ matrix.usdVersion }}.zip $("-o" + "$env:TEMP" + "\usd-${{ matrix.usdVersion }}") -y 103 | # - name: Create build directories 104 | # run: | 105 | # mkdir -Force _build 106 | # mkdir -Force _install 107 | # - name: Configure 108 | # run: | 109 | # cmake -DUSD_ROOT="$env:TEMP/usd-${{ matrix.usdVersion }}" ` 110 | # -DCMAKE_BUILD_TYPE=${{ matrix.buildType }} ` 111 | # -DBUILD_TESTING=${{ matrix.buildTests }} ` 112 | # -DCMAKE_INSTALL_PREFIX="../_install" ` 113 | # -G "Visual Studio 15 2017 Win64" ` 114 | # .. 115 | # working-directory: "_build" 116 | # - name: Build 117 | # run: | 118 | # cmake --build . ` 119 | # --verbose ` 120 | # --config ${{ matrix.buildType }} ` 121 | # --target ALL_BUILD 122 | # working-directory: "_build" 123 | # - name: Run Tests 124 | # run: | 125 | # ctest --extra-verbose ` 126 | # --output-on-failure ` 127 | # -C ${{ matrix.buildType }} 128 | # working-directory: "_build" 129 | # - name: Install 130 | # run: | 131 | # cmake --build . ` 132 | # --verbose ` 133 | # --config ${{ matrix.buildType }} ` 134 | # --target INSTALL 135 | # working-directory: "_build" 136 | 137 | # Run automated code formatting checks. 138 | code-formatting-check: 139 | runs-on: ubuntu-22.04 140 | steps: 141 | - name: Install dependencies (Linux) 142 | run: | 143 | sudo apt-get install clang-format-13 144 | - uses: actions/checkout@v2 145 | - name: Run clang-format on source code 146 | run: | 147 | find . \ 148 | -name ".git" -prune -o \ 149 | -name "*.cpp" -type f -exec clang-format -i --verbose {} + -o \ 150 | -name "*.h" -type f -exec clang-format -i --verbose {} + 151 | - name: Check for code differences 152 | run: | 153 | set +e 154 | git diff --color 155 | git diff-index --quiet HEAD --; EXIT_CODE=$? 156 | set -e 157 | if [ $EXIT_CODE -ne 0 ]; then echo "C++ code formatting check failed. Please run clang-format on *.h and *.cpp, then push your changes."; fi 158 | exit $EXIT_CODE 159 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # A common directory to host intermediate build files. 2 | build/ 3 | 4 | # VIM swap files. 5 | *.sw[pon] 6 | 7 | # Backup files. 8 | .bak 9 | 10 | # C++ object files. 11 | *.o 12 | 13 | # Python cache files. 14 | *.pyc 15 | 16 | # Local convenience scripts. 17 | build.sh 18 | runtime.sh 19 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 3.13 for target_link_directories. 2 | cmake_minimum_required(VERSION 3.13) 3 | 4 | # Define project. 5 | project( 6 | USDPluginExamples 7 | VERSION 0.0.0 8 | DESCRIPTION "A collection of example plugins for Pixar's USD (Universal Scene Description)." 9 | LANGUAGES CXX 10 | ) 11 | 12 | # Discover cmake modules. 13 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} 14 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake/ 15 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake/packages 16 | ) 17 | 18 | # Exposes build options (with default values) for this project. 19 | include(Options) 20 | 21 | # Set project defaults. 22 | include(Defaults) 23 | 24 | # Import the package dependencies (USD, TBB, ...). 25 | include(Packages) 26 | 27 | # Include USD plugin building CMake utilities. 28 | include(USDPluginTools) 29 | 30 | # Recurse into source tree. 31 | add_subdirectory(src) 32 | 33 | # Export targets and install package files. 34 | # This must come after source tree recursion as exporting targets 35 | # requires the targets to be defined in the first place! 36 | include(Export) 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # USDPluginExamples 4 | 5 | A collection of example plugins for [Pixar's USD](https://github.com/PixarAnimationStudios/USD) (Universal Scene Description). 6 | 7 | This project also aims to provide a set of CMake utilities for building USD plugins outside of the USD project source tree. The utilities are heavily based on the build logic prescribed by the USD project itself. 8 | 9 | We hope the minimal examples and surrounding build infrastructure can be useful to USD community developers interested in building and deploying their own plugin(s). 10 | 11 | Huge thanks to Pixar's USD team for providing a highly extensible platform! 12 | 13 | ## Table of Contents 14 | 15 | - [USD Plugins](#usd-plugins) 16 | - [Dependencies](#dependencies) 17 | - [Building](#building) 18 | - [Running](#running) 19 | - [CMake Utilities](#cmake-utilities) 20 | 21 | ## USD Plugins 22 | 23 | **USDPluginExamples** provides the following USD plugins: 24 | - [usdTri](./src/usdTri): A schema library defining a **Triangle** prim type. 25 | - [usdTriImaging](./src/usdTriImaging): A *Hydra 1 only* prim adapter which images the **Triangle** prim type. [*] 26 | - [usdTriImagingHd2](./src/usdTriImagingHd2): A *Hydra 2 only* prim adapter which images the **Triangle** prim type. [*] 27 | - [usdTriFileFormat](./src/usdTriFileFormat): A file format plugin which authors a triangular mesh for a `.triangle` payload. 28 | - [hdTri](./src/hdTri): A hydra renderer plugin which images a triangle (in the most direct sense). 29 | - [usdviewTri](./src/usdviewTri): An usdview plugin providing a menu command to define child Triangle prim(s) under selected paths. 30 | 31 | [*] We deliberatly split the Hydra 1 & 2 Triangle Prim Adapters into two plugins/sources to outline the differences 32 | 33 | There are many other USD plugins available online - check out [USD Working Group: Projects & Resources](https://wiki.aswf.io/display/WGUSD/USD+Projects+and+Resources) for more! 34 | 35 | ## Dependencies 36 | 37 | The following dependencies are required: 38 | - C++ compiler 39 | - [CMake](https://cmake.org/documentation/) (Tested with CMake 3.29.2) 40 | - [USD](https://github.com/pixaranimationstudios/USD) (24.05) 41 | - [Boost](https://boost.org) and [Intel TBB](https://www.threadingbuildingblocks.org/) (USD dependencies) 42 | 43 | [Python](https://www.python.org/) may also be required, depending on python support in the USD installation. 44 | 45 | ## Building 46 | 47 | Example snippet for building the plugins on Linux (and potentially MacOS): 48 | ```bash 49 | mkdir build 50 | cd build 51 | cmake \ 52 | -DUSD_ROOT="/apps/usd/" \ 53 | -DCMAKE_INSTALL_PREFIX="/apps/USDPluginExamples/" \ 54 | .. 55 | cmake --build . -- VERBOSE=1 -j8 all test install 56 | ``` 57 | 58 | Example snippet for building a Visual Studio project on Windows (x64 Native Tools Command Prompt with Administrator privileges): 59 | ```cmd 60 | mkdir build 61 | cd build 62 | cmake ^ 63 | -G "Visual Studio 15 2017 Win64" ^ 64 | -DUSD_ROOT="D:\install\usd" ^ 65 | -DCMAKE_INSTALL_PREFIX="D:\install\USDPluginExamples\" ^ 66 | .. 67 | 68 | cmake --build . --config Release -j 8 --target ALL_BUILD RUN_TESTS INSTALL 69 | ``` 70 | 71 | 72 | CMake options for configuring this project: 73 | 74 | | CMake Variable name | Description | Default | 75 | | ----------------------- | ---------------------------------------------------------------------- | ------- | 76 | | `USD_ROOT` | Root directory of USD installation | | 77 | | `TBB_ROOT` | Root directory of Intel TBB installation | | 78 | | `BOOST_ROOT` | Root directory of Boost installation | | 79 | | `ENABLE_PYTHON_SUPPORT` | Enable python support. Must match python support of USD installation. | `ON` | 80 | | `BUILD_TESTING` | Enable automated testing. | `ON` | 81 | | `BUILD_HYDRA2` | Enable building Hydra2 plugins, will disable Hydra1 plugin building. | `OFF` | 82 | 83 | ## Running 84 | 85 | To register the plugin(s) as part of the USD runtime, the following environment variables will need 86 | to be defined: 87 | | Environment Variable | Value(s) | 88 | | --------------------- | ---------------------------------------------------------------------------------------- | 89 | | `PYTHONPATH` | `${USDPLUGINEXAMPLES_INSTALL_ROOT}/lib/python` | 90 | | `PXR_PLUGINPATH_NAME` | `${USDPLUGINEXAMPLES_INSTALL_ROOT}/lib/usd`
`${USDPLUGINEXAMPLES_INSTALL_ROOT}/plugin/usd` | 91 | 92 | Additionally, Windows requires: 93 | | Environment Variable | Value(s) | 94 | | --------------------- | ---------------------------------------------------------------------------------------- | 95 | | `PATH` | `${USDPLUGINEXAMPLES_INSTALL_ROOT}/lib` | 96 | 97 | Additionally, Linux requires: 98 | | Environment Variable | Value(s) | 99 | | --------------------- | ---------------------------------------------------------------------------------------- | 100 | | `LD_LIBRARY_PATH` | `${USDPLUGINEXAMPLES_INSTALL_ROOT}/lib` | 101 | 102 | Note: libraries and plugins are installed into different locations - thus PXR_PLUGINPATH_NAME specifies 103 | two separate values. 104 | 105 | To run the Hydra2 Prim Adapter with Storm/GL you have to enable the SceneIndex for UsdImagingGL 106 | | Environment Variable | Value(s) | 107 | | ---------------------------------------- | --------------------------------------------------------------------- | 108 | | `USDIMAGINGGL_ENGINE_ENABLE_SCENE_INDEX` | `1`````````````````` | 109 | 110 | 111 | Once the environment variables have been set-up, an example scene in this repo can be previewed with **usdview**: 112 | ``` 113 | usdview ./src/usdTri/scenes/triangle.usda 114 | ``` 115 | 116 | In the viewport, a triangle should be centered at origin: 117 | ![Triangle](./images/triangle_in_viewport.png) 118 | 119 | ## CMake Utilities 120 | 121 | Custom CMake functions are provided, for abstracting away USD plugin build intricacies: 122 | - `usd_library`: [Example usage](./src/usdTri/CMakeLists.txt) 123 | - `usd_plugin`: [Example usage](./src/hdTri/CMakeLists.txt) 124 | - `usd_executable`: [Example usage](./src/usdTri/CMakeLists.txt#L45) 125 | - `usd_test`: [Example usage](./src/usdTri/tests/CMakeLists.txt#L5) 126 | - `usd_python_library`: [Example usage](./src/usdviewTri/CMakeLists.txt) 127 | - `usd_python_test`: [Example usage](./src/usdTri/tests/CMakeLists.txt#L1) 128 | 129 | The interface of the above functions are largely based on those used throughout the [official USD project](https://github.com/PixarAnimationStudios/USD). 130 | 131 | **USDPluginExamples** can be used as a template ("Use this template" button near the top of the page). 132 | 133 | Another option to gain access to the cmake utilities is to copy/integrate the files under [cmake/](./cmake) into an existing project. 134 | -------------------------------------------------------------------------------- /cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | # @CMAKE_PROJECT_NAME@Config.cmake 2 | 3 | get_filename_component(@CMAKE_PROJECT_NAME@_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 4 | if(NOT TARGET @CMAKE_PROJECT_NAME@::usdTri) 5 | include("${@CMAKE_PROJECT_NAME@_CMAKE_DIR}/cmake/@CMAKE_PROJECT_NAME@Targets.cmake") 6 | endif() 7 | -------------------------------------------------------------------------------- /cmake/Defaults.cmake: -------------------------------------------------------------------------------- 1 | # Default build configurations for the USDPluginExamples project. 2 | 3 | # By default, build for release. 4 | if(NOT CMAKE_BUILD_TYPE) 5 | set(CMAKE_BUILD_TYPE "Release") 6 | endif() 7 | 8 | # Check if CTest should be enabled. 9 | if (BUILD_TESTING) 10 | enable_testing() 11 | 12 | # Be very verbose on test failure. 13 | list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") 14 | endif() 15 | 16 | if (MSVC) 17 | # From OpenUSD/cmake/defaults/msvcdefaults.cmake 18 | # 19 | # The /Zc:inline option strips out the "arch_ctor_" symbols used for 20 | # library initialization by ARCH_CONSTRUCTOR starting in Visual Studio 2019, 21 | # causing release builds to fail. Disable the option for this and later 22 | # versions. 23 | # 24 | # For more details, see: 25 | # https://developercommunity.visualstudio.com/content/problem/914943/zcinline-removes-extern-symbols-inside-anonymous-n.html 26 | if (MSVC_VERSION GREATER_EQUAL 1920) 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline-") 28 | else() 29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline") 30 | endif() 31 | endif() 32 | -------------------------------------------------------------------------------- /cmake/Export.cmake: -------------------------------------------------------------------------------- 1 | # This module is for exporting targets and installing CMake package 2 | # files which are used to import _this_ project into _other_ projects 3 | # in a robust manner. 4 | # 5 | # Note For developers using USDPluginExamples as a template: 6 | # Depending on the nature of your project, this module is optional. 7 | 8 | # Install exported library targets. 9 | install( 10 | EXPORT ${CMAKE_PROJECT_NAME}-targets 11 | NAMESPACE USDPluginExamples:: 12 | FILE ${CMAKE_PROJECT_NAME}Targets.cmake 13 | DESTINATION cmake 14 | ) 15 | 16 | # Configure and write Config.cmake to provide package import entry point. 17 | configure_file( 18 | ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in 19 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake 20 | @ONLY 21 | ) 22 | 23 | # Configure and write ConfigVersion.cmake for version compatibility management. 24 | include(CMakePackageConfigHelpers) 25 | write_basic_package_version_file( 26 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake 27 | VERSION ${CMAKE_PROJECT_VERSION} 28 | COMPATIBILITY SameMajorVersion 29 | ) 30 | 31 | # Install the package configuration files. 32 | install( 33 | FILES 34 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake 35 | ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake 36 | DESTINATION ${CMAKE_INSTALL_PREFIX} 37 | ) 38 | -------------------------------------------------------------------------------- /cmake/Options.cmake: -------------------------------------------------------------------------------- 1 | # CMake configuration options exposed for building USDPluginExamples. 2 | 3 | option(ENABLE_PYTHON_SUPPORT "Enable support for python." ON) 4 | option(BUILD_TESTING "Build & execute tests as part of build" ON) 5 | option(BUILD_HYDRA2 "Build Hydra2 Plugins, disables Hydra1 plugins" OFF) 6 | -------------------------------------------------------------------------------- /cmake/Packages.cmake: -------------------------------------------------------------------------------- 1 | # Discovery of the dependencies of USDPluginExamples. 2 | 3 | if (USD_ROOT) 4 | 5 | if (NOT BOOST_ROOT) 6 | message(STATUS "BOOST_ROOT not set, defaulting to ${USD_ROOT}") 7 | set(BOOST_ROOT ${USD_ROOT}) 8 | endif() 9 | 10 | if (NOT TBB_ROOT) 11 | message(STATUS "TBB_ROOT not set, defaulting to ${USD_ROOT}") 12 | set(TBB_ROOT ${USD_ROOT}) 13 | endif() 14 | 15 | else() 16 | message(FATAL_ERROR "USD_ROOT must be set to the root dir of the USD installation!") 17 | endif() 18 | 19 | # Boost & python. 20 | if (ENABLE_PYTHON_SUPPORT) 21 | # Find python libraries. 22 | find_package( 23 | Python3 24 | COMPONENTS 25 | Interpreter Development 26 | REQUIRED 27 | ) 28 | 29 | # Pick up boost version variables. 30 | find_package(Boost REQUIRED) 31 | 32 | # We can use Boost_VERSION_STRING in CMake 3.14+. 33 | set(boost_version_string "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") 34 | 35 | # Boost provided cmake files in 1.70 and above causes inconsistent failures. 36 | if (${boost_version_string} VERSION_GREATER_EQUAL "1.70") 37 | option(Boost_NO_BOOST_CMAKE "Disable boost-provided cmake config" ON) 38 | if (Boost_NO_BOOST_CMAKE) 39 | message(STATUS "Disabling boost-provided cmake config") 40 | endif() 41 | endif() 42 | 43 | if (${boost_version_string} VERSION_GREATER_EQUAL "1.67") 44 | # In boost-1.67 and greater, the boost python component includes the 45 | # python major and minor version as part of its name. 46 | set(PYTHON_VERSION_DOTLESS "${Python3_VERSION_MAJOR}${Python3_VERSION_MINOR}") 47 | find_package(Boost 48 | COMPONENTS 49 | python${PYTHON_VERSION_DOTLESS} 50 | REQUIRED 51 | ) 52 | set(Boost_PYTHON_LIBRARY "${Boost_PYTHON${PYTHON_VERSION_DOTLESS}_LIBRARY}") 53 | else() 54 | find_package(Boost 55 | COMPONENTS 56 | python 57 | REQUIRED 58 | ) 59 | endif() 60 | endif() 61 | 62 | # USD & TBB 63 | include(${USD_ROOT}/pxrConfig.cmake) 64 | find_package(TBB REQUIRED) 65 | -------------------------------------------------------------------------------- /cmake/USDPluginTools.cmake: -------------------------------------------------------------------------------- 1 | # ============================================================================ 2 | # Public-facing convenience functions & macros for building USD plugin(s). 3 | # ============================================================================ 4 | 5 | # To gain access to standard install directory variables such as CMAKE_INSTALL_LIBDIR. 6 | include(GNUInstallDirs) 7 | 8 | # Exposed USD variable(s) for installation. 9 | # XXX: We can hide these if we provide a more convenient way to install the 10 | # root plugInfo.json(s) and __init__.py files. 11 | set(USD_PLUGIN_DIR "plugin") 12 | set(USD_PYTHON_DIR "python") 13 | set(USD_PLUG_INFO_RESOURCES_DIR "resources") 14 | set(USD_PLUG_INFO_ROOT_DIR "usd") 15 | 16 | # 17 | # Public entry point for building a C++ based USD shared library. 18 | # 19 | function(usd_library NAME) 20 | set(options) 21 | 22 | set(oneValueArgs 23 | ) 24 | 25 | set(multiValueArgs 26 | PUBLIC_HEADERS_INSTALL_PREFIX 27 | PUBLIC_HEADERS 28 | PUBLIC_CLASSES 29 | CPPFILES 30 | LIBRARIES 31 | INCLUDE_DIRS 32 | RESOURCE_FILES 33 | PYTHON_INSTALL_PREFIX 34 | PYTHON_FILES 35 | PYTHON_CPPFILES 36 | PYMODULE_CPPFILES 37 | ) 38 | 39 | cmake_parse_arguments(args 40 | "${options}" 41 | "${oneValueArgs}" 42 | "${multiValueArgs}" 43 | ${ARGN} 44 | ) 45 | 46 | _usd_cpp_library(${NAME} 47 | TYPE 48 | SHARED 49 | PUBLIC_HEADERS_INSTALL_PREFIX 50 | ${args_PUBLIC_HEADERS_INSTALL_PREFIX} 51 | PUBLIC_HEADERS 52 | ${args_PUBLIC_HEADERS} 53 | PUBLIC_CLASSES 54 | ${args_PUBLIC_CLASSES} 55 | CPPFILES 56 | ${args_CPPFILES} 57 | LIBRARIES 58 | ${args_LIBRARIES} 59 | INCLUDE_DIRS 60 | ${args_INCLUDE_DIRS} 61 | PYTHON_CPPFILES 62 | ${args_PYTHON_CPPFILES} 63 | ) 64 | 65 | _usd_install_resource_files(${NAME} 66 | TYPE 67 | SHARED 68 | RESOURCE_FILES 69 | ${args_RESOURCE_FILES} 70 | ) 71 | 72 | if (ENABLE_PYTHON_SUPPORT) 73 | _usd_python_module(${NAME} 74 | PYTHON_INSTALL_PREFIX 75 | ${args_PYTHON_INSTALL_PREFIX} 76 | LIBRARIES 77 | ${args_LIBRARIES} 78 | INCLUDE_DIRS 79 | ${args_INCLUDE_DIRS} 80 | PYMODULE_CPPFILES 81 | ${args_PYMODULE_CPPFILES} 82 | PYTHON_FILES 83 | ${args_PYTHON_FILES} 84 | ) 85 | endif() 86 | 87 | endfunction() 88 | 89 | # 90 | # Public entry point for building a C++ based USD plugin. 91 | # 92 | function(usd_plugin NAME) 93 | set(options) 94 | 95 | set(oneValueArgs 96 | ) 97 | 98 | set(multiValueArgs 99 | CPPFILES 100 | LIBRARIES 101 | INCLUDE_DIRS 102 | RESOURCE_FILES 103 | ) 104 | 105 | cmake_parse_arguments(args 106 | "${options}" 107 | "${oneValueArgs}" 108 | "${multiValueArgs}" 109 | ${ARGN} 110 | ) 111 | 112 | _usd_cpp_library(${NAME} 113 | TYPE 114 | "PLUGIN" 115 | PUBLIC_HEADERS_INSTALL_PREFIX 116 | ${args_PUBLIC_HEADERS_INSTALL_PREFIX} 117 | PUBLIC_HEADERS 118 | ${args_PUBLIC_HEADERS} 119 | PUBLIC_CLASSES 120 | ${args_PUBLIC_CLASSES} 121 | CPPFILES 122 | ${args_CPPFILES} 123 | LIBRARIES 124 | ${args_LIBRARIES} 125 | INCLUDE_DIRS 126 | ${args_INCLUDE_DIRS} 127 | ) 128 | 129 | _usd_install_resource_files(${NAME} 130 | TYPE 131 | "PLUGIN" 132 | RESOURCE_FILES 133 | ${args_RESOURCE_FILES} 134 | ) 135 | endfunction() 136 | 137 | # Public entry point for building python-and-resource-files only library. 138 | # This was _specifically_ exposed to produce plugins for usdview, but can be useful 139 | # for deploying python plugins in general that adhere to the installation structure 140 | # prescribed by USDPluginTools. 141 | # 142 | function(usd_python_library NAME) 143 | set(options) 144 | 145 | set(oneValueArgs 146 | ) 147 | 148 | set(multiValueArgs 149 | PYTHON_INSTALL_PREFIX 150 | PYTHON_FILES 151 | RESOURCE_FILES 152 | ) 153 | 154 | cmake_parse_arguments(args 155 | "${options}" 156 | "${oneValueArgs}" 157 | "${multiValueArgs}" 158 | ${ARGN} 159 | ) 160 | 161 | if (ENABLE_PYTHON_SUPPORT) 162 | _usd_python_module(${NAME} 163 | PYTHON_INSTALL_PREFIX 164 | ${args_PYTHON_INSTALL_PREFIX} 165 | PYTHON_FILES 166 | ${args_PYTHON_FILES} 167 | ) 168 | 169 | _usd_install_resource_files(${NAME} 170 | TYPE 171 | SHARED 172 | RESOURCE_FILES 173 | ${args_RESOURCE_FILES} 174 | ) 175 | endif() 176 | endfunction() 177 | 178 | # Adds a USD-based C++ executable application. 179 | function(usd_executable EXECUTABLE_NAME) 180 | 181 | set(options) 182 | 183 | set(oneValueArgs 184 | ) 185 | 186 | set(multiValueArgs 187 | CPPFILES 188 | LIBRARIES 189 | INCLUDE_DIRS 190 | ) 191 | 192 | cmake_parse_arguments(args 193 | "${options}" 194 | "${oneValueArgs}" 195 | "${multiValueArgs}" 196 | ${ARGN} 197 | ) 198 | 199 | # Define a new executable. 200 | add_executable(${EXECUTABLE_NAME} 201 | ${args_CPPFILES} 202 | ) 203 | 204 | # Apply properties. 205 | _usd_target_properties(${EXECUTABLE_NAME} 206 | INCLUDE_DIRS 207 | ${args_INCLUDE_DIRS} 208 | LIBRARIES 209 | ${args_LIBRARIES} 210 | ) 211 | 212 | # Install built executable. 213 | install( 214 | TARGETS ${EXECUTABLE_NAME} 215 | DESTINATION ${CMAKE_INSTALL_BINDIR} 216 | ) 217 | 218 | endfunction() # usd_executable 219 | 220 | # Adds a USD-based cpp test which is executed by CTest. 221 | function(usd_test TEST_TARGET) 222 | 223 | if (NOT BUILD_TESTING) 224 | return() 225 | endif() 226 | 227 | set(options) 228 | 229 | set(oneValueArgs 230 | ) 231 | 232 | set(multiValueArgs 233 | CPPFILES 234 | LIBRARIES 235 | INCLUDE_DIRS 236 | ) 237 | 238 | cmake_parse_arguments(args 239 | "${options}" 240 | "${oneValueArgs}" 241 | "${multiValueArgs}" 242 | ${ARGN} 243 | ) 244 | 245 | # Define a new executable. 246 | add_executable(${TEST_TARGET} 247 | ${args_CPPFILES} 248 | ) 249 | 250 | # Apply properties. 251 | _usd_target_properties(${TEST_TARGET} 252 | INCLUDE_DIRS 253 | ${args_INCLUDE_DIRS} 254 | LIBRARIES 255 | ${args_LIBRARIES} 256 | ) 257 | 258 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 259 | target_link_options(${TEST_TARGET} 260 | PRIVATE 261 | "-Wl,--no-as-needed" 262 | ) 263 | endif() 264 | 265 | # Add the test target. 266 | add_test( 267 | NAME ${TEST_TARGET} 268 | COMMAND $ 269 | ) 270 | 271 | # Set-up runtime environment variables for the test. 272 | _usd_set_test_properties(${TEST_TARGET} OFF) 273 | 274 | endfunction() 275 | 276 | # Adds a USD-based python test which is executed by CTest. 277 | # The python file is simply executed by the python interpreter 278 | # with no special arguments. 279 | function(usd_python_test TEST_TARGET PYTHON_FILE) 280 | if (NOT ENABLE_PYTHON_SUPPORT) 281 | message(STATUS "ENABLE_PYTHON_SUPPORT is OFF, skipping python test: ${TEST_PREFIX} ${PYTHON_FILE}") 282 | return() 283 | endif() 284 | 285 | if (NOT BUILD_TESTING) 286 | return() 287 | endif() 288 | 289 | # Add a new test target. 290 | add_test( 291 | NAME ${TEST_TARGET} 292 | COMMAND ${Python3_EXECUTABLE} ${PYTHON_FILE} 293 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 294 | ) 295 | 296 | # Set-up runtime environment variables for the test. 297 | _usd_set_test_properties(${TEST_TARGET} ON) 298 | 299 | endfunction() 300 | 301 | # 302 | # Internal function for building a USD-based C++ library. 303 | # 304 | function(_usd_cpp_library NAME) 305 | set(options) 306 | 307 | set(oneValueArgs 308 | TYPE 309 | ) 310 | 311 | set(multiValueArgs 312 | PUBLIC_HEADERS_INSTALL_PREFIX 313 | PUBLIC_HEADERS 314 | PUBLIC_CLASSES 315 | CPPFILES 316 | LIBRARIES 317 | INCLUDE_DIRS 318 | PYTHON_CPPFILES 319 | ) 320 | 321 | cmake_parse_arguments(args 322 | "${options}" 323 | "${oneValueArgs}" 324 | "${multiValueArgs}" 325 | ${ARGN} 326 | ) 327 | 328 | # 329 | # Resolve build variables. 330 | # 331 | 332 | # Check desired library type is supported. 333 | if (NOT args_TYPE STREQUAL "PLUGIN" AND NOT args_TYPE STREQUAL "SHARED") 334 | message(FATAL_ERROR 335 | "Building library type '${args_TYPE}' not supported.") 336 | endif() 337 | 338 | # Plugins do not provide public headers (nor public classes). 339 | if (args_TYPE STREQUAL "PLUGIN" AND (args_PUBLIC_HEADERS OR args_PUBLIC_CLASSES)) 340 | message(FATAL_ERROR 341 | "'${args_TYPE}' library type does not support public headers nor classes.") 342 | endif() 343 | 344 | # Does not make sense to build a companion python module for a "plugin". 345 | if (args_TYPE STREQUAL "PLUGIN" AND args_PYMODULE_CPPFILES) 346 | message(FATAL_ERROR 347 | "'${args_TYPE}' library type does not support associated python module.") 348 | endif() 349 | 350 | # Expand class names to .cpp & .h files. 351 | foreach(className ${args_PUBLIC_CLASSES}) 352 | list(APPEND args_CPPFILES ${className}.cpp) 353 | list(APPEND args_PUBLIC_HEADERS ${className}.h) 354 | endforeach() 355 | 356 | # If python support is enabled, then merge PYTHON_CPPFILES into CPPFILES. 357 | if (ENABLE_PYTHON_SUPPORT) 358 | if (args_PYTHON_CPPFILES) 359 | list(APPEND args_CPPFILES ${args_PYTHON_CPPFILES}) 360 | endif() 361 | endif() 362 | 363 | 364 | # Determine public header install location. 365 | if (args_PUBLIC_HEADERS_INSTALL_PREFIX) 366 | set(PUBLIC_HEADERS_INSTALL_PREFIX ${args_PUBLIC_HEADERS_INSTALL_PREFIX}/${NAME}) 367 | else() 368 | set(PUBLIC_HEADERS_INSTALL_PREFIX ${NAME}) 369 | endif() 370 | 371 | # Copy public headers into build tree. 372 | file( 373 | COPY ${args_PUBLIC_HEADERS} 374 | DESTINATION ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_INCLUDEDIR}/${PUBLIC_HEADERS_INSTALL_PREFIX} 375 | ) 376 | 377 | # Install public headers. 378 | install( 379 | FILES ${args_PUBLIC_HEADERS} 380 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PUBLIC_HEADERS_INSTALL_PREFIX} 381 | ) 382 | 383 | # Convert "PLUGIN" into "MODULE". 384 | # (MODULE is CMake terminology for a dynamic lib only intended to be dlopen'ed at runtime). 385 | if (args_TYPE STREQUAL "PLUGIN") 386 | set(LIBRARY_TYPE "MODULE") 387 | else() 388 | set(LIBRARY_TYPE ${args_TYPE}) 389 | endif() 390 | 391 | # Add a new library target. 392 | add_library(${NAME} 393 | ${LIBRARY_TYPE} 394 | ) 395 | 396 | # Add sources for building the target. 397 | target_sources(${NAME} 398 | PRIVATE 399 | ${args_CPPFILES} 400 | ${args_PUBLIC_HEADERS} 401 | ) 402 | 403 | # Apply common compiler properties, and include path properties. 404 | _usd_target_properties(${NAME} 405 | INCLUDE_DIRS 406 | ${args_INCLUDE_DIRS} 407 | LIBRARIES 408 | ${args_LIBRARIES} 409 | ) 410 | 411 | _usd_compute_library_install_and_file_prefix(${args_TYPE} 412 | LIBRARY_INSTALL_PREFIX 413 | LIBRARY_FILE_PREFIX 414 | ) 415 | 416 | if (args_TYPE STREQUAL "PLUGIN") 417 | # Install the plugin. 418 | # We do not need to export the target because plugins are _not_ 419 | # meant to be built against. 420 | install( 421 | TARGETS ${NAME} 422 | LIBRARY DESTINATION ${LIBRARY_INSTALL_PREFIX} 423 | ) 424 | else() 425 | # Setup SOVERSION & VERSION properties to create 426 | # NAMELINK, SONAME, and actual library with full version suffix. 427 | set_target_properties(${NAME} 428 | PROPERTIES 429 | SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR} 430 | VERSION ${CMAKE_PROJECT_VERSION} 431 | ) 432 | 433 | # Install the library and export it as an public target. 434 | install( 435 | TARGETS ${NAME} 436 | EXPORT ${CMAKE_PROJECT_NAME}-targets 437 | LIBRARY DESTINATION ${LIBRARY_INSTALL_PREFIX} 438 | RUNTIME DESTINATION ${LIBRARY_INSTALL_PREFIX} 439 | ) 440 | endif() 441 | 442 | # Mirror installation structure in PROJECT_BINARY_DIR - for running tests against. 443 | if (BUILD_TESTING) 444 | add_custom_command( 445 | TARGET ${NAME} 446 | POST_BUILD 447 | COMMAND ${CMAKE_COMMAND} -E create_symlink $ ${PROJECT_BINARY_DIR}/${LIBRARY_INSTALL_PREFIX}/$ 448 | ) 449 | endif() 450 | 451 | # Update the target properties. 452 | set_target_properties(${NAME} 453 | PROPERTIES 454 | PREFIX "${LIBRARY_FILE_PREFIX}" 455 | ) 456 | 457 | endfunction() # _usd_cpp_library 458 | 459 | # 460 | # Internal function for build a C++ python module with python files. 461 | # 462 | function(_usd_python_module NAME) 463 | set(options) 464 | 465 | set(oneValueArgs 466 | TYPE 467 | ) 468 | 469 | set(multiValueArgs 470 | LIBRARIES 471 | INCLUDE_DIRS 472 | PYTHON_INSTALL_PREFIX 473 | PYTHON_FILES 474 | PYMODULE_CPPFILES 475 | ) 476 | 477 | cmake_parse_arguments(args 478 | "${options}" 479 | "${oneValueArgs}" 480 | "${multiValueArgs}" 481 | ${ARGN} 482 | ) 483 | 484 | # Public module name (example: UsdTri) 485 | _usd_get_python_module_name(${NAME} PYTHON_MODULE_NAME) 486 | 487 | # Construct the installation prefix for the python modules & files. 488 | if (args_PYTHON_INSTALL_PREFIX) 489 | set(PYTHON_INSTALL_PREFIX ${CMAKE_INSTALL_LIBDIR}/${USD_PYTHON_DIR}/${args_PYTHON_INSTALL_PREFIX}/${PYTHON_MODULE_NAME}) 490 | else() 491 | set(PYTHON_INSTALL_PREFIX ${CMAKE_INSTALL_LIBDIR}/${USD_PYTHON_DIR}/${PYTHON_MODULE_NAME}) 492 | endif() 493 | 494 | # 495 | # Python module / bindings. 496 | # 497 | 498 | if (args_PYMODULE_CPPFILES) 499 | 500 | # Target name. 501 | set(PYLIB_NAME "_${NAME}") 502 | 503 | # Add a library target. 504 | add_library(${PYLIB_NAME} 505 | MODULE 506 | ) 507 | 508 | # Add sources for building the target. 509 | target_sources(${PYLIB_NAME} 510 | PRIVATE 511 | ${args_PYMODULE_CPPFILES} 512 | ) 513 | 514 | # Lose the library prefix. 515 | if (MSVC) 516 | set_target_properties(${PYLIB_NAME} 517 | PROPERTIES 518 | PREFIX "" 519 | SUFFIX ".pyd" 520 | ) 521 | else() 522 | set_target_properties(${PYLIB_NAME} 523 | PROPERTIES 524 | PREFIX "" 525 | ) 526 | endif() 527 | 528 | # Apply common compilation properties, and include path properties. 529 | _usd_target_properties(${PYLIB_NAME} 530 | INCLUDE_DIRS 531 | ${args_INCLUDE_DIRS} 532 | DEFINES 533 | MFB_PACKAGE_NAME=${NAME} 534 | MFB_ALT_PACKAGE_NAME=${NAME} 535 | MFB_PACKAGE_MODULE=${PYTHON_MODULE_NAME} 536 | LIBRARIES 537 | ${args_LIBRARIES} 538 | ${NAME} 539 | ) 540 | 541 | # Mirror installation structure in PROJECT_BINARY_DIR - for running tests against. 542 | if (BUILD_TESTING) 543 | add_custom_command( 544 | TARGET ${PYLIB_NAME} 545 | POST_BUILD 546 | COMMAND ${CMAKE_COMMAND} -E create_symlink $ ${PROJECT_BINARY_DIR}/${PYTHON_INSTALL_PREFIX}/$ 547 | ) 548 | endif() 549 | 550 | # Install python module library. 551 | install( 552 | TARGETS 553 | ${PYLIB_NAME} 554 | RENAME 555 | ${PYLIB_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} 556 | DESTINATION 557 | ${PYTHON_INSTALL_PREFIX} 558 | ) 559 | endif() 560 | 561 | # 562 | # Install python files. 563 | # 564 | 565 | if (args_PYTHON_FILES) 566 | 567 | # If tests are enabled - copy these files into project binary dir 568 | # _mirroring_ the install structure, such that we can run tests against 569 | # them. 570 | if (BUILD_TESTING) 571 | foreach(pythonFile ${args_PYTHON_FILES}) 572 | file( 573 | COPY ${CMAKE_CURRENT_SOURCE_DIR}/${pythonFile} 574 | DESTINATION ${PROJECT_BINARY_DIR}/${PYTHON_INSTALL_PREFIX} 575 | ) 576 | endforeach() 577 | endif() 578 | 579 | # Install python files. 580 | install( 581 | FILES 582 | ${args_PYTHON_FILES} 583 | DESTINATION 584 | ${PYTHON_INSTALL_PREFIX} 585 | ) 586 | endif() 587 | endfunction() # _usd_python_module 588 | 589 | # 590 | # Internal function for installing resource files (plugInfo, etc). 591 | # 592 | function(_usd_install_resource_files NAME) 593 | set(options) 594 | 595 | set(oneValueArgs 596 | TYPE 597 | ) 598 | 599 | set(multiValueArgs 600 | RESOURCE_FILES 601 | ) 602 | 603 | cmake_parse_arguments(args 604 | "${options}" 605 | "${oneValueArgs}" 606 | "${multiValueArgs}" 607 | ${ARGN} 608 | ) 609 | 610 | _usd_compute_library_install_and_file_prefix(${args_TYPE} 611 | LIBRARY_INSTALL_PREFIX 612 | LIBRARY_FILE_PREFIX 613 | ) 614 | 615 | if (args_TYPE STREQUAL "PLUGIN") 616 | set(LIBRARY_FILE_SUFFIX ${CMAKE_SHARED_MODULE_SUFFIX}) 617 | else() 618 | set(LIBRARY_FILE_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) 619 | endif() 620 | 621 | # Compose the full name of the library. 622 | # This will be used when performing variable substition on the plugInfo.json resource file. 623 | set(LIBRARY_FILE_NAME ${LIBRARY_FILE_PREFIX}${NAME}${LIBRARY_FILE_SUFFIX}) 624 | 625 | # Plugin resources will be installed as a 'usd' subdir under the library install location. 626 | set(RESOURCES_INSTALL_PREFIX ${LIBRARY_INSTALL_PREFIX}/${USD_PLUG_INFO_ROOT_DIR}) 627 | 628 | foreach(resourceFile ${args_RESOURCE_FILES}) 629 | 630 | # Apply string substitution to plugInfo.json, copy to binary dir. 631 | if (${resourceFile} STREQUAL "plugInfo.json") 632 | file(RELATIVE_PATH 633 | RESOURCE_TO_LIBRARY_PATH 634 | ${CMAKE_INSTALL_PREFIX}/${RESOURCES_INSTALL_PREFIX}/${NAME} 635 | ${CMAKE_INSTALL_PREFIX}/${LIBRARY_INSTALL_PREFIX}/${LIBRARY_FILE_NAME}) 636 | 637 | _usd_plug_info_subst(${NAME} ${RESOURCE_TO_LIBRARY_PATH} ${resourceFile}) 638 | 639 | # Update resourceFile var to path of substituted file. 640 | set(resourceFile "${CMAKE_CURRENT_BINARY_DIR}/${resourceFile}") 641 | endif() 642 | 643 | # Install into project binary dir (for tests) 644 | if (BUILD_TESTING) 645 | file( 646 | COPY ${resourceFile} 647 | DESTINATION ${PROJECT_BINARY_DIR}/${RESOURCES_INSTALL_PREFIX}/${NAME}/${USD_PLUG_INFO_RESOURCES_DIR} 648 | ) 649 | endif() 650 | 651 | # Install resource file. 652 | install( 653 | FILES 654 | ${resourceFile} 655 | DESTINATION 656 | ${RESOURCES_INSTALL_PREFIX}/${NAME}/${USD_PLUG_INFO_RESOURCES_DIR} 657 | ) 658 | endforeach() 659 | endfunction() # _usd_install_resource_files 660 | 661 | # Internal utility for differentiating between "shared library" vs "plugin". 662 | # 663 | # Outputs: 664 | # LIBRARY_INSTALL_PREFIX: The sub-directory under installation root where the 665 | # shared library will be deployed. 666 | # LIBRARY_FILE_PREFIX: The filename prefix of the shared library. ("lib" on Linux) 667 | function(_usd_compute_library_install_and_file_prefix 668 | TYPE 669 | LIBRARY_INSTALL_PREFIX 670 | LIBRARY_FILE_PREFIX 671 | ) 672 | if (TYPE STREQUAL "PLUGIN") 673 | set(${LIBRARY_INSTALL_PREFIX} ${USD_PLUGIN_DIR} PARENT_SCOPE) 674 | set(${LIBRARY_FILE_PREFIX} "" PARENT_SCOPE) 675 | else() 676 | set(${LIBRARY_INSTALL_PREFIX} ${CMAKE_INSTALL_LIBDIR} PARENT_SCOPE) 677 | set(${LIBRARY_FILE_PREFIX} ${CMAKE_SHARED_LIBRARY_PREFIX} PARENT_SCOPE) 678 | endif() 679 | endfunction() 680 | 681 | # Converts a library name, such as _tf.so to the internal module name given 682 | # our naming conventions, e.g. Tf 683 | function(_usd_get_python_module_name 684 | LIBRARY_FILENAME 685 | MODULE_NAME 686 | ) 687 | # Library names are either something like tf.so for shared libraries 688 | # or _tf.pyd/_tf_d.pyd for Python module libraries. 689 | # We want to strip off the leading "_" and the trailing "_d". 690 | set(LIBNAME ${LIBRARY_FILENAME}) 691 | string(REGEX REPLACE "^_" "" LIBNAME ${LIBNAME}) 692 | string(SUBSTRING ${LIBNAME} 0 1 LIBNAME_FL) 693 | string(TOUPPER ${LIBNAME_FL} LIBNAME_FL) 694 | string(SUBSTRING ${LIBNAME} 1 -1 LIBNAME_SUFFIX) 695 | set(${MODULE_NAME} 696 | "${LIBNAME_FL}${LIBNAME_SUFFIX}" 697 | PARENT_SCOPE 698 | ) 699 | endfunction() # _usd_get_python_module_name 700 | 701 | # Performs variable substitution in a plugInfo.json file. 702 | function(_usd_plug_info_subst 703 | LIBRARY_TARGET 704 | RESOURCE_TO_LIBRARY_PATH 705 | PLUG_INFO_PATH 706 | ) 707 | set(PLUG_INFO_ROOT "..") 708 | set(PLUG_INFO_LIBRARY_PATH ${RESOURCE_TO_LIBRARY_PATH}) 709 | set(PLUG_INFO_RESOURCE_PATH ${USD_PLUG_INFO_RESOURCES_DIR}) 710 | configure_file( 711 | ${PLUG_INFO_PATH} 712 | ${CMAKE_CURRENT_BINARY_DIR}/${PLUG_INFO_PATH} 713 | ) 714 | endfunction() # _usd_plug_info_subst 715 | 716 | # Common target-specific properties to apply to library targets. 717 | function(_usd_target_properties 718 | TARGET_NAME 719 | ) 720 | set(options) 721 | set(oneValueArgs) 722 | set(multiValueArgs 723 | INCLUDE_DIRS 724 | DEFINES 725 | LIBRARIES 726 | ) 727 | 728 | cmake_parse_arguments( 729 | args 730 | "${options}" 731 | "${oneValueArgs}" 732 | "${multiValueArgs}" 733 | ${ARGN} 734 | ) 735 | 736 | # Add additional platform-speific compile definitions 737 | set (platform_definitions) 738 | if (MSVC) 739 | # Depending on which parts of USD the project uses, additional definitions for windows may need 740 | # to be added. A explicit list of MSVC definitions USD builds with can be found in the USD source at: 741 | # cmake/defaults/CXXDefaults.cmake 742 | # cmake/defaults/msvcdefaults.cmake 743 | list(APPEND platform_definitions NOMINMAX) 744 | endif() 745 | 746 | # Some implementations of C++17 removes some deprecated functions from stl 747 | # MSVC adds this define by default 748 | if (NOT MSVC) 749 | list(APPEND platform_definitions BOOST_NO_CXX98_FUNCTION_BASE) 750 | endif() 751 | 752 | target_compile_definitions(${TARGET_NAME} 753 | PRIVATE 754 | ${args_DEFINES} 755 | ${platform_definitions} 756 | ) 757 | 758 | target_compile_features(${TARGET_NAME} 759 | PRIVATE 760 | cxx_std_17 761 | ) 762 | 763 | # Exported include paths for this target. 764 | target_include_directories(${TARGET_NAME} 765 | INTERFACE 766 | $ 767 | ) 768 | 769 | # Project includes for building against. 770 | target_include_directories(${TARGET_NAME} 771 | PRIVATE 772 | $ 773 | ) 774 | 775 | # Setup include path for binary dir. 776 | # We set external includes as SYSTEM so that their warnings are muted. 777 | set(_INCLUDE_DIRS "") 778 | list(APPEND _INCLUDE_DIRS ${args_INCLUDE_DIRS} ${USD_INCLUDE_DIR} ${TBB_INCLUDE_DIRS}) 779 | if (ENABLE_PYTHON_SUPPORT) 780 | list(APPEND _INCLUDE_DIRS ${Python3_INCLUDE_DIR} ${Boost_INCLUDE_DIR}) 781 | endif() 782 | target_include_directories(${TARGET_NAME} 783 | SYSTEM 784 | PRIVATE 785 | ${_INCLUDE_DIRS} 786 | ) 787 | 788 | # Set-up library search path. 789 | target_link_directories(${TARGET_NAME} 790 | PRIVATE 791 | ${USD_LIBRARY_DIR} 792 | ) 793 | 794 | # Link to libraries. 795 | set(_LINK_LIBRARIES "") 796 | list(APPEND _LINK_LIBRARIES ${args_LIBRARIES} ${TBB_LIBRARIES}) 797 | if (ENABLE_PYTHON_SUPPORT) 798 | list(APPEND _LINK_LIBRARIES ${Boost_PYTHON_LIBRARY} ${Python3_LIBRARIES}) 799 | endif() 800 | target_link_libraries(${TARGET_NAME} 801 | PRIVATE 802 | ${_LINK_LIBRARIES} 803 | ) 804 | endfunction() # _usd_target_properties 805 | 806 | # Set-up runtime environment variables for the test. 807 | # When USE_PYTHONPATH is one, will include project python libraries 808 | function(_usd_set_test_properties 809 | TARGET_NAME 810 | USE_PYTHONPATH 811 | ) 812 | # The paths refer to the build tree (which mirrors the final installation). 813 | # The first path for an env var needs the 'VARNAME=' prepended. 814 | # On windows, calls to "$ENV{}" must be sanitized to replace back slashes with forward slashes 815 | # Env vars after the first must be prepended with a double escaped semicolon to be recognized. 816 | 817 | set(TEST_ENV_VARS "") 818 | 819 | # Building the PXR_PLUGINPATH_NAME environment variable 820 | set(TEST_PXR_PLUGINPATH_NAME "$ENV{PXR_PLUGINPATH_NAME}") 821 | if (MSVC) 822 | string(REGEX REPLACE "\\\\" "/" TEST_PXR_PLUGINPATH_NAME "${TEST_PXR_PLUGINPATH_NAME}") 823 | endif() 824 | string(PREPEND TEST_PXR_PLUGINPATH_NAME "PXR_PLUGINPATH_NAME=") 825 | list(APPEND TEST_PXR_PLUGINPATH_NAME 826 | "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/${USD_PLUG_INFO_ROOT_DIR}" 827 | "${PROJECT_BINARY_DIR}/${USD_PLUGIN_DIR}/${USD_PLUG_INFO_ROOT_DIR}" 828 | ) 829 | list(APPEND TEST_ENV_VARS "${TEST_PXR_PLUGINPATH_NAME}") 830 | 831 | # Building the PYTHONPATH environment variable 832 | if (USE_PYTHONPATH) 833 | set(TEST_PYTHON_PATH "$ENV{PYTHONPATH}") 834 | if (MSVC) 835 | string(REGEX REPLACE "\\\\" "/" TEST_PYTHON_PATH "${TEST_PYTHON_PATH}") 836 | endif() 837 | string(PREPEND TEST_PYTHON_PATH "PYTHONPATH=") 838 | string(PREPEND TEST_PYTHON_PATH "\\;") 839 | list(APPEND TEST_PYTHON_PATH 840 | "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/python" 841 | "${USD_ROOT}/${CMAKE_INSTALL_LIBDIR}/python" 842 | ) 843 | 844 | list(APPEND TEST_ENV_VARS "${TEST_PYTHON_PATH}") 845 | endif() 846 | 847 | # Add MSVC-required paths 848 | if (MSVC) 849 | # Building the PATH environment variable 850 | set(TEST_PATH "$ENV{PATH}") 851 | string(REGEX REPLACE "\\\\" "/" TEST_PATH "${TEST_PATH}") 852 | string(PREPEND TEST_PATH "PATH=") 853 | string(PREPEND TEST_PATH "\\;") 854 | list(APPEND TEST_PATH 855 | "${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}" 856 | "${USD_ROOT}/${CMAKE_INSTALL_LIBDIR}" 857 | "${USD_ROOT}/${CMAKE_INSTALL_BINDIR}" 858 | ) 859 | 860 | list(APPEND TEST_ENV_VARS "${TEST_PATH}") 861 | endif() 862 | 863 | 864 | if (MSVC) 865 | list(JOIN TEST_ENV_VARS "\\;" TEST_ENV_VARS) 866 | else() 867 | list(JOIN TEST_ENV_VARS ":" TEST_ENV_VARS) 868 | endif() 869 | 870 | set_tests_properties(${TARGET_NAME} 871 | PROPERTIES 872 | ENVIRONMENT 873 | "${TEST_ENV_VARS}" 874 | ) 875 | 876 | endfunction() # _usd_set_test_properties 877 | -------------------------------------------------------------------------------- /cmake/packages/FindTBB.cmake: -------------------------------------------------------------------------------- 1 | # Obtained from Justus Calvin: 2 | # https://github.com/justusc/FindTBB/blob/25ecdea817b3af4a26d74ddcd439642dbd706acb/FindTBB.cmake 3 | # 4 | # With the following modifications: 5 | # * Move the "tbb" imported library target into a namespace as "TBB::tbb" to 6 | # conform to modern CMake conventions. 7 | # * Append "lib" as a library path suffix on all platforms. 8 | # 9 | # The MIT License (MIT) 10 | # 11 | # Copyright (c) 2015 Justus Calvin 12 | # 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documentation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furnished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in all 21 | # copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | # SOFTWARE. 30 | 31 | # 32 | # FindTBB 33 | # ------- 34 | # 35 | # Find TBB include directories and libraries. 36 | # 37 | # Usage: 38 | # 39 | # find_package(TBB [major[.minor]] [EXACT] 40 | # [QUIET] [REQUIRED] 41 | # [[COMPONENTS] [components...]] 42 | # [OPTIONAL_COMPONENTS components...]) 43 | # 44 | # where the allowed components are tbbmalloc and tbb_preview. Users may modify 45 | # the behavior of this module with the following variables: 46 | # 47 | # * TBB_ROOT_DIR - The base directory the of TBB installation. 48 | # * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. 49 | # * TBB_LIBRARY - The directory that contains the TBB library files. 50 | # * TBB__LIBRARY - The path of the TBB the corresponding TBB library. 51 | # These libraries, if specified, override the 52 | # corresponding library search results, where 53 | # may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, 54 | # tbb_preview, or tbb_preview_debug. 55 | # * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will 56 | # be used instead of the release version. 57 | # 58 | # Users may modify the behavior of this module with the following environment 59 | # variables: 60 | # 61 | # * TBB_INSTALL_DIR 62 | # * TBBROOT 63 | # * LIBRARY_PATH 64 | # 65 | # This module will set the following variables: 66 | # 67 | # * TBB_FOUND - Set to false, or undefined, if we haven’t found, or 68 | # don’t want to use TBB. 69 | # * TBB__FOUND - If False, optional part of TBB sytem is 70 | # not available. 71 | # * TBB_VERSION - The full version string 72 | # * TBB_VERSION_MAJOR - The major version 73 | # * TBB_VERSION_MINOR - The minor version 74 | # * TBB_INTERFACE_VERSION - The interface version number defined in 75 | # tbb/tbb_stddef.h. 76 | # * TBB__LIBRARY_RELEASE - The path of the TBB release version of 77 | # , where may be tbb, tbb_debug, 78 | # tbbmalloc, tbbmalloc_debug, tbb_preview, or 79 | # tbb_preview_debug. 80 | # * TBB__LIBRARY_DEGUG - The path of the TBB release version of 81 | # , where may be tbb, tbb_debug, 82 | # tbbmalloc, tbbmalloc_debug, tbb_preview, or 83 | # tbb_preview_debug. 84 | # 85 | # The following varibles should be used to build and link with TBB: 86 | # 87 | # * TBB_INCLUDE_DIRS - The include directory for TBB. 88 | # * TBB_LIBRARIES - The libraries to link against to use TBB. 89 | # * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB. 90 | # * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB. 91 | # * TBB_DEFINITIONS - Definitions to use when compiling code that uses 92 | # TBB. 93 | # * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that 94 | # uses TBB. 95 | # * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that 96 | # uses TBB. 97 | # 98 | # This module will also create the "TBB::tbb" target that may be used when 99 | # building executables and libraries. 100 | 101 | include(FindPackageHandleStandardArgs) 102 | 103 | if(NOT TBB_FOUND) 104 | 105 | ################################## 106 | # Check the build type 107 | ################################## 108 | 109 | if(NOT DEFINED TBB_USE_DEBUG_BUILD) 110 | if(CMAKE_BUILD_TYPE MATCHES "(Debug|DEBUG|debug|RelWithDebInfo|RELWITHDEBINFO|relwithdebinfo)") 111 | set(TBB_BUILD_TYPE DEBUG) 112 | else() 113 | set(TBB_BUILD_TYPE RELEASE) 114 | endif() 115 | elseif(TBB_USE_DEBUG_BUILD) 116 | set(TBB_BUILD_TYPE DEBUG) 117 | else() 118 | set(TBB_BUILD_TYPE RELEASE) 119 | endif() 120 | 121 | ################################## 122 | # Set the TBB search directories 123 | ################################## 124 | 125 | # Define search paths based on user input and environment variables 126 | set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT}) 127 | 128 | # Define the search directories based on the current platform 129 | if(CMAKE_SYSTEM_NAME STREQUAL "Windows") 130 | set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" 131 | "C:/Program Files (x86)/Intel/TBB") 132 | 133 | # Set the target architecture 134 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 135 | set(TBB_ARCHITECTURE "intel64") 136 | else() 137 | set(TBB_ARCHITECTURE "ia32") 138 | endif() 139 | 140 | # Set the TBB search library path search suffix based on the version of VC 141 | if(WINDOWS_STORE) 142 | set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui") 143 | elseif(MSVC14) 144 | set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14") 145 | elseif(MSVC12) 146 | set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12") 147 | elseif(MSVC11) 148 | set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11") 149 | elseif(MSVC10) 150 | set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10") 151 | endif() 152 | 153 | # Add the library path search suffix for the VC independent version of TBB 154 | list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt") 155 | 156 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 157 | # OS X 158 | set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") 159 | 160 | # TODO: Check to see which C++ library is being used by the compiler. 161 | if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) 162 | # The default C++ library on OS X 10.9 and later is libc++ 163 | set(TBB_LIB_PATH_SUFFIX "lib/libc++") 164 | endif() 165 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") 166 | # Linux 167 | set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") 168 | 169 | # TODO: Check compiler version to see the suffix should be /gcc4.1 or 170 | # /gcc4.1. For now, assume that the compiler is more recent than 171 | # gcc 4.4.x or later. 172 | if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") 173 | set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") 174 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") 175 | set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") 176 | endif() 177 | endif() 178 | 179 | # The above TBB_LIB_PATH_SUFFIX is based on where Intel puts the libraries 180 | # in the package of prebuilt libraries it distributes. However, users may 181 | # install these shared libraries into the more conventional "lib" directory 182 | # (especially when building from source), so we add that as an additional 183 | # location to search. 184 | list(APPEND TBB_LIB_PATH_SUFFIX "lib") 185 | 186 | ################################## 187 | # Find the TBB include dir 188 | ################################## 189 | 190 | find_path(TBB_INCLUDE_DIRS tbb/tbb.h 191 | HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR} 192 | PATHS ${TBB_DEFAULT_SEARCH_DIR} 193 | PATH_SUFFIXES include) 194 | 195 | ################################## 196 | # Set version strings 197 | ################################## 198 | 199 | if(TBB_INCLUDE_DIRS) 200 | file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) 201 | string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" 202 | TBB_VERSION_MAJOR "${_tbb_version_file}") 203 | string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" 204 | TBB_VERSION_MINOR "${_tbb_version_file}") 205 | string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" 206 | TBB_INTERFACE_VERSION "${_tbb_version_file}") 207 | set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") 208 | endif() 209 | 210 | ################################## 211 | # Find TBB components 212 | ################################## 213 | 214 | if(TBB_VERSION VERSION_LESS 4.3) 215 | set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb) 216 | else() 217 | set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb) 218 | endif() 219 | 220 | # Find each component 221 | foreach(_comp ${TBB_SEARCH_COMPOMPONENTS}) 222 | if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};") 223 | 224 | # Search for the libraries 225 | find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp} 226 | HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} 227 | PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH 228 | PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) 229 | 230 | find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug 231 | HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} 232 | PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH 233 | PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) 234 | 235 | if(TBB_${_comp}_LIBRARY_DEBUG) 236 | list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}") 237 | endif() 238 | if(TBB_${_comp}_LIBRARY_RELEASE) 239 | list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}") 240 | endif() 241 | if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY) 242 | set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}") 243 | endif() 244 | 245 | if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}") 246 | set(TBB_${_comp}_FOUND TRUE) 247 | else() 248 | set(TBB_${_comp}_FOUND FALSE) 249 | endif() 250 | 251 | # Mark internal variables as advanced 252 | mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) 253 | mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) 254 | mark_as_advanced(TBB_${_comp}_LIBRARY) 255 | 256 | endif() 257 | endforeach() 258 | 259 | ################################## 260 | # Set compile flags and libraries 261 | ################################## 262 | 263 | set(TBB_DEFINITIONS_RELEASE "") 264 | set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1") 265 | 266 | if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) 267 | set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}") 268 | set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") 269 | elseif(TBB_LIBRARIES_RELEASE) 270 | set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}") 271 | set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}") 272 | elseif(TBB_LIBRARIES_DEBUG) 273 | set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}") 274 | set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}") 275 | endif() 276 | 277 | find_package_handle_standard_args(TBB 278 | REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES 279 | HANDLE_COMPONENTS 280 | VERSION_VAR TBB_VERSION) 281 | 282 | ################################## 283 | # Create targets 284 | ################################## 285 | 286 | if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) 287 | add_library(TBB::tbb SHARED IMPORTED) 288 | set_target_properties(TBB::tbb PROPERTIES 289 | INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS} 290 | IMPORTED_LOCATION ${TBB_LIBRARIES}) 291 | if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) 292 | set_target_properties(TBB::tbb PROPERTIES 293 | INTERFACE_COMPILE_DEFINITIONS "$<$,$>:TBB_USE_DEBUG=1>" 294 | IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG} 295 | IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_DEBUG} 296 | IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE} 297 | IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} 298 | ) 299 | elseif(TBB_LIBRARIES_RELEASE) 300 | set_target_properties(TBB::tbb PROPERTIES IMPORTED_LOCATION ${TBB_LIBRARIES_RELEASE}) 301 | else() 302 | set_target_properties(TBB::tbb PROPERTIES 303 | INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}" 304 | IMPORTED_LOCATION ${TBB_LIBRARIES_DEBUG} 305 | ) 306 | endif() 307 | endif() 308 | 309 | mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) 310 | 311 | unset(TBB_ARCHITECTURE) 312 | unset(TBB_BUILD_TYPE) 313 | unset(TBB_LIB_PATH_SUFFIX) 314 | unset(TBB_DEFAULT_SEARCH_DIR) 315 | 316 | endif() 317 | -------------------------------------------------------------------------------- /images/triangle_in_viewport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wetadigital/USDPluginExamples/aad3a7528ebd3bf0094a76f2bce3842657ed3add/images/triangle_in_viewport.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # A top-level name used as the root directory for public headers 2 | # installation, and the root python module. 3 | # This is optional. See ./usdTri/CMakeLists.txt for how it's used. 4 | set(ORGANIZATION "usdpluginexamples") 5 | 6 | # Build & install libraries. 7 | add_subdirectory(usdTri) 8 | add_subdirectory(usdviewTri) 9 | 10 | # Build & install plugins. 11 | if (BUILD_HYDRA2) 12 | add_subdirectory(usdTriImagingHd2) 13 | else() 14 | add_subdirectory(usdTriImaging) 15 | endif() 16 | 17 | add_subdirectory(usdTriFileFormat) 18 | add_subdirectory(hdTri) 19 | 20 | # Install top-level plugInfo for including per-library plugInfo(s). 21 | install( 22 | FILES plugInfo.json 23 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/${USD_PLUG_INFO_ROOT_DIR} 24 | ) 25 | 26 | # Install top-level plugInfo for including per-plugin plugInfo(s). 27 | install( 28 | FILES plugInfo.json 29 | DESTINATION ${USD_PLUGIN_DIR}/${USD_PLUG_INFO_ROOT_DIR} 30 | ) 31 | 32 | # Install top level python __init__.py 33 | install( 34 | FILES __init__.py 35 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/${USD_PYTHON_DIR}/${ORGANIZATION} 36 | ) 37 | 38 | # Mirror installation structure in intermediate binary dir for running tests against. 39 | if (BUILD_TESTING) 40 | file( 41 | COPY plugInfo.json 42 | DESTINATION ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/${USD_PLUG_INFO_ROOT_DIR} 43 | ) 44 | 45 | file( 46 | COPY plugInfo.json 47 | DESTINATION ${PROJECT_BINARY_DIR}/${USD_PLUGIN_DIR}/${USD_PLUG_INFO_ROOT_DIR} 48 | ) 49 | 50 | file( 51 | COPY __init__.py 52 | DESTINATION ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/${USD_PYTHON_DIR}/${ORGANIZATION} 53 | ) 54 | endif() 55 | 56 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wetadigital/USDPluginExamples/aad3a7528ebd3bf0094a76f2bce3842657ed3add/src/__init__.py -------------------------------------------------------------------------------- /src/hdTri/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB CPPFILES *.cpp) 2 | 3 | usd_plugin(hdTri 4 | 5 | CPPFILES 6 | ${CPPFILES} 7 | 8 | LIBRARIES 9 | arch 10 | js 11 | plug 12 | tf 13 | sdf 14 | vt 15 | gf 16 | hd 17 | hf 18 | 19 | RESOURCE_FILES 20 | plugInfo.json 21 | ) 22 | 23 | -------------------------------------------------------------------------------- /src/hdTri/debugCodes.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "debugCodes.h" 7 | 8 | PXR_NAMESPACE_OPEN_SCOPE 9 | 10 | TF_REGISTRY_FUNCTION(TfDebug) 11 | { 12 | TF_DEBUG_ENVIRONMENT_SYMBOL(HDTRI_GENERAL, "HdTri general debug logging."); 13 | } 14 | 15 | PXR_NAMESPACE_CLOSE_SCOPE 16 | -------------------------------------------------------------------------------- /src/hdTri/debugCodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | TF_DEBUG_CODES(HDTRI_GENERAL); 14 | 15 | PXR_NAMESPACE_CLOSE_SCOPE 16 | -------------------------------------------------------------------------------- /src/hdTri/plugInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "Plugins": [ 3 | { 4 | "Info": { 5 | "Types": { 6 | "HdTriRendererPlugin": { 7 | "bases": [ 8 | "HdRendererPlugin" 9 | ], 10 | "displayName": "Tri", 11 | "priority": 99 12 | } 13 | } 14 | }, 15 | "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", 16 | "Name": "hdTri", 17 | "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@", 18 | "Root": "@PLUG_INFO_ROOT@", 19 | "Type": "library" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/hdTri/renderBuffer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "renderBuffer.h" 7 | #include "debugCodes.h" 8 | 9 | PXR_NAMESPACE_OPEN_SCOPE 10 | 11 | HdTriRenderBuffer::HdTriRenderBuffer(const SdfPath& bprimId) 12 | : HdRenderBuffer(bprimId) 13 | { 14 | } 15 | 16 | bool 17 | HdTriRenderBuffer::Allocate(const GfVec3i& dimensions, 18 | HdFormat format, 19 | bool multiSampled) 20 | { 21 | TF_DEBUG(HDTRI_GENERAL) 22 | .Msg("[%s] Allocate render buffer id=%s, dimensions=(%i, %i, %i), " 23 | "format=%i\n", 24 | TF_FUNC_NAME().c_str(), 25 | GetId().GetText(), 26 | dimensions[0], 27 | dimensions[1], 28 | dimensions[2], 29 | format); 30 | 31 | _Deallocate(); 32 | 33 | // 2D buffer for now! 34 | TF_VERIFY(dimensions[2] == 1); 35 | 36 | _dimensions = dimensions; 37 | _format = format; 38 | _buffer.resize(_dimensions[0] * _dimensions[1] * _dimensions[2] * 39 | HdDataSizeOfFormat(format)); 40 | 41 | TF_DEBUG(HDTRI_GENERAL) 42 | .Msg("[%s] Render buffer id=%s, size=%lu\n", 43 | TF_FUNC_NAME().c_str(), 44 | GetId().GetText(), 45 | _buffer.size()); 46 | 47 | return true; 48 | } 49 | 50 | unsigned int 51 | HdTriRenderBuffer::GetWidth() const 52 | { 53 | return _dimensions[0]; 54 | } 55 | 56 | unsigned int 57 | HdTriRenderBuffer::GetHeight() const 58 | { 59 | return _dimensions[1]; 60 | } 61 | 62 | unsigned int 63 | HdTriRenderBuffer::GetDepth() const 64 | { 65 | return _dimensions[2]; 66 | } 67 | 68 | HdFormat 69 | HdTriRenderBuffer::GetFormat() const 70 | { 71 | return _format; 72 | } 73 | 74 | bool 75 | HdTriRenderBuffer::IsMultiSampled() const 76 | { 77 | return false; 78 | } 79 | 80 | void* 81 | HdTriRenderBuffer::Map() 82 | { 83 | _mappers.fetch_add(1); 84 | return static_cast(_buffer.data()); 85 | } 86 | 87 | void 88 | HdTriRenderBuffer::Unmap() 89 | { 90 | _mappers.fetch_sub(1); 91 | } 92 | 93 | bool 94 | HdTriRenderBuffer::IsMapped() const 95 | { 96 | return _mappers.load() > 0; 97 | } 98 | 99 | bool 100 | HdTriRenderBuffer::IsConverged() const 101 | { 102 | return _converged.load(); 103 | } 104 | 105 | void 106 | HdTriRenderBuffer::SetConverged(bool converged) 107 | { 108 | _converged.store(converged); 109 | } 110 | 111 | void 112 | HdTriRenderBuffer::Resolve() 113 | { 114 | // Nothing to do, there is only a single internal buffer for read/write. 115 | return; 116 | } 117 | 118 | void 119 | HdTriRenderBuffer::_Deallocate() 120 | { 121 | TF_VERIFY(!IsMapped()); 122 | 123 | // Reset to default/empty values. 124 | _dimensions = GfVec3i(0, 0, 0); 125 | _format = HdFormatInvalid; 126 | _buffer.resize(0); 127 | _mappers.store(0); 128 | _converged.store(false); 129 | } 130 | 131 | PXR_NAMESPACE_CLOSE_SCOPE 132 | -------------------------------------------------------------------------------- /src/hdTri/renderBuffer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | /// \class HdTriRenderBuffer 14 | /// 15 | /// A block of memory which we are rendering into. 16 | class HdTriRenderBuffer : public HdRenderBuffer 17 | { 18 | public: 19 | HdTriRenderBuffer(const SdfPath& bprimId); 20 | 21 | /// Allocate a new buffer with the given dimensions and format. 22 | virtual bool Allocate(const GfVec3i& dimensions, 23 | HdFormat format, 24 | bool multiSampled) override; 25 | 26 | /// Accessor for buffer width. 27 | virtual unsigned int GetWidth() const override; 28 | 29 | /// Accessor for buffer height. 30 | virtual unsigned int GetHeight() const override; 31 | 32 | /// Accessor for buffer depth. 33 | virtual unsigned int GetDepth() const override; 34 | 35 | /// Accessor for buffer format. 36 | virtual HdFormat GetFormat() const override; 37 | 38 | /// Accessor for the buffer multisample state. 39 | virtual bool IsMultiSampled() const override; 40 | 41 | /// Map the buffer for reading/writing. The control flow should be Map(), 42 | /// before any I/O, followed by memory access, followed by Unmap() when 43 | /// done. 44 | virtual void* Map() override; 45 | 46 | /// Unmap the buffer. 47 | virtual void Unmap() override; 48 | 49 | /// Return whether any clients have this buffer mapped currently. 50 | virtual bool IsMapped() const override; 51 | 52 | /// Is the buffer converged? 53 | virtual bool IsConverged() const override; 54 | 55 | /// Set the convergence. 56 | void SetConverged(bool converged); 57 | 58 | /// Resolve the sample buffer into final values. 59 | virtual void Resolve() override; 60 | 61 | private: 62 | // Release any allocated resources. 63 | virtual void _Deallocate() override; 64 | 65 | // Buffer dimensions. 66 | GfVec3i _dimensions = GfVec3i(0, 0, 0); 67 | 68 | // Buffer format. 69 | HdFormat _format = HdFormatInvalid; 70 | 71 | // The actual buffer of bytes. 72 | std::vector _buffer; 73 | 74 | // The number of callers mapping this buffer. 75 | std::atomic _mappers{ 0 }; 76 | 77 | // Whether the buffer has been marked as converged. 78 | std::atomic _converged{ false }; 79 | }; 80 | 81 | PXR_NAMESPACE_CLOSE_SCOPE 82 | -------------------------------------------------------------------------------- /src/hdTri/renderDelegate.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "debugCodes.h" 7 | #include "renderBuffer.h" 8 | #include "renderDelegate.h" 9 | #include "renderParam.h" 10 | #include "renderPass.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | PXR_NAMESPACE_OPEN_SCOPE 18 | 19 | /// Supported Hydra prim types. 20 | const TfTokenVector HdTriRenderDelegate::SUPPORTED_RPRIM_TYPES = {}; 21 | const TfTokenVector HdTriRenderDelegate::SUPPORTED_SPRIM_TYPES = { 22 | HdPrimTypeTokens->camera 23 | }; 24 | const TfTokenVector HdTriRenderDelegate::SUPPORTED_BPRIM_TYPES = { 25 | HdPrimTypeTokens->renderBuffer 26 | }; 27 | 28 | HdTriRenderDelegate::HdTriRenderDelegate() 29 | : HdRenderDelegate() 30 | { 31 | _Setup(); 32 | } 33 | 34 | HdTriRenderDelegate::HdTriRenderDelegate(const HdRenderSettingsMap& settingsMap) 35 | : HdRenderDelegate(settingsMap) 36 | { 37 | _Setup(); 38 | } 39 | 40 | HdTriRenderDelegate::~HdTriRenderDelegate() 41 | { 42 | // Clean resources. 43 | _renderParam.reset(); 44 | } 45 | 46 | TfTokenVector const& 47 | HdTriRenderDelegate::GetSupportedRprimTypes() const 48 | { 49 | return SUPPORTED_RPRIM_TYPES; 50 | } 51 | 52 | TfTokenVector const& 53 | HdTriRenderDelegate::GetSupportedSprimTypes() const 54 | { 55 | return SUPPORTED_SPRIM_TYPES; 56 | } 57 | 58 | TfTokenVector const& 59 | HdTriRenderDelegate::GetSupportedBprimTypes() const 60 | { 61 | return SUPPORTED_BPRIM_TYPES; 62 | } 63 | 64 | HdRenderParam* 65 | HdTriRenderDelegate::GetRenderParam() const 66 | { 67 | return _renderParam.get(); 68 | } 69 | 70 | HdRenderSettingDescriptorList 71 | HdTriRenderDelegate::GetRenderSettingDescriptors() const 72 | { 73 | return _settingDescriptors; 74 | } 75 | 76 | HdResourceRegistrySharedPtr 77 | HdTriRenderDelegate::GetResourceRegistry() const 78 | { 79 | return _resourceRegistry; 80 | } 81 | 82 | HdRenderPassSharedPtr 83 | HdTriRenderDelegate::CreateRenderPass(HdRenderIndex* index, 84 | const HdRprimCollection& collection) 85 | { 86 | return HdRenderPassSharedPtr(new HdTriRenderPass(index, collection)); 87 | } 88 | 89 | void 90 | HdTriRenderDelegate::CommitResources(HdChangeTracker* tracker) 91 | { 92 | } 93 | 94 | HdRprim* 95 | HdTriRenderDelegate::CreateRprim(const TfToken& typeId, const SdfPath& rprimId) 96 | { 97 | TF_DEBUG(HDTRI_GENERAL) 98 | .Msg("[%s] Create HdTri Rprim type %s id %s\n", 99 | TF_FUNC_NAME().c_str(), 100 | typeId.GetText(), 101 | rprimId.GetText()); 102 | TF_CODING_ERROR( 103 | "Unknown Rprim type=%s id=%s", typeId.GetText(), rprimId.GetText()); 104 | return nullptr; 105 | } 106 | 107 | void 108 | HdTriRenderDelegate::DestroyRprim(HdRprim* rprim) 109 | { 110 | TF_DEBUG(HDTRI_GENERAL) 111 | .Msg("[%s] Destroy Rprim id %s\n", 112 | TF_FUNC_NAME().c_str(), 113 | rprim->GetId().GetText()); 114 | delete rprim; 115 | } 116 | 117 | HdSprim* 118 | HdTriRenderDelegate::CreateSprim(const TfToken& typeId, const SdfPath& sprimId) 119 | { 120 | if (typeId == HdPrimTypeTokens->camera) { 121 | return new HdCamera(sprimId); 122 | } else { 123 | TF_CODING_ERROR( 124 | "Unknown Sprim type=%s id=%s", typeId.GetText(), sprimId.GetText()); 125 | } 126 | return nullptr; 127 | } 128 | 129 | HdSprim* 130 | HdTriRenderDelegate::CreateFallbackSprim(const TfToken& typeId) 131 | { 132 | if (typeId == HdPrimTypeTokens->camera) { 133 | return new HdCamera(SdfPath::EmptyPath()); 134 | } else { 135 | TF_CODING_ERROR("Unknown Fallback Sprim type=%s id=%s", 136 | typeId.GetText(), 137 | typeId.GetText()); 138 | } 139 | return nullptr; 140 | } 141 | 142 | void 143 | HdTriRenderDelegate::DestroySprim(HdSprim* sprim) 144 | { 145 | delete sprim; 146 | } 147 | 148 | HdBprim* 149 | HdTriRenderDelegate::CreateBprim(const TfToken& typeId, const SdfPath& bprimId) 150 | { 151 | if (typeId == HdPrimTypeTokens->renderBuffer) { 152 | return new HdTriRenderBuffer(bprimId); 153 | } else { 154 | TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); 155 | } 156 | 157 | return nullptr; 158 | } 159 | 160 | HdBprim* 161 | HdTriRenderDelegate::CreateFallbackBprim(const TfToken& typeId) 162 | { 163 | if (typeId == HdPrimTypeTokens->renderBuffer) { 164 | return new HdTriRenderBuffer(SdfPath::EmptyPath()); 165 | } else { 166 | TF_CODING_ERROR("Unknown Bprim Type %s", typeId.GetText()); 167 | } 168 | 169 | return nullptr; 170 | } 171 | 172 | void 173 | HdTriRenderDelegate::DestroyBprim(HdBprim* bprim) 174 | { 175 | delete bprim; 176 | } 177 | 178 | HdInstancer* 179 | HdTriRenderDelegate::CreateInstancer(HdSceneDelegate* delegate, 180 | const SdfPath& id) 181 | { 182 | TF_CODING_ERROR("Creating Instancer not supported id=%s", id.GetText()); 183 | return nullptr; 184 | } 185 | 186 | void 187 | HdTriRenderDelegate::DestroyInstancer(HdInstancer* instancer) 188 | { 189 | TF_CODING_ERROR("Destroy instancer not supported"); 190 | } 191 | 192 | HdAovDescriptor 193 | HdTriRenderDelegate::GetDefaultAovDescriptor(const TfToken& aovName) const 194 | { 195 | if (aovName == HdAovTokens->color) { 196 | return HdAovDescriptor( 197 | HdFormatUNorm8Vec4, true, VtValue(GfVec4f(0.0f))); 198 | } else if (aovName == HdAovTokens->depth) { 199 | return HdAovDescriptor(HdFormatFloat32, false, VtValue(1.0f)); 200 | } else if (aovName == HdAovTokens->primId || 201 | aovName == HdAovTokens->instanceId || 202 | aovName == HdAovTokens->elementId) { 203 | return HdAovDescriptor(HdFormatInt32, false, VtValue(-1)); 204 | } 205 | 206 | return HdAovDescriptor(); 207 | } 208 | 209 | void 210 | HdTriRenderDelegate::_Setup() 211 | { 212 | _renderParam = std::unique_ptr(new HdTriRenderParam()); 213 | _resourceRegistry = 214 | std::shared_ptr(new HdResourceRegistry()); 215 | } 216 | 217 | PXR_NAMESPACE_CLOSE_SCOPE 218 | -------------------------------------------------------------------------------- /src/hdTri/renderDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | class HdTriRenderParam; 14 | 15 | /// \class HdTriRenderDelegate 16 | /// 17 | /// Hydra renderer interface for the tri renderer. 18 | class HdTriRenderDelegate final : public HdRenderDelegate 19 | { 20 | public: 21 | /// Default constructor. 22 | HdTriRenderDelegate(); 23 | 24 | /// Constructor with render settings. 25 | HdTriRenderDelegate(const HdRenderSettingsMap& settingsMap); 26 | 27 | /// Destrucutor. 28 | virtual ~HdTriRenderDelegate() override; 29 | 30 | /// Cannot copy. 31 | HdTriRenderDelegate(const HdTriRenderDelegate&) = delete; 32 | HdTriRenderDelegate& operator=(const HdTriRenderDelegate&) = delete; 33 | 34 | /// Query supported hydra prim types. 35 | virtual const TfTokenVector& GetSupportedRprimTypes() const override; 36 | virtual const TfTokenVector& GetSupportedSprimTypes() const override; 37 | virtual const TfTokenVector& GetSupportedBprimTypes() const override; 38 | 39 | /// Return this delegate's render param, which provides top-level scene 40 | /// state. 41 | /// \return An instance of HdEmbreeRenderParam. 42 | virtual HdRenderParam* GetRenderParam() const override; 43 | 44 | /// Returns a list of user-configurable render settings, available in the 45 | /// UI. 46 | virtual HdRenderSettingDescriptorList GetRenderSettingDescriptors() 47 | const override; 48 | 49 | /// Get the resource registry. 50 | virtual HdResourceRegistrySharedPtr GetResourceRegistry() const override; 51 | 52 | /// Create render pass. 53 | virtual HdRenderPassSharedPtr CreateRenderPass( 54 | HdRenderIndex* index, 55 | const HdRprimCollection& collection) override; 56 | 57 | /// Create an instancer. 58 | virtual HdInstancer* CreateInstancer(HdSceneDelegate* delegate, 59 | const SdfPath& id) override; 60 | 61 | /// Destroy an instancer. 62 | virtual void DestroyInstancer(HdInstancer* instancer) override; 63 | 64 | /// Create a new Rprim. 65 | virtual HdRprim* CreateRprim(const TfToken& typeId, 66 | const SdfPath& rprimId) override; 67 | 68 | virtual void DestroyRprim(HdRprim* rprim) override; 69 | 70 | /// Create a new Sprim. 71 | virtual HdSprim* CreateSprim(const TfToken& typeId, 72 | const SdfPath& sprimId) override; 73 | 74 | /// TODO. 75 | virtual HdSprim* CreateFallbackSprim(const TfToken& typeId) override; 76 | 77 | /// Destroy an existing Sprim. 78 | virtual void DestroySprim(HdSprim* sprim) override; 79 | 80 | /// Create a new buffer prim. 81 | virtual HdBprim* CreateBprim(const TfToken& typeId, 82 | const SdfPath& bprimId) override; 83 | 84 | /// Create a fallback buffer prim. 85 | virtual HdBprim* CreateFallbackBprim(const TfToken& typeId) override; 86 | 87 | /// Destroy an existing Bprim. 88 | virtual void DestroyBprim(HdBprim* bprim) override; 89 | 90 | /// Do work. 91 | virtual void CommitResources(HdChangeTracker* tracker) override; 92 | 93 | /// Return the AOV description for \param aovName. 94 | /// This will be used to initialize the aov buffers. 95 | virtual HdAovDescriptor GetDefaultAovDescriptor( 96 | const TfToken& aovName) const override; 97 | 98 | private: 99 | // Setup routine (used in both constructors). 100 | void _Setup(); 101 | 102 | static const TfTokenVector SUPPORTED_RPRIM_TYPES; 103 | static const TfTokenVector SUPPORTED_SPRIM_TYPES; 104 | static const TfTokenVector SUPPORTED_BPRIM_TYPES; 105 | 106 | std::unique_ptr _renderParam; 107 | HdRenderSettingDescriptorList _settingDescriptors; 108 | 109 | HdResourceRegistrySharedPtr _resourceRegistry; 110 | }; 111 | 112 | PXR_NAMESPACE_CLOSE_SCOPE 113 | -------------------------------------------------------------------------------- /src/hdTri/renderParam.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "renderParam.h" 7 | 8 | PXR_NAMESPACE_OPEN_SCOPE 9 | 10 | HdTriRenderParam::HdTriRenderParam() 11 | : HdRenderParam() 12 | { 13 | } 14 | 15 | PXR_NAMESPACE_CLOSE_SCOPE 16 | -------------------------------------------------------------------------------- /src/hdTri/renderParam.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | /// \class HdTriRenderParam 14 | /// 15 | /// Object created by the render delegate to transport top-level scene state 16 | /// to each prim during Sync(). 17 | class HdTriRenderParam final : public HdRenderParam 18 | { 19 | public: 20 | HdTriRenderParam(); 21 | virtual ~HdTriRenderParam() = default; 22 | }; 23 | 24 | PXR_NAMESPACE_CLOSE_SCOPE 25 | -------------------------------------------------------------------------------- /src/hdTri/renderPass.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "renderPass.h" 7 | #include "renderBuffer.h" 8 | #include "renderer.h" 9 | #include "debugCodes.h" 10 | 11 | #include 12 | #include 13 | 14 | PXR_NAMESPACE_OPEN_SCOPE 15 | 16 | HdTriRenderPass::HdTriRenderPass(HdRenderIndex* index, 17 | const HdRprimCollection& collection) 18 | : HdRenderPass(index, collection) 19 | { 20 | } 21 | 22 | HdTriRenderPass::~HdTriRenderPass() {} 23 | 24 | bool 25 | HdTriRenderPass::IsConverged() const 26 | { 27 | return _converged; 28 | } 29 | 30 | void 31 | HdTriRenderPass::_Execute(const HdRenderPassStateSharedPtr& renderPassState, 32 | const TfTokenVector& renderTags) 33 | { 34 | TF_DEBUG(HDTRI_GENERAL) 35 | .Msg("[%s] Executing render pass\n", TF_FUNC_NAME().c_str()); 36 | 37 | // Iterate over each AOV. 38 | HdRenderPassAovBindingVector aovBindings = 39 | renderPassState->GetAovBindings(); 40 | for (const HdRenderPassAovBinding& aovBinding : aovBindings) { 41 | 42 | // We will only write into the color AOV buffer. 43 | if (aovBinding.aovName == HdAovTokens->color) { 44 | HdTriRenderBuffer* renderBuffer = 45 | static_cast(aovBinding.renderBuffer); 46 | HdTriRenderer::DrawTriangle(renderBuffer); 47 | } 48 | } 49 | 50 | _converged = true; 51 | } 52 | 53 | PXR_NAMESPACE_CLOSE_SCOPE 54 | -------------------------------------------------------------------------------- /src/hdTri/renderPass.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | 10 | PXR_NAMESPACE_OPEN_SCOPE 11 | 12 | /// \class HdTriRenderPass 13 | /// 14 | /// Represents a single iteration of a render. 15 | class HdTriRenderPass final : public HdRenderPass 16 | { 17 | public: 18 | HdTriRenderPass(HdRenderIndex* index, const HdRprimCollection& collection); 19 | virtual ~HdTriRenderPass(); 20 | 21 | protected: 22 | /// Draw the scene with the bound renderpass state. 23 | /// 24 | /// \param renderPassState Input parameters (including viewer parameters) 25 | /// for this renderpass. \param renderTags Which rendertags should be drawn 26 | /// this pass. 27 | virtual void _Execute(const HdRenderPassStateSharedPtr& renderPassState, 28 | const TfTokenVector& renderTags) override; 29 | 30 | /// Determine whether the sample buffer has enough samples, to be considered 31 | /// final. 32 | virtual bool IsConverged() const override; 33 | 34 | private: 35 | // Is converged? 36 | bool _converged = false; 37 | }; 38 | 39 | PXR_NAMESPACE_CLOSE_SCOPE 40 | -------------------------------------------------------------------------------- /src/hdTri/renderer.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "renderBuffer.h" 7 | #include "renderer.h" 8 | 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | // 2D operation for checking if a point is inside a triangle. 14 | static bool 15 | _PointInsideTriangle(const GfVec2f& point, const GfVec2f triangle[3]) 16 | { 17 | float dX = point[0] - triangle[2][0]; 18 | float dY = point[1] - triangle[2][1]; 19 | float dX21 = triangle[2][0] - triangle[1][0]; 20 | float dY12 = triangle[1][1] - triangle[2][1]; 21 | float D = dY12 * (triangle[0][0] - triangle[2][0]) + 22 | dX21 * (triangle[0][1] - triangle[2][1]); 23 | float s = dY12 * dX + dX21 * dY; 24 | float t = (triangle[2][1] - triangle[0][1]) * dX + 25 | (triangle[0][0] - triangle[2][0]) * dY; 26 | if (D < 0) { 27 | return s <= 0 && t <= 0 && s + t >= D; 28 | } else { 29 | return s >= 0 && t >= 0 && s + t <= D; 30 | } 31 | } 32 | 33 | void 34 | HdTriRenderer::DrawTriangle(HdTriRenderBuffer* colorBuffer) 35 | { 36 | // Gather format information. 37 | // (size of each pixel, and of each pixel component). 38 | HdFormat format = colorBuffer->GetFormat(); 39 | size_t formatSize = HdDataSizeOfFormat(format); 40 | size_t componentCount = HdGetComponentCount(format); 41 | 42 | // Begin buffer write. 43 | uint8_t* buffer = static_cast(colorBuffer->Map()); 44 | 45 | // Compute raster-space coordinates composing a equilateral 46 | // triangle, whose sideLength is proportionate to the buffer width. 47 | float sideLength = (float)colorBuffer->GetWidth() * 0.45f; 48 | GfVec2f centerOffset((float)colorBuffer->GetWidth() * 0.5f, 49 | (float)colorBuffer->GetHeight() * 0.41f); 50 | GfVec2f trianglePoints[3] = { 51 | GfVec2f(0.0f, 0.57735027f * sideLength) + centerOffset, 52 | GfVec2f(-0.5f * sideLength, -0.28867513f * sideLength) + centerOffset, 53 | GfVec2f(0.5f * sideLength, -0.28867513f * sideLength) + centerOffset 54 | }; 55 | 56 | // Iterate over all raster coordinates. 57 | for (uint32_t y = 0; y < colorBuffer->GetHeight(); ++y) { 58 | for (uint32_t x = 0; x < colorBuffer->GetWidth(); ++x) { 59 | // Compute the raster index (pixel) offset. 60 | uint32_t bufferIndex = (y * colorBuffer->GetWidth()) + x; 61 | 62 | // Compute the byte offset, based on raster format. 63 | uint8_t* dst = &buffer[bufferIndex * formatSize]; 64 | 65 | // Check if the raster coordinate is inside the 2D triangle. 66 | GfVec2f rasterCoord(x, y); 67 | if (_PointInsideTriangle(rasterCoord, trianglePoints)) { 68 | // Fill with white color. 69 | for (size_t c = 0; c < componentCount; ++c) { 70 | dst[c] = 255; 71 | } 72 | } 73 | } 74 | } 75 | 76 | // End buffer write. 77 | colorBuffer->Unmap(); 78 | } 79 | 80 | PXR_NAMESPACE_CLOSE_SCOPE 81 | -------------------------------------------------------------------------------- /src/hdTri/renderer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | PXR_NAMESPACE_OPEN_SCOPE 9 | 10 | // Forward declarations. 11 | class HdTriRenderBuffer; 12 | 13 | /// \class HdTriRenderer 14 | /// 15 | /// A triangle renderer. 16 | class HdTriRenderer final 17 | { 18 | public: 19 | /// Draw a triangle into a color buffer. 20 | /// 21 | /// \param colorBuffer A 2D color buffer. 22 | static void DrawTriangle(HdTriRenderBuffer* colorBuffer); 23 | }; 24 | 25 | PXR_NAMESPACE_CLOSE_SCOPE 26 | -------------------------------------------------------------------------------- /src/hdTri/rendererPlugin.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "renderDelegate.h" 7 | #include "rendererPlugin.h" 8 | 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | TF_REGISTRY_FUNCTION(TfType) 14 | { 15 | HdRendererPluginRegistry::Define(); 16 | } 17 | 18 | HdRenderDelegate* 19 | HdTriRendererPlugin::CreateRenderDelegate() 20 | { 21 | return new HdTriRenderDelegate(); 22 | } 23 | 24 | void 25 | HdTriRendererPlugin::DeleteRenderDelegate(HdRenderDelegate* renderDelegate) 26 | { 27 | delete renderDelegate; 28 | } 29 | 30 | bool 31 | HdTriRendererPlugin::IsSupported(bool gpuEnabled) const 32 | { 33 | return true; 34 | } 35 | 36 | PXR_NAMESPACE_CLOSE_SCOPE 37 | -------------------------------------------------------------------------------- /src/hdTri/rendererPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | 10 | PXR_NAMESPACE_OPEN_SCOPE 11 | 12 | /// Plugin entry points (construction, destruction) for the tri render delegate. 13 | class HdTriRendererPlugin final : public HdRendererPlugin 14 | { 15 | public: 16 | HdTriRendererPlugin() = default; 17 | ~HdTriRendererPlugin() override = default; 18 | 19 | /// Cannot copy. 20 | HdTriRendererPlugin(const HdTriRendererPlugin&) = delete; 21 | HdTriRendererPlugin& operator=(const HdTriRendererPlugin&) = delete; 22 | 23 | /// Create a new tri render delegate instance. 24 | virtual HdRenderDelegate* CreateRenderDelegate() override; 25 | 26 | /// Delete a tri render delegate instance. 27 | virtual void DeleteRenderDelegate( 28 | HdRenderDelegate* renderDelegate) override; 29 | 30 | /// Is this plugin supported? 31 | virtual bool IsSupported(bool gpuEnabled = true) const override; 32 | }; 33 | 34 | PXR_NAMESPACE_CLOSE_SCOPE 35 | -------------------------------------------------------------------------------- /src/plugInfo.json: -------------------------------------------------------------------------------- 1 | # Used as the root plugInfo for including all other plugInfo(s). 2 | { 3 | "Includes": [ 4 | "*/resources/" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/usdTri/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_library(usdTri 2 | 3 | PUBLIC_HEADERS_INSTALL_PREFIX 4 | ${ORGANIZATION} 5 | 6 | PYTHON_INSTALL_PREFIX 7 | ${ORGANIZATION} 8 | 9 | LIBRARIES 10 | js 11 | plug 12 | tf 13 | sdf 14 | vt 15 | gf 16 | usd 17 | usdGeom 18 | arch 19 | 20 | PUBLIC_CLASSES 21 | triangle 22 | 23 | PUBLIC_HEADERS 24 | api.h 25 | tokens.h 26 | 27 | CPPFILES 28 | tokens.cpp 29 | 30 | PYTHON_CPPFILES 31 | moduleDeps.cpp 32 | 33 | PYMODULE_CPPFILES 34 | module.cpp 35 | wrapTokens.cpp 36 | wrapTriangle.cpp 37 | 38 | PYTHON_FILES 39 | __init__.py 40 | 41 | RESOURCE_FILES 42 | generatedSchema.usda 43 | plugInfo.json 44 | ) 45 | 46 | usd_executable(triangleCounter 47 | 48 | CPPFILES 49 | triangleCounter.cpp 50 | 51 | LIBRARIES 52 | tf 53 | sdf 54 | usd 55 | usdTri 56 | ) 57 | 58 | add_subdirectory(tests) 59 | -------------------------------------------------------------------------------- /src/usdTri/__init__.py: -------------------------------------------------------------------------------- 1 | from pxr import Tf 2 | Tf.PreparePythonModule() 3 | del Tf 4 | -------------------------------------------------------------------------------- /src/usdTri/api.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #ifndef USDTRI_API_H 7 | #define USDTRI_API_H 8 | 9 | #include "pxr/base/arch/export.h" 10 | 11 | #if defined(PXR_STATIC) 12 | # define USDTRI_API 13 | # define USDTRI_API_TEMPLATE_CLASS(...) 14 | # define USDTRI_API_TEMPLATE_STRUCT(...) 15 | # define USDTRI_LOCAL 16 | #else 17 | # if defined(USDTRI_EXPORTS) 18 | # define USDTRI_API ARCH_EXPORT 19 | # define USDTRI_API_TEMPLATE_CLASS(...) \ 20 | ARCH_EXPORT_TEMPLATE(class, __VA_ARGS__) 21 | # define USDTRI_API_TEMPLATE_STRUCT(...) \ 22 | ARCH_EXPORT_TEMPLATE(struct, __VA_ARGS__) 23 | # else 24 | # define USDTRI_API ARCH_IMPORT 25 | # define USDTRI_API_TEMPLATE_CLASS(...) \ 26 | ARCH_IMPORT_TEMPLATE(class, __VA_ARGS__) 27 | # define USDTRI_API_TEMPLATE_STRUCT(...) \ 28 | ARCH_IMPORT_TEMPLATE(struct, __VA_ARGS__) 29 | # endif 30 | # define USDTRI_LOCAL ARCH_HIDDEN 31 | #endif 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/usdTri/generatedSchema.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | "WARNING: THIS FILE IS GENERATED BY usdGenSchema. DO NOT EDIT." 4 | ) 5 | 6 | class Triangle "Triangle" ( 7 | doc = """An equilateral triangle, whose vertices are equidistant to the 8 | origin and lie on the XY plane in object-space.""" 9 | ) 10 | { 11 | uniform bool doubleSided = 0 ( 12 | doc = """Although some renderers treat all parametric or polygonal 13 | surfaces as if they were effectively laminae with outward-facing 14 | normals on both sides, some renderers derive significant optimizations 15 | by considering these surfaces to have only a single outward side, 16 | typically determined by control-point winding order and/or 17 | orientation. By doing so they can perform \"backface culling\" to 18 | avoid drawing the many polygons of most closed surfaces that face away 19 | from the viewer. 20 | 21 | However, it is often advantageous to model thin objects such as paper 22 | and cloth as single, open surfaces that must be viewable from both 23 | sides, always. Setting a gprim's doubleSided attribute to 24 | \\c true instructs all renderers to disable optimizations such as 25 | backface culling for the gprim, and attempt (not all renderers are able 26 | to do so, but the USD reference GL renderer always will) to provide 27 | forward-facing normals on each side of the surface for lighting 28 | calculations.""" 29 | ) 30 | float3[] extent = [(-0.5, -0.28867513, 0), (0.5, 0.57735026, 0)] ( 31 | doc = "Fallback extent value of a triangle with side length of 1.0." 32 | ) 33 | uniform token orientation = "rightHanded" ( 34 | allowedTokens = ["rightHanded", "leftHanded"] 35 | doc = """Orientation specifies whether the gprim's surface normal 36 | should be computed using the right hand rule, or the left hand rule. 37 | Please see for a deeper explanation and 38 | generalization of orientation to composed scenes with transformation 39 | hierarchies.""" 40 | ) 41 | color3f[] primvars:displayColor ( 42 | doc = '''It is useful to have an "official" colorSet that can be used 43 | as a display or modeling color, even in the absence of any specified 44 | shader for a gprim. DisplayColor serves this role; because it is a 45 | UsdGeomPrimvar, it can also be used as a gprim override for any shader 46 | that consumes a displayColor parameter.''' 47 | ) 48 | float[] primvars:displayOpacity ( 49 | doc = """Companion to displayColor that specifies opacity, broken 50 | out as an independent attribute rather than an rgba color, both so that 51 | each can be independently overridden, and because shaders rarely consume 52 | rgba parameters.""" 53 | ) 54 | rel proxyPrim ( 55 | doc = '''The proxyPrim relationship allows us to link a 56 | prim whose purpose is "render" to its (single target) 57 | purpose="proxy" prim. This is entirely optional, but can be 58 | useful in several scenarios: 59 | 60 | - In a pipeline that does pruning (for complexity management) 61 | by deactivating prims composed from asset references, when we 62 | deactivate a purpose="render" prim, we will be able to discover 63 | and additionally deactivate its associated purpose="proxy" prim, 64 | so that preview renders reflect the pruning accurately. 65 | 66 | - DCC importers may be able to make more aggressive optimizations 67 | for interactive processing and display if they can discover the proxy 68 | for a given render prim. 69 | 70 | - With a little more work, a Hydra-based application will be able 71 | to map a picked proxy prim back to its render geometry for selection. 72 | 73 | \\note It is only valid to author the proxyPrim relationship on 74 | prims whose purpose is "render".''' 75 | ) 76 | uniform token purpose = "default" ( 77 | allowedTokens = ["default", "render", "proxy", "guide"] 78 | doc = """Purpose is a classification of geometry into categories that 79 | can each be independently included or excluded from traversals of prims 80 | on a stage, such as rendering or bounding-box computation traversals. 81 | 82 | See for more detail about how 83 | purpose is computed and used.""" 84 | ) 85 | double sideLength = 1 ( 86 | doc = "The length of each side of the equilateral triangle." 87 | ) 88 | token visibility = "inherited" ( 89 | allowedTokens = ["inherited", "invisible"] 90 | doc = '''Visibility is meant to be the simplest form of "pruning" 91 | visibility that is supported by most DCC apps. Visibility is 92 | animatable, allowing a sub-tree of geometry to be present for some 93 | segment of a shot, and absent from others; unlike the action of 94 | deactivating geometry prims, invisible geometry is still 95 | available for inspection, for positioning, for defining volumes, etc.''' 96 | ) 97 | uniform token[] xformOpOrder ( 98 | doc = """Encodes the sequence of transformation operations in the 99 | order in which they should be pushed onto a transform stack while 100 | visiting a UsdStage's prims in a graph traversal that will effect 101 | the desired positioning for this prim and its descendant prims. 102 | 103 | You should rarely, if ever, need to manipulate this attribute directly. 104 | It is managed by the AddXformOp(), SetResetXformStack(), and 105 | SetXformOpOrder(), and consulted by GetOrderedXformOps() and 106 | GetLocalTransformation().""" 107 | ) 108 | } 109 | 110 | -------------------------------------------------------------------------------- /src/usdTri/module.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include 7 | #include 8 | 9 | // Definition of the _usdTri python module, with associated classes and 10 | // functions. 11 | 12 | PXR_NAMESPACE_USING_DIRECTIVE 13 | 14 | TF_WRAP_MODULE 15 | { 16 | TF_WRAP(UsdTriTriangle); 17 | } 18 | -------------------------------------------------------------------------------- /src/usdTri/moduleDeps.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | PXR_NAMESPACE_OPEN_SCOPE 14 | 15 | TF_REGISTRY_FUNCTION(TfScriptModuleLoader) 16 | { 17 | // List of direct dependencies for this library. 18 | const std::vector reqs = { 19 | TfToken("js"), TfToken("plug"), TfToken("sdf"), 20 | TfToken("tf"), TfToken("trace"), TfToken("usd"), 21 | TfToken("vt"), TfToken("work"), TfToken("usdGeom"), 22 | }; 23 | TfScriptModuleLoader::GetInstance().RegisterLibrary( 24 | TfToken("usdTri"), TfToken("usdpluginexamples.UsdTri"), reqs); 25 | } 26 | 27 | PXR_NAMESPACE_CLOSE_SCOPE 28 | -------------------------------------------------------------------------------- /src/usdTri/plugInfo.json: -------------------------------------------------------------------------------- 1 | # Portions of this file auto-generated by usdGenSchema. 2 | # Edits will survive regeneration except for comments and 3 | # changes to types with autoGenerated=true. 4 | { 5 | "Plugins": [ 6 | { 7 | "Info": { 8 | "Types": { 9 | "UsdTriTriangle": { 10 | "alias": { 11 | "UsdSchemaBase": "Triangle" 12 | }, 13 | "autoGenerated": true, 14 | "bases": [ 15 | "UsdGeomGprim" 16 | ], 17 | "implementsComputeExtent": true, 18 | "schemaKind": "concreteTyped" 19 | } 20 | } 21 | }, 22 | "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", 23 | "Name": "usdTri", 24 | "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@", 25 | "Root": "@PLUG_INFO_ROOT@", 26 | "Type": "library" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/usdTri/scenes/expandingTriangle.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | defaultPrim = "triangle" 4 | endTimeCode = 10 5 | startTimeCode = 1 6 | ) 7 | 8 | def Triangle "triangle" 9 | { 10 | double sideLength.timeSamples = { 11 | 1: 1, 12 | 10: 10, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/usdTri/scenes/triangle.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | defaultPrim = "triangle" 4 | ) 5 | 6 | def Triangle "triangle" 7 | { 8 | } 9 | -------------------------------------------------------------------------------- /src/usdTri/schema.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | ( 3 | subLayers = [ 4 | @usdGeom/schema.usda@ 5 | ] 6 | ) 7 | 8 | over "GLOBAL" ( 9 | customData = { 10 | string libraryName = "usdTri" 11 | string libraryPath = "." 12 | string libraryPrefix = "UsdTri" 13 | } 14 | ) { 15 | } 16 | 17 | class Triangle "Triangle" ( 18 | doc = """An equilateral triangle, whose vertices are equidistant to the 19 | origin and lie on the XY plane in object-space.""" 20 | inherits = 21 | 22 | customData = { 23 | dictionary extraPlugInfo = { 24 | bool implementsComputeExtent = true 25 | } 26 | } 27 | ) { 28 | double sideLength = 1.0 ( 29 | doc = """The length of each side of the equilateral triangle.""" 30 | ) 31 | 32 | float3[] extent = [(-0.5, -0.28867513, 0.0), (0.5, 0.57735027, 0.0)] ( 33 | doc = """Fallback extent value of a triangle with side length of 1.0.""" 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/usdTri/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_python_test(usdTri_python_testTriangle 2 | testTriangle.py 3 | ) 4 | 5 | usd_test(usdTri_testTriangle 6 | 7 | CPPFILES 8 | testTriangle.cpp 9 | 10 | LIBRARIES 11 | tf 12 | sdf 13 | usd 14 | usdGeom 15 | usdTri 16 | ) 17 | -------------------------------------------------------------------------------- /src/usdTri/tests/testTriangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include 7 | #include 8 | #include 9 | 10 | PXR_NAMESPACE_USING_DIRECTIVE 11 | 12 | int 13 | main(int argc, char* argv[]) 14 | { 15 | // Create a new stage. 16 | UsdStageRefPtr stage = UsdStage::CreateInMemory(); 17 | 18 | // Define a Triangle. 19 | UsdTriTriangle triangle = 20 | UsdTriTriangle::Define(stage, SdfPath("/myTriangle")); 21 | TF_AXIOM(triangle); 22 | 23 | // Validate side length attr fallback value. 24 | double sideLength; 25 | TF_AXIOM(triangle.GetSideLengthAttr().Get(&sideLength)); 26 | TF_AXIOM(sideLength == 1.0f); 27 | 28 | return EXIT_SUCCESS; 29 | } 30 | -------------------------------------------------------------------------------- /src/usdTri/tests/testTriangle.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from pxr import Gf, Vt, Usd, UsdGeom 3 | from usdpluginexamples import UsdTri 4 | 5 | 6 | class TestTriangle(unittest.TestCase): 7 | def testComputeExtent(self): 8 | # Create a stage. 9 | stage = Usd.Stage.CreateInMemory() 10 | 11 | # Define a Triangle. 12 | triangle = UsdTri.Triangle.Define(stage, "/triangle") 13 | self.assertTrue(triangle) 14 | self.assertEqual(triangle.GetSideLengthAttr().Get(), 1) 15 | 16 | # Compute extent & validate. 17 | boundable = UsdGeom.Boundable(triangle.GetPrim()) 18 | self.assertTrue(boundable) 19 | extent = UsdGeom.Boundable.ComputeExtentFromPlugins( 20 | boundable, Usd.TimeCode.Default() 21 | ) 22 | expectedExtent = Vt.Vec3fArray(((0.5, -0.28867513, 0), (0.5, 0.57735026, 0))) 23 | for actualValue, expectedValue in zip(extent, expectedExtent): 24 | self.assertTrue(Gf.IsClose(actualValue, expectedValue, 1e-5)) 25 | 26 | 27 | if __name__ == "__main__": 28 | unittest.main() 29 | -------------------------------------------------------------------------------- /src/usdTri/tokens.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "./tokens.h" 7 | 8 | PXR_NAMESPACE_OPEN_SCOPE 9 | 10 | UsdTriTokensType::UsdTriTokensType() 11 | : extent("extent", TfToken::Immortal) 12 | , sideLength("sideLength", TfToken::Immortal) 13 | , Triangle("Triangle", TfToken::Immortal) 14 | , allTokens({ extent, sideLength, Triangle }) 15 | { 16 | } 17 | 18 | TfStaticData UsdTriTokens; 19 | 20 | PXR_NAMESPACE_CLOSE_SCOPE 21 | -------------------------------------------------------------------------------- /src/usdTri/tokens.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #ifndef USDTRI_TOKENS_H 7 | #define USDTRI_TOKENS_H 8 | 9 | /// \file usdTri/tokens.h 10 | 11 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 12 | // 13 | // This is an automatically generated file (by usdGenSchema.py). 14 | // Do not hand-edit! 15 | // 16 | // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 17 | 18 | #include "pxr/pxr.h" 19 | #include "./api.h" 20 | #include "pxr/base/tf/staticData.h" 21 | #include "pxr/base/tf/token.h" 22 | #include 23 | 24 | PXR_NAMESPACE_OPEN_SCOPE 25 | 26 | /// \class UsdTriTokensType 27 | /// 28 | /// \link UsdTriTokens \endlink provides static, efficient 29 | /// \link TfToken TfTokens\endlink for use in all public USD API. 30 | /// 31 | /// These tokens are auto-generated from the module's schema, representing 32 | /// property names, for when you need to fetch an attribute or relationship 33 | /// directly by name, e.g. UsdPrim::GetAttribute(), in the most efficient 34 | /// manner, and allow the compiler to verify that you spelled the name 35 | /// correctly. 36 | /// 37 | /// UsdTriTokens also contains all of the \em allowedTokens values 38 | /// declared for schema builtin attributes of 'token' scene description type. 39 | /// Use UsdTriTokens like so: 40 | /// 41 | /// \code 42 | /// gprim.GetMyTokenValuedAttr().Set(UsdTriTokens->extent); 43 | /// \endcode 44 | struct UsdTriTokensType 45 | { 46 | USDTRI_API UsdTriTokensType(); 47 | /// \brief "extent" 48 | /// 49 | /// UsdTriTriangle 50 | const TfToken extent; 51 | /// \brief "sideLength" 52 | /// 53 | /// UsdTriTriangle 54 | const TfToken sideLength; 55 | /// \brief "Triangle" 56 | /// 57 | /// Schema identifer and family for UsdTriTriangle 58 | const TfToken Triangle; 59 | /// A vector of all of the tokens listed above. 60 | const std::vector allTokens; 61 | }; 62 | 63 | /// \var UsdTriTokens 64 | /// 65 | /// A global variable with static, efficient \link TfToken TfTokens\endlink 66 | /// for use in all public USD API. \sa UsdTriTokensType 67 | extern USDTRI_API TfStaticData UsdTriTokens; 68 | 69 | PXR_NAMESPACE_CLOSE_SCOPE 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/usdTri/triangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "./triangle.h" 7 | #include "pxr/usd/usd/schemaRegistry.h" 8 | #include "pxr/usd/usd/typed.h" 9 | 10 | #include "pxr/usd/sdf/types.h" 11 | #include "pxr/usd/sdf/assetPath.h" 12 | 13 | PXR_NAMESPACE_OPEN_SCOPE 14 | 15 | // Register the schema with the TfType system. 16 | TF_REGISTRY_FUNCTION(TfType) 17 | { 18 | TfType::Define>(); 19 | 20 | // Register the usd prim typename as an alias under UsdSchemaBase. This 21 | // enables one to call 22 | // TfType::Find().FindDerivedByName("Triangle") 23 | // to find TfType, which is how IsA queries are 24 | // answered. 25 | TfType::AddAlias("Triangle"); 26 | } 27 | 28 | /* virtual */ 29 | UsdTriTriangle::~UsdTriTriangle() {} 30 | 31 | /* static */ 32 | UsdTriTriangle 33 | UsdTriTriangle::Get(const UsdStagePtr& stage, const SdfPath& path) 34 | { 35 | if (!stage) { 36 | TF_CODING_ERROR("Invalid stage"); 37 | return UsdTriTriangle(); 38 | } 39 | return UsdTriTriangle(stage->GetPrimAtPath(path)); 40 | } 41 | 42 | /* static */ 43 | UsdTriTriangle 44 | UsdTriTriangle::Define(const UsdStagePtr& stage, const SdfPath& path) 45 | { 46 | static TfToken usdPrimTypeName("Triangle"); 47 | if (!stage) { 48 | TF_CODING_ERROR("Invalid stage"); 49 | return UsdTriTriangle(); 50 | } 51 | return UsdTriTriangle(stage->DefinePrim(path, usdPrimTypeName)); 52 | } 53 | 54 | /* virtual */ 55 | UsdSchemaKind 56 | UsdTriTriangle::_GetSchemaKind() const 57 | { 58 | return UsdTriTriangle::schemaKind; 59 | } 60 | 61 | /* static */ 62 | const TfType& 63 | UsdTriTriangle::_GetStaticTfType() 64 | { 65 | static TfType tfType = TfType::Find(); 66 | return tfType; 67 | } 68 | 69 | /* static */ 70 | bool 71 | UsdTriTriangle::_IsTypedSchema() 72 | { 73 | static bool isTyped = _GetStaticTfType().IsA(); 74 | return isTyped; 75 | } 76 | 77 | /* virtual */ 78 | const TfType& 79 | UsdTriTriangle::_GetTfType() const 80 | { 81 | return _GetStaticTfType(); 82 | } 83 | 84 | UsdAttribute 85 | UsdTriTriangle::GetSideLengthAttr() const 86 | { 87 | return GetPrim().GetAttribute(UsdTriTokens->sideLength); 88 | } 89 | 90 | UsdAttribute 91 | UsdTriTriangle::CreateSideLengthAttr(VtValue const& defaultValue, 92 | bool writeSparsely) const 93 | { 94 | return UsdSchemaBase::_CreateAttr(UsdTriTokens->sideLength, 95 | SdfValueTypeNames->Double, 96 | /* custom = */ false, 97 | SdfVariabilityVarying, 98 | defaultValue, 99 | writeSparsely); 100 | } 101 | 102 | UsdAttribute 103 | UsdTriTriangle::GetExtentAttr() const 104 | { 105 | return GetPrim().GetAttribute(UsdTriTokens->extent); 106 | } 107 | 108 | UsdAttribute 109 | UsdTriTriangle::CreateExtentAttr(VtValue const& defaultValue, 110 | bool writeSparsely) const 111 | { 112 | return UsdSchemaBase::_CreateAttr(UsdTriTokens->extent, 113 | SdfValueTypeNames->Float3Array, 114 | /* custom = */ false, 115 | SdfVariabilityVarying, 116 | defaultValue, 117 | writeSparsely); 118 | } 119 | 120 | namespace { 121 | static inline TfTokenVector 122 | _ConcatenateAttributeNames(const TfTokenVector& left, 123 | const TfTokenVector& right) 124 | { 125 | TfTokenVector result; 126 | result.reserve(left.size() + right.size()); 127 | result.insert(result.end(), left.begin(), left.end()); 128 | result.insert(result.end(), right.begin(), right.end()); 129 | return result; 130 | } 131 | } 132 | 133 | /*static*/ 134 | const TfTokenVector& 135 | UsdTriTriangle::GetSchemaAttributeNames(bool includeInherited) 136 | { 137 | static TfTokenVector localNames = { 138 | UsdTriTokens->sideLength, 139 | UsdTriTokens->extent, 140 | }; 141 | static TfTokenVector allNames = _ConcatenateAttributeNames( 142 | UsdGeomGprim::GetSchemaAttributeNames(true), localNames); 143 | 144 | if (includeInherited) 145 | return allNames; 146 | else 147 | return localNames; 148 | } 149 | 150 | PXR_NAMESPACE_CLOSE_SCOPE 151 | 152 | // ===================================================================== // 153 | // Feel free to add custom code below this line. It will be preserved by 154 | // the code generator. 155 | // 156 | // Just remember to wrap code in the appropriate delimiters: 157 | // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'. 158 | // ===================================================================== // 159 | // --(BEGIN CUSTOM CODE)-- 160 | 161 | #include "pxr/usd/usdGeom/boundableComputeExtent.h" 162 | #include "pxr/base/tf/registryManager.h" 163 | 164 | PXR_NAMESPACE_OPEN_SCOPE 165 | 166 | bool 167 | UsdTriTriangle::ComputeExtent(double sideLength, VtVec3fArray* extent) 168 | { 169 | extent->resize(2); 170 | 171 | (*extent)[0] = GfVec3f(0.5 * sideLength, -0.28867513 * sideLength, 0.0); 172 | (*extent)[1] = GfVec3f(0.5 * sideLength, 0.57735027 * sideLength, 0.0); 173 | 174 | return true; 175 | } 176 | 177 | bool 178 | UsdTriTriangle::ComputeExtent(double sideLength, 179 | const GfMatrix4d& transform, 180 | VtVec3fArray* extent) 181 | { 182 | extent->resize(2); 183 | 184 | GfBBox3d bbox = GfBBox3d( 185 | GfRange3d(GfVec3d(-0.5 * sideLength, -0.28867513 * sideLength, 0.0), 186 | GfVec3d(0.5 * sideLength, 0.57735027 * sideLength, 0.0)), 187 | transform); 188 | GfRange3d range = bbox.ComputeAlignedRange(); 189 | (*extent)[0] = GfVec3f(range.GetMin()); 190 | (*extent)[1] = GfVec3f(range.GetMax()); 191 | 192 | return true; 193 | } 194 | 195 | static bool 196 | _ComputeExtentForTriangle(const UsdGeomBoundable& boundable, 197 | const UsdTimeCode& time, 198 | const GfMatrix4d* transform, 199 | VtVec3fArray* extent) 200 | { 201 | const UsdTriTriangle triangle(boundable); 202 | if (!TF_VERIFY(triangle)) { 203 | return false; 204 | } 205 | 206 | double sideLength; 207 | if (!triangle.GetSideLengthAttr().Get(&sideLength, time)) { 208 | return false; 209 | } 210 | 211 | if (transform) { 212 | return UsdTriTriangle::ComputeExtent(sideLength, *transform, extent); 213 | } else { 214 | return UsdTriTriangle::ComputeExtent(sideLength, extent); 215 | } 216 | } 217 | 218 | TF_REGISTRY_FUNCTION(UsdGeomBoundable) 219 | { 220 | UsdGeomRegisterComputeExtentFunction( 221 | _ComputeExtentForTriangle); 222 | } 223 | 224 | PXR_NAMESPACE_CLOSE_SCOPE 225 | -------------------------------------------------------------------------------- /src/usdTri/triangle.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #ifndef USDTRI_GENERATED_TRIANGLE_H 7 | #define USDTRI_GENERATED_TRIANGLE_H 8 | 9 | /// \file usdTri/triangle.h 10 | 11 | #include "pxr/pxr.h" 12 | #include "./api.h" 13 | #include "pxr/usd/usdGeom/gprim.h" 14 | #include "pxr/usd/usd/prim.h" 15 | #include "pxr/usd/usd/stage.h" 16 | #include "./tokens.h" 17 | 18 | #include "pxr/base/vt/value.h" 19 | 20 | #include "pxr/base/gf/vec3d.h" 21 | #include "pxr/base/gf/vec3f.h" 22 | #include "pxr/base/gf/matrix4d.h" 23 | 24 | #include "pxr/base/tf/token.h" 25 | #include "pxr/base/tf/type.h" 26 | 27 | PXR_NAMESPACE_OPEN_SCOPE 28 | 29 | class SdfAssetPath; 30 | 31 | // -------------------------------------------------------------------------- // 32 | // TRIANGLE // 33 | // -------------------------------------------------------------------------- // 34 | 35 | /// \class UsdTriTriangle 36 | /// 37 | /// An equilateral triangle, whose vertices are equidistant to the 38 | /// origin and lie on the XY plane in object-space. 39 | /// 40 | class UsdTriTriangle : public UsdGeomGprim 41 | { 42 | public: 43 | /// Compile time constant representing what kind of schema this class is. 44 | /// 45 | /// \sa UsdSchemaKind 46 | static const UsdSchemaKind schemaKind = UsdSchemaKind::ConcreteTyped; 47 | 48 | /// Construct a UsdTriTriangle on UsdPrim \p prim . 49 | /// Equivalent to UsdTriTriangle::Get(prim.GetStage(), prim.GetPath()) 50 | /// for a \em valid \p prim, but will not immediately throw an error for 51 | /// an invalid \p prim 52 | explicit UsdTriTriangle(const UsdPrim& prim = UsdPrim()) 53 | : UsdGeomGprim(prim) 54 | { 55 | } 56 | 57 | /// Construct a UsdTriTriangle on the prim held by \p schemaObj . 58 | /// Should be preferred over UsdTriTriangle(schemaObj.GetPrim()), 59 | /// as it preserves SchemaBase state. 60 | explicit UsdTriTriangle(const UsdSchemaBase& schemaObj) 61 | : UsdGeomGprim(schemaObj) 62 | { 63 | } 64 | 65 | /// Destructor. 66 | USDTRI_API 67 | virtual ~UsdTriTriangle(); 68 | 69 | /// Return a vector of names of all pre-declared attributes for this schema 70 | /// class and all its ancestor classes. Does not include attributes that 71 | /// may be authored by custom/extended methods of the schemas involved. 72 | USDTRI_API 73 | static const TfTokenVector& GetSchemaAttributeNames( 74 | bool includeInherited = true); 75 | 76 | /// Return a UsdTriTriangle holding the prim adhering to this 77 | /// schema at \p path on \p stage. If no prim exists at \p path on 78 | /// \p stage, or if the prim at that path does not adhere to this schema, 79 | /// return an invalid schema object. This is shorthand for the following: 80 | /// 81 | /// \code 82 | /// UsdTriTriangle(stage->GetPrimAtPath(path)); 83 | /// \endcode 84 | /// 85 | USDTRI_API 86 | static UsdTriTriangle Get(const UsdStagePtr& stage, const SdfPath& path); 87 | 88 | /// Attempt to ensure a \a UsdPrim adhering to this schema at \p path 89 | /// is defined (according to UsdPrim::IsDefined()) on this stage. 90 | /// 91 | /// If a prim adhering to this schema at \p path is already defined on this 92 | /// stage, return that prim. Otherwise author an \a SdfPrimSpec with 93 | /// \a specifier == \a SdfSpecifierDef and this schema's prim type name for 94 | /// the prim at \p path at the current EditTarget. Author \a SdfPrimSpec s 95 | /// with \p specifier == \a SdfSpecifierDef and empty typeName at the 96 | /// current EditTarget for any nonexistent, or existing but not \a Defined 97 | /// ancestors. 98 | /// 99 | /// The given \a path must be an absolute prim path that does not contain 100 | /// any variant selections. 101 | /// 102 | /// If it is impossible to author any of the necessary PrimSpecs, (for 103 | /// example, in case \a path cannot map to the current UsdEditTarget's 104 | /// namespace) issue an error and return an invalid \a UsdPrim. 105 | /// 106 | /// Note that this method may return a defined prim whose typeName does not 107 | /// specify this schema class, in case a stronger typeName opinion overrides 108 | /// the opinion at the current EditTarget. 109 | /// 110 | USDTRI_API 111 | static UsdTriTriangle Define(const UsdStagePtr& stage, const SdfPath& path); 112 | 113 | protected: 114 | /// Returns the kind of schema this class belongs to. 115 | /// 116 | /// \sa UsdSchemaKind 117 | USDTRI_API 118 | UsdSchemaKind _GetSchemaKind() const override; 119 | 120 | private: 121 | // needs to invoke _GetStaticTfType. 122 | friend class UsdSchemaRegistry; 123 | USDTRI_API 124 | static const TfType& _GetStaticTfType(); 125 | 126 | static bool _IsTypedSchema(); 127 | 128 | // override SchemaBase virtuals. 129 | USDTRI_API 130 | const TfType& _GetTfType() const override; 131 | 132 | public: 133 | // --------------------------------------------------------------------- // 134 | // SIDELENGTH 135 | // --------------------------------------------------------------------- // 136 | /// The length of each side of the equilateral triangle. 137 | /// 138 | /// | || 139 | /// | -- | -- | 140 | /// | Declaration | `double sideLength = 1` | 141 | /// | C++ Type | double | 142 | /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Double | 143 | USDTRI_API 144 | UsdAttribute GetSideLengthAttr() const; 145 | 146 | /// See GetSideLengthAttr(), and also 147 | /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. 148 | /// If specified, author \p defaultValue as the attribute's default, 149 | /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - 150 | /// the default for \p writeSparsely is \c false. 151 | USDTRI_API 152 | UsdAttribute CreateSideLengthAttr(VtValue const& defaultValue = VtValue(), 153 | bool writeSparsely = false) const; 154 | 155 | public: 156 | // --------------------------------------------------------------------- // 157 | // EXTENT 158 | // --------------------------------------------------------------------- // 159 | /// Fallback extent value of a triangle with side length of 1.0. 160 | /// 161 | /// | || 162 | /// | -- | -- | 163 | /// | Declaration | `float3[] extent = [(-0.5, -0.28867513, 0), (0.5, 164 | /// 0.57735026, 0)]` | | C++ Type | VtArray | | \ref Usd_Datatypes 165 | /// "Usd Type" | SdfValueTypeNames->Float3Array | 166 | USDTRI_API 167 | UsdAttribute GetExtentAttr() const; 168 | 169 | /// See GetExtentAttr(), and also 170 | /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. 171 | /// If specified, author \p defaultValue as the attribute's default, 172 | /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - 173 | /// the default for \p writeSparsely is \c false. 174 | USDTRI_API 175 | UsdAttribute CreateExtentAttr(VtValue const& defaultValue = VtValue(), 176 | bool writeSparsely = false) const; 177 | 178 | public: 179 | // ===================================================================== // 180 | // Feel free to add custom code below this line, it will be preserved by 181 | // the code generator. 182 | // 183 | // Just remember to: 184 | // - Close the class declaration with }; 185 | // - Close the namespace with PXR_NAMESPACE_CLOSE_SCOPE 186 | // - Close the include guard with #endif 187 | // ===================================================================== // 188 | // --(BEGIN CUSTOM CODE)-- 189 | 190 | /// Compute the extent for the triangle defined by its side length. 191 | /// 192 | /// \retval true Successful extent computation. 193 | /// \retval false Failure to compute extent. 194 | USDGEOM_API 195 | static bool ComputeExtent(double sideLength, VtVec3fArray* extent); 196 | 197 | /// \overload 198 | /// Computes the extent as if the matrix \p transform was first applied. 199 | USDGEOM_API 200 | static bool ComputeExtent(double sideLength, 201 | const GfMatrix4d& transform, 202 | VtVec3fArray* extent); 203 | }; 204 | 205 | PXR_NAMESPACE_CLOSE_SCOPE 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /src/usdTri/triangleCounter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | /* A simple program which opens an input USD file, and prints 8 | * the number of prims of type "Triangle" in the composed stage */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | PXR_NAMESPACE_USING_DIRECTIVE 15 | 16 | int 17 | main(int argc, char* argv[]) 18 | { 19 | if (argc != 2) { 20 | printf("usage: triangleCounter \n"); 21 | return EXIT_FAILURE; 22 | } 23 | 24 | int triangleCount = 0; 25 | UsdStageRefPtr stage = UsdStage::Open(argv[1]); 26 | for (UsdPrim prim : stage->TraverseAll()) { 27 | if (prim.IsA()) { 28 | triangleCount++; 29 | } 30 | } 31 | 32 | printf("Number of triangles: %i\n", triangleCount); 33 | return EXIT_SUCCESS; 34 | } 35 | -------------------------------------------------------------------------------- /src/usdTri/wrapTokens.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | // GENERATED FILE. DO NOT EDIT. 7 | #include 8 | #include "./tokens.h" 9 | 10 | PXR_NAMESPACE_USING_DIRECTIVE 11 | 12 | namespace { 13 | 14 | // Helper to return a static token as a string. We wrap tokens as Python 15 | // strings and for some reason simply wrapping the token using def_readonly 16 | // bypasses to-Python conversion, leading to the error that there's no 17 | // Python type for the C++ TfToken type. So we wrap this functor instead. 18 | class _WrapStaticToken 19 | { 20 | public: 21 | _WrapStaticToken(const TfToken* token) 22 | : _token(token) 23 | { 24 | } 25 | 26 | std::string operator()() const { return _token->GetString(); } 27 | 28 | private: 29 | const TfToken* _token; 30 | }; 31 | 32 | template 33 | void 34 | _AddToken(T& cls, const char* name, const TfToken& token) 35 | { 36 | cls.add_static_property( 37 | name, 38 | boost::python::make_function(_WrapStaticToken(&token), 39 | boost::python::return_value_policy< 40 | boost::python::return_by_value>(), 41 | boost::mpl::vector1())); 42 | } 43 | 44 | } // anonymous 45 | 46 | void 47 | wrapUsdTriTokens() 48 | { 49 | boost::python::class_ cls( 50 | "Tokens", boost::python::no_init); 51 | _AddToken(cls, "extent", UsdTriTokens->extent); 52 | _AddToken(cls, "sideLength", UsdTriTokens->sideLength); 53 | _AddToken(cls, "Triangle", UsdTriTokens->Triangle); 54 | } 55 | -------------------------------------------------------------------------------- /src/usdTri/wrapTriangle.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "./triangle.h" 7 | #include "pxr/usd/usd/schemaBase.h" 8 | 9 | #include "pxr/usd/sdf/primSpec.h" 10 | 11 | #include "pxr/usd/usd/pyConversions.h" 12 | #include "pxr/base/tf/pyContainerConversions.h" 13 | #include "pxr/base/tf/pyResultConversions.h" 14 | #include "pxr/base/tf/pyUtils.h" 15 | #include "pxr/base/tf/wrapTypeHelpers.h" 16 | 17 | #include 18 | 19 | #include 20 | 21 | using namespace boost::python; 22 | 23 | PXR_NAMESPACE_USING_DIRECTIVE 24 | 25 | namespace { 26 | 27 | #define WRAP_CUSTOM \ 28 | template \ 29 | static void _CustomWrapCode(Cls& _class) 30 | 31 | // fwd decl. 32 | WRAP_CUSTOM; 33 | 34 | static UsdAttribute 35 | _CreateSideLengthAttr(UsdTriTriangle& self, 36 | object defaultVal, 37 | bool writeSparsely) 38 | { 39 | return self.CreateSideLengthAttr( 40 | UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Double), 41 | writeSparsely); 42 | } 43 | 44 | static UsdAttribute 45 | _CreateExtentAttr(UsdTriTriangle& self, object defaultVal, bool writeSparsely) 46 | { 47 | return self.CreateExtentAttr( 48 | UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float3Array), 49 | writeSparsely); 50 | } 51 | 52 | static std::string 53 | _Repr(const UsdTriTriangle& self) 54 | { 55 | std::string primRepr = TfPyRepr(self.GetPrim()); 56 | return TfStringPrintf("UsdTri.Triangle(%s)", primRepr.c_str()); 57 | } 58 | 59 | } // anonymous namespace 60 | 61 | void 62 | wrapUsdTriTriangle() 63 | { 64 | typedef UsdTriTriangle This; 65 | 66 | class_> cls("Triangle"); 67 | 68 | cls.def(init(arg("prim"))) 69 | .def(init(arg("schemaObj"))) 70 | .def(TfTypePythonClass()) 71 | 72 | .def("Get", &This::Get, (arg("stage"), arg("path"))) 73 | .staticmethod("Get") 74 | 75 | .def("Define", &This::Define, (arg("stage"), arg("path"))) 76 | .staticmethod("Define") 77 | 78 | .def("GetSchemaAttributeNames", 79 | &This::GetSchemaAttributeNames, 80 | arg("includeInherited") = true, 81 | return_value_policy()) 82 | .staticmethod("GetSchemaAttributeNames") 83 | 84 | .def("_GetStaticTfType", 85 | (TfType const& (*)())TfType::Find, 86 | return_value_policy()) 87 | .staticmethod("_GetStaticTfType") 88 | 89 | .def(!self) 90 | 91 | .def("GetSideLengthAttr", &This::GetSideLengthAttr) 92 | .def("CreateSideLengthAttr", 93 | &_CreateSideLengthAttr, 94 | (arg("defaultValue") = object(), arg("writeSparsely") = false)) 95 | 96 | .def("GetExtentAttr", &This::GetExtentAttr) 97 | .def("CreateExtentAttr", 98 | &_CreateExtentAttr, 99 | (arg("defaultValue") = object(), arg("writeSparsely") = false)) 100 | 101 | .def("__repr__", ::_Repr); 102 | 103 | _CustomWrapCode(cls); 104 | } 105 | 106 | // ===================================================================== // 107 | // Feel free to add custom code below this line, it will be preserved by 108 | // the code generator. The entry point for your custom code should look 109 | // minimally like the following: 110 | // 111 | // WRAP_CUSTOM { 112 | // _class 113 | // .def("MyCustomMethod", ...) 114 | // ; 115 | // } 116 | // 117 | // Of course any other ancillary or support code may be provided. 118 | // 119 | // Just remember to wrap code in the appropriate delimiters: 120 | // 'namespace {', '}'. 121 | // 122 | // ===================================================================== // 123 | // --(BEGIN CUSTOM CODE)-- 124 | 125 | namespace { 126 | 127 | WRAP_CUSTOM {} 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_plugin(usdTriFileFormat 2 | 3 | CPPFILES 4 | fileFormat.cpp 5 | 6 | LIBRARIES 7 | tf 8 | sdf 9 | vt 10 | gf 11 | pcp 12 | usd 13 | usdGeom 14 | arch 15 | 16 | RESOURCE_FILES 17 | plugInfo.json 18 | ) 19 | 20 | add_subdirectory(tests) 21 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/fileFormat.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "fileFormat.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | PXR_NAMESPACE_OPEN_SCOPE 19 | 20 | // Default value of the triangle side length. 21 | static const double defaultSideLengthValue = 1.0; 22 | 23 | // Convenience function to extract the length value from a file format context. 24 | static double 25 | _ExtractSideLengthFromContext(const PcpDynamicFileFormatContext& context) 26 | { 27 | // Default sideLength. 28 | double sideLength = defaultSideLengthValue; 29 | 30 | VtValue value; 31 | if (!context.ComposeValue(UsdTriangleFileFormatTokens->SideLength, 32 | &value) || 33 | value.IsEmpty()) { 34 | return sideLength; 35 | } 36 | 37 | if (!value.IsHolding()) { 38 | TF_CODING_ERROR("Expected '%s' value to hold a double, got '%s'", 39 | UsdTriangleFileFormatTokens->SideLength.GetText(), 40 | TfStringify(value).c_str()); 41 | return sideLength; 42 | } 43 | 44 | return value.UncheckedGet(); 45 | } 46 | 47 | static double 48 | _ExtractSideLengthFromArgs(const SdfFileFormat::FileFormatArguments& args) 49 | { 50 | // Default sideLength. 51 | double sideLength = defaultSideLengthValue; 52 | 53 | // Find "sideLength" file format argument. 54 | auto it = args.find(UsdTriangleFileFormatTokens->SideLength); 55 | if (it == args.end()) { 56 | return sideLength; 57 | } 58 | 59 | // Try to convert the string value to the actual output value type. 60 | double extractVal; 61 | bool success = true; 62 | extractVal = TfUnstringify(it->second, &success); 63 | if (!success) { 64 | TF_CODING_ERROR( 65 | "Could not convert arg string '%s' to value of type double", 66 | UsdTriangleFileFormatTokens->SideLength.GetText()); 67 | return sideLength; 68 | } 69 | 70 | sideLength = extractVal; 71 | return sideLength; 72 | } 73 | 74 | TF_DEFINE_PUBLIC_TOKENS(UsdTriangleFileFormatTokens, 75 | USD_TRIANGLE_FILE_FORMAT_TOKENS); 76 | 77 | TF_REGISTRY_FUNCTION(TfType) 78 | { 79 | SDF_DEFINE_FILE_FORMAT(UsdTriangleFileFormat, SdfFileFormat); 80 | } 81 | 82 | UsdTriangleFileFormat::UsdTriangleFileFormat() 83 | : SdfFileFormat(UsdTriangleFileFormatTokens->Id, 84 | UsdTriangleFileFormatTokens->Version, 85 | UsdTriangleFileFormatTokens->Target, 86 | UsdTriangleFileFormatTokens->Extension) 87 | { 88 | } 89 | 90 | UsdTriangleFileFormat::~UsdTriangleFileFormat() {} 91 | 92 | bool 93 | UsdTriangleFileFormat::CanRead(const std::string& filePath) const 94 | { 95 | return true; 96 | } 97 | 98 | bool 99 | UsdTriangleFileFormat::Read(SdfLayer* layer, 100 | const std::string& resolvedPath, 101 | bool metadataOnly) const 102 | { 103 | if (!TF_VERIFY(layer)) { 104 | return false; 105 | } 106 | 107 | // Extract file format arguments. 108 | FileFormatArguments args; 109 | std::string layerPath; 110 | SdfLayer::SplitIdentifier(layer->GetIdentifier(), &layerPath, &args); 111 | double sideLength = _ExtractSideLengthFromArgs(args); 112 | 113 | // Create a new anonymous layer and wrap a stage around it. 114 | SdfLayerRefPtr newLayer = SdfLayer::CreateAnonymous(".usd"); 115 | UsdStageRefPtr stage = UsdStage::Open(newLayer); 116 | 117 | // Define a Mesh, set as default prim. 118 | UsdGeomMesh mesh = UsdGeomMesh::Define(stage, SdfPath("/Triangle")); 119 | stage->SetDefaultPrim(mesh.GetPrim()); 120 | 121 | // Author mesh attributes (describing a length-scaled equilateral triangle). 122 | VtIntArray faceVertexCounts(1, 3); 123 | mesh.CreateFaceVertexCountsAttr(VtValue(faceVertexCounts)); 124 | 125 | VtIntArray faceVertexIndices{ 0, 1, 2 }; 126 | mesh.CreateFaceVertexIndicesAttr(VtValue(faceVertexIndices)); 127 | 128 | VtVec3fArray points{ 129 | GfVec3f(0.0f, 0.57735027f * sideLength, 0.0f), 130 | GfVec3f(-0.5f * sideLength, -0.28867513f * sideLength, 0.0f), 131 | GfVec3f(0.5f * sideLength, -0.28867513f * sideLength, 0.0f) 132 | }; 133 | mesh.CreatePointsAttr(VtValue(points)); 134 | 135 | // Copy contents into output layer. 136 | layer->TransferContent(newLayer); 137 | 138 | return true; 139 | } 140 | 141 | bool 142 | UsdTriangleFileFormat::WriteToString(const SdfLayer& layer, 143 | std::string* str, 144 | const std::string& comment) const 145 | { 146 | // Write the generated contents in usda text format. 147 | return SdfFileFormat::FindById(UsdUsdaFileFormatTokens->Id) 148 | ->WriteToString(layer, str, comment); 149 | } 150 | 151 | bool 152 | UsdTriangleFileFormat::WriteToStream(const SdfSpecHandle& spec, 153 | std::ostream& out, 154 | size_t indent) const 155 | { 156 | // Write the generated contents in usda text format. 157 | return SdfFileFormat::FindById(UsdUsdaFileFormatTokens->Id) 158 | ->WriteToStream(spec, out, indent); 159 | } 160 | 161 | void 162 | UsdTriangleFileFormat::ComposeFieldsForFileFormatArguments( 163 | const std::string& assetPath, 164 | const PcpDynamicFileFormatContext& context, 165 | FileFormatArguments* args, 166 | VtValue* contextDependencyData) const 167 | { 168 | double sideLength = _ExtractSideLengthFromContext(context); 169 | (*args)[UsdTriangleFileFormatTokens->SideLength] = TfStringify(sideLength); 170 | } 171 | 172 | bool 173 | UsdTriangleFileFormat::CanFieldChangeAffectFileFormatArguments( 174 | const TfToken& field, 175 | const VtValue& oldValue, 176 | const VtValue& newValue, 177 | const VtValue& contextDependencyData) const 178 | { 179 | // Check if the "sideLength" argument changed. 180 | double oldLength = oldValue.IsHolding() 181 | ? oldValue.UncheckedGet() 182 | : defaultSideLengthValue; 183 | double newLength = newValue.IsHolding() 184 | ? newValue.UncheckedGet() 185 | : defaultSideLengthValue; 186 | 187 | return oldLength != newLength; 188 | } 189 | 190 | PXR_NAMESPACE_CLOSE_SCOPE 191 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/fileFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | PXR_NAMESPACE_OPEN_SCOPE 14 | 15 | /* clang-format off */ 16 | #define USD_TRIANGLE_FILE_FORMAT_TOKENS \ 17 | ((Id, "usdTriangleFileFormat")) \ 18 | ((Version, "1.0")) \ 19 | ((Target, "usd")) \ 20 | ((Extension, "triangle")) \ 21 | ((SideLength, "Usd_Triangle_SideLength")) 22 | /* clang-format on */ 23 | 24 | TF_DECLARE_PUBLIC_TOKENS(UsdTriangleFileFormatTokens, 25 | USD_TRIANGLE_FILE_FORMAT_TOKENS); 26 | 27 | TF_DECLARE_WEAK_AND_REF_PTRS(UsdTriangleFileFormat); 28 | 29 | /// \class UsdTriangleFileFormat 30 | /// 31 | /// A simple file format plugin which "expands" any payload with a .triangle 32 | /// suffix into a UsdGeomMesh representation of a equilateral triangle. 33 | class UsdTriangleFileFormat 34 | : public SdfFileFormat 35 | , public PcpDynamicFileFormatInterface 36 | { 37 | public: 38 | // We can always "read" (given that we never need to actually examine the 39 | // contents). 40 | bool CanRead(const std::string& filePath) const override; 41 | 42 | // Author USD scene description into the output layer for a given .triangle 43 | // file. 44 | bool Read(SdfLayer* layer, 45 | const std::string& resolvedPath, 46 | bool metadataOnly) const override; 47 | 48 | // Author .usda text format when writing to string or stream. 49 | bool WriteToString( 50 | const SdfLayer& layer, 51 | std::string* str, 52 | const std::string& comment = std::string()) const override; 53 | bool WriteToStream(const SdfSpecHandle& spec, 54 | std::ostream& out, 55 | size_t indent) const override; 56 | 57 | // Read fields values (from context) and write into file format args. 58 | void ComposeFieldsForFileFormatArguments( 59 | const std::string& assetPath, 60 | const PcpDynamicFileFormatContext& context, 61 | FileFormatArguments* args, 62 | VtValue* contextDependencyData) const override; 63 | 64 | // Check if a field change affects any of the file format arguments 65 | // affecting the triangle (spoilers: the answer is yes). 66 | bool CanFieldChangeAffectFileFormatArguments( 67 | const TfToken& field, 68 | const VtValue& oldValue, 69 | const VtValue& newValue, 70 | const VtValue& contextDependencyData) const override; 71 | 72 | protected: 73 | SDF_FILE_FORMAT_FACTORY_ACCESS; 74 | 75 | virtual ~UsdTriangleFileFormat(); 76 | UsdTriangleFileFormat(); 77 | }; 78 | 79 | PXR_NAMESPACE_CLOSE_SCOPE 80 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/plugInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "Plugins": [ 3 | { 4 | "Info": { 5 | "SdfMetadata": { 6 | "Usd_Triangle_SideLength": { 7 | "type": "double", 8 | "displayGroup": "Core", 9 | "appliesTo": ["prims"], 10 | "documentation:": "Length of the triangle side." 11 | } 12 | }, 13 | "Types": { 14 | "UsdTriangleFileFormat": { 15 | "bases": [ 16 | "SdfFileFormat" 17 | ], 18 | "displayName": "USD Triangle File Format", 19 | "extensions": [ 20 | "triangle" 21 | ], 22 | "formatId": "usdTriangleFileFormat", 23 | "primary": true, 24 | "target": "usd" 25 | } 26 | } 27 | }, 28 | "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", 29 | "Name": "usdTriFileFormat", 30 | "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@", 31 | "Root": "@PLUG_INFO_ROOT@", 32 | "Type": "library" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/scenes/empty.triangle: -------------------------------------------------------------------------------- 1 | // Dummy file! 2 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/scenes/triangle.usda: -------------------------------------------------------------------------------- 1 | #usda 1.0 2 | 3 | def "triangle" ( 4 | Usd_Triangle_SideLength = 1 5 | payload = @./empty.triangle@ 6 | ) 7 | { 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_python_test(usdTriFileFormat_python testFileFormat.py) 2 | -------------------------------------------------------------------------------- /src/usdTriFileFormat/tests/testFileFormat.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | from pxr import Vt, Gf, Sdf, Usd, UsdGeom 4 | 5 | 6 | class TestUsdTriangleFileFormat(unittest.TestCase): 7 | def testPayloadExpansion(self): 8 | # Create a new stage. 9 | stage = Usd.Stage.CreateInMemory() 10 | 11 | # Define a un-typed prim, with side length metadatum value of 5. 12 | prim = stage.DefinePrim("/triangle") 13 | prim.SetMetadata("Usd_Triangle_SideLength", 5) 14 | 15 | # Set payload path to ../scenes/empty.triangle. 16 | payloadPath = os.path.join( 17 | os.path.dirname(__file__), "..", "scenes", "empty.triangle" 18 | ) 19 | prim.SetPayload(Sdf.Payload(payloadPath)) 20 | 21 | # Should be expanded into a mesh! 22 | mesh = UsdGeom.Mesh(prim) 23 | self.assertTrue(mesh) 24 | 25 | # Validate mesh attribute values. 26 | self.assertEqual(mesh.GetFaceVertexCountsAttr().Get(), Vt.IntArray((3,))) 27 | self.assertEqual(mesh.GetFaceVertexIndicesAttr().Get(), Vt.IntArray((0, 1, 2,))) 28 | 29 | actualPoints = mesh.GetPointsAttr().Get() 30 | expectedPoints = Vt.Vec3fArray( 31 | ( 32 | Gf.Vec3f(0.0, 2.88675, 0.0), 33 | Gf.Vec3f(-2.5, -1.44337, 0.0), 34 | Gf.Vec3f(2.5, -1.44337, 0.0), 35 | ) 36 | ) 37 | self.assertEqual(len(actualPoints), len(expectedPoints)) 38 | for actualPoint, expectedPoint in zip(actualPoints, expectedPoints): 39 | self.assertTrue(Gf.IsClose(actualPoint, expectedPoint, 1e-5)) 40 | 41 | 42 | if __name__ == "__main__": 43 | unittest.main() 44 | -------------------------------------------------------------------------------- /src/usdTriImaging/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_plugin(usdTriImaging 2 | 3 | CPPFILES 4 | triangleAdapter.cpp 5 | debugCodes.cpp 6 | 7 | LIBRARIES 8 | arch 9 | js 10 | plug 11 | usd 12 | tf 13 | sdf 14 | vt 15 | gf 16 | hd 17 | usdGeom 18 | usdImaging 19 | usdTri 20 | 21 | RESOURCE_FILES 22 | plugInfo.json 23 | ) 24 | 25 | -------------------------------------------------------------------------------- /src/usdTriImaging/debugCodes.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "debugCodes.h" 7 | 8 | #include 9 | 10 | PXR_NAMESPACE_OPEN_SCOPE 11 | 12 | TF_REGISTRY_FUNCTION(TfDebug) 13 | { 14 | TF_DEBUG_ENVIRONMENT_SYMBOL(USDTRIIMAGING, 15 | "Global debug symbol for usdTriImaging."); 16 | } 17 | 18 | PXR_NAMESPACE_CLOSE_SCOPE 19 | -------------------------------------------------------------------------------- /src/usdTriImaging/debugCodes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | 11 | PXR_NAMESPACE_OPEN_SCOPE 12 | 13 | TF_DEBUG_CODES(USDTRIIMAGING); 14 | 15 | PXR_NAMESPACE_CLOSE_SCOPE 16 | -------------------------------------------------------------------------------- /src/usdTriImaging/plugInfo.json: -------------------------------------------------------------------------------- 1 | { 2 | "Plugins": [ 3 | { 4 | "Info": { 5 | "Types": { 6 | "UsdTriImagingTriangleAdapter": { 7 | "bases": [ 8 | "UsdImagingGprimAdapter" 9 | ], 10 | "primTypeName": "Triangle" 11 | } 12 | } 13 | }, 14 | "LibraryPath": "@PLUG_INFO_LIBRARY_PATH@", 15 | "Name": "usdTriImaging", 16 | "ResourcePath": "@PLUG_INFO_RESOURCE_PATH@", 17 | "Root": "@PLUG_INFO_ROOT@", 18 | "Type": "library" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /src/usdTriImaging/triangleAdapter.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #include "triangleAdapter.h" 7 | #include "debugCodes.h" 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | PXR_NAMESPACE_OPEN_SCOPE 17 | 18 | TF_REGISTRY_FUNCTION(TfType) 19 | { 20 | typedef UsdTriImagingTriangleAdapter Adapter; 21 | TfType adapterType = 22 | TfType::Define>(); 23 | adapterType.SetFactory>(); 24 | } 25 | 26 | bool 27 | UsdTriImagingTriangleAdapter::IsSupported( 28 | const UsdImagingIndexProxy* index) const 29 | { 30 | return index->IsRprimTypeSupported(HdPrimTypeTokens->mesh); 31 | } 32 | 33 | void 34 | UsdTriImagingTriangleAdapter::TrackVariability( 35 | const UsdPrim& usdPrim, 36 | const SdfPath& cachePath, 37 | HdDirtyBits* o_timeVaryingBits, 38 | const UsdImagingInstancerContext* i_instancerContext) const 39 | { 40 | BaseAdapter::TrackVariability( 41 | usdPrim, cachePath, o_timeVaryingBits, i_instancerContext); 42 | 43 | // If sideLength varies over time then points need to be pulled on time 44 | // change. 45 | _IsVarying(usdPrim, 46 | UsdTriTokens->sideLength, 47 | HdChangeTracker::DirtyPoints, 48 | UsdImagingTokens->usdVaryingPrimvar, 49 | o_timeVaryingBits, 50 | /*inherited*/ false); 51 | 52 | TF_DEBUG(USDTRIIMAGING) 53 | .Msg("[%s] <%s>, <%s>, dirtyBits: %s\n", 54 | TF_FUNC_NAME().c_str(), 55 | usdPrim.GetPath().GetText(), 56 | cachePath.GetText(), 57 | HdChangeTracker::StringifyDirtyBits(*o_timeVaryingBits).c_str()); 58 | } 59 | 60 | SdfPath 61 | UsdTriImagingTriangleAdapter::Populate( 62 | const UsdPrim& usdPrim, 63 | UsdImagingIndexProxy* index, 64 | const UsdImagingInstancerContext* instancerContext) 65 | { 66 | TF_DEBUG(USDTRIIMAGING) 67 | .Msg( 68 | "[%s] <%s>\n", TF_FUNC_NAME().c_str(), usdPrim.GetPath().GetText()); 69 | 70 | return _AddRprim(HdPrimTypeTokens->mesh, 71 | usdPrim, 72 | index, 73 | GetMaterialUsdPath(usdPrim), 74 | instancerContext); 75 | } 76 | 77 | HdDirtyBits 78 | UsdTriImagingTriangleAdapter::ProcessPropertyChange(const UsdPrim& usdPrim, 79 | const SdfPath& cachePath, 80 | const TfToken& propertyName) 81 | { 82 | 83 | TF_DEBUG(USDTRIIMAGING) 84 | .Msg("[%s] <%s>, <%s>, propertyName: %s\n", 85 | TF_FUNC_NAME().c_str(), 86 | usdPrim.GetPath().GetText(), 87 | cachePath.GetText(), 88 | propertyName.GetText()); 89 | 90 | // If the sideLength attribute changes, then the points are dirty. 91 | if (propertyName == UsdTriTokens->sideLength) { 92 | return HdChangeTracker::DirtyPoints; 93 | } 94 | 95 | // Allow base class to handle change processing. 96 | return BaseAdapter::ProcessPropertyChange(usdPrim, cachePath, propertyName); 97 | } 98 | 99 | VtValue 100 | UsdTriImagingTriangleAdapter::GetPoints(const UsdPrim& usdPrim, 101 | UsdTimeCode timeCode) const 102 | { 103 | UsdTriTriangle triangle(usdPrim); 104 | TF_VERIFY(triangle); 105 | 106 | double sideLength; 107 | TF_VERIFY(triangle.GetSideLengthAttr().Get(&sideLength, timeCode)); 108 | 109 | VtVec3fArray points{ 110 | GfVec3f(0.0f, 0.57735027f * sideLength, 0.0f), 111 | GfVec3f(-0.5f * sideLength, -0.28867513f * sideLength, 0.0f), 112 | GfVec3f(0.5f * sideLength, -0.28867513f * sideLength, 0.0f) 113 | }; 114 | return VtValue(points); 115 | } 116 | 117 | VtValue 118 | UsdTriImagingTriangleAdapter::GetTopology(const UsdPrim& usdPrim, 119 | const SdfPath& cachePath, 120 | UsdTimeCode time) const 121 | { 122 | // A single triangle. 123 | VtIntArray faceVertexCounts(1, 3); 124 | VtIntArray faceVertexIndices{ 0, 1, 2 }; 125 | static HdMeshTopology planeTopology(UsdGeomTokens->catmullClark, 126 | HdTokens->rightHanded, 127 | faceVertexCounts, 128 | faceVertexIndices); 129 | return VtValue(planeTopology); 130 | } 131 | 132 | PXR_NAMESPACE_CLOSE_SCOPE 133 | -------------------------------------------------------------------------------- /src/usdTriImaging/triangleAdapter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta Digital Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | #pragma once 7 | 8 | #include 9 | 10 | PXR_NAMESPACE_OPEN_SCOPE 11 | 12 | /// \class UsdTriImagingTriangleAdapter 13 | /// 14 | /// PrimAdapter plugin for the "Triangle" prim type. 15 | class UsdTriImagingTriangleAdapter : public UsdImagingGprimAdapter 16 | { 17 | public: 18 | using BaseAdapter = UsdImagingGprimAdapter; 19 | 20 | // ---------------------------------------------------------------------- // 21 | /// \name Initialization 22 | // ---------------------------------------------------------------------- // 23 | 24 | virtual SdfPath Populate( 25 | const UsdPrim& usdPrim, 26 | UsdImagingIndexProxy* index, 27 | const UsdImagingInstancerContext* instancerContext = nullptr) override; 28 | 29 | virtual bool IsSupported(const UsdImagingIndexProxy* index) const override; 30 | 31 | // ---------------------------------------------------------------------- // 32 | /// \name Parallel Setup and Resolve 33 | // ---------------------------------------------------------------------- // 34 | 35 | virtual void TrackVariability( 36 | const UsdPrim& usdPrim, 37 | const SdfPath& cachePath, 38 | HdDirtyBits* timeVaryingBits, 39 | const UsdImagingInstancerContext* i_instancerContext = 40 | nullptr) const override; 41 | 42 | // ---------------------------------------------------------------------- // 43 | /// \name Change processing 44 | // ---------------------------------------------------------------------- // 45 | 46 | virtual HdDirtyBits ProcessPropertyChange( 47 | const UsdPrim& usdPrim, 48 | const SdfPath& cachePath, 49 | const TfToken& propertyName) override; 50 | 51 | // ---------------------------------------------------------------------- // 52 | /// \name GprimAdapter overrides 53 | // ---------------------------------------------------------------------- // 54 | 55 | /// Override the implementation in GprimAdapter and provide \em custom 56 | /// points for a triangle. 57 | virtual VtValue GetPoints(const UsdPrim& usdPrim, 58 | UsdTimeCode timeCode) const override; 59 | 60 | /// Override the implementation in GprimAdapter and provide \em custom 61 | /// topology for a triangle. 62 | virtual VtValue GetTopology(const UsdPrim& usdPrim, 63 | const SdfPath& cachePath, 64 | UsdTimeCode time) const override; 65 | }; 66 | 67 | PXR_NAMESPACE_CLOSE_SCOPE 68 | -------------------------------------------------------------------------------- /src/usdTriImagingHd2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | usd_plugin(usdTriImagingHd2 2 | 3 | CPPFILES 4 | triangleAdapter.cpp 5 | debugCodes.cpp 6 | dataSourceTri.cpp 7 | 8 | LIBRARIES 9 | arch 10 | js 11 | plug 12 | usd 13 | tf 14 | sdf 15 | vt 16 | gf 17 | hd 18 | usdGeom 19 | usdImaging 20 | usdTri 21 | 22 | RESOURCE_FILES 23 | plugInfo.json 24 | ) -------------------------------------------------------------------------------- /src/usdTriImagingHd2/dataSourceTri.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright © 2024 Weta FX Limited 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | // 6 | 7 | #include "dataSourceTri.h" 8 | #include "debugCodes.h" 9 | 10 | #include 11 | #include 12 | 13 | #include "pxr/imaging/hd/meshSchema.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | PXR_NAMESPACE_OPEN_SCOPE 21 | 22 | // a static container-handle for the mesh-topology 23 | HdContainerDataSourceHandle 24 | _meshTopologyDs() 25 | { 26 | static const VtIntArray faceVertexCounts = { 3 }; 27 | 28 | static const VtIntArray faceVertexIndices = { 0, 1, 2 }; 29 | 30 | using _IntArrayDs = HdRetainedTypedSampledDataSource; 31 | 32 | static const _IntArrayDs::Handle fvcDs = _IntArrayDs::New(faceVertexCounts); 33 | 34 | static const _IntArrayDs::Handle fviDs = 35 | _IntArrayDs::New(faceVertexIndices); 36 | 37 | static const HdContainerDataSourceHandle meshDs = 38 | HdMeshSchema::Builder() 39 | .SetTopology(HdMeshTopologySchema::Builder() 40 | .SetFaceVertexCounts(fvcDs) 41 | .SetFaceVertexIndices(fviDs) 42 | .Build()) 43 | .Build(); 44 | 45 | return meshDs; 46 | } 47 | 48 | // a DataHandle producing Sampled Vec3fArray data 49 | // to be used as points of the triangle 50 | // it carries a great resemblence and is very much a copy of 51 | // UsdImagingDataSourceAttribute we technically would just need to overwrite 52 | // ::GetTypedValue(...) for our purposes here, but the constructor of 53 | // UsdImagingDataSourceAttribute is private so we need to re-implement 54 | // everything 55 | 56 | class _PointsFromSideLengthDataSource 57 | : public HdTypedSampledDataSource 58 | { 59 | public: 60 | HD_DECLARE_DATASOURCE(_PointsFromSideLengthDataSource); 61 | 62 | // copied the code from UsdImagingDataSourceAttribute 63 | bool GetContributingSampleTimesForInterval( 64 | Time startTime, 65 | Time endTime, 66 | std::vector