diff --git a/DeclarativePixarUSD.usda b/DeclarativePixarUSD.usda index 815066f9f6..07708076f4 100644 --- a/DeclarativePixarUSD.usda +++ b/DeclarativePixarUSD.usda @@ -1,6 +1,6 @@ #usda 1.0 ( - doc = "SwiftUSD v24.08.0 | Declarative API" + doc = "SwiftUSD v24.08.3 | Declarative API" ) def "DeclarativeScene" diff --git a/HelloPixarUSD.usda b/HelloPixarUSD.usda index 84c745b4e2..44b54d444d 100644 --- a/HelloPixarUSD.usda +++ b/HelloPixarUSD.usda @@ -1,6 +1,6 @@ #usda 1.0 ( - doc = "SwiftUSD v24.08.0" + doc = "SwiftUSD v24.08.3" ) def Xform "Geometry" diff --git a/Package.swift b/Package.swift index c4b0a80068..e823e027ab 100644 --- a/Package.swift +++ b/Package.swift @@ -177,6 +177,26 @@ let package = Package( name: "Hd", targets: ["Hd"] ), + .library( + name: "HdAr", + targets: ["HdAr"] + ), + .library( + name: "HdMtlx", + targets: ["HdMtlx"] + ), + .library( + name: "HdSi", + targets: ["HdSi"] + ), + .library( + name: "HdSt", + targets: ["HdSt"] + ), + .library( + name: "Hdx", + targets: ["Hdx"] + ), .library( name: "Garch", targets: ["Garch"] @@ -218,6 +238,14 @@ let package = Package( name: "UsdShaders", targets: ["UsdShaders"] ), + .library( + name: "UsdImaging", + targets: ["UsdImaging"] + ), + .library( + name: "UsdImagingGL", + targets: ["UsdImagingGL"] + ), // ----------------- Apps ----- .executable( name: "UsdView", @@ -1308,6 +1336,7 @@ let package = Package( .target(name: "Hio"), ], resources: [ + .copy("shaders"), .process("Resources") ], cxxSettings: [ @@ -1337,6 +1366,209 @@ let package = Package( ] ), + .target( + name: "HdSi", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Plug"), + .target(name: "Trace"), + .target(name: "Vt"), + .target(name: "Work"), + .target(name: "Sdf"), + .target(name: "CameraUtil"), + .target(name: "GeomUtil"), + .target(name: "Hf"), + .target(name: "Hd"), + .target(name: "PxOsd"), + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "HdSi"), + .define("MFB_ALT_PACKAGE_NAME", to: "HdSi"), + .define("MFB_PACKAGE_MODULE", to: "HdSi"), + .define("HDSI_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "HdMtlx", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Trace"), + .target(name: "Vt"), + .target(name: "Gf"), + .target(name: "Hd"), + .target(name: "Sdf"), + .target(name: "Sdr"), + .target(name: "UsdMtlx") + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "HdMtlx"), + .define("MFB_ALT_PACKAGE_NAME", to: "HdMtlx"), + .define("MFB_PACKAGE_MODULE", to: "HdMtlx"), + .define("HDMTLX_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "HdSt", + dependencies: [ + .target(name: "Hio"), + .target(name: "Garch"), + .target(name: "Glf"), + .target(name: "Hd"), + .target(name: "HdSi"), + .target(name: "HgiGL"), + .target(name: "HgiInterop"), + .target(name: "Sdr"), + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Trace"), + .target(name: "HdMtlx"), + ], + resources: [ + .copy("shaders"), + .copy("textures"), + .process("Resources") + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "HdSt"), + .define("MFB_ALT_PACKAGE_NAME", to: "HdSt"), + .define("MFB_PACKAGE_MODULE", to: "HdSt"), + .define("HDST_EXPORTS", to: "1"), + .define("PXR_MATERIALX_SUPPORT_ENABLED", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "Hdx", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Gf"), + .target(name: "Vt"), + .target(name: "Plug"), + .target(name: "Work"), + .target(name: "Sdf"), + .target(name: "Garch"), + .target(name: "Glf"), + .target(name: "PxOsd"), + .target(name: "Hd"), + .target(name: "HdSt"), + .target(name: "Hgi"), + .target(name: "HgiInterop"), + .target(name: "CameraUtil"), + ], + resources: [ + .copy("shaders"), + .copy("textures"), + .process("Resources") + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "Hdx"), + .define("MFB_ALT_PACKAGE_NAME", to: "Hdx"), + .define("MFB_PACKAGE_MODULE", to: "Hdx"), + .define("HDX_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "HdAr", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Hd"), + .target(name: "Ar"), + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "HdAr"), + .define("MFB_ALT_PACKAGE_NAME", to: "HdAr"), + .define("MFB_PACKAGE_MODULE", to: "HdAr"), + .define("HDAR_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "UsdImaging", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Gf"), + .target(name: "Vt"), + .target(name: "Plug"), + .target(name: "Trace"), + .target(name: "Work"), + .target(name: "GeomUtil"), + .target(name: "Hd"), + .target(name: "HdAr"), + .target(name: "Hio"), + .target(name: "PxOsd"), + .target(name: "Ar"), + .target(name: "Sdf"), + .target(name: "Usd"), + .target(name: "UsdGeom"), + .target(name: "UsdLux"), + .target(name: "UsdRender"), + .target(name: "UsdShade"), + .target(name: "UsdVol"), + ], + resources: [ + .process("Resources") + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "UsdImaging"), + .define("MFB_ALT_PACKAGE_NAME", to: "UsdImaging"), + .define("MFB_PACKAGE_MODULE", to: "UsdImaging"), + .define("USDIMAGING_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + + .target( + name: "UsdImagingGL", + dependencies: [ + .target(name: "Arch"), + .target(name: "Tf"), + .target(name: "Gf"), + .target(name: "Vt"), + .target(name: "Plug"), + .target(name: "Trace"), + .target(name: "Work"), + .target(name: "Hio"), + .target(name: "Garch"), + .target(name: "Glf"), + .target(name: "Hd"), + .target(name: "HdSi"), + .target(name: "Hdx"), + .target(name: "Hgi"), + .target(name: "PxOsd"), + .target(name: "Ar"), + .target(name: "Sdf"), + .target(name: "Sdr"), + .target(name: "Usd"), + .target(name: "UsdGeom"), + .target(name: "UsdHydra"), + .target(name: "UsdShade"), + .target(name: "UsdImaging"), + ], + resources: [ + .process("Resources") + ], + cxxSettings: [ + .define("MFB_PACKAGE_NAME", to: "UsdImagingGL"), + .define("MFB_ALT_PACKAGE_NAME", to: "UsdImagingGL"), + .define("MFB_PACKAGE_MODULE", to: "UsdImagingGL"), + .define("USDIMAGINGGL_EXPORTS", to: "1"), + .define("_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH", .when(platforms: [.windows])), + ] + ), + .executableTarget( name: "UsdView", dependencies: [ @@ -1491,20 +1723,27 @@ let package = Package( .target(name: "UsdVol"), // ------- imaging. ------ .target(name: "CameraUtil"), + .target(name: "Garch"), + .target(name: "GeomUtil"), + .target(name: "Glf"), .target(name: "Hf"), - .target(name: "PxOsd"), .target(name: "Hd"), - .target(name: "Garch"), + .target(name: "HdAr"), + .target(name: "HdMtlx"), + .target(name: "HdSi"), + .target(name: "HdSt"), + .target(name: "Hdx"), .target(name: "Hgi"), .target(name: "HgiMetal", condition: .when(platforms: Arch.OS.apple.platform)), // .target(name: "HgiVulkan", condition: .when(platforms: Arch.OS.linux.platform)), .target(name: "HgiGL"), .target(name: "HgiInterop"), .target(name: "Hio"), - .target(name: "Glf"), - .target(name: "GeomUtil"), + .target(name: "PxOsd"), // --- usd imaging. ------ .target(name: "UsdShaders"), + .target(name: "UsdImaging"), + .target(name: "UsdImagingGL"), // -------- macros. ------ .target(name: "PixarMacros"), // ----------------------- diff --git a/Sources/Bin/.gitkeep b/Sources/Bin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/Bin/bakeMaterialX.cpp b/Sources/Bin/bakeMaterialX.cpp index aa51a5d1a2..06e9253bb8 100644 --- a/Sources/Bin/bakeMaterialX.cpp +++ b/Sources/Bin/bakeMaterialX.cpp @@ -22,9 +22,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include diff --git a/Sources/Bin/include/Bin/bakeMaterialX.h b/Sources/Bin/include/Bin/bakeMaterialX.h index 956ec2e061..f25b80f047 100644 --- a/Sources/Bin/include/Bin/bakeMaterialX.h +++ b/Sources/Bin/include/Bin/bakeMaterialX.h @@ -14,7 +14,7 @@ #include "Hd/material.h" #include "UsdShade/material.h" -#include +#include #include "Tf/declarePtrs.h" #include diff --git a/Sources/Glf/Resources/shaders/pcfShader.glslfx b/Sources/Glf/shaders/pcfShader.glslfx similarity index 77% rename from Sources/Glf/Resources/shaders/pcfShader.glslfx rename to Sources/Glf/shaders/pcfShader.glslfx index c03cd8e85d..e6003f1e41 100644 --- a/Sources/Glf/Resources/shaders/pcfShader.glslfx +++ b/Sources/Glf/shaders/pcfShader.glslfx @@ -3,25 +3,8 @@ // // Copyright 2016 Pixar // -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. // ---Percentage-Closer Filtering (PCF) diff --git a/Sources/Glf/Resources/shaders/simpleLighting.glslfx b/Sources/Glf/shaders/simpleLighting.glslfx similarity index 93% rename from Sources/Glf/Resources/shaders/simpleLighting.glslfx rename to Sources/Glf/shaders/simpleLighting.glslfx index 6dbfa6d59c..aea52730b4 100644 --- a/Sources/Glf/Resources/shaders/simpleLighting.glslfx +++ b/Sources/Glf/shaders/simpleLighting.glslfx @@ -3,25 +3,8 @@ // // Copyright 2016 Pixar // -// Licensed under the Apache License, Version 2.0 (the "Apache License") -// with the following modification; you may not use this file except in -// compliance with the Apache License and the following modification to it: -// Section 6. Trademarks. is deleted and replaced with: -// -// 6. Trademarks. This License does not grant permission to use the trade -// names, trademarks, service marks, or product names of the Licensor -// and its affiliates, except as required to comply with Section 4(c) of -// the License and to reproduce the content of the NOTICE file. -// -// You may obtain a copy of the Apache License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the Apache License with the above modification is -// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the Apache License for the specific -// language governing permissions and limitations under the Apache License. +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. // --- This is what an import might look like. diff --git a/Sources/Hd/include/Hd/version.h b/Sources/Hd/include/Hd/version.h index 3e701d8b5f..84489eb7d3 100644 --- a/Sources/Hd/include/Hd/version.h +++ b/Sources/Hd/include/Hd/version.h @@ -63,7 +63,7 @@ // 56 -> 57: Changing SetOverrideWindowPolicy to std::optional on // HdRenderPassState, HdxPickFromRenderBufferTaskParams, // HdxTaskController and UsdImagingGLEngine. -// 57 -> 58: Introducing hdsi/version.h +// 57 -> 58: Introducing version.h // 58 -> 59: HdGeomSubsetsSchema::GetIds() renamed to // HdGeomSubsetsSchema::GetGeomSubsetNames(). // 59 -> 60: Introduced HdRenderDelegate::GetCapabilities(). diff --git a/Sources/HdAr/.gitkeep b/Sources/HdAr/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/HdGp/.gitkeep b/Sources/HdGp/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/HdMtlx/.gitkeep b/Sources/HdMtlx/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/HdMtlx/hdMtlx.cpp b/Sources/HdMtlx/hdMtlx.cpp index 385958d5b2..0865c9e809 100644 --- a/Sources/HdMtlx/hdMtlx.cpp +++ b/Sources/HdMtlx/hdMtlx.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include namespace mx = MaterialX; diff --git a/Sources/HdMtlx/include/HdMtlx/hdMtlx.h b/Sources/HdMtlx/include/HdMtlx/hdMtlx.h index 078dfd318a..e81b8356fa 100644 --- a/Sources/HdMtlx/include/HdMtlx/hdMtlx.h +++ b/Sources/HdMtlx/include/HdMtlx/hdMtlx.h @@ -14,7 +14,7 @@ #include #include -#include +#include MATERIALX_NAMESPACE_BEGIN class FileSearchPath; diff --git a/Sources/HdSi/.gitkeep b/Sources/HdSi/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/HdSi/include/HdSi/materialBindingResolvingSceneIndex.h b/Sources/HdSi/include/HdSi/materialBindingResolvingSceneIndex.h index e57862a754..e9153fdd21 100644 --- a/Sources/HdSi/include/HdSi/materialBindingResolvingSceneIndex.h +++ b/Sources/HdSi/include/HdSi/materialBindingResolvingSceneIndex.h @@ -7,7 +7,7 @@ #define PXR_IMAGING_HDSI_MATERIAL_BINDING_RESOLVING_SCENE_INDEX_H #include "Hd/filteringSceneIndex.h" -#include "Hdsi/api.h" +#include "HdSi/api.h" #include "pxr/pxrns.h" diff --git a/Sources/HdSi/include/HdSi/primTypePruningSceneIndex.h b/Sources/HdSi/include/HdSi/primTypePruningSceneIndex.h index 01fe745be0..a22489cb9f 100644 --- a/Sources/HdSi/include/HdSi/primTypePruningSceneIndex.h +++ b/Sources/HdSi/include/HdSi/primTypePruningSceneIndex.h @@ -9,7 +9,7 @@ #include "pxr/pxrns.h" #include "Hd/filteringSceneIndex.h" -#include "Hdsi/api.h" +#include "HdSi/api.h" #include "Sdf/pathTable.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSi/include/HdSi/velocityMotionResolvingSceneIndex.h b/Sources/HdSi/include/HdSi/velocityMotionResolvingSceneIndex.h index 0d4ddd0868..2a6bb50e76 100644 --- a/Sources/HdSi/include/HdSi/velocityMotionResolvingSceneIndex.h +++ b/Sources/HdSi/include/HdSi/velocityMotionResolvingSceneIndex.h @@ -28,7 +28,7 @@ #include "Hd/filteringSceneIndex.h" #include "Hd/sceneIndex.h" #include "Hd/sceneIndexObserver.h" -#include "Hdsi/api.h" +#include "HdSi/api.h" #include "Sdf/path.h" diff --git a/Sources/HdSt/.gitkeep b/Sources/HdSt/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/HdSt/Resources/plugInfo.json b/Sources/HdSt/Resources/plugInfo.json new file mode 100644 index 0000000000..abb63a809c --- /dev/null +++ b/Sources/HdSt/Resources/plugInfo.json @@ -0,0 +1,70 @@ +{ + "Plugins": [ + { + "Info": { + "Types": { + "HdSt_DependencySceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Storm Dependency Scene Index" + }, + "HdSt_DependencyForwardingSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Storm Dependency Forwarding Scene Index" + }, + "HdSt_MaterialBindingResolvingSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to resolve material bindings." + }, + "HdSt_MaterialPrimvarTransferSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to transfer primvars from material to prim." + }, + "HdSt_NodeIdentifierResolvingSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to resolve nodeIdentifier from glslfx sourceAsset." + }, + "HdSt_ImplicitSurfaceSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to turn implicit surfaces into prims suitable for Storm" + }, + "HdSt_NurbsApproximatingSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to resolve terminal names." + }, + "HdSt_TetMeshConversionSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer" : "GL", + "priority": 0, + "displayName": "Scene Index to convert tet meshes into standard triangle based meshes." + }, + "HdSt_VelocityMotionResolvingSceneIndexPlugin" : { + "bases": ["HdSceneIndexPlugin"], + "loadWithRenderer": "GL", + "priority": 0, + "displayName": "Scene index to resolve velocity-based motion." + } + }, + "ShaderResources": "shaders" + }, + "LibraryPath": "", + "Name": "HdSt", + "ResourcePath": "Contents/Resources", + "Root": "../..", + "Type": "library" + } + ] +} diff --git a/Sources/HdSt/implicitSurfaceSceneIndexPlugin.cpp b/Sources/HdSt/implicitSurfaceSceneIndexPlugin.cpp index 4bbdae5ed5..9afb503c71 100644 --- a/Sources/HdSt/implicitSurfaceSceneIndexPlugin.cpp +++ b/Sources/HdSt/implicitSurfaceSceneIndexPlugin.cpp @@ -9,7 +9,7 @@ #include "Hd/retainedDataSource.h" #include "Hd/sceneIndexPluginRegistry.h" #include "Hd/tokens.h" -#include "Hdsi/implicitSurfaceSceneIndex.h" +#include "HdSi/implicitSurfaceSceneIndex.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/include/HdSt/glslProgram.h b/Sources/HdSt/include/HdSt/glslProgram.h index a7652c4342..0464187083 100644 --- a/Sources/HdSt/include/HdSt/glslProgram.h +++ b/Sources/HdSt/include/HdSt/glslProgram.h @@ -7,12 +7,15 @@ #ifndef PXR_IMAGING_HD_ST_GLSL_PROGRAM_H #define PXR_IMAGING_HD_ST_GLSL_PROGRAM_H +#include "pxr/pxrns.h" + #include "Hd/version.h" #include "HdSt/api.h" #include "Hgi/buffer.h" #include "Hgi/enums.h" #include "Hgi/shaderProgram.h" -#include "pxr/pxrns.h" + +#include "Tf/token.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/include/HdSt/materialNetwork.h b/Sources/HdSt/include/HdSt/materialNetwork.h index 4d42238bc6..23cc79357e 100644 --- a/Sources/HdSt/include/HdSt/materialNetwork.h +++ b/Sources/HdSt/include/HdSt/materialNetwork.h @@ -15,7 +15,7 @@ #include "pxr/pxrns.h" #ifdef PXR_MATERIALX_SUPPORT_ENABLED -# include +# include #endif PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/include/HdSt/materialXFilter.h b/Sources/HdSt/include/HdSt/materialXFilter.h index 9d5809b52c..a7dadbdec1 100644 --- a/Sources/HdSt/include/HdSt/materialXFilter.h +++ b/Sources/HdSt/include/HdSt/materialXFilter.h @@ -14,7 +14,7 @@ #include "pxr/pxrns.h" #include #include -#include +#include PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/include/HdSt/materialXShaderGen.h b/Sources/HdSt/include/HdSt/materialXShaderGen.h index 4beceec0a0..66fd48fb48 100644 --- a/Sources/HdSt/include/HdSt/materialXShaderGen.h +++ b/Sources/HdSt/include/HdSt/materialXShaderGen.h @@ -9,9 +9,9 @@ #include "pxr/pxrns.h" -#include -#include -#include +#include +#include +#include PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/include/HdSt/resourceRegistry.h b/Sources/HdSt/include/HdSt/resourceRegistry.h index 5a4d0e27aa..b48e8d51e8 100644 --- a/Sources/HdSt/include/HdSt/resourceRegistry.h +++ b/Sources/HdSt/include/HdSt/resourceRegistry.h @@ -29,7 +29,7 @@ #include #ifdef PXR_MATERIALX_SUPPORT_ENABLED -# include +# include MATERIALX_NAMESPACE_BEGIN using ShaderPtr = std::shared_ptr; MATERIALX_NAMESPACE_END diff --git a/Sources/HdSt/materialPrimvarTransferSceneIndexPlugin.cpp b/Sources/HdSt/materialPrimvarTransferSceneIndexPlugin.cpp index 768174f60f..2c5f8a8b5b 100644 --- a/Sources/HdSt/materialPrimvarTransferSceneIndexPlugin.cpp +++ b/Sources/HdSt/materialPrimvarTransferSceneIndexPlugin.cpp @@ -7,7 +7,7 @@ #include "HdSt/materialPrimvarTransferSceneIndexPlugin.h" #include "Hd/sceneIndexPluginRegistry.h" -#include "Hdsi/materialPrimvarTransferSceneIndex.h" +#include "HdSi/materialPrimvarTransferSceneIndex.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/materialXFilter.cpp b/Sources/HdSt/materialXFilter.cpp index d926392c1c..ff7ecad999 100644 --- a/Sources/HdSt/materialXFilter.cpp +++ b/Sources/HdSt/materialXFilter.cpp @@ -23,10 +23,10 @@ #include "Tf/diagnostic.h" -#include -#include -#include -#include +#include +#include +#include +#include namespace mx = MaterialX; diff --git a/Sources/HdSt/materialXShaderGen.cpp b/Sources/HdSt/materialXShaderGen.cpp index 8e1fe51fd1..dc18f89c70 100644 --- a/Sources/HdSt/materialXShaderGen.cpp +++ b/Sources/HdSt/materialXShaderGen.cpp @@ -8,14 +8,14 @@ #include "HdSt/materialXFilter.h" #include "Tf/stringUtils.h" -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include namespace mx = MaterialX; diff --git a/Sources/HdSt/nodeIdentifierResolvingSceneIndexPlugin.cpp b/Sources/HdSt/nodeIdentifierResolvingSceneIndexPlugin.cpp index 289f682268..bce2c9c1a0 100644 --- a/Sources/HdSt/nodeIdentifierResolvingSceneIndexPlugin.cpp +++ b/Sources/HdSt/nodeIdentifierResolvingSceneIndexPlugin.cpp @@ -3,9 +3,9 @@ // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. -#include "nodeIdentifierResolvingSceneIndexPlugin.h" +#include "HdSt/nodeIdentifierResolvingSceneIndexPlugin.h" -#include "nodeIdentifierResolvingSceneIndex.h" +#include "HdSt/nodeIdentifierResolvingSceneIndex.h" #include "Hd/sceneIndexPluginRegistry.h" diff --git a/Sources/HdSt/resourceRegistry.cpp b/Sources/HdSt/resourceRegistry.cpp index 6c92e4daee..069223d426 100644 --- a/Sources/HdSt/resourceRegistry.cpp +++ b/Sources/HdSt/resourceRegistry.cpp @@ -28,7 +28,7 @@ #include "Tf/hash.h" #ifdef PXR_MATERIALX_SUPPORT_ENABLED -# include +# include #endif PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/shaders/basisCurves.glslfx b/Sources/HdSt/shaders/basisCurves.glslfx new file mode 100644 index 0000000000..f389a14a64 --- /dev/null +++ b/Sources/HdSt/shaders/basisCurves.glslfx @@ -0,0 +1,1315 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/basisCurves.glslfx + +#import $TOOLS/hdSt/shaders/instancing.glslfx +#import $TOOLS/hdSt/shaders/terminals.glslfx +#import $TOOLS/hdSt/shaders/pointId.glslfx +#import $TOOLS/hdSt/shaders/visibility.glslfx + +// Known issues: +// * The direction of the 'v' post tessellation is inconsistent between +// curve representations with regards to whether it increases from left to right +// or right to left. If we start using materials that require 'v', we should fix +// this to be both consistent and match the RenderMan default orientation. +// +// * RenderMan uses 'u' describe the parameter along curve profile and 'v' to +// describe the curve length. It's opposite here. It would be good to align +// these once we start to use 'u' and 'v' in curve materials. +// +// * We might want to explore using fractional_even_spacing to better preserve +// the shape of cubic curves. +// +// * We've realized that u appears to be 'backwards' in many cases, and so we +// have updated many of the functions to use +// mix(endPointValue, startPointValue, u) when intuitively it should be +// the other way around. + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonData + +struct Coeffs +{ + vec4 basis; + vec4 tangent_basis; +}; + +struct CurveData +{ + vec4 Peye[4]; + vec3 Neye[4]; +}; + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTess.CurveData + +CurveData PopulatePeyeAndNeye() +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + + CurveData vertexData; + for (int i = 0; i < HD_NUM_PATCH_VERTS; i++) { + vertexData.Peye[i] = vec4(GetWorldToViewMatrix() * transform * + vec4(HdGet_points(i), 1.0)); + vertexData.Neye[i] = getNormal(transpose(transformInv * + GetWorldToViewInverseMatrix()), i); + } + return vertexData; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Tess.CurveData.Patch + +CurveData PopulatePeyeAndNeye() +{ + CurveData vertexData; + for (int i = 0; i < gl_MaxPatchVertices; i++) { + vertexData.Peye[i] = inData[i].Peye; + vertexData.Neye[i] = inData[i].Neye; + } + return vertexData; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Tess.CurveData.Wire + +CurveData PopulatePeye() +{ + CurveData vertexData; + for (int i = 0; i < gl_MaxPatchVertices; i++) { + vertexData.Peye[i] = inData[i].Peye; + } + return vertexData; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessFactorsGLSL + +void SetTessFactors(float out0, float out1, float out2, float out3, + float in0, float in1) +{ + gl_TessLevelOuter[0] = out0; + gl_TessLevelOuter[1] = out1; + gl_TessLevelOuter[2] = out2; + gl_TessLevelOuter[3] = out3; + + gl_TessLevelInner[0] = in0; + gl_TessLevelInner[1] = in1; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessFactorsMSL + +void SetTessFactors(float out0, float out1, float out2, float out3, + float in0, float in1) +{ + device half *tessAsHalf = (device half *)tessFactors + patch_id * 6; + + tessAsHalf[0] = half(out0); + tessAsHalf[1] = half(out1); + tessAsHalf[2] = half(out2); + tessAsHalf[3] = half(out3); + + tessAsHalf[4] = half(in0); + tessAsHalf[5] = half(in1); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.Vertex.Patch + +[ + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.Vertex.Patch + +// We will either generate a camera facing normal or use the authored normal. +FORWARD_DECL(vec3 getNormal(MAT4 transform)); +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + + outData.Peye = vec4(GetWorldToViewMatrix() * transform * + vec4(HdGet_points(), 1)); + outData.Neye = getNormal(transpose(transformInv * + GetWorldToViewInverseMatrix())); + + ProcessPrimvarsIn(); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + int pointId = GetPointId(); +#if defined(HD_HAS_pointSizeScale) + float scale = HdGet_pointSizeScale(); +#else + float scale = 1; +#endif + gl_PointSize = GetPointRasterSize(pointId) * scale; + ProcessPointId(pointId); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Vertex.Normal.Implicit + +vec3 getNormal(MAT4 transform) +{ + // Generate a camera-facing normal in camera/eye space, designed to match + // RenderMan. + return vec3(0, 0, 1); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Vertex.Normal.Oriented + +vec3 getNormal(MAT4 transform) +{ + return (transform * vec4(HdGet_normals(), 0)).xyz; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTess.Normal.Implicit + +vec3 getNormal(MAT4 transform, int index) +{ + // Generate a camera-facing normal in camera/eye space, designed to match + // RenderMan. + return vec3(0, 0, 1); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTess.Normal.Oriented + +vec3 getNormal(MAT4 transform, int index) +{ + return (transform * vec4(HdGet_normals(index), 0)).xyz; +} + +--- -------------------------------------------------------------------------- +-- layout Curves.Vertex.Wire + +[ + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.Vertex.Wire + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + outData.Peye = vec4(GetWorldToViewMatrix() * transform * + vec4(HdGet_points(), 1)); + + ProcessPrimvarsIn(); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + int pointId = GetPointId(); +#if defined(HD_HAS_pointSizeScale) + float scale = HdGet_pointSizeScale(); +#else + float scale = 1; +#endif + gl_PointSize = GetPointRasterSize(pointId) * scale; + ProcessPointId(pointId);} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonControl + +float GetMaxTess() +{ + // Should be replaced with a uniform + return 40; +} + +float GetPixelToTessRatio() +{ + // Should be replaced with a uniform + return 20.0; +} + +vec2 projectToScreen(MAT4 projMat, vec4 P, vec2 screen_size) +{ + vec4 res = vec4(projMat * P); + res /= res.w; + return (clamp(res.xy, -1.3f, 1.3f) + 1.0f) * (screen_size * 0.5f); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTessControl.Linear.Patch + +void main(void) +{ + CurveData vertexData = PopulatePeyeAndNeye(); + determineLODSettings(vertexData); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.TessControl.Linear.Patch + +[ + ["out", "HD_NUM_PATCH_EVAL_VERTS"], + ["in block array", "CurveVertexData", "inData", "gl_MaxPatchVertices", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block array", "CurveVertexData", "outData", "HD_NUM_PATCH_EVAL_VERTS", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessControl.Linear.Patch + +void determineLODSettings(CurveData vertexData); +void main(void) +{ + if (gl_InvocationID == 0) { + CurveData vertexData = PopulatePeyeAndNeye(); + determineLODSettings(vertexData); + } + + outData[gl_InvocationID].Peye = inData[gl_InvocationID].Peye; + outData[gl_InvocationID].Neye = inData[gl_InvocationID].Neye; + + ProcessPrimvarsOut(); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonControl.Linear.Ribbon + +// Use the length of the control points in screen space to determine how many +// times to subdivide the curve. +void determineLODSettings(CurveData vertexData) +{ + SetTessFactors(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonControl.Linear.HalfTube + +// Use the width of the control points in screen space to determine how +// many times to subdivide the curve. NOTE. As a quick hack, we leverage the +// fact that the normal isn't normalized at this point in the pipeline to +// provide a quick estimate of width in eye space. If that becomes a bad +// assumption in the future, this needs to be reworked. +void determineLODSettings(CurveData vertexData) +{ + MAT4 projMat = GetProjectionMatrix(); + vec4 viewport = GetViewport(); + vec2 screen_size = vec2(viewport.z, viewport.w); + + // NOTE. We've observed that outData.Neye is not normalized, and + // we're using its length as an estimator of the accumulated transform + float wEye0 = HdGet_widths(0) * length(vertexData.Neye[0]); + float wEye1 = HdGet_widths(1) * length(vertexData.Neye[1]); + + // project a point that is 'w' units away from the origin + vec2 v_w0 = projectToScreen(projMat, vec4(wEye0, 0, 0, 1), screen_size); + vec2 v_w1 = projectToScreen(projMat, vec4(wEye1, 0, 0, 1), screen_size); + + float maxTess = GetMaxTess(); + // reduce the tessellation in the width by this value. + float widthDecimation = 10.0; + + float maxWidthScreenSpace = max(length(v_w0), length(v_w1)); + + float level_w = clamp( + maxWidthScreenSpace / GetPixelToTessRatio() / widthDecimation, + 1.0f, maxTess); + + SetTessFactors(1.0f, level_w, 1.0f, level_w, level_w, 1.0f); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTessControl.Cubic.Wire +void main(void) +{ + MAT4 projMat = HdGet_projectionMatrix(); + vec4 viewport = HdGet_viewport(); + vec2 screen_size = vec2(viewport.z, viewport.w); + + CurveData vertexData = PopulatePeyeAndNeye(Peye, Neye); + vec2 v0 = projectToScreen(projMat, vertexData.Peye[0], screen_size); + vec2 v1 = projectToScreen(projMat, vertexData.Peye[1], screen_size); + vec2 v2 = projectToScreen(projMat, vertexData.Peye[2], screen_size); + vec2 v3 = projectToScreen(projMat, vertexData.Peye[3], screen_size); + + float maxTess = GetMaxTess(); + + // Need to handle off screen + float dist = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); + float level = clamp(dist / GetPixelToTessRatio(), 0.0f, maxTess); + + SetTessFactors(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, level); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.TessControl.Cubic.Wire + +[ + ["out", "HD_NUM_PATCH_EVAL_VERTS"], + ["in block array", "CurveVertexData", "inData", "gl_MaxPatchVertices", + ["vec4", "Peye"] + ], + ["out block array", "CurveVertexData", "outData", "HD_NUM_PATCH_EVAL_VERTS", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessControl.Cubic.Wire + +void determineLODSettings(CurveData vertexData); +void main(void) +{ + if (gl_InvocationID == 0) { + CurveData vertexData = PopulatePeye(); + determineLODSettings(vertexData); + } + + outData[gl_InvocationID].Peye = inData[gl_InvocationID].Peye; + + ProcessPrimvarsOut(); +} + +// Use the length of the control points in screen space to determine how many +// times to subdivide the curve. +void determineLODSettings(CurveData vertexData) +{ + MAT4 projMat = GetProjectionMatrix(); + vec4 viewport = GetViewport(); + vec2 screen_size = vec2(viewport.z, viewport.w); + vec2 v0 = projectToScreen(projMat, vertexData.Peye[0], screen_size); + vec2 v1 = projectToScreen(projMat, vertexData.Peye[1], screen_size); + vec2 v2 = projectToScreen(projMat, vertexData.Peye[2], screen_size); + vec2 v3 = projectToScreen(projMat, vertexData.Peye[3], screen_size); + + float maxTess = GetMaxTess(); + + // Need to handle off screen + float dist = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); + float level = clamp(dist / GetPixelToTessRatio(), 0.0f, maxTess); + + SetTessFactors(1.0f, level, 0.0f, 0.0f, 0.0f, 0.0f); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTessControl.Cubic.Patch + +void main(void) +{ + CurveData vertexData = PopulatePeyeAndNeye(); + determineLODSettings(vertexData); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.TessControl.Cubic.Patch + +[ + ["out", "HD_NUM_PATCH_EVAL_VERTS"], + ["in block array", "CurveVertexData", "inData", "gl_MaxPatchVertices", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block array", "CurveVertexData", "outData", "HD_NUM_PATCH_EVAL_VERTS", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessControl.Cubic.Patch + +void determineLODSettings(CurveData vertexData); +void main(void) +{ + if (gl_InvocationID == 0) { + CurveData vertexData = PopulatePeyeAndNeye(); + determineLODSettings(vertexData); + } + + outData[gl_InvocationID].Peye = inData[gl_InvocationID].Peye; + outData[gl_InvocationID].Neye = inData[gl_InvocationID].Neye; + + ProcessPrimvarsOut(); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonControl.Cubic.Ribbon + +// Use the length of the control points in screen space to determine how many +// times to subdivide the curve. +void determineLODSettings(CurveData vertexData) +{ + MAT4 projMat = GetProjectionMatrix(); + vec4 viewport = GetViewport(); + vec2 screen_size = vec2(viewport.z, viewport.w); + vec2 v0 = projectToScreen(projMat, vertexData.Peye[0], screen_size); + vec2 v1 = projectToScreen(projMat, vertexData.Peye[1], screen_size); + vec2 v2 = projectToScreen(projMat, vertexData.Peye[2], screen_size); + vec2 v3 = projectToScreen(projMat, vertexData.Peye[3], screen_size); + + float maxTess = GetMaxTess(); + + // Need to handle off screen + float dist = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); + float level = clamp(dist / GetPixelToTessRatio(), 0.0f, maxTess); + + SetTessFactors(level, 1.0f, level, 1.0f, 1.0f, level); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonControl.Cubic.HalfTube + +// Use the width & length of the control points in screen space to determine how +// many times to subdivide the curve. NOTE. As a quick hack, we leverage the +// fact that the normal isn't normalized at this point in the pipeline to +// provide a quick estimate of width in eye space. If that becomes a bad +// assumption in the future, this needs to be reworked. +void determineLODSettings(CurveData vertexData) +{ + MAT4 projMat = GetProjectionMatrix(); + vec4 viewport = GetViewport(); + vec2 screen_size = vec2(viewport.z, viewport.w); + vec2 v0 = projectToScreen(projMat, vertexData.Peye[0], screen_size); + vec2 v1 = projectToScreen(projMat, vertexData.Peye[1], screen_size); + vec2 v2 = projectToScreen(projMat, vertexData.Peye[2], screen_size); + vec2 v3 = projectToScreen(projMat, vertexData.Peye[3], screen_size); + + // NOTE. We've observed that outData.Neye is not normalized, and + // we're using its length as an estimator of the accumulated transform + float wEye0 = HdGet_widths(0) * length(vertexData.Neye[0]); + float wEye1 = HdGet_widths(1) * length(vertexData.Neye[1]); + float wEye2 = HdGet_widths(2) * length(vertexData.Neye[2]); + float wEye3 = HdGet_widths(3) * length(vertexData.Neye[3]); + + // project a point that is 'w' units away from the origin + vec2 v_w0 = projectToScreen(projMat, vec4(wEye0, 0, 0, 1), screen_size); + vec2 v_w1 = projectToScreen(projMat, vec4(wEye1, 0, 0, 1), screen_size); + vec2 v_w2 = projectToScreen(projMat, vec4(wEye2, 0, 0, 1), screen_size); + vec2 v_w3 = projectToScreen(projMat, vec4(wEye3, 0, 0, 1), screen_size); + + float maxTess = GetMaxTess(); + // reduce the tessellation in the width by this value. + float widthDecimation = 10.0; + + // Need to handle off screen + float dist = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); + float level = clamp(dist / GetPixelToTessRatio(), 0.0f, maxTess); + + float maxWidthScreenSpace = + max(max(max(length(v_w0), length(v_w1)), length(v_w2)), length(v_w3)); + + float level_w = clamp( + maxWidthScreenSpace / GetPixelToTessRatio() / widthDecimation, + 1.0f, maxTess); + + SetTessFactors(level, level_w, level, level_w, level_w, level); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.PostTessVertex.Cubic.Wire + +[ + ["in", "quads"], + ["in", "fractional_odd_spacing"], + ["in", "ccw"], + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTessVertex.Cubic.Wire + +void main(void) +{ + float u = gl_TessCoord.x; + float v = .5; + + CurveData vertexData = PopulatePeyeAndNeye(); + + Coeffs coeffs = evaluateBasis(u, vertexData.Peye); + vec4 basis = coeffs.basis; + vec4 pos = basis[0] * vertexData.Peye[0] + + basis[1] * vertexData.Peye[1] + + basis[2] * vertexData.Peye[2] + + basis[3] * vertexData.Peye[3]; + + outData.Peye = pos; + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 3, vec2(u, v)); // interpolate varying primvars +} + +--- -------------------------------------------------------------------------- +-- layout Curves.TessEval.Cubic.Wire + +[ + ["in", "isolines"], + ["in", "fractional_odd_spacing"], + ["in block array", "CurveVertexData", "inData", "gl_MaxPatchVertices", + ["vec4", "Peye"] + ], + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessEval.Cubic.Wire + +FORWARD_DECL(Coeffs evaluateBasis(float u, const vec4 cv[4])); + +void main() +{ + float u = gl_TessCoord.x; + float v = .5; + + const vec4 cv[4] = { + inData[0].Peye, + inData[1].Peye, + inData[2].Peye, + inData[3].Peye, + }; + + Coeffs coeffs = evaluateBasis(u, cv); + vec4 basis = coeffs.basis; + vec4 pos = + basis[0] * cv[0] + + basis[1] * cv[1] + + basis[2] * cv[2] + + basis[3] * cv[3]; + + outData.Peye = pos; + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 3, vec2(u, v)); // interpolate varying primvars +} + +--- -------------------------------------------------------------------------- +-- layout Curves.PostTessVertex.Patch + +[ + ["in", "quads"], + ["in", "fractional_odd_spacing"], + ["in", "ccw"], + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "float", "u"], + ["out", "float", "v"] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.PostTessVertex.Patch + +--- -------------------------------------------------------------------------- +-- layout Curves.TessEval.Patch + +[ + ["in", "quads"], + ["in", "fractional_odd_spacing"], + ["in", "ccw"], + ["in block array", "CurveVertexData", "inData", "gl_MaxPatchVertices", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block", "CurveVertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "float", "u"], + ["out", "float", "v"] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.TessEval.Patch + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.Patch + +// Predefine so that we can later swap in the correct one depending +// on what type of curve we have + +FORWARD_DECL( + void evaluate(float u, float v, REF(thread, vec4) position, + REF(thread, vec4) tangent, REF(thread, float) width, + REF(thread, vec3) normal, CurveData vertexData)); +FORWARD_DECL(Coeffs evaluateBasis(float u, const vec4 cv[4])); + +// it's the responsibility of orient to store Neye, usually with either +// the computed normal or the tangent (from which the normal will be computed +// in the fragment shader.) +FORWARD_DECL(vec3 orient(float v, vec4 position, vec4 tangent, vec3 normal)); + +void main() +{ + u = gl_TessCoord.y; + v = gl_TessCoord.x; + + CurveData vertexData = PopulatePeyeAndNeye(); + + Coeffs coeffs = evaluateBasis(u, vertexData.Peye); + vec4 basis = coeffs.basis; + + vec4 position; + vec4 tangent; + float rawWidth; + vec3 normal; + + evaluate(u, v, position, tangent, rawWidth, normal, vertexData); + vec3 direction = orient(v, position, tangent, normal); + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + float worldSpaceWidth = rawWidth * length( + GetWorldToViewMatrix() * transform * vec4(direction, 0)); + + MAT4 projMat = GetProjectionMatrix(); + +#if defined(HD_HAS_screenSpaceWidths) || defined(HD_HAS_minScreenSpaceWidths) + + // If any screen space width operations are required, compute the + // conversion factor from world units to screen pixels at this curve tess + // position. Critically, this procedure does not rely on the thickening + // 'direction' vector, which may point out of the image plane and have + // zero apparent screen-space length in some circumstances. + // + // This procedure is correct for both perspective and ortho cameras. It is a + // boiled-down x-only expression of the projected pixel length of a + // hypothetical unit X vector in eye space, and can be derived by writing a + // projection matrix transforming (1,0,0,1) and performing the usual + // division by w. Since the viewport is 2 NDC units across, we take half the + // viewportSizeX. The division is by -position.z for perspective projections + // and by 1 for ortho projections, using entries 2,3 and 3,3 to select + // which. See articles on the forms of these projection matrices for more + // info. + float x = projMat[0][0]; + float w = position.z * projMat[2][3] + projMat[3][3]; + float viewportSizeX = GetViewport().z; + float worldToPixelWidth = abs((viewportSizeX * 0.5) * (x / w)); + +#ifdef HD_HAS_screenSpaceWidths + if (HdGet_screenSpaceWidths()) { + // Compute a world space width that yields the given width interpreted + // in screen space pixels. + worldSpaceWidth = rawWidth / worldToPixelWidth; + } +#endif + +#ifdef HD_HAS_minScreenSpaceWidths + // Compute a world space width that yields, at minimum, the given + // minScreenSpaceWidth interpreted in screen space pixels. + float minScreenSpaceWidth = HdGet_minScreenSpaceWidths(); + float screenSpaceWidth = worldSpaceWidth * worldToPixelWidth; + if (screenSpaceWidth < minScreenSpaceWidth) { + worldSpaceWidth *= minScreenSpaceWidth / screenSpaceWidth; + } +#endif + +#endif // end screen space operations + + vec3 offset = direction * worldSpaceWidth * 0.5; + position.xyz = position.xyz + offset; + position.w = 1; + + outData.Peye = position; + + gl_Position = vec4(projMat * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 3, vec2(u, v)); // interpolate varying primvars +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.Linear.Patch + +vec3 evaluateNormal(float u, CurveData vertexData) +{ + // XXX: This clamp is a hack to mask some odd orientation flipping issues + u = clamp(u, 1e-3f, 1.0f - 1e-3f); + return mix(vertexData.Neye[1], vertexData.Neye[0], u); +} + +void evaluate(float u, float v, REF(thread, vec4) position, + REF(thread, vec4) tangent, REF(thread, float) width, + REF(thread, vec3) normal, CurveData vertexData) { + vec4 p0 = vertexData.Peye[0]; + vec4 p1 = vertexData.Peye[1]; + + float w0 = HdGet_widths(0); + float w1 = HdGet_widths(1); + + position = mix(p1, p0, u); + tangent = normalize(p1 - p0); + width = mix(w1, w0, u); + normal = normalize(evaluateNormal(u, vertexData)); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.Cubic.Patch + +FORWARD_DECL(Coeffs evaluateBasis(float u, const vec4 cv[4])); +FORWARD_DECL(float evaluateWidths(vec4 basis, float u)); +FORWARD_DECL(vec3 evaluateNormal(vec4 basis, float u, CurveData vertexData)); + +void evaluate(float u, float v, REF(thread, vec4) position, + REF(thread, vec4) tangent, REF(thread, float) width, + REF(thread, vec3) normal, CurveData vertexData) { + Coeffs coeffs = evaluateBasis(u, vertexData.Peye); + + position = coeffs.basis[0] * vertexData.Peye[0] + + coeffs.basis[1] * vertexData.Peye[1] + + coeffs.basis[2] * vertexData.Peye[2] + + coeffs.basis[3] * vertexData.Peye[3]; + + tangent = coeffs.tangent_basis[0] * vertexData.Peye[0] + + coeffs.tangent_basis[1] * vertexData.Peye[1] + + coeffs.tangent_basis[2] * vertexData.Peye[2] + + coeffs.tangent_basis[3] * vertexData.Peye[3]; + + width = evaluateWidths(coeffs.basis, u); + normal = normalize(evaluateNormal(coeffs.basis, u, vertexData)); + const float tanLength = length(tangent); + if (tanLength > 1e-5) { + tangent /= tanLength; + } else { + // Flipped from what you expect. + tangent = normalize(vertexData.Peye[0] - vertexData.Peye[3]); + } +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.HalfTube + +vec3 orient(float v, vec4 position, vec4 tangent, vec3 normal){ + outData.Neye = tangent.xyz; + vec3 d = normalize(cross(position.xyz, tangent.xyz)); + vec3 n = normalize(cross(d, tangent.xyz)); + + vec3 norm_pos = mix(n, d, (2.0*v) - 1.0); + vec3 norm_neg = mix(-d, n, (2.0*v)); + normal = normalize(mix(norm_neg, norm_pos, step(0.5, v))); + return normal; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.Ribbon.Oriented + +vec3 orient(float v, vec4 position, vec4 tangent, vec3 normal){ + outData.Neye = normal; + return normalize(cross(tangent.xyz, normal) * (v - 0.5)); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CommonEval.Ribbon.Implicit + +vec3 orient(float v, vec4 position, vec4 tangent, vec3 normal){ + outData.Neye = tangent.xyz; + // NOTE: lava/lib/basisCurves currently uses tangent X position instead of + // tangent X normal. We should do a more thorough evaluation to see which + // is better but to minimize regressions, we're going to keep this as + // tangent X normal for now. + return normalize(cross(tangent.xyz, normal) * (v - 0.5)); +} + + +--- -------------------------------------------------------------------------- +-- glsl Curves.Cubic.Normals.Basis + +vec3 evaluateNormal(vec4 basis, float u, CurveData vertexData) +{ + vec3 n0 = vertexData.Neye[0]; + vec3 n1 = vertexData.Neye[1]; + vec3 n2 = vertexData.Neye[2]; + vec3 n3 = vertexData.Neye[3]; + return n0 * basis.x + + n1 * basis.y + + n2 * basis.z + + n3 * basis.w; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Cubic.Normals.Linear + +// HdSt only supports vertex (cubic) primvar indexes and expands varying +// (linear) primvars so we pull the data out of only the two interior indices. +// This may not be valid for all potential basis, but works well for curves with +// vstep = 1 and bezier, the only supported cubic curves in HdSt. + +vec3 evaluateNormal(vec4 basis, float u, CurveData vertexData) +{ + // XXX: This clamp is a hack to mask some odd orientation flipping issues + // for oriented bezier curves. + u = clamp(u, 1e-3f, 1.0f - 1e-3f); + return mix(vertexData.Neye[2], vertexData.Neye[1], u); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Cubic.Widths.Basis + +float evaluateWidths(vec4 basis, float u) +{ + float w0 = HdGet_widths(0); + float w1 = HdGet_widths(1); + float w2 = HdGet_widths(2); + float w3 = HdGet_widths(3); + return w0 * basis.x + + w1 * basis.y + + w2 * basis.z + + w3 * basis.w; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Cubic.Widths.Linear + +// HdSt only supports vertex (cubic) primvar indexes and expands varying +// (linear) primvars so we pull the data out of only the two interior indices. +// (ie. w0 -> widths[1], w1 -> widths[2]) +// This may not be valid for all potential basis, but works well for curves with +// vstep = 1 and bezier, the only supported cubic curves in HdSt. +float evaluateWidths(vec4 basis, float u) +{ + float w0 = HdGet_widths(1); + float w1 = HdGet_widths(2); + return mix(w1, w0, u); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Linear.VaryingInterpolation + +float InterpolatePrimvar(float inPv0, float inPv1, float inPv2, float inPv3, + vec4 basis, vec2 uv) +{ + return inPv0 * basis.x + + inPv1 * basis.y + + inPv2 * basis.z + + inPv3 * basis.w; +} + +vec2 InterpolatePrimvar(vec2 inPv0, vec2 inPv1, vec2 inPv2, vec2 inPv3, + vec4 basis, vec2 uv) +{ + return inPv0 * basis.x + + inPv1 * basis.y + + inPv2 * basis.z + + inPv3 * basis.w; +} + +vec3 InterpolatePrimvar(vec3 inPv0, vec3 inPv1, vec3 inPv2, vec3 inPv3, + vec4 basis, vec2 uv) +{ + return inPv0 * basis.x + + inPv1 * basis.y + + inPv2 * basis.z + + inPv3 * basis.w; +} + +vec4 InterpolatePrimvar(vec4 inPv0, vec4 inPv1, vec4 inPv2, vec4 inPv3, + vec4 basis, vec2 uv) +{ + return inPv0 * basis.x + + inPv1 * basis.y + + inPv2 * basis.z + + inPv3 * basis.w; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Cubic.VaryingInterpolation + +float InterpolatePrimvar(float inPv0, float inPv1, float inPv2, float inPv3, + vec4 basis, vec2 uv) +{ + return mix(inPv2, inPv1, uv.x); +} + +vec2 InterpolatePrimvar(vec2 inPv0, vec2 inPv1, vec2 inPv2, vec2 inPv3, + vec4 basis, vec2 uv) +{ + return mix(inPv2, inPv1, uv.x); +} + +vec3 InterpolatePrimvar(vec3 inPv0, vec3 inPv1, vec3 inPv2, vec3 inPv3, + vec4 basis, vec2 uv) +{ + return mix(inPv2, inPv1, uv.x); +} + +vec4 InterpolatePrimvar(vec4 inPv0, vec4 inPv1, vec4 inPv2, vec4 inPv3, + vec4 basis, vec2 uv) +{ + return mix(inPv2, inPv1, uv.x); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.BezierBasis + +Coeffs evaluateBasis(float u, const vec4 cv[4]) +{ + const float u2 = u*u; + const float u3 = u2*u; + + vec4 basis; vec4 tangent_basis; + basis[0] = u3; + basis[1] = -3.0*u3 + 3.0*u2; + basis[2] = 3.0*u3 - 6.0*u2 + 3.0*u; + basis[3] = -1.0*u3 + 3.0*u2 - 3.0*u + 1.0; + + tangent_basis[0] = 3.0*u2; + tangent_basis[1] = -9.0*u2 + 6.0*u; + tangent_basis[2] = 9.0*u2 - 12.0*u + 3.0; + tangent_basis[3] = -3.0*u2 + 6.0*u - 3.0; + + Coeffs coeffs = { basis, tangent_basis }; + return coeffs; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.LinearBasis + +Coeffs evaluateBasis(float u, const vec4 cv[4]) +{ + const float u2 = u*u; + const float u3 = u2*u; + + vec4 basis; vec4 tangent_basis; + basis[0] = u; + basis[1] = 1.0 - u; + basis[2] = 0; + basis[3] = 0.0; + + tangent_basis[0] = 1; + tangent_basis[1] = -1; + tangent_basis[2] = 0; + tangent_basis[3] = 0; + + Coeffs coeffs = { basis, tangent_basis }; + return coeffs; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CatmullRomBasis + +Coeffs evaluateBasis(float u, const vec4 cv[4]) +{ + const float u2 = u*u; + const float u3 = u2*u; + + vec4 basis; vec4 tangent_basis; + basis[0] = 0.5*u3 - 0.5*u2; + basis[1] = -1.5*u3 + 2.0*u2 + 0.5*u; + basis[2] = 1.5*u3 - 2.5*u2 + 1.0; + basis[3] = -0.5*u3 + u2 - 0.5*u; + + tangent_basis[0] = 1.5*u2 - u; + tangent_basis[1] = -4.5*u2 + 4.0*u + 0.5; + tangent_basis[2] = 4.5*u2 - 5.0*u; + tangent_basis[3] = -1.5*u2 + 2.0*u - 0.5; + + Coeffs coeffs = { basis, tangent_basis }; + return coeffs; +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.CentripetalCatmullRomBasis + +Coeffs evaluateBasis(float u, const vec4 cv[4]) +{ + // centripetal arc-length + float d01 = sqrt(length(cv[1] - cv[0])); + float d12 = sqrt(length(cv[2] - cv[1])); + float d23 = sqrt(length(cv[3] - cv[2])); + + // handling generate CVs. + if (d12 < 1.e-4) d12 = 1.; + if (d01 < 1.e-4) d01 = d12; + if (d23 < 1.e-4) d23 = d12; + + // centripetal reparametrization + vec4 w; + w[0] = 0.; + w[1] = w[0] + d01; + w[2] = w[1] + d12; + w[3] = w[2] + d23; + + // remap parameter value to reparametrized values. + const float t = (1.-u)*w[1] + u*w[2]; + const float dtdu = w[2] - w[1]; + + // coefficients (and derivatives) for recursive evaluation. + + vec2 P01, dP01; + vec2 P12, dP12; + vec2 P23, dP23; + vec2 P012, dP012; + vec2 P123, dP123; + vec2 P0123, dP0123; + + P01[0] = (w[1] - t) / (w[1] - w[0]); + dP01[0] = - dtdu / (w[1] - w[0]); + + P12[0] = (w[2] - t) / (w[2] - w[1]); + dP12[0] = - dtdu / (w[2] - w[1]); + + P23[0] = (w[3] - t) / (w[3] - w[2]); + dP23[0] = - dtdu / (w[3] - w[2]); + + P012[0] = (w[2] - t) / (w[2] - w[0]); + dP012[0] = - dtdu / (w[2] - w[0]); + + P123[0] = (w[3] - t) / (w[3] - w[1]); + dP123[0] = - dtdu / (w[3] - w[1]); + + P0123[0] = (w[2] - t) / (w[2] - w[1]); + dP0123[0] = - dtdu / (w[2] - w[1]); + + P01[1] = 1. - P01[0]; + P12[1] = 1. - P12[0]; + P23[1] = 1. - P23[0]; + P012[1] = 1. - P012[0]; + P123[1] = 1. - P123[0]; + P0123[1] = 1. - P0123[0]; + + dP01[1] = - dP01[0]; + dP12[1] = - dP12[0]; + dP23[1] = - dP23[0]; + dP012[1] = - dP012[0]; + dP123[1] = - dP123[0]; + dP0123[1] = - dP0123[0]; + + vec4 basis; + basis[0] = P01[0]*P012[0]*P0123[0]; + basis[1] = P01[1]*P012[0]*P0123[0] + + P12[0]*P012[1]*P0123[0] + P12[0]*P123[0]*P0123[1]; + basis[2] = P12[1]*P012[1]*P0123[0] + + P12[1]*P123[0]*P0123[1] + P23[0]*P123[1]*P0123[1]; + basis[3] = P23[1]*P123[1]*P0123[1]; + + vec4 tangent_basis; + tangent_basis[0] = dP01[0]*P012[0]*P0123[0] + + P01[0]*dP012[0]*P0123[0] + P01[0]*P012[0]*dP0123[0]; + tangent_basis[1] = dP01[1]*P012[0]*P0123[0] + + P01[1]*dP012[0]*P0123[0] + P01[1]*P012[0]*dP0123[0] + + dP12[0]*P012[1]*P0123[0] + P12[0]*dP012[1]*P0123[0] + + P12[0]*P012[1]*dP0123[0] + dP12[0]*P123[0]*P0123[1] + + P12[0]*dP123[0]*P0123[1] + P12[0]*P123[0]*dP0123[1]; + tangent_basis[2] = dP12[1]*P012[1]*P0123[0] + + P12[1]*dP012[1]*P0123[0] + P12[1]*P012[1]*dP0123[0] + + dP12[1]*P123[0]*P0123[1] + P12[1]*dP123[0]*P0123[1] + + P12[1]*P123[0]*dP0123[1] + dP23[0]*P123[1]*P0123[1] + + P23[0]*dP123[1]*P0123[1] + P23[0]*P123[1]*dP0123[1]; + tangent_basis[3] = dP23[1]*P123[1]*P0123[1] + + P23[1]*dP123[1]*P0123[1] + P23[1]*P123[1]*dP0123[1]; + + return Coeffs(basis, tangent_basis); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.BsplineBasis + +Coeffs evaluateBasis(float u, const vec4 cv[4]) +{ + const float u2 = u*u; + const float u3 = u2*u; + + vec4 basis; vec4 tangent_basis; + basis[0] = (1.0/6.0)*u3; + basis[1] = -0.5*u3 + 0.5*u2 + 0.5*u + (1.0/6.0); + basis[2] = 0.5*u3 - u2 + (2.0/3.0); + basis[3] = -(1.0/6.0)*u3 + 0.5*u2 - 0.5*u + (1.0/6.0); + + tangent_basis[0] = 0.5*u2; + tangent_basis[1] = -1.5*u2 + u + 0.5; + tangent_basis[2] = 1.5*u2 - 2.0*u; + tangent_basis[3] = -0.5*u2 + u - 0.5; + + Coeffs coeffs = { basis, tangent_basis }; + return coeffs; +} + +--- -------------------------------------------------------------------------- +-- layout Curves.Fragment.Wire + +[ + ["in block", "CurveVertexData", "inData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.Wire + +void main(void) +{ + DiscardBasedOnTopologicalVisibility(); + + vec4 color = vec4(0.5, 0.5, 0.5, 1); +#ifdef HD_HAS_displayColor + color.rgb = HdGet_displayColor().rgb; +#endif +#ifdef HD_HAS_displayOpacity + color.a = HdGet_displayOpacity(); +#endif + vec3 Peye = inData.Peye.xyz / inData.Peye.w; + + // We would like to have a better oriented normal here, however to keep the + // shader fast, we use this camera-facing approximation. + vec3 Neye = vec3(0,0,1); + + vec4 patchCoord = vec4(0); + + color = ShadingTerminal(vec4(Peye, 1), Neye, color, patchCoord); + +#ifdef HD_MATERIAL_TAG_MASKED + if (ShouldDiscardByAlpha(color)) { + discard; + } +#endif + + RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); +} + +--- -------------------------------------------------------------------------- +-- layout Curves.Fragment.Patch + +[ + ["in", "float", "u", "centroid"], + ["in", "float", "v", "centroid"], + ["in block", "CurveVertexData", "inData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.Patch + +/// In the previous stage, we may have stored the tangent in Neye from which +/// we plan to compute a normal in the fragment shader. + +FORWARD_DECL(vec3 fragmentNormal(vec3 position, vec3 normal, float v)); +void main(void) +{ + DiscardBasedOnTopologicalVisibility(); + + vec4 color = vec4(0.5, 0.5, 0.5, 1); +#ifdef HD_HAS_displayColor + color.rgb = HdGet_displayColor().rgb; +#endif +#ifdef HD_HAS_displayOpacity + color.a = HdGet_displayOpacity(); +#endif + vec3 Peye = inData.Peye.xyz / inData.Peye.w; + + vec3 Neye = fragmentNormal(Peye, inData.Neye, v); + + vec4 patchCoord = vec4(0, v, 0, 0); + color = ShadingTerminal(vec4(Peye, 1), Neye, color, patchCoord); + +#ifdef HD_MATERIAL_TAG_MASKED + if (ShouldDiscardByAlpha(color)) { + discard; + } +#endif + + RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.HalfTube + +vec3 fragmentNormal(in vec3 position, in vec3 tangent, in float v) +{ + vec3 d = normalize(cross(position, tangent)); + vec3 n = normalize(cross(d, tangent)); + vec3 norm_pos = mix(n, d, (2.0*v) - 1.0); + vec3 norm_neg = mix(-d, n, (2.0*v)); + return normalize(mix(norm_neg, norm_pos, step(0.5, v))); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.Ribbon.Round + +float remapFragmentV(float v){ + // As we are using a plane to approximate a tube, we don't want to shade + // based on v but rather the projection of the tube's v onto the plane + return clamp((asin(v * 2.0 - 1.0) / (3.146 / 2.0) + 1.0) / 2.0, 0.0, 1.0); +} + +vec3 fragmentNormal(vec3 position, in vec3 tangent, float v) +{ + + // we slightly bias v towards 0.5 based on filterwidth as a hack to + // minimize aliasing + v = mix(remapFragmentV(v), 0.5, min(fwidth(v), .2)); + + vec3 d = normalize(cross(position, tangent)); + vec3 n = normalize(cross(d, tangent)); + vec3 norm_pos = mix(n, d, (2.0*v) - 1.0); + vec3 norm_neg = mix(-d, n, (2.0*v)); + + return normalize(mix(norm_neg, norm_pos, step(0.5, v))); +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.Ribbon.Oriented + +vec3 fragmentNormal(vec3 position, in vec3 normal, float v) +{ + normal = normalize(normal); + if (gl_FrontFacing){ + return normal; + } + else{ + return -normal; + } +} + +--- -------------------------------------------------------------------------- +-- glsl Curves.Fragment.Hair + +// XXX: Neye is interpolated in from previous stages, however the +// polarity is not stable due to instability in the cross-product in the +// TessEval shader. Once that is fixed, we could use Neye directly here. +// The normal computed here results in faceted shading. +// +vec3 fragmentNormal(vec3 position, in vec3 unused, float v) +{ + return cross(dFdx(position), dFdy(position)); +} diff --git a/Sources/HdSt/shaders/compute.glslfx b/Sources/HdSt/shaders/compute.glslfx new file mode 100644 index 0000000000..e562ecd819 --- /dev/null +++ b/Sources/HdSt/shaders/compute.glslfx @@ -0,0 +1,439 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/compute.glslfx + +-- configuration +{ + "techniques": { + "default": { + "smoothNormalsFloatToFloat": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstFloat", + "Compute.SmoothNormals" ] + }, + "smoothNormalsDoubleToDouble": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstDouble", + "Compute.SmoothNormals" ] + }, + "smoothNormalsFloatToPacked": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstPacked", + "Compute.SmoothNormals" ] + }, + "smoothNormalsDoubleToPacked": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstPacked", + "Compute.SmoothNormals" ] + }, + "flatNormalsTriFloatToFloat": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstFloat", + "Compute.FlatNormals", + "Compute.FlatNormalsTri" ] + }, + "flatNormalsTriDoubleToDouble": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstDouble", + "Compute.FlatNormals", + "Compute.FlatNormalsTri" ] + }, + "flatNormalsTriFloatToPacked": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsTri" ] + }, + "flatNormalsTriDoubleToPacked": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsTri" ] + }, + "flatNormalsQuadFloatToFloat": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstFloat", + "Compute.FlatNormals", + "Compute.FlatNormalsQuad" ] + }, + "flatNormalsQuadDoubleToDouble": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstDouble", + "Compute.FlatNormals", + "Compute.FlatNormalsQuad" ] + }, + "flatNormalsQuadFloatToPacked": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsQuad" ] + }, + "flatNormalsQuadDoubleToPacked": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsQuad" ] + }, + "flatNormalsTriQuadFloatToFloat": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstFloat", + "Compute.FlatNormals", + "Compute.FlatNormalsTriQuad" ] + }, + "flatNormalsTriQuadDoubleToDouble": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstDouble", + "Compute.FlatNormals", + "Compute.FlatNormalsTriQuad" ] + }, + "flatNormalsTriQuadFloatToPacked": { + "source": [ "Compute.NormalsSrcFloat", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsTriQuad" ] + }, + "flatNormalsTriQuadDoubleToPacked": { + "source": [ "Compute.NormalsSrcDouble", + "Compute.NormalsDstPacked", + "Compute.FlatNormals", + "Compute.FlatNormalsTriQuad" ] + }, + "quadrangulateFloat": { + "source": [ "Compute.QuadrangulateFloat", + "Compute.Quadrangulate" ] + }, + "quadrangulateDouble": { + "source": [ "Compute.QuadrangulateDouble", + "Compute.Quadrangulate" ] + }, + "evalStencils": { + "source": [ "Compute.EvalStencils" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.NormalsSrcFloat + +vec3 getPoint(int index) +{ + return vec3(points[index], + points[index + 1], + points[index + 2]); +} +--- -------------------------------------------------------------------------- +-- glsl Compute.NormalsSrcDouble + +vec3 getPoint(int index) +{ + return vec3(points[index], + points[index + 1], + points[index + 2]); +} +--- -------------------------------------------------------------------------- +-- glsl Compute.NormalsDstFloat + +void writeNormal(int nIndex, vec3 normal) +{ + normals[nIndex+0] = normal.x; + normals[nIndex+1] = normal.y; + normals[nIndex+2] = normal.z; +} +--- -------------------------------------------------------------------------- +-- glsl Compute.NormalsDstDouble + +void writeNormal(int nIndex, vec3 normal) +{ + normals[nIndex+0] = normal.x; + normals[nIndex+1] = normal.y; + normals[nIndex+2] = normal.z; +} +--- -------------------------------------------------------------------------- +-- glsl Compute.NormalsDstPacked + +void writeNormal(int nIndex, vec3 normal) +{ + normal *= 511.0; + normals[nIndex] = + ((int(normal.x) & 0x3ff) ) | + ((int(normal.y) & 0x3ff) << 10) | + ((int(normal.z) & 0x3ff) << 20); +} +--- -------------------------------------------------------------------------- +-- glsl Compute.SmoothNormals + +int getPointsIndex(int idx) +{ + return (idx+vertexOffset)*pointsStride + pointsOffset; +} + +int getNormalsIndex(int idx) +{ + return (idx+vertexOffset)*normalsStride + normalsOffset; +} + +void main() +{ + int index = int(hd_GlobalInvocationID.x); + if (index >= indexEnd) { + return; + } + + int offIndex = index * 2 + adjacencyOffset; + + int offset = entry[offIndex] + adjacencyOffset; + int valence = entry[offIndex + 1]; + + vec3 normal = vec3(0); + + vec3 current = getPoint(getPointsIndex(index)); + for (int i = 0; i < valence; ++i) { + int entryIdx = i * 2 + offset; + + int prevIdx = entry[entryIdx]; + int nextIdx = entry[entryIdx + 1]; + + vec3 next = getPoint(getPointsIndex(nextIdx)); + vec3 prev = getPoint(getPointsIndex(prevIdx)); + normal += cross(next - current, prev - current); + + } + float n = 1.0/max(length(normal), 0.000001); + normal *= n; + writeNormal(getNormalsIndex(index), normal); +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.FlatNormals + +int getPointsIndex(int idx) +{ + return (idx+vertexOffset)*pointsStride + pointsOffset; +} + +int getNormalsIndex(int idx) +{ + return (idx+elementOffset)*normalsStride + normalsOffset; +} + +int getIndicesIndex(int idx) +{ + return (idx+topologyOffset)*indexStride + indexOffset; +} + +int getPrimitiveParamIndex(int idx) +{ + return (idx+topologyOffset)*pParamStride + pParamOffset; +} + +int getEdgeFlag(int pParam) +{ + return pParam & 3; +} + +int getFaceIndex(int pParam) +{ + return pParam >> 2; +} + +FORWARD_DECL(vec3 computeNormalForPrimIndex(int primIndex)); + +void main() +{ + int primIndex = int(hd_GlobalInvocationID.x); + if (primIndex >= primIndexEnd) { + return; + } + + int pParam = primitiveParam[getPrimitiveParamIndex(primIndex)]; + int edgeFlag = getEdgeFlag(pParam); + int faceIndex = getFaceIndex(pParam); + vec3 normal = vec3(0); + + if (getEdgeFlag(pParam) == 0) { + // 0 indicates an unsplit face (as authored) + normal += computeNormalForPrimIndex(primIndex); + + } else if (getEdgeFlag(pParam) == 1) { + // A subdivided face will have a run of prims with + // edge flags like: 1, 3, 3, 3, 2; where "3" denotes an interior + // prim. Only compute normals for the first prim in a face. + + int primCounter = 0; + do { + pParam = primitiveParam[getPrimitiveParamIndex( + primIndex+primCounter)]; + normal += computeNormalForPrimIndex(primIndex+primCounter); + primCounter++; + } while(getEdgeFlag(pParam) != 2); + + } else { + return; + } + float n = 1.0/max(length(normal), 0.000001); + normal *= n; + writeNormal(getNormalsIndex(faceIndex), normal); +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.FlatNormalsTri + +ivec3 getIndices(int idx) +{ + return ivec3(indices[idx], + indices[idx+1], + indices[idx+2]); +} + +vec3 computeNormalForPrimIndex(int primIndex) +{ + ivec3 indices = getIndices(getIndicesIndex(primIndex)); + + vec3 p0 = getPoint(getPointsIndex(indices.x)); + vec3 p1 = getPoint(getPointsIndex(indices.y)); + vec3 p2 = getPoint(getPointsIndex(indices.z)); + + return cross(p1-p0, p2-p0); +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.FlatNormalsQuad + +ivec4 getIndices(int idx) +{ + return ivec4(indices[idx], + indices[idx+1], + indices[idx+2], + indices[idx+3]); +} + +vec3 computeNormalForPrimIndex(int primIndex) +{ + ivec4 indices = getIndices(getIndicesIndex(primIndex)); + + vec3 p0 = getPoint(getPointsIndex(indices.x)); + vec3 p1 = getPoint(getPointsIndex(indices.y)); + vec3 p2 = getPoint(getPointsIndex(indices.z)); + vec3 p3 = getPoint(getPointsIndex(indices.w)); + + return cross(p0-p3, p2-p3) + cross(p2-p1, p0-p1); +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.FlatNormalsTriQuad + +ivec4 getIndices(int idx) +{ + return ivec4(indices[idx], + indices[idx+1], + indices[idx+2], + indices[idx+4]); +} + +vec3 computeNormalForPrimIndex(int primIndex) +{ + ivec4 indices = getIndices(getIndicesIndex(primIndex)); + + vec3 p0 = getPoint(getPointsIndex(indices.x)); + vec3 p1 = getPoint(getPointsIndex(indices.y)); + vec3 p2 = getPoint(getPointsIndex(indices.z)); + vec3 p3 = getPoint(getPointsIndex(indices.w)); + + return cross(p0-p3, p2-p3) + cross(p2-p1, p0-p1); +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.QuadrangulateFloat + +#define DATATYPE float + +--- -------------------------------------------------------------------------- +-- glsl Compute.QuadrangulateDouble + +#define DATATYPE double + +--- -------------------------------------------------------------------------- +-- glsl Compute.Quadrangulate + +void main() +{ + int index = int(hd_GlobalInvocationID.x); + if (index >= indexEnd) { + return; + } + + int quadInfoIndex = index * quadInfoStride + quadInfoOffset; + int numVert = quadInfo[quadInfoIndex]; + int dstOffset = quadInfo[quadInfoIndex+1]; + + // GPU quadinfo table layout + // + // struct NonQuad { + // int numVert; + // int dstOffset; + // int index[maxNumVert]; + // } quadInfo[] + // + + for (int j = 0; j < numComponents; ++j) { + DATATYPE center = 0; + for (int i = 0; i < numVert; ++i) { + int i0 = quadInfo[quadInfoIndex + 2 + i]; + int i1 = quadInfo[quadInfoIndex + 2 + (i+1)%numVert]; + + DATATYPE v0 = primvar[(i0 + vertexOffset)*primvarStride + primvarOffset + j]; + DATATYPE v1 = primvar[(i1 + vertexOffset)*primvarStride + primvarOffset + j]; + DATATYPE edge = (v0 + v1) * 0.5; + center += v0; + + // edge + primvar[(dstOffset + i + vertexOffset)*primvarStride + primvarOffset + j] = edge; + } + // center + center /= numVert; + primvar[(dstOffset + numVert + vertexOffset)*primvarStride + primvarOffset + j] = center; + } +} + +--- -------------------------------------------------------------------------- +-- glsl Compute.EvalStencils + +void main() +{ + const int pointIndex = pointIndexStart + int(hd_GlobalInvocationID.x); + if (pointIndex >= pointIndexEnd) { + return; + } + + const int numElements = EVAL_STENCILS_NUM_ELEMENTS; + float result[numElements]; + for (int element = 0; element < numElements; ++element) { + result[element] = 0; + } + + const int stencilSize = sizes[pointIndex + sizesBase]; + const int stencilOffset = offsets[pointIndex + offsetsBase]; + + for (int stencil = 0; stencil < stencilSize; ++stencil) { + const int index = indices[stencil + stencilOffset + indicesBase]; + const float weight = weights[stencil + stencilOffset + weightsBase]; + const int srcIndex = (index + srcBase) * srcStride; + for (int element = 0; element < numElements; ++element) { + result[element] += weight * primvar[srcIndex + element]; + } + } + + const int dstIndex = (pointIndex + dstBase) * dstStride; + for (int element = 0; element < numElements; ++element) { + primvar[dstIndex + element] = result[element]; + } +} diff --git a/Sources/HdSt/shaders/domeLight.glslfx b/Sources/HdSt/shaders/domeLight.glslfx new file mode 100644 index 0000000000..922d37fa82 --- /dev/null +++ b/Sources/HdSt/shaders/domeLight.glslfx @@ -0,0 +1,260 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "domeLightIrradiance": { + "source": [ "DomeLight.Common", + "DomeLight.Irradiance" ] + }, + "domeLightPrefilter": { + "source": [ "DomeLight.Common", + "DomeLight.CommonSampling", + "DomeLight.Prefilter" ] + }, + "domeLightBRDF": { + "source": [ "DomeLight.Common", + "DomeLight.CommonSampling", + "DomeLight.BRDF" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl DomeLight.Common + +const float PI = 3.1415926536; + +// compute texture coords based on the size of the output image/texture +vec2 GetTexCoords(ivec2 outCoords) +{ + vec2 outDims = vec2(HgiGetSize_outTexture()); + // apply a (0.5, 0.5) offset to use pixel centers and not pixel corners + vec2 texCoords = (vec2(outCoords) + vec2(0.5, 0.5)) / outDims; + return texCoords; +} + +// sample lat/long env map input texture +vec3 SampleEnvMapLod(vec3 sampleVec, float sampleLod) { + vec2 coord = vec2((atan(sampleVec.z, sampleVec.x) + PI) / (2.0 * PI), + acos(sampleVec.y) / PI); + vec3 value = HgiTextureLod_inTexture(coord, sampleLod).rgb; + + return mix(value, vec3(0.0, 0.0, 0.0), vec3(isnan(value))); +} + +// compute world position from texture coords +vec3 GetWorldPos(vec2 textureCoord) +{ + // have theta range from [-PI, PI] so the origin is in the center + // of the image + float theta = (textureCoord.x * 2.0 * PI) - PI; + float phi = (textureCoord.y * PI); + float x = cos(theta) * sin(phi); + float y = cos(phi); + float z = sin(theta) * sin(phi); + return vec3(x, y, z); +} + +--- -------------------------------------------------------------------------- +-- glsl DomeLight.CommonSampling + +float RadicalInverse(uint a) +{ + return float(bitfieldReverse(a)) * 2.3283064365386963e-10; // 0x1p-32 +} + +vec2 Hammersley2d(uint a, uint N) +{ + return vec2(float(a) / float(N), RadicalInverse(a)); +} + +vec3 ImportanceSample_GGX(vec2 Xi, float roughness, vec3 normal) +{ + // Maps a 2D point to a hemisphere with spread based on roughness + float alpha = roughness * roughness; + float phi = 2.0 * PI * Xi.x; + float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (alpha*alpha - 1.0) * Xi.y)); + float sinTheta = sqrt(1.0 - cosTheta * cosTheta); + vec3 H = vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); + + // Tangent space + vec3 up = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangentX = normalize(cross(up, normal)); + vec3 tangentY = normalize(cross(normal, tangentX)); + + // Convert to world Space + return normalize(tangentX * H.x + tangentY * H.y + normal * H.z); +} + +--- -------------------------------------------------------------------------- +-- glsl DomeLight.Irradiance + +const float deltaPhi = (2.0f * float(PI)) / 180.0f; +const float deltaTheta = (0.5f * float(PI)) / 64.0f; + +vec3 SampleEnvMap(vec3 sampleVec) +{ + // sample from a mipmap level of the environment map determined by the + // size of the environment map and the number of samples we are taking + ivec2 inDims = HgiGetSize_inTexture(); + float mipLevel = ceil(log2(inDims.x * deltaPhi/(2.0 * PI)) * 2.0f); + + return SampleEnvMapLod(sampleVec, mipLevel); +} + +vec3 ComputeIrradiance(vec3 inPos) +{ + vec3 N = normalize(inPos); + vec3 up = vec3(0.0, 1.0, 0.0); + vec3 right = normalize(cross(up, N)); + up = cross(N, right); + + const float TWO_PI = PI * 2.0; + const float HALF_PI = PI * 0.5; + + vec3 color = vec3(0.0); + uint sampleCount = 0u; + for (float phi = 0.0; phi < TWO_PI; phi += deltaPhi) { + for (float theta = 0.0; theta < HALF_PI; theta += deltaTheta) { + vec3 tempVec = cos(phi) * right + sin(phi) * up; + vec3 sampleVector = cos(theta) * N + sin(theta) * tempVec; + color += SampleEnvMap(sampleVector).rgb * cos(theta) * sin(theta); + sampleCount++; + } + } + return PI * color / float(sampleCount); +} + +void main(void) +{ + ivec2 outCoords = ivec2(hd_GlobalInvocationID.xy); + + vec2 texCoords = GetTexCoords(outCoords); + vec3 pos3D = GetWorldPos(texCoords); + vec4 outColor = vec4(ComputeIrradiance(pos3D), 1.0); + + HgiSet_outTexture(outCoords, outColor); +} + +--- -------------------------------------------------------------------------- +-- glsl DomeLight.Prefilter + +// Normal Distribution function +float Distribution_GGX(float dotNH, float roughness) +{ + float alpha = roughness * roughness; + float alpha2 = alpha * alpha; + float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0; + return (alpha2)/(PI * denom*denom); +} + +vec3 PrefilterEnvMap(vec3 R, float roughness) +{ + vec3 N = R; + vec3 V = R; + vec3 color = vec3(0.0); + float totalWeight = 0.0; + float envMapDim = float(HgiGetSize_inTexture().x); + const uint numSamples = 1024u; + for (uint i = 0u; i < numSamples; i++) { + vec2 Xi = Hammersley2d(i, numSamples); + vec3 H = ImportanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + float dotNL = clamp(dot(N, L), 0.0, 1.0); + if (dotNL > 0.0) { + + float dotNH = clamp(dot(N, H), 0.0, 1.0); + float dotVH = clamp(dot(V, H), 0.0, 1.0); + + // Probability Distribution Function + float pdf = Distribution_GGX(dotNH, roughness) * dotNH + / (4.0 * dotVH) + 0.0001; + // Solid angle of current sample + float omegaS = 1.0 / (float(numSamples) * pdf); + // Solid angle of 1 pixel across all cube faces + float omegaP = 4.0 * PI / (6.0 * envMapDim * envMapDim); + // Biased (+1.0) mip level for better result + float mipLevel = roughness == 0.0 + ? 0.0 : max(0.5 * log2(omegaS / omegaP) + 1.0, 0.0f); + color += SampleEnvMapLod(L, mipLevel).rgb * dotNL; + totalWeight += dotNL; + + } + } + return (color / totalWeight); +} + +void main(void) +{ + ivec2 outCoords = ivec2(hd_GlobalInvocationID.xy); + + vec2 texCoords = GetTexCoords(outCoords); + vec3 pos3D = GetWorldPos(texCoords); + vec3 R = normalize(pos3D); + vec4 outColor = vec4(PrefilterEnvMap(R, inRoughness), 1.0); + + HgiSet_outTexture(outCoords, outColor); +} + +--- -------------------------------------------------------------------------- +-- glsl DomeLight.BRDF + +float Geometry_SchlicksmithGGX(float dotNL, float dotNV, float roughness) +{ + float k = (roughness * roughness) / 2.0; + float GL = dotNL / (dotNL * (1.0 - k) + k); + float GV = dotNV / (dotNV * (1.0 - k) + k); + return GL * GV; +} + +vec2 ComputeBRDF(float NoV, float roughness) +{ + // make sure NoV doesn't go exactly to 0 to avoid NaN + NoV = max(NoV, 0.001); + + // Normal always points along z-axis for the 2D lookup + const vec3 N = vec3(0.0, 0.0, 1.0); + vec3 V = vec3(sqrt(1.0 - NoV*NoV), 0.0, NoV); + + vec2 LUT = vec2(0.0); + const uint NUM_SAMPLES = 1024u; + for (uint i = 0u; i < NUM_SAMPLES; i++) { + vec2 Xi = Hammersley2d(i, NUM_SAMPLES); + vec3 H = ImportanceSample_GGX(Xi, roughness, N); + vec3 L = 2.0 * dot(V, H) * H - V; + + float dotNL = max(dot(N, L), 0.0); + float dotNV = max(dot(N, V), 0.0); + float dotVH = max(dot(V, H), 0.0); + float dotNH = max(dot(H, N), 0.0); + + if (dotNL > 0.0) { + float G = Geometry_SchlicksmithGGX(dotNL, dotNV, roughness); + float G_Vis = (G * dotVH) / (dotNH * dotNV); + float Fc = pow(1.0 - dotVH, 5.0); + LUT += vec2((1.0 - Fc) * G_Vis, Fc * G_Vis); + } + } + return LUT / float(NUM_SAMPLES); +} + +void main(void) +{ + ivec2 outCoords = ivec2(hd_GlobalInvocationID.xy); + + vec2 texCoords = GetTexCoords(outCoords); + // texCoords.x represents N dot E and texCoords.y represents roughness + vec4 outColor = vec4(ComputeBRDF(texCoords.x, texCoords.y), 0.0, 1.0); + + HgiSet_outTexture(outCoords, outColor); +} diff --git a/Sources/HdSt/shaders/edgeId.glslfx b/Sources/HdSt/shaders/edgeId.glslfx new file mode 100644 index 0000000000..11e24eb825 --- /dev/null +++ b/Sources/HdSt/shaders/edgeId.glslfx @@ -0,0 +1,191 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/edgeId.glslfx + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.Common + +// Determines whether a fragment is on or close to an unhidden triangle edge. +const float edgePickRadius = 2; // in viewport pixels +const float edgePickParametricRadius = 0.02; // in parametric space + +// For smooth looking edges, use an exponential falloff for the opacity. +// Note: We use a slower falloff fn than in meshWire.glslfx to make the +// selected edges stand out. +float SelectedEdgeFalloff(float d) { + return exp2(-1 * d * d); +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.TriangleSurface + +FORWARD_DECL(vec3 GetEdgeDistanceTriangle()); + +vec3 ComputeBaseFaceEdgeDistanceTriangle() +{ + return GetEdgeDistanceTriangle(); +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.TriangleLines + +vec3 ComputeBaseFaceEdgeDistanceTriangle() +{ + // Use parametric distance since we can't use surface derivatives for lines + vec3 param = GetEdgeParamTriangle(); + bvec3 nearEdge = lessThan(param, vec3(edgePickParametricRadius)); + return vec3(edgePickRadius) * vec3(not(nearEdge)); +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.TriangleParam + +float GetSelectedEdgeOpacity() +{ + float closestEdgeDistance = 0.0; + + // The sequence of comparisons should match GetPrimitiveEdgeId() + vec3 dist = ComputeBaseFaceEdgeDistanceTriangle(); + if (dist.x < edgePickRadius) { + closestEdgeDistance = dist.x; + } else if (dist.y < edgePickRadius) { + closestEdgeDistance = dist.y; + } else if (dist.z < edgePickRadius) { + closestEdgeDistance = dist.z; + } else { + return 0; + } + + return SelectedEdgeFalloff(closestEdgeDistance); +} + +// called from hdx/renderPass.glslfx and selection.glslfx +int GetPrimitiveEdgeId() +{ + // 2 (0,1,0) + // ^ + // e2 / \ e1 + // / \' + // (0,0,1) 0 ----- 1 (1,0,0) + // e0 + + int edgeId = -1; + + vec3 dist = ComputeBaseFaceEdgeDistanceTriangle(); + if (dist.x < edgePickRadius) { + edgeId = 0; + } else if (dist.y < edgePickRadius) { + edgeId = 1; + } else if (dist.z < edgePickRadius) { + edgeId = 2; + } else { + return -1; // Not on a mesh edge + } + + const int edgeFlag = GetEdgeFlag(); + const int meshEdgeIndex = HdGetScalar_edgeIndices(); + + // Translate face-edge to authored mesh-edge + if (edgeFlag == 0) { + edgeId = meshEdgeIndex + edgeId; // regular triangle face. + } else if ((bool(edgeFlag & 1) && edgeId == 2) || + (bool(edgeFlag & 2) && edgeId == 0)) { + edgeId = -1; // Not an authored mesh edge + } else { + edgeId = meshEdgeIndex + edgeId - 1; + } + return edgeId; +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.QuadSurface + +vec4 ComputeBaseFaceEdgeDistanceQuad() +{ + return GetEdgeDistanceQuad(); +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.QuadLines + +vec4 ComputeBaseFaceEdgeDistanceQuad() +{ + // Use parametric distance since we can't use surface derivatives for lines + vec4 param = GetEdgeParamQuad(); + bvec4 nearEdge = lessThan(param, vec4(edgePickParametricRadius)); + return vec4(edgePickRadius) * vec4(not(nearEdge)); +} + +--- -------------------------------------------------------------------------- +-- glsl EdgeId.Fragment.QuadParam + +float GetSelectedEdgeOpacity() +{ + float closestEdgeDistance = 0.0; + + // The sequence of comparisons should match GetPrimitiveEdgeId() + vec4 dist = ComputeBaseFaceEdgeDistanceQuad(); + if (dist.x < edgePickRadius) { + closestEdgeDistance = dist.x; + } else if (dist.y < edgePickRadius) { + closestEdgeDistance = dist.y; + } else if (dist.z < edgePickRadius) { + closestEdgeDistance = dist.z; + } else if (dist.w < edgePickRadius) { + closestEdgeDistance = dist.w; + } else { + return 0; + } + + return SelectedEdgeFalloff(closestEdgeDistance); +} + +// called from hdx/renderPass.glslfx and selection.glslfx +int GetPrimitiveEdgeId() +{ + // e2 + // (0,1) 3 ------ 2 (1,1) + // | | + // e3 | | e1 + // | | + // (0,0) 0 ------ 1 (1,0) + // e0 + + int edgeId = -1; + + vec4 dist = ComputeBaseFaceEdgeDistanceQuad(); + if (dist.x < edgePickRadius) { + edgeId = 0; + } else if (dist.y < edgePickRadius) { + edgeId = 1; + } else if (dist.z < edgePickRadius) { + edgeId = 2; + } else if (dist.w < edgePickRadius) { + edgeId = 3; + } else { + return -1; // Not on a mesh edge + } + + const int edgeFlag = GetEdgeFlag(); + const ivec2 meshEdgeIndices = HdGet_edgeIndices(); + + // Translate face-edge to authored mesh-edge + if (edgeFlag == 0) { + edgeId = meshEdgeIndices[0] + edgeId; // regular quad face + } else if (edgeId == 0) { + edgeId = meshEdgeIndices[0]; + } else if (edgeId == 3) { + edgeId = meshEdgeIndices[1]; + } else { + edgeId = -1; // Not an authored mesh edge + } + return edgeId; +} diff --git a/Sources/HdSt/shaders/fallbackLighting.glslfx b/Sources/HdSt/shaders/fallbackLighting.glslfx new file mode 100644 index 0000000000..504ab8f1f1 --- /dev/null +++ b/Sources/HdSt/shaders/fallbackLighting.glslfx @@ -0,0 +1,59 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/fallbackLighting.glslfx + +--- -------------------------------------------------------------------------- +-- glsl Fallback.LightIntegrator +#ifndef HD_HAS_integrateLights +#define HD_HAS_integrateLights +#endif + +struct LightingContribution { + vec3 diffuse; +}; + +struct LightingInterfaceProperties { + float unused; +}; + +LightingContribution +integrateLightsDefault(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + vec3 n = normalize(Neye); + + LightingContribution result; + result.diffuse = vec3(dot(n, vec3(0,0,1))); + + return result; +} + +LightingContribution +integrateLightsConstant(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + LightingContribution result; + //pefectly diffuse white hemisphere contribution + result.diffuse = vec3(1); + + return result; +} + +-- glsl Fallback.Lighting + +FORWARD_DECL( + LightingContribution integrateLights(vec4 Peye, vec3 Neye, + LightingInterfaceProperties props)); + +vec3 FallbackLighting(in vec3 Peye, in vec3 Neye, in vec3 color) +{ + LightingInterfaceProperties props; + LightingContribution light = integrateLights(vec4(Peye, 1), Neye, props); + return color * light.diffuse; +} diff --git a/Sources/HdSt/shaders/fallbackLightingShader.glslfx b/Sources/HdSt/shaders/fallbackLightingShader.glslfx new file mode 100644 index 0000000000..82d8dd5d13 --- /dev/null +++ b/Sources/HdSt/shaders/fallbackLightingShader.glslfx @@ -0,0 +1,27 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/fallbackLightingShader.glslfx + +#import $TOOLS/hdSt/shaders/fallbackLighting.glslfx + +-- configuration +{ + "techniques": { + "default": { + "fragmentShader" : { + "source": [ + "Fallback.LightIntegrator", + "Fallback.Lighting" + ] + } + } + } +} diff --git a/Sources/HdSt/shaders/fallbackMaterialNetwork.glslfx b/Sources/HdSt/shaders/fallbackMaterialNetwork.glslfx new file mode 100644 index 0000000000..66fc80bd97 --- /dev/null +++ b/Sources/HdSt/shaders/fallbackMaterialNetwork.glslfx @@ -0,0 +1,47 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/fallbackMaterialNetwork.glslfx + +--- +--- The fallback shader is used as a replacement shader if no material binding +--- was provided. It needs to define both the surfaceShader() and +--- displacementShader() terminals. +--- +-- configuration +{ + "techniques": { + "default": { + "displacementShader": { + "source": [ "Fallback.Displacement" ] + }, + "surfaceShader": { + "source": [ "Fallback.Surface" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl Fallback.Surface + +vec4 surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + // lighting + color.rgb = FallbackLighting(Peye.xyz, Neye, color.rgb); + return color; +} +--- -------------------------------------------------------------------------- +-- glsl Fallback.Displacement + +vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return Peye; +} diff --git a/Sources/HdSt/shaders/fallbackVolume.glslfx b/Sources/HdSt/shaders/fallbackVolume.glslfx new file mode 100644 index 0000000000..8a112173fe --- /dev/null +++ b/Sources/HdSt/shaders/fallbackVolume.glslfx @@ -0,0 +1,97 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/fallbackVolume.glslfx + +-- configuration +{ + "techniques": { + "default": { + "volumeShader": { + "source": [ "FallbackVolume.VolumeShader" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl FallbackVolume.VolumeShader + +// Functions that the volume shader of a volume material would provide. +// +// The functions give extinction, scattering, emission at a point as well as +// a phase function such as Henyey-Greenstein (see, e.g., [1]). +// +// Only single scattering is taken into account and the result of the +// scattering function (together with the phase function) is used to compute +// the in-scattering component of the volume rendering equation for a light +// source (point lights only). +// The extinction function is supposed to return the sum of the +// absorption and out-scattering cross section. +// Note that the interpretation of emission here follows [1] (rather than [2]), +// so the emission is added by the ray-marcher without being multiplied by +// extinction. +// Note that one cannot use the fallback volume shader for assets containing +// "glow" rather "emission" where the convention is +// emission = glow * extinction. +// +// [1] Matt Pharr, Wenzel Jakob, Greg Humphreys, "Physically Based Rendering", +// Third Edition). +// [2] Julian Fong, Magnus Wrenninge, Christopher Kulla, Ralf Habel, +// "Production Volume Rendering", SIGGRAPH 2017 Course. + +// The functions given here use a density and emission field with a fixed +// albedo. +// +// + +// Extinction function, returns sum of absorption and out-scattering cross +// ratio. +// +float +extinctionFunction(vec3 p) +{ + return HdGet_density(p); +} + +// Scattering function, returns in-scattering cross-section (will be combined +// with phase function). +// +// Here: constant on ellipsoid and zero outside. +float +scatteringFunction(vec3 p) +{ + const float albedo = 0.18; + + return extinctionFunction(p) * albedo; +} + +// Emission function, returns emission cross-section. +// +// Here: zero since volume is not emitting light. +vec3 +emissionFunction(vec3 p) +{ + return HdGet_emission(p); +} + +// Phase function in volume rendering equation. +// +// Here: isotropic. +float +phaseFunction(vec3 direction1, vec3 direction2) +{ + const float pi = 3.14159265358979; + const float sphereArea = 4.0 * pi; + const float inverseSphereArea = 1.0 / sphereArea; + + return inverseSphereArea; +} + diff --git a/Sources/HdSt/shaders/frustumCull.glslfx b/Sources/HdSt/shaders/frustumCull.glslfx new file mode 100644 index 0000000000..b08dcce129 --- /dev/null +++ b/Sources/HdSt/shaders/frustumCull.glslfx @@ -0,0 +1,448 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/compute.glslfx + +#import $TOOLS/hdSt/shaders/instancing.glslfx + +--- -------------------------------------------------------------------------- +-- layout ViewFrustumCull.Counting + +[ + ["buffer readWrite", "ResultData", "drawIndirectResult", + ["atomic_int", "numVisibleInstances"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.Counting + +void +FrustumCullCountVisibleInstances(int resultInstanceCount) +{ + ATOMIC_ADD(numVisibleInstances[0], resultInstanceCount); +} + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.NoCounting + +void +FrustumCullCountVisibleInstances(int resultInstanceCount) +{ + // do nothing +} + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.NoTinyCull + +bool +FrustumCullIsTinyPrim(vec4 bboxMin, vec4 bboxMax, vec2 drawRangeNDC) +{ + // do nothing + return false; +} + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.TinyCull + +bool +FrustumCullIsTinyPrim(vec4 bboxMin, vec4 bboxMax, vec2 drawRangeNDC) +{ + // Check the length of the min/max diagonal, could do something better here. + vec2 ndcMin = (bboxMin.xy/max(.000001,bboxMin.w)); + vec2 ndcMax = (bboxMax.xy/max(.000001,bboxMax.w)); + float diag = distance(ndcMin, ndcMax); + + // Cull prims outside the min(x)/max(y) range. + // When max is negative, do not cull based on max size + + #define isLargeEnough (diag > drawRangeNDC.x) + #define isSmallEnough (drawRangeNDC.y < 0 || diag < drawRangeNDC.y) + + return !isLargeEnough || !isSmallEnough; + + #undef isLargeEnough + #undef isSmallEnough +} + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.IsVisible + +bool +FrustumCullIsVisible(MAT4 toClip, vec4 localMin, vec4 localMax, vec2 drawRangeNDC) +{ + // Disable culling when: + // (a) BBox is empty. An empty bbox defaults to [FLT_MAX, -FLT_MAX]), so + // min > max. + // (b) Bounds are infinite. + if (any(greaterThan(localMin, localMax)) || + any(isinf(localMin)) || any(isinf(localMax))) { + return true; + } + + // Transform the corners of the bounding box to clipping space. + vec4 p[8]; + p[0] = vec4(toClip * vec4(localMin.x, localMin.y, localMin.z, 1)); + p[2] = vec4(toClip * vec4(localMin.x, localMax.y, localMin.z, 1)); + p[5] = vec4(toClip * vec4(localMax.x, localMin.y, localMax.z, 1)); + p[7] = vec4(toClip * vec4(localMax.x, localMax.y, localMax.z, 1)); + + // This prim is visible if it wasn't culled and at least one tiny prim test + // failed. Test two axes here because size is measured in screen space. + // We front-load this test because it saves quite a bit of compute: in one + // test the framerate went from 7.7 to 9.0 FPS. + if (FrustumCullIsTinyPrim(p[0], p[7], drawRangeNDC) && + FrustumCullIsTinyPrim(p[2], p[5], drawRangeNDC)) + { + return false; + } + + // Finish computing points and perform frustum culling. + p[1] = vec4(toClip * vec4(localMin.x, localMin.y, localMax.z, 1)); + p[3] = vec4(toClip * vec4(localMin.x, localMax.y, localMax.z, 1)); + p[4] = vec4(toClip * vec4(localMax.x, localMin.y, localMin.z, 1)); + p[6] = vec4(toClip * vec4(localMax.x, localMax.y, localMin.z, 1)); + + // Test the corners of the bounding box against the clipping volume. + // clipFlags is effectively a 6-bit field, holding one bit of information + // per frustum plane. Each component of the vector holds 2 bits. + // If the bounding box overlaps the clip volume, then clipFlags will be + // (0b11, 0b11, 0b11). + ivec3 clipFlags = ivec3(0); + for (int i=0; i<8; ++i) { + vec4 clipPos = p[i]; + bvec3 clip0 = lessThan(clipPos.xyz, vec3(clipPos.w)); + bvec3 clip1 = greaterThan(clipPos.xyz, -vec3(clipPos.w)); + clipFlags |= ivec3(clip0) /* bit 0 */ + 2*ivec3(clip1) /*bit 1*/; + } + + return all(equal(clipFlags, ivec3(3))); +} + +--- -------------------------------------------------------------------------- +-- layout ViewFrustumCull.Vertex + +[ + ["in", "int", "instanceCountInput"], + ["in", "int", "drawCommandIndex"], + ["uniform block", "Uniforms", "ulocCullParams", + ["mat4", "cullMatrix"], + ["vec2", "drawRangeNDC"], + ["uint", "drawCommandNumUints"] + ], + ["buffer readWrite", "DispatchBuffer", "dispatchBuffer", + ["uint", "drawCommands", "[]"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.Vertex + +MAT4 GetCullMatrix() +{ + return MAT4(cullMatrix); +} + +void main() +{ + // instanceCountOffset is a relative offset in drawcommand struct. + // it's a second entry in both DrawArraysCommand and DrawElementsCommand. + const uint instanceCountOffset = 1; + + MAT4 transform = HdGet_transform(); + MAT4 toClip = GetCullMatrix() * transform; + + vec4 localMin = HdGet_bboxLocalMin(); + vec4 localMax = HdGet_bboxLocalMax(); + + bool isVisible = FrustumCullIsVisible( + toClip, localMin, localMax, drawRangeNDC); + + // Compute the index to the 'instanceCount' struct member in drawCommands. + uint index = uint(drawCommandIndex) * + drawCommandNumUints + instanceCountOffset; + + // Set the resulting instance count to 0 if the primitive is culled + // otherwise pass through the original incoming instance count. + uint resultInstanceCount = instanceCountInput * uint(isVisible); + drawCommands[index] = resultInstanceCount; + + FrustumCullCountVisibleInstances(int(resultInstanceCount)); +} + +--- -------------------------------------------------------------------------- +-- layout ViewFrustumCull.VertexInstancing + +[ + ["in", "int", "drawCommandIndex"], + ["uniform block", "Uniforms", "ulocCullParams", + ["mat4", "cullMatrix"], + ["vec2", "drawRangeNDC"], + ["uint", "drawCommandNumUints"], + ["uint", "drawBatchId"], + ["int", "resetPass"] + ], + ["buffer readWrite", "DispatchBuffer", "dispatchBuffer", + ["atomic_uint", "drawCommands", "[]"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.VertexInstancing + +/* + per-instance culling + + We use instance index indirection buffer to switch prototypes efficiently. + Per-instance culling exploits this indirection to trim culled instances + from draw call. + + Example: Prototype mesh M is instanced for 5 instances. + + Instancer has instance primvars (translate, rotate, ...) + and index indirection for M. + + InstancePrimvar (T:translate) + +-------+-----------------------------+-----------+ + : |T0 T1 T2 T3 T4 T5 T6 T7 T8 T9| : + +-------+-----------------------------+-----------+ + ^ + InstanceIndices(for M) | + +-----------+---------------+-----------+ + : | 0 2 5 8 9 | : + +-----------+---------------+-----------+ + ^ + | + M: gl_InstanceID (0-5) + + We can draw all instances of M, by just drawing with numInstance = 6. + + For per-instance culling, we test each bbox against the frustum. + Then, we store only passed instance indices into culledInstanceIndices buffer, + as well as counting them. + + InstanceIndices(for M) + +-----------+---------------+-----------+ + : | 0 2 5 8 9 | : instanceCount = 5 + +-----------+---------------+-----------+ + V + (say only 2 and 8 are visible in frustum) + V + +-----------+---------------+-----------+ + : | 2 8 x x x | : instanceCount = 2 + +-----------+---------------+-----------+ + x:undefined value +*/ + +MAT4 GetCullMatrix() +{ + return MAT4(cullMatrix); +} + +void main() +{ + // instanceCountOffset is a relative offset in drawcommand struct. + // it's a second entry in both DrawArraysCommand and DrawElementsCommand. + const uint instanceCountOffset = 1; + + const uint instanceCountBufferOffset = + drawCommandIndex * drawCommandNumUints + instanceCountOffset; + + // reset pass + if (resetPass == 1) { + // note: we expect all instance invocations of this draw command + // are clearing same field to zero, and and so might not guard this + // access as atomic. + ATOMIC_STORE(drawCommands[instanceCountBufferOffset], 0); + + // Sets first value of culledInstancesIndices to 0. + ATOMIC_STORE(culledInstanceIndices[GetBaseInstanceIndexCoord()], 0); + + return; + } + + // culling pass + // precondition: drawCommand.instanceCount has to be reset in the separate + // invocation unit. + + vec4 localMin = HdGet_bboxLocalMin(); + vec4 localMax = HdGet_bboxLocalMax(); + + MAT4 toClip = GetCullMatrix() * ApplyInstanceTransform(HdGet_transform()); + + bool isVisible = FrustumCullIsVisible( + toClip, localMin, localMax, drawRangeNDC); + + if (isVisible) { + // increment the instance count and store instanceIndex to + // culledInstanceIndices. + + uint id = ATOMIC_ADD(drawCommands[instanceCountBufferOffset], 1); + + // There is a potential correctness issue that happens when an instanced + // prim has geom subsets, resulting in multiple draw items with the same + // instanceIndices and culledInstanceIndices buffers (as we do not + // duplicate these buffers for geom subset draw items). These geom + // subset draw items will each try to read and write from the same + // instanceIndices and culledInstanceIndices buffers from different + // threads of this shader. Given the potential difference in execution + // order of the different threads, which each corresponding to a + // different instance id, this can result in incorrect + // culledInstanceIndices. + // + // To guard against this, we only allow one of these geom subset draw + // items to write to the culledInstanceIndices buffer, by adding an + // extra value at the start of culledInstanceIndices where we store + // the xor of the drawCommandIndex and drawBatchId for the first thread + // to complete the atomic op below. Only this thread will be allowed to + // edit the culledInstanceIndices buffer. + int hash = drawCommandIndex ^ int(drawBatchId); + + // XXX: There is a linking error in OpenGL when using atomicCompSwap + // on bindless buffer culledInstanceIndices using the else case method. + // Thus we add this alternative. +#ifdef HD_BINDLESS_BUFFERS_ENABLED + ATOMIC_COMP_SWAP( + culledInstanceIndices + GetBaseInstanceIndexCoord(), 0, hash); +#else + ATOMIC_COMP_SWAP( + culledInstanceIndices[GetBaseInstanceIndexCoord()], 0, hash); +#endif + + if (culledInstanceIndices[GetBaseInstanceIndexCoord()] != hash) { + return; + } + + SetCulledInstanceIndex(id); + FrustumCullCountVisibleInstances(1); + } +} + + +--- -------------------------------------------------------------------------- +-- layout ViewFrustumCull.Compute + +[ + ["uniform block", "Uniforms", "ulocCullParams", + ["mat4", "cullMatrix"], + ["vec2", "drawRangeNDC"], + ["uint", "drawCommandNumUints"] + ], + ["buffer readOnly", "DrawCullInput", "drawCullInput", + ["uint", "drawCullInput", "[]"] + ], + ["buffer readWrite", "DispatchBuffer", "dispatchBuffer", + ["uint", "drawCommands", "[]"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.Compute + +MAT4 GetCullMatrix() +{ + return MAT4(cullMatrix); +} + +void compute(int drawCommandIndex) +{ + SetDrawIndex(drawCommandIndex, 0); + + // instanceCountOffset is a relative offset in drawcommand struct. + // it's a second entry in both DrawArraysCommand and DrawElementsCommand. + const uint instanceCountOffset = 1; + + MAT4 transform = HdGet_transform(); + MAT4 toClip = GetCullMatrix() * transform; + + vec4 localMin = HdGet_bboxLocalMin(); + vec4 localMax = HdGet_bboxLocalMax(); + + bool isVisible = FrustumCullIsVisible( + toClip, localMin, localMax, drawRangeNDC); + + // Compute the index to the 'instanceCount' struct member in drawCommands. + uint instanceIndex = uint(drawCommandIndex) * + drawCommandNumUints + instanceCountOffset; + + // Set the resulting instance count to 0 if the primitive is culled + // otherwise pass through the original incoming instance count. + uint resultInstanceCount = drawCullInput[instanceIndex] * uint(isVisible); + drawCommands[instanceIndex] = resultInstanceCount; + + FrustumCullCountVisibleInstances(int(resultInstanceCount)); +} + +--- -------------------------------------------------------------------------- +-- layout ViewFrustumCull.ComputeInstancing + +[ + ["uniform block", "Uniforms", "ulocCullParams", + ["mat4", "cullMatrix"], + ["vec2", "drawRangeNDC"], + ["uint", "drawCommandNumUints"] + ], + ["buffer readOnly", "DrawCullInput", "drawCullInput", + ["uint", "drawCullInput", "[]"] + ], + ["buffer readWrite", "DispatchBuffer", "dispatchBuffer", + ["uint", "drawCommands", "[]"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ViewFrustumCull.ComputeInstancing + +MAT4 GetCullMatrix() +{ + return MAT4(cullMatrix); +} + +void compute(int drawCommandIndex) +{ + SetDrawIndex(drawCommandIndex, 0); + + // instanceCountOffset is a relative offset in drawcommand struct. + // it's a second entry in both DrawArraysCommand and DrawElementsCommand. + const uint instanceCountOffset = 1; + + const uint instanceCountBufferOffset = + drawCommandIndex * drawCommandNumUints + instanceCountOffset; + + const uint instanceCount = drawCullInput[instanceCountBufferOffset]; + + vec4 localMin = HdGet_bboxLocalMin(); + vec4 localMax = HdGet_bboxLocalMax(); + MAT4 transform = HdGet_transform(); + + // Reset the instance count. + drawCommands[instanceCountBufferOffset] = 0; + + for (int i = 0; i < instanceCount; ++i) + { + SetDrawIndex(drawCommandIndex, i); + + MAT4 toClip = GetCullMatrix() * ApplyInstanceTransform(transform); + + bool isVisible = FrustumCullIsVisible( + toClip, localMin, localMax, drawRangeNDC); + + if (isVisible) { + // Increment the instance count and store instanceIndex to + // culledInstanceIndices. + uint id = drawCommands[instanceCountBufferOffset]; + + drawCommands[instanceCountBufferOffset] += 1; + + SetCulledInstanceIndex(id); + FrustumCullCountVisibleInstances(1); + } + } +} diff --git a/Sources/HdSt/shaders/imageShader.glslfx b/Sources/HdSt/shaders/imageShader.glslfx new file mode 100644 index 0000000000..c74e544557 --- /dev/null +++ b/Sources/HdSt/shaders/imageShader.glslfx @@ -0,0 +1,103 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/imageShader.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "ImageShader.Vertex" ] + }, + "fragmentShader" : { + "source": [ "ImageShader.Fragment" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- layout ImageShader.Vertex + +[ + ["out block", "VertexData", "outData", + ["vec2", "uv"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl ImageShader.Vertex + +void main(void) +{ + // Position the vertices to create a large-than-screen triangle. + // Adjust the UVs of the triangle to have 0-1 fit the screen exactly. + // 'st' is the geometric UV where the [bottom,left] returns [0, 0]. + // Unlike gl_fragCoord where the [bottom,left] defaults to [0.5, 0.5]. + // + // hd_VertexID=0 -> (-1,-1) + // hd_VertexID=1 -> ( 3,-1) + // hd_VertexID=2 -> (-1, 3) + // + // glDrawArrays( GL_TRIANGLES, 0, 3 ); + // + // ID=2 + // x,y=-1,3 + // u,v=0,2 + // |\ + // | \ + // | \ + // | \ + // |--------\ + // | | \ + // | screen | \ + // | | \ + // ---------------- + // ID=0 ID=1 + // x,y=-1,-1 x,y=3,-1 + // u,v=0,0 u,v=2,0 + // + // + float x = -1.0 + float(((hd_VertexID%3) & 1) << 2); + float y = -1.0 + float(((hd_VertexID%3) & 2) << 1); + outData.uv.x = (x+1.0) * 0.5; + outData.uv.y = (y+1.0) * 0.5; + + gl_Position = vec4(x, y, 0, 1); +} + +--- -------------------------------------------------------------------------- +-- layout ImageShader.Fragment + +[ + ["in block", "VertexData", "inData", + ["vec2", "uv"] + ], + ["out", "vec4", "colorOut"] +] + +--- -------------------------------------------------------------------------- +-- glsl ImageShader.Fragment + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) { + return integrateLightsDefault(Peye, Neye, props); +} +#endif +#endif + +void main(void) +{ + colorOut = imageShader(inData.uv); +} diff --git a/Sources/HdSt/shaders/instancing.glslfx b/Sources/HdSt/shaders/instancing.glslfx new file mode 100644 index 0000000000..d6fae68d88 --- /dev/null +++ b/Sources/HdSt/shaders/instancing.glslfx @@ -0,0 +1,217 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/instancing.glslfx + +--- -------------------------------------------------------------------------- +-- glsl Instancing.Transform + +// quaternion to matrix. xyz = imaginary, w = real +MAT4 GetRotationMatrix(vec4 q) +{ + MAT4 r; + r[0].xyzw = vec4(1 - 2 * (q.y * q.y + q.z * q.z), + 2 * (q.x * q.y + q.z * q.w), + 2 * (q.x * q.z - q.y * q.w), + 0); + r[1].xyzw = vec4( 2 * (q.x * q.y - q.z * q.w), + 1 - 2 * (q.x * q.x + q.z * q.z), + 2 * (q.y * q.z + q.x * q.w), + 0); + r[2].xyzw = vec4( 2 * (q.x * q.z + q.y * q.w), + 2 * (q.y * q.z - q.x * q.w), + 1 - 2 * (q.x * q.x + q.y * q.y), + 0); + r[3] = vec4(0, 0, 0, 1); + return r; +} + +// --------------------------------------------------------------------------- + +MAT4 GetInstanceTransform(int level) +{ + MAT4 m = MAT4(1); +#ifdef HD_HAS_INSTANCE_hydra_instanceTransforms + m = HdGetInstance_hydra_instanceTransforms(level, MAT4(1)) * m; +#elif defined(HD_HAS_INSTANCE_instanceTransform) + m = HdGetInstance_instanceTransform(level, MAT4(1)) * m; +#endif + + // instance transform elements are applied: + // scale then rotate then translate + // i.e. (T * R * S) * position + +#ifdef HD_HAS_INSTANCE_hydra_instanceScales + vec3 s = HdGetInstance_hydra_instanceScales(level, /*default=*/vec3(1)); + m = MAT4(s.x, 0, 0, 0, + 0, s.y, 0, 0, + 0, 0, s.z, 0, + 0, 0, 0, 1) * m; +#elif defined(HD_HAS_INSTANCE_instanceScale) + vec3 s = HdGetInstance_scale(level, /*default=*/vec3(1)); + m = MAT4(s.x, 0, 0, 0, + 0, s.y, 0, 0, + 0, 0, s.z, 0, + 0, 0, 0, 1) * m; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceRotations // GfQuat(ix, iy, iz, real) + vec4 q = HdGetInstance_hydra_instanceRotations(level, /*default=*/vec4(0)); + m = GetRotationMatrix(q) * m; +#elif defined(HD_HAS_INSTANCE_rotate) + vec4 q = HdGetInstance_rotate(level, /*default=*/vec4(0)); + m = GetRotationMatrix(q) * m; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceTranslations + vec3 t = HdGetInstance_hydra_instanceTranslations(level, /*default=*/vec3(0)); + m = MAT4( 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + t.x, t.y, t.z, 1) * m; +#elif defined(HD_HAS_INSTANCE_translate) + vec3 t = HdGetInstance_translate(level, /*default=*/vec3(0)); + m = MAT4( 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + t.x, t.y, t.z, 1) * m; +#endif + return m; +} + +MAT4 GetInstanceTransformInverse(int level) +{ + MAT4 m = MAT4(1); + +#ifdef HD_HAS_INSTANCE_hydra_instanceTransforms + m = inverse(HdGetInstance_hydra_instanceTransforms(level, MAT4(1))) * m; +#elif defined(HD_HAS_INSTANCE_instanceTransform) + m = inverse(HdGetInstance_instanceTransform(level, MAT4(1))) * m; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceTranslations + vec3 it = -HdGetInstance_hydra_instanceTranslations(level, /*default=*/vec3(0)); // negate + m = MAT4( 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + it.x, it.y, it.z, 1) * m; +#elif defined(HD_HAS_INSTANCE_translate) + vec3 it = -HdGetInstance_translate(level, /*default=*/vec3(0)); // negate + m = MAT4( 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + it.x, it.y, it.z, 1) * m; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceRotations + vec4 q = HdGetInstance_hydra_instanceRotations(level, /*default=*/vec4(0)); + q.xyz = -q.xyz; // inverse rotataion axis + m = GetRotationMatrix(q) * m; +#elif defined(HD_HAS_INSTANCE_rotate) + vec4 q = HdGetInstance_rotate(level, /*default=*/vec4(0)); + q.xyz = -q.xyz; // inverse rotataion axis + m = GetRotationMatrix(q) * m; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceScales + vec3 is = 1.0/HdGetInstance_hydra_instanceScales(level, /*default=*/vec3(1)); // inverse scale + m = MAT4(is.x, 0, 0, 0, + 0, is.y, 0, 0, + 0, 0, is.z, 0, + 0, 0, 0, 1) * m; +#elif defined(HD_HAS_INSTANCE_scale) + vec3 is = 1.0/HdGetInstance_scale(level, /*default=*/vec3(1)); // inverse scale + m = MAT4(is.x, 0, 0, 0, + 0, is.y, 0, 0, + 0, 0, is.z, 0, + 0, 0, 0, 1) * m; +#endif + return m; +} + +// --------------------------------------------------------------------------- + +MAT4 GetInstanceTransform() +{ + MAT4 m = MAT4(1); +#ifdef HD_INSTANCER_NUM_LEVELS + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + m = GetInstanceTransform(i) * m; +#ifdef HD_HAS_instancerTransform + m = HdGet_instancerTransform(i) * m; +#endif + } +#endif + return m; +} + +MAT4 GetInstanceTransformInverse() +{ + MAT4 m = MAT4(1); +#ifdef HD_INSTANCER_NUM_LEVELS + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + m = m * GetInstanceTransformInverse(i); +#ifdef HD_HAS_instancerTransformInverse + m = m * HdGet_instancerTransformInverse(i); +#endif + } +#endif + return m; +} + +// --------------------------------------------------------------------------- + +MAT4 ApplyInstanceTransform(MAT4 m) +{ + return GetInstanceTransform() * m; +} + +MAT4 ApplyInstanceTransformInverse(MAT4 m) +{ + return m * GetInstanceTransformInverse(); +} + +bool IsFlipped() +{ +#if defined(HD_HAS_isFlipped) + bool flip = (HdGet_isFlipped() != 0); +#elif defined(HD_HAS_transform) + // The sign of the determinant indicates whether m flips handedness + bool flip = (determinant(HdGet_transform()) < 0.0); +#else + bool flip = false; +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceScales + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + vec3 scale = HdGetInstance_hydra_instanceScales(i, /*default=*/vec3(1)); + flip = flip != ((sign(scale.x) * sign(scale.y) * sign(scale.z)) < 0); + } +#elif defined(HD_HAS_INSTANCE_scale) + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + vec3 scale = HdGetInstance_scale(i, /*default=*/vec3(1)); + flip = flip != ((sign(scale.x) * sign(scale.y) * sign(scale.z)) < 0); + } +#endif + +#ifdef HD_HAS_INSTANCE_hydra_instanceTransforms + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + MAT4 m = HdGetInstance_hydra_instanceTransforms(i, MAT4(1)); + flip = flip != (determinant(m) < 0.0); + } +#elif defined(HD_HAS_INSTANCE_instanceTransform) + for (int i = 0; i < HD_INSTANCER_NUM_LEVELS; ++i) { + MAT4 m = HdGetInstance_instanceTransform(i, MAT4(1)); + flip = flip != (determinant(m) < 0.0); + } +#endif + + return flip; +} diff --git a/Sources/HdSt/shaders/invalidMaterialNetwork.glslfx b/Sources/HdSt/shaders/invalidMaterialNetwork.glslfx new file mode 100644 index 0000000000..7a98a7c5ec --- /dev/null +++ b/Sources/HdSt/shaders/invalidMaterialNetwork.glslfx @@ -0,0 +1,53 @@ +-- glslfx version 0.1 + +// +// Copyright 2023 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/invalidMaterialNetwork.glslfx + +--- +--- The invalid shader is used as a replacement shader if the +--- original material shader failed to compile. It needs to +--- define both the surfaceShader() and displacementShader() terminals. +--- +-- configuration +{ + "techniques": { + "default": { + "displacementShader": { + "source": [ "Invalid.Displacement" ] + }, + "surfaceShader": { + "source": [ "Invalid.Surface" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl Invalid.Surface + +vec4 surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + vec2 t = gl_FragCoord.xy; + float v = mod(round(t.x + t.y), 16.0); + + const vec4 invalidColor = vec4(0.7, 0.3, 0.3, 1.0); + return mix(color, invalidColor, v); + + // Alt look: + // Override the color to a bright red. Don't light it. + // return vec4(0.9, 0.0, 0.0, 1.0); +} +--- -------------------------------------------------------------------------- +-- glsl Invalid.Displacement + +vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return Peye; +} diff --git a/Sources/HdSt/shaders/mesh.glslfx b/Sources/HdSt/shaders/mesh.glslfx new file mode 100644 index 0000000000..9c26e43bef --- /dev/null +++ b/Sources/HdSt/shaders/mesh.glslfx @@ -0,0 +1,1551 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/mesh.glslfx + +#import $TOOLS/hdSt/shaders/instancing.glslfx +#import $TOOLS/hdSt/shaders/meshFaceCull.glslfx +#import $TOOLS/hdSt/shaders/meshNormal.glslfx +#import $TOOLS/hdSt/shaders/meshWire.glslfx +#import $TOOLS/hdSt/shaders/terminals.glslfx +#import $TOOLS/hdSt/shaders/edgeId.glslfx +#import $TOOLS/hdSt/shaders/pointId.glslfx +#import $TOOLS/hdSt/shaders/visibility.glslfx + +--- -------------------------------------------------------------------------- +-- layout Mesh.Vertex + +[ + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Vertex + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + ProcessPrimvarsIn(); + + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + vec4 point = vec4(HdGet_points().xyz, 1); + outData.Peye = vec4(GetWorldToViewMatrix() * transform * point); + + outData.Neye = GetNormal(vec3(0), 0); // normalized + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.PostTessVertex.Triangle + +[ + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessVertex.Triangle + +vec4 GetPatchCoord(int index) +{ + vec2 uv[3]; + uv[0] = vec2(0, 0); // (0, 0, 1); + uv[1] = vec2(1, 0); // (1, 0, 0); + uv[2] = vec2(0, 1); // (0, 1, 0); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoordTriangle(uv[index], patchParam); +} + +vec2 GetPatchCoordLocalST() +{ + return gl_TessCoord.yz; +} + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + vec4 point0 = GetWorldToViewMatrix() * transform * vec4(points[0],1.0); + vec4 point1 = GetWorldToViewMatrix() * transform * vec4(points[1],1.0); + vec4 point2 = GetWorldToViewMatrix() * transform * vec4(points[2],1.0); + + // Get the indata Neye if provided. + bool isFlipped = IsFlipped(); + vec3 Neye0 = GetNormal(vec3(0),0); + vec3 Neye1 = GetNormal(vec3(0),1); + vec3 Neye2 = GetNormal(vec3(0),2); + + Neye0 = GetTriGeometryNormal(Neye0, point0, point1, point2, isFlipped); + Neye1 = GetTriGeometryNormal(Neye1, point0, point1, point2, isFlipped); + Neye2 = GetTriGeometryNormal(Neye2, point0, point1, point2, isFlipped); + + point0 = DisplacementTerminal(0, point0, Neye0, GetPatchCoord(0)); + point1 = DisplacementTerminal(1, point1, Neye1, GetPatchCoord(1)); + point2 = DisplacementTerminal(2, point2, Neye2, GetPatchCoord(2)); + + vec2 coord = gl_TessCoord.xy; + vec4 basis = vec4(coord.x, coord.y, 1.0f-coord.x-coord.y, 0.0f); + + outData.Peye = InterpolatePrimvar(point0, point1, point2, point0, basis); + outData.Neye = InterpolatePrimvar(Neye0, Neye1, Neye2, Neye0, basis); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 0); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.PostTessVertex.Quad + +[ + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessVertex.Quad + +vec4 GetPatchCoord(int index) +{ + vec2 uv[4]; + uv[0] = vec2(0, 0); + uv[1] = vec2(1, 0); + uv[2] = vec2(1, 1); + uv[3] = vec2(0, 1); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoord(uv[index], patchParam); +} + +vec2 GetPatchCoordLocalST() +{ + return gl_TessCoord; +} + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + vec4 point0 = GetWorldToViewMatrix() * transform * vec4(points[0],1.0); + vec4 point1 = GetWorldToViewMatrix() * transform * vec4(points[1],1.0); + vec4 point2 = GetWorldToViewMatrix() * transform * vec4(points[2],1.0); + vec4 point3 = GetWorldToViewMatrix() * transform * vec4(points[3],1.0); + + // Get the indata Neye if provided. + bool isFlipped = IsFlipped(); + vec3 Neye0 = GetNormal(vec3(0),0); + vec3 Neye1 = GetNormal(vec3(0),1); + vec3 Neye2 = GetNormal(vec3(0),2); + vec3 Neye3 = GetNormal(vec3(0),3); + + Neye0 = GetQuadGeometryNormal( + Neye0, point0, point1, point2, point3, isFlipped); + Neye1 = GetQuadGeometryNormal( + Neye1, point0, point1, point2, point3, isFlipped); + Neye2 = GetQuadGeometryNormal( + Neye2, point0, point1, point2, point3, isFlipped); + Neye3 = GetQuadGeometryNormal( + Neye3, point0, point1, point2, point3, isFlipped); + + point0 = DisplacementTerminal(0, point0, Neye0, GetPatchCoord(0)); + point1 = DisplacementTerminal(1, point1, Neye1, GetPatchCoord(1)); + point2 = DisplacementTerminal(2, point2, Neye2, GetPatchCoord(2)); + point3 = DisplacementTerminal(3, point3, Neye3, GetPatchCoord(3)); + + vec3 coord = gl_TessCoord.xy; + vec4 basis = vec4((1.0-coord.x) * (1.0-coord.y), coord.x * (1.0-coord.y), + (1.0-coord.x) * coord.y, coord.x * coord.y); + + outData.Peye = InterpolatePrimvar(point0, point1, point2, point3, basis); + outData.Neye = InterpolatePrimvar(Neye0, Neye1, Neye2, Neye3, basis); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 3); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.PostTessVertex.TriQuad + +[ + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessVertex.TriQuad + +vec4 GetPatchCoord(int index) +{ + vec2 uv[4]; + uv[0] = vec2(0, 0); + uv[1] = vec2(1, 0); + uv[2] = vec2(1, 1); + uv[3] = vec2(0, 1); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoord(uv[index], patchParam); +} + +vec2 GetPatchCoordLocalST() +{ + return gl_TessCoord; +} + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(float GetPointRasterSize(int)); +FORWARD_DECL(void ProcessPointId(int)); + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + vec4 point0 = GetWorldToViewMatrix() * transform * vec4(points[0],1.0); + vec4 point1 = GetWorldToViewMatrix() * transform * vec4(points[1],1.0); + vec4 point2 = GetWorldToViewMatrix() * transform * vec4(points[2],1.0); + vec4 point3 = GetWorldToViewMatrix() * transform * vec4(points[4],1.0); + + //Get the indata Neye if provided. + bool isFlipped = IsFlipped(); + vec3 Neye0 = GetNormal(vec3(0),0); + vec3 Neye1 = GetNormal(vec3(0),1); + vec3 Neye2 = GetNormal(vec3(0),2); + vec3 Neye3 = GetNormal(vec3(0),4); + + Neye0 = GetQuadGeometryNormal(Neye0, + point0, point1, point2, point3, isFlipped); + Neye1 = GetQuadGeometryNormal(Neye1, + point0, point1, point2, point3, isFlipped); + Neye2 = GetQuadGeometryNormal(Neye2, + point0, point1, point2, point3, isFlipped); + Neye3 = GetQuadGeometryNormal(Neye3, + point0, point1, point2, point3, isFlipped); + + point0 = DisplacementTerminal(0, point0, Neye0, GetPatchCoord(0)); + point1 = DisplacementTerminal(1, point1, Neye1, GetPatchCoord(1)); + point2 = DisplacementTerminal(2, point2, Neye2, GetPatchCoord(2)); + point3 = DisplacementTerminal(3, point3, Neye3, GetPatchCoord(3)); + + vec2 coord = gl_TessCoord.xy; + vec4 basis = vec4((1.0-coord.x) * (1.0-coord.y), coord.x * (1.0-coord.y), + (1.0-coord.x) * coord.y, coord.x * coord.y); + + outData.Peye = InterpolatePrimvar(point0, point1, point3, point2, basis); + outData.Neye = InterpolatePrimvar(Neye0, Neye1, Neye3, Neye2, basis); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(basis, 0, 1, 2, 4); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessControl.PatchCommon + +void +ClampTessLevels(inout vec4 tessOuterLo, inout vec4 tessOuterHi) +{ + // Clamp outer tess levels to a minimum of 2 so that we always + // sample along each edge and in the middle of transition patches. + const vec4 minOuterTessLevel = vec4(2.0); + + // Values in the tessOuterHi segments which are zero should remain zero. + const bvec4 maskOuterHi = notEqual(tessOuterHi, vec4(0.0)); + + tessOuterLo = max(minOuterTessLevel, tessOuterLo); + tessOuterHi = max(minOuterTessLevel * vec4(maskOuterHi), tessOuterHi); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.TessControl.BSplineQuad + +[ + ["out", "HD_NUM_PATCH_EVAL_VERTS"], + ["out", "vec4", "tessOuterLo", "patch"], + ["out", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexData", "inpt", "gl_MaxPatchVertices", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block array", "VertexDataTess", "outpt", "HD_NUM_PATCH_EVAL_VERTS", + ["OsdPerPatchVertexBezier", "v"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessControl.BSplineQuad + +void main(void) +{ + vec3 cv[HD_NUM_PATCH_VERTS]; + for (int i = 0; i < HD_NUM_PATCH_VERTS; ++i) { + cv[i] = inpt[i].Peye.xyz; + } + + ivec3 patchParam = GetPatchParam(); + + OsdComputePerPatchVertexBSpline(patchParam, gl_InvocationID, cv, + outpt[gl_InvocationID].v); + + // Wait for all basis conversion to be finished + barrier(); + + if (gl_InvocationID == 0) { + vec4 tessLevelOuter = vec4(0); + vec2 tessLevelInner = vec2(0); + + // Gather bezier control points to compute limit surface tess levels + OsdPerPatchVertexBezier cpBezier[HD_NUM_PATCH_EVAL_VERTS]; + for (int i = 0; i < HD_NUM_PATCH_EVAL_VERTS; ++i) { + cpBezier[i] = outpt[i].v; + } + OsdEvalPatchBezierTessLevels(cpBezier, patchParam, + tessOuterLo, tessOuterHi); + ClampTessLevels(tessOuterLo, tessOuterHi); + + OsdComputeTessLevels(tessOuterLo, tessOuterHi, + tessLevelOuter, tessLevelInner); + + gl_TessLevelOuter[0] = tessLevelOuter[0]; + gl_TessLevelOuter[1] = tessLevelOuter[1]; + gl_TessLevelOuter[2] = tessLevelOuter[2]; + gl_TessLevelOuter[3] = tessLevelOuter[3]; + + gl_TessLevelInner[0] = tessLevelInner[0]; + gl_TessLevelInner[1] = tessLevelInner[1]; + } + + ProcessPrimvarsOut(); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.TessEval.BezierQuad + +# XXX: due to NVIDIA shader compiler bug (filed as 1687344) +# we can't put patchCoord into interface block. +[ + ["in", "quads"], + ["in", "vec4", "tessOuterLo", "patch"], + ["in", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexDataTess", "inpt", "gl_MaxPatchVertices", + ["OsdPerPatchVertexBezier", "v"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessEval.BezierQuad + +void main(void) +{ + OsdPerPatchVertexBezier cv[16]; + for (int i = 0; i < 16; ++i) { + cv[i] = inpt[i].v; + } + vec2 UV = OsdGetTessParameterization(gl_TessCoord.xy, + tessOuterLo, + tessOuterHi); + + vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); + vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); + + ivec3 patchParam = inpt[0].v.patchParam; + OsdEvalPatchBezier(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); + + outData.Peye = vec4(P, 1); + outData.Neye = N; // normalized + + tesPatchCoord = OsdInterpolatePatchCoord(UV, patchParam); + tesTessCoord = UV; + + // Bilinear basis + vec4 basis = vec4( + (1.0-UV.x) * (1.0-UV.y), UV.x * (1.0-UV.y), + (1.0-UV.x) * UV.y, UV.x * UV.y ); + + ProcessPrimvarsOut(basis, 5, 6, 9, 10, UV); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.TessControl.BoxSplineTriangle + +[ + ["out", "HD_NUM_PATCH_EVAL_VERTS"], + ["out", "vec4", "tessOuterLo", "patch"], + ["out", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexData", "inpt", "gl_MaxPatchVertices", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block array", "VertexDataTess", "outpt", "HD_NUM_PATCH_EVAL_VERTS", + ["OsdPerPatchVertexBezier", "v"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessControl.BoxSplineTriangle + +void main(void) +{ + vec3 cv[HD_NUM_PATCH_VERTS]; + for (int i = 0; i < HD_NUM_PATCH_VERTS; ++i) { + cv[i] = inpt[i].Peye.xyz; + } + + ivec3 patchParam = GetPatchParam(); + + OsdComputePerPatchVertexBoxSplineTriangle(patchParam, gl_InvocationID, cv, + outpt[gl_InvocationID].v); + + // Wait for all basis conversion to be finished + barrier(); + + if (gl_InvocationID == 0) { + vec4 tessLevelOuter = vec4(0); + vec2 tessLevelInner = vec2(0); + + // Gather bezier control points to compute limit surface tess levels + vec3 cpBezier[HD_NUM_PATCH_EVAL_VERTS]; + for (int i = 0; i < HD_NUM_PATCH_EVAL_VERTS; ++i) { + cpBezier[i] = outpt[i].v.P; + } + OsdEvalPatchBezierTriangleTessLevels(cpBezier, patchParam, + tessOuterLo, tessOuterHi); + ClampTessLevels(tessOuterLo, tessOuterHi); + + OsdComputeTessLevelsTriangle(tessOuterLo, tessOuterHi, + tessLevelOuter, tessLevelInner); + + gl_TessLevelOuter[0] = tessLevelOuter[0]; + gl_TessLevelOuter[1] = tessLevelOuter[1]; + gl_TessLevelOuter[2] = tessLevelOuter[2]; + + gl_TessLevelInner[0] = tessLevelInner[0]; + } + + ProcessPrimvarsOut(); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.TessEval.BezierTriangle + +# XXX: due to NVIDIA shader compiler bug (filed as 1687344) +# we can't put patchCoord into interface block. +[ + ["in", "triangles"], + ["in", "vec4", "tessOuterLo", "patch"], + ["in", "vec4", "tessOuterHi", "patch"], + ["in block array", "VertexDataTess", "inpt", "gl_MaxPatchVertices", + ["OsdPerPatchVertexBezier", "v"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessEval.BezierTriangle + +void main(void) +{ + OsdPerPatchVertexBezier cv[15]; + for (int i = 0; i < 15; ++i) { + cv[i] = inpt[i].v; + } + vec2 UV = OsdGetTessParameterizationTriangle(gl_TessCoord.xyz, + tessOuterLo, + tessOuterHi); + + vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); + vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); + + ivec3 patchParam = inpt[0].v.patchParam; + OsdEvalPatchBezierTriangle(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); + + outData.Peye = vec4(P, 1); + outData.Neye = N; // normalized + + tesPatchCoord = OsdInterpolatePatchCoordTriangle(UV, patchParam); + tesTessCoord = UV; + + // Barycentric basis + vec4 basis = vec4( + (1.0f-UV.x-UV.y), UV.x, UV.y, 0.0f); + + ProcessPrimvarsOut(basis, 4, 5, 8, 0, UV); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessControl.PatchCommon + +void +ClampTessLevels(thread vec4 &tessOuterLo, thread vec4 &tessOuterHi) +{ + // Clamp outer tess levels to a minimum of 2 so that we always + // sample along each edge and in the middle of transition patches. + const vec4 minOuterTessLevel = vec4(2.0); + + // Values in the tessOuterHi segments which are zero should remain zero. + const bvec4 maskOuterHi = notEqual(tessOuterHi, vec4(0.0)); + + tessOuterLo = max(minOuterTessLevel, tessOuterLo); + tessOuterHi = max(minOuterTessLevel * vec4(maskOuterHi), tessOuterHi); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessControl.BSplineQuad + +vec3 GetPosAtUv(vec2 uv, OsdPatchParam param, thread vec3 *cv) +{ + float wP[HD_NUM_PATCH_VERTS]; + float wDs[HD_NUM_PATCH_VERTS]; + float wDt[HD_NUM_PATCH_VERTS]; + float wDss[HD_NUM_PATCH_VERTS]; + float wDst[HD_NUM_PATCH_VERTS]; + float wDtt[HD_NUM_PATCH_VERTS]; + OsdEvaluatePatchBasisNormalized(OSD_PATCH_DESCRIPTOR_REGULAR, + param, uv.x, uv.y, + &(wP[0]), &(wDs[0]), &(wDt[0]), &(wDss[0]), &(wDst[0]), &(wDtt[0])); + + vec3 pos = vec3(0.0, 0.0, 0.0); + for (int i = 0; i < 16; ++i) { + pos += cv[i] * wP[i]; + } + return pos; +} + +vec4 GetPatchCoord(int index) +{ + vec2 uv[4]; + uv[0] = vec2(0, 0); + uv[1] = vec2(1, 0); + uv[2] = vec2(1, 1); + uv[3] = vec2(0, 1); + + ivec3 patchParam = GetPatchParam(); + return OsdInterpolatePatchCoord(uv[index], patchParam); +} + +void main(void) +{ + MAT4 transform = + GetWorldToViewMatrix() * ApplyInstanceTransform(HdGet_transform()); + + ivec3 patchParam = GetPatchParam(); + OsdPatchParam osdParam = OsdPatchParamInit(patchParam.x, patchParam.y, 0); + + const vec2 corner0Uv = vec2(0.0, 0.0); + const vec2 corner1Uv = vec2(1.0, 0.0); + const vec2 corner2Uv = vec2(1.0, 1.0); + const vec2 corner3Uv = vec2(0.0, 1.0); + + vec3 corners[4]; + corners[0] = GetPosAtUv(corner0Uv, osdParam, &(points[0])); + corners[1] = GetPosAtUv(corner1Uv, osdParam, &(points[0])); + corners[2] = GetPosAtUv(corner2Uv, osdParam, &(points[0])); + corners[3] = GetPosAtUv(corner3Uv, osdParam, &(points[0])); + + int transitionMask = OsdGetPatchTransitionMask(patchParam); + vec3 midPoints[4]; + midPoints[0] = ((transitionMask & 8) == 0) + ? float3(0) + : GetPosAtUv(float2(0.0, 0.5), osdParam, &(points[0])); + midPoints[1] = ((transitionMask & 1) == 0) + ? float3(0) + : GetPosAtUv(float2(0.5, 0.0), osdParam, &(points[0])); + midPoints[2] = ((transitionMask & 2) == 0) + ? float3(0) + : GetPosAtUv(float2(1.0, 0.5), osdParam, &(points[0])); + midPoints[3] = ((transitionMask & 4) == 0) + ? float3(0) + : GetPosAtUv(float2(0.5, 1.0), osdParam, &(points[0])); + + vec4 tessLevelOuter = vec4(0); + vec2 tessLevelInner = vec2(0); + vec4 tessOuterLo = vec4(0); + vec4 tessOuterHi = vec4(0); + + // Gather bezier control points to compute limit surface tess levels + Osd_GetTessLevelsFromPatchBoundaries4( + GetTessLevel(), GetProjectionMatrix(), transform, + corners, midPoints, patchParam, tessOuterLo, tessOuterHi); + ClampTessLevels(tessOuterLo, tessOuterHi); + + OsdComputeTessLevels(tessOuterLo, tessOuterHi, + tessLevelOuter, tessLevelInner); + + device half *tessAsHalf = (device half *)tessFactors + patch_id * 6; + + tessAsHalf[0] = half(tessLevelOuter[0]); + tessAsHalf[1] = half(tessLevelOuter[1]); + tessAsHalf[2] = half(tessLevelOuter[2]); + tessAsHalf[3] = half(tessLevelOuter[3]); + + tessAsHalf[4] = half(tessLevelInner[0]); + tessAsHalf[5] = half(tessLevelInner[1]); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.PostTessVertex.BSplineQuad + +[ + ["in", "equal_spacing"], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessVertex.BSplineQuad + +vec2 GetPatchTessUV() +{ + const ivec3 patchParam = GetPatchParam(); + + const int refinementLevel = OsdGetPatchRefinementLevel(patchParam); + const float tessLevel = min(GetTessLevel(), + (float)OSD_MAX_TESS_LEVEL) / exp2((float)refinementLevel - 1); + + vec4 tessOuterLo(0), tessOuterHi(0); + OsdGetTessLevelsUniform(tessLevel, patchParam, tessOuterLo, tessOuterHi); + + return OsdGetTessParameterization(gl_TessCoord.xy, + tessOuterLo, + tessOuterHi); +} + +vec4 GetPatchCoord(int index) +{ + return OsdInterpolatePatchCoord(GetPatchTessUV(), GetPatchParam()); +} + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + const ivec3 patchParam = GetPatchParam(); + const vec2 UV = GetPatchTessUV(); + + float wP[HD_NUM_PATCH_VERTS]; + float wDs[HD_NUM_PATCH_VERTS]; + float wDt[HD_NUM_PATCH_VERTS]; + float wDss[HD_NUM_PATCH_VERTS]; + float wDst[HD_NUM_PATCH_VERTS]; + float wDtt[HD_NUM_PATCH_VERTS]; + OsdPatchParam osdParam = OsdPatchParamInit(patchParam.x, patchParam.y, 0); + OsdEvaluatePatchBasisNormalized(OSD_PATCH_DESCRIPTOR_REGULAR, + osdParam, UV.x, UV.y, + &(wP[0]), &(wDs[0]), &(wDt[0]), &(wDss[0]), &(wDst[0]), &(wDtt[0])); + + vec3 P = vec3(0.0); + vec3 N = vec3(0.0); + + vec3 pDs = vec3(0.0); + vec3 pDt = vec3(0.0); + + for (int i = 0; i < 16; ++i) { + P += points[i] * wP[i]; + pDs += points[i] * wDs[i]; + pDt += points[i] * wDt[i]; + } + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + N = normalize(cross(pDs,pDt)); + N = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(N,0)).xyz; + + if (length(N) > 0.0) { + N = normalize(N); + } + + tesPatchCoord = OsdInterpolatePatchCoord(UV, patchParam); + tesTessCoord = UV; + + P = (GetWorldToViewMatrix() * transform * vec4(P,1.0)).xyz; + P = (DisplacementTerminal(0, vec4(P,1.0), N, tesPatchCoord)).xyz; + + outData.Peye = vec4(P, 1); + outData.Neye = N; // normalized + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + // Bilinear basis + vec4 basis = vec4( + (1.0-UV.x) * (1.0-UV.y), UV.x * (1.0-UV.y), + (1.0-UV.x) * UV.y, UV.x * UV.y ); + + ProcessPrimvarsOut(basis, 5, 6, 9, 10, UV); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessControl.BoxSplineTriangle + +vec3 GetPosAtUv(vec2 uv, OsdPatchParam param, thread vec3 *cv) +{ + float wP[HD_NUM_PATCH_VERTS]; + float wDs[HD_NUM_PATCH_VERTS]; + float wDt[HD_NUM_PATCH_VERTS]; + float wDss[HD_NUM_PATCH_VERTS]; + float wDst[HD_NUM_PATCH_VERTS]; + float wDtt[HD_NUM_PATCH_VERTS]; + OsdEvaluatePatchBasisNormalized(OSD_PATCH_DESCRIPTOR_LOOP, + param, uv.x, uv.y, + &(wP[0]), &(wDs[0]), &(wDt[0]), &(wDss[0]), &(wDst[0]), &(wDtt[0])); + + vec3 pos = vec3(0.0, 0.0, 0.0); + for (int i = 0; i < 12; ++i) { + pos += cv[i] * wP[i]; + } + return pos; +} + +vec4 GetPatchCoord(int index) +{ + vec2 uv[3]; + uv[0] = vec2(0, 0); // (0, 0, 1); + uv[1] = vec2(1, 0); // (1, 0, 0); + uv[2] = vec2(0, 1); // (0, 1, 0); + + ivec3 patchParam = GetPatchParam(); + return OsdInterpolatePatchCoordTriangle(uv[index], patchParam); +} + +void main(void) +{ + MAT4 transform = + GetWorldToViewMatrix() * ApplyInstanceTransform(HdGet_transform()); + + ivec3 patchParam = GetPatchParam(); + OsdPatchParam osdParam = OsdPatchParamInit(patchParam.x, patchParam.y, 0); + + const vec3 corner0Uv = vec3(0.0, 0.0, 1.0); + const vec3 corner1Uv = vec3(1.0, 0.0, 0.0); + const vec3 corner2Uv = vec3(0.0, 1.0, 0.0); + + vec3 corners[3]; + corners[0] = GetPosAtUv(corner0Uv.xy, osdParam, &(points[0])); + corners[1] = GetPosAtUv(corner1Uv.xy, osdParam, &(points[0])); + corners[2] = GetPosAtUv(corner2Uv.xy, osdParam, &(points[0])); + + int transitionMask = OsdGetPatchTransitionMask(patchParam); + vec3 midPoints[3]; + midPoints[0] = ((transitionMask & 4) == 0) + ? float3(0) + : GetPosAtUv(((corner2Uv + corner0Uv)/2.0).xy, osdParam, &(points[0])); + midPoints[1] = ((transitionMask & 1) == 0) + ? float3(0) + : GetPosAtUv(((corner0Uv + corner1Uv)/2.0).xy, osdParam, &(points[0])); + midPoints[2] = ((transitionMask & 2) == 0) + ? float3(0) + : GetPosAtUv(((corner1Uv + corner2Uv)/2.0).xy, osdParam, &(points[0])); + + vec4 tessLevelOuter = vec4(0); + vec2 tessLevelInner = vec2(0); + vec4 tessOuterLo = vec4(0); + vec4 tessOuterHi = vec4(0); + Osd_GetTessLevelsFromPatchBoundaries3( + GetTessLevel(), GetProjectionMatrix(), transform, + corners, midPoints, patchParam, tessOuterLo, tessOuterHi); + ClampTessLevels(tessOuterLo, tessOuterHi); + + OsdComputeTessLevelsTriangle(tessOuterLo, tessOuterHi, + tessLevelOuter, tessLevelInner); + + device half *tessAsHalf = (device half *)tessFactors + patch_id * 4; + + tessAsHalf[0] = half(tessLevelOuter[0]); + tessAsHalf[1] = half(tessLevelOuter[1]); + tessAsHalf[2] = half(tessLevelOuter[2]); + + tessAsHalf[3] = half(tessLevelInner[0]); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.PostTessVertex.BoxSplineTriangle + +[ + ["in", "equal_spacing"], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "tesPatchCoord"], + ["out", "vec2", "tesTessCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.PostTessVertex.BoxSplineTriangle + +vec2 GetPatchTessUV() +{ + const ivec3 patchParam = GetPatchParam(); + + const int refinementLevel = OsdGetPatchRefinementLevel(patchParam); + const float tessLevel = min(GetTessLevel(), + (float)OSD_MAX_TESS_LEVEL) / exp2((float)refinementLevel - 1); + + vec4 tessOuterLo(0), tessOuterHi(0); + OsdGetTessLevelsUniform(tessLevel, patchParam, tessOuterLo, tessOuterHi); + + return OsdGetTessParameterizationTriangle(gl_TessCoord.xyz, + tessOuterLo, + tessOuterHi); +} + +vec4 GetPatchCoord(int index) +{ + return OsdInterpolatePatchCoordTriangle(GetPatchTessUV(), GetPatchParam()); +} + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + int pointId = GetPointId(); + gl_PointSize = GetPointRasterSize(pointId); + ProcessPointId(pointId); + + const ivec3 patchParam = GetPatchParam(); + const vec2 UV = GetPatchTessUV(); + + float wP[HD_NUM_PATCH_VERTS]; + float wDs[HD_NUM_PATCH_VERTS]; + float wDt[HD_NUM_PATCH_VERTS]; + float wDss[HD_NUM_PATCH_VERTS]; + float wDst[HD_NUM_PATCH_VERTS]; + float wDtt[HD_NUM_PATCH_VERTS]; + OsdPatchParam osdParam = OsdPatchParamInit(patchParam.x, patchParam.y, 0); + OsdEvaluatePatchBasisNormalized(OSD_PATCH_DESCRIPTOR_LOOP, + osdParam, UV.x, UV.y, + &(wP[0]), &(wDs[0]), &(wDt[0]), &(wDss[0]), &(wDst[0]), &(wDtt[0])); + + vec3 P = vec3(0.0); + vec3 N = vec3(0.0); + + vec3 pDs = vec3(0.0); + vec3 pDt = vec3(0.0); + + for (int i = 0; i < 12; ++i) { + P += points[i] * wP[i]; + pDs += points[i] * wDs[i]; + pDt += points[i] * wDt[i]; + } + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + N = normalize(cross(pDs,pDt)); + N = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(N,0)).xyz; + + if (length(N) > 0.0) { + N = normalize(N); + } + + tesPatchCoord = OsdInterpolatePatchCoordTriangle(UV, patchParam); + tesTessCoord = UV; + + P = (GetWorldToViewMatrix() * transform * vec4(P,1.0)).xyz; + P = (DisplacementTerminal(0, vec4(P,1.0), N, tesPatchCoord)).xyz; + + outData.Peye = vec4(P, 1); + outData.Neye = N; // normalized + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + // Barycentric basis + vec4 basis = vec4( + (1.0f-UV.x-UV.y), UV.x, UV.y, 0.0f); + + ProcessPrimvarsOut(basis, 4, 5, 8, 0, UV); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Geometry.TriangleTess + +[ + ["in", "triangles"], + ["out", "triangle_strip"], + ["out", "3"], + ["in block array", "VertexData", "inData", "3", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["in array", "vec4", "tesPatchCoord", "3"], + ["in array", "vec2", "tesTessCoord", "3"], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "gsPatchCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Geometry.TriangleTess + +vec4 GetPatchCoord(int index) +{ + return tesPatchCoord[index]; +} + +void emit(int index, vec4 Peye, vec3 Neye) +{ + outData.Peye = Peye; + outData.Neye = Neye; + gsPatchCoord = GetPatchCoord(index); + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(index, tesTessCoord[index]); + + EmitVertex(); +} + +FORWARD_DECL(vec4 ComputeSelectionOffset()); // selection.glslfx + +void main(void) +{ + gl_PrimitiveID = gl_PrimitiveIDIn; + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + + vec3 Neye0 = isFlipped ? -inData[0].Neye : inData[0].Neye; + Neye0 = GetNormal(Neye0, 0, tesTessCoord[0]); + Neye0 = GetTriGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye1 = isFlipped ? -inData[1].Neye : inData[1].Neye; + Neye1 = GetNormal(Neye1, 0, tesTessCoord[1]); + Neye1 = GetTriGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye2 = isFlipped ? -inData[2].Neye : inData[2].Neye; + Neye2 = GetNormal(Neye2, 0, tesTessCoord[2]); + Neye2 = GetTriGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + + vec4 Peye0 = DisplacementTerminal( + 0, inData[0].Peye, Neye0, GetPatchCoord(0)); + vec4 Peye1 = DisplacementTerminal( + 1, inData[1].Peye, Neye1, GetPatchCoord(1)); + vec4 Peye2 = DisplacementTerminal( + 2, inData[2].Peye, Neye2, GetPatchCoord(2)); + + // For wireframe, add a polygon offset to selected faces to ensure they + // rasterize over unselected faces. + vec4 selOffset = ComputeSelectionOffset(); + Peye0 += selOffset; + Peye1 += selOffset; + Peye2 += selOffset; + + // triangle 0: vertices (0,1,2) + emit(0, Peye0, Neye0); + emit(1, Peye1, Neye1); + emit(2, Peye2, Neye2); + + EndPrimitive(); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.TessEval.VaryingInterpolation + +float InterpolatePrimvar(float inPv0, float inPv1, float inPv2, float inPv3, + vec4 basis, vec2 uv) +{ + return basis[0] * inPv0 + + basis[1] * inPv1 + + basis[2] * inPv2 + + basis[3] * inPv3; +} + +vec2 InterpolatePrimvar(vec2 inPv0, vec2 inPv1, vec2 inPv2, vec2 inPv3, + vec4 basis, vec2 uv) +{ + return basis[0] * inPv0 + + basis[1] * inPv1 + + basis[2] * inPv2 + + basis[3] * inPv3; +} + +vec3 InterpolatePrimvar(vec3 inPv0, vec3 inPv1, vec3 inPv2, vec3 inPv3, + vec4 basis, vec2 uv) +{ + return basis[0] * inPv0 + + basis[1] * inPv1 + + basis[2] * inPv2 + + basis[3] * inPv3; +} + +vec4 InterpolatePrimvar(vec4 inPv0, vec4 inPv1, vec4 inPv2, vec4 inPv3, + vec4 basis, vec2 uv) +{ + return basis[0] * inPv0 + + basis[1] * inPv1 + + basis[2] * inPv2 + + basis[3] * inPv3; +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Geometry.Triangle + +[ + ["in", "triangles"], + ["out", "triangle_strip"], + ["out", "3"], + ["in block array", "VertexData", "inData", "3", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "gsPatchCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Geometry.Triangle + +vec4 GetPatchCoord(int index) +{ + vec2 uv[3]; + uv[0] = vec2(0, 0); // (0, 0, 1); + uv[1] = vec2(1, 0); // (1, 0, 0); + uv[2] = vec2(0, 1); // (0, 1, 0); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoordTriangle(uv[index], patchParam); +} + +void emit(int index, vec4 Peye, vec3 Neye) +{ + outData.Peye = Peye; + outData.Neye = Neye; + + gsPatchCoord = GetPatchCoord(index); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(index); + + EmitVertex(); +} + +FORWARD_DECL(vec4 ComputeSelectionOffset()); // selection.glslfx + +void main(void) +{ + gl_PrimitiveID = gl_PrimitiveIDIn; + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + + vec3 Neye0 = GetNormal(inData[0].Neye, 0); + Neye0 = GetTriGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye1 = GetNormal(inData[1].Neye, 1); + Neye1 = GetTriGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye2 = GetNormal(inData[2].Neye, 2); + Neye2 = GetTriGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + + vec4 Peye0 = DisplacementTerminal( + 0, inData[0].Peye, Neye0, GetPatchCoord(0)); + vec4 Peye1 = DisplacementTerminal( + 1, inData[1].Peye, Neye1, GetPatchCoord(1)); + vec4 Peye2 = DisplacementTerminal( + 2, inData[2].Peye, Neye2, GetPatchCoord(2)); + + // For wireframe, add a polygon offset to selected faces to ensure they + // rasterize over unselected faces. + vec4 selOffset = ComputeSelectionOffset(); + Peye0 += selOffset; + Peye1 += selOffset; + Peye2 += selOffset; + + // triangle 0: vertices (0,1,2) + emit(0, Peye0, Neye0); + emit(1, Peye1, Neye1); + emit(2, Peye2, Neye2); + + EndPrimitive(); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Geometry.TriQuad + +[ + ["in", "triangles"], + ["out", "triangle_strip"], + ["out", "3"], + ["in block array", "VertexData", "inData", "3", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Geometry.TriQuad + +vec4 GetPatchCoord(int index) +{ + vec2 uv[4]; + uv[0] = vec2(0, 0); + uv[1] = vec2(1, 0); + uv[2] = vec2(1, 1); + uv[3] = vec2(0, 1); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoord(uv[index], patchParam); +} + +void emit(int index, vec4 Peye, vec3 Neye) +{ + outData.Peye = Peye; + outData.Neye = Neye; + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(index); + + EmitVertex(); +} + +FORWARD_DECL(vec4 ComputeSelectionOffset()); // selection.glslfx + +void main(void) +{ + gl_PrimitiveID = gl_PrimitiveIDIn; + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + + vec3 Neye0 = GetNormal(inData[0].Neye, 0); + Neye0 = GetTriGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye1 = GetNormal(inData[1].Neye, 1); + Neye1 = GetTriGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + vec3 Neye2 = GetNormal(inData[2].Neye, 2); + Neye2 = GetTriGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, + inData[2].Peye, isFlipped); + + vec4 Peye0 = DisplacementTerminal( + 0, inData[0].Peye, Neye0, GetPatchCoord(0)); + vec4 Peye1 = DisplacementTerminal( + 1, inData[1].Peye, Neye1, GetPatchCoord(1)); + vec4 Peye2 = DisplacementTerminal( + 2, inData[2].Peye, Neye2, GetPatchCoord(2)); + + // For wireframe, add a polygon offset to selected faces to ensure they + // rasterize over unselected faces. + vec4 selOffset = ComputeSelectionOffset(); + Peye0 += selOffset; + Peye1 += selOffset; + Peye2 += selOffset; + + // triangle 0: vertices (0,1,2) + emit(0, Peye0, Neye0); + emit(1, Peye1, Neye1); + emit(2, Peye2, Neye2); + EndPrimitive(); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Geometry.Quad + +[ + ["in", "lines_adjacency"], + ["out", "triangle_strip"], + ["out", "6"], + ["in block array", "VertexData", "inData", "4", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out block", "VertexData", "outData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ], + ["out", "vec4", "gsPatchCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Geometry.Quad + +vec4 GetPatchCoord(int index) +{ + vec2 uv[4]; + uv[0] = vec2(0, 0); + uv[1] = vec2(1, 0); + uv[2] = vec2(1, 1); + uv[3] = vec2(0, 1); + + ivec3 patchParam = GetPatchParam(); + return InterpolatePatchCoord(uv[index], patchParam); +} + +void emit(int index, vec4 Peye, vec3 Neye) +{ + outData.Peye = Peye; + outData.Neye = Neye; + + gsPatchCoord = GetPatchCoord(index); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + ProcessPrimvarsOut(index); + + EmitVertex(); +} + +FORWARD_DECL(vec4 ComputeSelectionOffset()); // selection.glslfx + +void main(void) +{ + gl_PrimitiveID = gl_PrimitiveIDIn; + + bool isFlipped = IsFlipped(); // consider handedness AND negative-scale + + vec3 Neye0 = GetNormal(inData[0].Neye, 0); + Neye0 = GetQuadGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, + inData[2].Peye, inData[3].Peye, isFlipped); + vec3 Neye1 = GetNormal(inData[1].Neye, 1); + Neye1 = GetQuadGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, + inData[2].Peye, inData[3].Peye, isFlipped); + vec3 Neye2 = GetNormal(inData[2].Neye, 2); + Neye2 = GetQuadGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, + inData[2].Peye, inData[3].Peye, isFlipped); + vec3 Neye3 = GetNormal(inData[3].Neye, 3); + Neye3 = GetQuadGeometryNormal(Neye3, inData[0].Peye, inData[1].Peye, + inData[2].Peye, inData[3].Peye, isFlipped); + + vec4 Peye0 = DisplacementTerminal( + 0, inData[0].Peye, Neye0, GetPatchCoord(0)); + vec4 Peye1 = DisplacementTerminal( + 1, inData[1].Peye, Neye1, GetPatchCoord(1)); + vec4 Peye2 = DisplacementTerminal( + 2, inData[2].Peye, Neye2, GetPatchCoord(2)); + vec4 Peye3 = DisplacementTerminal( + 3, inData[3].Peye, Neye3, GetPatchCoord(3)); + + // Generate triangles (0,1,2) and (2,3,0) + // 3---2 + // | .| + // | . | + // |. | + // 0---1 + // The indices post-quadrangulation/subdivision follow the convention: + // 0 -> original (hull) vertex + // 1,3 -> edge vertices + // 2 -> center vertex + // + // By having index 2 in both the triangles, we ensure the pre-quadrangulated + // face's normal (at the center) is part of the rasterizer interpolation, + // which matters when we use smooth/limit normals. + // In the case of flat normals, we use the vertex positions, so it doesn't + // matter. + + // For wireframe, add a polygon offset to selected faces to ensure they + // rasterize over unselected faces. + vec4 selOffset = ComputeSelectionOffset(); + Peye0 += selOffset; + Peye1 += selOffset; + Peye2 += selOffset; + Peye3 += selOffset; + + // triangle 0: vertices (0,1,2) + emit(0, Peye0, Neye0); + emit(1, Peye1, Neye1); + emit(2, Peye2, Neye2); + EndPrimitive(); + + // triangle 1: vertices (2,3,0) + gl_PrimitiveID = gl_PrimitiveIDIn; + emit(2, Peye2, Neye2); + emit(3, Peye3, Neye3); + emit(0, Peye0, Neye0); + EndPrimitive(); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Fragment.PatchCoord + +[ + ["in", "vec4", "gsPatchCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord + +vec4 GetInterpolatedPatchCoord() +{ + return gsPatchCoord; +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.NoGS + +vec4 GetInterpolatedPatchCoord() +{ + return vec4(0); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Fragment.PatchCoord.Tess + +[ + ["in", "vec4", "tesPatchCoord"] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.Tess + +vec4 GetInterpolatedPatchCoord() +{ + return tesPatchCoord; +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.Triangle + +vec2 GetPatchCoordLocalST() +{ + return GetBarycentricCoord().yz; +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoordTriangle( + GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.Quad + +vec2 GetPatchCoordLocalST() +{ + return GetBarycentricCoord().yz; +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoord(GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.TriQuad + +vec2 GetPatchCoordLocalST() +{ + vec3 barycentric = GetBarycentricCoord(); + if (GetTriQuadID() == 0) { + vec2 uv[3] = { vec2(0,0), vec2(1,0), vec2(1,1) }; + return uv[0]*barycentric.x + uv[1]*barycentric.y + uv[2]*barycentric.z; + } else { + vec2 uv[3] = { vec2(1,1), vec2(0,1), vec2(0,0) }; + return uv[0]*barycentric.x + uv[1]*barycentric.y + uv[2]*barycentric.z; + } +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoord(GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.TrianglePTVS + +vec2 GetPatchCoordLocalST() +{ + return GetTessCoordTriangle().yz; +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoordTriangle( + GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.QuadPTVS + +vec2 GetPatchCoordLocalST() +{ + return GetTessCoordTriangle().yz; +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoord(GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment.PatchCoord.TriQuadPTVS + +vec2 GetPatchCoordLocalST() +{ + return GetTessCoord().xy; +} + +vec4 GetInterpolatedPatchCoord() +{ + return InterpolatePatchCoord(GetPatchCoordLocalST(), GetPatchParam()); +} + +--- -------------------------------------------------------------------------- +-- layout Mesh.Fragment + +[ + ["in block", "VertexData", "inData", + ["vec4", "Peye"], + ["vec3", "Neye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Mesh.Fragment + +#ifndef HD_HAS_ptexFaceOffset +#define HD_HAS_ptexFaceOffset +int HdGet_ptexFaceOffset() +{ + return 0; +} +#endif + +vec4 GetPatchCoord(int localIndex) +{ + vec4 patchCoord = GetInterpolatedPatchCoord(); + return vec4(patchCoord.xyz, patchCoord.w + HdGet_ptexFaceOffset()); +} + +vec4 GetPatchCoord() +{ + return GetPatchCoord(0); +} + +vec3 ComputeScreenSpacePeye() +{ + return inData.Peye.xyz / inData.Peye.w; +} + +vec3 ComputeScreenSpaceNeye() +{ + vec3 Peye = ComputeScreenSpacePeye(); + vec3 Neye = normalize(cross(dFdx(Peye), dFdy(Peye))); + return (gl_FrontFacing ? Neye : -Neye); +} + +void main(void) +{ + bool isFlipped = IsFlipped(); + + DiscardBasedOnShading(gl_FrontFacing, isFlipped); + + DiscardBasedOnTopologicalVisibility(); + + vec4 color = vec4(0.5, 0.5, 0.5, 1); +#ifdef HD_HAS_displayColor + color.rgb = HdGet_displayColor().rgb; +#endif +#ifdef HD_HAS_displayOpacity + color.a = HdGet_displayOpacity(); +#endif + + vec3 Peye = ComputeScreenSpacePeye(); + + vec3 Neye = inData.Neye; + // Normalize Neye after rasterizer interpolation. + if (length(Neye) > 0.0) { + Neye = normalize(Neye); + } + // Give the shader key a chance to override the normal. + Neye = GetNormal(Neye, 0); + // Orient the normal for shading. + Neye = GetShadingNormal(Neye, isFlipped); + + vec4 patchCoord = GetPatchCoord(); + color = ShadingTerminal(vec4(Peye, 1), Neye, color, patchCoord); + + color = ApplyEdgeColor(color, patchCoord); + +#ifdef HD_MATERIAL_TAG_MASKED + if (ShouldDiscardByAlpha(color)) { + discard; + return; + } +#endif + + RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); +} diff --git a/Sources/HdSt/shaders/meshFaceCull.glslfx b/Sources/HdSt/shaders/meshFaceCull.glslfx new file mode 100644 index 0000000000..d9afbb8708 --- /dev/null +++ b/Sources/HdSt/shaders/meshFaceCull.glslfx @@ -0,0 +1,40 @@ +-- glslfx version 0.1 + +// +// Copyright 2020 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/meshFaceCull.glslfx + + +--- -------------------------------------------------------------------------- +-- glsl MeshFaceCull.Fragment.None + +void DiscardBasedOnShading(bool frontFacing, bool isFlipped) +{ + // Nothing to do since h/w face culling is used. +} + +--- -------------------------------------------------------------------------- +-- glsl MeshFaceCull.Fragment.FrontFacing + +void DiscardBasedOnShading(bool frontFacing, bool isFlipped) +{ + if (frontFacing != isFlipped) { + discard; + } +} + +--- -------------------------------------------------------------------------- +-- glsl MeshFaceCull.Fragment.BackFacing + +void DiscardBasedOnShading(bool frontFacing, bool isFlipped) +{ + if ((!frontFacing) != isFlipped) { + discard; + } +} diff --git a/Sources/HdSt/shaders/meshNormal.glslfx b/Sources/HdSt/shaders/meshNormal.glslfx new file mode 100644 index 0000000000..38fea44cc6 --- /dev/null +++ b/Sources/HdSt/shaders/meshNormal.glslfx @@ -0,0 +1,201 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/meshNormal.glslfx + + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Scene + +vec3 GetNormal(vec3 Neye, int index) +{ + vec3 normal = vec3(0); +#if defined(HD_HAS_normals) + normal = vec3(HdGet_normals(index).xyz); +#endif + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(normal,0)).xyz; + + if (length(normal) > 0.0) + normal = normalize(normal); + return normal; +} + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + return GetNormal(Neye, index); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Scene.Patches + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + vec3 normal = vec3(0); +#if defined(HD_HAS_normals) + normal = vec3(HdGet_normals(index, localST).xyz); +#endif + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(normal,0)).xyz; + + if (length(normal) > 0.0) + normal = normalize(normal); + return normal; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Smooth + +vec3 GetNormal(vec3 Neye, int index) +{ + vec3 normal = vec3(0); +#if defined(HD_HAS_smoothNormals) + normal = vec3(HdGet_smoothNormals(index).xyz); +#elif defined(HD_HAS_packedSmoothNormals) + normal = vec3(HdGet_packedSmoothNormals(index).xyz); +#endif + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(normal,0)).xyz; + + if (length(normal) > 0.0) + normal = normalize(normal); + return normal; +} + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + return GetNormal(Neye, index); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Flat + +vec3 GetNormal(vec3 Neye, int index) +{ + vec3 normal = vec3(0); +#if defined(HD_HAS_flatNormals) + normal = vec3(HdGet_flatNormals(index).xyz); +#elif defined(HD_HAS_packedFlatNormals) + normal = vec3(HdGet_packedFlatNormals(index).xyz); +#endif + + MAT4 transformInv = ApplyInstanceTransformInverse(HdGet_transformInverse()); + normal = vec4(transpose(transformInv * GetWorldToViewInverseMatrix()) * + vec4(normal,0)).xyz; + + if (length(normal) > 0.0) + normal = normalize(normal); + return normal; +} + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + return GetNormal(Neye, index); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Fragment.ScreenSpace + +FORWARD_DECL(vec3 ComputeScreenSpaceNeye()); + +vec3 GetNormal(vec3 Neye, int index) +{ + return ComputeScreenSpaceNeye(); +} + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + return GetNormal(Neye, index); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Pass + +vec3 GetNormal(vec3 Neye, int index) +{ + return Neye; +} + +vec3 GetNormal(vec3 Neye, int index, vec2 localST) +{ + return GetNormal(Neye, index); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Geometry.Flat + +vec3 GetTriGeometryNormal(vec3 Neye, vec4 Peye0, vec4 Peye1, vec4 Peye2, + bool isFlipped) +{ + // ignore vertex normal and compute flat facing normal + vec3 n = normalize(cross(Peye1.xyz - Peye0.xyz, Peye2.xyz - Peye0.xyz)); + return isFlipped ? -n : n; +} + +vec3 GetQuadGeometryNormal(vec3 Neye, + vec4 Peye0, vec4 Peye1, vec4 Peye2, vec4 Peye3, + bool isFlipped) +{ + // 0---3 + // |. | + // | . | + // | .| + // 1---2 + // ignore vertex normal and compute flat facing normal + // average diagonal cross products to deal with co-linear edges + vec3 A0 = Peye2.xyz - Peye3.xyz; + vec3 B0 = Peye0.xyz - Peye3.xyz; + vec3 A1 = Peye0.xyz - Peye1.xyz; + vec3 B1 = Peye2.xyz - Peye1.xyz; + vec3 n = normalize(cross(B0, A0) + cross(B1, A1)); + return isFlipped ? -n : n; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Geometry.NoFlat + +vec3 GetTriGeometryNormal(vec3 Neye, vec4 Peye0, vec4 Peye1, vec4 Peye2, + bool isFlipped) +{ + return Neye; +} + +vec3 GetQuadGeometryNormal(vec3 Neye, + vec4 Peye0, vec4 Peye1, vec4 Peye2, vec4 Peye3, + bool isFlipped) +{ + return Neye; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Fragment.SingleSided + +vec3 GetShadingNormal(vec3 N, bool isFlipped) +{ + // the fragment shader takes already-flipped-normals. + // no need to flip here. + return N; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshNormal.Fragment.DoubleSided + +vec3 GetShadingNormal(vec3 N, bool isFlipped) +{ + // note that negative scaling isn't taken into account in gl_FrontFacing + // so we have to consider isFlipped here too. + return (isFlipped != gl_FrontFacing) ? N : -N; +} diff --git a/Sources/HdSt/shaders/meshWire.glslfx b/Sources/HdSt/shaders/meshWire.glslfx new file mode 100644 index 0000000000..6969bea248 --- /dev/null +++ b/Sources/HdSt/shaders/meshWire.glslfx @@ -0,0 +1,326 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/meshWire.glslfx + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeMaskTriangle + +vec3 GetPrimitiveEdgeMask() +{ + // A value of one in this mask hides the corresponding edge. + // (See hd/meshUtil.cpp) + return vec3(0, GetEdgeFlag() & 1, GetEdgeFlag() & 2); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeMaskQuad + +vec3 GetPrimitiveEdgeMask() +{ + // A value of one in this mask hides the corresponding edge. + // (See hd/meshUtil.cpp) + return vec3(GetEdgeFlag() != 0, 1, 0); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeMaskTriQuad + +vec3 GetPrimitiveEdgeMask() +{ + // A value of one in this mask hides the corresponding edge. + // (See hd/meshUtil.cpp) + if (GetTriQuadID() == 0) { + return vec3(GetEdgeFlag() != 0, 1, 0); + } else { + return vec3(0, 1, GetEdgeFlag() != 0); + } +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeMaskRefinedQuad + +vec3 GetPrimitiveEdgeMask() +{ + // Hide the common edge between the pair of rasterized triangles. + return vec3(0,1,0); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeMaskNone + +vec3 GetPrimitiveEdgeMask() +{ + return vec3(0); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeCommon + +// Returns the distance of the current fragment (in viewport pixel units) from +// the nearest edge. +float GetMinEdgeDistance() +{ + // Hide triangle edges by adding edge mask. + vec3 param = GetEdgeCoord() + GetPrimitiveEdgeMask(); + vec3 edgeDistance = max(vec3(0.0), param / fwidth(param)); + return min(edgeDistance.x, + min(edgeDistance.y, + edgeDistance.z)); +} + +// Use edge distance to compute a smooth opacity falloff for good looking edges. +float GetEdgeFalloff(float d) { + return exp2(-4 * d * d); +} + +float GetEdgeOpacity() { + return GetEdgeFalloff(GetMinEdgeDistance()); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeTriQuadPTVS + +// Returns the distance of the current fragment (in viewport pixel units) from +// the nearest edge. +float GetMinEdgeDistance() +{ + vec2 leftBottom = GetEdgeCoord().xy; + vec2 rightTop = vec2(1.0) - leftBottom; + + vec4 param = vec4(leftBottom.y, rightTop.x, rightTop.y, leftBottom.x); + vec4 edgeDistance = max(vec4(0.0), param / fwidth(param)); + + // Hide internal edges introduced by quadrangulation + if (GetEdgeFlag() != 0) edgeDistance.yz += vec2(2.0); + + return min(min(edgeDistance.x, edgeDistance.y), + min(edgeDistance.z, edgeDistance.w)); +} + +// Use edge distance to compute a smooth opacity falloff for good looking edges. +float GetEdgeFalloff(float d) { + return exp2(-4 * d * d); +} + +float GetEdgeOpacity() { + return GetEdgeFalloff(GetMinEdgeDistance()); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeParam + +vec3 GetEdgeParamTriangle() +{ + // Expand barycentric coordinates + vec2 param = GetPatchCoord(0).xy; + vec3 barycentric = vec3(param.x, param.y, 1 - param.x - param.y); + + // Match triangle edge order + return barycentric.yzx; +} + +vec3 GetEdgeDistanceTriangle() +{ + vec3 param = GetEdgeParamTriangle(); + return max(vec3(0.0), param / fwidth(param)); +} + +vec4 GetEdgeParamQuad() +{ + // Expand coordinates to opposite corners of quad + vec2 leftBottom = GetPatchCoord(0).xy; + vec2 rightTop = vec2(1.0) - leftBottom; + + // Match quad edge order + return vec4(leftBottom.y, rightTop.x, rightTop.y, leftBottom.x); +} + +vec4 GetEdgeDistanceQuad() +{ + vec4 param = GetEdgeParamQuad(); + return max(vec4(0.0), param / fwidth(param)); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshPatchWire.Fragment.PatchEdgeTriangle + +// Override for subdivided faces to make the boundary of the face stand out. +float GetEdgeOpacityForPatch() +{ + // Distance in pixels from triangle patch edges. + vec3 patchEdgeDistance = GetEdgeDistanceTriangle(); + + const float patchEdgeMinDistance = + min(patchEdgeDistance.x, min(patchEdgeDistance.y, patchEdgeDistance.z)); + + // Reduce the opacity of edges not on patch boundaries + if (patchEdgeMinDistance > 1.0) { + return 0.3 * GetEdgeOpacity(); + } + + // Use distance to patch edge rather than distance to primitive edge + return GetEdgeFalloff(patchEdgeMinDistance); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshPatchWire.Fragment.PatchEdgeQuad + +// Override for subdivided faces to make the boundary of the face stand out. +float GetEdgeOpacityForPatch() +{ + // Distance in pixels from quad patch edges. + vec4 patchEdgeDistance = GetEdgeDistanceQuad(); + + // Hide sub-patch internal edges introduced by quadrangulation + if (GetEdgeFlag() != 0) patchEdgeDistance.yz += vec2(2.0); + + const float patchEdgeMinDistance = + min(min(patchEdgeDistance.x, patchEdgeDistance.y), + min(patchEdgeDistance.z, patchEdgeDistance.w)); + + // Reduce the opacity of edges not on patch boundaries + if (patchEdgeMinDistance > 1.0) { + return 0.3 * GetEdgeOpacity(); + } + + // Use distance to patch edge rather than distance to primitive edge + return GetEdgeFalloff(patchEdgeMinDistance); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.FinalEdgeOpacityNoForce + +vec4 ApplyFinalEdgeOpacity(vec4 Cfill) +{ + return Cfill; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.FinalEdgeOpacityForce + +vec4 ApplyFinalEdgeOpacity(vec4 Cfill) +{ + Cfill.a = 1.0; + return Cfill; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.NoEdge + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + return Cfill; +} + +// Return a large value, signifying that the fragment isn't near an edge. +float GetMinEdgeDistance() +{ + return 1000.0; +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeOnSurface + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + float p = GetEdgeOpacity(); + + vec4 wireColor = GetWireframeColor(); + + // If wireColor is unset (zero), the fill color is just dimmed a bit. + if (all(equal(wireColor, vec4(0)))) wireColor.a = 0.5; + + vec4 Cedge = vec4(mix(Cfill.rgb, wireColor.rgb, wireColor.a), 1); + Cfill.rgb = mix(Cfill.rgb, Cedge.rgb, p); + + return ApplyFinalEdgeOpacity(Cfill); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeOnlyBlendColor + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + float p = GetEdgeOpacity(); + if (p < 0.5) discard; + + vec4 wireColor = GetWireframeColor(); + + // If wireColor is unset (zero), ignore it altogether + + Cfill.rgb = mix(Cfill.rgb, wireColor.rgb, wireColor.a); + + return ApplyFinalEdgeOpacity(Cfill); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeOnlyNoBlend + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + float p = GetEdgeOpacity(); + if (p < 0.5) discard; + + return ApplyFinalEdgeOpacity(Cfill); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeCoord.Barycentric + +vec3 GetEdgeCoord() +{ + return GetBarycentricCoord(); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeCoord.Tess + +vec2 GetEdgeCoord() +{ + return GetTessCoord(); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshWire.Fragment.EdgeCoord.TessTriangle + +vec3 GetEdgeCoord() +{ + return GetTessCoordTriangle(); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshPatchWire.Fragment.EdgeOnSurface + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + float p = GetEdgeOpacityForPatch(); + + vec4 wireColor = GetWireframeColor(); + + // If wireColor is unset (zero), the fill color is just dimmed a bit. + if (all(equal(wireColor, vec4(0)))) wireColor.a = 0.5; + + vec4 Cedge = vec4(mix(Cfill.rgb, wireColor.rgb, wireColor.a), 1); + Cfill.rgb = mix(Cfill.rgb, Cedge.rgb, p); + + return ApplyFinalEdgeOpacity(Cfill); +} + +--- -------------------------------------------------------------------------- +-- glsl MeshPatchWire.Fragment.EdgeOnly + +vec4 ApplyEdgeColor(vec4 Cfill, vec4 patchCoord) +{ + float p = GetEdgeOpacity(); + if (p < 0.5) discard; + + return ApplyFinalEdgeOpacity(Cfill); +} diff --git a/Sources/HdSt/shaders/pointId.glslfx b/Sources/HdSt/shaders/pointId.glslfx new file mode 100644 index 0000000000..d39b170d4f --- /dev/null +++ b/Sources/HdSt/shaders/pointId.glslfx @@ -0,0 +1,87 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/pointId.glslfx + +#import $TOOLS/hdx/shaders/selection.glslfx + +--- -------------------------------------------------------------------------- +-- glsl PointId.Vertex.None + +int GetPointId() +{ + return -1; +} + +float GetPointRasterSize(int pointId) +{ + return GetPointSize(); +} + +void ProcessPointId(int pointId) +{ + // do nothing +} + +--- -------------------------------------------------------------------------- +-- layout PointId.Vertex.PointParam + +# Plumb the pointId, for use in the FS. +# XXX: This works only because the TES and GS stages are disabled when +# rendering as points. If they are enabled, we need to add the plumbing. +[ + ["out", "int", "vsPointId", "flat"] +] + +--- -------------------------------------------------------------------------- +-- glsl PointId.Vertex.PointParam + +// Fwd declare accessor method defined via code gen +FORWARD_DECL(int GetBaseVertexOffset()); +int GetPointId() +{ + return int(hd_VertexID) - GetBaseVertexOffset(); +} + +// Fwd declare selection decoder method defined in hdx/shaders/selection.glslfx +FORWARD_DECL(bool IsPointSelected(int)); +float GetPointRasterSize(int pointId) +{ + return IsPointSelected(pointId)? + GetPointSelectedSize() : GetPointSize(); +} + +void ProcessPointId(int pointId) +{ + vsPointId = pointId; +} + +--- -------------------------------------------------------------------------- +-- glsl PointId.Fragment.Fallback + +int GetPointId() +{ + return -1; +} + +--- -------------------------------------------------------------------------- +-- layout PointId.Fragment.PointParam + +[ + ["in", "int", "vsPointId", "flat"] +] + +--- -------------------------------------------------------------------------- +-- glsl PointId.Fragment.PointParam + +int GetPointId() +{ + return vsPointId; +} diff --git a/Sources/HdSt/shaders/points.glslfx b/Sources/HdSt/shaders/points.glslfx new file mode 100644 index 0000000000..1e8ad2d623 --- /dev/null +++ b/Sources/HdSt/shaders/points.glslfx @@ -0,0 +1,151 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/points.glslfx + +#import $TOOLS/hdSt/shaders/instancing.glslfx +#import $TOOLS/hdSt/shaders/terminals.glslfx +#import $TOOLS/hdSt/shaders/pointId.glslfx + +--- -------------------------------------------------------------------------- +-- layout Point.Vertex + +[ + ["out block", "VertexData", "outData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Point.Vertex + +// Fwd declare methods defined in pointId.glslfx, that are used below. +FORWARD_DECL(int GetPointId()); +FORWARD_DECL(void ProcessPointId(int)); + +// The approach used below transforms a unit diagonal vector by the provided +// matrix and returns its length. +// This works when the provided transform is computed from a chain of +// transformations wherein the scale operation doesn't follow a rotation. +// This is typically true with scene-graph hierachies wherein the parent nodes +// are rigid-body transformations. +// +// When that isn't the case, this approach would result in scaling that is +// coordinate-system dependent. +// The accurate way to calculate the scale would be to compute the determinant. +// +float ExtractAverageScaleFromMatrix( + MAT4 transform) +{ + const vec4 eyeScale = vec4(transform * normalize(vec4(1,1,1,0))); + return length(eyeScale.xyz); +} + + +// Compute the point size in pixels based on the authored width. +float ComputeRasterPointSize( + MAT4 modelToWorldTransform, float eyeZ) +{ + // Check for primvar 'widths'. This is in model space. +#if defined(HD_HAS_widths) + float modelWidth = HdGet_widths(); +#else + float modelWidth = 1.0; +#endif + + // Compute scaling from the modelToWorld and worldToView transforms. + const float modelToEyeScale = + ExtractAverageScaleFromMatrix( + GetWorldToViewMatrix() * modelToWorldTransform); + + // Compute the scaling factor in X when transforming from eye space to NDC + // space. We want to know how much the x-value of the result of the + // perspective division varies as the x-value of the position (x,y,z,1) in + // eye space varies. + // + // With 'p' being the projection matrix and using row-major order, the + // x-value in NDC space is: + // + // (x * p[0][0] + y * p[1][0] + z * p[2][0] + 1 * p[3][0]) / + // (x * p[0][3] + y * p[1][3] + z * p[2][3] + 1 * p[3][3]) + // + // The derivative with respect to x under the assumption that p[0][3] and + // p[1][3] is zero (which is the case for perspective and orthographic + // projection) then simply is p[0][0] / (z * p[2][3] + p[3][3]). + // + const MAT4 projMat = GetProjectionMatrix(); + const float eyeToClipXScale = float(projMat[0][0]); + const float clipW = float(eyeZ * projMat[2][3] + projMat[3][3]); + const float eyeToNDCScale = eyeToClipXScale / clipW; + + // Our final scaling factor is from the viewport transform, transforming + // from [-1,1] NDC space to image (pixel) space. + const float viewportSizeX = GetViewport().z; + const float NDCToImageScale = viewportSizeX * 0.5; + + return modelWidth * modelToEyeScale * eyeToNDCScale * NDCToImageScale; +} + +void main(void) +{ + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + vec4 point = vec4(HdGet_points().xyz, 1); + + outData.Peye = vec4(GetWorldToViewMatrix() * transform * point); + + ProcessPrimvarsIn(); + + gl_Position = vec4(GetProjectionMatrix() * outData.Peye); + ApplyClipPlanes(outData.Peye); + + float screenSpaceWidth = ComputeRasterPointSize(transform, outData.Peye.z); + gl_PointSize = clamp(screenSpaceWidth, + HD_GL_POINT_SIZE_MIN, HD_GL_POINT_SIZE_MAX); + + ProcessPointId(GetPointId()); +} + +--- -------------------------------------------------------------------------- +-- layout Point.Fragment + +[ + ["in block", "VertexData", "inData", + ["vec4", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Point.Fragment + +void main(void) +{ + vec3 Peye = inData.Peye.xyz / inData.Peye.w; + // camera facing. + vec3 Neye = vec3(0, 0, 1); + + vec4 color = vec4(0.5, 0.5, 0.5, 1); +#ifdef HD_HAS_displayColor + color.rgb = HdGet_displayColor().rgb; +#endif +#ifdef HD_HAS_displayOpacity + color.a = HdGet_displayOpacity(); +#endif + + vec4 patchCoord = vec4(0); + color = ShadingTerminal(vec4(Peye, 1), Neye, color, patchCoord); + +#ifdef HD_MATERIAL_TAG_MASKED + if (ShouldDiscardByAlpha(color)) { + discard; + } +#endif + + RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); +} diff --git a/Sources/HdSt/shaders/ptexTexture.glslfx b/Sources/HdSt/shaders/ptexTexture.glslfx new file mode 100644 index 0000000000..339228f845 --- /dev/null +++ b/Sources/HdSt/shaders/ptexTexture.glslfx @@ -0,0 +1,371 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "ptexTextureSampler" : { + "source": [ + "PtexTextureSampler" + ] + } + } + } +} + +-- glsl PtexTextureSampler + +// ----- following code comes from OpenSubdiv/examples/common + +struct PtexPacking { + int page; + int nMipmap; + int uOffset; + int vOffset; + int adjSizeDiffs[4]; + int width; + int height; +}; + +int computeMipmapOffsetU(int w, int level) +{ + int width = 1 << w; + int m = (0x55555555 & (width | (width-1))) << (w&1); + int x = ~((1 << (w -((level-1)&~1))) - 1); + return (m & x) + ((level+1)&~1); +} + +int computeMipmapOffsetV(int h, int level) +{ + int height = 1 << h; + int m = (0x55555555 & (height-1)) << ((h+1)&1);; + int x = ~((1 << (h - (level&~1))) - 1 ); + return (m & x) + (level&~1); +} + +void evalQuadraticBSpline(float u, + REF(thread,float) B0, REF(thread,float) B1, REF(thread,float) B2, + REF(thread,float) BU0, REF(thread,float) BU1, REF(thread,float) BU2) +{ + B0 = 0.5 * (u*u - 2.0*u + 1); + B1 = 0.5 + u - u*u; + B2 = 0.5 * u*u; + + BU0 = u - 1.0; + BU1 = 1 - 2 * u; + BU2 = u; +} + +PtexPacking getPtexPacking(usampler1DArray packings, int faceID, int level) +{ + const int layoutTexelsPerFace = 3; + const int stride = textureSize(packings, 0).x; + const int index = faceID * layoutTexelsPerFace; + const int layer = index / stride; + + const ivec2 packingIndex = ivec2(index - (layer * stride), layer); + + const uvec2 page = texelFetch(packings, packingIndex+ivec2(0,0), 0).xy; + const uvec2 offsets = texelFetch(packings, packingIndex+ivec2(1,0), 0).xy; + const uvec2 sizes = texelFetch(packings, packingIndex+ivec2(2,0), 0).xy; + + PtexPacking packing; + packing.page = int(page.x); + packing.nMipmap = int(page.y); + packing.uOffset = int(offsets.x); + packing.vOffset = int(offsets.y); + + const int adjSizeDiffs = int(sizes.x); + packing.adjSizeDiffs[0] = (adjSizeDiffs >> 12) & 0xf; + packing.adjSizeDiffs[1] = (adjSizeDiffs >> 8) & 0xf; + packing.adjSizeDiffs[2] = (adjSizeDiffs >> 4) & 0xf; + packing.adjSizeDiffs[3] = (adjSizeDiffs >> 0) & 0xf; + + const int wh = int(sizes.y); + const int w = wh >> 8; + const int h = wh & 0xff; + + // clamp max level + level = min(level, packing.nMipmap); + + packing.width = 1 << (w-level); + packing.height = 1 << (h-level); + + if (level > 0) { + packing.uOffset += computeMipmapOffsetU(w, level); + packing.vOffset += computeMipmapOffsetV(h, level); + } + + return packing; +} + +// ---------------------------------------------------------------------------- +// Non-Mipmap Lookups +// ---------------------------------------------------------------------------- + +vec4 PtexLookupNearest(vec4 patchCoord, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, 0); + vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset, + uv.y * ppack.height + ppack.vOffset); + return texelFetch(data, ivec3(int(coords.x), int(coords.y), ppack.page), 0); +} + +vec4 PtexLookupNearest(vec4 patchCoord, + int level, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, level); + vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset, + uv.y * ppack.height + ppack.vOffset); + return texelFetch(data, ivec3(int(coords.x), int(coords.y), ppack.page), 0); +} + +vec4 PtexLookupFast(vec4 patchCoord, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, 0); + + ivec3 size = textureSize(data, 0); + vec2 coords = vec2((uv.x * ppack.width + ppack.uOffset)/size.x, + (uv.y * ppack.height + ppack.vOffset)/size.y); + return texture(data, vec3(coords.x, coords.y, ppack.page)); +} + +vec4 PtexLookupFast(vec4 patchCoord, + int level, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, level); + + ivec3 size = textureSize(data, 0); + vec2 coords = vec2((uv.x * ppack.width + ppack.uOffset)/size.x, + (uv.y * ppack.height + ppack.vOffset)/size.y); + return texture(data, vec3(coords.x, coords.y, ppack.page)); +} + +vec4 PtexLookup(vec4 patchCoord, + int level, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, level); + + vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset, + uv.y * ppack.height + ppack.vOffset); + + coords -= vec2(0.5, 0.5); + + int c0X = int(floor(coords.x)); + int c1X = int(ceil(coords.x)); + int c0Y = int(floor(coords.y)); + int c1Y = int(ceil(coords.y)); + + float t = coords.x - float(c0X); + float s = coords.y - float(c0Y); + + vec4 d0 = texelFetch(data, ivec3(c0X, c0Y, ppack.page), 0); + vec4 d1 = texelFetch(data, ivec3(c0X, c1Y, ppack.page), 0); + vec4 d2 = texelFetch(data, ivec3(c1X, c0Y, ppack.page), 0); + vec4 d3 = texelFetch(data, ivec3(c1X, c1Y, ppack.page), 0); + + vec4 result = (1-t) * ((1-s)*d0 + s*d1) + t * ((1-s)*d2 + s*d3); + + return result; +} + +vec4 PtexLookupQuadratic(REF(thread, vec4) du, + REF(thread, vec4) dv, + vec4 patchCoord, + int level, + sampler2DArray data, + usampler1DArray packings) +{ + vec2 uv = clamp(patchCoord.xy, vec2(0), vec2(1)); + int faceID = int(patchCoord.w); + PtexPacking ppack = getPtexPacking(packings, faceID, level); + + vec2 coords = vec2(uv.x * ppack.width + ppack.uOffset, + uv.y * ppack.height + ppack.vOffset); + + coords -= vec2(0.5, 0.5); + + int cX = int(round(coords.x)); + int cY = int(round(coords.y)); + + float x = 0.5 - (float(cX) - coords.x); + float y = 0.5 - (float(cY) - coords.y); + + vec4 d[9]; + d[0] = texelFetch(data, ivec3(cX-1, cY-1, ppack.page), 0); + d[1] = texelFetch(data, ivec3(cX-1, cY-0, ppack.page), 0); + d[2] = texelFetch(data, ivec3(cX-1, cY+1, ppack.page), 0); + d[3] = texelFetch(data, ivec3(cX-0, cY-1, ppack.page), 0); + d[4] = texelFetch(data, ivec3(cX-0, cY-0, ppack.page), 0); + d[5] = texelFetch(data, ivec3(cX-0, cY+1, ppack.page), 0); + d[6] = texelFetch(data, ivec3(cX+1, cY-1, ppack.page), 0); + d[7] = texelFetch(data, ivec3(cX+1, cY-0, ppack.page), 0); + d[8] = texelFetch(data, ivec3(cX+1, cY+1, ppack.page), 0); + + float B[3], D[3]; + vec4 BUCP[3], DUCP[3]; + BUCP[0] = vec4(0); BUCP[1] = vec4(0); BUCP[2] = vec4(0); + DUCP[0] = vec4(0); DUCP[1] = vec4(0); DUCP[2] = vec4(0); + + evalQuadraticBSpline(y, B[0], B[1], B[2], D[0], D[1], D[2]); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; j++) { + vec4 A = d[i*3+j]; + BUCP[i] += A * B[j]; + DUCP[i] += A * D[j]; + } + } + + evalQuadraticBSpline(x, B[0], B[1], B[2], D[0], D[1], D[2]); + + vec4 result = vec4(0); + du = vec4(0); + dv = vec4(0); + for (int i = 0; i < 3; ++i) { + result += B[i] * BUCP[i]; + du += D[i] * BUCP[i]; + dv += B[i] * DUCP[i]; + } + + du *= ppack.width; + dv *= ppack.height; + + return result; +} + +// ---------------------------------------------------------------------------- +// MipMap Lookups +// ---------------------------------------------------------------------------- +vec4 PtexMipmapLookupNearest(vec4 patchCoord, + float level, + sampler2DArray data, + usampler1DArray packings) +{ +#if defined(SEAMLESS_MIPMAP) + // diff level + int faceID = int(patchCoord.w); + vec2 uv = patchCoord.xy; + PtexPacking packing = getPtexPacking(packings, faceID); + level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x), + mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x), + uv.y); +#endif + + int levelm = int(floor(level)); + int levelp = int(ceil(level)); + float t = level - float(levelm); + + vec4 result = (1-t) * PtexLookupNearest(patchCoord, levelm, data, packings) + + t * PtexLookupNearest(patchCoord, levelp, data, packings); + return result; +} + + +vec4 PtexMipmapLookup(vec4 patchCoord, + float level, + sampler2DArray data, + usampler1DArray packings) +{ +#if defined(SEAMLESS_MIPMAP) + // diff level + int faceID = int(patchCoord.w); + vec2 uv = patchCoord.xy; + PtexPacking packing = getPtexPacking(packings, faceID); + level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x), + mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x), + uv.y); +#endif + + int levelm = int(floor(level)); + int levelp = int(ceil(level)); + float t = level - float(levelm); + + vec4 result = (1-t) * PtexLookup(patchCoord, levelm, data, packings) + + t * PtexLookup(patchCoord, levelp, data, packings); + return result; +} + +vec4 PtexMipmapLookupQuadratic(REF(thread, vec4) du, + REF(thread, vec4) dv, + vec4 patchCoord, + float level, + sampler2DArray data, + usampler1DArray packings) +{ +#if defined(SEAMLESS_MIPMAP) + // diff level + int faceID = int(patchCoord.w); + vec2 uv = patchCoord.xy; + PtexPacking packing = getPtexPacking(packings, faceID); + level += mix(mix(packing.adjSizeDiffs[0], packing.adjSizeDiffs[1], uv.x), + mix(packing.adjSizeDiffs[3], packing.adjSizeDiffs[2], uv.x), + uv.y); +#endif + + int levelm = int(floor(level)); + int levelp = int(ceil(level)); + float t = level - float(levelm); + + vec4 du0, du1, dv0, dv1; + vec4 r0 = PtexLookupQuadratic(du0, dv0, patchCoord, levelm, data, packings); + vec4 r1 = PtexLookupQuadratic(du1, dv1, patchCoord, levelp, data, packings); + + vec4 result = mix(r0, r1, t); + du = mix(du0, du1, t); + dv = mix(dv0, dv1, t); + + return result; +} + +vec4 PtexMipmapLookupQuadratic(vec4 patchCoord, + float level, + sampler2DArray data, + usampler1DArray packings) +{ + vec4 du, dv; + return PtexMipmapLookupQuadratic(du, dv, patchCoord, level, data, packings); +} + +// end from OpenSubdiv/examples/common + +// ---------------------------------------------------------------------------- + +vec4 +PtexTextureLookup(sampler2DArray data, + usampler1DArray packings, + vec4 patchCoord) +{ + return PtexLookup(patchCoord, + /*level = */0, + data, + packings); +} + diff --git a/Sources/HdSt/shaders/renderPass.glslfx b/Sources/HdSt/shaders/renderPass.glslfx new file mode 100644 index 0000000000..95433df404 --- /dev/null +++ b/Sources/HdSt/shaders/renderPass.glslfx @@ -0,0 +1,285 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/renderPass.glslfx + +-- glsl RenderPass.Camera + +// --------------------------------------------------------------------------- +// global defines +// --------------------------------------------------------------------------- +// codeGen can override this range (currently not). +// quadro 4000's max is 189. +#ifndef HD_GL_POINT_SIZE_MAX +#define HD_GL_POINT_SIZE_MAX 100.0 +#endif +#ifndef HD_GL_POINT_SIZE_MIN +#define HD_GL_POINT_SIZE_MIN .45 +#endif + +// --------------------------------------------------------------------------- +// render pass states +// --------------------------------------------------------------------------- + +MAT4 GetWorldToViewMatrix() { +#if defined(HD_HAS_worldToViewMatrix) + return MAT4(HdGet_worldToViewMatrix()); +#else + return MAT4(1); +#endif +} +MAT4 GetWorldToViewInverseMatrix() { +#if defined(HD_HAS_worldToViewInverseMatrix) + return MAT4(HdGet_worldToViewInverseMatrix()); +#else + return MAT4(1); +#endif +} +MAT4 GetProjectionMatrix() { +#if defined(HD_HAS_projectionMatrix) + return MAT4(HdGet_projectionMatrix()); +#else + return MAT4(1); +#endif +} +vec3 GetPositionInWorldSpace(vec3 windowRelativeCoord) +{ +#if defined(HD_HAS_imageToWorldMatrix) + vec4 pImage = vec4(windowRelativeCoord, 1.0); + vec4 pWorld = vec4(HdGet_imageToWorldMatrix() * pImage); + return (pWorld / pWorld.w).xyz; +#else + return windowRelativeCoord; +#endif +} +float GetLightingBlendAmount() { +#if defined(HD_HAS_lightingBlendAmount) + return HdGet_lightingBlendAmount(); +#else + return 1; +#endif +} +vec4 GetViewport() { +#if defined(HD_HAS_viewport) + return HdGet_viewport(); +#else + return vec4(0,0,1,1); +#endif +} +float GetTessLevel() { +#if defined(HD_HAS_tessLevel) + return HdGet_tessLevel(); +#else + return 1; +#endif +} +float GetPointSize() { +#if defined(HD_HAS_pointSize) + return HdGet_pointSize(); +#else + return 3.0; +#endif +} +float GetPointSelectedSize() { +#if defined(HD_HAS_pointSelectedSize) + return HdGet_pointSelectedSize(); +#else + return 5.0; +#endif +} +vec4 GetWireframeColor() { +// Individual prims can specify an alternative wireframe color +// to one specified in the render pass. This is used in cases were +// there is not enough contrast with the normal one. +#if defined(HD_HAS_overrideWireframeColor) + return HdGet_overrideWireframeColor(); +#elif defined(HD_HAS_wireframeColor) + return HdGet_wireframeColor(); +#else + return vec4(0,0,0,0); +#endif +} +vec4 GetMaskColor() { +#if defined(HD_HAS_maskColor) + return HdGet_maskColor(); +#else + return vec4(0.5,0,0,1); +#endif +} +vec4 GetIndicatorColor() { +#if defined(HD_HAS_indicatorColor) + return HdGet_indicatorColor(); +#else + return vec4(0,0.5,0,1); +#endif +} + +bool ShouldDiscardByAlpha(vec4 color) +{ +#if defined(HD_HAS_alphaThreshold) + float alphaThreshold = HdGet_alphaThreshold(); +#else + float alphaThreshold = 0; +#endif + return (color.a < alphaThreshold); +} + +vec2 ApplyAxisAlignedAffineTransform(vec4 t, vec2 pt) +{ + return t.xy * pt + t.zw; +} + +-- glsl RenderPass.CameraFS + +vec2 HorizontallyNormalizedFilmbackCoordinates() +{ + const vec4 transform = +#ifdef HD_HAS_imageToHorizontallyNormalizedFilmback + HdGet_imageToHorizontallyNormalizedFilmback(); +#else + vec4(vec2(1.0), vec2(0.0)); +#endif + return ApplyAxisAlignedAffineTransform(transform, gl_FragCoord.xy); +} + +-- glsl RenderPass.ApplyClipPlanes + +void ApplyClipPlanes(vec4 Peye) +{ +#if defined(HD_HAS_numClipPlanes) +#if defined(HD_HAS_clipPlanes) + for (int i=0; i> 0) & 0xff) / 255.0, + ((id >> 8) & 0xff) / 255.0, + ((id >> 16) & 0xff) / 255.0, + ((id >> 24) & 0xff) / 255.0); +} + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + // Allow alpha threshold discard for ID renders regardless of material tag + if (ShouldDiscardByAlpha(color)) { + discard; + } + + int primId = HdGet_primID(); + primIdOut = IntToVec4(primId); + + // instanceIndex is a tuple of integers (num nested levels). + // for picking, we store global instanceId (instanceIndex[0]) in the + // selection framebuffer and then reconstruct the tuple in postprocess. + int instanceId = GetDrawingCoord().instanceIndex[0]; + instanceIdOut = IntToVec4(instanceId); +} diff --git a/Sources/HdSt/shaders/renderPassShader.glslfx b/Sources/HdSt/shaders/renderPassShader.glslfx new file mode 100644 index 0000000000..cae3277529 --- /dev/null +++ b/Sources/HdSt/shaders/renderPassShader.glslfx @@ -0,0 +1,50 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/renderPassShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader": { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader": { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "RenderPass.NoSelection", + "RenderPass.ApplyColorOverrides", + "RenderPass.RenderColor" ] + } + } + } +} diff --git a/Sources/HdSt/shaders/simpleLightingShader.glslfx b/Sources/HdSt/shaders/simpleLightingShader.glslfx new file mode 100644 index 0000000000..205fade32f --- /dev/null +++ b/Sources/HdSt/shaders/simpleLightingShader.glslfx @@ -0,0 +1,41 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/simpleLightingShader.glslfx + +#import $TOOLS/glf/shaders/pcfShader.glslfx +#import $TOOLS/glf/shaders/simpleLighting.glslfx + +-- configuration +{ + "techniques": { + "default": { + "fragmentShader" : { + "source": [ + "PCF.ShadowFilterFragmentOnly", + "SimpleLighting.LightIntegrator", + "SimpleLighting.SimpleLighting", + "LightingOverride.SimpleLighting" + ] + } + } + } +} + +-- glsl LightingOverride.SimpleLighting + +vec3 FallbackLighting(in vec3 Peye, in vec3 Neye, in vec3 color) +{ + return simpleLightingMaterial( + vec4(color,1), + vec4(Peye,1), + Neye, + vec4(1)).rgb; +} diff --git a/Sources/HdSt/shaders/surfaceHelpers.glslfx b/Sources/HdSt/shaders/surfaceHelpers.glslfx new file mode 100644 index 0000000000..930c22fd3c --- /dev/null +++ b/Sources/HdSt/shaders/surfaceHelpers.glslfx @@ -0,0 +1,80 @@ +-- glslfx version 0.1 + +// +// Copyright 2023 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + + + +--- -------------------------------------------------------------------------- +-- glsl SurfaceHelpers.Lighting + +#define PI 3.1415 +vec2 ProjectToLatLong(vec3 sample3D) +{ + // project spherical coord onto latitude-longitude map with + // latitude: +y == pi/2 and longitude: +z == 0, +x == pi/2 + float x = (atan(sample3D.z, sample3D.x) + 0.5 * PI) / (2.0 * PI); + float y = acos(sample3D.y) / PI; + + return vec2(x,y); +} + + +--- -------------------------------------------------------------------------- +-- glsl SurfaceHelpers.TangentSpace + +// Calculation of TBN matrix and terminology based on "Surface +// Gradient-Based Bump Mapping Framework" (2020) +mat3 +ComputeTBNMatrix(vec3 P, vec3 N, vec2 st) +{ + // Get screen space derivatives of position + vec3 dPdx = dFdx(P); + vec3 dPdy = dFdy(P); + + // Ensure position derivatives are perpendicular to N + vec3 sigmaX = dPdx - dot(dPdx, N) * N; + vec3 sigmaY = dPdy - dot(dPdy, N) * N; + + float flipSign = dot(dPdy, cross(N, dPdx)) < 0 ? -1 : 1; + + // Get screen space derivatives of st + vec2 dSTdx = dFdx(st); + vec2 dSTdy = dFdy(st); + + // Get determinant and determinant sign of st matrix + float det = dot(dSTdx, vec2(dSTdy.y, -dSTdy.x)); + float signDet = det < 0 ? -1 : 1; + + // Get first column of inv st matrix + // Don't divide by det, but scale by its sign + vec2 invC0 = signDet * vec2(dSTdy.y, -dSTdx.y); + + vec3 T = sigmaX * invC0.x + sigmaY * invC0.y; + + if (abs(det) > 0) { + T = normalize(T); + } + + vec3 B = (signDet * flipSign) * cross(N, T); + + return mat3(T, B, N); +} + +vec3 +ComputeTangentVector(vec3 P, vec3 N, vec2 st) +{ + mat3 TBN = ComputeTBNMatrix(P, N, st); + return TBN[0]; +} + +vec3 +PerturbNormal(vec3 P, vec3 N, vec2 st, vec3 Nt) +{ + mat3 TBN = ComputeTBNMatrix(P, N, st); + return normalize(TBN * Nt); +} diff --git a/Sources/HdSt/shaders/terminals.glslfx b/Sources/HdSt/shaders/terminals.glslfx new file mode 100644 index 0000000000..8ceea5acea --- /dev/null +++ b/Sources/HdSt/shaders/terminals.glslfx @@ -0,0 +1,455 @@ +-- glslfx version 0.1 + +// +// Copyright 2017 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/terminals.glslfx + +--- -------------------------------------------------------------------------- +-- glsl Geometry.CustomDisplacement + +FORWARD_DECL( + vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord)); + +vec4 DisplacementTerminal(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return displacementShader(index, Peye, Neye, patchCoord); +} + +--- -------------------------------------------------------------------------- +-- glsl Geometry.NoCustomDisplacement + +vec4 DisplacementTerminal(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return Peye; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.CommonTerminals + +struct ReprStyle +{ + vec4 color; + bool usePrimvarColor; + bool usePrimvarAlpha; + bool applyColorOverride; + bool useSurfaceShaderColor; + bool useSurfaceShaderAlpha; +}; + +struct ScalarOverride +{ + bool enabled; + vec3 color; +}; + +FORWARD_DECL(ReprStyle GetReprStyle()); +FORWARD_DECL(ScalarOverride GetScalarOverride()); +FORWARD_DECL( + vec4 surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)); +FORWARD_DECL(vec4 postSurfaceShader(vec4 Peye, vec3 Neye, vec4 color)); + +vec4 ShadingTerminal(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + ReprStyle reprStyle = GetReprStyle(); + + // Apply scalar override. + ScalarOverride scalarOverride = GetScalarOverride(); + if (scalarOverride.enabled) { + vec4 result; + + result.rgb = scalarOverride.color; + result.a = reprStyle.usePrimvarAlpha ? color.a: reprStyle.color.a; + + vec4 colorOverride = ApplyColorOverrides(result); + result = reprStyle.applyColorOverride ? colorOverride : result; + + return result; + } + + // Draw mode can override face color + vec4 reprColor; + + reprColor.rgb = reprStyle.usePrimvarColor ? color.rgb : reprStyle.color.rgb; + reprColor.a = reprStyle.usePrimvarAlpha ? color.a : reprStyle.color.a; + + // Compute color overrides + vec4 colorOverride = ApplyColorOverrides(reprColor); + reprColor = reprStyle.applyColorOverride ? colorOverride : reprColor; + + + // Surface shading can be expensive and also can contain undesirable + // side effects (like discards). So only run it for reprs that require it. + + if (reprStyle.useSurfaceShaderColor || + reprStyle.useSurfaceShaderAlpha) { + vec4 shadingColor; + + shadingColor = surfaceShader(Peye, + Neye, + reprColor, + patchCoord); + +#ifdef HD_HAS_postSurfaceShader + shadingColor = postSurfaceShader(Peye, + Neye, + shadingColor); +#endif + + reprColor.rgb = reprStyle.useSurfaceShaderColor ? + shadingColor.rgb : + reprColor.rgb; + + reprColor.a = reprStyle.useSurfaceShaderAlpha ? + shadingColor.a : + reprColor.a; + } + + vec4 baseColor = color; + baseColor = ApplyColorOverrides(baseColor); + + vec4 litColor = mix(baseColor, + reprColor, + GetLightingBlendAmount()); + + // Final overrides. + + return ApplyColorOverridesPostLighting(litColor); +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.Surface + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsDefault(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + ReprStyle reprStyle; + + reprStyle.color = vec4(0.0, 0.0, 0.0, 1.0); + reprStyle.usePrimvarColor = true; + reprStyle.usePrimvarAlpha = true; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = true; + reprStyle.useSurfaceShaderAlpha = true; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.SurfaceUnlit + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + ReprStyle reprStyle; + + reprStyle.color = vec4(0.0, 0.0, 0.0, 1.0); + reprStyle.usePrimvarColor = true; + reprStyle.usePrimvarAlpha = true; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = true; + reprStyle.useSurfaceShaderAlpha = true; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.SurfaceSheer + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + // shade only every 2nd pixel in x and y + // creating a thin stippled mesh grid + float factor = step(0.5, fract((gl_FragCoord.x + 1.0) * 0.5)) + * step(0.5, fract((gl_FragCoord.y + 0.0) * 0.5)); + + // make the surface translucent so that the lines of + // the mesh edges are visible even from the back faces. + float alpha = 0.2 * (1.0 - factor); + + + ReprStyle reprStyle; + + reprStyle.color = vec4(0.0, 0.0, 0.0, alpha); + reprStyle.usePrimvarColor = true; + reprStyle.usePrimvarAlpha = false; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = true; + reprStyle.useSurfaceShaderAlpha = false; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.SurfaceOutline + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + ReprStyle reprStyle; + + reprStyle.color = vec4(0.0, 0.0, 0.0, 1.0); + reprStyle.usePrimvarColor = false; + reprStyle.usePrimvarAlpha = false; + reprStyle.applyColorOverride = false; + reprStyle.useSurfaceShaderColor = false; + reprStyle.useSurfaceShaderAlpha = false; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.ConstantColor + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + ReprStyle reprStyle; + + reprStyle.color = vec4(0.0, 0.0, 0.0, 1.0); + reprStyle.usePrimvarColor = true; + reprStyle.usePrimvarAlpha = true; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = false; + reprStyle.useSurfaceShaderAlpha = false; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.HullColor + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + vec4 hullColor = vec4(vec3(0.18), 1.0); + +#if defined(HD_HAS_selectedWeight) + float weight = clamp(HdGet_selectedWeight(), 0.0, 1.0); + + if (weight <= 0.0) { + discard; + } + + // The three control points of the quadratic curve for the selection color + // with the binomial coefficient premultiplied in. + // constant : 1 + // linear : 1 1 + // quadratic : 1 2 1 + vec3 c0 = vec3(0.0, 0.0, 0.0); // 1.0 * Black + vec3 c1 = vec3(2.0, 0.0, 0.0); // 2.0 * Red + vec3 c2 = vec3(1.0, 1.0, 0.0); // 1.0 * Yellow + + // de Casteljau quadratic curve interpolation + // A recursive application of lerp ('mix' in glsl) reducing the order each + // step of the recursion. + // at weight = 0.0 we get c0 + // at weight = 0.5 we get c0 * .25 + c1 * 0.5 + c2 *.25 + // at weight = 1.0 we get c2 + // Thus it is a smooth curve going from c0 to c2 bending towards c1 + hullColor.rgb = mix(mix(c0, c1, weight), + mix(c1, c2, weight), weight); + +#else +#if defined(HD_HAS_hullColor) + hullColor.rgb = HdGet_hullColor(); +#endif +#if defined(HD_HAS_hullOpacity) + hullColor.a = HdGet_hullOpacity(); +#endif +#endif + + ReprStyle reprStyle; + + reprStyle.color = hullColor; + reprStyle.usePrimvarColor = false; + reprStyle.usePrimvarAlpha = false; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = false; + reprStyle.useSurfaceShaderAlpha = false; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.PointColor + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights + +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) +{ + return integrateLightsConstant(Peye, Neye, props); +} + +#endif // HD_HAS_definedIntegrateLights +#endif + +ReprStyle GetReprStyle() +{ + vec4 pointColor = vec4(vec3(0.18), 1.0); +#if defined(HD_HAS_pointColor) + pointColor = HdGet_pointColor(); +#endif + + ReprStyle reprStyle; + + reprStyle.color = pointColor; + reprStyle.usePrimvarColor = false; + reprStyle.usePrimvarAlpha = false; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = false; + reprStyle.useSurfaceShaderAlpha = false; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.PointShaded + +ReprStyle GetReprStyle() +{ + vec4 pointColor = vec4(vec3(0.18), 1.0); +#if defined(HD_HAS_pointColor) + pointColor = HdGet_pointColor(); +#endif + + ReprStyle reprStyle; + + reprStyle.color = pointColor; + reprStyle.usePrimvarColor = false; + reprStyle.usePrimvarAlpha = false; + reprStyle.applyColorOverride = true; + reprStyle.useSurfaceShaderColor = true; + reprStyle.useSurfaceShaderAlpha = true; + + return reprStyle; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.ScalarOverride + +ScalarOverride GetScalarOverride() +{ + ScalarOverride result; + +#if defined(HD_HAS_scalarOverride) + result.enabled = true; + + // Allow a scalar value to override the color from the surface + // for previewing heatmaps. This is useful for editing workflows. +#if defined(HD_HAS_scalarOverrideColorRamp) + int rampCount = constantPrimvars[GetDrawingCoord().constantCoord]. + scalarOverrideColorRamp.length(); + float scalar = HdGet_scalarOverride() * float(rampCount - 1); + float baseIndex = floor(scalar); + float nextIndex = min(float(rampCount - 1), baseIndex + 1.0); + float interp = scalar - baseIndex; + result.color = mix(HdGet_scalarOverrideColorRamp(int(baseIndex)).rgb, + HdGet_scalarOverrideColorRamp(int(nextIndex)).rgb, + interp); +#else + // If no ramp is given just gamma correct the scalar as greyscale. + result.color = vec3(pow(HdGet_scalarOverride(), 2.2)); +#endif // HD_HAS_scalarOverrideColorRamp + +#else // HD_HAS_scalarOverride + result.enabled = false; + result.color = vec3(0.0, 0.0, 0.0); +#endif + + return result; +} + +--- -------------------------------------------------------------------------- +-- glsl Fragment.NoScalarOverride + +ScalarOverride GetScalarOverride() +{ + ScalarOverride result; + + result.enabled = false; + result.color = vec3(0.0, 0.0, 0.0); + + return result; +} diff --git a/Sources/HdSt/shaders/visibility.glslfx b/Sources/HdSt/shaders/visibility.glslfx new file mode 100644 index 0000000000..cc532107c2 --- /dev/null +++ b/Sources/HdSt/shaders/visibility.glslfx @@ -0,0 +1,80 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/visibility.glslfx + +--- -------------------------------------------------------------------------- +-- glsl Visibility.Fragment.Fallback +void DiscardBasedOnTopologicalVisibility() +{ + // Nothing to do, since there's no authored opinion. +} + +--- -------------------------------------------------------------------------- +-- glsl Visibility.Fragment.Topology + +FORWARD_DECL(int GetElementID()); // code gen + +void GetBitmaskBufferIndices( + int id, REF(thread, int) arrayIndex, REF(thread, int) bitIndex) +{ + arrayIndex = id / 32; + bitIndex = id % 32; +} + +bool IsBitSet(uint bitmask, int bitIndex) +{ + return bool(bitmask & (1 << bitIndex)); +} + +bool IsElementVisible() +{ +#if defined(HD_HAS_elementsVisibility) + // Element (face) visibility is encoded as an array of bitmasks (uint32) + // with 1 bit per authored face. + int elementId = GetElementID(); + // When rendering a mesh as points, element id doesn't make sense. Code + // gen returns -1 as a fallback for this case. + if (elementId != -1) { + int arrayIndex, bitIndex; + GetBitmaskBufferIndices(elementId, arrayIndex, bitIndex); + uint ev = HdGet_elementsVisibility(arrayIndex); + return IsBitSet(ev, bitIndex); + } +#endif + return true; +} + +FORWARD_DECL(int GetPointId()); // pointId.glslfx + +bool IsPointVisible() +{ +#if defined(HD_HAS_pointsVisibility) + // Point visibility is encoded as an array of bitmasks (uint32) with 1 bit + // per unrefined vertex. + int pointId = GetPointId(); + // When *not* rendering a mesh as points, we return -1 for the point id. + // See PointId.Fragment.Fallback + if (pointId != -1) { + int arrayIndex, bitIndex; + GetBitmaskBufferIndices(pointId, arrayIndex, bitIndex); + uint pv = HdGet_pointsVisibility(arrayIndex); + return IsBitSet(pv, bitIndex); + } +#endif + return true; +} + +void DiscardBasedOnTopologicalVisibility() +{ + if (!IsElementVisible() || !IsPointVisible()) { + discard; + } +} \ No newline at end of file diff --git a/Sources/HdSt/shaders/volume.glslfx b/Sources/HdSt/shaders/volume.glslfx new file mode 100644 index 0000000000..0823438619 --- /dev/null +++ b/Sources/HdSt/shaders/volume.glslfx @@ -0,0 +1,631 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/volume.glslfx + +#import $TOOLS/hdSt/shaders/instancing.glslfx +#import $TOOLS/hdSt/shaders/pointId.glslfx + +--- -------------------------------------------------------------------------- +-- layout Volume.Vertex + +[ + ["out block", "VertexData", "outData", + # Relying on perspectively correct interpolation. + ["vec3", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Volume.Vertex + +void main(void) +{ + // Bounding box vertex in local spce + const vec4 point = vec4(HdGet_points().xyz, 1); + + const MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + + // Bounding box vertex in eye space. + const vec4 pointEye = vec4(GetWorldToViewMatrix() * transform * point); + + outData.Peye = pointEye.xyz / pointEye.w; + + gl_Position = vec4(GetProjectionMatrix() * pointEye); + + ProcessPrimvarsIn(); +} + +--- -------------------------------------------------------------------------- +-- layout Volume.Fragment + +[ + ["in block", "VertexData", "inData", + ["vec3", "Peye"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl Volume.Fragment + +// Quality knobs, should eventually be configurable. +// +// We also might have different values for the raymarch +// integrating the pixel value and for the raymarch doing +// the lighting computation. + +const int maxNumSteps = 10000; + +// Min transmittance (ray marching stops when underrun) +const float minTransmittance = 0.002; + +// Minimal scattering amount to ray march to light +const float minScattering = 0.002; + +// Eye space to local space. +// Used frequently per ray-marching step in both volumeIntegrator +// and accumulatedTransmittance, so computed only once in main. +// +MAT4 instanceModelViewInverse; +// Eye space to volume bounding box space +mat4 eyeToBBox; +float resolvedStepSizeEye; +float resolvedStepSizeEyeLighting; +float resolvedStepSizeWorld; +float resolvedStepSizeWorldLighting; + +// Transform a point by a 4x4 matrix +vec3 +transformPoint(mat4 m, vec3 point) +{ + const vec4 result = vec4(m * vec4(point, 1.0)); + return result.xyz / result.w; +} + +#ifdef HD_SHADER_SUPPORTS_DOUBLE_PRECISION +vec3 +transformPoint(dmat4 m, vec3 point) +{ + const vec4 result = vec4(m * vec4(point, 1.0)); + return result.xyz / result.w; +} +#endif + +// Transform a direction by a 4x4 matrix +vec3 +transformDir(mat4 m, vec3 dir) +{ + const vec4 result = vec4(m * vec4(dir, 0.0)); + return result.xyz; +} + +#ifdef HD_SHADER_SUPPORTS_DOUBLE_PRECISION +vec3 +transformDir(dmat4 m, vec3 dir) +{ + const vec4 result = vec4(m * vec4(dir, 0.0)); + return result.xyz; +} +#endif + +// Compute time when a ray starting at pos with direction dir +// exits the axis-aligned box with vertices lMin and lMax. +// +// Assumes that dir.x isn't close to zero. +float +timeRayExitsBoxPreferX(vec3 pos, vec3 dir, vec3 lMin, vec3 lMax) +{ + // Compute the time when the ray exists the region + // R1 = [xMin, xMax] x [-inf,inf] x [-inf,inf]. + + // Depending on whether the the ray is going left or right, compute + // the time when the ray is intersecting the plane containing the + // left or right face of the box. + float result = (((dir.x > 0.0) ? lMax.x : lMin.x) - pos.x) / dir.x; + + // Compute the time when the ray exists the region + // R2 = [xMin, xMax] x [yMin,yMax] x [-inf,inf]. + + // We can compute the intersection where the ray left R1 as + // pos + dir * result. + // If this intersection is above or below the box, we know that there + // is an earlier intersection of the ray with the plane containing + // the top or bottom face of the box, compute that intersection time. + const float y = pos.y + dir.y * result; + if (y < lMin.y) { + result = (lMin.y - pos.y) / dir.y; + } + if (y > lMax.y) { + result = (lMax.y - pos.y) / dir.y; + } + + // Compute the time when the ray exists the region + // R3 = [xMin, xMax] x [yMin,yMax] x [zMin,zMax]. + + // Analogous procedure to above. + const float z = pos.z + dir.z * result; + if (z < lMin.z) { + result = (lMin.z - pos.z) / dir.z; + } + if (z > lMax.z) { + result = (lMax.z - pos.z) / dir.z; + } + + return result; +} + +// Compute time when a ray starting at pos with direction dir +// exits the axis-aligned box with vertices lMin and lMax. +// +// Assumes that dir is normalized. +float +timeRayExitsBox(vec3 pos, vec3 dir, vec3 lMin, vec3 lMax) +{ + // Uses timeRayExitsBoxPreferX after permuting the coordinates + // to make sure that x is not close to zero. + // + // Note that because dir has unit length, at least one of its entries + // has absolute value larger 1/2 ( (1/2)^2 + (1/2)^2 + (1/2)^2 < 1^2). + + const vec3 abs_dir = abs(dir); + if (abs_dir.x > 0.5) { + return timeRayExitsBoxPreferX( + pos , dir , lMin , lMax ); + } + if (abs_dir.y > 0.5) { + return timeRayExitsBoxPreferX( + pos.yzx, dir.yzx, lMin.yzx, lMax.yzx); + } + + return timeRayExitsBoxPreferX( + pos.zxy, dir.zxy, lMin.zxy, lMax.zxy); +} + +// Given a ray in eye space starting inside a volume, compute the time when it +// exists the volume (assuming rayDirectionEye is normalized). +float +timeRayExitsVolume(vec3 rayStartEye, vec3 rayDirectionEye) +{ + // Transform ray to volume bounding box space + const vec3 rayStartBBox = transformPoint(eyeToBBox, rayStartEye); + const vec3 rayDirectionBBox = transformDir (eyeToBBox, rayDirectionEye); + + // Compute when ray is leaving the volume bounding box + return timeRayExitsBox(rayStartBBox, + rayDirectionBBox, + vec3(HdGet_volumeBBoxLocalMin().xyz), + vec3(HdGet_volumeBBoxLocalMax().xyz)); + +} + +// Given a ray in eye space, compute the time when it entered the volume +// (assuming rayDirectionEye is normalized). +// Note that it is assumed that the ray point is in the volume and that the +// result will be negative. +float +timeRayEnteredVolume(vec3 rayEndEye, vec3 rayDirectionEye) +{ + // Compute when reversed ray is exiting the volume bounding box + return - timeRayExitsVolume(rayEndEye, -rayDirectionEye); +} + +vec3 +coordsToLocalVolumeSpace(vec3 coords) +{ + return transformPoint(instanceModelViewInverse, coords); +} + +#if NUM_LIGHTS == 0 + +vec3 +lightingComputation(vec3 rayPointEye, vec3 rayDirectionEye) +{ + return vec3(0.0); +} + +#else + +// Compute how the transmittance of volume from Peye to a +// light source in the given direction rayDirection. +// This integrates the density from Peye to the boundary of +// the volume. The assumption is that the light source is +// out of the volume. +float +accumulatedTransmittance(vec3 rayStartEye, vec3 rayDirectionEye) +{ + int i = 1; + + float totalExtinction = 0.0; + + const vec3 rayStepEye = resolvedStepSizeEyeLighting * rayDirectionEye; + + const float rayLength = timeRayExitsVolume(rayStartEye, rayDirectionEye); + + const int numSteps = + int(floor(min(float(maxNumSteps), + rayLength / resolvedStepSizeEyeLighting))); + + while(i < numSteps) { + const vec3 rayPointEye = rayStartEye + i * rayStepEye; + + totalExtinction += extinctionFunction(rayPointEye); + + i+=1; + } + + return exp(-totalExtinction * resolvedStepSizeWorldLighting); +} + +// Computes amount of light arriving at point Peye +// taking attenuation (e.g., by inverse-square law), shadows, +// transmittance by volume into account. +vec3 +lightingComputation(vec3 rayPointEye, vec3 rayDirectionEye) +{ + vec3 result = vec3(0.0); + for (int i = 0; i < NUM_LIGHTS; ++i) { + LightSource light = GetLightSource(i); + + const vec4 Plight = light.position; + + const vec3 lightDirectionEye = normalize( + (Plight.w == 0.0) ? Plight.xyz : Plight.xyz - rayPointEye); + + const float atten = + lightDistanceAttenuation(vec4(rayPointEye,1), i) * + lightSpotAttenuation(lightDirectionEye, i); + +// For now, not using shadows for volumes. +#if USE_SHADOWS && 0 + const float shadow = light.hasShadow ? + shadowing(/*lightIndex=*/i, rayPointEye) : 1.0; +#else + const float shadow = 1.0; +#endif + + if (shadow > 0.0001) { + result += + shadow * + atten * + // Assuming that light source is outside of volume's + // bounding box (might integrate extinction along ray + // beyond light source). + accumulatedTransmittance(rayPointEye, lightDirectionEye) * + phaseFunction(-rayDirectionEye, lightDirectionEye) * + light.diffuse.rgb; + } + } + + return result; +} + +#endif + +// Result of integrating volume along a ray +struct VolumeContribution +{ + // Coordinates where ray marching hit the first non-empty voxel + // in eye space. 0 indicates the ray hit only empty voxels. + vec3 firstHitPeye; + + // Integrated color + vec3 color; + + // Integrated transmittance, i.e., what fraction of light from + // geometry behind the volume is still visible. + float transmittance; +}; + +VolumeContribution +volumeIntegrator(vec3 rayStartEye, vec3 rayDirectionEye, float rayLength) +{ + int i = 1; + + VolumeContribution result; + result.firstHitPeye = vec3(0.0); + result.color = vec3(0.0); + result.transmittance = 1.0; + + const vec3 rayStepEye = resolvedStepSizeEye * rayDirectionEye; + + const int numSteps = + int(floor(min(float(maxNumSteps), rayLength / resolvedStepSizeEye))); + + // integrate transmittance and light along ray for bounding box + while(i < numSteps) { + const vec3 rayPointEye = rayStartEye + i * rayStepEye; + + // Evaluate volume shader functions to determine extinction, + // scattering, and emission. + const float extinctionValue = extinctionFunction(rayPointEye); + const float scatteringValue = scatteringFunction(rayPointEye); + const vec3 emissionValue = emissionFunction(rayPointEye); + + // If this is the first time the ray is hitting a non-empty voxel, + // record the coordinates. + if (all(equal(result.firstHitPeye, vec3(0.0)))) { + if ( extinctionValue > 0 || + scatteringValue > 0 || + any(greaterThan(emissionValue, vec3(0)))) { + result.firstHitPeye = rayPointEye; + } + } + + // In scattering contribution, lighting only computed if scattering + // is non-trivial. + const vec3 inScattering = + (resolvedStepSizeWorld * scatteringValue >= minScattering) ? + (scatteringValue * + lightingComputation(rayPointEye, rayDirectionEye)) + : vec3(0.0); + + // In scattering and emission contribution + result.color += + (resolvedStepSizeWorld * result.transmittance) * + (inScattering + emissionValue); + + // Update transmittance + result.transmittance *= exp(-extinctionValue * resolvedStepSizeWorld); + + // Stop when the volume has become close to opaque. + if (result.transmittance < minTransmittance) { + break; + } + + i+=1; + } + + return result; +} + +// Is camera orthographic? +bool +isCameraOrthographic() +{ + return abs(GetProjectionMatrix()[3][3] - 1.0) < 1e-5; +} + +// Convert depth value z in [-1,1] to depth in eye space [-near, -far]. +float +NDCtoEyeZ(float z) +{ + const MAT4 m = inverse(GetProjectionMatrix()); + return float((m[2][2] * z + m[3][2]) / (m[2][3] * z + m[3][3])); +} + +// Compute the z-value of the near clipping plane in eye space. +float +computeNearZ() +{ +#ifdef HD_MINUS_ONE_TO_ONE_DEPTH_RANGE + return NDCtoEyeZ(-1.0); +#else + return NDCtoEyeZ(0.0); +#endif +} + +// Compute the near clipping distance. Always returns a positive value. +float +computeNearDistance() +{ + return abs(computeNearZ()); +} + +// Consider the ray from the eye to a given point in eye space. +// Computes the direction of this ray in both cases where the +// camera is orthographic or perspective. +vec3 +computeRayDirectionEye(vec3 rayPointEye) +{ + // In NDC space, the ray is always pointing into the z-direction (0,0,1). + // In clip space, this corresponds to (0,0,1,0). + // We need to multiply (0,0,1,0) by the inverse projection matrix to + // get to homogeneous eye space. + // Or alternatively, we can get the direction in homogeneous eye space + // by taking the respective column of the inverse projection matrix: + const vec4 dir = vec4(inverse(GetProjectionMatrix())[2]); + + // To compute the corresponding direction in non-homogeneous eye space, + // compute the position of the ray after time dt << 1: + // vec4 pHomogeneous = vec4(rayPointEye, 1.0) + dt * dir; + // vec3 p = pHomogeneous.xyz / pHomogeneous.w; + // + // Or equivalently: + // vec3 p = (rayPointEye + dt * dir.xyz) / (1.0 + dir.w * dt); + // And since dt << 1, we have + // vec3 p = (rayPointEye + dt * dir.xyz) * (1.0 - dir.w * dt); + // And dropping higher order terms: + // vec3 p = rayPointEye + dt * (dir.xyz - rayPointEye * dir.w); + // So the new direction is given by: + // vec3 d = dir.xyz - rayPointEye * dir.w; + + // Normalize direction in eye space. + return normalize(dir.xyz - rayPointEye * dir.w); +} + +// Given where the ray is about to leave the volume, compute where we +// should start ray marching: this is either the point where the ray +// would have entered the volume or the intersection with the near +// clipping plane or a sphere about the eye (in the perspective case). +// +vec3 +computeRayStartEye(vec3 rayEndEye, vec3 rayDirectionEye) +{ + // Time where ray would have entered volume (negative). + const float startTime = timeRayEnteredVolume(rayEndEye, rayDirectionEye); + + if (isCameraOrthographic()) { + // Time where ray would have intersected near plane + const float nearTime = + (computeNearZ() - rayEndEye.z) + / rayDirectionEye.z; + // Take the latter of the two times for getting the start point + return rayEndEye + max(startTime, nearTime) * rayDirectionEye; + } + + // Note that we intersect the ray with sphere about the eye with + // radius equal to the near distance in the perspective case rather + // than just the above intersection with the near plane. + // + // The motivation is that the distance between the eye and the + // near plane is non-constant across the image. Thus, ray-marching + // would skip more volume away from the center of the image making + // the image darker there - so we see opposite vignetting. To + // avoid this bias, we use a sphere about the eye. + // + // Note that we can use points in front of the near plane + // since OIT resolution makes no assumptions about the + // depth value. + // + + // Compute point where ray would have entered volume + const vec3 rayStartEye = rayEndEye + startTime * rayDirectionEye; + // If this point is behind the eye or in the sphere about the eye, ... + if (rayStartEye.z > 0.0 || length(rayStartEye) < computeNearDistance()) { + // ... use point on sphere. + return normalize(rayDirectionEye) * computeNearDistance(); + } + + return rayStartEye; +} + +// The depth at which we hit opaque geometry in eye space (negative +// value by OpenGL convention). +float +sampleZBuffer(vec2 fragcoord) +{ +#ifdef HD_HAS_depthReadback + // Sample the z-Buffer at the frag coordinate. + const float bufferVal = texelFetch(HdGetSampler_depthReadback(), + ivec2(fragcoord), + /* lod = */ 0).x; +#else + // Assume far-plane if we cannot sample the z-Buffer. + const float bufferVal = 1.0; +#endif + +#ifdef HD_MINUS_ONE_TO_ONE_DEPTH_RANGE + // Convert from [0, 1] to [-1, 1] to if necessary + return NDCtoEyeZ(2.0 * bufferVal - 1.0); +#else + return NDCtoEyeZ(bufferVal); +#endif +} + +// Compute how much length we need to ray march. +// +// The ray is encoded through it start point and direction. Its end will be +// determined from two things: +// - the eye space coordinates of this fragment which is part of the back-faces +// of the volume. +// - the z-Value of the opaque geometry (since we want to stop raymarching +// once the ray has hit opaque geometry) +float +computeRayLength(vec3 rayStartEye, vec3 rayDirectionEye, vec3 rayEndEye, + float opaqueZ) +{ + // Recall that the camera is looking down the minus z-direction by + // OpenGL conventions so we need to take the max to get the closer + // point. + const float rayEndZ = max(opaqueZ, rayEndEye.z); + return (rayEndZ - rayStartEye.z) / rayDirectionEye.z; +} + +float +computeMax3(float a, float b, float c) +{ + return max(a, max(b, c)); +} + +// Computes the inverse of the scaling of an affine transform. +// Approximately - since most transforms have uniform scaling +// and no shear, this is fine. +float +scaleOfMatrix(MAT4 m) +{ + // Take the maximum of the lengths of the images of the x, y + // and z vector. + // + // A more general, coordinate independent implementation would take + // the minimum singular value from the singular value decomposition. + // + const mat3 affinePart = mat3(m[0][0], m[0][1], m[0][2], + m[1][0], m[1][1], m[1][2], + m[2][0], m[2][1], m[2][2]); + return computeMax3(length(affinePart[0]), + length(affinePart[1]), + length(affinePart[2])); +} + +#ifdef HD_HAS_integrateLights +#ifndef HD_HAS_definedIntegrateLights +#define HD_HAS_definedIntegrateLights +LightingContribution +integrateLights(vec4 Peye, vec3 Neye, LightingInterfaceProperties props) { + return integrateLightsDefault(Peye, Neye, props); +} +#endif +#endif + +void main(void) +{ + instanceModelViewInverse = + ApplyInstanceTransformInverse(HdGet_transformInverse()) * + GetWorldToViewInverseMatrix(); + + eyeToBBox = mat4( + MAT4(HdGet_volumeBBoxInverseTransform()) * instanceModelViewInverse); + + ProcessSamplingTransforms(instanceModelViewInverse); + + const float halfWorldSampleDistance = + 0.5 * float(HdGet_sampleDistance()) + / scaleOfMatrix(instanceModelViewInverse); + + const float viewScale = scaleOfMatrix(GetWorldToViewInverseMatrix()); + + resolvedStepSizeEye = + HdGet_stepSize() * halfWorldSampleDistance; + resolvedStepSizeWorld = + viewScale * resolvedStepSizeEye; + resolvedStepSizeEyeLighting = + HdGet_stepSizeLighting() * halfWorldSampleDistance; + resolvedStepSizeWorldLighting = + viewScale * resolvedStepSizeEyeLighting; + + // Discard front faces - ray marching stops at fragment eye position + // and starts at the intersection of ray with volume bounding box or + // near plane. + if (gl_FrontFacing != (determinant(instanceModelViewInverse) < 0.0)) { + discard; + } + + // camera facing. + const vec3 Neye = vec3(0, 0, 1); + + // compute ray for ray marching + const vec3 rayDirectionEye = computeRayDirectionEye(inData.Peye); + const vec3 rayStartEye = computeRayStartEye(inData.Peye, rayDirectionEye); + + // Use z-value from depth buffer to compute length for ray marching + const float opaqueZ = sampleZBuffer(gl_FragCoord.xy); + const float rayLength = computeRayLength( + rayStartEye, rayDirectionEye, inData.Peye, opaqueZ); + + const VolumeContribution volumeContribution = + volumeIntegrator(rayStartEye, rayDirectionEye, rayLength); + const float alpha = 1 - volumeContribution.transmittance; + const vec4 color = ApplyColorOverrides(vec4(volumeContribution.color, alpha)); + + const vec4 patchCoord = vec4(0.0); + + RenderOutput(vec4(volumeContribution.firstHitPeye, 1), + Neye, color, patchCoord); +} diff --git a/Sources/HdSt/shaders/widgetShader.glslfx b/Sources/HdSt/shaders/widgetShader.glslfx new file mode 100644 index 0000000000..7c9871acc5 --- /dev/null +++ b/Sources/HdSt/shaders/widgetShader.glslfx @@ -0,0 +1,66 @@ +-- glslfx version 0.1 + +// +// Copyright 2021 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/widgetShader.glslfx + +--- +--- The fallback widget shader is used as a replacement shader if the +--- original material shader failed to compile. It needs to +--- define both the surfaceShader() and displacementShader() terminals. +--- +-- configuration +{ + "techniques": { + "default": { + "displacementShader": { + "source": [ "Widget.Displacement" ] + }, + "surfaceShader": { + "source": [ "Widget.Surface" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- glsl Widget.Surface + +vec4 surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + float d = 1.0; + vec4 bg = vec4(0,0,0,1); + +#ifdef HD_HAS_depthReadback + d = texelFetch(HdGetSampler_depthReadback(), ivec2(gl_FragCoord.xy), + 0).x; +#endif + +#ifdef HD_HAS_colorReadback + bg = texelFetch(HdGetSampler_colorReadback(), ivec2(gl_FragCoord.xy), + 0); +#endif + + vec4 colorOut = color; + if (d <= gl_FragCoord.z) { + const float showThroughAlpha = 0.3; + float adjAlpha = showThroughAlpha * color.a; + colorOut.rgb = color.rgb*adjAlpha + bg.rgb*bg.a*(1-adjAlpha); + colorOut.a = adjAlpha + bg.a*(1.0-adjAlpha); + } + + return colorOut; +} +--- -------------------------------------------------------------------------- +-- glsl Widget.Displacement + +vec4 displacementShader(int index, vec4 Peye, vec3 Neye, vec4 patchCoord) +{ + return Peye; +} diff --git a/Sources/HdSt/tetMeshConversionSceneIndexPlugin.cpp b/Sources/HdSt/tetMeshConversionSceneIndexPlugin.cpp index fb10c46996..9261ffb0cf 100644 --- a/Sources/HdSt/tetMeshConversionSceneIndexPlugin.cpp +++ b/Sources/HdSt/tetMeshConversionSceneIndexPlugin.cpp @@ -9,7 +9,7 @@ #include "Hd/retainedDataSource.h" #include "Hd/sceneIndexPluginRegistry.h" #include "Hd/tokens.h" -#include "Hdsi/tetMeshConversionSceneIndex.h" +#include "HdSi/tetMeshConversionSceneIndex.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/HdSt/textures/fallbackBlackDomeLight.png b/Sources/HdSt/textures/fallbackBlackDomeLight.png new file mode 100644 index 0000000000..d4c45e520e Binary files /dev/null and b/Sources/HdSt/textures/fallbackBlackDomeLight.png differ diff --git a/Sources/HdSt/velocityMotionResolvingSceneIndexPlugin.cpp b/Sources/HdSt/velocityMotionResolvingSceneIndexPlugin.cpp index 28e15b991a..ef066f36bb 100644 --- a/Sources/HdSt/velocityMotionResolvingSceneIndexPlugin.cpp +++ b/Sources/HdSt/velocityMotionResolvingSceneIndexPlugin.cpp @@ -28,7 +28,7 @@ #include "Hd/sceneIndexObserver.h" #include "Hd/sceneIndexPlugin.h" #include "Hd/sceneIndexPluginRegistry.h" -#include "Hdsi/velocityMotionResolvingSceneIndex.h" +#include "HdSi/velocityMotionResolvingSceneIndex.h" #include "Tf/registryManager.h" #include "Tf/staticTokens.h" diff --git a/Sources/Hdx/.gitkeep b/Sources/Hdx/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/Hdx/Resources/plugInfo.json b/Sources/Hdx/Resources/plugInfo.json new file mode 100644 index 0000000000..5a61875fd9 --- /dev/null +++ b/Sources/Hdx/Resources/plugInfo.json @@ -0,0 +1,14 @@ +{ + "Plugins": [ + { + "Info": { + "ShaderResources": "shaders" + }, + "LibraryPath": "", + "Name": "Hdx", + "ResourcePath": "Contents/Resources", + "Root": "../..", + "Type": "library" + } + ] +} diff --git a/Sources/Hdx/shaders/boundingBox.glslfx b/Sources/Hdx/shaders/boundingBox.glslfx new file mode 100644 index 0000000000..417300155d --- /dev/null +++ b/Sources/Hdx/shaders/boundingBox.glslfx @@ -0,0 +1,52 @@ +-- glslfx version 0.1 + +// +// Copyright 2022 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "BoundingBoxVertex": { + "source": [ "BoundingBox.Vertex" ] + }, + "BoundingBoxFragment": { + "source": [ "BoundingBox.Fragment" ] + } + } + } +} + +-- glsl BoundingBox.Vertex + +void main(void) +{ + const vec4 clipPos = worldViewProj[hd_InstanceID] * vec4(position,1.0); + gl_Position = clipPos; + + // Write out a flat (non-interpolated) screen space position for the + // provoking vertex for a line so we can measure how far a fragment + // is from that vertex in screen space. + dashStart = (clipPos.xy/clipPos.w+vec2(1.0))*(viewport.zw/2.0)+viewport.xy; +} + +-- glsl BoundingBox.Fragment + +void main(void) +{ + // Skip any pattern styling if the uniform/constant dashSize is invalid. + if (dashSize != 0.0) { + // Otherwise create a dashed pattern with equal solid and blank pixel + // sections for the line. + const float pixelDist = distance(dashStart, gl_FragCoord.xy); + if (mod(pixelDist, 2.0*dashSize) > dashSize) { + discard; + } + } + + hd_FragColor = color; +} diff --git a/Sources/Hdx/shaders/colorChannel.glslfx b/Sources/Hdx/shaders/colorChannel.glslfx new file mode 100644 index 0000000000..43c28b393b --- /dev/null +++ b/Sources/Hdx/shaders/colorChannel.glslfx @@ -0,0 +1,53 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "ColorChannelFragment": { + "source": [ "ColorChannel.Fragment" ] + } + } + } +} + +-- glsl ColorChannel.Fragment + + +// Display channel values. These should match the the indices of the entries in +// HdxDisplayChannelTokens +#define CHANNEL_COLOR 0 +#define CHANNEL_RED 1 +#define CHANNEL_GREEN 2 +#define CHANNEL_BLUE 3 +#define CHANNEL_ALPHA 4 +#define CHANNEL_LUMINANCE 5 + +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + vec4 color = HgiTexelFetch_colorIn(ivec2(fragCoord)); + + // Display Channel + if (channel == CHANNEL_RED) { + color.g = color.b = color.r; + } else if (channel == CHANNEL_GREEN) { + color.r = color.b = color.g; + } else if (channel == CHANNEL_BLUE) { + color.r = color.g = color.b; + } else if (channel == CHANNEL_ALPHA) { + color.r = color.g = color.b = color.a; + } else if (channel == CHANNEL_LUMINANCE) { + const vec3 W = vec3(0.30, 0.59, 0.11); + color.r = color.g = color.b = dot(color.rgb, W); + } // Do nothing if channel == CHANNEL_COLOR + + hd_FragColor = color; +} diff --git a/Sources/Hdx/shaders/colorCorrection.glslfx b/Sources/Hdx/shaders/colorCorrection.glslfx new file mode 100644 index 0000000000..0a3314edc1 --- /dev/null +++ b/Sources/Hdx/shaders/colorCorrection.glslfx @@ -0,0 +1,57 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "ColorCorrectionVertex": { + "source": [ "ColorCorrection.Vertex" ] + }, + "ColorCorrectionFragment": { + "source": [ "ColorCorrection.Fragment" ] + } + } + } +} + +-- glsl ColorCorrection.Vertex + +void main(void) +{ + gl_Position = position; + uvOut = uvIn; +} + +-- glsl ColorCorrection.Fragment + +// Similar to D3DX_DXGIFormatConvert.inl, but branchless +// https://www.shadertoy.com/view/wds3zM +vec3 FloatToSRGB(vec3 val) +{ + val = mix((val * 12.92), + (1.055 * pow(val, vec3(1.0/2.4)) - 0.055), + step(0.0031308, val)); + return val; +} + +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + vec4 inCol = HgiTexelFetch_colorIn(ivec2(fragCoord)); + + #if defined(GLSLFX_USE_OCIO) + inCol = OCIO_DISPLAY_FUNC(inCol); + #else + // Only color, not alpha is gamma corrected! + inCol.rgb = FloatToSRGB(inCol.rgb); + #endif + + hd_FragColor = inCol; +} diff --git a/Sources/Hdx/shaders/fullscreen.glslfx b/Sources/Hdx/shaders/fullscreen.glslfx new file mode 100644 index 0000000000..06a9bbaf43 --- /dev/null +++ b/Sources/Hdx/shaders/fullscreen.glslfx @@ -0,0 +1,48 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "FullscreenVertex": { + "source": [ "Fullscreen.Vertex" ] + }, + "CompositeFragmentNoDepth": { + "source": [ "Composite.FragmentNoDepth" ] + }, + "CompositeFragmentWithDepth": { + "source": [ "Composite.FragmentWithDepth" ] + } + } + } +} + +-- glsl Fullscreen.Vertex + +void main(void) +{ + gl_Position = position; + uvOut = uvIn; +} + +-- glsl Composite.FragmentNoDepth + +void main(void) +{ + hd_FragColor = vec4(HgiGet_colorIn(uvOut)); +} + +-- glsl Composite.FragmentWithDepth + +void main(void) +{ + hd_FragColor = vec4(HgiGet_colorIn(uvOut)); + gl_FragDepth = HgiGet_depth(uvOut).x; +} diff --git a/Sources/Hdx/shaders/oitResolveImageShader.glslfx b/Sources/Hdx/shaders/oitResolveImageShader.glslfx new file mode 100644 index 0000000000..90e07ee976 --- /dev/null +++ b/Sources/Hdx/shaders/oitResolveImageShader.glslfx @@ -0,0 +1,93 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "fragmentShader": { + "source": [ "OitResolve.Image" ] + } + } + } +} + +--- -------------------------------------------------------------------------- +-- layout OitResolve.Image + +[ + ["buffer readWrite", "CounterBuffer", "hdxOitCounterBuffer", + ["atomic_int", "hdxOitCounterBuffer"] + ] +] + +-- glsl OitResolve.Image + +vec4 imageShader(vec2 uv) +{ +#if defined(HD_HAS_hdxOitDataBuffer) + const int screenWidth = int(HdGet_oitScreenSize().x); + const int screenHeight = int(HdGet_oitScreenSize().y); + + // Must match the per-pixel sample count used when creating the OIT buffers. + // (See HdxOitResolveTask::_PrepareOitBuffers) + const int maxSamples = 8; + + const int dataBufferSize = screenWidth * screenHeight * maxSamples; + + // +1 because index 0 of counter buffer is reserved as atomic counter in + // WriteOitLayersToBuffer + int screenIndex = int(gl_FragCoord.x) + int(gl_FragCoord.y) * screenWidth; + screenIndex += 1; + + int nodeIndex = ATOMIC_LOAD(hdxOitCounterBuffer[screenIndex]); + int numDepths = 0; + + // XXX renderPass.WriteOitLayersToBuffer does not clamp the number of + // depth samples we store for a pixel. Here we process no more than + // 'maxSamples' for a pixel. (If there are greater than 'maxSamples' + // samples stored for this pixel some will currently not contribute) + vec4 sortedColor[maxSamples]; + float sortedDepth[maxSamples]; + + while (nodeIndex != -1 && + numDepths < maxSamples && + nodeIndex < dataBufferSize) + { + float currentDepth = hdxOitDepthBuffer[nodeIndex]; + int insertIndex = numDepths; + // Recall that depths are in eye space, so inequality is flipped. + while (insertIndex > 0 && sortedDepth[insertIndex - 1] < currentDepth) { + sortedDepth[insertIndex] = sortedDepth[insertIndex - 1]; + sortedColor[insertIndex] = sortedColor[insertIndex - 1]; + insertIndex -= 1; + } + sortedColor[insertIndex] = hdxOitDataBuffer[nodeIndex]; + sortedDepth[insertIndex] = hdxOitDepthBuffer[nodeIndex]; + numDepths += 1; + nodeIndex = hdxOitIndexBuffer[nodeIndex]; + } + + // Assume color in sortedColor is pre-multiplied by alpha + int depth = 0; + vec4 colorAccum = vec4(0); + while (depth < numDepths) { + colorAccum += sortedColor[depth] * (1 - colorAccum.a); + + if (colorAccum.a >= 1.0) break; + + depth += 1; + } + + colorAccum = clamp(colorAccum, vec4(0), vec4(1)); + return colorAccum; +#else + return vec4(0); +#endif +} diff --git a/Sources/Hdx/shaders/outline.glslfx b/Sources/Hdx/shaders/outline.glslfx new file mode 100644 index 0000000000..6dd686b012 --- /dev/null +++ b/Sources/Hdx/shaders/outline.glslfx @@ -0,0 +1,138 @@ +-- glslfx version 0.1 + +// +// Copyright 2020 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "OutlineFragment": { + "source": [ "Outline.Fragment" ] + } + } + } +} + +-- glsl Outline.Fragment + +#define EPSILON 0.0001 +#define LARGE 100000 + +// The color texture with the highlighted areas. + +// Given a delta x and y in relation to the current texel coordinates, check if +// the colorIn texture has a non-black texel and its distance^2 to the current +// texel is smaller than the one passed as dist2. The color of that texel will +// be returned in the color output var. +void testTexel(int x, int y, REF(thread,float) dist2, REF(thread,vec4) color) +{ + vec2 texCoords = uvOut + vec2(x, y) * texelSize; + vec4 c = HgiGet_colorIn(texCoords); + + if ( c.r > EPSILON || c.g > EPSILON || c.b > EPSILON) { + float d = float(x * x + y * y ); + if (d < dist2) { + dist2 = d; + color = c; + } + } +} + +// Used by testOctants() to scan each horizontal line in the circle. +// Returns the distance^2 and color of the non-black texel that is closest to +// the current texel. +void testHLine(int x0, int x1, int y, REF(thread,float) dist2, REF(thread,vec4) color) { + for (int x = x0; x < x1; x++) { + testTexel(x, y, dist2, color); + } +} + +// Part of the Bresenham algorithm: mirror the circle octant edge coords to +// obtain a half circle and then mirror them horizontally to obtain the +// horizontal lines that define the circle and its interior. +// Returns the distance^2 and color of the non-black texel that is closest to +// the current texel. +void testOctants(int x, int y, REF(thread,float) dist2, REF(thread,vec4) color) { + testHLine(-x, x, y, dist2, color); + testHLine(-x, x, -y, dist2, color); + testHLine(-y, y, x, dist2, color); + testHLine(-y, y, -x, dist2, color); +} + +// Find the color and distance^2 to the closest texel in colorIn that is not +// black and that is within a circle defined by the specified radius, centered +// in the current texel. (Note: distance^2 is used to avoid sqrt). +// This uses the Bresenham circle algorithm to discover the texels inside that +// circle, to avoid having to read the colorIn texels outside of it. +void testCircle(int r, REF(thread,float) dist2, REF(thread,vec4) color) { + if (r < 0) { r = 0; } + + int d = 3 - (2 * r); + int x = 0; + int y = r; + + testOctants(x, y, dist2, color); + + while (x < y) { + x++; + + if (d > 0) { + y--; + d = d + 4 * (x - y) + 10; + } else { + d = d + 4 * x + 6; + } + + testOctants(x, y, dist2, color); + } +} + +// If radius is 0 then render colorIn as is. If radius > 0 then render only the +// outline of the non-black areas in colorIn. The radius will define the +// thickness of the outline. The color of each texel in the outline will be +// defined by the closest color in colorIn, fading out when the distance to that +// colorIn texel equals the radius. This will allow colorIn to potentially hold +// several colors that will be respected by the outline. + +void main() +{ + hd_FragColor = vec4(0, 0, 0, 1); + // Check if the current texel is not black - meaning that we are inside an + // area of colorId that has been highlighted. + vec4 color = HgiGet_colorIn(uvOut); + bool isInside = color.r > EPSILON || color.g > EPSILON || color.b > EPSILON; + + if (enableOutline==0) { + if (isInside) { + // Inside the highlighted areas in colorIn : render colorIn. + hd_FragColor = color; + } + } else { + + if (!isInside) { + // Outside the highlighted area: render the outline + float r2 = float(radius * radius); + float dist2 = LARGE; + + // Check if there are any highlighted texels around the current one + // inside the specified radius. + testCircle(radius, dist2, color); + + // Check if the distance^2 to the closest highlighted texel is within + // radius^2. + if (dist2 <= r2) { + // Attenuate the texel color using the distance^2 to it. + float factor = (r2 - dist2 ) / r2; + factor *= factor; + + hd_FragColor = color * factor; + hd_FragColor.a = 1; + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPass.glslfx b/Sources/Hdx/shaders/renderPass.glslfx new file mode 100644 index 0000000000..9b9e515f79 --- /dev/null +++ b/Sources/Hdx/shaders/renderPass.glslfx @@ -0,0 +1,395 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPass.glslfx + +--- -------------------------------------------------------------------------- + +-- layout HdxRenderPass.RenderOitOpaquePixels + +[ + ["out", "vec4", "colorOut"] +] + +-- glsl HdxRenderPass.RenderOitOpaquePixels + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + if (color.a >= 1.0) { + colorOut = vec4(color.rgb, 1); + } else { + discard; + return; + } +} + +-- layout HdxRenderPass.WriteOitLayersToBufferCommon + +[ + ["in", "early_fragment_tests"], + ["buffer readWrite", "CounterBuffer", "hdxOitCounterBuffer", + ["atomic_int", "hdxOitCounterBuffer"] + ] +] + +-- glsl HdxRenderPass.WriteOitLayersToBufferCommon + +void RenderOutputImpl(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + #if defined(HD_HAS_hdxOitDataBuffer) + + const int screenWidth = int(HdGet_oitScreenSize().x); + const int screenHeight = int(HdGet_oitScreenSize().y); + // Must match the per-pixel sample count used when creating the OIT buffers. + // (See HdxOitResolveTask::_PrepareOitBuffers) + const int numSamples = 8; + + const int dataBufferSize = screenWidth * screenHeight * numSamples; + const int counterBufferSize = screenWidth * screenHeight + 1; + + // +1 because the counter buffer is cleared with -1, but we want the + // first index to start at 0. + int writeIndex = ATOMIC_ADD(hdxOitCounterBuffer[0], 1) + 1; + + if (writeIndex < dataBufferSize) { + int screenIndex = + int(gl_FragCoord.x) + int(gl_FragCoord.y) * screenWidth; + + if (screenIndex < counterBufferSize) { + int prevIndex = + ATOMIC_EXCHANGE(hdxOitCounterBuffer[screenIndex+1], writeIndex); + hdxOitDataBuffer[writeIndex] = color; + + // Note that we have a choice here to either pick gl_FragCoord.z or + // the depth value from Peye. The former is obtained by applying + // the perspective transform and cannot be changed by a shader. + // + // We pick Peye here so that a shader has an opportunity to change + // the depth of the sample inserted into the OIT list. + // + // This is used by volumes. However, non-volume translucent + // geometry should never modify Peye value and call RenderOutput + // with the Peye value from the vertex shader so that it is + // consistent with gl_FragCoord. This is because such geometry is + // subject to a opaque pixel render pass performing a z-test + // against gl_FragCoord.z. + // + // Note there are implications of using the depth value from Peye + // instead of gl_FragCoord.z here for the subsequent OIT resolve + // shader: the depth sorting order needs to be flipped and the + // OIT resolve shader cannot compare depths in the OIT list + // against the depth buffer unless it takes the perspective + // transform into account. + hdxOitDepthBuffer[writeIndex] = Peye.z / Peye.w; + hdxOitIndexBuffer[writeIndex] = prevIndex; + } + } else { + // We may overrun the counter buffer integer and wrap back to 0 if + // we have a lot of OIT samples. + ATOMIC_ADD(hdxOitCounterBuffer[0], -1); + } + + #endif +} + +-- glsl HdxRenderPass.WriteOitLayersToBufferTranslucent + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + // There are two render passes for ordinary OIT geometry. + // Fragments with alpha >= 1.0 are handled in the first (opaque) + // render pass. + if (color.a < 1.0 && color.a >= 0.0001) { + RenderOutputImpl(Peye, Neye, color, patchCoord); + } +} + +-- glsl HdxRenderPass.WriteOitLayersToBufferVolume + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + // Unlike ordinary OIT geometry, volumes have only one render pass, + // so insert into OIT buffers even if alpha is 1. + if (any(greaterThan(color, vec4(0.0001)))) { + RenderOutputImpl(Peye, Neye, color, patchCoord); + } +} + +-- layout HdxRenderPass.RenderPick + +[ + ["out", "vec4", "primIdOut"], + ["out", "vec4", "instanceIdOut"], + ["out", "vec4", "elementIdOut"], + ["out", "vec4", "edgeIdOut"], + ["out", "vec4", "pointIdOut"], + ["out", "vec4", "neyeOut"], + ["buffer readWrite", "CounterBuffer", "PickBuffer", ["atomic_int", "PickBuffer"]] +] + +-- glsl HdxRenderPass.RenderPick + +vec4 IntToVec4(int id) +{ + return vec4(((id >> 0) & 0xff) / 255.0, + ((id >> 8) & 0xff) / 255.0, + ((id >> 16) & 0xff) / 255.0, + ((id >> 24) & 0xff) / 255.0); +} + +// Fwd declare necessary methods to determine the subprim id of a fragment. +FORWARD_DECL(int GetElementID()); // generated via codeGen +FORWARD_DECL(int GetPrimitiveEdgeId()); // defined in edgeId.glslfx, or generated via codeGen +FORWARD_DECL(int GetPointId()); // defined in pointId.glslfx + +// Declared below. +#if defined(HD_HAS_PickBuffer) +FORWARD_DECL(void RenderDeepPicks(int primId, int instanceId, int elementId, int edgeId, int pointId)); +#endif + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + int primId = HdGet_primID(); + primIdOut = IntToVec4(primId); + + // instanceIndex is a tuple of integers (num nested levels). + // for picking, we store global instanceId (instanceIndex[0]) in the + // selection framebuffer and then reconstruct the tuple in postprocess. + int instanceId = GetDrawingCoord().instanceIndex[0]; + instanceIdOut = IntToVec4(instanceId); + + int elementId = GetElementID(); + int edgeId = GetPrimitiveEdgeId(); + int pointId = GetPointId(); + + elementIdOut = IntToVec4(elementId); + edgeIdOut = IntToVec4(edgeId); + pointIdOut = IntToVec4(pointId); + + neyeOut = IntToVec4(hd_vec4_2_10_10_10_set(vec4(Neye,0))); + +#if defined(HD_HAS_PickBuffer) + RenderDeepPicks(primId, instanceId, elementId, edgeId, pointId); +#endif +} + +#if defined(HD_HAS_PickBuffer) +int cantor(int a, int b) { + return (a + b + 1) * (a + b) / 2 + b; +} + +// Uses cantor pairing to compute a hash value for a-b-c. +int hash3(int a, int b, int c) { + return cantor(a, cantor(b, c)); +} + +bool +compareOrSet( + const int valueOffset, + const int primId, + const int instanceId, + const int partId) +{ + int primIdOffset = valueOffset; + int instanceIdOffset = valueOffset + 1; + int partIdOffset = valueOffset + 2; + + int primIdValue = ATOMIC_LOAD(PickBuffer[primIdOffset]); + int instanceIdValue = ATOMIC_LOAD(PickBuffer[instanceIdOffset]); + int partIdValue = ATOMIC_LOAD(PickBuffer[partIdOffset]); + + // Check if the slot is in use. + // if all the values are initialized, just compare + if ((primIdValue != -9) && + (instanceIdValue != -9) && + (partIdValue != -9)) { + return (primId == primIdValue) && + (instanceId == instanceIdValue) && + (partId == partIdValue); + } else { + + // Potentially available slot, store the values and return true if successful. + int expected = -9; + primIdValue = ATOMIC_COMP_SWAP(PickBuffer[primIdOffset], expected, primId); + + // Exit if the slot was unavailable. + if (primIdValue != -9 && primIdValue != primId) + return false; + + expected = -9; + instanceIdValue = ATOMIC_COMP_SWAP(PickBuffer[instanceIdOffset], expected, instanceId); + + // Exit if the slot was unavailable. + if (instanceIdValue != -9 && instanceIdValue != instanceId) + return false; + + expected = -9; + partIdValue = ATOMIC_COMP_SWAP(PickBuffer[partIdOffset], expected, partId); + + // Exit if the slot was unavailable. + if (partIdValue != -9 && partIdValue != partId) + return false; + } + + return true; +} + +void RenderDeepPicks(int primId, int instanceId, int elementId, + int edgeId, int pointId) +{ + // add the item to the pick buffer, but only unique + + // if the pick buffer is not initialized, we are done + if (ATOMIC_LOAD(PickBuffer[0]) == 0) + return; + + // Get some constants from the Pick Buffer + // These are initialized in: HdxPickTask::_ClearPickBuffer() + // + // The first 8 entries in the PickBuffer describe the buffer layout + // [0] == The number of sub-buffers (total max hits allowed / sub-buffer size) + // The total max hits allowed is configurable on the pickContext (default = 32,000) + // [1] == The max number of hits hashed and stored per sub-buffer (value = 32) + // [2] == The TableOffset which is the first entry after this header block. (value = 8) + // The Table is a collection of fields the length of the number of sub-buffers. + // It holds the number of current hits stored per sub-buffer. + // These fields are initialized to zero and populated by this shader to track hit storage. + // [3] == The StorageOffset which is the starting point where hits are stored. + // Hit results are stored in sub-buffers. + // Each sub-buffer holds up to 32 entries each with 3 entries per hit (primId, instanceId, partId). + // [4] == Indicates if faces should be picked (value == 1 or 0) + // [5] == Indicates if edges should be picked (value == 1 or 0) + // [6] == Indicates if points should be picked (value == 1 or 0) + // [7] == Padding + // + // [TableOffset -> StorageOffset] + // The table of current entry counts in each sub-buffer (values initialized to 0) + // [StorageOffset -> End of Buffer] + // The collection of hits as a (primId, instanceId, partId) tuple. (values initialized to -9) + + const int entrySize = 3; + const int numSubBuffers = ATOMIC_LOAD(PickBuffer[0]); + const int subBufferCapacity = ATOMIC_LOAD(PickBuffer[1]); + const int tableOffset = ATOMIC_LOAD(PickBuffer[2]); + const int storageOffset = ATOMIC_LOAD(PickBuffer[3]); + const int partId = ATOMIC_LOAD(PickBuffer[4]) * elementId + + ATOMIC_LOAD(PickBuffer[5]) * edgeId + + ATOMIC_LOAD(PickBuffer[6]) * pointId; + + // compute the hash for an instance/element and assign it to a sub-buffer + const int hashValue = hash3(primId, instanceId, partId); + const int subBufferNumber = hashValue % numSubBuffers; + int bufferNumber = subBufferNumber; + + // Loop through all sub buffers to find space if we fail to find any in the designated one. + do + { + const int sizeOffset = tableOffset + bufferNumber; + const int subBufferOffset = storageOffset + bufferNumber * subBufferCapacity * entrySize; + + // loop through the item's sub-buffer to see if the item is already there + // if not, add it in atomic fashion + int entryNumber = 0; + do + { + // see if we need to add a new entry + if (entryNumber == ATOMIC_LOAD(PickBuffer[sizeOffset])) { + ATOMIC_COMP_SWAP(PickBuffer[sizeOffset], entryNumber, entryNumber + 1); + } + + // if either the item equals to the current entry or we managed to + // initialize the entry with the item's data, we are done + if (compareOrSet( + subBufferOffset + entryNumber * entrySize, + primId, instanceId, partId)) { + + // We are done. + return; + } + } // we exit out if we reach the capacity of the sub-buffer + while(++entryNumber != subBufferCapacity); + + // Get the next buffer. + bufferNumber = (bufferNumber + 1) % numSubBuffers; + } + while (bufferNumber != subBufferNumber); +} +#endif // HD_HAS_PickBuffer + +-- layout HdxRenderPass.RenderColorAndSelection + +[ + ["out", "vec4", "colorOut"], + ["out", "float", "selectedOut"] +] + +-- glsl HdxRenderPass.RenderColorAndSelection + +// Note: This mixin expects color and selected color attachments in the bound +// FBO. It writes out the computed fragment color and whether it is selected +// (as a float, so, 1.0 or 0.0). + +bool IsSelected(); // defined in selection.glslfx + +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + colorOut = color; + selectedOut = float(IsSelected()); +} + +-- layout HdxRenderPass.RenderColorWithOccludedSelection + +[ + ["out", "vec4", "colorOut"] +] + +-- glsl HdxRenderPass.RenderColorWithOccludedSelection + +// Note: This mixin expects color and selected color attachments in the bound +// FBO. The alpha component of the computed fragment color is adjusted to blend +// the existing (destination) fragment color if it is selected. + +bool +HasOccludedSelection(vec2 fragcoord) +{ +#ifdef HD_HAS_selectedReadback + const float isSelected = texelFetch(HdGetSampler_selectedReadback(), + ivec2(fragcoord), + 0).x; + return bool(isSelected); +#endif + return false; +} + +float +GetShowThroughOpacity() +{ +#ifdef HD_HAS_occludedSelectionOpacity + // Note: occludedSelectionOpacity flows in as a parameter to the selection + // setup task (HdxSelectionTask) + const float dstOpacity = HdGet_occludedSelectionOpacity(); + // adjust source alpha used to blend source and dst colors. + return 1.0 - dstOpacity; +#else + return 0.5; +#endif +} + +// Input AOV textures are provided by the task. +void RenderOutput(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord) +{ + color.rgb *= color.a; + + if (HasOccludedSelection(gl_FragCoord.xy)) { + color.a *= GetShowThroughOpacity(); + } + + colorOut = color; +} diff --git a/Sources/Hdx/shaders/renderPassColorAndSelectionShader.glslfx b/Sources/Hdx/shaders/renderPassColorAndSelectionShader.glslfx new file mode 100644 index 0000000000..c56f7ece06 --- /dev/null +++ b/Sources/Hdx/shaders/renderPassColorAndSelectionShader.glslfx @@ -0,0 +1,56 @@ +-- glslfx version 0.1 + +// +// Copyright 2020 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassColorAndSelectionShader.glslfx +// Render pass shader configuration that writes color and selection information +// (whether the fragment is selected). + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "Selection.Fragment", + "RenderPass.ApplyColorOverrides", + "HdxRenderPass.RenderColorAndSelection" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassColorShader.glslfx b/Sources/Hdx/shaders/renderPassColorShader.glslfx new file mode 100644 index 0000000000..bb05ce38ff --- /dev/null +++ b/Sources/Hdx/shaders/renderPassColorShader.glslfx @@ -0,0 +1,53 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassColorShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "RenderPass.ApplyColorOverrides", + "RenderPass.RenderColor" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassColorWithOccludedSelectionShader.glslfx b/Sources/Hdx/shaders/renderPassColorWithOccludedSelectionShader.glslfx new file mode 100644 index 0000000000..b667c7383c --- /dev/null +++ b/Sources/Hdx/shaders/renderPassColorWithOccludedSelectionShader.glslfx @@ -0,0 +1,55 @@ +-- glslfx version 0.1 + +// +// Copyright 2020 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassColorWithOccludedSelectionShader.glslfx +// Render pass shader configuration that writes color and selection information +// (whether the fragment is selected). + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "RenderPass.ApplyColorOverrides", + "HdxRenderPass.RenderColorWithOccludedSelection" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassIdShader.glslfx b/Sources/Hdx/shaders/renderPassIdShader.glslfx new file mode 100644 index 0000000000..67495226ea --- /dev/null +++ b/Sources/Hdx/shaders/renderPassIdShader.glslfx @@ -0,0 +1,51 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassIdShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "RenderPass.NoSelection", + "RenderPass.NoColorOverrides", + "RenderPass.RenderId" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassOitOpaqueShader.glslfx b/Sources/Hdx/shaders/renderPassOitOpaqueShader.glslfx new file mode 100644 index 0000000000..c688346164 --- /dev/null +++ b/Sources/Hdx/shaders/renderPassOitOpaqueShader.glslfx @@ -0,0 +1,53 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassOitOpaqueShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "RenderPass.ApplyColorOverrides", + "HdxRenderPass.RenderOitOpaquePixels" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassOitShader.glslfx b/Sources/Hdx/shaders/renderPassOitShader.glslfx new file mode 100644 index 0000000000..f4f67abf57 --- /dev/null +++ b/Sources/Hdx/shaders/renderPassOitShader.glslfx @@ -0,0 +1,54 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassOitShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "RenderPass.ApplyColorOverrides", + "HdxRenderPass.WriteOitLayersToBufferCommon", + "HdxRenderPass.WriteOitLayersToBufferTranslucent" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassOitVolumeShader.glslfx b/Sources/Hdx/shaders/renderPassOitVolumeShader.glslfx new file mode 100644 index 0000000000..37162e8ca1 --- /dev/null +++ b/Sources/Hdx/shaders/renderPassOitVolumeShader.glslfx @@ -0,0 +1,53 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassOitVolumeShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/selection.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "Selection.DecodeUtils", + "Selection.ComputeColor", + "RenderPass.ApplyColorOverrides", + "HdxRenderPass.WriteOitLayersToBufferCommon", + "HdxRenderPass.WriteOitLayersToBufferVolume" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassPickingShader.glslfx b/Sources/Hdx/shaders/renderPassPickingShader.glslfx new file mode 100644 index 0000000000..f02d97dcfc --- /dev/null +++ b/Sources/Hdx/shaders/renderPassPickingShader.glslfx @@ -0,0 +1,51 @@ +-- glslfx version 0.1 + +// +// Copyright 2019 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassPickingShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "RenderPass.NoSelection", + "RenderPass.NoColorOverrides", + "HdxRenderPass.RenderPick" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/renderPassShadowShader.glslfx b/Sources/Hdx/shaders/renderPassShadowShader.glslfx new file mode 100644 index 0000000000..967a419f3e --- /dev/null +++ b/Sources/Hdx/shaders/renderPassShadowShader.glslfx @@ -0,0 +1,51 @@ +-- glslfx version 0.1 + +// +// Copyright 2016 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/renderPassShadowShader.glslfx + +#import $TOOLS/hdSt/shaders/renderPass.glslfx +#import $TOOLS/hdx/shaders/renderPass.glslfx + +-- configuration +{ + "techniques": { + "default": { + "vertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "postTessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "postTessVertexShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "tessControlShader" : { + "source": [ "RenderPass.Camera" ] + }, + "tessEvalShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "geometryShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.ApplyClipPlanes" ] + }, + "fragmentShader" : { + "source": [ "RenderPass.Camera", + "RenderPass.CameraFS", + "RenderPass.NoSelection", + "RenderPass.NoColorOverrides", + "RenderPass.RenderColor" ] + } + } + } +} diff --git a/Sources/Hdx/shaders/selection.glslfx b/Sources/Hdx/shaders/selection.glslfx new file mode 100644 index 0000000000..22977eabf0 --- /dev/null +++ b/Sources/Hdx/shaders/selection.glslfx @@ -0,0 +1,527 @@ +-- glslfx version 0.1 + +// +// Copyright 2018 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +--- This is what an import might look like. +--- #import $TOOLS/hdx/shaders/selection.glslfx + +--- -------------------------------------------------------------------------- +-- glsl Selection.DecodeUtils +/// Decoding utilities for selection highlighting. +/// This mixin may be safely included by any shader stage. Its lone dependency +/// on code generation is the hdxSelectionBuffer SSBO that holds the encoded +/// selection state. + +// This should match the HdSelection enum. +int GetMaxNumSelectionHighlightModes() +{ + return 2; +} + +#if defined(HD_HAS_hdxSelectionBuffer) +// helper methods to decode hdxSelectionBuffer +// ------ selection highlight mode specifics ------- +bool HighlightModeHasSelection(int offset) +{ + return (offset != 0); +} + +int GetIndexOffsetForHighlightMode(int mode) +{ + return HdGet_hdxSelectionBuffer(mode + 1/*[0] holds #modes*/); +} + +int GetNumSelectionHighlightModes() +{ + return HdGet_hdxSelectionBuffer(0); +} + +// ------ selection offset specifics ------- +// Note: This should match the selection offset encoding in +// hdx/SelectionTracker.cpp +void DecodeSelOffset(int selOffset, REF(thread, bool) isSelected, + REF(thread, int) nextOffset) +{ + isSelected = bool(selOffset & 0x1); // bit 0 + nextOffset = selOffset >> 1; // bits 31:1 +} + +// --------- subprim decoding ---------- +// Each subprims offsets' buffer encoding is: +// [subprim-type][min][max][ selOffsets ] +// <----------3 ----------><--- max - min + 1 --> +struct SubprimHeader { + int type; + int min; + int max; +}; +SubprimHeader DecodeSubprimHeader(int offset) +{ + SubprimHeader header; + header.type = HdGet_hdxSelectionBuffer(offset ); + header.min = HdGet_hdxSelectionBuffer(offset + 1); + header.max = HdGet_hdxSelectionBuffer(offset + 2); + return header; +} + +bool IsSubprimSelected(int id, int min, int max, int headerStart, + REF(thread, int) nextSubprimOffset) +{ + const int SUBPRIM_SELOFFSETS_HEADER_SIZE = 3; + + nextSubprimOffset = 0; // initialize + bool isSelected = false; + + if (id >= min && id < max) { + int netSubprimIndex = + headerStart + SUBPRIM_SELOFFSETS_HEADER_SIZE + id - min; + int selOffset = HdGet_hdxSelectionBuffer(netSubprimIndex); + + DecodeSelOffset(selOffset, /*out*/isSelected, /*out*/nextSubprimOffset); + } else { + // The subprim id does not fall in the selected id range, so the subprim + // in question isn't selected. However, we can still have other + // subprim(s) selected. To get the offset to jump to, we mimic decoding + // the "min" subprim id. + int minSubprimIndex = headerStart + SUBPRIM_SELOFFSETS_HEADER_SIZE; + DecodeSelOffset(HdGet_hdxSelectionBuffer(minSubprimIndex), + /*out*/isSelected, /*out*/nextSubprimOffset); + isSelected = false; + } + + return isSelected; +} +#endif // HD_HAS_hdxSelectionBuffer + +// Keep the result struct definition outside guards. +struct SubprimSelectionResult { + bool elementSelected; + bool edgeSelected; + bool pointSelected; + int pointColorId; +}; + +SubprimSelectionResult InitSubprimSelectionResult( + bool _elementSelected, + bool _edgeSelected, + bool _pointSelected, + int _pointColorId) +{ + SubprimSelectionResult res; + + res.elementSelected = _elementSelected; + res.edgeSelected = _edgeSelected; + res.pointSelected = _pointSelected; + res.pointColorId = _pointColorId; + + return res; +} + +bool IsAnySubprimSelected(SubprimSelectionResult s) +{ + return (s.elementSelected || s.edgeSelected || s.pointSelected); +} +bool HasCustomizedPointColor(SubprimSelectionResult s) +{ + // Use -1 to encode selected points that don't have a custom point color. + return (s.pointColorId != -1); +} + +#if defined(HD_HAS_hdxSelectionBuffer) +// Note: These should match the SubprimType enum in hdx/SelectionTracker.cpp +#define SUBPRIM_TYPE_ELEMENT 0 +#define SUBPRIM_TYPE_EDGE 1 +#define SUBPRIM_TYPE_POINT 2 +#define SUBPRIM_TYPE_INSTANCE 3 + +SubprimSelectionResult GetSubprimSel(int offset, + int elementId, int edgeId, int pointId) +{ + SubprimSelectionResult s = InitSubprimSelectionResult(false, false, false, 0); + + int nextSubprimOffset = 0; + SubprimHeader header = DecodeSubprimHeader(offset); + + if (header.type == SUBPRIM_TYPE_ELEMENT) { + s.elementSelected = + IsSubprimSelected(elementId, header.min, header.max, + offset, /*out*/nextSubprimOffset); + + if (nextSubprimOffset != 0) { + // fragment has additional subprim(s) selected. update header. + header = DecodeSubprimHeader(nextSubprimOffset); + offset = nextSubprimOffset; + } + } + + if (header.type == SUBPRIM_TYPE_EDGE) { + s.edgeSelected = + IsSubprimSelected(edgeId, header.min, header.max, + offset, /*out*/nextSubprimOffset); + + if (nextSubprimOffset != 0) { + // fragment has points selected. update header. + header = DecodeSubprimHeader(nextSubprimOffset); + offset = nextSubprimOffset; + } + } + + if (header.type == SUBPRIM_TYPE_POINT) { + s.pointSelected = + IsSubprimSelected(pointId, header.min, header.max, + offset, /*unused*/nextSubprimOffset); + // For points alone, since there isn't any subprim to follow it, the + // offset field is overriden to represent the index into the + // selectedPointColors buffer to support customized coloring of a set of + // selected points. + s.pointColorId = nextSubprimOffset; + } + + return s; +} + +// --------- instance decoding ---------- +bool IsInstanceSelected(int offset, REF(thread, int) nextOffset) +{ + // If we don't find an instance subprim block, pass the same offset to + // GetSubprimSel. + nextOffset = offset; + bool sel = false; + + int instanceId = GetDrawingCoord().instanceIndex[0]; + + SubprimHeader header = DecodeSubprimHeader(offset); + if (header.type == SUBPRIM_TYPE_INSTANCE) { + sel = + IsSubprimSelected(instanceId, header.min, header.max, + offset, /*out*/nextOffset); + } + + return sel; +} +#endif // HD_HAS_hdxSelectionBuffer + +// --------- selection buffer decoding entry point ---------- +struct SelectionResult { + bool primOrInstanceSel; + SubprimSelectionResult subprimSel; +}; + +SelectionResult InitSelectionResult( + bool _primOrInstanceSel, + bool _elementSelected, + bool _edgeSelected, + bool _pointSelected, + int _pointColorId) +{ + SelectionResult res; + + res.primOrInstanceSel = _primOrInstanceSel; + res.subprimSel = InitSubprimSelectionResult( + _elementSelected, _edgeSelected, + _pointSelected, _pointColorId); + + return res; +} + + +// Decodes the selection buffer encoding scheme for a given mode, and returns +// the selection result. +SelectionResult GetSelectionResult(int mode, + int elementId, int edgeId, int pointId) +{ + SelectionResult res = InitSelectionResult(false, false, false, false, 0); + +#if defined(HD_HAS_hdxSelectionBuffer) + // The hdxSelectionBuffer layout is: + // [#modes] [per-mode offset] [data mode0] ... [data modeM] + // [---------header---------] + // Each mode's data is laid out as: + // [ prims | points | edges | elements | instance level-N | ... | level 0 ] + // <-------- subprims -------> <----------- instances ---------> + // <---------------------- per prim ----------------------------> + // See hdx/SelectionTracker.cpp for details on the encoding scheme. + int modeOffset = GetIndexOffsetForHighlightMode(mode); + if (!HighlightModeHasSelection(modeOffset)) { + // highlight mode has no selected objects (prims/instances/elements) + return res; + } + + const int PRIM_SELOFFSETS_HEADER_SIZE = 2; + const int primId = HdGet_primID(); + int smin = HdGet_hdxSelectionBuffer(modeOffset); + int smax = HdGet_hdxSelectionBuffer(modeOffset + 1); + + if (primId >= smin && primId < smax) { + int offset = modeOffset + PRIM_SELOFFSETS_HEADER_SIZE + primId - smin; + int nextOffset = 0; + bool sel = false; + DecodeSelOffset(HdGet_hdxSelectionBuffer(offset), + /*out*/sel, /*out*/nextOffset); + + // At this point, sel indicates whether the fragment corresponds to + // a prim that needs to be fully highlighted, while a non-zero + // nextOffset indicates whether additional decoding may be done. + + // We don't currently differentiate between prim, instance and + // subprim selection highlighting (i.e., visually, they look the + // same), and thus can skip additional decoding if sel is true. + // We choose not to, for ease of future customization. + if (nextOffset != 0) { + // check if instance (or) subprim(s) are selected + offset = nextOffset; + sel = sel || IsInstanceSelected(offset, /*out*/nextOffset); + + if (nextOffset != 0) { + res.subprimSel = + GetSubprimSel(nextOffset, elementId, edgeId, pointId); + } + } + res.primOrInstanceSel = sel; + } +#endif // HD_HAS_hdxSelectionBuffer + + return res; +} + +// Returns the logical OR of the inputs +SelectionResult +_CombineWithOr(SelectionResult a, SelectionResult b) +{ + SelectionResult res = InitSelectionResult(false, false, false, false, 0); + + res.primOrInstanceSel = a.primOrInstanceSel || b.primOrInstanceSel; + res.subprimSel.elementSelected = a.subprimSel.elementSelected || + b.subprimSel.elementSelected; + res.subprimSel.edgeSelected = a.subprimSel.edgeSelected || + b.subprimSel.edgeSelected; + res.subprimSel.pointSelected = a.subprimSel.pointSelected || + b.subprimSel.pointSelected; + // pointColorIndex is ignored. + return res; +} + +// Returns the net selection result aggregating the result of each selection +// mode. +SelectionResult GetNetSelectionResult(int elementId, int edgeId, int pointId) +{ + SelectionResult netResult = InitSelectionResult(false, false, false, false, 0); + +#if defined(HD_HAS_hdxSelectionBuffer) + const int numSelectionModes = GetNumSelectionHighlightModes(); + for (int mode = 0; mode < numSelectionModes; mode++) { + SelectionResult modeResult = + GetSelectionResult(mode, elementId, edgeId, pointId); + netResult = _CombineWithOr(modeResult, netResult); + } +#endif + return netResult; +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.Vertex.PointSel +// Mixin for use in the vertex shader stage. +// Decodes the selection buffer to find out if the current vertex (point) is +// selected. This is called from hdSt/shaders/pointId.glslfx +bool IsPointSelected(int pointId) +{ + bool sel = false; + #if defined(HD_HAS_hdxSelectionBuffer) + const int numSelectionModes = GetNumSelectionHighlightModes(); + for (int mode = 0; mode < numSelectionModes; mode++) { + // At the VS stage, we don't carry enough state to determine the + // elementId and edgeId. So, use fallback values instead. + SelectionResult res = + GetSelectionResult(mode, /*elementId*/-1, /*edgeId*/-1, pointId); + if (res.subprimSel.pointSelected && + !HasCustomizedPointColor(res.subprimSel)) { + sel = true; + break; + } + } // for each highlight mode + #endif + return sel; +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.Geometry.ElementSel +// Mixin for use in the geometry shader stage. +// Helper functions to determine if the element (face) is selected for either +// a given selection mode, or any of the modes. + +FORWARD_DECL(int GetElementID()); // code gen + +bool IsElementSelected(int mode) +{ + bool sel = false; + #if defined(HD_HAS_hdxSelectionBuffer) + const int numSelectionModes = GetNumSelectionHighlightModes(); + if (mode < numSelectionModes) { + SelectionResult res = + GetSelectionResult(mode, GetElementID(), + /*edgeId*/-1, /*pointId*/-1); + if (res.subprimSel.elementSelected) { + sel = true; + } + } + #endif + return sel; +} + +bool IsSelected() +{ + // Edge and point selection aren't relevant at the GS stage. + SelectionResult res = GetNetSelectionResult( + GetElementID(), /*edgeId*/-1, /*pointId*/-1); + + return res.primOrInstanceSel || res.subprimSel.elementSelected; +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.Geometry.WireSelOffset +// Mixin for use in the geometry shader stage for wireframe rendering. +// See comment below. + +FORWARD_DECL(int GetMaxNumSelectionHighlightModes()); +FORWARD_DECL(bool IsElementSelected(int mode)); +FORWARD_DECL(int GetElementID()); // code gen + +vec4 ComputeSelectionOffset() +{ + // For wireframe, we only render the edges of faces. Because we don't have + // a way to control which face gets rasterized first, if face A is selected + // and face B is unselected, it's possible for face B to draw over face A + // and for the highlight to be dropped. + + // To compensate for this, since we're running the geometry shader anyway, + // add a small polygon offset for selected faces, to push them in front of + // unselected faces. + + // For doubly-selected faces (e.g. rollover & selection), apply a double + // offset. The code below chooses a unique offset for each combination + // of selection modes by constructing a bitmask of selection modes for + // this face, and reinterpreting it as an integer. + + int offset = 0; + + int numModes = GetMaxNumSelectionHighlightModes(); + for (int mode = 0; mode < numModes; ++mode) { + if (IsElementSelected(mode)) { + offset += (1 << mode); + } + } + + // Note: for our base epsilon, we're choosing this somewhat arbitrarily. + // This is an eye space epsilon, so it's not dependent on distance-from- + // camera. Rather, it's dependent on scene scale. 1e-3 works well for + // our scenes, but if this causes trouble we could use an epsilon based on + // the eye-space distance of a z-buffer bit flip, which would match the + // behavior of glPolygonOffset better, at the cost of more math and some + // extra shader uniforms. + float eps = 1e-3; + + return vec4(0, 0, offset * eps, 0); +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.Geometry.WireSelNoOffset + +vec4 ComputeSelectionOffset() +{ + return vec4(0); +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.Fragment +// Mixin for use in the fragment shader stage to determine if the fragment is +// selected. + +FORWARD_DECL(int GetElementID()); // generated via codeGen +FORWARD_DECL(int GetPrimitiveEdgeId()); // defined in edgeId.glslfx, or generated via codeGen +FORWARD_DECL(int GetPointId()); // defined in pointId.glslfx + +bool IsSelected() +{ + SelectionResult res = GetNetSelectionResult( + GetElementID(), GetPrimitiveEdgeId(), GetPointId()); + + return res.primOrInstanceSel || res.subprimSel.elementSelected; +} + +--- -------------------------------------------------------------------------- +-- glsl Selection.ComputeColor + +#if defined(HD_HAS_hdxSelectionBuffer) +vec4 GetSelectionColor(int mode) +{ + vec4 s = vec4(0,0,0,0); + // XXX: Make selection colors an array so we can avoid the branching. + if (mode == 0) + s = HdGet_selColor(); + else if (mode == 1) + s = HdGet_selLocateColor(); + + return s; +} + +// fwd decl fn defined in edgeId.glslfx or generated via codeGen +FORWARD_DECL(float GetSelectedEdgeOpacity()); + +vec4 GetSubprimSelectionColor(int mode, SubprimSelectionResult res) +{ + vec4 s = GetSelectionColor(mode); + if (res.edgeSelected) { + s.a = GetSelectedEdgeOpacity(); + } + if (res.pointSelected && HasCustomizedPointColor(res)) { + #if defined(HD_HAS_selectionPointColors) + s = HdGet_selectionPointColors(res.pointColorId); + #endif + } + + return s; +} +#endif + +// Fwd declare necessary methods to determine the subprim id of a fragment. +FORWARD_DECL(int GetElementID()); // generated via codeGen +FORWARD_DECL(int GetPrimitiveEdgeId()); // defined in edgeId.glslfx, or generated via codeGen +FORWARD_DECL(int GetPointId()); // defined in pointId.glslfx + +// Decodes the selection buffer to find out if the current fragment is from +// a prim/instance/subprim that is selected, applies selection highlighting to +// the incoming color, and returns the resulting color. +vec4 ApplySelectionColor(vec4 color) +{ +#if defined(HD_HAS_hdxSelectionBuffer) + int elementId = GetElementID(); + int edgeId = GetPrimitiveEdgeId(); + int pointId = GetPointId(); + + const int numSelectionModes = GetNumSelectionHighlightModes(); + + bool isSelected = false; + for (int mode = 0; mode < numSelectionModes; mode++) { + SelectionResult res = + GetSelectionResult(mode, elementId, edgeId, pointId); + + if (res.primOrInstanceSel) { + isSelected = true; + vec4 s = GetSelectionColor(mode); + color.rgb = mix(color.rgb, s.rgb, s.a); + } + if (IsAnySubprimSelected(res.subprimSel)) { + isSelected = true; + vec4 ss = GetSubprimSelectionColor(mode, res.subprimSel); + color.rgb = mix(color.rgb, ss.rgb, ss.a); + } + } // for each highlight mode + +#endif + return color; +} diff --git a/Sources/Hdx/shaders/skydome.glslfx b/Sources/Hdx/shaders/skydome.glslfx new file mode 100644 index 0000000000..b61707c6ac --- /dev/null +++ b/Sources/Hdx/shaders/skydome.glslfx @@ -0,0 +1,64 @@ +-- glslfx version 0.1 + +// +// Copyright 2021 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +#import $TOOLS/hdSt/shaders/surfaceHelpers.glslfx + +-- configuration +{ + "techniques": { + "default": { + "SkydomeFragment": { + "source": [ "SurfaceHelpers.Lighting", + "Skydome.Fragment" ] + } + } + } +} + +-- glsl Skydome.Fragment + +const float farPlane = 1.0; + +float wrapSampleValue(float value) +{ + if (value < 0.0) { + value += 1.0; + } + else if (value > 1.0) { + value -= 1.0; + } + return value; +} + +vec2 getSampleCoord(vec3 sample3D) +{ + vec2 latLong = ProjectToLatLong(sample3D); + return vec2(wrapSampleValue(latLong.x), wrapSampleValue(latLong.y)); +} + + +void main(void) +{ + // Transform the UV coordinates into NDC space and place at the far plane + // (z = 1) before transforming into view space. + vec2 uvOut_ndc = (uvOut * vec2(2.0)) - vec2(1.0); + vec4 uvOut_view = invProjMatrix * vec4(uvOut_ndc, farPlane, 1.0); + + // Normalize to use as the initial sampleDirection + vec3 sampleDirection = normalize(uvOut_view.xyz); + + // Apply the camera rotation and lightTransform to the sampleDirection + sampleDirection = + ( lightTransform * viewToWorld * vec4(sampleDirection, 0.0) ).xyz; + + // Sample Skydome Texture with the sampleDirection + vec2 sampleCoord = getSampleCoord(sampleDirection); + hd_FragColor = vec4(HgiGet_skydomeTexture(sampleCoord).xyz, 1.0); + gl_FragDepth = farPlane; +} diff --git a/Sources/Hdx/shaders/visualize.glslfx b/Sources/Hdx/shaders/visualize.glslfx new file mode 100644 index 0000000000..d8bba7ef21 --- /dev/null +++ b/Sources/Hdx/shaders/visualize.glslfx @@ -0,0 +1,107 @@ +-- glslfx version 0.1 + +// +// Copyright 2021 Pixar +// +// Licensed under the terms set forth in the LICENSE.txt file available at +// https://openusd.org/license. +// + +-- configuration +{ + "techniques": { + "default": { + "VisualizeVertex": { + "source": [ "Visualize.Vertex" ] + }, + "VisualizeFragmentDepth": { + "source": [ "Visualize.Fragment.Depth" ] + }, + "VisualizeFragmentId": { + "source": [ "Visualize.Fragment.Id" ] + }, + "VisualizeFragmentNormal": { + "source": [ "Visualize.Fragment.Normal" ] + }, + "VisualizeFragmentFallback": { + "source": [ "Visualize.Fragment.Fallback" ] + } + } + } +} + +-- glsl Visualize.Vertex + +void main(void) +{ + gl_Position = position; + uvOut = uvIn; +} + +-- glsl Visualize.Fragment.Depth + +// Re-normalize clip space depth in the range [0.0, 1.0] to the range [min, max] +// to allow better visualization of depth differences. +float normalizeDepth(float depth) +{ + float min = minMaxDepth.x, max = minMaxDepth.y; + return (depth - min) / (max - min); +} + +// Display the renormalized depth as a grayscale image. +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + float depth = HgiTexelFetch_depthIn(ivec2(fragCoord)).x; + hd_FragColor = vec4( vec3(normalizeDepth(depth)), 1.0 ); +} + +-- glsl Visualize.Fragment.Id + +// Convert a 32 bit integer into a vec3 color. +vec3 IntToVec3(int id) +{ + // Create a 24 bit value by XORing the leading 8 bits with the remaining + // 24 bits. + int leadBits = id >> 24; + int restBits = (id << 8) >> 8; + int result = restBits ^ leadBits; + + return vec3(((result >> 0) & 0xff) / 255.0, + ((result >> 8) & 0xff) / 255.0, + ((result >> 16) & 0xff) / 255.0); +} + +// Convert a 32 bit integer representing the ID of a primitive or sub-primitive +// into a color such that consecutive IDs generally map to different colors. +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + int id = int(HgiTexelFetch_idIn(ivec2(fragCoord)).x); + int vizId = id * 11629091; // prime number near ln(2) * 2^24 + hd_FragColor = vec4(IntToVec3(vizId), 1.0); +} + +-- glsl Visualize.Fragment.Normal + +// [-1,1] to [0,1] +vec3 renormalize(vec3 normal) +{ + return 0.5 * normal + 0.5; +} + +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + vec3 normal = HgiTexelFetch_normalIn(ivec2(fragCoord)).xyz; + hd_FragColor = vec4(renormalize(normal), 1.0); +} + +-- glsl Visualize.Fragment.Fallback + +void main(void) +{ + vec2 fragCoord = uvOut * screenSize; + // Force conversion to a vector of floats. + hd_FragColor = vec4(HgiTexelFetch_aovIn(ivec2(fragCoord))); +} diff --git a/Sources/Hdx/textures/StinsonBeach.hdr b/Sources/Hdx/textures/StinsonBeach.hdr new file mode 100644 index 0000000000..a7d1590dbd Binary files /dev/null and b/Sources/Hdx/textures/StinsonBeach.hdr differ diff --git a/Sources/Hdx/textures/StinsonBeach.tex b/Sources/Hdx/textures/StinsonBeach.tex new file mode 100644 index 0000000000..9a2d5119f7 Binary files /dev/null and b/Sources/Hdx/textures/StinsonBeach.tex differ diff --git a/Sources/HioOpenVDB/.gitkeep b/Sources/HioOpenVDB/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/PixarUSD/Bundle.swift b/Sources/PixarUSD/Bundle.swift index 7542a27caf..2fe2a397a2 100644 --- a/Sources/PixarUSD/Bundle.swift +++ b/Sources/PixarUSD/Bundle.swift @@ -158,6 +158,14 @@ public extension Bundle * Where ``HgiGL`` application bundle resources are located. */ static let hgiGL = Bundle(path: "\(pxrRoot)/SwiftUSD_HgiGL\(ext)") + /** + * Where ``HdSt`` application bundle resources are located. */ + static let hdSt = Bundle(path: "\(pxrRoot)/SwiftUSD_HdSt\(ext)") + + /** + * Where ``Hdx`` application bundle resources are located. */ + static let hdx = Bundle(path: "\(pxrRoot)/SwiftUSD_Hdx\(ext)") + /** * Where ``Hio`` application bundle resources are located. */ static let hio = Bundle(path: "\(pxrRoot)/SwiftUSD_Hio\(ext)") @@ -166,6 +174,14 @@ public extension Bundle * Where ``Glf`` application bundle resources are located. */ static let glf = Bundle(path: "\(pxrRoot)/SwiftUSD_Glf\(ext)") + /** + * Where ``UsdImaging`` application bundle resources are located. */ + static let usdImaging = Bundle(path: "\(pxrRoot)/SwiftUSD_UsdImaging\(ext)") + + /** + * Where ``UsdImagingGL`` application bundle resources are located. */ + static let usdImagingGL = Bundle(path: "\(pxrRoot)/SwiftUSD_UsdImagingGL\(ext)") + /** * Where ``Tf`` python bundle resources are located. */ static let pyTf = Bundle(path: "\(pxrRoot)/SwiftUSD_PyTf\(ext)") @@ -424,8 +440,12 @@ public enum BundleFramework: CaseIterable case hgiMetal case hgiVulkan case hgiGL + case hdSt + case hdx case hio case glf + case usdImaging + case usdImagingGL public var resourcePath: String? { @@ -456,8 +476,12 @@ public enum BundleFramework: CaseIterable case .hgiMetal: Bundle.hgiMetal?.resourcePath case .hgiVulkan: Bundle.hgiVulkan?.resourcePath case .hgiGL: Bundle.hgiGL?.resourcePath + case .hdSt: Bundle.hdSt?.resourcePath + case .hdx: Bundle.hdx?.resourcePath case .hio: Bundle.hio?.resourcePath case .glf: Bundle.glf?.resourcePath + case .usdImaging: Bundle.usdImaging?.resourcePath + case .usdImagingGL: Bundle.usdImagingGL?.resourcePath } } } diff --git a/Sources/Plugin/.gitkeep b/Sources/Plugin/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/Plugin/implicitSurfaceSceneIndexPlugin.cpp b/Sources/Plugin/implicitSurfaceSceneIndexPlugin.cpp index 185ee3d29c..dc821e764d 100644 --- a/Sources/Plugin/implicitSurfaceSceneIndexPlugin.cpp +++ b/Sources/Plugin/implicitSurfaceSceneIndexPlugin.cpp @@ -9,7 +9,7 @@ #include "Hd/retainedDataSource.h" #include "Hd/sceneIndexPluginRegistry.h" #include "Hd/tokens.h" -#include "Hdsi/implicitSurfaceSceneIndex.h" +#include "HdSi/implicitSurfaceSceneIndex.h" PXR_NAMESPACE_OPEN_SCOPE diff --git a/Sources/Ts/.gitkeep b/Sources/Ts/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdAppUtils/.gitkeep b/Sources/UsdAppUtils/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdImaging/.gitkeep b/Sources/UsdImaging/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdImaging/Resources/plugInfo.json b/Sources/UsdImaging/Resources/plugInfo.json new file mode 100644 index 0000000000..890c958975 --- /dev/null +++ b/Sources/UsdImaging/Resources/plugInfo.json @@ -0,0 +1,340 @@ +{ + "Plugins": [ + { + "Info": { + "SdfMetadata": { + "faceIndexPrimvar": { + "appliesTo": [ + "attributes" + ], + "default": "ptexFaceIndex", + "documentation": "Specifies an array of face indices used for ptex mapping", + "type": "token" + }, + "faceOffsetPrimvar": { + "appliesTo": [ + "attributes" + ], + "default": "ptexFaceOffset", + "documentation": "Specifies the ptex face index offset for aggregated ptex files", + "type": "token" + }, + "uvPrimvar": { + "appliesTo": [ + "attributes" + ], + "default": "", + "documentation": "Specifies the UV primvar for texture mapping", + "type": "token" + } + }, + "Types": { + "UsdImagingBasisCurvesAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "BasisCurves" + }, + "UsdImagingCameraAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "Camera" + }, + "UsdImagingCapsuleAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "includeSchemaFamily": true, + "primTypeName": "Capsule" + }, + "UsdImagingCollectionAPIAdapter" : { + "bases": ["UsdImagingAPISchemaAdapter"], + "isInternal": true, + "apiSchemaName": "CollectionAPI" + }, + "UsdImagingConeAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Cone" + }, + "UsdImagingCoordSysAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "coordSys" + }, + "UsdImagingCoordSysAPIAdapter" : { + "bases": ["UsdImagingAPISchemaAdapter"], + "isInternal": true, + "apiSchemaName": "CoordSysAPI" + }, + "UsdImagingCubeAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Cube" + }, + "UsdImagingCylinderAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "includeSchemaFamily": true, + "primTypeName": "Cylinder" + }, + "UsdImagingDrawModeAdapter" : { + "bases": ["UsdImagingInstanceablePrimAdapter"], + "isInternal": true, + "primTypeName": "__drawModeAdapter" + }, + "UsdImagingGeomSubsetAdapter" : { + "bases": ["UsdImagingPrimAdapter"], + "isInternal": true, + "primTypeName": "GeomSubset" + }, + "UsdImagingHermiteCurvesAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "HermiteCurves" + }, + "UsdImagingMaterialAdapter" : { + "bases": ["UsdImagingPrimAdapter"], + "isInternal": true, + "primTypeName": "Material" + }, + + "UsdImagingShaderAdapter" : { + "bases": ["UsdImagingRepresentedByAncestorPrimAdapter"], + "isInternal": true, + "primTypeName": "Shader" + }, + + "UsdImagingNodeGraphAdapter" : { + "bases": ["UsdImagingRepresentedByAncestorPrimAdapter"], + "isInternal": true, + "primTypeName": "NodeGraph" + }, + + "UsdImagingMaterialBindingAPIAdapter" : { + "bases": ["UsdImagingAPISchemaAdapter"], + "isInternal": true, + "apiSchemaName": "MaterialBindingAPI" + }, + "UsdImagingMeshAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Mesh" + }, + "UsdImagingTetMeshAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "TetMesh" + }, + "UsdImagingNurbsCurvesAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "NurbsCurves" + }, + "UsdImagingNurbsPatchAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "NurbsPatch" + }, + "UsdImagingPlaneAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Plane" + }, + "UsdImagingPointsAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Points" + }, + "UsdImagingPointInstancerAdapter": { + "bases": [ + "UsdImagingInstanceablePrimAdapter" + ], + "isInternal": true, + "primTypeName": "PointInstancer" + }, + "UsdImagingSphereAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Sphere" + }, + "UsdImagingRenderPassAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "RenderPass" + }, + "UsdImagingRenderSettingsAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "RenderSettings" + }, + "UsdImagingRenderProductAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "RenderProduct" + }, + "UsdImagingRenderVarAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "RenderVar" + }, + "UsdImagingVolumeAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "Volume" + }, + "UsdImagingLightAdapter": { + "bases": [ + "UsdImagingInstanceablePrimAdapter" + ], + "isInternal": true, + "primTypeName": "LightAPI", + "includeDerivedPrimTypes" : true + }, + "UsdImagingLightAPIAdapter": { + "bases": [ + "UsdImagingAPISchemaAdapter" + ], + "isInternal": true, + "apiSchemaName": "LightAPI" + }, + "UsdImagingLightFilterAdapter": { + "bases": [ + "UsdImagingPrimAdapter" + ], + "isInternal": true, + "primTypeName": "LightFilter", + "includeDerivedPrimTypes" : true + }, + "UsdImagingDomeLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "DomeLight" + }, + "UsdImagingDomeLight_1Adapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "DomeLight_1" + }, + "UsdImagingRectLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "RectLight" + }, + "UsdImagingSphereLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "SphereLight" + }, + "UsdImagingCylinderLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "CylinderLight" + }, + "UsdImagingDiskLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "DiskLight" + }, + "UsdImagingDistantLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "DistantLight" + }, + "UsdImagingPluginLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "PluginLight" + }, + "UsdImagingGeometryLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "GeometryLight" + }, + "UsdImagingPortalLightAdapter": { + "bases": [ + "UsdImagingLightAdapter" + ], + "isInternal": true, + "primTypeName": "PortalLight" + }, + "UsdImagingPluginLightFilterAdapter": { + "bases": [ + "UsdImagingLightFilterAdapter" + ], + "isInternal": true, + "primTypeName": "PluginLightFilter" + }, + "UsdImagingGeomModelAPIAdapter": { + "bases": [ + "UsdImagingAPISchemaAdapter" + ], + "isInternal": true, + "apiSchemaName": "GeomModelAPI" + } + } + }, + "LibraryPath": "", + "Name": "UsdImaging", + "ResourcePath": "Contents/Resources", + "Root": "../..", + "Type": "library" + } + ] +} diff --git a/Sources/UsdImagingGL/.gitkeep b/Sources/UsdImagingGL/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdImagingGL/Resources/plugInfo.json b/Sources/UsdImagingGL/Resources/plugInfo.json new file mode 100644 index 0000000000..39c586ffe0 --- /dev/null +++ b/Sources/UsdImagingGL/Resources/plugInfo.json @@ -0,0 +1,12 @@ +{ + "Plugins": [ + { + "Info" : {}, + "LibraryPath": "", + "Name": "UsdImagingGL", + "ResourcePath": "Contents/Resources", + "Root": "../..", + "Type": "library" + } + ] +} diff --git a/Sources/UsdImagingGL/engine.cpp b/Sources/UsdImagingGL/engine.cpp index 9f15c11271..4b0d2e5743 100644 --- a/Sources/UsdImagingGL/engine.cpp +++ b/Sources/UsdImagingGL/engine.cpp @@ -26,9 +26,9 @@ #include "Hd/sceneIndexPluginRegistry.h" #include "Hd/systemMessages.h" #include "Hd/utils.h" -#include "Hdsi/legacyDisplayStyleOverrideSceneIndex.h" -#include "Hdsi/primTypePruningSceneIndex.h" -#include "Hdsi/sceneGlobalsSceneIndex.h" +#include "HdSi/legacyDisplayStyleOverrideSceneIndex.h" +#include "HdSi/primTypePruningSceneIndex.h" +#include "HdSi/sceneGlobalsSceneIndex.h" #include "Hdx/pickTask.h" #include "Hdx/taskController.h" #include "Hdx/tokens.h" diff --git a/Sources/UsdProcImaging/.gitkeep b/Sources/UsdProcImaging/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdRiPxrImaging/.gitkeep b/Sources/UsdRiPxrImaging/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdSkelImaging/.gitkeep b/Sources/UsdSkelImaging/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdView/HDMTLRenderer.swift b/Sources/UsdView/HDMTLRenderer.swift index 7862b72a45..1b6522bccd 100644 --- a/Sources/UsdView/HDMTLRenderer.swift +++ b/Sources/UsdView/HDMTLRenderer.swift @@ -29,12 +29,12 @@ import PixarUSD class HDMTLRenderer: NSObject, MTKViewDelegate { let hgi: Pixar.HgiMetalPtr - let driver: HdDriver init?(device _: MTLDevice) { hgi = HgiMetal.createHgi() - driver = HdDriver(name: .renderDriver, driver: VtValue(hgi)) + + let driver = HdDriver(name: .renderDriver, driver: VtValue(hgi)) } func info() diff --git a/Sources/UsdViewQ/.gitkeep b/Sources/UsdViewQ/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/UsdVolImaging/.gitkeep b/Sources/UsdVolImaging/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Sources/pxr/include/pxr/pxrns.h b/Sources/pxr/include/pxr/pxrns.h index a212347ccb..832e9042c3 100644 --- a/Sources/pxr/include/pxr/pxrns.h +++ b/Sources/pxr/include/pxr/pxrns.h @@ -29,7 +29,7 @@ /* ------ swift usd. ------ */ -# define SWIFTUSD_EVOLUTION 0 +# define SWIFTUSD_EVOLUTION 3 # define PXR_INTERNAL_NS Pixar /* ------------------------ */