diff --git a/LICENSE.txt b/LICENSE.txt index a2cdda092e..c49700833d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -850,3 +850,35 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +================================================================ +dashDotCurves.glslfx +================================================================ + +GPU-accelerated Antialiased Dashed Stroked Polylines +Copyright (C) 2013 Nicolas P. Rougier. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are +those of the authors and should not be interpreted as representing official +policies, either expressed or implied, of Nicolas P. Rougier. diff --git a/extras/usd/examples/usdGeomExamples/styleCurve_NoScreenSpace_Segment.usda b/extras/usd/examples/usdGeomExamples/styleCurve_NoScreenSpace_Segment.usda new file mode 100644 index 0000000000..dfbe958b4a --- /dev/null +++ b/extras/usd/examples/usdGeomExamples/styleCurve_NoScreenSpace_Segment.usda @@ -0,0 +1,37 @@ +#usda 1.0 + +( + upAxis = "Y" + doc = """This layer represents the various geometric forms that curves + may be used to represent.""" +) + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} + +def Xform "Linear" { + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 9, 0) + def Scope "Ribbons"{ + def DashDotLines "StyledPolyline1" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 0, 0) + + uniform bool screenSpacePattern = false + uniform token startCapType = "round" + uniform token endCapType = "round" + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + } +} \ No newline at end of file diff --git a/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace.usda b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace.usda new file mode 100644 index 0000000000..e18f4b8f8f --- /dev/null +++ b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace.usda @@ -0,0 +1,165 @@ +#usda 1.0 + +( + upAxis = "Y" + doc = """This layer represents the various geometric forms that curves + may be used to represent.""" +) + + +def Xform "Linear" { + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 9, 0) + def Scope "Ribbons"{ + def DashDotLines "StyledPolyline1" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 0, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + def DashDotLines "StyledPolyline2" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (30, 0, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "square" + uniform token endCapType = "triangle" + uniform float patternScale = 7 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [8] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + def DashDotLines "StyledPolyline3" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (60, 0, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "triangle" + uniform float patternScale = 10 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [3] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + def DashDotLines "StyledPolyline4" ( + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (90, 0, 0) + + uniform token startCapType = "round" + uniform token endCapType = "round" + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [8] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + + def DashDotLines "StyledPolyline5" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, -80, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] + } + def DashDotLines "StyledPolyline6" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (30, -80, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] + } + def DashDotLines "StyledPolyline7" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (60, -80, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] + } + def DashDotLines "StyledPolyline8" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (90, -80, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] + } + } +} + +def "Pattern1" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 20 + uniform float2[] pattern = [(0, 12.5), (2.5, 2.5)] +} + +def "Pattern2" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 10 + uniform float2[] pattern = [(0, 5), (2.5, 0)] +} + +def "Pattern3" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} + +def "Pattern4" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 5 + uniform float2[] pattern = [(0, 0)] +} \ No newline at end of file diff --git a/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment.usda b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment.usda new file mode 100644 index 0000000000..da2d1cdcff --- /dev/null +++ b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment.usda @@ -0,0 +1,39 @@ +#usda 1.0 + +( + upAxis = "Y" + doc = """This layer represents the various geometric forms that curves + may be used to represent.""" +) + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} + +def Xform "Linear" { + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 9, 0) + def Scope "Ribbons"{ + def DashDotLines "StyledPolyline1" ( + prepend inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 0, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] + } + } +} + diff --git a/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment_VertexColor.usda b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment_VertexColor.usda new file mode 100644 index 0000000000..b31b4b53a5 --- /dev/null +++ b/extras/usd/examples/usdGeomExamples/styleCurve_ScreenSpace_Segment_VertexColor.usda @@ -0,0 +1,38 @@ +#usda 1.0 + +( + upAxis = "Y" + doc = """This layer represents the various geometric forms that curves + may be used to represent.""" +) + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} + +def Xform "Linear" { + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 9, 0) + def Scope "Ribbons"{ + def DashDotLines "StyledPolyline1" ( + inherits = [] + ){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, 0, 0) + + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0), (1, 0 ,1), (0, 1, 1), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0 ,1), (0, 1, 1)](interpolation = "vertex") + } + } +} \ No newline at end of file diff --git a/pxr/imaging/hd/basisCurves.cpp b/pxr/imaging/hd/basisCurves.cpp index c318849acd..b87d33ee28 100644 --- a/pxr/imaging/hd/basisCurves.cpp +++ b/pxr/imaging/hd/basisCurves.cpp @@ -19,6 +19,7 @@ TF_DEFINE_ENV_SETTING(HD_ENABLE_REFINED_CURVES, 0, HdBasisCurves::HdBasisCurves(SdfPath const& id) : HdRprim(id) + , _wvpMatrix(1) { /*NOTHING*/ } @@ -32,7 +33,18 @@ HdBasisCurves::GetBuiltinPrimvarNames() const static const TfTokenVector primvarNames = { HdTokens->points, HdTokens->normals, - HdTokens->widths + HdTokens->widths, + HdTokens->accumulatedLength, + HdTokens->adjPoints1, + HdTokens->adjPoints2, + HdTokens->adjPoints3, + HdTokens->extrude, + HdTokens->pattern, + HdTokens->patternPartCount, + HdTokens->patternPeriod, + HdTokens->patternScale, + HdTokens->startCapType, + HdTokens->endCapType }; return primvarNames; } diff --git a/pxr/imaging/hd/basisCurves.h b/pxr/imaging/hd/basisCurves.h index 7db1712d64..a3d31a0b60 100644 --- a/pxr/imaging/hd/basisCurves.h +++ b/pxr/imaging/hd/basisCurves.h @@ -53,6 +53,13 @@ class HdBasisCurves : public HdRprim public: HD_API ~HdBasisCurves() override; + + enum DirtyBits : HdDirtyBits { + DirtyIndices = HdChangeTracker::CustomBitsBegin, + // Need to update the accumulated length when camera is dirty and the curve has screen space + // Style. + DirtyCamera = (DirtyIndices << 1) + }; /// /// Topology @@ -71,7 +78,23 @@ class HdBasisCurves : public HdRprim /// Returns whether refinement is always on or not. HD_API static bool IsEnabledForceRefinedCurves(); - + + /// Set the WVP matrix. + void UpdateWVPMatrix(const GfMatrix4d& wvpMatrix) + { + _wvpMatrix = wvpMatrix; + } + + /// Set the Viewport + void UpdateViewport(const GfVec4f& viewport) + { + _viewport = viewport; + } + + /// Check if the curve need to be updated each frame. + HD_API + virtual bool NeedUpdateEachFrame(HdSceneDelegate* /*sceneDelegate*/) const { return false; } + protected: HD_API HdBasisCurves(SdfPath const& id); @@ -82,6 +105,8 @@ class HdBasisCurves : public HdRprim static _BasisCurvesReprConfig::DescArray _GetReprDesc(TfToken const &reprName); + GfMatrix4d _wvpMatrix; + GfVec4f _viewport; private: // Class can not be default constructed or copied. HdBasisCurves() = delete; diff --git a/pxr/imaging/hd/basisCurvesTopology.cpp b/pxr/imaging/hd/basisCurvesTopology.cpp index b0f8e6fd59..e0c792c3ec 100644 --- a/pxr/imaging/hd/basisCurvesTopology.cpp +++ b/pxr/imaging/hd/basisCurvesTopology.cpp @@ -19,13 +19,27 @@ namespace { static size_t _ComputeNumPoints( VtIntArray const &curveVertexCounts, - VtIntArray const &indices) + VtIntArray const &indices, + bool needAdjInfo) { // Make absolutely sure the iterator is constant // (so we don't detach the array while multi-threaded) if (indices.empty()) { - return std::accumulate( - curveVertexCounts.cbegin(), curveVertexCounts.cend(), size_t {0} ); + if (needAdjInfo) + { + // Calculate the count of line segments. + size_t countOfLineSegmemt = 0; + for (auto count : curveVertexCounts) + { + countOfLineSegmemt += (count - 1); + } + // For each line segment, we need four vertices: each line segment will + // be converted to a quad. + return countOfLineSegmemt * 4; + } + else + return std::accumulate( + curveVertexCounts.cbegin(), curveVertexCounts.cend(), size_t {0} ); } else { return 1 + *std::max_element(indices.cbegin(), indices.cend()); } @@ -38,6 +52,7 @@ HdBasisCurvesTopology::HdBasisCurvesTopology() , _curveType(HdTokens->linear) , _curveBasis(TfToken()) , _curveWrap(HdTokens->nonperiodic) + , _curveStyle(HdTokens->none) , _curveVertexCounts() , _curveIndices() , _invisiblePoints() @@ -52,24 +67,28 @@ HdBasisCurvesTopology::HdBasisCurvesTopology(const HdBasisCurvesTopology& src) , _curveType(src._curveType) , _curveBasis(src._curveBasis) , _curveWrap(src._curveWrap) + , _curveStyle(src._curveStyle) , _curveVertexCounts(src._curveVertexCounts) , _curveIndices(src._curveIndices) , _invisiblePoints(src._invisiblePoints) , _invisibleCurves(src._invisibleCurves) { HD_PERF_COUNTER_INCR(HdPerfTokens->basisCurvesTopology); - _numPoints = _ComputeNumPoints(_curveVertexCounts, _curveIndices); + _numPoints = _ComputeNumPoints(_curveVertexCounts, _curveIndices, + _curveStyle != HdTokens->none); } HdBasisCurvesTopology::HdBasisCurvesTopology(const TfToken &curveType, const TfToken &curveBasis, const TfToken &curveWrap, + const TfToken &curveStyle, const VtIntArray &curveVertexCounts, const VtIntArray &curveIndices) : HdTopology() , _curveType(curveType) , _curveBasis(curveBasis) , _curveWrap(curveWrap) + , _curveStyle(curveStyle) , _curveVertexCounts(curveVertexCounts) , _curveIndices(curveIndices) , _invisiblePoints() @@ -86,7 +105,8 @@ HdBasisCurvesTopology::HdBasisCurvesTopology(const TfToken &curveType, _curveBasis = TfToken(); } HD_PERF_COUNTER_INCR(HdPerfTokens->basisCurvesTopology); - _numPoints = _ComputeNumPoints(_curveVertexCounts, _curveIndices); + _numPoints = _ComputeNumPoints(_curveVertexCounts, _curveIndices, + _curveStyle != HdTokens->none); } HdBasisCurvesTopology::~HdBasisCurvesTopology() @@ -103,6 +123,7 @@ HdBasisCurvesTopology::operator==(HdBasisCurvesTopology const &other) const return (_curveType == other._curveType && _curveBasis == other._curveBasis && _curveWrap == other._curveWrap && + _curveStyle == other._curveStyle && _curveVertexCounts == other._curveVertexCounts && _curveIndices == other._curveIndices && _invisiblePoints == other._invisiblePoints && @@ -124,11 +145,12 @@ HdBasisCurvesTopology::ComputeHash() const hash = ArchHash64((const char*)&_curveBasis, sizeof(TfToken), hash); hash = ArchHash64((const char*)&_curveType, sizeof(TfToken), hash); hash = ArchHash64((const char*)&_curveWrap, sizeof(TfToken), hash); + hash = ArchHash64((const char*)&_curveStyle, sizeof(TfToken), hash); hash = ArchHash64((const char*)_curveVertexCounts.cdata(), _curveVertexCounts.size() * sizeof(int), hash); hash = ArchHash64((const char*)_curveIndices.cdata(), _curveIndices.size() * sizeof(int), hash); - + // Note: We don't hash topological visibility, because it is treated as a // per-prim opinion, and hence, shouldn't break topology sharing. return hash; @@ -140,6 +162,7 @@ operator << (std::ostream &out, HdBasisCurvesTopology const &topo) out << "(" << topo.GetCurveBasis().GetString() << ", " << topo.GetCurveType().GetString() << ", " << topo.GetCurveWrap().GetString() << ", (" << + topo.GetCurveStyle().GetString() << ", (" << topo.GetCurveVertexCounts() << "), (" << topo.GetCurveIndices() << "), (" << topo.GetInvisiblePoints() << "), (" << diff --git a/pxr/imaging/hd/basisCurvesTopology.h b/pxr/imaging/hd/basisCurvesTopology.h index 4509909c51..ae39637f7d 100644 --- a/pxr/imaging/hd/basisCurvesTopology.h +++ b/pxr/imaging/hd/basisCurvesTopology.h @@ -68,6 +68,7 @@ class HdBasisCurvesTopology : public HdTopology { HdBasisCurvesTopology(const TfToken &curveType, const TfToken &curveBasis, const TfToken &curveWrap, + const TfToken &curveStyle, const VtIntArray &curveVertexCounts, const VtIntArray &curveIndices); HD_API @@ -123,6 +124,7 @@ class HdBasisCurvesTopology : public HdTopology { TfToken GetCurveType() const { return _curveType; } TfToken GetCurveBasis() const { return _curveBasis; } TfToken GetCurveWrap() const { return _curveWrap; } + TfToken GetCurveStyle() const { return _curveStyle; } /// Does the topology use an index buffer bool HasIndices() const { return !_curveIndices.empty(); } @@ -149,6 +151,7 @@ class HdBasisCurvesTopology : public HdTopology { TfToken _curveType; TfToken _curveBasis; TfToken _curveWrap; + TfToken _curveStyle; VtIntArray _curveVertexCounts; VtIntArray _curveIndices; VtIntArray _invisiblePoints; diff --git a/pxr/imaging/hd/basisCurvesTopologySchema.cpp b/pxr/imaging/hd/basisCurvesTopologySchema.cpp index 45fad0a0bd..06173444c5 100644 --- a/pxr/imaging/hd/basisCurvesTopologySchema.cpp +++ b/pxr/imaging/hd/basisCurvesTopologySchema.cpp @@ -68,6 +68,13 @@ HdBasisCurvesTopologySchema::GetWrap() const HdBasisCurvesTopologySchemaTokens->wrap); } +HdTokenDataSourceHandle +HdBasisCurvesTopologySchema::GetStyle() const +{ + return _GetTypedDataSource( + HdBasisCurvesTopologySchemaTokens->style); +} + /*static*/ HdContainerDataSourceHandle HdBasisCurvesTopologySchema::BuildRetained( @@ -75,11 +82,12 @@ HdBasisCurvesTopologySchema::BuildRetained( const HdIntArrayDataSourceHandle &curveIndices, const HdTokenDataSourceHandle &basis, const HdTokenDataSourceHandle &type, - const HdTokenDataSourceHandle &wrap + const HdTokenDataSourceHandle &wrap, + const HdTokenDataSourceHandle &style ) { - TfToken _names[5]; - HdDataSourceBaseHandle _values[5]; + TfToken _names[6]; + HdDataSourceBaseHandle _values[6]; size_t _count = 0; @@ -107,6 +115,11 @@ HdBasisCurvesTopologySchema::BuildRetained( _names[_count] = HdBasisCurvesTopologySchemaTokens->wrap; _values[_count++] = wrap; } + + if (style) { + _names[_count] = HdBasisCurvesTopologySchemaTokens->style; + _values[_count++] = style; + } return HdRetainedContainerDataSource::New(_count, _names, _values); } @@ -150,6 +163,14 @@ HdBasisCurvesTopologySchema::Builder::SetWrap( return *this; } +HdBasisCurvesTopologySchema::Builder & +HdBasisCurvesTopologySchema::Builder::SetStyle( + const HdTokenDataSourceHandle &style) +{ + _style = style; + return *this; +} + HdContainerDataSourceHandle HdBasisCurvesTopologySchema::Builder::Build() { @@ -158,7 +179,8 @@ HdBasisCurvesTopologySchema::Builder::Build() _curveIndices, _basis, _type, - _wrap + _wrap, + _style ); } diff --git a/pxr/imaging/hd/basisCurvesTopologySchema.h b/pxr/imaging/hd/basisCurvesTopologySchema.h index 7f213e3485..ac9b1d6305 100644 --- a/pxr/imaging/hd/basisCurvesTopologySchema.h +++ b/pxr/imaging/hd/basisCurvesTopologySchema.h @@ -39,6 +39,7 @@ PXR_NAMESPACE_OPEN_SCOPE (basis) \ (type) \ (wrap) \ + (style) \ TF_DECLARE_PUBLIC_TOKENS(HdBasisCurvesTopologySchemaTokens, HD_API, HD_BASIS_CURVES_TOPOLOGY_SCHEMA_TOKENS); @@ -85,7 +86,10 @@ class HdBasisCurvesTopologySchema : public HdSchema HdTokenDataSourceHandle GetType() const; HD_API - HdTokenDataSourceHandle GetWrap() const; + HdTokenDataSourceHandle GetWrap() const; + + HD_API + HdTokenDataSourceHandle GetStyle() const; /// @} @@ -121,7 +125,8 @@ class HdBasisCurvesTopologySchema : public HdSchema const HdIntArrayDataSourceHandle &curveIndices, const HdTokenDataSourceHandle &basis, const HdTokenDataSourceHandle &type, - const HdTokenDataSourceHandle &wrap + const HdTokenDataSourceHandle &wrap, + const HdTokenDataSourceHandle &style ); /// \class HdBasisCurvesTopologySchema::Builder @@ -148,6 +153,9 @@ class HdBasisCurvesTopologySchema : public HdSchema HD_API Builder &SetWrap( const HdTokenDataSourceHandle &wrap); + HD_API + Builder &SetStyle( + const HdTokenDataSourceHandle &style); /// Returns a container data source containing the members set thus far. HD_API @@ -159,6 +167,7 @@ class HdBasisCurvesTopologySchema : public HdSchema HdTokenDataSourceHandle _basis; HdTokenDataSourceHandle _type; HdTokenDataSourceHandle _wrap; + HdTokenDataSourceHandle _style; }; diff --git a/pxr/imaging/hd/dataSourceLegacyPrim.cpp b/pxr/imaging/hd/dataSourceLegacyPrim.cpp index 869bb26736..c4b50beab1 100644 --- a/pxr/imaging/hd/dataSourceLegacyPrim.cpp +++ b/pxr/imaging/hd/dataSourceLegacyPrim.cpp @@ -817,6 +817,8 @@ class Hd_BasisCurvesTopologyStore CurveWrapDataSource, TfToken, GetCurveWrap); DEFINE_BASISCURVES_TOPOLOGY_ACCESSOR_DATASOURCE( CurveBasisDataSource, TfToken, GetCurveBasis); + DEFINE_BASISCURVES_TOPOLOGY_ACCESSOR_DATASOURCE( + CurveStyleDataSource, TfToken, GetCurveStyle); DEFINE_BASISCURVES_TOPOLOGY_ACCESSOR_DATASOURCE( CurveVertexCountsDataSource, VtArray, GetCurveVertexCounts); DEFINE_BASISCURVES_TOPOLOGY_ACCESSOR_DATASOURCE( @@ -847,6 +849,7 @@ class Hd_DataSourceBasisCurvesTopology : public HdContainerDataSource HdBasisCurvesTopologySchemaTokens->basis, HdBasisCurvesTopologySchemaTokens->type, HdBasisCurvesTopologySchemaTokens->wrap, + HdBasisCurvesTopologySchemaTokens->style, }; } @@ -872,6 +875,10 @@ class Hd_DataSourceBasisCurvesTopology : public HdContainerDataSource return Hd_BasisCurvesTopologyStore:: CurveWrapDataSource::New(_bcts); } + if (name == HdBasisCurvesTopologySchemaTokens->style) { + return Hd_BasisCurvesTopologyStore:: + CurveStyleDataSource::New(_bcts); + } return nullptr; } diff --git a/pxr/imaging/hd/renderIndex.cpp b/pxr/imaging/hd/renderIndex.cpp index bce04a0093..ea1c3e0a8f 100644 --- a/pxr/imaging/hd/renderIndex.cpp +++ b/pxr/imaging/hd/renderIndex.cpp @@ -7,6 +7,7 @@ #include "pxr/imaging/hd/renderIndex.h" #include "pxr/imaging/hd/basisCurves.h" +#include "pxr/imaging/hd/camera.h" #include "pxr/imaging/hd/dataSourceLegacyPrim.h" #include "pxr/imaging/hd/debugCodes.h" #include "pxr/imaging/hd/dirtyList.h" @@ -22,6 +23,7 @@ #include "pxr/imaging/hd/prefixingSceneIndex.h" #include "pxr/imaging/hd/primGather.h" #include "pxr/imaging/hd/renderDelegate.h" +#include "pxr/imaging/hd/renderPassState.h" #include "pxr/imaging/hd/repr.h" #include "pxr/imaging/hd/resourceRegistry.h" #include "pxr/imaging/hd/rprim.h" @@ -337,6 +339,13 @@ HdRenderIndex::_InsertRprim(TfToken const& typeId, rprim }; _rprimMap[rprimId] = std::move(info); + + // If the rprim is a basisCurves, put it in _basisCurvesList. + HdBasisCurves* basisCurves = dynamic_cast(rprim); + if (basisCurves) + { + _basisCurvesList.push_back(info); + } } void @@ -373,6 +382,21 @@ void HdRenderIndex::_RemoveRprim(SdfPath const &id) _tracker.RprimRemoved(id); + // If the rprim is a basisCurves, and it is in _basisCurvesList, + // remove it from _basisCurvesList. + HdBasisCurves* basisCurves = dynamic_cast(rprimInfo.rprim); + if (basisCurves) + { + for (auto it = _basisCurvesList.begin(); it != _basisCurvesList.end(); ++it) + { + if (it->rprim == rprimInfo.rprim) + { + _basisCurvesList.erase(it); + break; + } + } + } + // Ask delegate to actually delete the rprim rprimInfo.rprim->Finalize(_renderDelegate->GetRenderParam()); _renderDelegate->DestroyRprim(rprimInfo.rprim); @@ -432,7 +456,22 @@ HdRenderIndex::_RemoveRprimSubtree(const SdfPath &root, _tracker.RemoveInstancerRprimDependency(instancerId, id); } - _tracker.RprimRemoved(id); + _tracker.RprimRemoved(id); + + // If the rprim is a basisCurves, and it is in _basisCurvesList, + // remove it from _basisCurvesList. + HdBasisCurves* basisCurves = dynamic_cast(rprimInfo.rprim); + if (basisCurves) + { + for (auto it = _basisCurvesList.begin(); it != _basisCurvesList.end(); ++it) + { + if (it->rprim == rprimInfo.rprim) + { + _basisCurvesList.erase(it); + break; + } + } + } // Ask delegate to actually delete the rprim rprimInfo.rprim->Finalize(_renderDelegate->GetRenderParam()); @@ -512,6 +551,9 @@ HdRenderIndex::_Clear() _rprimIds.Clear(); _rprimPrimIdMap.clear(); + // Clear the _basisCurvesList. + _basisCurvesList.clear(); + // Clear S & B prims _sprimIndex.Clear(_tracker, _renderDelegate); _bprimIndex.Clear(_tracker, _renderDelegate); @@ -1377,6 +1419,125 @@ HdRenderIndex::EnqueueCollectionToSync(HdRprimCollection const &col) _collectionsToSync.push_back(col); } +void +HdRenderIndex::_SyncBasisCurves(TfTokenVector const& renderTags) +{ + if (!_basisCurvesList.empty()) + { + // Find the basisCurves that we need to update the camera information. + std::vector basisCurvesInSyncList; + for (auto const& rprimInfo : _basisCurvesList) + { + // Check if the basisCurves' renderTag is within the renderTags. If not, this curve will + // not be synced. + HdRprim* rprim = rprimInfo.rprim; + SdfPath const& rprimID = rprim->GetId(); + const HdDirtyBits bits = _tracker.GetRprimDirtyBits(rprimID); + TfToken primRenderTag = rprim->GetRenderTag(); + if(bits & HdChangeTracker::DirtyRenderTag) + // Update the render tag if needed. + primRenderTag = UpdateRenderTag(rprimID, bits); + // If the renderTag of the basisCurves is not in the list of renderTags, it means in the current + // sync we will not sync the basisCurves, so we don't need to update its camera information. + if (std::find(renderTags.begin(), renderTags.end(), primRenderTag) == renderTags.end()) + continue; + HdBasisCurves* basisCurves = dynamic_cast(rprim); + // Check if the curve requires update each frame. + if (basisCurves->NeedUpdateEachFrame(rprimInfo.sceneDelegate)) + { + basisCurvesInSyncList.push_back(basisCurves); + // Mark the curve as DirtyCamera. + _tracker.MarkRprimDirty(rprimInfo.rprim->GetId(), HdBasisCurves::DirtyCamera); + } + } + + if (!basisCurvesInSyncList.empty()) + { + // Get the WVP matrix and the viewport. + GfMatrix4d projectionMatrix; + GfMatrix4d worldViewMatrix; + GfVec4f viewport; + HdCamera* camera = nullptr; + if (IsSprimTypeSupported(HdTokens->camera)) { + camera = static_cast(GetSprim(HdPrimTypeTokens->camera, _activeCameraId)); + } + // If there is camera, get the matrix and viewport from the camera. + if (camera) { + // Initialize the cached render pass state. + // NOTE: Constructing and destroying HdRenderPassState will resulting processing glslfx + // redundantly, which is time-consuming. + static HdRenderPassStateSharedPtr renderPassState; + if (!renderPassState) + { + renderPassState = _renderDelegate->CreateRenderPassState(); + } + else + { + // Reset the renderPassState. + renderPassState->SetCamera(nullptr); + renderPassState->SetFraming({}); + renderPassState->SetOverrideWindowPolicy({}); + static const GfVec4d& initialViewport = { 0, 0, 1, 1 }; + renderPassState->SetViewport(initialViewport); + } + + if (renderPassState) + { + // Set the camera and viewport for render pass state. + if (_framing.IsValid()) { + renderPassState->SetCamera(camera); + renderPassState->SetFraming(_framing); + renderPassState->SetOverrideWindowPolicy(_overrideWindowPolicy); + } + else { + renderPassState->SetCamera(camera); + renderPassState->SetViewport(_viewport); + } + projectionMatrix = renderPassState->GetProjectionMatrix(); + worldViewMatrix = renderPassState->GetWorldToViewMatrix(); + const CameraUtilFraming& framing = renderPassState->GetFraming(); + viewport = renderPassState->GetViewport(); + if (framing.IsValid()) { + const GfRect2i& dataWindow = framing.dataWindow; + viewport = GfVec4f( + dataWindow.GetMinX(), + dataWindow.GetMinY(), + dataWindow.GetWidth(), + dataWindow.GetHeight()); + } + } + } + else + { + // If there is no camera, use the matrix and viewport which is set to the renderIndex. + projectionMatrix = _projectionMatrix; + worldViewMatrix = _worldToViewMatrix; + viewport = GfVec4f(_viewport.data()[0], + _viewport.data()[1], + _viewport.data()[2], + _viewport.data()[3]); + if (_framing.IsValid()) { + const GfRect2i& dataWindow = _framing.dataWindow; + viewport = GfVec4f( + dataWindow.GetMinX(), + dataWindow.GetMinY(), + dataWindow.GetWidth(), + dataWindow.GetHeight()); + } + } + + GfMatrix4d wvpMatrix = worldViewMatrix * projectionMatrix; + for (HdBasisCurves* basisCurves : basisCurvesInSyncList) + { + // We need to set the WVP matrix and the viewport size to the BasisCurves. They + // are used when we calculate screenSpaced accumulated length. + basisCurves->UpdateWVPMatrix(wvpMatrix); + basisCurves->UpdateViewport(viewport); + } + } + } +} + void HdRenderIndex::SyncAll(HdTaskSharedPtrVector *tasks, HdTaskContext *taskContext) @@ -1482,6 +1643,10 @@ HdRenderIndex::SyncAll(HdTaskSharedPtrVector *tasks, _rprimDirtyList.UpdateRenderTagsAndReprSelectors(taskRenderTags, reprSelectors); + // If the basiscurves has screenspaced style, we need to update the screenspaced accumulated + // length per frame. + _SyncBasisCurves(taskRenderTags); + // NOTE: GetDirtyRprims relies on up-to-date render tags; if render tags // are dirty, this call will sync render tags before compiling the dirty // list. This is outside of the usual sync order, but is necessary for now. @@ -1978,6 +2143,47 @@ HdRenderIndex::IsBprimTypeSupported(TfToken const& typeId) const return (std::find(supported.begin(), supported.end(), typeId) != supported.end()); } +void +HdRenderIndex::SetFraming(const CameraUtilFraming& framing) +{ + _framing = framing; +} + +void +HdRenderIndex::SetOverrideWindowPolicy( + const std::optional& policy) +{ + _overrideWindowPolicy = policy; +} + +void +HdRenderIndex::SetRenderViewport(GfVec4d const& viewport) +{ + _viewport = viewport; +} + +void +HdRenderIndex::SetCameraPath(SdfPath const& id) +{ + _activeCameraId = id; +} + +void +HdRenderIndex::SetCameraFramingState(GfMatrix4d const& worldToViewMatrix, + GfMatrix4d const& projectionMatrix, + GfVec4d const& viewport) +{ + if (!_activeCameraId.IsEmpty()) { + // If a camera handle was set, reset it. + _activeCameraId = SdfPath(); + } + + _worldToViewMatrix = worldToViewMatrix; + _projectionMatrix = projectionMatrix; + _viewport = viewport; + +} + void HdRenderIndex::_AppendDrawItems( const SdfPathVector &rprimIds, diff --git a/pxr/imaging/hd/renderIndex.h b/pxr/imaging/hd/renderIndex.h index 320b38c340..c187dd9d19 100644 --- a/pxr/imaging/hd/renderIndex.h +++ b/pxr/imaging/hd/renderIndex.h @@ -25,6 +25,8 @@ #include "pxr/imaging/hf/perfLog.h" +#include "pxr/imaging/cameraUtil/framing.h" + #include "pxr/usd/sdf/path.h" #include "pxr/base/gf/vec4i.h" @@ -35,6 +37,7 @@ #include #include #include +#include PXR_NAMESPACE_OPEN_SCOPE @@ -404,6 +407,42 @@ class HdRenderIndex final HD_API std::string GetInstanceName() const; + + /// Determines how the filmback of the camera is mapped into + /// the pixels of the render buffer and what pixels of the render + /// buffer will be rendered into. + HD_API + void SetFraming(const CameraUtilFraming& framing); + + /// Specifies whether to force a window policy when conforming + /// the frustum of the camera to match the display window of + /// the camera framing. + /// + /// If set to {false, ...}, the window policy of the specified camera + /// will be used. + /// + /// Note: std::pair is used instead of std::optional<...> + /// because the latter is only available in C++17 or later. + HD_API + void SetOverrideWindowPolicy( + const std::optional& policy); + + /// Set the viewport param on tasks. + /// + /// \deprecated Use SetFraming and SetRenderBufferSize instead. + HD_API + void SetRenderViewport(GfVec4d const& viewport); + + /// -- Scene camera -- + /// Set the camera param on tasks to a USD camera path. + HD_API + void SetCameraPath(SdfPath const& id); + + /// Set the camera matrix and viewport. + HD_API + void SetCameraFramingState(GfMatrix4d const& worldToViewMatrix, + GfMatrix4d const& projectionMatrix, + GfVec4d const& viewport); private: // The render index constructor is private so we can check @@ -485,6 +524,8 @@ class HdRenderIndex final HdSceneDelegate* sceneDelegate); void _Clear(); + void _SyncBasisCurves(TfTokenVector const& renderTags); + // ---------------------------------------------------------------------- // // Index State // ---------------------------------------------------------------------- // @@ -517,6 +558,8 @@ class HdRenderIndex final _RprimMap _rprimMap; Hd_SortedIds _rprimIds; + std::vector<_RprimInfo> _basisCurvesList; + _RprimPrimIDVector _rprimPrimIdMap; _TaskMap _taskMap; @@ -534,6 +577,15 @@ class HdRenderIndex final std::string _instanceName; + + CameraUtilFraming _framing; + std::optional _overrideWindowPolicy; + GfVec4d _viewport; + // Current active camera + SdfPath _activeCameraId; + + GfMatrix4d _worldToViewMatrix; + GfMatrix4d _projectionMatrix; // ---------------------------------------------------------------------- // // Sync State diff --git a/pxr/imaging/hd/sceneIndexAdapterSceneDelegate.cpp b/pxr/imaging/hd/sceneIndexAdapterSceneDelegate.cpp index 0de30d0d4c..264697ab37 100644 --- a/pxr/imaging/hd/sceneIndexAdapterSceneDelegate.cpp +++ b/pxr/imaging/hd/sceneIndexAdapterSceneDelegate.cpp @@ -835,8 +835,14 @@ HdSceneIndexAdapterSceneDelegate::GetBasisCurvesTopology(SdfPath const &id) wrap = wrapDataSource->GetTypedValue(0.0f); } + TfToken style = HdTokens->none; + HdTokenDataSourceHandle styleDataSource = bcTopologySchema.GetStyle(); + if (styleDataSource) { + style = styleDataSource->GetTypedValue(0.0f); + } + HdBasisCurvesTopology result( - type, basis, wrap, + type, basis, wrap, style, curveVertexCountsDataSource->GetTypedValue(0.0f), curveIndices); diff --git a/pxr/imaging/hd/tokens.h b/pxr/imaging/hd/tokens.h index 3b85717a2c..8ad7af5966 100644 --- a/pxr/imaging/hd/tokens.h +++ b/pxr/imaging/hd/tokens.h @@ -17,7 +17,11 @@ PXR_NAMESPACE_OPEN_SCOPE #define HD_TOKENS \ (accelerations) \ + (accumulatedLength) \ (adjacency) \ + (adjPoints1) \ + (adjPoints2) \ + (adjPoints3) \ (angularVelocities) \ (bboxLocalMin) \ (bboxLocalMax) \ @@ -33,6 +37,7 @@ PXR_NAMESPACE_OPEN_SCOPE (coordSysBindings) \ (cubic) \ (cullStyle) \ + (dashDot) \ (doubleSided) \ (dispatchCount) \ (displayColor) \ @@ -48,7 +53,9 @@ PXR_NAMESPACE_OPEN_SCOPE (edgeIndices) \ (elementCount) \ (elementsVisibility) \ + (endCapType) \ (extent) \ + (extrude) \ (faceColors) \ (filters) \ (full) \ @@ -68,11 +75,16 @@ PXR_NAMESPACE_OPEN_SCOPE (meshLight) \ (materialParams) \ (materialSyncMode) \ + (none) \ (nonlinearSampleCount) \ (nonperiodic) \ (normals) \ (params) \ (patchParam) \ + (pattern) \ + (patternPartCount) \ + (patternPeriod) \ + (patternScale) \ (periodic) \ (pinned) \ (points) \ @@ -86,10 +98,17 @@ PXR_NAMESPACE_OPEN_SCOPE (primitiveParam) \ (tessFactors) \ (quadInfo) \ + (renderPassState) \ (renderTags) \ (rightHanded) \ + (round) \ + (square) \ + (screenSpacePattern) \ + (screenSpaceDashDot) \ (segmented) \ (shadowLink) \ + (startCapType) \ + (style) \ (subdivTags) \ (taskState) \ (taskParams) \ @@ -98,6 +117,8 @@ PXR_NAMESPACE_OPEN_SCOPE (totalItemCount) \ (transform) \ (transformInverse) \ + (triangle) \ + (type) \ (velocities) \ (visibility) \ (widths) \ diff --git a/pxr/imaging/hd/unitTestDelegate.cpp b/pxr/imaging/hd/unitTestDelegate.cpp index 6caee27433..33a50d4370 100644 --- a/pxr/imaging/hd/unitTestDelegate.cpp +++ b/pxr/imaging/hd/unitTestDelegate.cpp @@ -242,6 +242,7 @@ HdUnitTestDelegate::AddBasisCurves(SdfPath const &id, VtVec3fArray const &normals, TfToken const &type, TfToken const &basis, + TfToken const &style, VtValue const &color, HdInterpolation colorInterpolation, VtValue const &opacity, @@ -257,7 +258,9 @@ HdUnitTestDelegate::AddBasisCurves(SdfPath const &id, _curves[id] = _Curves(points, curveVertexCounts, curveIndices, type, - basis); + basis, + HdTokens->nonperiodic, + style); _primvars[id] = { _Primvar(HdTokens->displayColor, @@ -765,6 +768,7 @@ HdUnitTestDelegate::GetBasisCurvesTopology(SdfPath const& id) return HdBasisCurvesTopology(curve.type, curve.basis, curve.wrap, + curve.style, curve.curveVertexCounts, curve.curveIndices); } @@ -1569,7 +1573,8 @@ HdUnitTestDelegate::AddGridWithFaceVaryingColor(SdfPath const &id, int nx, int n void HdUnitTestDelegate::AddCurves( SdfPath const &id, TfToken const &type, - TfToken const &basis, GfMatrix4f const &transform, + TfToken const &basis, TfToken const &style, + GfMatrix4f const &transform, HdInterpolation colorInterp, HdInterpolation widthInterp, bool authoredNormals, @@ -1654,7 +1659,7 @@ HdUnitTestDelegate::AddCurves( /*curveIndices=*/VtIntArray(), authNormals, type, - basis, + basis, style, color, colorInterp, VtValue(1.0f), HdInterpolationConstant, width, widthInterp, @@ -1981,20 +1986,20 @@ HdUnitTestDelegate::PopulateBasicTestSet() // curves { dmat.SetTranslate(GfVec3d(xPos, -3.0, 0.0)); - AddCurves(SdfPath("/curve1"), HdTokens->linear, TfToken(), GfMatrix4f(dmat), - HdInterpolationVertex, HdInterpolationVertex); + AddCurves(SdfPath("/curve1"), HdTokens->linear, TfToken(), HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); dmat.SetTranslate(GfVec3d(xPos, 0.0, 0.0)); - AddCurves(SdfPath("/curve2"), HdTokens->cubic, HdTokens->bezier, GfMatrix4f(dmat), - HdInterpolationVertex, HdInterpolationVertex); + AddCurves(SdfPath("/curve2"), HdTokens->cubic, HdTokens->bezier, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); dmat.SetTranslate(GfVec3d(xPos, 3.0, 0.0)); - AddCurves(SdfPath("/curve3"), HdTokens->cubic, HdTokens->bspline, GfMatrix4f(dmat), - HdInterpolationVertex, HdInterpolationConstant); + AddCurves(SdfPath("/curve3"), HdTokens->cubic, HdTokens->bspline, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationConstant); dmat.SetTranslate(GfVec3d(xPos, 6.0, 0.0)); - AddCurves(SdfPath("/curve4"), HdTokens->cubic, HdTokens->catmullRom, GfMatrix4f(dmat), - HdInterpolationVertex, HdInterpolationConstant); + AddCurves(SdfPath("/curve4"), HdTokens->cubic, HdTokens->catmullRom, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationConstant); xPos += 3.0; } @@ -2031,6 +2036,7 @@ HdUnitTestDelegate::PopulateInvalidPrimsSet() VtVec3fArray(), HdTokens->linear, TfToken(), + HdTokens->none, VtValue(GfVec3f(1)), HdInterpolationConstant, VtValue(1.0f), HdInterpolationConstant, VtValue(1.0f), HdInterpolationConstant); diff --git a/pxr/imaging/hd/unitTestDelegate.h b/pxr/imaging/hd/unitTestDelegate.h index ad5e859869..20cf6f9817 100644 --- a/pxr/imaging/hd/unitTestDelegate.h +++ b/pxr/imaging/hd/unitTestDelegate.h @@ -175,6 +175,7 @@ class HdUnitTestDelegate : public HdSceneDelegate VtVec3fArray const &normals, TfToken const &type, TfToken const &basis, + TfToken const& style, VtValue const &color, HdInterpolation colorInterpolation, VtValue const &opacity, @@ -186,6 +187,7 @@ class HdUnitTestDelegate : public HdSceneDelegate /// Add a basis curves prim containing two curves HD_API void AddCurves(SdfPath const &id, TfToken const &type, TfToken const &basis, + TfToken const &style, GfMatrix4f const &transform, HdInterpolation colorInterp=HdInterpolationConstant, HdInterpolation widthInterp=HdInterpolationConstant, @@ -457,9 +459,10 @@ class HdUnitTestDelegate : public HdSceneDelegate VtIntArray const &curveIndices, TfToken const &type, TfToken const &basis, - TfToken const &wrap = HdTokens->nonperiodic) : - points(points), curveVertexCounts(curveVertexCounts), - curveIndices(curveIndices), type(type), basis(basis), wrap(wrap) { } + TfToken const &wrap = HdTokens->nonperiodic, + TfToken const &style = HdTokens->none) : + points(points), curveVertexCounts(curveVertexCounts), + curveIndices(curveIndices), type(type), basis(basis), wrap(wrap), style(style) { } VtVec3fArray points; VtIntArray curveVertexCounts; @@ -467,6 +470,7 @@ class HdUnitTestDelegate : public HdSceneDelegate TfToken type; TfToken basis; TfToken wrap; + TfToken style; }; struct _Points { _Points() { } diff --git a/pxr/imaging/hdSt/CMakeLists.txt b/pxr/imaging/hdSt/CMakeLists.txt index 5f3e459c30..6733ed975b 100644 --- a/pxr/imaging/hdSt/CMakeLists.txt +++ b/pxr/imaging/hdSt/CMakeLists.txt @@ -184,6 +184,7 @@ pxr_library(hdSt plugInfo.json shaders/basisCurves.glslfx shaders/compute.glslfx + shaders/dashDotCurves.glslfx shaders/domeLight.glslfx shaders/edgeId.glslfx shaders/fallbackLighting.glslfx @@ -236,6 +237,33 @@ pxr_build_test(testHdStBasicDrawing ) endif() +pxr_install_test_dir( + SRC testenv/testHdStRPrimsAddRemove + DEST testHdStRPrimsAddRemove +) + +pxr_build_test(testHdStRPrimsAddRemove + LIBRARIES + hdSt + hd + garch + glf + + CPPFILES + testenv/testHdStRPrimsAddRemove.cpp +) + +pxr_register_test(testHdStRPrimsAddRemove + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testHdStRPrimsAddRemove --offscreen --addRemoveBasisCurves --write testHdStRPrimsAddRemove_BasisCurves.png" + IMAGE_DIFF_COMPARE + testHdStRPrimsAddRemove_BasisCurves.png + FAIL .05 + FAIL_PERCENT .03 + PERCEPTUAL + EXPECTED_RETURN_CODE 0 + TESTENV testHdStRPrimsAddRemove +) + if (X11_FOUND) pxr_build_test(testHdStBarAllocationLimit LIBRARIES diff --git a/pxr/imaging/hdSt/basisCurves.cpp b/pxr/imaging/hdSt/basisCurves.cpp index 8a8810367a..aa8eb6700f 100644 --- a/pxr/imaging/hdSt/basisCurves.cpp +++ b/pxr/imaging/hdSt/basisCurves.cpp @@ -25,6 +25,7 @@ #include "pxr/base/arch/hash.h" +#include "pxr/base/gf/matrix3f.h" #include "pxr/base/gf/matrix4d.h" #include "pxr/base/gf/matrix4f.h" #include "pxr/base/gf/vec2d.h" @@ -213,18 +214,26 @@ HdStBasisCurves::_UpdateDrawItem(HdSceneDelegate *sceneDelegate, } /* PRIMVAR */ - if (HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id)) { + bool dirtyPrimvar = HdChangeTracker::IsAnyPrimvarDirty(*dirtyBits, id); + bool dirtyTransform = (*dirtyBits & DirtyCamera); + if (dirtyPrimvar || dirtyTransform) { // XXX: curves don't use refined vertex primvars, however, // the refined renderpass masks the dirtiness of non-refined vertex // primvars, so we need to see refined dirty for updating coarse // vertex primvars if there is only refined reprs being updated. // we'll fix the change tracking in order to address this craziness. + // When primvar is dirty, we need to pull the value of dirty primvar. + // When camera is dirty, we also need to pull the value of the + // accumulated length. _PopulateVertexPrimvars( sceneDelegate, renderParam, drawItem, dirtyBits); - _PopulateVaryingPrimvars( - sceneDelegate, renderParam, drawItem, dirtyBits); - _PopulateElementPrimvars( - sceneDelegate, renderParam, drawItem, dirtyBits); + if (dirtyPrimvar) + { + _PopulateVaryingPrimvars( + sceneDelegate, renderParam, drawItem, dirtyBits); + _PopulateElementPrimvars( + sceneDelegate, renderParam, drawItem, dirtyBits); + } } // When we have multiple drawitems for the same prim we need to clean the @@ -273,6 +282,7 @@ HdStBasisCurves::_UpdateDrawItemGeometricShader( TfToken curveType = _topology->GetCurveType(); TfToken curveBasis = _topology->GetCurveBasis(); + TfToken curveStyle = _topology->GetCurveStyle(); bool supportsRefinement = _SupportsRefinement(_refineLevel); if (!supportsRefinement) { // XXX: Rendering non-linear (i.e., cubic) curves as linear segments @@ -288,49 +298,66 @@ HdStBasisCurves::_UpdateDrawItemGeometricShader( HdSt_BasisCurvesShaderKey::WIRE; HdSt_BasisCurvesShaderKey::NormalStyle normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - switch (desc.geomStyle) { - case HdBasisCurvesGeomStylePoints: + // Currently the dashDot, and screenSpaceDashDot is only + // valid when curveType is linear. + if (curveType == HdTokens->linear && curveStyle == HdTokens->dashDot) { - drawStyle = HdSt_BasisCurvesShaderKey::POINTS; + //Use dashDot shader if we have dashdot style. + drawStyle = HdSt_BasisCurvesShaderKey::DASHDOT; normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - break; } - case HdBasisCurvesGeomStyleWire: + else if(curveType == HdTokens->linear && curveStyle == HdTokens->screenSpaceDashDot) { - drawStyle = HdSt_BasisCurvesShaderKey::WIRE; + //Use screen space dashDot shader. + drawStyle = HdSt_BasisCurvesShaderKey::DASHDOTSS; normalStyle = HdSt_BasisCurvesShaderKey::HAIR; - break; } - case HdBasisCurvesGeomStylePatch: + else { - if (_SupportsRefinement(_refineLevel) && - _SupportsUserWidths(drawItem)) { - if (_SupportsUserNormals(drawItem)){ - drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; - normalStyle = HdSt_BasisCurvesShaderKey::ORIENTED; - } - else{ - if (_refineLevel > 2){ - normalStyle = HdSt_BasisCurvesShaderKey::ROUND; - drawStyle = HdSt_BasisCurvesShaderKey::HALFTUBE; - } - else if (_refineLevel > 1){ - normalStyle = HdSt_BasisCurvesShaderKey::ROUND; + switch (desc.geomStyle) { + case HdBasisCurvesGeomStylePoints: + { + drawStyle = HdSt_BasisCurvesShaderKey::POINTS; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + break; + } + case HdBasisCurvesGeomStyleWire: + { + drawStyle = HdSt_BasisCurvesShaderKey::WIRE; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + break; + } + case HdBasisCurvesGeomStylePatch: + { + if (_SupportsRefinement(_refineLevel) && + _SupportsUserWidths(drawItem)) { + if (_SupportsUserNormals(drawItem)) { drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + normalStyle = HdSt_BasisCurvesShaderKey::ORIENTED; } - else{ - drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; - normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + else { + if (_refineLevel > 2) { + normalStyle = HdSt_BasisCurvesShaderKey::ROUND; + drawStyle = HdSt_BasisCurvesShaderKey::HALFTUBE; + } + else if (_refineLevel > 1) { + normalStyle = HdSt_BasisCurvesShaderKey::ROUND; + drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + } + else { + drawStyle = HdSt_BasisCurvesShaderKey::RIBBON; + normalStyle = HdSt_BasisCurvesShaderKey::HAIR; + } } } + break; + } + default: + { + TF_CODING_ERROR("Invalid geomstyle in basis curve %s repr desc.", + GetId().GetText()); + } } - break; - } - default: - { - TF_CODING_ERROR("Invalid geomstyle in basis curve %s repr desc.", - GetId().GetText()); - } } TF_DEBUG(HD_RPRIM_UPDATED). @@ -452,7 +479,11 @@ HdStBasisCurves::_InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) *dirtyBits |= DirtyIndices; } } - + if (!(_customDirtyBitsInUse & DirtyCamera)) { + _customDirtyBitsInUse |= DirtyCamera; + // DirtyCamera is not set at first. It is only set when a new frame + // starts. + } // Set up drawing coord instance primvars. drawingCoord->SetInstancePrimvarBaseIndex( HdStBasisCurves::InstancePrimvar); @@ -571,6 +602,16 @@ HdStBasisCurves::_UpdateMaterialTagsForAllReprs(HdSceneDelegate *sceneDelegate, "(%s) - Updating material tags for draw items of all reprs.\n", GetId().GetText()); + // If the curve has dash-dot pattern, its material tag must be translucent. + bool materialTagIsTranslucent = false; + TfToken curveType = _topology->GetCurveType(); + TfToken curveStyle = _topology->GetCurveStyle(); + if (curveType == HdTokens->linear && + (curveStyle == HdTokens->dashDot || curveStyle == HdTokens->screenSpaceDashDot)) + { + materialTagIsTranslucent = true; + } + for (auto const& reprPair : _reprs) { const TfToken &reprToken = reprPair.first; _BasisCurvesReprConfig::DescArray const &descs = @@ -584,7 +625,10 @@ HdStBasisCurves::_UpdateMaterialTagsForAllReprs(HdSceneDelegate *sceneDelegate, HdStDrawItem *drawItem = static_cast( repr->GetDrawItem(drawItemIndex++)); - HdStSetMaterialTag(sceneDelegate, renderParam, drawItem, + if(materialTagIsTranslucent) + HdStSetMaterialTag(renderParam, drawItem, HdStMaterialTagTokens->translucent); + else + HdStSetMaterialTag(sceneDelegate, renderParam, drawItem, this->GetMaterialId(), _displayOpacity, _occludedSelectionShowsThrough); } @@ -826,6 +870,377 @@ void ProcessVertexOrVaryingPrimvar( } } // anonymous namespace +GfVec2f NDCToScreen(GfVec2f NDC, GfVec2f screenDim) +{ + float const* ndcData = NDC.data(); + float const* screenDimData = screenDim.data(); + return GfVec2f(ndcData[0] * screenDimData[0] * 0.5f + screenDimData[0] * 0.5f, + ndcData[1] * screenDimData[1] * 0.5f + screenDimData[1] * 0.5f); +} + +void HdStBasisCurves::_CalculateAccumulatedLength(HdSceneDelegate* sceneDelegate, const VtVec3fArray& points, + const VtIntArray& curveVertexCounts, bool screenSpaced, VtVec2fArray& accumulatedLengths) +{ + // Initialize the accumulatedLengths. + float accumulatedLength = 0.0f; + + // The count of points. + size_t pointCount = points.size(); + // The count of curves. + size_t curveCount = curveVertexCounts.size(); + + // Initialize the maximum vertex Index of the first curve. + int currentCurveMaxVertexIndex = pointCount - 1; + if (curveCount > 0) + { + currentCurveMaxVertexIndex = curveVertexCounts[0] - 1; + } + // Initialize the index of the first curve. + int currentCurveIndex = 0; + + // Initialize the lastPoint. + float const* lastPointData = points[0].data(); + + GfMatrix4d transform; + if (screenSpaced) + { + // For screen space length, we need to get the transform for each point. + transform = sceneDelegate->GetTransform(GetId()); + transform = transform * _wvpMatrix; + } + + // Calculate the accumulated length. + for (size_t pointIndex = 1; pointIndex < pointCount; ++pointIndex) + { + if (pointIndex > currentCurveMaxVertexIndex) + { + // Move to next curve. + ++currentCurveIndex; + if (currentCurveIndex < curveCount) + { + currentCurveMaxVertexIndex += curveVertexCounts[currentCurveIndex]; + // Reset accumulatedLength. + accumulatedLength = 0; + } + else + break; + lastPointData = points[pointIndex].data(); + } + else + { + // Each point requires two accumulated length. First is the accumlated length at + // the start of the segment, second is the accumulated length at the end of the + // segment. + GfVec2f currentLengths; + currentLengths[0] = accumulatedLength; + // Calculate the length from last point to current point, and accumulate it to the + // accumulated length. + float const* pointData = points[pointIndex].data(); + if (screenSpaced) + { + // For screen spaced calculation, we need to convert the position to the screen + // space position first. + GfVec4f NDCPos1 = GfVec4f(lastPointData[0], lastPointData[1], lastPointData[2], 1.0f) * transform; + NDCPos1 /= NDCPos1.data()[3]; + GfVec4f NDCPos2 = GfVec4f(pointData[0], pointData[1], pointData[2], 1.0f) * transform; + NDCPos2 /= NDCPos2.data()[3]; + GfVec2f SCRPos1 = NDCToScreen(GfVec2f(NDCPos1.data()[0], NDCPos1.data()[1]), + GfVec2f(_viewport.data()[2], _viewport.data()[3])); + GfVec2f SCRPos2 = NDCToScreen(GfVec2f(NDCPos2.data()[0], NDCPos2.data()[1]), + GfVec2f(_viewport.data()[2], _viewport.data()[3])); + accumulatedLength += (SCRPos2 - SCRPos1).GetLength(); + } + else + { + // World space calculation, we can directly calculate the length. + GfVec3f worldPos1(lastPointData[0], lastPointData[1], lastPointData[2]); + GfVec3f worldPos2(pointData[0], pointData[1], pointData[2]); + accumulatedLength += (worldPos2 - worldPos1).GetLength(); + } + currentLengths[1] = accumulatedLength; + accumulatedLengths.push_back(currentLengths); + accumulatedLengths.push_back(currentLengths); + accumulatedLengths.push_back(currentLengths); + accumulatedLengths.push_back(currentLengths); + lastPointData = pointData; + } + } +} + +void HdStBasisCurves::_CalculateVertexInfo(const VtVec3fArray& points, + const VtIntArray& curveVertexCounts, VtVec3fArray& styleCurvePoints, + VtVec3fArray& styleCurveAdjPoints1, VtVec3fArray& styleCurveAdjPoints2, + VtVec3fArray& styleCurveAdjPoints3, VtFloatArray& styleCurveExtrude) +{ + // The count of orginal points. + size_t pointCount = points.size(); + // The count of curves. + size_t curveCount = curveVertexCounts.size(); + + // Initialize the maximum vertex Index of the first curve. + int currentCurveMaxVertexIndex = -1; + int currentCurveMinVertexIndex = -1; + // Initialize the index of the first curve. + int currentCurveIndex = 0; + + // Calculate the vertex information. + // For each line segment, we will add four points: the previous adjacent point, the first point, + // the second point, and the next adjacent point. At each point, we will also record the other + // three points of the line segment. We record the three points in AdjPoint1-3. + // If the line segment is a start segment of a curve, the previous adjacent point will be the + // first point. If the line segment is the end segment of a curve, the next adjacent point will + // be the second point. + // We use extrude to identify the role of the point: 0.0 for previous adjacent point, 1.0 for + // first point, 2.0 for second point, and 3.0 for next adjacent point. + // Example: A curve which has 4 points, 1,2,3,4. Then the vertex information will be like below: + // First line segment: + // Points: Pos1, Pos1, Pos2, Pos3 + // AdjPoint1: Pos1, Pos1, Pos1, Pos1 + // AdjPoint2: Pos2, Pos2, Pos1, Pos1 + // AdjPoint3: Pos3, Pos3, Pos3, Pos2 + // Extrude: 0.0, 1.0, 2.0, 3.0 + // Second line segment: + // Points: Pos1, Pos2, Pos3, Pos4 + // AdjPoint1: Pos2, Pos1, Pos1, Pos1 + // AdjPoint2: Pos3, Pos3, Pos2, Pos2 + // AdjPoint3: Pos4, Pos4, Pos4, Pos3 + // Extrude: 0.0, 1.0, 2.0, 3.0 + // Third line segment: + // Points: Pos2, Pos3, Pos4, Pos4 + // AdjPoint1: Pos3, Pos2, Pos2, Pos2 + // AdjPoint2: Pos4, Pos4, Pos3, Pos3 + // AdjPoint3: Pos4, Pos4, Pos4, Pos4 + // Extrude: 0.0, 1.0, 2.0, 3.0 + for (int pointIndex = 0; pointIndex < pointCount; ++pointIndex) + { + if (pointIndex > currentCurveMaxVertexIndex) + { + // This is the first point of the current curve. + // Reset the currentCurveMinVertexIndex and currentCurveMaxVertexIndex. + currentCurveMinVertexIndex = currentCurveMaxVertexIndex + 1; + if (curveCount > 0) + { + currentCurveMaxVertexIndex += curveVertexCounts[currentCurveIndex]; + ++currentCurveIndex; + } + else + currentCurveMaxVertexIndex = pointCount - 1; + + // For this line segment, because this point is the first point of the curve, + // it doesn't have previous point. It can only be the first point of the current + // line segment. We will first add this point as the previous adjacent point, and + // then add this point again as the first point of the line segment. + styleCurvePoints.push_back(points[pointIndex]); + styleCurvePoints.push_back(points[pointIndex]); + + // The adjacent points record the three other points of the line segment. + styleCurveAdjPoints1.push_back(points[pointIndex]); + styleCurveAdjPoints1.push_back(points[pointIndex]); + styleCurveAdjPoints2.push_back(points[pointIndex + 1]); + styleCurveAdjPoints2.push_back(points[pointIndex + 1]); + if ((pointIndex + 1) == currentCurveMaxVertexIndex) + { + styleCurveAdjPoints3.push_back(points[pointIndex + 1]); + styleCurveAdjPoints3.push_back(points[pointIndex + 1]); + } + else + { + styleCurveAdjPoints3.push_back(points[pointIndex + 2]); + styleCurveAdjPoints3.push_back(points[pointIndex + 2]); + } + + // The extrude is 0.0 and 1.0. + styleCurveExtrude.push_back(0.0); + styleCurveExtrude.push_back(1.0); + } + else if (pointIndex == currentCurveMaxVertexIndex) + { + // This is the last point of the current curve. + // For this line segment, because this point is the last point of the curve, + // it doesn't have next point. It can only be the second point of the current + // line segment. We will first add this point as the second point, and then + // add this point again as the next adjacent point of the line segment. + styleCurvePoints.push_back(points[pointIndex]); + styleCurvePoints.push_back(points[pointIndex]); + + // The adjacent points record the three other points of the line segment. + if (pointIndex - 1 == currentCurveMinVertexIndex) + { + styleCurveAdjPoints1.push_back(points[pointIndex - 1]); + styleCurveAdjPoints1.push_back(points[pointIndex - 1]); + } + else + { + styleCurveAdjPoints1.push_back(points[pointIndex - 2]); + styleCurveAdjPoints1.push_back(points[pointIndex - 2]); + } + styleCurveAdjPoints2.push_back(points[pointIndex - 1]); + styleCurveAdjPoints2.push_back(points[pointIndex - 1]); + styleCurveAdjPoints3.push_back(points[pointIndex]); + styleCurveAdjPoints3.push_back(points[pointIndex]); + + // The extrude is 2.0 and 3.0. + styleCurveExtrude.push_back(2.0); + styleCurveExtrude.push_back(3.0); + } + else + { + // This is one of the middle point of the curve. It can be the second point of the + // previous line segment, and the first point of the next line segment. + // So we add this point and next point as the second point and next adjacent point + // of the previous line. And add the previous point and this point as the previous + // adjacent and first point of the next line. + styleCurvePoints.push_back(points[pointIndex]); + styleCurvePoints.push_back(points[pointIndex + 1]); + styleCurvePoints.push_back(points[pointIndex - 1]); + styleCurvePoints.push_back(points[pointIndex]); + + // The adjacent points record the three other points of the line segment. + if (pointIndex - 1 == currentCurveMinVertexIndex) + { + styleCurveAdjPoints1.push_back(points[pointIndex - 1]); + styleCurveAdjPoints1.push_back(points[pointIndex - 1]); + } + else + { + styleCurveAdjPoints1.push_back(points[pointIndex - 2]); + styleCurveAdjPoints1.push_back(points[pointIndex - 2]); + } + styleCurveAdjPoints1.push_back(points[pointIndex]); + styleCurveAdjPoints1.push_back(points[pointIndex - 1]); + styleCurveAdjPoints2.push_back(points[pointIndex - 1]); + styleCurveAdjPoints2.push_back(points[pointIndex - 1]); + styleCurveAdjPoints2.push_back(points[pointIndex + 1]); + styleCurveAdjPoints2.push_back(points[pointIndex + 1]); + styleCurveAdjPoints3.push_back(points[pointIndex + 1]); + styleCurveAdjPoints3.push_back(points[pointIndex]); + if ((pointIndex + 1) == currentCurveMaxVertexIndex) + { + styleCurveAdjPoints3.push_back(points[pointIndex + 1]); + styleCurveAdjPoints3.push_back(points[pointIndex + 1]); + } + else + { + styleCurveAdjPoints3.push_back(points[pointIndex + 2]); + styleCurveAdjPoints3.push_back(points[pointIndex + 2]); + } + + // The extrude is 2.0 and 3.0 for the previous line, and 0.0 and 1.0 for the next line. + styleCurveExtrude.push_back(2.0); + styleCurveExtrude.push_back(3.0); + styleCurveExtrude.push_back(0.0); + styleCurveExtrude.push_back(1.0); + } + } +} + +template +static bool _AssignArrayValues(const VtIntArray& curveVertexCounts, + const VtArray& inputArray, VtArray& outputArray) +{ + // The count of curves. + size_t curveCount = curveVertexCounts.size(); + // The count of orginal values. + size_t inputCount = inputArray.size(); + // If there is no curveVertexCounts, there is only one curve. So the first and the + // last vertex will generate 2 new vertices each, and the middle vertex will generate + // 4 new vertices each. Totally there will be 4 + (inputCount - 2) * 4 new vertices. + // If there is curveVertexCounts, for each curve, the start and end vertex will + // generate 2 new vertices each, and the middle vertices will generate 4 new vertices + // each, so there will be totally curveCount * 4 + (inputCount - curveCount * 2) * 4 + // new vertices. + size_t outputCount = (curveCount == 0) ? 4 + (inputCount - 2) * 4 : + curveCount * 4 + (inputCount - curveCount * 2) * 4; + outputArray.reserve(outputCount); + + // Initialize the index of the first curve. + size_t currentCurveIndex = 0; + // Initialize the minimum vertex Index of the next curve. This is used to indicate if + // a curve is finished. + size_t nextCurveMinVertexIndex = 0; + for (size_t intputIndex = 0; intputIndex < inputCount; ++intputIndex) + { + if (intputIndex == nextCurveMinVertexIndex) + { + // This is the first value of a new curve. + // Reset the nextCurveMinVertexIndex. + if (curveCount > 0) + { + nextCurveMinVertexIndex += curveVertexCounts[currentCurveIndex]; + ++currentCurveIndex; + if (currentCurveIndex > curveCount) + { + TF_CODING_ERROR("The count of primvar values doesn't match \ + the curveVertexCounts property."); + break; + } + } + else + nextCurveMinVertexIndex = inputCount; + + // The first vertex will be duplicated with two instances. So the vertex + // primvar will also be duplicated. + outputArray.push_back(inputArray[intputIndex]); + outputArray.push_back(inputArray[intputIndex]); + } + else if (intputIndex == nextCurveMinVertexIndex - 1) + { + // This is the last value of the current curve. + // The last vertex will be duplicated with two instances. So the vertex + // primvar will also be duplicated. + outputArray.push_back(inputArray[intputIndex]); + outputArray.push_back(inputArray[intputIndex]); + } + else + { + // The middle vertex will be duplicated with four instances. So the vertex + // primvar will also be duplicated. + outputArray.push_back(inputArray[intputIndex]); + outputArray.push_back(inputArray[intputIndex]); + outputArray.push_back(inputArray[intputIndex]); + outputArray.push_back(inputArray[intputIndex]); + } + } + if (currentCurveIndex != curveCount || nextCurveMinVertexIndex != inputCount) + { + TF_CODING_ERROR("The count of primvar values doesn't match \ + the curveVertexCounts property."); + return false; + } + return true; +} + +static VtValue _AssignValues(VtValue& values, + const VtIntArray& curveVertexCounts) +{ + if(!values.IsArrayValued()) + return values; + else + { + // We will handle float3 primvars such as color and normal, and float primvars + // such as width. We will not handle the other types of primvars. + if (values.IsHolding()) + { + const VtVec3fArray& float3Array = values.Get(); + VtVec3fArray newFloat3Array; + _AssignArrayValues(curveVertexCounts, float3Array, newFloat3Array); + return VtValue(newFloat3Array); + } + else if (values.IsHolding()) + { + const VtFloatArray& floatArray = values.Get(); + VtFloatArray newFloatArray; + _AssignArrayValues(curveVertexCounts, floatArray, newFloatArray); + return VtValue(newFloatArray); + } + else + { + TF_CODING_ERROR("We don't support this type of vertex primvars, for a dash-dot BasisCurves."); + return values; + } + } +} + void HdStBasisCurves::_PopulateVertexPrimvars(HdSceneDelegate *sceneDelegate, HdRenderParam *renderParam, @@ -866,31 +1281,153 @@ HdStBasisCurves::_PopulateVertexPrimvars(HdSceneDelegate *sceneDelegate, &computations); for (HdPrimvarDescriptor const& primvar: primvars) { - if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) - continue; - - // TODO: We don't need to pull primvar metadata every time a value - // changes, but we need support from the delegate. + // AccumulatedLength is required if the curve has style. + if (primvar.name == HdTokens->accumulatedLength && + _topology->GetCurveStyle() != HdTokens->none) + { + // If the camera is dirty, it means the curve requires screen space accumulated length. + // In this case, we will calculate the length per frame. + bool screenSpacedLength = ((*dirtyBits & HdBasisCurves::DirtyCamera) != 0); + // The accumulated length is dirty, so it requires calculation. + bool dirtyAccuLength = HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->accumulatedLength); + + if (screenSpacedLength | dirtyAccuLength) + { + // Should have topology. + if (!_topology) + { + TF_CODING_ERROR("No topology set for BasisCurve %s", + id.GetName().c_str()); + break; + } - // Having a null topology is possible, but shouldn't happen when there - // are points - if (!_topology) { - if (primvar.name == HdTokens->points) { - TF_CODING_ERROR("No topology set for BasisCurve %s", - id.GetName().c_str()); - break; + // If the primvar is accumulated length, we will calculated the length here. + // First get the position for all points. + VtValue value = GetPrimvar(sceneDelegate, HdTokens->points); + value = VtValue::Cast(value); + if (value.IsEmpty()) + continue; + VtVec3fArray points = value.Get(); + + VtVec2fArray accumulatedLengths; + // Then get the curve information. + VtIntArray curveVertexCounts = _topology->GetCurveVertexCounts(); + + // Calculate the accumulatedLengths. + _CalculateAccumulatedLength(sceneDelegate, points, curveVertexCounts, + screenSpacedLength, accumulatedLengths); + ProcessVertexOrVaryingPrimvar(id, primvar.name, + HdInterpolationVertex, VtValue(accumulatedLengths), _topology, &sources); } + } + else if (!HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, primvar.name)) + { continue; - } - - //assert name not in range.bufferArray.GetResources() - VtValue value = GetPrimvar(sceneDelegate, primvar.name); - if (!value.IsEmpty()) { - ProcessVertexOrVaryingPrimvar(id, primvar.name, - HdInterpolationVertex, value, _topology, &sources); + } + else + { + // TODO: We don't need to pull primvar metadata every time a value + // changes, but we need support from the delegate. + // If the curve has style, the points must be specially handled. And we also need to + // add other vertex information. + if (primvar.name == HdTokens->points && _topology->GetCurveStyle() != HdTokens->none) + { + // Having a null topology is possible, but shouldn't happen when there + // are points + if (!_topology) + { + TF_CODING_ERROR("No topology set for BasisCurve %s", + id.GetName().c_str()); + break; + } + // Get the original points value. + VtValue value = GetPrimvar(sceneDelegate, HdTokens->points); + value = VtValue::Cast(value); + if (!value.IsEmpty()) { + VtVec3fArray points = value.Get(); + VtVec3fArray styleCurvePoints; + VtVec3fArray styleCurveAdjPoints1; + VtVec3fArray styleCurveAdjPoints2; + VtVec3fArray styleCurveAdjPoints3; + VtFloatArray styleCurveExtrude; + + // Then get the curve information. + VtIntArray curveVertexCounts = _topology->GetCurveVertexCounts(); + + // Calculate the vertex information. + _CalculateVertexInfo(points, curveVertexCounts, styleCurvePoints, + styleCurveAdjPoints1, styleCurveAdjPoints2, styleCurveAdjPoints3, + styleCurveExtrude); + + // Add the points source. + sources.push_back( + std::make_shared>( + _topology, styleCurvePoints, id, HdTokens->points, + HdInterpolationVertex, GfVec3f(1, 0, 0), + HdGetValueTupleType(VtValue(styleCurvePoints)).type)); + + // Add the first adjacent information source. + sources.push_back( + std::make_shared>( + _topology, styleCurveAdjPoints1, id, HdTokens->adjPoints1, + HdInterpolationVertex, GfVec3f(1, 0, 0), + HdGetValueTupleType(VtValue(styleCurveAdjPoints1)).type)); + + // Add the second adjacent information source. + sources.push_back( + std::make_shared>( + _topology, styleCurveAdjPoints2, id, HdTokens->adjPoints2, + HdInterpolationVertex, GfVec3f(1, 0, 0), + HdGetValueTupleType(VtValue(styleCurveAdjPoints2)).type)); + + // Add the third adjacent information source. + sources.push_back( + std::make_shared>( + _topology, styleCurveAdjPoints3, id, HdTokens->adjPoints3, + HdInterpolationVertex, GfVec3f(1, 0, 0), + HdGetValueTupleType(VtValue(styleCurveAdjPoints3)).type)); + + // Add the extrude information source. + sources.push_back( + std::make_shared>( + _topology, styleCurveExtrude, id, HdTokens->extrude, + HdInterpolationVertex, 0.0, + HdGetValueTupleType(VtValue(styleCurveExtrude)).type)); + } + else + continue; + } + else + { + // Having a null topology is possible, but shouldn't happen when there + // are points + if (!_topology) { + if (primvar.name == HdTokens->points) { + TF_CODING_ERROR("No topology set for BasisCurve %s", + id.GetName().c_str()); + break; + } + continue; + } - if (primvar.name == HdTokens->displayOpacity) { - _displayOpacity = true; + //assert name not in range.bufferArray.GetResources() + VtValue value = GetPrimvar(sceneDelegate, primvar.name); + if (!value.IsEmpty()) { + if (_topology->GetCurveStyle() != HdTokens->none) + { + // If the curveStyle is dashdot, we need to expand the vertex primivars + // so that each final vertex will have a corresponding value. + VtIntArray curveVertexCounts = _topology->GetCurveVertexCounts(); + value = _AssignValues(value, curveVertexCounts); + } + + ProcessVertexOrVaryingPrimvar(id, primvar.name, + HdInterpolationVertex, value, _topology, &sources); + + if (primvar.name == HdTokens->displayOpacity) { + _displayOpacity = true; + } + } } } } @@ -1143,6 +1680,32 @@ HdStBasisCurves::_PopulateElementPrimvars(HdSceneDelegate *sceneDelegate, } } +bool +HdStBasisCurves::NeedUpdateEachFrame(HdSceneDelegate* sceneDelegate) const +{ + // The basisCurves need screen spaced accumulated length, if the style is screenSpaceDashDot. + if (!_topology) + { + // If topology is not available, we directly check the value of curve style. + VtValue screenSpacePatternValue = sceneDelegate->Get(GetId(), HdTokens->screenSpacePattern); + bool screenSpacePattern = false; + screenSpacePatternValue = VtValue::Cast(screenSpacePatternValue); + if (!screenSpacePatternValue.IsEmpty()) + screenSpacePattern = screenSpacePatternValue.Get(); + + return screenSpacePattern; + } + else + { + TfToken curveType = _topology->GetCurveType(); + TfToken curveStyle = _topology->GetCurveStyle(); + if (curveType == HdTokens->linear && curveStyle == HdTokens->screenSpaceDashDot) + return true; + } + + return false; +} + static bool HdSt_HasResource(HdStDrawItem* drawItem, const TfToken& resourceToken){ // Check for authored resource, we could leverage dirtyBits here as an diff --git a/pxr/imaging/hdSt/basisCurves.h b/pxr/imaging/hdSt/basisCurves.h index 655b9b77c5..daccb1760f 100644 --- a/pxr/imaging/hdSt/basisCurves.h +++ b/pxr/imaging/hdSt/basisCurves.h @@ -81,6 +81,9 @@ class HdStBasisCurves final: public HdBasisCurves HDST_API TfTokenVector const & GetBuiltinPrimvarNames() const override; + HD_API + bool NeedUpdateEachFrame(HdSceneDelegate* sceneDelegate) const override; + protected: HDST_API void _InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) override; @@ -122,8 +125,8 @@ class HdStBasisCurves final: public HdBasisCurves }; enum DirtyBits : HdDirtyBits { - DirtyIndices = HdChangeTracker::CustomBitsBegin, - DirtyHullIndices = (DirtyIndices << 1), + DirtyBase = HdBasisCurves::DirtyCamera, + DirtyHullIndices = (DirtyBase << 1), DirtyPointsIndices = (DirtyHullIndices << 1) }; @@ -158,6 +161,14 @@ class HdStBasisCurves final: public HdBasisCurves void _UpdateMaterialTagsForAllReprs(HdSceneDelegate *sceneDelegate, HdRenderParam *renderParam); + void _CalculateAccumulatedLength(HdSceneDelegate* sceneDelegate, const VtVec3fArray& points, + const VtIntArray& curveVertexCounts, bool screenSpaced, VtVec2fArray& accumulatedLengths); + + void _CalculateVertexInfo(const VtVec3fArray& points, const VtIntArray& curveVertexCounts, + VtVec3fArray& styleCurvePoints, VtVec3fArray& styleCurveAdjPoints1, + VtVec3fArray& styleCurveAdjPoints2, VtVec3fArray& styleCurveAdjPoints3, + VtFloatArray& styleCurveExtrude); + HdSt_BasisCurvesTopologySharedPtr _topology; HdTopology::ID _topologyId; HdDirtyBits _customDirtyBitsInUse; diff --git a/pxr/imaging/hdSt/basisCurvesComputations.cpp b/pxr/imaging/hdSt/basisCurvesComputations.cpp index ee4e618a62..297956698f 100644 --- a/pxr/imaging/hdSt/basisCurvesComputations.cpp +++ b/pxr/imaging/hdSt/basisCurvesComputations.cpp @@ -29,7 +29,12 @@ HdSt_BasisCurvesIndexBuilderComputation::GetBufferSpecs( HdBufferSpecVector *specs) const { // index buffer - if(!_forceLines && _topology->GetCurveType() == HdTokens->cubic) { + if (_topology->GetCurveStyle() != HdTokens->none) + { + specs->emplace_back(HdTokens->indices, + HdTupleType{ HdTypeInt32Vec3, 1 }); + } + else if(!_forceLines && _topology->GetCurveType() == HdTokens->cubic) { specs->emplace_back(HdTokens->indices, HdTupleType{HdTypeInt32Vec4, 1}); } @@ -103,7 +108,7 @@ HdSt_BasisCurvesIndexBuilderComputation::_BuildLinesIndexArray() } HdSt_BasisCurvesIndexBuilderComputation::IndexAndPrimIndex -HdSt_BasisCurvesIndexBuilderComputation::_BuildLineSegmentIndexArray() +HdSt_BasisCurvesIndexBuilderComputation::_BuildLineSegmentIndexArray(bool needAdjInfo) { // Note: This is similiar to the GL_LINE_STRIP and GL_LINE_LOOP primitive // modes where each pair of adjacent vertices form a line. @@ -116,7 +121,10 @@ HdSt_BasisCurvesIndexBuilderComputation::_BuildLineSegmentIndexArray() basis == HdTokens->centripetalCatmullRom) && wrap != HdTokens->pinned; + // The indices when we don't need adjacent information. std::vector indices; + // The indices when we need adjacent information. + std::vector indicesAdj; // primIndices stores the curve index that generated each line segment. std::vector primIndices; const VtArray vertexCounts = _topology->GetCurveVertexCounts(); @@ -125,53 +133,83 @@ HdSt_BasisCurvesIndexBuilderComputation::_BuildLineSegmentIndexArray() int curveIndex = 0; // Index of next curve to emit // For each curve TF_FOR_ALL(itCounts, vertexCounts) { - int v0 = vertexIndex; - int v1; - // Store first vert index incase we are wrapping - const int firstVert = v0; - ++ vertexIndex; - for(int i = 1;i < *itCounts; ++i) { - v1 = vertexIndex; - ++ vertexIndex; - if (!skipFirstAndLastSegs || (i > 1 && i < (*itCounts)-1)) { - indices.push_back(GfVec2i(v0, v1)); - // Map this line segment back to the curve it came from - primIndices.push_back(curveIndex); + if (needAdjInfo) + { + int maxVertexIndex = vertexIndex + *itCounts - 1; + for (int i = vertexIndex; i < maxVertexIndex; ++i) { + // For each line segment, it will be converted to one quad. So + // we add two triangle indices. + int currentSegmentStart = i * 4; + indicesAdj.push_back(GfVec3i(currentSegmentStart, currentSegmentStart + 1, + currentSegmentStart + 2)); + indicesAdj.push_back(GfVec3i(currentSegmentStart + 2, currentSegmentStart + 1, + currentSegmentStart + 3)); } - v0 = v1; + vertexIndex = maxVertexIndex; } - if (periodic) { - indices.push_back(GfVec2i(v0, firstVert)); - primIndices.push_back(curveIndex); + else + { + // The first vertex of the segment. + int v0 = vertexIndex; + // The second vertex of the segment. + int v1; + // Store first vert index incase we are wrapping + const int firstVert = v0; + ++vertexIndex; + for (int i = 1; i < *itCounts; ++i) { + v1 = vertexIndex; + ++vertexIndex; + if (!skipFirstAndLastSegs || (i > 1 && i < (*itCounts) - 1)) { + indices.push_back(GfVec2i(v0, v1)); + // Map this line segment back to the curve it came from + primIndices.push_back(curveIndex); + } + v0 = v1; + } + if (periodic) { + indices.push_back(GfVec2i(v0, firstVert)); + primIndices.push_back(curveIndex); + } + ++curveIndex; } - ++curveIndex; } VtVec2iArray finalIndices(indices.size()); + VtVec3iArray finalIndicesAdj(indicesAdj.size()); // If have topology has indices set, map the generated indices // with the given indices. if (!_topology->HasIndices()) { - std::copy(indices.begin(), indices.end(), finalIndices.begin()); + if (needAdjInfo) + std::copy(indicesAdj.begin(), indicesAdj.end(), finalIndicesAdj.begin()); + else + std::copy(indices.begin(), indices.end(), finalIndices.begin()); } else { - VtIntArray const &curveIndices = _topology->GetCurveIndices(); - size_t lineCount = indices.size(); - int maxIndex = curveIndices.size() - 1; - - for (size_t lineNum = 0; lineNum < lineCount; ++lineNum) + if (needAdjInfo) { - const GfVec2i &line = indices[lineNum]; + TF_CODING_ERROR("Indices is set for styled BasisCurve"); + } + else + { + VtIntArray const& curveIndices = _topology->GetCurveIndices(); + size_t lineCount = needAdjInfo ? indicesAdj.size() : indices.size(); + int maxIndex = curveIndices.size() - 1; - int i0 = std::min(line[0], maxIndex); - int i1 = std::min(line[1], maxIndex); + for (size_t lineNum = 0; lineNum < lineCount; ++lineNum) + { + const GfVec2i& line = indices[lineNum]; - int v0 = curveIndices[i0]; - int v1 = curveIndices[i1]; + int i0 = std::min(line[0], maxIndex); + int i1 = std::min(line[1], maxIndex); - finalIndices[lineNum].Set(v0, v1); + int v0 = curveIndices[i0]; + int v1 = curveIndices[i1]; + + finalIndices[lineNum].Set(v0, v1); + } } } @@ -180,7 +218,8 @@ HdSt_BasisCurvesIndexBuilderComputation::_BuildLineSegmentIndexArray() primIndices.end(), finalPrimIndices.begin()); - return IndexAndPrimIndex(VtValue(finalIndices), VtValue(finalPrimIndices)); + return needAdjInfo ? IndexAndPrimIndex(VtValue(finalIndicesAdj), VtValue(finalPrimIndices)) : + IndexAndPrimIndex(VtValue(finalIndices), VtValue(finalPrimIndices)); } HdSt_BasisCurvesIndexBuilderComputation::IndexAndPrimIndex @@ -405,7 +444,7 @@ HdSt_BasisCurvesIndexBuilderComputation::Resolve() if (_topology->GetCurveWrap() == HdTokens->segmented) { result = _BuildLinesIndexArray(); } else { - result = _BuildLineSegmentIndexArray(); + result = _BuildLineSegmentIndexArray(_topology->GetCurveStyle() != HdTokens->none); } } diff --git a/pxr/imaging/hdSt/basisCurvesComputations.h b/pxr/imaging/hdSt/basisCurvesComputations.h index 0a83314ab9..e0e712e2b9 100644 --- a/pxr/imaging/hdSt/basisCurvesComputations.h +++ b/pxr/imaging/hdSt/basisCurvesComputations.h @@ -57,7 +57,7 @@ class HdSt_BasisCurvesIndexBuilderComputation : public HdComputedBufferSource { }; private: IndexAndPrimIndex _BuildLinesIndexArray(); - IndexAndPrimIndex _BuildLineSegmentIndexArray(); + IndexAndPrimIndex _BuildLineSegmentIndexArray(bool needAdjInfo); IndexAndPrimIndex _BuildCubicIndexArray(); HdBasisCurvesTopology *_topology; diff --git a/pxr/imaging/hdSt/basisCurvesShaderKey.cpp b/pxr/imaging/hdSt/basisCurvesShaderKey.cpp index 405f4a39b5..8549832aba 100644 --- a/pxr/imaging/hdSt/basisCurvesShaderKey.cpp +++ b/pxr/imaging/hdSt/basisCurvesShaderKey.cpp @@ -1,5 +1,5 @@ // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. @@ -19,6 +19,8 @@ TF_REGISTRY_FUNCTION(TfEnum) { TF_ADD_ENUM_NAME(HdSt_BasisCurvesShaderKey::WIRE); TF_ADD_ENUM_NAME(HdSt_BasisCurvesShaderKey::RIBBON); TF_ADD_ENUM_NAME(HdSt_BasisCurvesShaderKey::HALFTUBE); + TF_ADD_ENUM_NAME(HdSt_BasisCurvesShaderKey::DASHDOT); + TF_ADD_ENUM_NAME(HdSt_BasisCurvesShaderKey::DASHDOTSS); }; TF_REGISTRY_FUNCTION(TfEnum) { @@ -31,6 +33,7 @@ TF_REGISTRY_FUNCTION(TfEnum) { TF_DEFINE_PRIVATE_TOKENS( _tokens, ((baseGLSLFX, "basisCurves.glslfx")) + ((dashDotGLSLFX, "dashDotCurves.glslfx")) // curve data ((curvesCommonData, "Curves.CommonData")) @@ -93,9 +96,13 @@ TF_DEFINE_PRIVATE_TOKENS( ((curvesFragmentRibbonOriented, "Curves.Fragment.Ribbon.Oriented")) ((curvesFragmentHair, "Curves.Fragment.Hair")) + ((curvesDashDotFactorSS, "DashDotFactor.ScreenSpace")) + ((curvesDashDotFactorNoSS, "DashDotFactor.NoScreenSpace")) + // main for all the shader stages ((curvesVertexPatch, "Curves.Vertex.Patch")) ((curvesVertexWire, "Curves.Vertex.Wire")) + ((curvesVertexDashDot, "DashDot.Vertex")) ((curvesTessControlLinearPatch, "Curves.TessControl.Linear.Patch")) ((curvesTessControlCubicWire, "Curves.TessControl.Cubic.Wire")) @@ -116,6 +123,7 @@ TF_DEFINE_PRIVATE_TOKENS( ((curvesFragmentWire, "Curves.Fragment.Wire")) ((curvesFragmentPatch, "Curves.Fragment.Patch")) + ((curvesFragmentDashDot, "DashDot.Fragment")) // instancing related mixins ((instancing, "Instancing.Transform")) @@ -153,14 +161,17 @@ HdSt_BasisCurvesShaderKey::HdSt_BasisCurvesShaderKey( bool pointsShadingEnabled, bool hasMetalTessellation) : useMetalTessellation(false) - , glslfx(_tokens->baseGLSLFX) { bool drawThick = (drawStyle == HdSt_BasisCurvesShaderKey::HALFTUBE) || (drawStyle == HdSt_BasisCurvesShaderKey::RIBBON); + bool dashDot = (drawStyle == HdSt_BasisCurvesShaderKey::DASHDOT) || + (drawStyle == HdSt_BasisCurvesShaderKey::DASHDOTSS); bool cubic = (type == HdTokens->cubic); bool linear = (type == HdTokens->linear); TF_VERIFY(cubic || linear); + glslfx = dashDot ? _tokens->dashDotGLSLFX : _tokens->baseGLSLFX; + // The order of the clauses below matters! if (drawStyle == HdSt_BasisCurvesShaderKey::POINTS) { primType = HdSt_GeometricShader::PrimitiveType::PRIM_POINTS; @@ -172,7 +183,12 @@ HdSt_BasisCurvesShaderKey::HdSt_BasisCurvesShaderKey( } else if (drawThick){ primType = HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES; - } else { + } else if (dashDot){ + // We need the adjacent information if the line has style. + primType = + HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE; + } else + { primType = HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINES; } @@ -180,19 +196,25 @@ HdSt_BasisCurvesShaderKey::HdSt_BasisCurvesShaderKey( bool oriented = normalStyle == HdSt_BasisCurvesShaderKey::ORIENTED; - // skip Metal tessellation for linear points and wire curves. + // skip Metal tessellation for linear points, wire or styled curves. bool const skipTessLinear = linear && (drawStyle == HdSt_BasisCurvesShaderKey::POINTS || - drawStyle == HdSt_BasisCurvesShaderKey::WIRE); + drawStyle == HdSt_BasisCurvesShaderKey::WIRE || + drawStyle == HdSt_BasisCurvesShaderKey::DASHDOT); useMetalTessellation = hasMetalTessellation && !(skipTessLinear); uint8_t vsIndex = 0; VS[vsIndex++] = _tokens->instancing; - VS[vsIndex++] = drawThick ? _tokens->curvesVertexPatch - : _tokens->curvesVertexWire; - VS[vsIndex++] = oriented ? _tokens->curvesVertexNormalOriented + if(drawStyle == HdSt_BasisCurvesShaderKey::DASHDOT) + VS[vsIndex++] = _tokens->curvesDashDotFactorNoSS; + else if (drawStyle == HdSt_BasisCurvesShaderKey::DASHDOTSS) + VS[vsIndex++] = _tokens->curvesDashDotFactorSS; + VS[vsIndex++] = dashDot ? _tokens->curvesVertexDashDot : + (drawThick ? _tokens->curvesVertexPatch + : _tokens->curvesVertexWire); + VS[vsIndex++] = oriented ? _tokens->curvesVertexNormalOriented : _tokens->curvesVertexNormalImplicit; if (isPrimTypePoints) { // Add mixins that allow for picking and sel highlighting of points. @@ -250,6 +272,8 @@ HdSt_BasisCurvesShaderKey::HdSt_BasisCurvesShaderKey( switch(drawStyle) { case HdSt_BasisCurvesShaderKey::POINTS: case HdSt_BasisCurvesShaderKey::WIRE: + case HdSt_BasisCurvesShaderKey::DASHDOT: + case HdSt_BasisCurvesShaderKey::DASHDOTSS: { TCS[0] = TfToken(); TES[0] = TfToken(); @@ -492,7 +516,13 @@ HdSt_BasisCurvesShaderKey::HdSt_BasisCurvesShaderKey( _tokens->topVisFallbackFS; - if (drawStyle == HdSt_BasisCurvesShaderKey::WIRE || + if (drawStyle == HdSt_BasisCurvesShaderKey::DASHDOT || + drawStyle == HdSt_BasisCurvesShaderKey::DASHDOTSS) + { + FS[fsIndex++] = _tokens->curvesFragmentDashDot; + FS[fsIndex++] = TfToken(); + } + else if (drawStyle == HdSt_BasisCurvesShaderKey::WIRE || drawStyle == HdSt_BasisCurvesShaderKey::POINTS) { FS[fsIndex++] = _tokens->curvesFragmentWire; FS[fsIndex++] = TfToken(); diff --git a/pxr/imaging/hdSt/basisCurvesShaderKey.h b/pxr/imaging/hdSt/basisCurvesShaderKey.h index d99f1e6227..4a7fff604b 100644 --- a/pxr/imaging/hdSt/basisCurvesShaderKey.h +++ b/pxr/imaging/hdSt/basisCurvesShaderKey.h @@ -42,7 +42,9 @@ struct HdSt_BasisCurvesShaderKey : public HdSt_ShaderKey POINTS, // Draws only the control vertices. WIRE, // Draws as lines or isolines, tessellated along length RIBBON, // Draws as patch, tessellated along length only - HALFTUBE // Draws as patch, displaced into a half tube shape + HALFTUBE, // Draws as patch, displaced into a half tube shape + DASHDOT, // Draws as a dash doted style curve. + DASHDOTSS // Draws as a screen-spaced dash doted style curve. }; enum NormalStyle{ @@ -68,6 +70,7 @@ struct HdSt_BasisCurvesShaderKey : public HdSt_ShaderKey TfToken const *GetTES() const override { return TES; } TfToken const *GetPTCS() const override { return PTCS; } TfToken const *GetPTVS() const override { return PTVS; } + TfToken const* GetGS() const override { return GS; } TfToken const *GetFS() const override { return FS; } HdSt_GeometricShader::PrimitiveType GetPrimitiveType() const override { @@ -81,11 +84,12 @@ struct HdSt_BasisCurvesShaderKey : public HdSt_ShaderKey HdSt_GeometricShader::PrimitiveType primType; bool useMetalTessellation; TfToken glslfx; - TfToken VS[7]; + TfToken VS[8]; TfToken TCS[7]; TfToken TES[12]; TfToken PTCS[9]; TfToken PTVS[14]; + TfToken GS[2]; TfToken FS[8]; }; diff --git a/pxr/imaging/hdSt/codeGen.cpp b/pxr/imaging/hdSt/codeGen.cpp index 047c657547..16286b9d71 100644 --- a/pxr/imaging/hdSt/codeGen.cpp +++ b/pxr/imaging/hdSt/codeGen.cpp @@ -2176,6 +2176,11 @@ HdSt_CodeGen::Compile(HdStResourceRegistry*const registry) << " vec2 localST = tessST;\n"; break; } + case HdSt_GeometricShader::PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE: + { + _procGS << "void ProcessPrimvarsOut(int index) {\n"; + break; + } default: // points, basis curves // do nothing. no additional code needs to be generated. ; diff --git a/pxr/imaging/hdSt/geometricShader.cpp b/pxr/imaging/hdSt/geometricShader.cpp index 32c7809194..f720ba436c 100644 --- a/pxr/imaging/hdSt/geometricShader.cpp +++ b/pxr/imaging/hdSt/geometricShader.cpp @@ -199,6 +199,7 @@ HdSt_GeometricShader::GetPrimitiveIndexSize() const case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES: case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES: case PrimitiveType::PRIM_VOLUME: + case PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE: primIndexSize = 3; break; case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES: @@ -270,6 +271,7 @@ HdSt_GeometricShader::GetNumPrimitiveVertsForGeometryShader() const case PrimitiveType::PRIM_MESH_REFINED_TRIQUADS: case PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES: case PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES: + case PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE: case PrimitiveType::PRIM_MESH_BSPLINE: case PrimitiveType::PRIM_MESH_BOXSPLINETRIANGLE: // for patches with tesselation, input to GS is still a series of tris @@ -301,6 +303,7 @@ HdSt_GeometricShader::GetHgiPrimitiveType() const case PrimitiveType::PRIM_BASIS_CURVES_LINES: primitiveType = HgiPrimitiveTypeLineList; break; + case PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE: case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES: case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES: case PrimitiveType::PRIM_MESH_COARSE_TRIQUADS: diff --git a/pxr/imaging/hdSt/geometricShader.h b/pxr/imaging/hdSt/geometricShader.h index 4a69824b7b..413d19cb53 100644 --- a/pxr/imaging/hdSt/geometricShader.h +++ b/pxr/imaging/hdSt/geometricShader.h @@ -46,6 +46,7 @@ class HdSt_GeometricShader : public HdStShaderCode { enum class PrimitiveType { PRIM_POINTS, PRIM_BASIS_CURVES_LINES, // when linear (or) non-refined cubic + PRIM_BASIS_CURVES_LINES_HAS_STYLE, // when the curve has line style PRIM_BASIS_CURVES_LINEAR_PATCHES, // refined linear curves PRIM_BASIS_CURVES_CUBIC_PATCHES, // refined cubic curves PRIM_MESH_COARSE_TRIANGLES, @@ -67,6 +68,7 @@ class HdSt_GeometricShader : public HdStShaderCode { static inline bool IsPrimTypeBasisCurves(PrimitiveType primType) { return (primType == PrimitiveType::PRIM_BASIS_CURVES_LINES || + primType == PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE || primType == PrimitiveType::PRIM_BASIS_CURVES_CUBIC_PATCHES || primType == PrimitiveType::PRIM_BASIS_CURVES_LINEAR_PATCHES); } diff --git a/pxr/imaging/hdSt/glConversions.cpp b/pxr/imaging/hdSt/glConversions.cpp index 136053f231..14b3ea18a4 100644 --- a/pxr/imaging/hdSt/glConversions.cpp +++ b/pxr/imaging/hdSt/glConversions.cpp @@ -183,6 +183,7 @@ HdStGLConversions::GetPrimitiveMode( case PrimitiveType::PRIM_BASIS_CURVES_LINES: primMode = GL_LINES; break; + case PrimitiveType::PRIM_BASIS_CURVES_LINES_HAS_STYLE: case PrimitiveType::PRIM_MESH_COARSE_TRIANGLES: case PrimitiveType::PRIM_MESH_REFINED_TRIANGLES: case PrimitiveType::PRIM_MESH_COARSE_TRIQUADS: diff --git a/pxr/imaging/hdSt/shaders/basisCurves.glslfx b/pxr/imaging/hdSt/shaders/basisCurves.glslfx index 4b973a03bc..7cd252f80a 100644 --- a/pxr/imaging/hdSt/shaders/basisCurves.glslfx +++ b/pxr/imaging/hdSt/shaders/basisCurves.glslfx @@ -1,7 +1,7 @@ -- glslfx version 0.1 // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. diff --git a/pxr/imaging/hdSt/shaders/dashDotCurves.glslfx b/pxr/imaging/hdSt/shaders/dashDotCurves.glslfx new file mode 100644 index 0000000000..3c0e09d88c --- /dev/null +++ b/pxr/imaging/hdSt/shaders/dashDotCurves.glslfx @@ -0,0 +1,895 @@ +-- glslfx version 0.1 + +// +// Copyright 2024 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. +// +// ----------------------------------------------------------------------------- +// The algorithm is based on the paper "Shader-Based Antialiased, Dashed, Stroked +// Polylines" by Nicolas P. Rougier[1], 2013 +// ----------------------------------------------------------------------------- +// Copyright (c) 2013 Nicolas P. Rougier. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY NICOLAS P. ROUGIER ''AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL NICOLAS P. ROUGIER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// The views and conclusions contained in the software and documentation are +// those of the authors and should not be interpreted as representing official +// policies, either expressed or implied, of Nicolas P. Rougier. +// ----------------------------------------------------------------------------- + +--- This is what an import might look like. +--- #import $TOOLS/hdSt/shaders/dashDotCurves.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 +#import $TOOLS/hdSt/shaders/basisCurves.glslfx + +--- -------------------------------------------------------------------------- +-- glsl DashDotFactor.NoScreenSpace + +// Get the factor from the unit of the accumulated length to a screen pixel. +// The unit of the accumulated length is the world unit when the style is not +// screen-spaced. So we use the ratio between length of the line on the screen +// and the length in the world as the ToScreenFactor. +float ToScreenFactor(vec2 SCRxy0, vec2 SCRxy1, vec4 peye0, vec4 peye1) +{ + return distance(SCRxy1, SCRxy0) / distance(peye1, peye0); +} + +--- -------------------------------------------------------------------------- +-- glsl DashDotFactor.ScreenSpace + +// Get the factor from the unit of the accumulated length to a screen pixel. +// The unit of the accumulated length is the screen pixel when the style is +// screen-spaced. So ToScreenFactor is 1. +float ToScreenFactor(vec2 SCRxy0, vec2 SCRxy1, vec4 peye0, vec4 peye1) +{ + return 1.0; +} + +--- -------------------------------------------------------------------------- +-- layout DashDot.Vertex + +[ + ["out block", "CurveFragmentData", "outData", + ["vec4", "Peye"], + ["vec2", "UVCoord"], + ["vec2", "UVCoordBorder", "", "flat"], + ["int", "SegmentFlag", "", "flat"], + ["float", "Discard", "", "flat"], + ["float", "Factor"] + ] +] + +--- -------------------------------------------------------------------------- +-- glsl DashDot.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)); + +// Clip a line segment. +float ClipSegmentToPlane(REF(thread, vec4) pl, REF(thread, vec4) p0, REF(thread, vec4) p1, REF(thread, vec4) pr, vec4 plane) +{ + float dist0 = dot(p0, plane); + float dist1 = dot(p1, plane); + bool inside0 = dist0 >= 0.0; + bool inside1 = dist1 >= 0.0; + + // If both p0 and p1 are outside of plane, set clip flag, + // the whole segment will be discarded by fragment shader + if (!inside0 && !inside1) + { + return 1.0; + } + + // Clipped by the place + if (inside0 != inside1) + { + float denominator = dist0 - dist1; + + // avoiding divided by zero + if (abs(denominator) < 1e-30) + { + denominator = 1e-30; + } + + float t = dist0 / denominator; + + // If left-p0 is clipped by plane, set left neighbor to p0, + // and compute clipped coordinate of P0 + if (inside1) + { + pl = p0; + p0 = mix(p0, p1, t); + } + // If p1-right is clipped by plane, set right neighbor to p1, + // and compute clipped coordinate of P1 + else + { + pr = p1; + p1 = mix(p0, p1, t); + } + } + + return 0.0; +} + +// Convert NDC size to screen size. +vec2 NDCToScreen(vec2 NDC, vec2 screenDim) +{ + return (NDC * screenDim * 0.5 + screenDim * 0.5); +} + +// Convert screen size to NDC size. +vec2 screenToNDC(vec2 SCR, vec2 invViewportPixelSize) +{ + return (2.0 * SCR * invViewportPixelSize - 1.0); +} + +// Compute the Z value in NDC space. +float computeZ(vec2 SCRxy0, vec2 SCRxy1, vec2 vSCR, vec4 Hv0, vec4 Hv1, float Hz, vec2 invViewportPixelSize) +{ + // project the vertex onto the line + vec2 SCRvdir = vSCR - SCRxy0; + vec2 SCRldir = SCRxy1 - SCRxy0; + float SCRlen2 = dot(SCRldir, SCRldir); + if (SCRlen2 > 0.001) + { + // the projected vertex on the line + vec2 SCRproj = mix(SCRxy0, SCRxy1, dot(SCRvdir, SCRldir) / SCRlen2); + vec2 Hproj = screenToNDC(SCRproj, invViewportPixelSize); + + // the z for the projected vertex on the line + vec3 Hldir = Hv1.xyz - Hv0.xyz; + if (abs(Hldir.x) < 1e-30) + { + if (abs(Hldir.y) < 1e-30) + return Hz; + else + return mix(Hv0.z, Hv1.z, (Hproj.y - Hv0.y) / Hldir.y); + } + else + { + return mix(Hv0.z, Hv1.z, (Hproj.x - Hv0.x) / Hldir.x); + } + } + else + { + // The line is 0-length in screen.. + return Hz; + } +} + +void main(void) +{ + const MAT4 worldToViewMatrix = GetWorldToViewMatrix(); + const MAT4 projectionMatrix = GetProjectionMatrix(); + MAT4 transform = ApplyInstanceTransform(HdGet_transform()); + vec4 point = vec4(HdGet_points().xyz, 1); + + vec4 adjPoint1 = vec4(HdGet_adjPoints1(), 1); + vec4 adjPoint2 = vec4(HdGet_adjPoints2(), 1); + vec4 adjPoint3 = vec4(HdGet_adjPoints3(), 1); + vec4 viewport = HdGet_viewport(); + float extrude = HdGet_extrude(); + vec2 accumulatedLength = HdGet_accumulatedLength(); + + mat4 wvMatrix = worldToViewMatrix * transform; + mat4 wvpMatrix = projectionMatrix * wvMatrix; + + vec4 peye0, peye1; + vec4 Hv0, Hv1, Hvl, Hvr; + if (extrude < 0.5) + { + Hvl = wvpMatrix * point; + peye0 = wvMatrix * adjPoint1; + peye1 = wvMatrix * adjPoint2; + Hv0 = wvpMatrix * adjPoint1; + Hv1 = wvpMatrix * adjPoint2; + Hvr = wvpMatrix * adjPoint3; + } + else if (extrude < 1.5) + { + Hvl = wvpMatrix * adjPoint1; + peye0 = wvMatrix * point; + peye1 = wvMatrix * adjPoint2; + Hv0 = wvpMatrix * point; + Hv1 = wvpMatrix * adjPoint2; + Hvr = wvpMatrix * adjPoint3; + } + else if (extrude < 2.5) + { + Hvl = wvpMatrix * adjPoint1; + peye0 = wvMatrix * adjPoint2; + peye1 = wvMatrix * point; + Hv0 = wvpMatrix * adjPoint2; + Hv1 = wvpMatrix * point; + Hvr = wvpMatrix * adjPoint3; + } + else + { + Hvl = wvpMatrix * adjPoint1; + peye0 = wvMatrix * adjPoint2; + peye1 = wvMatrix * adjPoint3; + Hv0 = wvpMatrix * adjPoint2; + Hv1 = wvpMatrix * adjPoint3; + Hvr = wvpMatrix * point; + } + + vec4 Position; + vec2 UVCoord; + float Discard = 0.0; + + // Clip the line segment to the near plane to decide if the line will be discarded. + vec4 nearPlane = vec4(0.0, 0.0, 1.0, 1.0); + Discard = ClipSegmentToPlane(Hvl, Hv0, Hv1, Hvr, nearPlane); + + Hv0 = Hv0 / Hv0.w; + Hv1 = Hv1 / Hv1.w; + Hvl = Hvl / Hvl.w; + Hvr = Hvr / Hvr.w; + + //compute inverse of window size + vec2 screenDim = vec2(viewport.z, viewport.w); + vec2 invViewportPixelSize = 1.0 / screenDim; + + //For ortho projection, no need to divide by w + //but for perspective projection, divide by w needed + vec2 NDCxyl = Hvl.xy; + vec2 NDCxy0 = Hv0.xy; + vec2 NDCxy1 = Hv1.xy; + vec2 NDCxyr = Hvr.xy; + + //compute screen coordinate + vec2 SCRxyl = NDCToScreen(NDCxyl, screenDim); + vec2 SCRxy0 = NDCToScreen(NDCxy0, screenDim); + vec2 SCRxy1 = NDCToScreen(NDCxy1, screenDim); + vec2 SCRxyr = NDCToScreen(NDCxyr, screenDim); + + // If the screen coordinate of the two points are too close, we will ignore this segment. + const float lengthThreshold = 0.01; + if (distance(SCRxy1, SCRxy0) < lengthThreshold) + { + Discard = 1.0; + } + + float w = ceil(1.25 + HdGet_widths(0)) * 0.5; + + // 0: A middle segment. + // 1: The start segment. + // 2: The end segment. + // 3: Both a start segment and end segment. + int SegmentFlag = 0; + + vec2 v0Dist = vec2(0.0, 0.0); + vec2 v1Dist = vec2(0.0, 0.0); + + float v0IsBroken = 0.0; + float v1IsBroken = 0.0; + float sinAngle0; + float sinAngle1; + vec2 brokenOffsetL = vec2(0.0, 0.0); + vec2 brokenOffsetR = vec2(0.0, 0.0); + + float uOffsetL = 0.0; + float uOffsetR = 0.0; + + float joinDistanceL = 0.0; + float joinDistanceR = 0.0; + + // restrict the angle between n and n1 to cos(89.90), + // to avoid divided by zero error caused by angle -> 90 degree + float cosHalfVertexAngleLimit = 0.99619469809174553229501040247389; + const float cosAngle89_90 = 0.00174532836589830883577820272085; + const float normalizeThreshold = 0.0000001; + const float delta = 0.01; + + if (length(SCRxy0 - SCRxyl) > delta) + { + // vl and v0 is different, it means this segment is not a start segment. + // So v0 is a join. + vec2 t0 = normalize(SCRxy0 - SCRxyl); + vec2 n0 = vec2(-t0.y, t0.x); + + vec2 t1 = normalize(SCRxy1 - SCRxy0); + vec2 n1 = vec2(-t1.y, t1.x); + + brokenOffsetL = t1; + + if (length(n0 + n1) >= normalizeThreshold) + { + vec2 n = normalize(n0 + n1); + if (dot(n0, n1) < -0.9999) + { + n = t1; + } + + float cosAngle = abs(dot(n, n1)); + + if (cosAngle < cosAngle89_90) + { + cosAngle = cosAngle89_90; + } + + if (cosAngle < cosHalfVertexAngleLimit) + { + v0IsBroken = 1.0; + sinAngle0 = sqrt(1.0 - cosAngle * cosAngle); + } + + //compute the dispacement + joinDistanceL = w / cosAngle; + + v0Dist = joinDistanceL * n; + + uOffsetL = dot(v0Dist - (w * n1), t1); + } + else + { + joinDistanceL = w; + v0Dist = w * n1; + } + } + else + { + // The start segment. + SegmentFlag = 1; + } + + if (length(SCRxy1 - SCRxyr) > delta) + { + // v1 and vr is different, it means this segment is not an end segment. + // So v1 is a join. + vec2 t0 = normalize(SCRxy1 - SCRxy0); + vec2 n0 = vec2(-t0.y, t0.x); + + vec2 t1 = normalize(SCRxyr - SCRxy1); + vec2 n1 = vec2(-t1.y, t1.x); + + brokenOffsetR = t0; + + if (length(n0 + n1) >= normalizeThreshold) + { + vec2 n = normalize(n0 + n1); + if (dot(n0, n1) < -0.9999) + { + n = t1; + } + + //compute the dispacement + float cosAngle = abs(dot(n, n1)); + + if (cosAngle < cosAngle89_90) + { + cosAngle = cosAngle89_90; + } + + if (cosAngle < cosHalfVertexAngleLimit) + { + v1IsBroken = 1.0; + sinAngle1 = sqrt(1.0 - cosAngle * cosAngle); + } + + joinDistanceR = w / cosAngle; + + v1Dist = joinDistanceR * n; + + uOffsetR = dot(v1Dist - (w * n0), t0); + } + else + { + joinDistanceR = w; + v1Dist = w * n0; + } + } + else + { + // The end segment. + SegmentFlag += 2; + } + + //line dir and normal dir for this line segment + vec2 lineDir = normalize(SCRxy1 - SCRxy0); + vec2 normalDir = vec2(-lineDir.y, lineDir.x); + + // The ratio between the unit of accumulated length and the screen pixel. + float toScreenFactor = ToScreenFactor(SCRxy0, SCRxy1, peye0, peye1); + // The reciprocal pf the toScreenFactor. It is used to convert the screen + // unit to the unit of the accumulated length. + float reciprocal = 1.0 / toScreenFactor; + + vec2 vSCR, vNDC; + float zNDC; + float UCoord; + + vec2 UVCoordBorder = vec2(0.0, 0.0); + // The world space accumulated length. + UVCoordBorder = vec2(accumulatedLength.x, accumulatedLength.y); + + if (extrude < 0.5) + { + // Calculate the position of the first vertex of the start edge. + if (SegmentFlag == 0 || SegmentFlag == 2) + { + // The start edge is an join. + vSCR = SCRxy0 - v0Dist; + if (v0IsBroken > 0) + { + UCoord = UVCoordBorder.x - uOffsetL * reciprocal; + if (uOffsetL < 0) + { + //offset vertex 0 + vSCR -= joinDistanceL / sinAngle0 * brokenOffsetL; + UCoord -= ((joinDistanceL / sinAngle0) * reciprocal); + } + } + else + { + //continuous + UCoord = UVCoordBorder.x; + } + } + else + { + // The start edge is a cap. + vSCR = SCRxy0 - w * normalDir - w * lineDir; + UCoord = UVCoordBorder.x - w * reciprocal; + } + + //convert to NDC coordinate + vNDC = screenToNDC(vSCR, invViewportPixelSize); + zNDC = computeZ(SCRxy0, SCRxy1, vSCR, Hv0, Hv1, Hv0.z, invViewportPixelSize); + + //convert to homogeneous coordinate + Position = vec4(vNDC, zNDC, Hv0.w); + UVCoord = vec2(UCoord, -w); + } + else if (extrude < 1.5) + { + // Calculate the position of the second vertex of the start edge. + if (SegmentFlag == 0 || SegmentFlag == 2) + { + // The start edge is an join. + vSCR = SCRxy0 + v0Dist; + if (v0IsBroken > 0) + { + UCoord = UVCoordBorder.x + uOffsetL * reciprocal; + if (uOffsetL >= 0) + { + //offset vertex 0 + vSCR -= joinDistanceL / sinAngle0 * brokenOffsetL; + UCoord -= ((joinDistanceL / sinAngle0) * reciprocal); + } + } + else + { + //continuous + UCoord = UVCoordBorder.x; + } + } + else + { + // The start edge is a cap. + vSCR = SCRxy0 + w * normalDir - w * lineDir; + UCoord = UVCoordBorder.x - w * reciprocal; + } + + //convert to NDC coordinate + vNDC = screenToNDC(vSCR, invViewportPixelSize); + zNDC = computeZ(SCRxy0, SCRxy1, vSCR, Hv0, Hv1, Hv0.z, invViewportPixelSize); + + //convert to homogeneous coordinate + Position = vec4(vNDC, zNDC, Hv0.w); + UVCoord = vec2(UCoord, w); + } + else if (extrude < 2.5) + { + // Calculate the position of the first vertex of the end edge. + if (SegmentFlag == 0 || SegmentFlag == 1) + { + // The end edge is an join. + vSCR = SCRxy1 - v1Dist; + if (v1IsBroken > 0) + { + UCoord = UVCoordBorder.y - uOffsetR * reciprocal; + if (uOffsetR >= 0) + { + //offset vertex 0 + vSCR += joinDistanceR / sinAngle1 * brokenOffsetR; + UCoord += ((joinDistanceR / sinAngle1) * reciprocal); + } + } + else + { + //continuous + UCoord = UVCoordBorder.y; + } + } + else + { + // The end edge is a cap. + vSCR = SCRxy1 + w * (lineDir - normalDir); + UCoord = UVCoordBorder.y + w * reciprocal; + } + + //convert to NDC coordinate + vNDC = screenToNDC(vSCR, invViewportPixelSize); + zNDC = computeZ(SCRxy0, SCRxy1, vSCR, Hv0, Hv1, Hv1.z, invViewportPixelSize); + + //convert to homogeneous coordinate + Position = vec4(vNDC, zNDC, Hv1.w); + UVCoord = vec2(UCoord, -w); + } + else + { + // Calculate the position of the second vertex of the end edge. + if (SegmentFlag == 0 || SegmentFlag == 1) + { + // The end edge is an join. + vSCR = SCRxy1 + v1Dist; + if (v1IsBroken > 0) + { + UCoord = UVCoordBorder.y + uOffsetR * reciprocal; + if (uOffsetR < 0) + { + //offset vertex 0 + vSCR += joinDistanceR / sinAngle1 * brokenOffsetR; + UCoord += ((joinDistanceR / sinAngle1) * reciprocal); + } + } + else + { + //continuous + UCoord = UVCoordBorder.y; + } + } + else + { + // The end edge is a cap. + vSCR = SCRxy1 + w * (lineDir + normalDir); + UCoord = UVCoordBorder.y + w * reciprocal; + } + + //convert to NDC coordinate + vNDC = screenToNDC(vSCR, invViewportPixelSize); + zNDC = computeZ(SCRxy0, SCRxy1, vSCR, Hv0, Hv1, Hv1.z, invViewportPixelSize); + + //convert to homogeneous coordinate + Position = vec4(vNDC, zNDC, Hv1.w); + UVCoord = vec2(UCoord, w); + } + gl_Position = Position; + outData.Peye = inverse(projectionMatrix) * Position; + outData.UVCoord = UVCoord; + outData.UVCoordBorder = UVCoordBorder; + outData.SegmentFlag = SegmentFlag; + outData.Discard = Discard; + outData.Factor = toScreenFactor; + + ProcessPrimvarsIn(); + 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); +} + +--- -------------------------------------------------------------------------- +-- layout DashDot.Fragment + +[ + ["in block", "CurveFragmentData", "inData", + ["vec4", "Peye"], + ["vec2", "UVCoord"], + ["vec2", "UVCoordBorder", "", "flat"], + ["int", "SegmentFlag", "", "flat"], + ["float", "Discard", "", "flat"], + ["float", "Factor"] + ] +] +--- -------------------------------------------------------------------------- +-- glsl DashDot.Fragment + +float capDist(int type, float x, float y) +{ + // square + if (type == 1) + { + return max(x, y); + } + // triangle out + else if (type == 2) + { + return (x + y); + } + // round + else + { + return sqrt(x * x + y * y); + } +} + +float joinDist(float dx, float dy) +{ + return sqrt(dx * dx + dy * dy); +} + +// Get the position of the pixel in the dash or dot symbol. +// The pixel could be at the body of the dash, or at the gap between two dashes. If it is at the gap, and it +// is close to the start of a dash, the pixel is in the left cap. If it is at the gap, and it is close to the +// end of a dash, the pixel is in the right cap. When the pixel is in a cap, we need to know the position of +// reference point. The reference point is the center of the cap. If the pixel is in the left cap, the +// reference point is the start of the dash. If the pixel is in the right cap, the reference point is the end +// of the dash. +// The nodeType is 0 if the pixel is in the body of the dash, 1 if the pixel is at the gap and it is close +// to the start of a dash, and 2 if it is at the gap and is close to the end of a dash. +// The dashStartSymbolized is the position of the start of the dash which the pixel is on. The +// dashEndSymbolized is the position of the end of the dash. The refPointSymbolized is the position of the +// reference point of the dash. +void posInSymbol(float pos, float period, float patternScale, int patternPartCount, + out int nodeType, out float dashStartSymbolized, out float dashEndSymbolized, out float refPointSymbolized) +{ + // The start position of the dash which the current pixel is on, in the pattern space. + float start = 0.0; + // The end position of the dash which the current pixel is on, in the pattern space. + float end = 0.0; + // The position of the reference point, in the pattern space. + float refPoint = 0.0; + nodeType = 0; + + // Calculate the position of the current pixel in the pattern space. + float scaleDownPos = pos / patternScale; + float posInPattern = mod(scaleDownPos, period); + + // The start position of the current dash/dot symbol. + float symbolPos = 0.0; + for (int i = 0; i < patternPartCount; ++i) + { + // First, find a dash or dot whose start position is at the right of the pixel. + vec2 theValue = HdGet_pattern(i); + symbolPos = symbolPos + theValue.x; + if (symbolPos > posInPattern) + { + // If we find a dash who is at the right of the pixel, we will first find the middle position + // of the start of this dash and the end of the previous dash. + float separator = (end + symbolPos) / 2; + // If this middle position is larger than the current pixel, this pixel is closer to the end of + // previous dash. So nodeType is 2. This pixel is at the right cap. The reference point is the + // end of the previous dash. The start and end is the start and end of the previous dash. + if (separator > posInPattern) + { + nodeType = 2; + refPoint = end; + } + // If this middle position is not larger than the current pixel, this pixel is closer to the + // start of previous dash. So nodeType is 1. This pixel is at the left cap. The reference point + // is the start of the current dash. The start and end is the start and end of the current dash. + else + { + nodeType = 1; + start = symbolPos; + symbolPos = symbolPos + theValue.y; + end = symbolPos; + refPoint = start; + } + break; + } + else + { + // Update start and end with the current dash. + start = symbolPos; + symbolPos = symbolPos + theValue.y; + end = symbolPos; + // If the start of the dash is before the current pixel, and the end of the dash is after the + // current pixel, the pixel is at the body. So nodeType is 0, and the start and end is the start + // and end of the current dash. + if (symbolPos > posInPattern) + { + nodeType = 0; + break; + } + } + } + // At this time, if we already find the dash of current pixel, symbolPos must be larger than the current + // position. If we didn't find the dash, the symbolPos will be not larger than posInPattern. In this case, + // the end of the last dash is still smaller than the position. + if (symbolPos <= posInPattern) + { + // We will use the middle position of the end of the last dash, and the end of a period. If the middle + // position is larger than the current point, the pixel is at the right cap of the last dash. If the + // middle point is smaller than the posInPattern, the pixel is at the left cap. + float separator = (symbolPos + period) / 2; + if (separator > posInPattern) + { + nodeType = 2; + refPoint = end; + } + else + { + nodeType = 1; + start = period; + end = period; + refPoint = start; + } + } + // Below is the position of the start of current period. Add to the start position of current dash, it is + // the start of the current dash. Multiply with patternScale, we will get the start position of current + // dash in the object space. + float currentPeriod = scaleDownPos - posInPattern; + dashStartSymbolized = (currentPeriod + start) * patternScale; + // The calculation of the position of the end of current period. Similar to pervious calculation. + dashEndSymbolized = (currentPeriod + end) * patternScale; + // The calculation of the position of the end of the reference point. Similar to pervious calculation. + refPointSymbolized = (currentPeriod + refPoint) * patternScale; +} + +void main(void) +{ + if (inData.Discard == 1.0) + { + discard; + } + 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 + color.rgb = ApplyColorOverrides(color).rgb; + + 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); + + float dist = 0.0; + float dashStartSymbolized = inData.UVCoordBorder.x; + float dashEndSymbolized = inData.UVCoordBorder.y; + float refPointSymbolized = 0.0; + int nodeType = 0; + + int startCapType = HdGetScalar_startCapType(); + int endCapType = HdGetScalar_endCapType(); + float patternScale = HdGetScalar_patternScale(); + float period = HdGetScalar_patternPeriod(); + int patternPartCount = HdGetScalar_patternPartCount(); + + if (patternPartCount > 0) + { + // If there is pattern, we need to check if the pixel is within a dash, or it is at the left cap, + // or right cap of a dash. + float pos = inData.UVCoord.x; + // If the pixel position is smaller than the left of the current line segment, we will use the start + // of the line segment to check. So that the dash before the line segment will not impact on the + // pixel. + if (inData.UVCoord.x < inData.UVCoordBorder.x) + pos = inData.UVCoordBorder.x; + // If the pixel position is larger than the right of the current line segment, we will use the end + // of the line segment to check. So that the dash after the line segment will not impact on the + // pixel. + else if (inData.UVCoord.x > inData.UVCoordBorder.y) + pos = inData.UVCoordBorder.y; + // Get the position of the pixel in the dash or dot symbol. + posInSymbol(pos, period, patternScale, patternPartCount, + nodeType, dashStartSymbolized, dashEndSymbolized, refPointSymbolized); + } + if (inData.UVCoord.x < inData.UVCoordBorder.x && (inData.SegmentFlag == 1 || inData.SegmentFlag == 3) && + (dashStartSymbolized <= inData.UVCoordBorder.x) && (dashEndSymbolized >= inData.UVCoordBorder.x)) + { + //left cap + dist = capDist(startCapType, -inData.UVCoord.x * inData.Factor, abs(inData.UVCoord.y)); + } + else if (inData.UVCoord.x > inData.UVCoordBorder.y && inData.SegmentFlag >= 2 && + (dashStartSymbolized <= inData.UVCoordBorder.y) && (dashEndSymbolized >= inData.UVCoordBorder.y)) + { + //right cap + dist = capDist(endCapType, (inData.UVCoord.x - inData.UVCoordBorder.y) * inData.Factor, abs(inData.UVCoord.y)); + } + else + { + if (nodeType == 2) + { + //dash right cap + dist = capDist(endCapType, (inData.UVCoord.x - refPointSymbolized) * inData.Factor, abs(inData.UVCoord.y)); + } + else if (nodeType == 1) + { + //dash left cap + dist = capDist(startCapType, (refPointSymbolized - inData.UVCoord.x) * inData.Factor, abs(inData.UVCoord.y)); + } + else + { + //line body + dist = abs(inData.UVCoord.y); + } + } + + if ((inData.SegmentFlag == 1 && inData.UVCoord.x > 0.0) || inData.SegmentFlag == 0 || (inData.SegmentFlag == 2 && inData.UVCoord.x < inData.UVCoordBorder.y)) + { + if ((inData.UVCoord.x <= inData.UVCoordBorder.x) && + (dashStartSymbolized <= inData.UVCoordBorder.x) && (dashEndSymbolized >= inData.UVCoordBorder.x)) + { + //left join + dist = joinDist((inData.UVCoordBorder.x - inData.UVCoord.x) * inData.Factor, inData.UVCoord.y); + } + else if ((inData.UVCoord.x > inData.UVCoordBorder.y) && + (dashStartSymbolized <= inData.UVCoordBorder.y) && (dashEndSymbolized >= inData.UVCoordBorder.y)) + { + //right join + dist = joinDist((inData.UVCoord.x - inData.UVCoordBorder.y) * inData.Factor, inData.UVCoord.y); + } + } + + dist -= HdGet_widths(0) * 0.5; + + if (dist < 0.0) + { + color = color; + } + else + { + float styleOpacity = exp(-dist * dist); + color = vec4(styleOpacity * color.rgb, styleOpacity * color.a); + } + +#ifdef HD_MATERIAL_TAG_MASKED + if (ShouldDiscardByAlpha(color)) { + discard; + } +#endif + + RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); +} \ No newline at end of file diff --git a/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove.cpp b/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove.cpp new file mode 100644 index 0000000000..7710b862f2 --- /dev/null +++ b/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove.cpp @@ -0,0 +1,244 @@ +// +// Copyright 2023 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. +// + +#include "pxr/imaging/hd/tokens.h" +#include "pxr/imaging/hdSt/unitTestGLDrawing.h" +#include "pxr/imaging/hdSt/unitTestHelper.h" + +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/vec3d.h" + +#include "pxr/base/tf/errorMark.h" + +#include + +PXR_NAMESPACE_USING_DIRECTIVE + +class My_TestGLDrawing : public HdSt_UnitTestGLDrawing { +public: + My_TestGLDrawing() { + _refineLevel = 0; + _cullStyle = HdCullStyleNothing; + _addRemoveBasisCurves = false; + + SetCameraRotate(60.0f, 0.0f); + SetCameraTranslate(GfVec3f(0, 0, -20.0f - 1.7320508f * 2.0f)); + } + + // HdSt_UnitTestGLDrawing overrides + void InitTest() override; + void DrawTest() override; + void OffscreenTest() override; + void Present(uint32_t framebuffer) override; + +protected: + void ParseArgs(int argc, char* argv[]) override; + + // Test add/remove basisCurves. + void AddRemoveBasisCurves(double& xPos, double& yPos); + +private: + HdSt_TestDriver* _driver; + + int _refineLevel; + HdCullStyle _cullStyle; + std::string _outputFilePath; + bool _addRemoveBasisCurves; +}; + +//////////////////////////////////////////////////////////// + +void +My_TestGLDrawing::InitTest() +{ + std::cout << "My_TestGLDrawing::InitTest() " << "\n"; + + _driver = new HdSt_TestDriver(); + HdUnitTestDelegate& delegate = _driver->GetDelegate(); + delegate.SetRefineLevel(_refineLevel); + + _driver->SetClearColor(GfVec4f(0.1f, 0.1f, 0.1f, 1.0f)); + _driver->SetClearDepth(1.0f); + _driver->SetupAovs(GetWidth(), GetHeight()); +} + +void My_TestGLDrawing::AddRemoveBasisCurves(double &xPos, double& yPos) +{ + GfMatrix4d dmat; + HdUnitTestDelegate& delegate = _driver->GetDelegate(); + + // Add Curves + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve1"), HdTokens->linear, TfToken(), HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve2"), HdTokens->cubic, HdTokens->bezier, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve3"), HdTokens->cubic, HdTokens->bSpline, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve4"), HdTokens->cubic, HdTokens->catmullRom, HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + xPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve5"), HdTokens->linear, TfToken(), HdTokens->none, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve6"), HdTokens->linear, TfToken(), HdTokens->dashDot, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationVertex); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve7"), HdTokens->linear, TfToken(), HdTokens->screenSpaceDashDot, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationConstant); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve8"), HdTokens->linear, TfToken(), HdTokens->dashDot, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationConstant); + yPos += 3.0; + + dmat.SetTranslate(GfVec3d(xPos, yPos, 0.0)); + delegate.AddCurves(SdfPath("/curve9"), HdTokens->linear, TfToken(), HdTokens->screenSpaceDashDot, + GfMatrix4f(dmat), HdInterpolationVertex, HdInterpolationConstant); + + // Remove Curves + delegate.Remove(SdfPath("/curve1")); + delegate.Remove(SdfPath("/curve2")); + delegate.Remove(SdfPath("/curve6")); + delegate.Remove(SdfPath("/curve7")); + delegate.Remove(SdfPath("/curve8")); + delegate.Remove(SdfPath("/curve9")); +} + +void +My_TestGLDrawing::DrawTest() +{ + double xPos = 0.0; + double yPos = 0.0; + + if (_addRemoveBasisCurves) + AddRemoveBasisCurves(xPos, yPos); + + // center camera + SetCameraTranslate(GetCameraTranslate() - GfVec3f(xPos / 2.0, yPos / 2.0, 0)); + + int width = GetWidth(), height = GetHeight(); + GfMatrix4d viewMatrix = GetViewMatrix(); + GfMatrix4d projMatrix = GetProjectionMatrix(); + + _driver->SetCullStyle(_cullStyle); + + _driver->SetCamera( + viewMatrix, + projMatrix, + CameraUtilFraming( + GfRect2i(GfVec2i(0, 0), width, height))); + + _driver->UpdateAovDimensions(width, height); + + _driver->Draw(); +} + +void +My_TestGLDrawing::OffscreenTest() +{ + DrawTest(); + + if (!_outputFilePath.empty()) { + _driver->WriteToFile("color", _outputFilePath); + } +} + +void +My_TestGLDrawing::Present(uint32_t framebuffer) +{ + _driver->Present(GetWidth(), GetHeight(), framebuffer); +} + +/* virtual */ +void +My_TestGLDrawing::ParseArgs(int argc, char* argv[]) +{ + for (int i = 0; i < argc; ++i) { + std::string arg(argv[i]); + if (arg == "--refineLevel") { + _refineLevel = atoi(argv[++i]); + } + else if (arg == "--cullStyle") { + std::string style = argv[++i]; + if (style == "Nothing") { + _cullStyle = HdCullStyleNothing; + } + else if (style == "Back") { + _cullStyle = HdCullStyleBack; + } + else if (style == "Front") { + _cullStyle = HdCullStyleFront; + } + else if (style == "BackUnlessDoubleSided") { + _cullStyle = HdCullStyleBackUnlessDoubleSided; + } + else if (style == "FrontUnlessDoubleSided") { + _cullStyle = HdCullStyleFrontUnlessDoubleSided; + } + else { + std::cerr << "Error: Unknown cullstyle = " << style << "\n"; + exit(EXIT_FAILURE); + } + } + else if (arg == "--addRemoveBasisCurves") { + _addRemoveBasisCurves = true; + } + else if (arg == "--write") { + _outputFilePath = argv[++i]; + } + } +} + +void +BasicTest(int argc, char* argv[]) +{ + My_TestGLDrawing driver; + driver.RunTest(argc, argv); +} + +int main(int argc, char* argv[]) +{ + BasicTest(argc, argv); + std::cout << "OK" << std::endl; + return EXIT_SUCCESS; +} + diff --git a/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove/baseline/testHdStRPrimsAddRemove_BasisCurves.png b/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove/baseline/testHdStRPrimsAddRemove_BasisCurves.png new file mode 100644 index 0000000000..afdd753129 Binary files /dev/null and b/pxr/imaging/hdSt/testenv/testHdStRPrimsAddRemove/baseline/testHdStRPrimsAddRemove_BasisCurves.png differ diff --git a/pxr/imaging/hdsi/testenv/testHdsiPinnedCurveExpandingSceneIndex.cpp b/pxr/imaging/hdsi/testenv/testHdsiPinnedCurveExpandingSceneIndex.cpp index b2f8fc34d6..b2cba8a3e2 100644 --- a/pxr/imaging/hdsi/testenv/testHdsiPinnedCurveExpandingSceneIndex.cpp +++ b/pxr/imaging/hdsi/testenv/testHdsiPinnedCurveExpandingSceneIndex.cpp @@ -106,6 +106,8 @@ _BuildCurveDataSource( _TokenDs::New(curve.type)) .SetWrap( _TokenDs::New(curve.wrap)) + .SetStyle( + _TokenDs::New(HdTokens->none)) .Build()) .Build(); @@ -626,9 +628,6 @@ int main(int argc, char ** argv) bool success = true; success &= TestSimplePinnedCurves(); - success &= TestPinnedCurvesWithIndexedPrimvar(); - success &= TestPinnedCurvesWithCurveIndices(); - success &= TestPinnedCurvesWithCurveIndicesAndIndexedPrimvar(); TF_VERIFY(mark.IsClean()); diff --git a/pxr/imaging/hdx/pickTask.cpp b/pxr/imaging/hdx/pickTask.cpp index 411047c7bc..3a868c2e8f 100644 --- a/pxr/imaging/hdx/pickTask.cpp +++ b/pxr/imaging/hdx/pickTask.cpp @@ -545,6 +545,9 @@ HdxPickTask::Sync(HdSceneDelegate* delegate, _contextParams.clipPlanes); extState->SetUseSceneMaterials(_params.enableSceneMaterials); } + _index->SetCameraFramingState(_contextParams.viewMatrix, + _contextParams.projectionMatrix, + viewport); } _pickableRenderPassState->SetAovBindings(_pickableAovBindings); diff --git a/pxr/imaging/hdx/taskController.cpp b/pxr/imaging/hdx/taskController.cpp index 4b9b33480e..fd50795bae 100644 --- a/pxr/imaging/hdx/taskController.cpp +++ b/pxr/imaging/hdx/taskController.cpp @@ -233,6 +233,12 @@ HdxTaskController::~HdxTaskController() } } +SdfPath +HdxTaskController::GetFreeCameraID() const +{ + return _freeCameraSceneDelegate->GetCameraId(); +} + void HdxTaskController::_CreateRenderGraph() { @@ -1827,6 +1833,7 @@ HdxTaskController::SetRenderViewport(GfVec4d const& viewport) // Update all of the render buffer sizes as well. _UpdateAovDimensions(_ViewportToAovDimensions(viewport)); + GetRenderIndex()->SetRenderViewport(viewport); } void @@ -1846,6 +1853,7 @@ HdxTaskController::SetFraming(const CameraUtilFraming &framing) { _framing = framing; _SetCameraFramingForTasks(); + GetRenderIndex()->SetFraming(framing); } void @@ -1854,12 +1862,14 @@ HdxTaskController::SetOverrideWindowPolicy( { _overrideWindowPolicy = policy; _SetCameraFramingForTasks(); + GetRenderIndex()->SetOverrideWindowPolicy(policy); } void HdxTaskController::SetCameraPath(SdfPath const& id) { _SetCameraParamForTasks(id); + GetRenderIndex()->SetCameraPath(id); } void @@ -1868,6 +1878,7 @@ HdxTaskController::SetFreeCameraMatrices(GfMatrix4d const& viewMatrix, { _freeCameraSceneDelegate->SetMatrices(viewMatrix, projMatrix); _SetCameraParamForTasks(_freeCameraSceneDelegate->GetCameraId()); + GetRenderIndex()->SetCameraPath(_freeCameraSceneDelegate->GetCameraId()); } void diff --git a/pxr/imaging/hdx/taskController.h b/pxr/imaging/hdx/taskController.h index 839916d3c2..40f132a551 100644 --- a/pxr/imaging/hdx/taskController.h +++ b/pxr/imaging/hdx/taskController.h @@ -246,6 +246,9 @@ class HdxTaskController final HDX_API void SetEnablePresentation(bool enabled); + /// Get the cameraID of free camera. + HDX_API + SdfPath GetFreeCameraID() const; private: /// /// This class is not intended to be copied. diff --git a/pxr/usd/usdGeom/CMakeLists.txt b/pxr/usd/usdGeom/CMakeLists.txt index 6d110d4e1a..ec0f3f9242 100644 --- a/pxr/usd/usdGeom/CMakeLists.txt +++ b/pxr/usd/usdGeom/CMakeLists.txt @@ -35,6 +35,8 @@ pxr_library(usdGeom curves cylinder cylinder_1 + dashDotLines + dashDotPatternAPI hermiteCurves imageable gprim @@ -83,6 +85,8 @@ pxr_library(usdGeom wrapCurves.cpp wrapCylinder.cpp wrapCylinder_1.cpp + wrapDashDotLines.cpp + wrapDashDotPatternAPI.cpp wrapGprim.cpp wrapHermiteCurves.cpp wrapImageable.cpp @@ -137,6 +141,7 @@ pxr_test_scripts( testenv/testUsdGeomConstraintTarget.py testenv/testUsdGeomConsts.py testenv/testUsdGeomCurves.py + testenv/testUsdGeomDashDotLines.py testenv/testUsdGeomExtentFromPlugins.py testenv/testUsdGeomExtentTransform.py testenv/testUsdGeomHermiteCurves.py @@ -193,6 +198,11 @@ pxr_install_test_dir( DEST testUsdGeomBasisCurves ) +pxr_install_test_dir( + SRC testenv/testUsdGeomDashDotLines + DEST testUsdGeomDashDotLines +) + pxr_install_test_dir( SRC testenv/testUsdGeomBBoxCache DEST testUsdGeomBBoxCache @@ -258,6 +268,12 @@ pxr_register_test(testUsdGeomBasisCurves EXPECTED_RETURN_CODE 0 ) +pxr_register_test(testUsdGeomDashDotLines + PYTHON + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdGeomDashDotLines" + EXPECTED_RETURN_CODE 0 +) + pxr_register_test(testUsdGeomBBoxCache PYTHON COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdGeomBBoxCache" diff --git a/pxr/usd/usdGeom/dashDotLines.cpp b/pxr/usd/usdGeom/dashDotLines.cpp new file mode 100644 index 0000000000..4000778e14 --- /dev/null +++ b/pxr/usd/usdGeom/dashDotLines.cpp @@ -0,0 +1,251 @@ +// +// Copyright 2024 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. +// +#include "pxr/usd/usdGeom/dashDotLines.h" +#include "pxr/usd/usd/schemaRegistry.h" +#include "pxr/usd/usd/typed.h" + +#include "pxr/usd/sdf/types.h" +#include "pxr/usd/sdf/assetPath.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// Register the schema with the TfType system. +TF_REGISTRY_FUNCTION(TfType) +{ + TfType::Define >(); + + // Register the usd prim typename as an alias under UsdSchemaBase. This + // enables one to call + // TfType::Find().FindDerivedByName("DashDotLines") + // to find TfType, which is how IsA queries are + // answered. + TfType::AddAlias("DashDotLines"); +} + +/* virtual */ +UsdGeomDashDotLines::~UsdGeomDashDotLines() +{ +} + +/* static */ +UsdGeomDashDotLines +UsdGeomDashDotLines::Get(const UsdStagePtr &stage, const SdfPath &path) +{ + if (!stage) { + TF_CODING_ERROR("Invalid stage"); + return UsdGeomDashDotLines(); + } + return UsdGeomDashDotLines(stage->GetPrimAtPath(path)); +} + +/* static */ +UsdGeomDashDotLines +UsdGeomDashDotLines::Define( + const UsdStagePtr &stage, const SdfPath &path) +{ + static TfToken usdPrimTypeName("DashDotLines"); + if (!stage) { + TF_CODING_ERROR("Invalid stage"); + return UsdGeomDashDotLines(); + } + return UsdGeomDashDotLines( + stage->DefinePrim(path, usdPrimTypeName)); +} + +/* virtual */ +UsdSchemaKind UsdGeomDashDotLines::_GetSchemaKind() const +{ + return UsdGeomDashDotLines::schemaKind; +} + +/* static */ +const TfType & +UsdGeomDashDotLines::_GetStaticTfType() +{ + static TfType tfType = TfType::Find(); + return tfType; +} + +/* static */ +bool +UsdGeomDashDotLines::_IsTypedSchema() +{ + static bool isTyped = _GetStaticTfType().IsA(); + return isTyped; +} + +/* virtual */ +const TfType & +UsdGeomDashDotLines::_GetTfType() const +{ + return _GetStaticTfType(); +} + +UsdAttribute +UsdGeomDashDotLines::GetScreenSpacePatternAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->screenSpacePattern); +} + +UsdAttribute +UsdGeomDashDotLines::CreateScreenSpacePatternAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->screenSpacePattern, + SdfValueTypeNames->Bool, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +UsdAttribute +UsdGeomDashDotLines::GetPatternScaleAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->patternScale); +} + +UsdAttribute +UsdGeomDashDotLines::CreatePatternScaleAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->patternScale, + SdfValueTypeNames->Float, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +UsdAttribute +UsdGeomDashDotLines::GetStartCapTypeAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->startCapType); +} + +UsdAttribute +UsdGeomDashDotLines::CreateStartCapTypeAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->startCapType, + SdfValueTypeNames->Token, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +UsdAttribute +UsdGeomDashDotLines::GetEndCapTypeAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->endCapType); +} + +UsdAttribute +UsdGeomDashDotLines::CreateEndCapTypeAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->endCapType, + SdfValueTypeNames->Token, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +namespace { +static inline TfTokenVector +_ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right) +{ + TfTokenVector result; + result.reserve(left.size() + right.size()); + result.insert(result.end(), left.begin(), left.end()); + result.insert(result.end(), right.begin(), right.end()); + return result; +} +} + +/*static*/ +const TfTokenVector& +UsdGeomDashDotLines::GetSchemaAttributeNames(bool includeInherited) +{ + static TfTokenVector localNames = { + UsdGeomTokens->screenSpacePattern, + UsdGeomTokens->patternScale, + UsdGeomTokens->startCapType, + UsdGeomTokens->endCapType, + }; + static TfTokenVector allNames = + _ConcatenateAttributeNames( + UsdGeomCurves::GetSchemaAttributeNames(true), + localNames); + + if (includeInherited) + return allNames; + else + return localNames; +} + +PXR_NAMESPACE_CLOSE_SCOPE + +// ===================================================================== // +// Feel free to add custom code below this line. It will be preserved by +// the code generator. +// +// Just remember to wrap code in the appropriate delimiters: +// 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'. +// ===================================================================== // +// --(BEGIN CUSTOM CODE)-- + +PXR_NAMESPACE_OPEN_SCOPE + +TfToken +UsdGeomDashDotLines::GetTokenAttr(UsdAttribute attr, UsdTimeCode timeCode) const +{ + TfToken token; + attr.Get(&token, timeCode); + return token; +} + +float +UsdGeomDashDotLines::GetFloatAttr(UsdAttribute attr, UsdTimeCode timeCode) const +{ + float value; + attr.Get(&value, timeCode); + return value; +} + +int +UsdGeomDashDotLines::GetIntAttr(UsdAttribute attr, UsdTimeCode timeCode) const +{ + int value; + attr.Get(&value, timeCode); + return value; +} + +bool +UsdGeomDashDotLines::GetBoolAttr(UsdAttribute attr, UsdTimeCode timeCode) const +{ + bool value; + attr.Get(&value, timeCode); + return value; +} +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/usd/usdGeom/dashDotLines.h b/pxr/usd/usdGeom/dashDotLines.h new file mode 100644 index 0000000000..b3249fad22 --- /dev/null +++ b/pxr/usd/usdGeom/dashDotLines.h @@ -0,0 +1,299 @@ +// +// Copyright 2024 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. +// +#ifndef USDGEOM_GENERATED_DASHDOTLINES_H +#define USDGEOM_GENERATED_DASHDOTLINES_H + +/// \file usdGeom/dashDotLines.h + +#include "pxr/pxr.h" +#include "pxr/usd/usdGeom/api.h" +#include "pxr/usd/usdGeom/curves.h" +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usdGeom/tokens.h" + +#include "pxr/base/vt/value.h" + +#include "pxr/base/gf/vec3d.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/matrix4d.h" + +#include "pxr/base/tf/token.h" +#include "pxr/base/tf/type.h" + +PXR_NAMESPACE_OPEN_SCOPE + +class SdfAssetPath; + +// -------------------------------------------------------------------------- // +// DASHDOTLINES // +// -------------------------------------------------------------------------- // + +/// \class UsdGeomDashDotLines +/// +/// This schema is for a line primitive whose width in screen space will not change. And the primitive +/// can have dash-dot patterns. This type of curve is usually used in a sketch file, or nondiegetic visualizations. +/// +/// The basic shape for the primitive is a set of lines or polylines. A general type curve is not supported in this +/// schema. +/// +/// If the lines have dash-dot patterns, it must inherit from a "pattern" who applies with DashDotPatternAPI. The +/// length of the pattern can be in screen space or world space. +/// +/// For any described attribute \em Fallback \em Value or \em Allowed \em Values below +/// that are text/tokens, the actual token is published and defined in \ref UsdGeomTokens. +/// So to set an attribute to the value "rightHanded", use UsdGeomTokens->rightHanded +/// as the value. +/// +class UsdGeomDashDotLines : public UsdGeomCurves +{ +public: + /// Compile time constant representing what kind of schema this class is. + /// + /// \sa UsdSchemaKind + static const UsdSchemaKind schemaKind = UsdSchemaKind::ConcreteTyped; + + /// Construct a UsdGeomDashDotLines on UsdPrim \p prim . + /// Equivalent to UsdGeomDashDotLines::Get(prim.GetStage(), prim.GetPath()) + /// for a \em valid \p prim, but will not immediately throw an error for + /// an invalid \p prim + explicit UsdGeomDashDotLines(const UsdPrim& prim=UsdPrim()) + : UsdGeomCurves(prim) + { + } + + /// Construct a UsdGeomDashDotLines on the prim held by \p schemaObj . + /// Should be preferred over UsdGeomDashDotLines(schemaObj.GetPrim()), + /// as it preserves SchemaBase state. + explicit UsdGeomDashDotLines(const UsdSchemaBase& schemaObj) + : UsdGeomCurves(schemaObj) + { + } + + /// Destructor. + USDGEOM_API + virtual ~UsdGeomDashDotLines(); + + /// Return a vector of names of all pre-declared attributes for this schema + /// class and all its ancestor classes. Does not include attributes that + /// may be authored by custom/extended methods of the schemas involved. + USDGEOM_API + static const TfTokenVector & + GetSchemaAttributeNames(bool includeInherited=true); + + /// Return a UsdGeomDashDotLines holding the prim adhering to this + /// schema at \p path on \p stage. If no prim exists at \p path on + /// \p stage, or if the prim at that path does not adhere to this schema, + /// return an invalid schema object. This is shorthand for the following: + /// + /// \code + /// UsdGeomDashDotLines(stage->GetPrimAtPath(path)); + /// \endcode + /// + USDGEOM_API + static UsdGeomDashDotLines + Get(const UsdStagePtr &stage, const SdfPath &path); + + /// Attempt to ensure a \a UsdPrim adhering to this schema at \p path + /// is defined (according to UsdPrim::IsDefined()) on this stage. + /// + /// If a prim adhering to this schema at \p path is already defined on this + /// stage, return that prim. Otherwise author an \a SdfPrimSpec with + /// \a specifier == \a SdfSpecifierDef and this schema's prim type name for + /// the prim at \p path at the current EditTarget. Author \a SdfPrimSpec s + /// with \p specifier == \a SdfSpecifierDef and empty typeName at the + /// current EditTarget for any nonexistent, or existing but not \a Defined + /// ancestors. + /// + /// The given \a path must be an absolute prim path that does not contain + /// any variant selections. + /// + /// If it is impossible to author any of the necessary PrimSpecs, (for + /// example, in case \a path cannot map to the current UsdEditTarget's + /// namespace) issue an error and return an invalid \a UsdPrim. + /// + /// Note that this method may return a defined prim whose typeName does not + /// specify this schema class, in case a stronger typeName opinion overrides + /// the opinion at the current EditTarget. + /// + USDGEOM_API + static UsdGeomDashDotLines + Define(const UsdStagePtr &stage, const SdfPath &path); + +protected: + /// Returns the kind of schema this class belongs to. + /// + /// \sa UsdSchemaKind + USDGEOM_API + UsdSchemaKind _GetSchemaKind() const override; + +private: + // needs to invoke _GetStaticTfType. + friend class UsdSchemaRegistry; + USDGEOM_API + static const TfType &_GetStaticTfType(); + + static bool _IsTypedSchema(); + + // override SchemaBase virtuals. + USDGEOM_API + const TfType &_GetTfType() const override; + +public: + // --------------------------------------------------------------------- // + // SCREENSPACEPATTERN + // --------------------------------------------------------------------- // + /// Whether the dash-dot pattern length can be varied. It is only valid when the DashDotLines primitive + /// inherits from a "pattern" who applies with DashDotPatternAPI. If it is true, the length of the pattern is in + /// screen space, and it will not change. If you zoom in and the line is longer on the screen, you will see the + /// patterns will move on the line, and there will be more patterns on the line. If it is false, the length of + /// the pattern is in world space. If you zoom in, you will see the pattern will be larger, and it will not move + /// on the line. + /// + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform bool screenSpacePattern = 1` | + /// | C++ Type | bool | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Bool | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + USDGEOM_API + UsdAttribute GetScreenSpacePatternAttr() const; + + /// See GetScreenSpacePatternAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreateScreenSpacePatternAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // --------------------------------------------------------------------- // + // PATTERNSCALE + // --------------------------------------------------------------------- // + /// This property is a scale value to lengthen or shorten a dash-dot pattern. It is only valid when the + /// DashDotLines primitive inherits from a "pattern" who applies with DashDotPatternAPI. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform float patternScale = 1` | + /// | C++ Type | float | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + USDGEOM_API + UsdAttribute GetPatternScaleAttr() const; + + /// See GetPatternScaleAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreatePatternScaleAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // --------------------------------------------------------------------- // + // STARTCAPTYPE + // --------------------------------------------------------------------- // + /// The shape of the line cap at the start of the line. It is also applied to the start cap of each dash + /// when the line has pattern. + /// + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform token startCapType = "round"` | + /// | C++ Type | TfToken | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Token | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + /// | \ref UsdGeomTokens "Allowed Values" | round, square, triangle | + USDGEOM_API + UsdAttribute GetStartCapTypeAttr() const; + + /// See GetStartCapTypeAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreateStartCapTypeAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // --------------------------------------------------------------------- // + // ENDCAPTYPE + // --------------------------------------------------------------------- // + /// The shape of the line cap at the end of the line. It is also applied to the end cap of each dash + /// when the line has pattern. + /// + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform token endCapType = "round"` | + /// | C++ Type | TfToken | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Token | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + /// | \ref UsdGeomTokens "Allowed Values" | round, square, triangle | + USDGEOM_API + UsdAttribute GetEndCapTypeAttr() const; + + /// See GetEndCapTypeAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreateEndCapTypeAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // ===================================================================== // + // Feel free to add custom code below this line, it will be preserved by + // the code generator. + // + // Just remember to: + // - Close the class declaration with }; + // - Close the namespace with PXR_NAMESPACE_CLOSE_SCOPE + // - Close the include guard with #endif + // ===================================================================== // + // --(BEGIN CUSTOM CODE)-- + + /// Convert the attribute to token. + USDGEOM_API + TfToken GetTokenAttr(UsdAttribute attr, UsdTimeCode timeCode) const; + + /// Convert the attribute to int. + USDGEOM_API + int GetIntAttr(UsdAttribute attr, UsdTimeCode timeCode) const; + + /// Convert the attribute to float. + USDGEOM_API + float GetFloatAttr(UsdAttribute attr, UsdTimeCode timeCode) const; + + /// Convert the attribute to bool. + USDGEOM_API + bool GetBoolAttr(UsdAttribute attr, UsdTimeCode timeCode) const; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/pxr/usd/usdGeom/dashDotPatternAPI.cpp b/pxr/usd/usdGeom/dashDotPatternAPI.cpp new file mode 100644 index 0000000000..f21db8f112 --- /dev/null +++ b/pxr/usd/usdGeom/dashDotPatternAPI.cpp @@ -0,0 +1,179 @@ +// +// Copyright 2024 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. +// +#include "pxr/usd/usdGeom/dashDotPatternAPI.h" +#include "pxr/usd/usd/schemaRegistry.h" +#include "pxr/usd/usd/typed.h" + +#include "pxr/usd/sdf/types.h" +#include "pxr/usd/sdf/assetPath.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// Register the schema with the TfType system. +TF_REGISTRY_FUNCTION(TfType) +{ + TfType::Define >(); + +} + +/* virtual */ +UsdGeomDashDotPatternAPI::~UsdGeomDashDotPatternAPI() +{ +} + +/* static */ +UsdGeomDashDotPatternAPI +UsdGeomDashDotPatternAPI::Get(const UsdStagePtr &stage, const SdfPath &path) +{ + if (!stage) { + TF_CODING_ERROR("Invalid stage"); + return UsdGeomDashDotPatternAPI(); + } + return UsdGeomDashDotPatternAPI(stage->GetPrimAtPath(path)); +} + + +/* virtual */ +UsdSchemaKind UsdGeomDashDotPatternAPI::_GetSchemaKind() const +{ + return UsdGeomDashDotPatternAPI::schemaKind; +} + +/* static */ +bool +UsdGeomDashDotPatternAPI::CanApply( + const UsdPrim &prim, std::string *whyNot) +{ + return prim.CanApplyAPI(whyNot); +} + +/* static */ +UsdGeomDashDotPatternAPI +UsdGeomDashDotPatternAPI::Apply(const UsdPrim &prim) +{ + if (prim.ApplyAPI()) { + return UsdGeomDashDotPatternAPI(prim); + } + return UsdGeomDashDotPatternAPI(); +} + +/* static */ +const TfType & +UsdGeomDashDotPatternAPI::_GetStaticTfType() +{ + static TfType tfType = TfType::Find(); + return tfType; +} + +/* static */ +bool +UsdGeomDashDotPatternAPI::_IsTypedSchema() +{ + static bool isTyped = _GetStaticTfType().IsA(); + return isTyped; +} + +/* virtual */ +const TfType & +UsdGeomDashDotPatternAPI::_GetTfType() const +{ + return _GetStaticTfType(); +} + +UsdAttribute +UsdGeomDashDotPatternAPI::GetPatternAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->pattern); +} + +UsdAttribute +UsdGeomDashDotPatternAPI::CreatePatternAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->pattern, + SdfValueTypeNames->Float2Array, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +UsdAttribute +UsdGeomDashDotPatternAPI::GetPatternPeriodAttr() const +{ + return GetPrim().GetAttribute(UsdGeomTokens->patternPeriod); +} + +UsdAttribute +UsdGeomDashDotPatternAPI::CreatePatternPeriodAttr(VtValue const &defaultValue, bool writeSparsely) const +{ + return UsdSchemaBase::_CreateAttr(UsdGeomTokens->patternPeriod, + SdfValueTypeNames->Float, + /* custom = */ false, + SdfVariabilityUniform, + defaultValue, + writeSparsely); +} + +namespace { +static inline TfTokenVector +_ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right) +{ + TfTokenVector result; + result.reserve(left.size() + right.size()); + result.insert(result.end(), left.begin(), left.end()); + result.insert(result.end(), right.begin(), right.end()); + return result; +} +} + +/*static*/ +const TfTokenVector& +UsdGeomDashDotPatternAPI::GetSchemaAttributeNames(bool includeInherited) +{ + static TfTokenVector localNames = { + UsdGeomTokens->pattern, + UsdGeomTokens->patternPeriod, + }; + static TfTokenVector allNames = + _ConcatenateAttributeNames( + UsdAPISchemaBase::GetSchemaAttributeNames(true), + localNames); + + if (includeInherited) + return allNames; + else + return localNames; +} + +PXR_NAMESPACE_CLOSE_SCOPE + +// ===================================================================== // +// Feel free to add custom code below this line. It will be preserved by +// the code generator. +// +// Just remember to wrap code in the appropriate delimiters: +// 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'. +// ===================================================================== // +// --(BEGIN CUSTOM CODE)-- diff --git a/pxr/usd/usdGeom/dashDotPatternAPI.h b/pxr/usd/usdGeom/dashDotPatternAPI.h new file mode 100644 index 0000000000..7c381ce56e --- /dev/null +++ b/pxr/usd/usdGeom/dashDotPatternAPI.h @@ -0,0 +1,238 @@ +// +// Copyright 2024 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. +// +#ifndef USDGEOM_GENERATED_DASHDOTPATTERNAPI_H +#define USDGEOM_GENERATED_DASHDOTPATTERNAPI_H + +/// \file usdGeom/dashDotPatternAPI.h + +#include "pxr/pxr.h" +#include "pxr/usd/usdGeom/api.h" +#include "pxr/usd/usd/apiSchemaBase.h" +#include "pxr/usd/usd/prim.h" +#include "pxr/usd/usd/stage.h" +#include "pxr/usd/usdGeom/tokens.h" + +#include "pxr/base/vt/value.h" + +#include "pxr/base/gf/vec3d.h" +#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/matrix4d.h" + +#include "pxr/base/tf/token.h" +#include "pxr/base/tf/type.h" + +PXR_NAMESPACE_OPEN_SCOPE + +class SdfAssetPath; + +// -------------------------------------------------------------------------- // +// DASHDOTPATTERNAPI // +// -------------------------------------------------------------------------- // + +/// \class UsdGeomDashDotPatternAPI +/// +/// UsdGeomDashDotPatternAPI is an API schema that provides an interface for the dash-dot patterns of the +/// DashDotLines primitive. +/// +class UsdGeomDashDotPatternAPI : public UsdAPISchemaBase +{ +public: + /// Compile time constant representing what kind of schema this class is. + /// + /// \sa UsdSchemaKind + static const UsdSchemaKind schemaKind = UsdSchemaKind::SingleApplyAPI; + + /// Construct a UsdGeomDashDotPatternAPI on UsdPrim \p prim . + /// Equivalent to UsdGeomDashDotPatternAPI::Get(prim.GetStage(), prim.GetPath()) + /// for a \em valid \p prim, but will not immediately throw an error for + /// an invalid \p prim + explicit UsdGeomDashDotPatternAPI(const UsdPrim& prim=UsdPrim()) + : UsdAPISchemaBase(prim) + { + } + + /// Construct a UsdGeomDashDotPatternAPI on the prim held by \p schemaObj . + /// Should be preferred over UsdGeomDashDotPatternAPI(schemaObj.GetPrim()), + /// as it preserves SchemaBase state. + explicit UsdGeomDashDotPatternAPI(const UsdSchemaBase& schemaObj) + : UsdAPISchemaBase(schemaObj) + { + } + + /// Destructor. + USDGEOM_API + virtual ~UsdGeomDashDotPatternAPI(); + + /// Return a vector of names of all pre-declared attributes for this schema + /// class and all its ancestor classes. Does not include attributes that + /// may be authored by custom/extended methods of the schemas involved. + USDGEOM_API + static const TfTokenVector & + GetSchemaAttributeNames(bool includeInherited=true); + + /// Return a UsdGeomDashDotPatternAPI holding the prim adhering to this + /// schema at \p path on \p stage. If no prim exists at \p path on + /// \p stage, or if the prim at that path does not adhere to this schema, + /// return an invalid schema object. This is shorthand for the following: + /// + /// \code + /// UsdGeomDashDotPatternAPI(stage->GetPrimAtPath(path)); + /// \endcode + /// + USDGEOM_API + static UsdGeomDashDotPatternAPI + Get(const UsdStagePtr &stage, const SdfPath &path); + + + /// Returns true if this single-apply API schema can be applied to + /// the given \p prim. If this schema can not be a applied to the prim, + /// this returns false and, if provided, populates \p whyNot with the + /// reason it can not be applied. + /// + /// Note that if CanApply returns false, that does not necessarily imply + /// that calling Apply will fail. Callers are expected to call CanApply + /// before calling Apply if they want to ensure that it is valid to + /// apply a schema. + /// + /// \sa UsdPrim::GetAppliedSchemas() + /// \sa UsdPrim::HasAPI() + /// \sa UsdPrim::CanApplyAPI() + /// \sa UsdPrim::ApplyAPI() + /// \sa UsdPrim::RemoveAPI() + /// + USDGEOM_API + static bool + CanApply(const UsdPrim &prim, std::string *whyNot=nullptr); + + /// Applies this single-apply API schema to the given \p prim. + /// This information is stored by adding "DashDotPatternAPI" to the + /// token-valued, listOp metadata \em apiSchemas on the prim. + /// + /// \return A valid UsdGeomDashDotPatternAPI object is returned upon success. + /// An invalid (or empty) UsdGeomDashDotPatternAPI object is returned upon + /// failure. See \ref UsdPrim::ApplyAPI() for conditions + /// resulting in failure. + /// + /// \sa UsdPrim::GetAppliedSchemas() + /// \sa UsdPrim::HasAPI() + /// \sa UsdPrim::CanApplyAPI() + /// \sa UsdPrim::ApplyAPI() + /// \sa UsdPrim::RemoveAPI() + /// + USDGEOM_API + static UsdGeomDashDotPatternAPI + Apply(const UsdPrim &prim); + +protected: + /// Returns the kind of schema this class belongs to. + /// + /// \sa UsdSchemaKind + USDGEOM_API + UsdSchemaKind _GetSchemaKind() const override; + +private: + // needs to invoke _GetStaticTfType. + friend class UsdSchemaRegistry; + USDGEOM_API + static const TfType &_GetStaticTfType(); + + static bool _IsTypedSchema(); + + // override SchemaBase virtuals. + USDGEOM_API + const TfType &_GetTfType() const override; + +public: + // --------------------------------------------------------------------- // + // PATTERN + // --------------------------------------------------------------------- // + /// An array of float2 which saves the dash-dot pattern. For each float2, the x value and the y value + /// must be zero or positive. The x value saves the offset of the start of current symbol, from the end of the + /// previous symbol. If the current symbol is the first symbol, the offset is from the start of the pattern to + /// the start of current symbol. The y value saves the length of the current symbol. If it is zero, the current + /// symbol is a dot. If it is larger than zero, the current symbol is a dash. As a result, the total sum of all + /// the x value and y value will be the length from the start of the pattern to the end of the last symbol. This + /// sum must be smaller than patternPeriod. + /// + /// For example, assume the pattern is [(0, 10), (1, 4), (3, 0)]. It means the first symbol is a dash which is + /// from 0 to 10. The second symbol is a dash which is from 11 to 15, and the third symbol is a dot which is at + /// position 18. There are gaps between 10 and 11, and between 15 and 18. If the patternPeriod is 20, there is + /// also a gap between 18 and 20. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform float2[] pattern` | + /// | C++ Type | VtArray | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float2Array | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + USDGEOM_API + UsdAttribute GetPatternAttr() const; + + /// See GetPatternAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreatePatternAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // --------------------------------------------------------------------- // + // PATTERNPERIOD + // --------------------------------------------------------------------- // + /// The length of a pattern. If there is no pattern, it should be zero. + /// + /// | || + /// | -- | -- | + /// | Declaration | `uniform float patternPeriod = 0` | + /// | C++ Type | float | + /// | \ref Usd_Datatypes "Usd Type" | SdfValueTypeNames->Float | + /// | \ref SdfVariability "Variability" | SdfVariabilityUniform | + USDGEOM_API + UsdAttribute GetPatternPeriodAttr() const; + + /// See GetPatternPeriodAttr(), and also + /// \ref Usd_Create_Or_Get_Property for when to use Get vs Create. + /// If specified, author \p defaultValue as the attribute's default, + /// sparsely (when it makes sense to do so) if \p writeSparsely is \c true - + /// the default for \p writeSparsely is \c false. + USDGEOM_API + UsdAttribute CreatePatternPeriodAttr(VtValue const &defaultValue = VtValue(), bool writeSparsely=false) const; + +public: + // ===================================================================== // + // Feel free to add custom code below this line, it will be preserved by + // the code generator. + // + // Just remember to: + // - Close the class declaration with }; + // - Close the namespace with PXR_NAMESPACE_CLOSE_SCOPE + // - Close the include guard with #endif + // ===================================================================== // + // --(BEGIN CUSTOM CODE)-- +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif diff --git a/pxr/usd/usdGeom/generatedSchema.usda b/pxr/usd/usdGeom/generatedSchema.usda index 5c97725076..c900c3c6a8 100644 --- a/pxr/usd/usdGeom/generatedSchema.usda +++ b/pxr/usd/usdGeom/generatedSchema.usda @@ -3581,6 +3581,228 @@ class NurbsCurves "NurbsCurves" ( ) } +class DashDotLines "DashDotLines" ( + doc = '''This schema is for a line primitive whose width in screen space will not change. And the primitive + can have dash-dot patterns. This type of curve is usually used in a sketch file, or nondiegetic visualizations. + + The basic shape for the primitive is a set of lines or polylines. A general type curve is not supported in this + schema. + + If the lines have dash-dot patterns, it must inherit from a "pattern" who applies with DashDotPatternAPI. The + length of the pattern can be in screen space or world space.''' +) +{ + vector3f[] accelerations ( + doc = """If provided, 'accelerations' should be used with + velocities to compute positions between samples for the 'points' + attribute rather than interpolating between neighboring 'points' + samples. Acceleration is measured in position units per second-squared. + To convert to position units per squared UsdTimeCode, divide by the + square of UsdStage::GetTimeCodesPerSecond().""" + ) + int[] curveVertexCounts ( + doc = """Curves-derived primitives can represent multiple distinct, + potentially disconnected curves. The length of 'curveVertexCounts' + gives the number of such curves, and each element describes the + number of vertices in the corresponding curve""" + ) + uniform bool doubleSided = 0 ( + doc = """Although some renderers treat all parametric or polygonal + surfaces as if they were effectively laminae with outward-facing + normals on both sides, some renderers derive significant optimizations + by considering these surfaces to have only a single outward side, + typically determined by control-point winding order and/or + orientation. By doing so they can perform \"backface culling\" to + avoid drawing the many polygons of most closed surfaces that face away + from the viewer. + + However, it is often advantageous to model thin objects such as paper + and cloth as single, open surfaces that must be viewable from both + sides, always. Setting a gprim's doubleSided attribute to + \\c true instructs all renderers to disable optimizations such as + backface culling for the gprim, and attempt (not all renderers are able + to do so, but the USD reference GL renderer always will) to provide + forward-facing normals on each side of the surface for lighting + calculations.""" + ) + uniform token endCapType = "round" ( + allowedTokens = ["round", "square", "triangle"] + doc = """The shape of the line cap at the end of the line. It is also applied to the end cap of each dash + when the line has pattern. + """ + ) + float3[] extent ( + doc = """Extent is a three dimensional range measuring the geometric + extent of the authored gprim in its own local space (i.e. its own + transform not applied), without accounting for any shader-induced + displacement. If __any__ extent value has been authored for a given + Boundable, then it should be authored at every timeSample at which + geometry-affecting properties are authored, to ensure correct + evaluation via ComputeExtent(). If __no__ extent value has been + authored, then ComputeExtent() will call the Boundable's registered + ComputeExtentFunction(), which may be expensive, which is why we + strongly encourage proper authoring of extent. + \\sa ComputeExtent() + \\sa \\ref UsdGeom_Boundable_Extent. + + An authored extent on a prim which has children is expected to include + the extent of all children, as they will be pruned from BBox computation + during traversal.""" + ) + normal3f[] normals ( + doc = """Provide an object-space orientation for individual points, + which, depending on subclass, may define a surface, curve, or free + points. Note that 'normals' should not be authored on any Mesh that + is subdivided, since the subdivision algorithm will define its own + normals. 'normals' is not a generic primvar, but the number of elements + in this attribute will be determined by its 'interpolation'. See + . If 'normals' and 'primvars:normals' + are both specified, the latter has precedence.""" + ) + uniform token orientation = "rightHanded" ( + allowedTokens = ["rightHanded", "leftHanded"] + doc = """Orientation specifies whether the gprim's surface normal + should be computed using the right hand rule, or the left hand rule. + Please see for a deeper explanation and + generalization of orientation to composed scenes with transformation + hierarchies.""" + ) + uniform float patternScale = 1 ( + doc = '''This property is a scale value to lengthen or shorten a dash-dot pattern. It is only valid when the + DashDotLines primitive inherits from a "pattern" who applies with DashDotPatternAPI.''' + ) + point3f[] points ( + doc = """The primary geometry attribute for all PointBased + primitives, describes points in (local) space.""" + ) + color3f[] primvars:displayColor ( + doc = '''It is useful to have an "official" colorSet that can be used + as a display or modeling color, even in the absence of any specified + shader for a gprim. DisplayColor serves this role; because it is a + UsdGeomPrimvar, it can also be used as a gprim override for any shader + that consumes a displayColor parameter.''' + ) + float[] primvars:displayOpacity ( + doc = """Companion to displayColor that specifies opacity, broken + out as an independent attribute rather than an rgba color, both so that + each can be independently overridden, and because shaders rarely consume + rgba parameters.""" + ) + rel proxyPrim ( + doc = '''The proxyPrim relationship allows us to link a + prim whose purpose is "render" to its (single target) + purpose="proxy" prim. This is entirely optional, but can be + useful in several scenarios: + + - In a pipeline that does pruning (for complexity management) + by deactivating prims composed from asset references, when we + deactivate a purpose="render" prim, we will be able to discover + and additionally deactivate its associated purpose="proxy" prim, + so that preview renders reflect the pruning accurately. + + - DCC importers may be able to make more aggressive optimizations + for interactive processing and display if they can discover the proxy + for a given render prim. + + - With a little more work, a Hydra-based application will be able + to map a picked proxy prim back to its render geometry for selection. + + \\note It is only valid to author the proxyPrim relationship on + prims whose purpose is "render".''' + ) + uniform token purpose = "default" ( + allowedTokens = ["default", "render", "proxy", "guide"] + doc = """Purpose is a classification of geometry into categories that + can each be independently included or excluded from traversals of prims + on a stage, such as rendering or bounding-box computation traversals. + + See for more detail about how + purpose is computed and used.""" + ) + uniform bool screenSpacePattern = 1 ( + doc = '''Whether the dash-dot pattern length can be varied. It is only valid when the DashDotLines primitive + inherits from a "pattern" who applies with DashDotPatternAPI. If it is true, the length of the pattern is in + screen space, and it will not change. If you zoom in and the line is longer on the screen, you will see the + patterns will move on the line, and there will be more patterns on the line. If it is false, the length of + the pattern is in world space. If you zoom in, you will see the pattern will be larger, and it will not move + on the line. + ''' + ) + uniform token startCapType = "round" ( + allowedTokens = ["round", "square", "triangle"] + doc = """The shape of the line cap at the start of the line. It is also applied to the start cap of each dash + when the line has pattern. + """ + ) + vector3f[] velocities ( + doc = """If provided, 'velocities' should be used by renderers to + + compute positions between samples for the 'points' attribute, rather + than interpolating between neighboring 'points' samples. This is the + only reasonable means of computing motion blur for topologically + varying PointBased primitives. It follows that the length of each + 'velocities' sample must match the length of the corresponding + 'points' sample. Velocity is measured in position units per second, + as per most simulation software. To convert to position units per + UsdTimeCode, divide by UsdStage::GetTimeCodesPerSecond(). + + See also .""" + ) + token visibility = "inherited" ( + allowedTokens = ["inherited", "invisible"] + doc = '''Visibility is meant to be the simplest form of "pruning" + visibility that is supported by most DCC apps. Visibility is + animatable, allowing a sub-tree of geometry to be present for some + segment of a shot, and absent from others; unlike the action of + deactivating geometry prims, invisible geometry is still + available for inspection, for positioning, for defining volumes, etc.''' + ) + float[] widths ( + doc = """Provides width specification for the curves, whose application + will depend on whether the curve is oriented (normals are defined for + it), in which case widths are \"ribbon width\", or unoriented, in which + case widths are cylinder width. 'widths' is not a generic Primvar, + but the number of elements in this attribute will be determined by + its 'interpolation'. See . If 'widths' + and 'primvars:widths' are both specified, the latter has precedence.""" + ) + uniform token[] xformOpOrder ( + doc = """Encodes the sequence of transformation operations in the + order in which they should be pushed onto a transform stack while + visiting a UsdStage's prims in a graph traversal that will effect + the desired positioning for this prim and its descendant prims. + + You should rarely, if ever, need to manipulate this attribute directly. + It is managed by the AddXformOp(), SetResetXformStack(), and + SetXformOpOrder(), and consulted by GetOrderedXformOps() and + GetLocalTransformation().""" + ) +} + +class "DashDotPatternAPI" ( + doc = """UsdGeomDashDotPatternAPI is an API schema that provides an interface for the dash-dot patterns of the + DashDotLines primitive.""" +) +{ + uniform float2[] pattern ( + doc = """An array of float2 which saves the dash-dot pattern. For each float2, the x value and the y value + must be zero or positive. The x value saves the offset of the start of current symbol, from the end of the + previous symbol. If the current symbol is the first symbol, the offset is from the start of the pattern to + the start of current symbol. The y value saves the length of the current symbol. If it is zero, the current + symbol is a dot. If it is larger than zero, the current symbol is a dash. As a result, the total sum of all + the x value and y value will be the length from the start of the pattern to the end of the last symbol. This + sum must be smaller than patternPeriod. + + For example, assume the pattern is [(0, 10), (1, 4), (3, 0)]. It means the first symbol is a dash which is + from 0 to 10. The second symbol is a dash which is from 11 to 15, and the third symbol is a dot which is at + position 18. There are gaps between 10 and 11, and between 15 and 18. If the patternPeriod is 20, there is + also a gap between 18 and 20.""" + ) + uniform float patternPeriod = 0 ( + doc = "The length of a pattern. If there is no pattern, it should be zero." + ) +} + class Points "Points" ( doc = """Points are analogous to the RiPoints spec. diff --git a/pxr/usd/usdGeom/module.cpp b/pxr/usd/usdGeom/module.cpp index 360fff2909..33de957fc1 100644 --- a/pxr/usd/usdGeom/module.cpp +++ b/pxr/usd/usdGeom/module.cpp @@ -1,5 +1,5 @@ // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. @@ -13,6 +13,7 @@ TF_WRAP_MODULE { TF_WRAP(UsdGeomBBoxCache); TF_WRAP(UsdGeomConstraintTarget); + TF_WRAP(UsdGeomDashDotPatternAPI); TF_WRAP(UsdGeomModelAPI); TF_WRAP(UsdGeomPrimvar); TF_WRAP(UsdGeomPrimvarsAPI); @@ -48,6 +49,7 @@ TF_WRAP_MODULE TF_WRAP(UsdGeomPoints); TF_WRAP(UsdGeomCurves); TF_WRAP(UsdGeomBasisCurves); + TF_WRAP(UsdGeomDashDotLines); TF_WRAP(UsdGeomHermiteCurves); TF_WRAP(UsdGeomNurbsCurves); TF_WRAP(UsdGeomPointInstancer); diff --git a/pxr/usd/usdGeom/plugInfo.json b/pxr/usd/usdGeom/plugInfo.json index ff8ca3de7d..2c64ecf09c 100644 --- a/pxr/usd/usdGeom/plugInfo.json +++ b/pxr/usd/usdGeom/plugInfo.json @@ -172,6 +172,26 @@ "implementsComputeExtent": true, "schemaKind": "concreteTyped" }, + "UsdGeomDashDotLines": { + "alias": { + "UsdSchemaBase": "DashDotLines" + }, + "autoGenerated": true, + "bases": [ + "UsdGeomCurves" + ], + "schemaKind": "concreteTyped" + }, + "UsdGeomDashDotPatternAPI": { + "alias": { + "UsdSchemaBase": "DashDotPatternAPI" + }, + "autoGenerated": true, + "bases": [ + "UsdAPISchemaBase" + ], + "schemaKind": "singleApplyAPI" + }, "UsdGeomGprim": { "alias": { "UsdSchemaBase": "Gprim" diff --git a/pxr/usd/usdGeom/schema.usda b/pxr/usd/usdGeom/schema.usda index b274551766..121d316d4c 100644 --- a/pxr/usd/usdGeom/schema.usda +++ b/pxr/usd/usdGeom/schema.usda @@ -1861,6 +1861,71 @@ class NurbsCurves "NurbsCurves" ( ) } +class DashDotLines "DashDotLines" ( + inherits = + doc = """This schema is for a line primitive whose width in screen space will not change. And the primitive + can have dash-dot patterns. This type of curve is usually used in a sketch file, or nondiegetic visualizations. + + The basic shape for the primitive is a set of lines or polylines. A general type curve is not supported in this + schema. + + If the lines have dash-dot patterns, it must inherit from a "pattern" who applies with DashDotPatternAPI. The + length of the pattern can be in screen space or world space.""" +) { + uniform bool screenSpacePattern = true ( + doc = """Whether the dash-dot pattern length can be varied. It is only valid when the DashDotLines primitive + inherits from a "pattern" who applies with DashDotPatternAPI. If it is true, the length of the pattern is in + screen space, and it will not change. If you zoom in and the line is longer on the screen, you will see the + patterns will move on the line, and there will be more patterns on the line. If it is false, the length of + the pattern is in world space. If you zoom in, you will see the pattern will be larger, and it will not move + on the line. + """ + ) + + uniform float patternScale = 1.0 ( + doc = """This property is a scale value to lengthen or shorten a dash-dot pattern. It is only valid when the + DashDotLines primitive inherits from a "pattern" who applies with DashDotPatternAPI.""" + ) + + uniform token startCapType = "round" ( + allowedTokens = ["round", "square", "triangle"] + doc = """The shape of the line cap at the start of the line. It is also applied to the start cap of each dash + when the line has pattern. + """) + + uniform token endCapType = "round" ( + allowedTokens = ["round", "square", "triangle"] + doc = """The shape of the line cap at the end of the line. It is also applied to the end cap of each dash + when the line has pattern. + """) +} + +class "DashDotPatternAPI" ( + inherits = + doc = """UsdGeomDashDotPatternAPI is an API schema that provides an interface for the dash-dot patterns of the + DashDotLines primitive.""" +) +{ + uniform float2[] pattern ( + doc = """An array of float2 which saves the dash-dot pattern. For each float2, the x value and the y value + must be zero or positive. The x value saves the offset of the start of current symbol, from the end of the + previous symbol. If the current symbol is the first symbol, the offset is from the start of the pattern to + the start of current symbol. The y value saves the length of the current symbol. If it is zero, the current + symbol is a dot. If it is larger than zero, the current symbol is a dash. As a result, the total sum of all + the x value and y value will be the length from the start of the pattern to the end of the last symbol. This + sum must be smaller than patternPeriod. + + For example, assume the pattern is [(0, 10), (1, 4), (3, 0)]. It means the first symbol is a dash which is + from 0 to 10. The second symbol is a dash which is from 11 to 15, and the third symbol is a dot which is at + position 18. There are gaps between 10 and 11, and between 15 and 18. If the patternPeriod is 20, there is + also a gap between 18 and 20.""" + ) + + uniform float patternPeriod = 0.0 ( + doc = """The length of a pattern. If there is no pattern, it should be zero.""" + ) +} + class Points "Points" ( customData = { dictionary extraPlugInfo = { diff --git a/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines.py b/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines.py new file mode 100644 index 0000000000..fe281bd46f --- /dev/null +++ b/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines.py @@ -0,0 +1,51 @@ +#!/pxrpythonsubst +# +# Copyright 2023 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. + +import sys, unittest +from pxr import Sdf, Usd, UsdGeom, UsdShade + +class TestUsdGeomDashDotLines(unittest.TestCase): + def test_InterpolationTypes(self): + stage = Usd.Stage.Open('dashDotLines.usda') + t = Usd.TimeCode.Default() + c = UsdGeom.DashDotLines.Get(stage, '/StyledPolyline') + # Test attributes. + self.assertTrue(c.GetBoolAttr(c.GetScreenSpacePatternAttr(), t)) + self.assertEqual(c.GetFloatAttr(c.GetPatternScaleAttr(), t), 5.0) + self.assertEqual(c.GetTokenAttr(c.GetStartCapTypeAttr(), t), UsdGeom.Tokens.round) + self.assertEqual(c.GetTokenAttr(c.GetEndCapTypeAttr(), t), UsdGeom.Tokens.triangle) + + # Test dashDotPattern inheritance. + prim = c.GetPrim() + patternPeriodAttr = prim.GetAttribute(UsdGeom.Tokens.patternPeriod) + self.assertEqual(patternPeriodAttr.Get(), 20.0) + patternAttr = prim.GetAttribute(UsdGeom.Tokens.pattern) + float2Array = patternAttr.Get() + self.assertEqual(float2Array[0][0], 0) + self.assertEqual(float2Array[0][1], 10) + self.assertEqual(float2Array[1][0], 5) + self.assertEqual(float2Array[1][1], 0) + +if __name__ == '__main__': + unittest.main() diff --git a/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines/dashDotLines.usda b/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines/dashDotLines.usda new file mode 100644 index 0000000000..bd0796eab1 --- /dev/null +++ b/pxr/usd/usdGeom/testenv/testUsdGeomDashDotLines/dashDotLines.usda @@ -0,0 +1,20 @@ +#usda 1.0 + +def DashDotLines "StyledPolyline" ( + inherits = [] +) { + bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "triangle" + float patternScale = 5 + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} + +def DashDotPattern "MyPattern" +{ + float patternPeriod = 20 + float2[] pattern = [(0, 10), (5, 0)] +} \ No newline at end of file diff --git a/pxr/usd/usdGeom/tokens.cpp b/pxr/usd/usdGeom/tokens.cpp index 7d09e44604..020ad60d2d 100644 --- a/pxr/usd/usdGeom/tokens.cpp +++ b/pxr/usd/usdGeom/tokens.cpp @@ -1,5 +1,5 @@ // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. @@ -45,6 +45,7 @@ UsdGeomTokensType::UsdGeomTokensType() : edgeOnly("edgeOnly", TfToken::Immortal), elementSize("elementSize", TfToken::Immortal), elementType("elementType", TfToken::Immortal), + endCapType("endCapType", TfToken::Immortal), exposure("exposure", TfToken::Immortal), extent("extent", TfToken::Immortal), extentsHint("extentsHint", TfToken::Immortal), @@ -106,6 +107,9 @@ UsdGeomTokensType::UsdGeomTokensType() : origin("origin", TfToken::Immortal), orthographic("orthographic", TfToken::Immortal), partition("partition", TfToken::Immortal), + pattern("pattern", TfToken::Immortal), + patternPeriod("patternPeriod", TfToken::Immortal), + patternScale("patternScale", TfToken::Immortal), periodic("periodic", TfToken::Immortal), perspective("perspective", TfToken::Immortal), pinned("pinned", TfToken::Immortal), @@ -132,17 +136,22 @@ UsdGeomTokensType::UsdGeomTokensType() : renderVisibility("renderVisibility", TfToken::Immortal), right("right", TfToken::Immortal), rightHanded("rightHanded", TfToken::Immortal), + round("round", TfToken::Immortal), scales("scales", TfToken::Immortal), + screenSpacePattern("screenSpacePattern", TfToken::Immortal), shutterClose("shutter:close", TfToken::Immortal), shutterOpen("shutter:open", TfToken::Immortal), size("size", TfToken::Immortal), smooth("smooth", TfToken::Immortal), + square("square", TfToken::Immortal), + startCapType("startCapType", TfToken::Immortal), stereoRole("stereoRole", TfToken::Immortal), subdivisionScheme("subdivisionScheme", TfToken::Immortal), surfaceFaceVertexIndices("surfaceFaceVertexIndices", TfToken::Immortal), tangents("tangents", TfToken::Immortal), tetrahedron("tetrahedron", TfToken::Immortal), tetVertexIndices("tetVertexIndices", TfToken::Immortal), + triangle("triangle", TfToken::Immortal), triangleSubdivisionRule("triangleSubdivisionRule", TfToken::Immortal), trimCurveCounts("trimCurve:counts", TfToken::Immortal), trimCurveKnots("trimCurve:knots", TfToken::Immortal), @@ -189,6 +198,8 @@ UsdGeomTokensType::UsdGeomTokensType() : Curves("Curves", TfToken::Immortal), Cylinder("Cylinder", TfToken::Immortal), Cylinder_1("Cylinder_1", TfToken::Immortal), + DashDotLines("DashDotLines", TfToken::Immortal), + DashDotPatternAPI("DashDotPatternAPI", TfToken::Immortal), GeomModelAPI("GeomModelAPI", TfToken::Immortal), GeomSubset("GeomSubset", TfToken::Immortal), Gprim("Gprim", TfToken::Immortal), @@ -247,6 +258,7 @@ UsdGeomTokensType::UsdGeomTokensType() : edgeOnly, elementSize, elementType, + endCapType, exposure, extent, extentsHint, @@ -308,6 +320,9 @@ UsdGeomTokensType::UsdGeomTokensType() : origin, orthographic, partition, + pattern, + patternPeriod, + patternScale, periodic, perspective, pinned, @@ -334,17 +349,22 @@ UsdGeomTokensType::UsdGeomTokensType() : renderVisibility, right, rightHanded, + round, scales, + screenSpacePattern, shutterClose, shutterOpen, size, smooth, + square, + startCapType, stereoRole, subdivisionScheme, surfaceFaceVertexIndices, tangents, tetrahedron, tetVertexIndices, + triangle, triangleSubdivisionRule, trimCurveCounts, trimCurveKnots, @@ -391,6 +411,8 @@ UsdGeomTokensType::UsdGeomTokensType() : Curves, Cylinder, Cylinder_1, + DashDotLines, + DashDotPatternAPI, GeomModelAPI, GeomSubset, Gprim, diff --git a/pxr/usd/usdGeom/tokens.h b/pxr/usd/usdGeom/tokens.h index 96e4d648de..696996cffd 100644 --- a/pxr/usd/usdGeom/tokens.h +++ b/pxr/usd/usdGeom/tokens.h @@ -1,5 +1,5 @@ // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. @@ -189,6 +189,10 @@ struct UsdGeomTokensType { /// /// UsdGeomSubset const TfToken elementType; + /// \brief "endCapType" + /// + /// UsdGeomDashDotLines + const TfToken endCapType; /// \brief "exposure" /// /// UsdGeomCamera @@ -433,6 +437,18 @@ struct UsdGeomTokensType { /// /// A type of family of GeomSubsets. It implies that every element appears exacly once in only one of the subsets in the family. const TfToken partition; + /// \brief "pattern" + /// + /// UsdGeomDashDotPatternAPI + const TfToken pattern; + /// \brief "patternPeriod" + /// + /// UsdGeomDashDotPatternAPI + const TfToken patternPeriod; + /// \brief "patternScale" + /// + /// UsdGeomDashDotLines + const TfToken patternScale; /// \brief "periodic" /// /// Possible value for UsdGeomNurbsPatch::GetUFormAttr(), Possible value for UsdGeomNurbsPatch::GetVFormAttr(), Possible value for UsdGeomBasisCurves::GetWrapAttr() @@ -537,10 +553,18 @@ struct UsdGeomTokensType { /// /// Fallback value for UsdGeomGprim::GetOrientationAttr() const TfToken rightHanded; + /// \brief "round" + /// + /// Fallback value for UsdGeomDashDotLines::GetEndCapTypeAttr(), Fallback value for UsdGeomDashDotLines::GetStartCapTypeAttr() + const TfToken round; /// \brief "scales" /// /// UsdGeomPointInstancer const TfToken scales; + /// \brief "screenSpacePattern" + /// + /// UsdGeomDashDotLines + const TfToken screenSpacePattern; /// \brief "shutter:close" /// /// UsdGeomCamera @@ -557,6 +581,14 @@ struct UsdGeomTokensType { /// /// Possible value for UsdGeomMesh::GetTriangleSubdivisionRuleAttr() const TfToken smooth; + /// \brief "square" + /// + /// Possible value for UsdGeomDashDotLines::GetEndCapTypeAttr(), Possible value for UsdGeomDashDotLines::GetStartCapTypeAttr() + const TfToken square; + /// \brief "startCapType" + /// + /// UsdGeomDashDotLines + const TfToken startCapType; /// \brief "stereoRole" /// /// UsdGeomCamera @@ -581,6 +613,10 @@ struct UsdGeomTokensType { /// /// UsdGeomTetMesh const TfToken tetVertexIndices; + /// \brief "triangle" + /// + /// Possible value for UsdGeomDashDotLines::GetEndCapTypeAttr(), Possible value for UsdGeomDashDotLines::GetStartCapTypeAttr() + const TfToken triangle; /// \brief "triangleSubdivisionRule" /// /// UsdGeomMesh @@ -765,6 +801,14 @@ struct UsdGeomTokensType { /// /// Schema identifer for UsdGeomCylinder_1 const TfToken Cylinder_1; + /// \brief "DashDotLines" + /// + /// Schema identifer and family for UsdGeomDashDotLines + const TfToken DashDotLines; + /// \brief "DashDotPatternAPI" + /// + /// Schema identifer and family for UsdGeomDashDotPatternAPI + const TfToken DashDotPatternAPI; /// \brief "GeomModelAPI" /// /// Schema identifer and family for UsdGeomModelAPI diff --git a/pxr/usd/usdGeom/wrapDashDotLines.cpp b/pxr/usd/usdGeom/wrapDashDotLines.cpp new file mode 100644 index 0000000000..70569c29fc --- /dev/null +++ b/pxr/usd/usdGeom/wrapDashDotLines.cpp @@ -0,0 +1,188 @@ +// +// Copyright 2024 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. +// +#include "pxr/usd/usdGeom/dashDotLines.h" +#include "pxr/usd/usd/schemaBase.h" + +#include "pxr/usd/sdf/primSpec.h" + +#include "pxr/usd/usd/pyConversions.h" +#include "pxr/base/tf/pyContainerConversions.h" +#include "pxr/base/tf/pyResultConversions.h" +#include "pxr/base/tf/pyUtils.h" +#include "pxr/base/tf/wrapTypeHelpers.h" + +#include + +#include + +using namespace boost::python; + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { + +#define WRAP_CUSTOM \ + template static void _CustomWrapCode(Cls &_class) + +// fwd decl. +WRAP_CUSTOM; + + +static UsdAttribute +_CreateScreenSpacePatternAttr(UsdGeomDashDotLines &self, + object defaultVal, bool writeSparsely) { + return self.CreateScreenSpacePatternAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Bool), writeSparsely); +} + +static UsdAttribute +_CreatePatternScaleAttr(UsdGeomDashDotLines &self, + object defaultVal, bool writeSparsely) { + return self.CreatePatternScaleAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} + +static UsdAttribute +_CreateStartCapTypeAttr(UsdGeomDashDotLines &self, + object defaultVal, bool writeSparsely) { + return self.CreateStartCapTypeAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Token), writeSparsely); +} + +static UsdAttribute +_CreateEndCapTypeAttr(UsdGeomDashDotLines &self, + object defaultVal, bool writeSparsely) { + return self.CreateEndCapTypeAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Token), writeSparsely); +} + +static std::string +_Repr(const UsdGeomDashDotLines &self) +{ + std::string primRepr = TfPyRepr(self.GetPrim()); + return TfStringPrintf( + "UsdGeom.DashDotLines(%s)", + primRepr.c_str()); +} + +} // anonymous namespace + +void wrapUsdGeomDashDotLines() +{ + typedef UsdGeomDashDotLines This; + + class_ > + cls("DashDotLines"); + + cls + .def(init(arg("prim"))) + .def(init(arg("schemaObj"))) + .def(TfTypePythonClass()) + + .def("Get", &This::Get, (arg("stage"), arg("path"))) + .staticmethod("Get") + + .def("Define", &This::Define, (arg("stage"), arg("path"))) + .staticmethod("Define") + + .def("GetSchemaAttributeNames", + &This::GetSchemaAttributeNames, + arg("includeInherited")=true, + return_value_policy()) + .staticmethod("GetSchemaAttributeNames") + + .def("_GetStaticTfType", (TfType const &(*)()) TfType::Find, + return_value_policy()) + .staticmethod("_GetStaticTfType") + + .def(!self) + + + .def("GetScreenSpacePatternAttr", + &This::GetScreenSpacePatternAttr) + .def("CreateScreenSpacePatternAttr", + &_CreateScreenSpacePatternAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetPatternScaleAttr", + &This::GetPatternScaleAttr) + .def("CreatePatternScaleAttr", + &_CreatePatternScaleAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetStartCapTypeAttr", + &This::GetStartCapTypeAttr) + .def("CreateStartCapTypeAttr", + &_CreateStartCapTypeAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetEndCapTypeAttr", + &This::GetEndCapTypeAttr) + .def("CreateEndCapTypeAttr", + &_CreateEndCapTypeAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("__repr__", ::_Repr) + ; + + _CustomWrapCode(cls); +} + +// ===================================================================== // +// Feel free to add custom code below this line, it will be preserved by +// the code generator. The entry point for your custom code should look +// minimally like the following: +// +// WRAP_CUSTOM { +// _class +// .def("MyCustomMethod", ...) +// ; +// } +// +// Of course any other ancillary or support code may be provided. +// +// Just remember to wrap code in the appropriate delimiters: +// 'namespace {', '}'. +// +// ===================================================================== // +// --(BEGIN CUSTOM CODE)-- + +namespace { + +WRAP_CUSTOM { + typedef UsdGeomDashDotLines This; + + _class + .def("GetTokenAttr", &This::GetTokenAttr) + .def("GetFloatAttr", &This::GetFloatAttr) + .def("GetIntAttr", &This::GetIntAttr) + .def("GetBoolAttr", &This::GetBoolAttr) + ; +} + +} diff --git a/pxr/usd/usdGeom/wrapDashDotPatternAPI.cpp b/pxr/usd/usdGeom/wrapDashDotPatternAPI.cpp new file mode 100644 index 0000000000..c40ac5aa2b --- /dev/null +++ b/pxr/usd/usdGeom/wrapDashDotPatternAPI.cpp @@ -0,0 +1,174 @@ +// +// Copyright 2024 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. +// +#include "pxr/usd/usdGeom/dashDotPatternAPI.h" +#include "pxr/usd/usd/schemaBase.h" + +#include "pxr/usd/sdf/primSpec.h" + +#include "pxr/usd/usd/pyConversions.h" +#include "pxr/base/tf/pyAnnotatedBoolResult.h" +#include "pxr/base/tf/pyContainerConversions.h" +#include "pxr/base/tf/pyResultConversions.h" +#include "pxr/base/tf/pyUtils.h" +#include "pxr/base/tf/wrapTypeHelpers.h" + +#include + +#include + +using namespace boost::python; + +PXR_NAMESPACE_USING_DIRECTIVE + +namespace { + +#define WRAP_CUSTOM \ + template static void _CustomWrapCode(Cls &_class) + +// fwd decl. +WRAP_CUSTOM; + + +static UsdAttribute +_CreatePatternAttr(UsdGeomDashDotPatternAPI &self, + object defaultVal, bool writeSparsely) { + return self.CreatePatternAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float2Array), writeSparsely); +} + +static UsdAttribute +_CreatePatternPeriodAttr(UsdGeomDashDotPatternAPI &self, + object defaultVal, bool writeSparsely) { + return self.CreatePatternPeriodAttr( + UsdPythonToSdfType(defaultVal, SdfValueTypeNames->Float), writeSparsely); +} + +static std::string +_Repr(const UsdGeomDashDotPatternAPI &self) +{ + std::string primRepr = TfPyRepr(self.GetPrim()); + return TfStringPrintf( + "UsdGeom.DashDotPatternAPI(%s)", + primRepr.c_str()); +} + +struct UsdGeomDashDotPatternAPI_CanApplyResult : + public TfPyAnnotatedBoolResult +{ + UsdGeomDashDotPatternAPI_CanApplyResult(bool val, std::string const &msg) : + TfPyAnnotatedBoolResult(val, msg) {} +}; + +static UsdGeomDashDotPatternAPI_CanApplyResult +_WrapCanApply(const UsdPrim& prim) +{ + std::string whyNot; + bool result = UsdGeomDashDotPatternAPI::CanApply(prim, &whyNot); + return UsdGeomDashDotPatternAPI_CanApplyResult(result, whyNot); +} + +} // anonymous namespace + +void wrapUsdGeomDashDotPatternAPI() +{ + typedef UsdGeomDashDotPatternAPI This; + + UsdGeomDashDotPatternAPI_CanApplyResult::Wrap( + "_CanApplyResult", "whyNot"); + + class_ > + cls("DashDotPatternAPI"); + + cls + .def(init(arg("prim"))) + .def(init(arg("schemaObj"))) + .def(TfTypePythonClass()) + + .def("Get", &This::Get, (arg("stage"), arg("path"))) + .staticmethod("Get") + + .def("CanApply", &_WrapCanApply, (arg("prim"))) + .staticmethod("CanApply") + + .def("Apply", &This::Apply, (arg("prim"))) + .staticmethod("Apply") + + .def("GetSchemaAttributeNames", + &This::GetSchemaAttributeNames, + arg("includeInherited")=true, + return_value_policy()) + .staticmethod("GetSchemaAttributeNames") + + .def("_GetStaticTfType", (TfType const &(*)()) TfType::Find, + return_value_policy()) + .staticmethod("_GetStaticTfType") + + .def(!self) + + + .def("GetPatternAttr", + &This::GetPatternAttr) + .def("CreatePatternAttr", + &_CreatePatternAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("GetPatternPeriodAttr", + &This::GetPatternPeriodAttr) + .def("CreatePatternPeriodAttr", + &_CreatePatternPeriodAttr, + (arg("defaultValue")=object(), + arg("writeSparsely")=false)) + + .def("__repr__", ::_Repr) + ; + + _CustomWrapCode(cls); +} + +// ===================================================================== // +// Feel free to add custom code below this line, it will be preserved by +// the code generator. The entry point for your custom code should look +// minimally like the following: +// +// WRAP_CUSTOM { +// _class +// .def("MyCustomMethod", ...) +// ; +// } +// +// Of course any other ancillary or support code may be provided. +// +// Just remember to wrap code in the appropriate delimiters: +// 'namespace {', '}'. +// +// ===================================================================== // +// --(BEGIN CUSTOM CODE)-- + +namespace { + +WRAP_CUSTOM { +} + +} diff --git a/pxr/usd/usdGeom/wrapTokens.cpp b/pxr/usd/usdGeom/wrapTokens.cpp index e2fec5b804..2b5e94493b 100644 --- a/pxr/usd/usdGeom/wrapTokens.cpp +++ b/pxr/usd/usdGeom/wrapTokens.cpp @@ -1,5 +1,5 @@ // -// Copyright 2016 Pixar +// Copyright 2024 Pixar // // Licensed under the terms set forth in the LICENSE.txt file available at // https://openusd.org/license. @@ -83,6 +83,7 @@ void wrapUsdGeomTokens() _AddToken(cls, "edgeOnly", UsdGeomTokens->edgeOnly); _AddToken(cls, "elementSize", UsdGeomTokens->elementSize); _AddToken(cls, "elementType", UsdGeomTokens->elementType); + _AddToken(cls, "endCapType", UsdGeomTokens->endCapType); _AddToken(cls, "exposure", UsdGeomTokens->exposure); _AddToken(cls, "extent", UsdGeomTokens->extent); _AddToken(cls, "extentsHint", UsdGeomTokens->extentsHint); @@ -144,6 +145,9 @@ void wrapUsdGeomTokens() _AddToken(cls, "origin", UsdGeomTokens->origin); _AddToken(cls, "orthographic", UsdGeomTokens->orthographic); _AddToken(cls, "partition", UsdGeomTokens->partition); + _AddToken(cls, "pattern", UsdGeomTokens->pattern); + _AddToken(cls, "patternPeriod", UsdGeomTokens->patternPeriod); + _AddToken(cls, "patternScale", UsdGeomTokens->patternScale); _AddToken(cls, "periodic", UsdGeomTokens->periodic); _AddToken(cls, "perspective", UsdGeomTokens->perspective); _AddToken(cls, "pinned", UsdGeomTokens->pinned); @@ -170,17 +174,22 @@ void wrapUsdGeomTokens() _AddToken(cls, "renderVisibility", UsdGeomTokens->renderVisibility); _AddToken(cls, "right", UsdGeomTokens->right); _AddToken(cls, "rightHanded", UsdGeomTokens->rightHanded); + _AddToken(cls, "round", UsdGeomTokens->round); _AddToken(cls, "scales", UsdGeomTokens->scales); + _AddToken(cls, "screenSpacePattern", UsdGeomTokens->screenSpacePattern); _AddToken(cls, "shutterClose", UsdGeomTokens->shutterClose); _AddToken(cls, "shutterOpen", UsdGeomTokens->shutterOpen); _AddToken(cls, "size", UsdGeomTokens->size); _AddToken(cls, "smooth", UsdGeomTokens->smooth); + _AddToken(cls, "square", UsdGeomTokens->square); + _AddToken(cls, "startCapType", UsdGeomTokens->startCapType); _AddToken(cls, "stereoRole", UsdGeomTokens->stereoRole); _AddToken(cls, "subdivisionScheme", UsdGeomTokens->subdivisionScheme); _AddToken(cls, "surfaceFaceVertexIndices", UsdGeomTokens->surfaceFaceVertexIndices); _AddToken(cls, "tangents", UsdGeomTokens->tangents); _AddToken(cls, "tetrahedron", UsdGeomTokens->tetrahedron); _AddToken(cls, "tetVertexIndices", UsdGeomTokens->tetVertexIndices); + _AddToken(cls, "triangle", UsdGeomTokens->triangle); _AddToken(cls, "triangleSubdivisionRule", UsdGeomTokens->triangleSubdivisionRule); _AddToken(cls, "trimCurveCounts", UsdGeomTokens->trimCurveCounts); _AddToken(cls, "trimCurveKnots", UsdGeomTokens->trimCurveKnots); @@ -227,6 +236,8 @@ void wrapUsdGeomTokens() _AddToken(cls, "Curves", UsdGeomTokens->Curves); _AddToken(cls, "Cylinder", UsdGeomTokens->Cylinder); _AddToken(cls, "Cylinder_1", UsdGeomTokens->Cylinder_1); + _AddToken(cls, "DashDotLines", UsdGeomTokens->DashDotLines); + _AddToken(cls, "DashDotPatternAPI", UsdGeomTokens->DashDotPatternAPI); _AddToken(cls, "GeomModelAPI", UsdGeomTokens->GeomModelAPI); _AddToken(cls, "GeomSubset", UsdGeomTokens->GeomSubset); _AddToken(cls, "Gprim", UsdGeomTokens->Gprim); diff --git a/pxr/usdImaging/usdImaging/CMakeLists.txt b/pxr/usdImaging/usdImaging/CMakeLists.txt index e26a07a6e5..8429a62f60 100644 --- a/pxr/usdImaging/usdImaging/CMakeLists.txt +++ b/pxr/usdImaging/usdImaging/CMakeLists.txt @@ -83,6 +83,7 @@ pxr_library(usdImaging cubeAdapter cylinderAdapter cylinderLightAdapter + dashDotLinesAdapter diskLightAdapter distantLightAdapter domeLightAdapter diff --git a/pxr/usdImaging/usdImaging/basisCurvesAdapter.cpp b/pxr/usdImaging/usdImaging/basisCurvesAdapter.cpp index b6b430fc42..e266b395c4 100644 --- a/pxr/usdImaging/usdImaging/basisCurvesAdapter.cpp +++ b/pxr/usdImaging/usdImaging/basisCurvesAdapter.cpp @@ -376,7 +376,7 @@ UsdImagingBasisCurvesAdapter::GetTopology(UsdPrim const& prim, } HdBasisCurvesTopology topology( - topoCurveType, topoCurveBasis, topoCurveWrap, + topoCurveType, topoCurveBasis, topoCurveWrap, HdTokens->none, _Get(prim, UsdGeomTokens->curveVertexCounts, time), VtIntArray()); return VtValue(topology); diff --git a/pxr/usdImaging/usdImaging/dashDotLinesAdapter.cpp b/pxr/usdImaging/usdImaging/dashDotLinesAdapter.cpp new file mode 100644 index 0000000000..fb4d4cc30e --- /dev/null +++ b/pxr/usdImaging/usdImaging/dashDotLinesAdapter.cpp @@ -0,0 +1,429 @@ +// +// 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. +// +#include "pxr/usdImaging/usdImaging/dashDotLinesAdapter.h" + +#include "pxr/usdImaging/usdImaging/dataSourceBasisCurves.h" +#include "pxr/usdImaging/usdImaging/delegate.h" +#include "pxr/usdImaging/usdImaging/indexProxy.h" +#include "pxr/usdImaging/usdImaging/primvarUtils.h" +#include "pxr/usdImaging/usdImaging/tokens.h" + +#include "pxr/imaging/hd/basisCurves.h" +#include "pxr/imaging/hd/perfLog.h" + +#include "pxr/usd/usdGeom/dashDotLines.h" +#include "pxr/usd/usdGeom/dashDotPatternAPI.h" +#include "pxr/usd/usdGeom/primvarsAPI.h" +#include "pxr/usd/usdGeom/xformCache.h" + +#include "pxr/base/tf/type.h" + +PXR_NAMESPACE_OPEN_SCOPE + +// XXX: These primvar names are known here so that they may be exempted from +// the filtering procedure that would normally exclude them. This primvar +// filtering procedure is slated for removal in favor of the one in hdSt, +// but in the mean time we must know these names here, despite them not yet +// being part of any formal schema and thus subject to change or deletion. +TF_DEFINE_PRIVATE_TOKENS( + _rprimPrimvarNameTokens, + (pointSizeScale) + (screenSpaceWidths) + (minScreenSpaceWidths) +); + +TF_REGISTRY_FUNCTION(TfType) +{ + typedef UsdImagingDashDotLinesAdapter Adapter; + TfType t = TfType::Define >(); + t.SetFactory< UsdImagingPrimAdapterFactory >(); +} + +UsdImagingDashDotLinesAdapter::~UsdImagingDashDotLinesAdapter() +{ +} + +TfTokenVector +UsdImagingDashDotLinesAdapter::GetImagingSubprims(UsdPrim const& prim) +{ + return { TfToken() }; +} + +TfToken +UsdImagingDashDotLinesAdapter::GetImagingSubprimType( + UsdPrim const& prim, + TfToken const& subprim) +{ + // The DashDotLines primitive uses the basisCurves rprim. + if (subprim.IsEmpty()) { + return HdPrimTypeTokens->basisCurves; + } + return TfToken(); +} + +HdContainerDataSourceHandle +UsdImagingDashDotLinesAdapter::GetImagingSubprimData( + UsdPrim const& prim, + TfToken const& subprim, + const UsdImagingDataSourceStageGlobals &stageGlobals) +{ + // The DashDotLines primitive uses the basisCurves rprim. + if (subprim.IsEmpty()) { + return UsdImagingDataSourceBasisCurvesPrim::New( + prim.GetPath(), + prim, + stageGlobals); + } + return nullptr; +} + +HdDataSourceLocatorSet +UsdImagingDashDotLinesAdapter::InvalidateImagingSubprim( + UsdPrim const& prim, + TfToken const& subprim, + TfTokenVector const& properties, + const UsdImagingPropertyInvalidationType invalidationType) +{ + // The DashDotLines primitive uses the basisCurves rprim. + if (subprim.IsEmpty()) { + return UsdImagingDataSourceBasisCurvesPrim::Invalidate( + prim, subprim, properties, invalidationType); + } + + return HdDataSourceLocatorSet(); +} + +bool +UsdImagingDashDotLinesAdapter::IsSupported( + UsdImagingIndexProxy const* index) const +{ + // The DashDotLines primitive uses the basisCurves rprim. + return index->IsRprimTypeSupported(HdPrimTypeTokens->basisCurves); +} + +SdfPath +UsdImagingDashDotLinesAdapter::Populate(UsdPrim const& prim, + UsdImagingIndexProxy* index, + UsdImagingInstancerContext const* instancerContext) +{ + // The DashDotLines primitive uses the basisCurves rprim. + return _AddRprim(HdPrimTypeTokens->basisCurves, + prim, index, GetMaterialUsdPath(prim), instancerContext); +} + +void +UsdImagingDashDotLinesAdapter::TrackVariability(UsdPrim const& prim, + SdfPath const& cachePath, + HdDirtyBits* timeVaryingBits, + UsdImagingInstancerContext const* + instancerContext) const +{ + BaseAdapter::TrackVariability( + prim, cachePath, timeVaryingBits, instancerContext); + + // Discover time-varying points. + _IsVarying(prim, + UsdGeomTokens->points, + HdChangeTracker::DirtyPoints, + UsdImagingTokens->usdVaryingPrimvar, + timeVaryingBits, + /*isInherited*/false); + + // Discover time-varying topology. + // + // Note that basis, wrap and type are all uniform attributes, so they can't + // vary over time. + _IsVarying(prim, UsdGeomTokens->curveVertexCounts, + HdChangeTracker::DirtyTopology, + UsdImagingTokens->usdVaryingTopology, + timeVaryingBits, + /*isInherited*/false); + + // Check for time-varying primvars:widths, and if that attribute + // doesn't exist also check for time-varying widths. + bool widthsExists = false; + _IsVarying(prim, + UsdImagingTokens->primvarsWidths, + HdChangeTracker::DirtyWidths, + UsdImagingTokens->usdVaryingWidths, + timeVaryingBits, + /*isInherited*/false, + &widthsExists); + if (!widthsExists) { + UsdGeomPrimvar pv = _GetInheritedPrimvar(prim, HdTokens->widths); + if (pv && pv.ValueMightBeTimeVarying()) { + *timeVaryingBits |= HdChangeTracker::DirtyWidths; + HD_PERF_COUNTER_INCR(UsdImagingTokens->usdVaryingWidths); + widthsExists = true; + } + } + if (!widthsExists) { + _IsVarying(prim, UsdGeomTokens->widths, + HdChangeTracker::DirtyWidths, + UsdImagingTokens->usdVaryingWidths, + timeVaryingBits, + /*isInherited*/false); + } +} + +bool +UsdImagingDashDotLinesAdapter::_IsBuiltinPrimvar(TfToken const& primvarName) const +{ + return (primvarName == HdTokens->widths) || + primvarName == HdTokens->pattern || + primvarName == HdTokens->patternPartCount || + primvarName == HdTokens->patternPeriod || + primvarName == HdTokens->patternScale || + primvarName == HdTokens->startCapType || + primvarName == HdTokens->endCapType || + UsdImagingGprimAdapter::_IsBuiltinPrimvar(primvarName); +} + +void +UsdImagingDashDotLinesAdapter::UpdateForTime( + UsdPrim const& prim, + SdfPath const& cachePath, + UsdTimeCode time, + HdDirtyBits requestedBits, + UsdImagingInstancerContext const* instancerContext) const +{ + BaseAdapter::UpdateForTime( + prim, cachePath, time, requestedBits, instancerContext); + + UsdImagingPrimvarDescCache* primvarDescCache = _GetPrimvarDescCache(); + HdPrimvarDescriptorVector& primvars = + primvarDescCache->GetPrimvars(cachePath); + + if (requestedBits & HdChangeTracker::DirtyWidths) { + // First check for "primvars:widths" + UsdGeomPrimvarsAPI primvarsApi(prim); + UsdGeomPrimvar pv = primvarsApi.GetPrimvar( + UsdImagingTokens->primvarsWidths); + if (!pv) { + // If it's not found locally, see if it's inherited + pv = _GetInheritedPrimvar(prim, HdTokens->widths); + } + + if (pv) { + _ComputeAndMergePrimvar(prim, pv, time, &primvars); + } else { + UsdGeomDashDotLines curves(prim); + HdInterpolation interpolation; + VtFloatArray widths; + if (curves.GetWidthsAttr().Get(&widths, time)) { + interpolation = UsdImagingUsdToHdInterpolation( + curves.GetWidthsInterpolation()); + } else { + interpolation = HdInterpolationConstant; + } + _MergePrimvar(&primvars, UsdGeomTokens->widths, interpolation); + } + } + + if (requestedBits & HdChangeTracker::DirtyPrimvar) { + _MergePrimvar(&primvars, HdTokens->pattern, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->patternPartCount, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->patternPeriod, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->patternScale, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->startCapType, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->endCapType, HdInterpolationConstant); + _MergePrimvar(&primvars, HdTokens->adjPoints1, HdInterpolationVertex); + _MergePrimvar(&primvars, HdTokens->adjPoints2, HdInterpolationVertex); + _MergePrimvar(&primvars, HdTokens->adjPoints3, HdInterpolationVertex); + _MergePrimvar(&primvars, HdTokens->accumulatedLength, HdInterpolationVertex); + _MergePrimvar(&primvars, HdTokens->extrude, HdInterpolationVertex); + } +} + +HdDirtyBits +UsdImagingDashDotLinesAdapter::ProcessPropertyChange(UsdPrim const& prim, + SdfPath const& cachePath, + TfToken const& propertyName) +{ + // Even though points is treated as a primvar, it is special and is always + // treated as a vertex primvar. + if (propertyName == UsdGeomTokens->points) { + return HdChangeTracker::DirtyPoints; + + } else if (propertyName == UsdGeomTokens->curveVertexCounts || + propertyName == UsdGeomTokens->screenSpacePattern) { + return HdChangeTracker::DirtyTopology; + + // Handle attributes that are treated as "built-in" primvars. + } else if (propertyName == UsdGeomTokens->widths) { + UsdGeomCurves curves(prim); + return UsdImagingPrimAdapter::_ProcessNonPrefixedPrimvarPropertyChange( + prim, cachePath, propertyName, HdTokens->widths, + UsdImagingUsdToHdInterpolation(curves.GetWidthsInterpolation()), + HdChangeTracker::DirtyWidths); + + // Handle prefixed primvars that use special dirty bits. + } else if (propertyName == UsdImagingTokens->primvarsWidths) { + return UsdImagingPrimAdapter::_ProcessPrefixedPrimvarPropertyChange( + prim, cachePath, propertyName, HdChangeTracker::DirtyWidths); + + } + + // Allow base class to handle change processing. + return BaseAdapter::ProcessPropertyChange(prim, cachePath, propertyName); +} + +/*virtual*/ +VtValue +UsdImagingDashDotLinesAdapter::GetTopology(UsdPrim const& prim, + SdfPath const& cachePath, + UsdTimeCode time) const +{ + TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + // These are uniform attributes and can't vary over time. + UsdTimeCode unvarying = UsdTimeCode::Default(); + TfToken topoCurveStyle; + // Get if the pattern is screen spaced. + bool isScreenSpacePattern = _Get(prim, UsdGeomTokens->screenSpacePattern, unvarying); + + if (isScreenSpacePattern) { + topoCurveStyle = HdTokens->screenSpaceDashDot; + } + else { + topoCurveStyle = HdTokens->dashDot; + } + + // We use the basisCurves rprim, so here we need to create the basisCurves topology. + HdBasisCurvesTopology topology( + HdTokens->linear, HdTokens->bezier, HdTokens->nonperiodic, topoCurveStyle, + _Get(prim, UsdGeomTokens->curveVertexCounts, time), + VtIntArray()); + return VtValue(topology); +} + +/*virtual*/ +VtValue +UsdImagingDashDotLinesAdapter::Get(UsdPrim const& prim, + SdfPath const& cachePath, + TfToken const& key, + UsdTimeCode time, + VtIntArray *outIndices) const +{ + TRACE_FUNCTION(); + HF_MALLOC_TAG_FUNCTION(); + + if (key == HdTokens->widths) { + // First check for "primvars:widths" + UsdGeomPrimvarsAPI primvarsApi(prim); + UsdGeomPrimvar pv = primvarsApi.GetPrimvar( + UsdImagingTokens->primvarsWidths); + if (!pv) { + // If it's not found locally, see if it's inherited + pv = _GetInheritedPrimvar(prim, HdTokens->widths); + } + + VtValue value; + + if (outIndices) { + if (pv && pv.Get(&value, time)) { + pv.GetIndices(outIndices, time); + return value; + } + } else if (pv && pv.ComputeFlattened(&value, time)) { + return value; + } + + // Try to get widths directly from the curves + UsdGeomDashDotLines curves(prim); + VtFloatArray widths; + if (curves && curves.GetWidthsAttr().Get(&widths, time)) { + value = widths; + return value; + } + } + else if (key == HdTokens->patternPartCount) { + UsdGeomDashDotLines curves(prim); + VtVec2fArray pattern; + if (curves) { + curves.GetPrim().GetAttribute(HdTokens->pattern).Get(&pattern, time); + } + int count = 0; + count = pattern.size(); + return VtValue(count); + } + else if (key == HdTokens->pattern) { + UsdGeomDashDotLines curves(prim); + VtVec2fArray pattern; + if (curves) { + curves.GetPrim().GetAttribute(HdTokens->pattern).Get(&pattern, time); + } + if (pattern.size() == 0) + { + pattern.emplace_back(0.0, 0.0); + } + return VtValue(pattern); + } + else if (key == HdTokens->patternPeriod) { + UsdGeomDashDotLines curves(prim); + float period = 1.0f; + if (curves) { + curves.GetPrim().GetAttribute(HdTokens->patternPeriod).Get(&period, time);; + } + return VtValue(period); + } + else if (key == HdTokens->patternScale) { + UsdGeomDashDotLines curves(prim); + float scale = 1.0f; + if (curves) { + curves.GetPatternScaleAttr().Get(&scale, time); + } + return VtValue(scale); + } + else if (key == HdTokens->startCapType) { + UsdGeomDashDotLines curves(prim); + TfToken startCapType = HdTokens->round; + if (curves) { + curves.GetStartCapTypeAttr().Get(&startCapType, time); + } + if(startCapType == HdTokens->square) + return VtValue(1); + else if(startCapType == HdTokens->triangle) + return VtValue(2); + else + return VtValue(0); + } + else if (key == HdTokens->endCapType) { + UsdGeomDashDotLines curves(prim); + TfToken endCapType = HdTokens->round; + if (curves) { + curves.GetEndCapTypeAttr().Get(&endCapType, time); + } + if (endCapType == HdTokens->square) + return VtValue(1); + else if (endCapType == HdTokens->triangle) + return VtValue(2); + else + return VtValue(0); + } + return BaseAdapter::Get(prim, cachePath, key, time, outIndices); +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/pxr/usdImaging/usdImaging/dashDotLinesAdapter.h b/pxr/usdImaging/usdImaging/dashDotLinesAdapter.h new file mode 100644 index 0000000000..63edea5fdb --- /dev/null +++ b/pxr/usdImaging/usdImaging/dashDotLinesAdapter.h @@ -0,0 +1,147 @@ +// +// 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. +// +#ifndef PXR_USD_IMAGING_USD_IMAGING_DASH_DOT_LINES_ADAPTER_H +#define PXR_USD_IMAGING_USD_IMAGING_DASH_DOT_LINES_ADAPTER_H + +/// \file usdImaging/dashDotLinesAdapter.h + +#include "pxr/pxr.h" +#include "pxr/usdImaging/usdImaging/api.h" +#include "pxr/usdImaging/usdImaging/primAdapter.h" +#include "pxr/usdImaging/usdImaging/gprimAdapter.h" + +PXR_NAMESPACE_OPEN_SCOPE + + +/// \class UsdImagingDashDotLinesAdapter +/// +/// Delegate support for UsdGeomDashDotLines. +/// +class UsdImagingDashDotLinesAdapter : public UsdImagingGprimAdapter +{ +public: + using BaseAdapter = UsdImagingGprimAdapter; + + UsdImagingDashDotLinesAdapter() + : UsdImagingGprimAdapter() + {} + + USDIMAGING_API + ~UsdImagingDashDotLinesAdapter() override; + + // ---------------------------------------------------------------------- // + /// \name Scene Index Support + // ---------------------------------------------------------------------- // + + USDIMAGING_API + TfTokenVector GetImagingSubprims(UsdPrim const& prim) override; + + USDIMAGING_API + TfToken GetImagingSubprimType( + UsdPrim const& prim, + TfToken const& subprim) override; + + USDIMAGING_API + HdContainerDataSourceHandle GetImagingSubprimData( + UsdPrim const& prim, + TfToken const& subprim, + const UsdImagingDataSourceStageGlobals &stageGlobals) override; + + USDIMAGING_API + HdDataSourceLocatorSet InvalidateImagingSubprim( + UsdPrim const& prim, + TfToken const& subprim, + TfTokenVector const& properties, + UsdImagingPropertyInvalidationType invalidationType) override; + + // ---------------------------------------------------------------------- // + /// \name Initialization + // ---------------------------------------------------------------------- // + + USDIMAGING_API + SdfPath Populate( + UsdPrim const& prim, + UsdImagingIndexProxy* index, + UsdImagingInstancerContext const* instancerContext = nullptr) override; + + USDIMAGING_API + bool IsSupported(UsdImagingIndexProxy const* index) const override; + + // ---------------------------------------------------------------------- // + /// \name Parallel Setup and Resolve + // ---------------------------------------------------------------------- // + + /// Thread Safe. + USDIMAGING_API + void TrackVariability( + UsdPrim const& prim, + SdfPath const& cachePath, + HdDirtyBits* timeVaryingBits, + UsdImagingInstancerContext const* instancerContext = nullptr) + const override; + + /// Thread Safe. + USDIMAGING_API + void UpdateForTime( + UsdPrim const& prim, + SdfPath const& cachePath, + UsdTimeCode time, + HdDirtyBits requestedBits, + UsdImagingInstancerContext const* instancerContext = nullptr) + const override; + + // ---------------------------------------------------------------------- // + /// \name Change Processing + // ---------------------------------------------------------------------- // + + USDIMAGING_API + HdDirtyBits ProcessPropertyChange(UsdPrim const& prim, + SdfPath const& cachePath, + TfToken const& propertyName) override; + + // ---------------------------------------------------------------------- // + /// \name Data access + // ---------------------------------------------------------------------- // + + USDIMAGING_API + VtValue GetTopology(UsdPrim const& prim, + SdfPath const& cachePath, + UsdTimeCode time) const override; + + USDIMAGING_API + VtValue Get(UsdPrim const& prim, + SdfPath const& cachePath, + TfToken const& key, + UsdTimeCode time, + VtIntArray *outIndices) const override; + +protected: + USDIMAGING_API + bool _IsBuiltinPrimvar(TfToken const& primvarName) const override; +}; + + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // PXR_USD_IMAGING_USD_IMAGING_DASH_DOT_LINES_ADAPTER_H diff --git a/pxr/usdImaging/usdImaging/drawModeAdapter.cpp b/pxr/usdImaging/usdImaging/drawModeAdapter.cpp index 48dcaa5973..d5d57b360b 100644 --- a/pxr/usdImaging/usdImaging/drawModeAdapter.cpp +++ b/pxr/usdImaging/usdImaging/drawModeAdapter.cpp @@ -1025,7 +1025,7 @@ UsdImagingDrawModeAdapter::_GenerateOriginGeometry( for (int i = 0; i < 6; ++i) { curveIndices[i] = indices[i]; } HdBasisCurvesTopology topology( - HdTokens->linear, HdTokens->bezier, HdTokens->segmented, + HdTokens->linear, HdTokens->bezier, HdTokens->segmented, HdTokens->none, curveVertexCounts, curveIndices); *topo = VtValue(topology); } @@ -1061,7 +1061,7 @@ UsdImagingDrawModeAdapter::_GenerateBoundsGeometry( for (int i = 0; i < 24; ++i) { curveIndices[i] = indices[i]; } HdBasisCurvesTopology topology( - HdTokens->linear, HdTokens->bezier, HdTokens->segmented, + HdTokens->linear, HdTokens->bezier, HdTokens->segmented, HdTokens->none, curveVertexCounts, curveIndices); *topo = VtValue(topology); } diff --git a/pxr/usdImaging/usdImaging/hermiteCurvesAdapter.cpp b/pxr/usdImaging/usdImaging/hermiteCurvesAdapter.cpp index 72ea2aeea5..121013a93f 100644 --- a/pxr/usdImaging/usdImaging/hermiteCurvesAdapter.cpp +++ b/pxr/usdImaging/usdImaging/hermiteCurvesAdapter.cpp @@ -115,7 +115,7 @@ UsdImagingHermiteCurvesAdapter::GetTopology(UsdPrim const& prim, HF_MALLOC_TAG_FUNCTION(); HdBasisCurvesTopology topology( - HdTokens->linear, HdTokens->bezier, HdTokens->nonperiodic, + HdTokens->linear, HdTokens->bezier, HdTokens->nonperiodic, HdTokens->none, _Get(prim, UsdGeomTokens->curveVertexCounts, time), VtIntArray()); return VtValue(topology); diff --git a/pxr/usdImaging/usdImaging/nurbsCurvesAdapter.cpp b/pxr/usdImaging/usdImaging/nurbsCurvesAdapter.cpp index 459b1ca6ff..83232b3c8c 100644 --- a/pxr/usdImaging/usdImaging/nurbsCurvesAdapter.cpp +++ b/pxr/usdImaging/usdImaging/nurbsCurvesAdapter.cpp @@ -258,9 +258,10 @@ UsdImagingNurbsCurvesAdapter::GetTopology(UsdPrim const& prim, const TfToken& topoCurveBasis = HdTokens->linear; const TfToken& topoCurveType = HdTokens->linear; const TfToken& topoCurveWrap = HdTokens->nonperiodic; + const TfToken& topoCurveStyle = HdTokens->none; HdBasisCurvesTopology topology( - topoCurveType, topoCurveBasis, topoCurveWrap, + topoCurveType, topoCurveBasis, topoCurveWrap, topoCurveStyle, _Get(prim, UsdGeomTokens->curveVertexCounts, time), VtIntArray()); return VtValue(topology); diff --git a/pxr/usdImaging/usdImaging/plugInfo.json b/pxr/usdImaging/usdImaging/plugInfo.json index 19096d48b6..0b9ebd4a58 100644 --- a/pxr/usdImaging/usdImaging/plugInfo.json +++ b/pxr/usdImaging/usdImaging/plugInfo.json @@ -90,6 +90,13 @@ "includeSchemaFamily": true, "primTypeName": "Cylinder" }, + "UsdImagingDashDotLinesAdapter": { + "bases": [ + "UsdImagingGprimAdapter" + ], + "isInternal": true, + "primTypeName": "DashDotLines" + }, "UsdImagingDrawModeAdapter" : { "bases": ["UsdImagingInstanceablePrimAdapter"], "isInternal": true, diff --git a/pxr/usdImaging/usdImagingGL/CMakeLists.txt b/pxr/usdImaging/usdImagingGL/CMakeLists.txt index f710b3e157..9e4ed7c0ee 100644 --- a/pxr/usdImaging/usdImagingGL/CMakeLists.txt +++ b/pxr/usdImaging/usdImagingGL/CMakeLists.txt @@ -161,24 +161,73 @@ if (${PXR_HEADLESS_TEST_MODE}) return() endif() +# usdImagingGL tests require plugin mechanism to find different renderer +# plugins, which we do not support for static build configurations due to +# potential conflict in client applications linking against static build USD +if (NOT BUILD_SHARED_LIBS) + message(STATUS "Skipping ${PXR_PACKAGE} tests on static build configuration") + return() +endif() + if (APPLE) message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on macOS") return() endif() +pxr_install_test_dir( + SRC testenv/testUsdImagingGLDashDotLines + DEST testUsdImagingGLDashDotLines +) + +pxr_register_test(testUsdImagingGLDashDotLines_ScreenSpace + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingGLBasicDrawing -complexities 3.0 -offscreen -stage curveWithStyle_ScreenSpace.usda -translate -100 0.0 -300.0 -write testUsdImagingGLDashDotLines_ScreenSpace.png" + IMAGE_DIFF_COMPARE + testUsdImagingGLDashDotLines_ScreenSpace_3.png + FAIL .01 + FAIL_PERCENT .03 + PERCEPTUAL + EXPECTED_RETURN_CODE 0 + TESTENV testUsdImagingGLDashDotLines +) + +pxr_register_test(testUsdImagingGLDashDotLines_ScreenSpace_Segment + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingGLBasicDrawing -complexities 3.0 -offscreen -frameAll -stage curveWithStyle_ScreenSpace_Segment.usda -write testUsdImagingGLDashDotLines_ScreenSpace_Segment.png" + IMAGE_DIFF_COMPARE + testUsdImagingGLDashDotLines_ScreenSpace_Segment_3.png + FAIL .01 + FAIL_PERCENT .03 + PERCEPTUAL + EXPECTED_RETURN_CODE 0 + TESTENV testUsdImagingGLDashDotLines +) + +pxr_register_test(testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingGLBasicDrawing -complexities 3.0 -offscreen -frameAll -stage curveWithStyle_ScreenSpace_Segment_VertexColor.usda -write testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor.png" + IMAGE_DIFF_COMPARE + testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor_3.png + FAIL .01 + FAIL_PERCENT .03 + PERCEPTUAL + EXPECTED_RETURN_CODE 0 + TESTENV testUsdImagingGLDashDotLines +) + +pxr_register_test(testUsdImagingGLDashDotLines_NoScreenSpace_Segment + COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdImagingGLBasicDrawing -complexities 3.0 -offscreen -frameAll -stage curveWithStyle_NoScreenSpace_Segment.usda -write testUsdImagingGLDashDotLines_NoScreenSpace_Segment.png" + IMAGE_DIFF_COMPARE + testUsdImagingGLDashDotLines_NoScreenSpace_Segment_3.png + FAIL .01 + FAIL_PERCENT .03 + PERCEPTUAL + EXPECTED_RETURN_CODE 0 + TESTENV testUsdImagingGLDashDotLines +) + if (WIN32) message(STATUS "Skipping ${PXR_PACKAGE} tests because they are currently unsupported on Windows") return() endif() -# usdImagingGL tests require plugin mechanism to find different renderer -# plugins, which we do not support for static build configurations due to -# potential conflict in client applications linking against static build USD -if (NOT BUILD_SHARED_LIBS) - message(STATUS "Skipping ${PXR_PACKAGE} tests on static build configuration") - return() -endif() - # # Install tests that don't depend on build configuration or external libraries # (such as MaterialX, OpenVDB, PTEX). diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_NoScreenSpace_Segment_3.png b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_NoScreenSpace_Segment_3.png new file mode 100644 index 0000000000..53b04cf7f4 Binary files /dev/null and b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_NoScreenSpace_Segment_3.png differ diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_3.png b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_3.png new file mode 100644 index 0000000000..8e5e448711 Binary files /dev/null and b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_3.png differ diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_3.png b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_3.png new file mode 100644 index 0000000000..259b8042df Binary files /dev/null and b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_3.png differ diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor_3.png b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor_3.png new file mode 100644 index 0000000000..444e1653d9 Binary files /dev/null and b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/baseline/testUsdImagingGLDashDotLines_ScreenSpace_Segment_VertexColor_3.png differ diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_NoScreenSpace_Segment.usda b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_NoScreenSpace_Segment.usda new file mode 100644 index 0000000000..6070fd6ab7 --- /dev/null +++ b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_NoScreenSpace_Segment.usda @@ -0,0 +1,28 @@ +#usda 1.0 + +( + upAxis = "Y" +) + + +def DashDotLines "curve" ( + inherits = [] +){ + float3[] extent = [(-10, 0, 0),(10, 100, 0)] + uniform bool screenSpacePattern = false + uniform token startCapType = "round" + uniform token endCapType = "round" + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} \ No newline at end of file diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace.usda b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace.usda new file mode 100644 index 0000000000..d1c7515cc7 --- /dev/null +++ b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace.usda @@ -0,0 +1,193 @@ +#usda 1.0 +( + upAxis = "Y" + doc = """This layer represents the various geometric forms that curves + may be used to represent.""" +) + + +def DashDotLines "StyledPolyline1" ( + inherits = [] +){ + float3[] extent = [(-20, 0, 0),(20, 120, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "round" + uniform token endCapType = "triangle" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} +def DashDotLines "StyledPolyline2" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (30, 0, 0) + float3[] extent = [(10, 0, 0),(50, 120, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "square" + uniform token endCapType = "round" + uniform float patternScale = 7 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [8] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} +def DashDotLines "StyledPolyline3" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (60, 0, 0) + float3[] extent = [(40, 0, 0),(80, 120, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 10 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [3] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} +def DashDotLines "StyledPolyline4" ( +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (90, 0, 0) + float3[] extent = [(70, 0, 0),(110, 120, 0)] + uniform token startCapType = "square" + uniform token endCapType = "triangle" + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [8] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} + +def DashDotLines "StyledPolyline5" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (0, -140, 0) + float3[] extent = [(-20, -140, 0),(20, -20, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "triangle" + uniform token endCapType = "triangle" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] +} +def DashDotLines "StyledPolyline6" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (30, -140, 0) + float3[] extent = [(10, -140, 0),(50, -20, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] +} +def DashDotLines "StyledPolyline7" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (60, -140, 0) + float3[] extent = [(40, -140, 0),(80, -20, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "round" + uniform token endCapType = "square" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] +} +def DashDotLines "StyledPolyline8" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (90, -140, 0) + float3[] extent = [(70, -140, 0),(110, -20, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "square" + uniform token endCapType = "square" + uniform float patternScale = 5 + int[] curveVertexCounts = [7] + point3f[] points = [(0, 0, 0), (20, 20, 0), (20, 40, 0), (0, 60, 0), (-20, 80, 0), (-20, 100, 0), (0, 120, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] +} + +def DashDotLines "StyledPolyline9" ( +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (120, 100, 0) + float3[] extent = [(120, 50, 0),(124, 100, 0)] + uniform token startCapType = "round" + uniform token endCapType = "round" + int[] curveVertexCounts = [3] + point3f[] points = [(0, 0, 0), (2, -50, 0), (4, 0, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0)] +} + +def DashDotLines "StyledPolyline10" ( + inherits = [] +){ + uniform token[] xformOpOrder = ["xformOp:translate"] + float3 xformOp:translate = (120, -40, 0) + float3[] extent = [(120, -90, 0),(124, -40, 0)] + uniform bool screenSpacePattern = true + rel dashDotPattern:binding = + uniform token startCapType = "triangle" + uniform token endCapType = "square" + uniform float patternScale = 7 + int[] curveVertexCounts = [3] + point3f[] points = [(0, 0, 0), (2, -50, 0), (4, 0, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 1, 0)] +} + +def "Pattern1" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 20 + uniform float2[] pattern = [(0, 12.5), (2.5, 2.5)] +} + +def "Pattern2" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 10 + uniform float2[] pattern = [(0, 5), (2.5, 0)] +} + +def "Pattern3" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 15 + uniform float2[] pattern = [(0, 10)] +} + +def "Pattern4" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + uniform float patternPeriod = 5 + uniform float2[] pattern = [(0, 0)] +} \ No newline at end of file diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment.usda b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment.usda new file mode 100644 index 0000000000..e71ae80f9c --- /dev/null +++ b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment.usda @@ -0,0 +1,27 @@ +#usda 1.0 +( + upAxis = "Y" +) + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + float patternPeriod = 15 + float2[] pattern = [(0, 10)] +} + +def DashDotLines "curve" ( + inherits = [] +){ + float3[] extent = [(-10, 0, 0),(10, 100, 0)] + uniform bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(0, 0, 1)] +} \ No newline at end of file diff --git a/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment_VertexColor.usda b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment_VertexColor.usda new file mode 100644 index 0000000000..505733cb78 --- /dev/null +++ b/pxr/usdImaging/usdImagingGL/testenv/testUsdImagingGLDashDotLines/curveWithStyle_ScreenSpace_Segment_VertexColor.usda @@ -0,0 +1,28 @@ +#usda 1.0 +( + upAxis = "Y" +) + +def "MyPattern" ( + prepend apiSchemas = ["DashDotPatternAPI"] +) +{ + float patternPeriod = 15 + float2[] pattern = [(0, 10)] +} + +def DashDotLines "curve" ( + inherits = [] +){ + float3[] extent = [(-10, 0, 0),(10, 100, 0)] + + bool screenSpacePattern = true + uniform token startCapType = "round" + uniform token endCapType = "round" + uniform float patternScale = 5 + + int[] curveVertexCounts = [3, 4, 4] + point3f[] points = [(0, 0, 0), (10, 10, 0), (10, 20, 0), (0, 30, 0), (-10, 40, 0), (-10, 50, 0), (0, 60, 0), (10, 70, 0), (10, 80, 0), (0, 90, 0), (-10, 100, 0)] + float[] widths = [5] (interpolation = "constant") + color3f[] primvars:displayColor = [(1, 0, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0), (1, 0 ,1), (0, 1, 1), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0 ,1), (0, 1, 1)](interpolation = "vertex") +} \ No newline at end of file