From 79cb7410c0ebc263d49ed64eed4ab6771dca0fcc Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Thu, 30 Jan 2020 18:25:04 -0500 Subject: [PATCH 1/9] VP2RenderDelegate now supports USD curves --- lib/CMakeLists.txt | 13 +- lib/render/vp2RenderDelegate/basisCurves.cpp | 1674 +++++++++++++++++ lib/render/vp2RenderDelegate/basisCurves.h | 143 ++ lib/render/vp2RenderDelegate/draw_item.cpp | 19 +- lib/render/vp2RenderDelegate/draw_item.h | 18 +- lib/render/vp2RenderDelegate/mesh.cpp | 146 +- lib/render/vp2RenderDelegate/mesh.h | 5 +- .../vp2RenderDelegate/proxyRenderDelegate.cpp | 21 +- .../vp2RenderDelegate/render_delegate.cpp | 107 +- .../vp2RenderDelegate/render_delegate.h | 6 +- .../BasisCurvesCubicDomain_Cg.xml | 59 + .../BasisCurvesCubicDomain_GLSL.xml | 186 ++ .../BasisCurvesCubicDomain_HLSL.xml | 193 ++ .../BasisCurvesCubicFallbackShader.xml | 106 ++ .../BasisCurvesCubicHull.xml | 201 ++ .../BasisCurvesLinearDomain_Cg.xml | 59 + .../BasisCurvesLinearDomain_GLSL.xml | 162 ++ .../BasisCurvesLinearDomain_HLSL.xml | 173 ++ .../BasisCurvesLinearFallbackShader.xml | 106 ++ .../BasisCurvesLinearHull.xml | 140 ++ .../vp2ShaderFragments/shaderFragments.cpp | 51 + 21 files changed, 3464 insertions(+), 124 deletions(-) create mode 100644 lib/render/vp2RenderDelegate/basisCurves.cpp create mode 100644 lib/render/vp2RenderDelegate/basisCurves.h create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesCubicFallbackShader.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_Cg.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesLinearFallbackShader.xml create mode 100644 lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 8dbc7f9d7a..81ce2e7be2 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,6 +1,6 @@ # # ======================================================================= -# Copyright 2019 Autodesk +# Copyright 2020 Autodesk # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -144,6 +144,7 @@ list(APPEND mayaUsd_src render/pxrUsdMayaGL/usdProxyShapeAdapter.cpp render/pxrUsdMayaGL/userData.cpp # + render/vp2RenderDelegate/basisCurves.cpp render/vp2RenderDelegate/bboxGeom.cpp render/vp2RenderDelegate/debugCodes.cpp render/vp2RenderDelegate/draw_item.cpp @@ -182,6 +183,16 @@ list(APPEND mayaUsdShaderFragments_xmls render/vp2ShaderFragments/usdPreviewSurfaceCombiner.xml render/vp2ShaderFragments/usdPreviewSurfaceLighting.xml # New fragments + render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml + render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml + render/vp2ShaderFragments/BasisCurvesLinearDomain_Cg.xml + render/vp2ShaderFragments/BasisCurvesLinearFallbackShader.xml + render/vp2ShaderFragments/BasisCurvesLinearHull.xml + render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml + render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml + render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml + render/vp2ShaderFragments/BasisCurvesCubicFallbackShader.xml + render/vp2ShaderFragments/BasisCurvesCubicHull.xml render/vp2ShaderFragments/FallbackCPVShader.xml render/vp2ShaderFragments/FallbackShader.xml render/vp2ShaderFragments/Float4ToFloat3.xml diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp new file mode 100644 index 0000000000..a1eed09fa4 --- /dev/null +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -0,0 +1,1674 @@ +// +// Copyright 2020 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include "basisCurves.h" +#include "bboxGeom.h" +#include "debugCodes.h" +#include "draw_item.h" +#include "material.h" +#include "instancer.h" +#include "render_delegate.h" +#include "tokens.h" + +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" +#include "pxr/base/vt/value.h" + +#include "pxr/imaging/hd/repr.h" +#include "pxr/imaging/hd/sceneDelegate.h" +#include "pxr/imaging/hd/tokens.h" + +#include +#include +#include + +// Conditional compilation due to Maya API gap. +#if MAYA_API_VERSION >= 20210000 +#define MAYA_ALLOW_PRIMITIVE_TYPE_SWITCH +#endif + +PXR_NAMESPACE_OPEN_SCOPE + +namespace { + + //! Required primvars when there is no material binding. + const TfTokenVector sFallbackShaderPrimvars = { + HdTokens->displayColor, + HdTokens->displayOpacity, + HdTokens->normals, + HdTokens->widths + }; + + const MColor kSelectionHighlightColor(0.056f, 1.0f, 0.366f, 1.0f); //!< Selection highlight color + const MColor kOpaqueGray(.18f, .18f, .18f, 1.0f); //!< The default 18% gray color + const unsigned int kNumColorChannels = 4; //!< The number of color channels + + //! Cached strings for efficiency + const MString kPositionsStr("positions"); + const MString kNormalsStr("normals"); + const MString kWidthStr("U0_1"); + const MString kDiffuseColorStr("diffuseColor"); + const MString kSolidColorStr("solidColor"); + + //! A primvar vertex buffer data map indexed by primvar name. + using PrimvarBufferDataMap = std::unordered_map< + TfToken, + void*, + TfToken::HashFunctor + >; + + //! \brief Helper struct used to package all the changes into single commit task + //! (such commit task will be executed on main-thread) + struct CommitState { + HdVP2DrawItem::RenderItemData& _drawItemData; + + //! If valid, new index buffer data to commit + int* _indexBufferData{ nullptr }; + //! If valid, new color buffer data to commit + void* _colorBufferData{ nullptr }; + //! If valid, new normals buffer data to commit + void* _normalsBufferData{ nullptr }; + //! If valid, new primvar buffer data to commit + PrimvarBufferDataMap _primvarBufferDataMap; + + //! If valid, world matrix to set on the render item + MMatrix* _worldMatrix{ nullptr }; + + //! If valid, bounding box to set on the render item + MBoundingBox* _boundingBox{ nullptr }; + + //! if valid, enable or disable the render item + bool* _enabled{ nullptr }; + + //! if valid, set the primitive type on the render item + MHWRender::MGeometry::Primitive* _primitiveType{ nullptr }; + //! if valid, set the primitive stride on the render item + int* _primitiveStride{ nullptr }; + + //! If valid, new shader instance to set + MHWRender::MShaderInstance* _shader{ nullptr }; + + //! Is this object transparent + bool _isTransparent{ false }; + + //! Instancing doesn't have dirty bits, every time we do update, we must update instance transforms + MMatrixArray _instanceTransforms; + + //! Color array to support per-instance color and selection highlight. + MFloatArray _instanceColors; + + //! If true, associate geometric buffers to the render item and trigger consolidation/instancing update + bool _geometryDirty{ false }; + + //! Construct valid commit state + CommitState(HdVP2DrawItem& item) : _drawItemData(item.GetRenderItemData()) + {} + + //! No default constructor, we need draw item and dirty bits. + CommitState() = delete; + }; + + template VtArray + InterpolateVarying( + size_t numVerts, + VtIntArray const & vertexCounts, + TfToken wrap, + TfToken basis, + VtArray const & authoredValues) + { + VtArray outputValues(numVerts); + + size_t srcIndex = 0; + size_t dstIndex = 0; + + if (wrap == HdTokens->periodic) { + // XXX : Add support for periodic curves + TF_WARN("Varying data is only supported for non-periodic curves."); + } + + TF_FOR_ALL(itVertexCount, vertexCounts) { + int nVerts = *itVertexCount; + + // Handling for the case of potentially incorrect vertex counts + if(nVerts < 1) { + continue; + } + + if(basis == HdTokens->catmullRom || basis == HdTokens->bSpline) { + // For splines with a vstep of 1, we are doing linear interpolation + // between segments, so all we do here is duplicate the first and + // last outputValues. Since these are never acutally used during + // drawing, it would also work just to set the to 0. + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; + for (int i = 1; i < nVerts - 2; ++i){ + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; ++srcIndex; + } + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; ++srcIndex; + } + else if (basis == HdTokens->bezier){ + // For bezier splines, we map the linear values to cubic values + // the begin value gets mapped to the first two vertices and + // the end value gets mapped to the last two vertices in a segment. + // shaders can choose to access value[1] and value[2] when linearly + // interpolating a value, which happens to match up with the + // indexing to use for catmullRom and bSpline basis. + int vStep = 3; + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; // don't increment the srcIndex + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; ++ srcIndex; + + // vstep - 1 control points will have an interpolated value + for(int i = 2; i < nVerts - 2; i += vStep) { + outputValues[dstIndex] = authoredValues[srcIndex]; + ++ dstIndex; // don't increment the srcIndex + outputValues[dstIndex] = authoredValues[srcIndex]; + ++ dstIndex; // don't increment the srcIndex + outputValues[dstIndex] = authoredValues[srcIndex]; + ++ dstIndex; ++ srcIndex; + } + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; // don't increment the srcIndex + outputValues[dstIndex] = authoredValues[srcIndex]; + ++dstIndex; ++ srcIndex; + } + else { + TF_WARN("Unsupported basis: '%s'", basis.GetText()); + } + } + TF_VERIFY(srcIndex == authoredValues.size()); + TF_VERIFY(dstIndex == numVerts); + + return outputValues; + } + + VtValue _BuildCubicIndexArray(const HdBasisCurvesTopology& topology) + { + /* + Here's a diagram of what's happening in this code: + + For open (non periodic, wrap = false) curves: + + bezier (vStep = 3) + 0------1------2------3------4------5------6 (vertex index) + [======= seg0 =======] + [======= seg1 =======] + + + bspline / catmullRom (vStep = 1) + 0------1------2------3------4------5------6 (vertex index) + [======= seg0 =======] + [======= seg1 =======] + [======= seg2 =======] + [======= seg3 =======] + + + For closed (periodic, wrap = true) curves: + + periodic bezier (vStep = 3) + 0------1------2------3------4------5------0 (vertex index) + [======= seg0 =======] + [======= seg1 =======] + + + periodic bspline / catmullRom (vStep = 1) + 0------1------2------3------4------5------0------1------2 (vertex index) + [======= seg0 =======] + [======= seg1 =======] + [======= seg2 =======] + [======= seg3 =======] + [======= seg4 =======] + [======= seg5 =======] + */ + std::vector indices; + + const VtArray vertexCounts = topology.GetCurveVertexCounts(); + bool wrap = topology.GetCurveWrap() == HdTokens->periodic; + int vStep; + TfToken basis = topology.GetCurveBasis(); + if(basis == HdTokens->bezier) { + vStep = 3; + } + else { + vStep = 1; + } + + int vertexIndex = 0; + int curveIndex = 0; + TF_FOR_ALL(itCounts, vertexCounts) { + int count = *itCounts; + // The first segment always eats up 4 verts, not just vstep, so to + // compensate, we break at count - 3. + int numSegs; + + // If we're closing the curve, make sure that we have enough + // segments to wrap all the way back to the beginning. + if (wrap) { + numSegs = count / vStep; + } else { + numSegs = ((count - 4) / vStep) + 1; + } + + for(int i = 0;i < numSegs; ++i) { + + // Set up curve segments based on curve basis + GfVec4i seg; + int offset = i*vStep; + for(int v = 0;v < 4; ++v) { + // If there are not enough verts to round out the segment + // just repeat the last vert. + seg[v] = wrap + ? vertexIndex + ((offset + v) % count) + : vertexIndex + std::min(offset + v, (count -1)); + } + indices.push_back(seg); + } + vertexIndex += count; + curveIndex++; + } + + VtVec4iArray finalIndices(indices.size()); + VtIntArray const &curveIndices = topology.GetCurveIndices(); + + // If have topology has indices set, map the generated indices + // with the given indices. + if (curveIndices.empty()) + { + std::copy(indices.begin(), indices.end(), finalIndices.begin()); + } + else + { + size_t lineCount = indices.size(); + int maxIndex = curveIndices.size() - 1; + + for (size_t lineNum = 0; lineNum < lineCount; ++lineNum) + { + const GfVec4i &line = indices[lineNum]; + + int i0 = std::min(line[0], maxIndex); + int i1 = std::min(line[1], maxIndex); + int i2 = std::min(line[2], maxIndex); + int i3 = std::min(line[3], maxIndex); + + int v0 = curveIndices[i0]; + int v1 = curveIndices[i1]; + int v2 = curveIndices[i2]; + int v3 = curveIndices[i3]; + + finalIndices[lineNum].Set(v0, v1, v2, v3); + } + } + + return VtValue(finalIndices); + } + + VtValue _BuildLinesIndexArray(const HdBasisCurvesTopology& topology) + { + std::vector indices; + VtArray vertexCounts = topology.GetCurveVertexCounts(); + + int vertexIndex = 0; + int curveIndex = 0; + TF_FOR_ALL(itCounts, vertexCounts) { + for(int i = 0; i < *itCounts; i+= 2) { + indices.push_back(GfVec2i(vertexIndex, vertexIndex + 1)); + vertexIndex += 2; + } + curveIndex++; + } + + VtVec2iArray finalIndices(indices.size()); + VtIntArray const &curveIndices = topology.GetCurveIndices(); + + // If have topology has indices set, map the generated indices + // with the given indices. + if (curveIndices.empty()) + { + std::copy(indices.begin(), indices.end(), finalIndices.begin()); + } + else + { + size_t lineCount = indices.size(); + int maxIndex = curveIndices.size() - 1; + + for (size_t lineNum = 0; lineNum < lineCount; ++lineNum) + { + const GfVec2i &line = indices[lineNum]; + + int i0 = std::min(line[0], maxIndex); + int i1 = std::min(line[1], maxIndex); + + int v0 = curveIndices[i0]; + int v1 = curveIndices[i1]; + + finalIndices[lineNum].Set(v0, v1); + } + } + + return VtValue(finalIndices); + } + + VtValue _BuildLineSegmentIndexArray(const HdBasisCurvesTopology& topology) + { + const TfToken basis = topology.GetCurveBasis(); + const bool skipFirstAndLastSegs = (basis == HdTokens->catmullRom); + + std::vector indices; + const VtArray vertexCounts = topology.GetCurveVertexCounts(); + bool wrap = topology.GetCurveWrap() == HdTokens->periodic; + int vertexIndex = 0; // Index of next vertex to emit + 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)); + } + v0 = v1; + } + if(wrap) { + indices.push_back(GfVec2i(v0, firstVert)); + } + ++curveIndex; + } + + VtVec2iArray finalIndices(indices.size()); + VtIntArray const &curveIndices = topology.GetCurveIndices(); + + // If have topology has indices set, map the generated indices + // with the given indices. + if (curveIndices.empty()) + { + std::copy(indices.begin(), indices.end(), finalIndices.begin()); + } + else + { + size_t lineCount = indices.size(); + int maxIndex = curveIndices.size() - 1; + + for (size_t lineNum = 0; lineNum < lineCount; ++lineNum) + { + const GfVec2i &line = indices[lineNum]; + + int i0 = std::min(line[0], maxIndex); + int i1 = std::min(line[1], maxIndex); + + int v0 = curveIndices[i0]; + int v1 = curveIndices[i1]; + + finalIndices[lineNum].Set(v0, v1); + } + } + + return VtValue(finalIndices); + } + + VtVec3fArray _BuildInterpolatedArray( + const HdBasisCurvesTopology& topology, + const VtVec3fArray& authoredData) + { + // We need to interpolate primvar depending on its type + size_t numVerts = topology.CalculateNeededNumberOfControlPoints(); + + VtVec3fArray result(numVerts); + size_t size = authoredData.size(); + + if(size == 1) { + // Uniform data + const GfVec3f& elem = authoredData[0]; + for(size_t i = 0; i < numVerts; ++ i) { + result[i] = elem; + } + } + else if(size == numVerts) { + // Vertex data + result = authoredData; + } + else if(size == topology.CalculateNeededNumberOfVaryingControlPoints()) { + // Varying data + result = InterpolateVarying(numVerts, + topology.GetCurveVertexCounts(), + topology.GetCurveWrap(), + topology.GetCurveBasis(), + authoredData); + } + else { + // Fallback + const GfVec3f elem(1.0f, 0.0f, 0.0f); + for(size_t i = 0; i < numVerts; ++ i) { + result[i] = elem; + } + TF_WARN("Incorrect number of primvar data, using default GfVec3f(0,0,0) for rendering."); + } + + return result; + } + + VtFloatArray _BuildInterpolatedArray( + const HdBasisCurvesTopology& topology, + const VtFloatArray& authoredData) + { + // We need to interpolate primvar depending on its type + size_t numVerts = topology.CalculateNeededNumberOfControlPoints(); + + VtFloatArray result(numVerts); + size_t size = authoredData.size(); + + if(size == 1) { + // Uniform or missing data + float elem = authoredData[0]; + for(size_t i = 0; i < numVerts; ++ i) { + result[i] = elem; + } + } + else if(size == numVerts) { + // Vertex data + result = authoredData; + } + else if(size == topology.CalculateNeededNumberOfVaryingControlPoints()) { + // Varying data + result = InterpolateVarying(numVerts, + topology.GetCurveVertexCounts(), + topology.GetCurveWrap(), + topology.GetCurveBasis(), + authoredData); + } + else { + // Fallback + for(size_t i = 0; i < numVerts; ++ i) { + result[i] = 1.0; + } + TF_WARN("Incorrect number of primvar data, using default 1.0 for rendering."); + } + + return result; + } + + //! Helper utility function to adapt Maya API changes. + void setWantConsolidation(MHWRender::MRenderItem& renderItem, bool state) + { +#if MAYA_API_VERSION >= 20190000 + renderItem.setWantConsolidation(state); +#else + renderItem.setWantSubSceneConsolidation(state); +#endif + } +} // anonymous namespace + +//! \brief Constructor +HdVP2BasisCurves::HdVP2BasisCurves( + HdVP2RenderDelegate *delegate, + SdfPath const &id, + SdfPath const &instancerId) +: HdBasisCurves(id, instancerId) +, _delegate(delegate) +, _rprimId(id.GetText()) +{ + const MHWRender::MVertexBufferDescriptor desc( + "", + MHWRender::MGeometry::kPosition, + MHWRender::MGeometry::kFloat, + 3); + + _curvesSharedData._positionsBuffer.reset(new MHWRender::MVertexBuffer(desc)); +} + +//! \brief Synchronize VP2 state with scene delegate state based on dirty bits and repr +void HdVP2BasisCurves::Sync( + HdSceneDelegate *delegate, + HdRenderParam *renderParam, + HdDirtyBits *dirtyBits, + TfToken const &reprToken) +{ + // We don't create a repr for the selection token because this token serves + // for selection state update only. Return early to reserve dirty bits so + // they can be used to sync regular reprs later. + if (reprToken == HdVP2ReprTokens->selection) { + return; + } + + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L2, _rprimId.asChar(), "HdVP2BasisCurves::Sync"); + + const SdfPath& id = GetId(); + + if (*dirtyBits & HdChangeTracker::DirtyMaterialId) { + _SetMaterialId(delegate->GetRenderIndex().GetChangeTracker(), + delegate->GetMaterialId(id)); + } + + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->normals) || + HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->primvar)) { + const HdVP2Material* material = static_cast( + delegate->GetRenderIndex().GetSprim( + HdPrimTypeTokens->material, GetMaterialId()) + ); + + const TfTokenVector& requiredPrimvars = + (material && material->GetSurfaceShader()) ? + material->GetRequiredPrimvars() : sFallbackShaderPrimvars; + + _UpdatePrimvarSources(delegate, *dirtyBits, requiredPrimvars); + } + + if (*dirtyBits & HdChangeTracker::DirtyDisplayStyle) { + _curvesSharedData._displayStyle = GetDisplayStyle(delegate); + } + + if (HdChangeTracker::IsTopologyDirty(*dirtyBits, id)) { + _curvesSharedData._topology = GetBasisCurvesTopology(delegate); + } + + // Prepare position buffer. It is shared among all draw items so it should + // be updated only once when it gets dirty. + if (HdChangeTracker::IsPrimvarDirty(*dirtyBits, id, HdTokens->points)) { + const VtValue value = delegate->Get(id, HdTokens->points); + _curvesSharedData._points = value.Get(); + + const size_t numVertices = _curvesSharedData._points.size(); + + const HdBasisCurvesTopology& topology = _curvesSharedData._topology; + const size_t numControlPoints = topology.CalculateNeededNumberOfControlPoints(); + + if (!topology.HasIndices() && numVertices != numControlPoints) { + TF_WARN("Topology and vertices do not match for BasisCurve %s", + id.GetName().c_str()); + } + + void* bufferData = _curvesSharedData._positionsBuffer->acquire(numVertices, true); + if (bufferData) { + const size_t numBytes = sizeof(GfVec3f) * numVertices; + memcpy(bufferData, _curvesSharedData._points.cdata(), numBytes); + + // Capture class member for lambda + MHWRender::MVertexBuffer* const positionsBuffer = + _curvesSharedData._positionsBuffer.get(); + const MString& rprimId = _rprimId; + + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [positionsBuffer, bufferData, rprimId]() { + MProfilingScope profilingScope( + HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L2, + rprimId.asChar(), + "CommitPositions"); + + positionsBuffer->commit(bufferData); + } + ); + } + } + + if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) { + _sharedData.bounds.SetRange(delegate->GetExtent(id)); + } + + if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { + _sharedData.bounds.SetMatrix(delegate->GetTransform(id)); + } + + if (HdChangeTracker::IsVisibilityDirty(*dirtyBits, id)) { + _sharedData.visible = delegate->GetVisible(id); + } + + *dirtyBits = HdChangeTracker::Clean; + + // Draw item update is controlled by its own dirty bits. + _UpdateRepr(delegate, reprToken); +} + +/*! \brief Update the draw item + + This call happens on worker threads and results of the change are collected + in CommitState and enqueued for Commit on main-thread using CommitTasks +*/ +void +HdVP2BasisCurves::_UpdateDrawItem( + HdSceneDelegate *sceneDelegate, + HdVP2DrawItem *drawItem, + HdBasisCurvesReprDesc const &desc) +{ + const MHWRender::MRenderItem* renderItem = drawItem->GetRenderItem(); + if (ARCH_UNLIKELY(!renderItem)) { + return; + } + + const HdDirtyBits itemDirtyBits = drawItem->GetDirtyBits(); + + // We don't need to update the dedicated selection highlight item when there + // is no selection highlight change and the prim is not selected. Draw item + // has its own dirty bits, so update will be doner when it shows in viewport. + const bool isDedicatedSelectionHighlightItem = + drawItem->MatchesUsage(HdVP2DrawItem::kSelectionHighlight); + if (isDedicatedSelectionHighlightItem && + ((itemDirtyBits & DirtySelectionHighlight) == 0) && + (_selectionState == kUnselected)) { + return; + } + + CommitState stateToCommit(*drawItem); + HdVP2DrawItem::RenderItemData& drawItemData = stateToCommit._drawItemData; + + const SdfPath& id = GetId(); + + auto* const param = static_cast(_delegate->GetRenderParam()); + ProxyRenderDelegate& drawScene = param->GetDrawScene(); + + const HdRenderIndex& renderIndex = sceneDelegate->GetRenderIndex(); + + const auto& primvarSourceMap = _curvesSharedData._primvarSourceMap; + + const HdBasisCurvesTopology& topology = _curvesSharedData._topology; + const VtIntArray& curveVertexCounts = topology.GetCurveVertexCounts(); + const size_t numCurves = curveVertexCounts.size(); + const size_t numControlPoints = topology.CalculateNeededNumberOfControlPoints(); + + const TfToken type = topology.GetCurveType(); + const TfToken wrap = topology.GetCurveWrap(); + + const MHWRender::MGeometry::DrawMode drawMode = renderItem->drawMode(); + + // The bounding box item uses a globally-shared geometry data therefore it + // doesn't need to extract index data from the prim. + const bool requiresIndexUpdate = (drawMode != MHWRender::MGeometry::kBoundingBox); + + // Prepare index buffer. + if (requiresIndexUpdate && (itemDirtyBits & HdChangeTracker::DirtyTopology)) { + + const bool forceLines = + (_curvesSharedData._displayStyle.refineLevel <= 0) || + (drawMode == MHWRender::MGeometry::kWireframe); + + VtValue result; + + if (!forceLines && type == HdTokens->cubic) { + result = _BuildCubicIndexArray(topology); + } + else if (wrap == HdTokens->segmented) { + result = _BuildLinesIndexArray(topology); + } + else { + result = _BuildLineSegmentIndexArray(topology); + } + + const void* indexData = nullptr; + unsigned int numIndices = 0; + + if (result.IsHolding()) { + indexData = result.UncheckedGet().cdata(); + numIndices = result.GetArraySize() * 2; + } + else if (result.IsHolding()) { + indexData = result.UncheckedGet().cdata(); + numIndices = result.GetArraySize() * 4; + } + + if (drawItemData._indexBuffer && numIndices > 0) { + stateToCommit._indexBufferData = static_cast( + drawItemData._indexBuffer->acquire(numIndices, true)); + + if (indexData != nullptr && stateToCommit._indexBufferData != nullptr) { + memcpy(stateToCommit._indexBufferData, indexData, + numIndices * sizeof(int)); + } + } + } + + if (desc.geomStyle == HdBasisCurvesGeomStylePatch) { + // Prepare normals buffer. + if (itemDirtyBits & + (HdChangeTracker::DirtyNormals | HdChangeTracker::DirtyDisplayStyle)) { + // Using a zero vector to indicate requirement of camera-facing + // normals when there is no authored normals. + VtVec3fArray normals(1, GfVec3f(0.0f, 0.0f, 0.0f)); + + const auto it = primvarSourceMap.find(HdTokens->normals); + if (it != primvarSourceMap.end()) { + const VtValue& value = it->second.data; + if (ARCH_LIKELY(value.IsHolding())) { + normals = value.UncheckedGet(); + } + } + + normals = _BuildInterpolatedArray(topology, normals); + + if (!drawItemData._normalsBuffer) { + const MHWRender::MVertexBufferDescriptor vbDesc("", + MHWRender::MGeometry::kNormal, + MHWRender::MGeometry::kFloat, + 3); + + drawItemData._normalsBuffer.reset( + new MHWRender::MVertexBuffer(vbDesc)); + } + + unsigned int numNormals = normals.size(); + if (drawItemData._normalsBuffer && numNormals > 0) { + stateToCommit._normalsBufferData = + drawItemData._normalsBuffer->acquire(numNormals, true); + + if (stateToCommit._normalsBufferData != nullptr) { + memcpy(stateToCommit._normalsBufferData, normals.cdata(), + numNormals * sizeof(GfVec3f)); + } + } + } + + // Prepare widths buffer. + if ((_curvesSharedData._displayStyle.refineLevel > 0) && + (itemDirtyBits & (HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyDisplayStyle))) { + VtFloatArray widths(1, 1.0f); + + const auto it = primvarSourceMap.find(HdTokens->widths); + if (it != primvarSourceMap.end()) { + const VtValue& value = it->second.data; + if (value.IsHolding()) { + widths = value.UncheckedGet(); + } + } + + widths = _BuildInterpolatedArray(topology, widths); + + MHWRender::MVertexBuffer* widthsBuffer = + drawItemData._primvarBuffers[HdTokens->widths].get(); + + if (!widthsBuffer) { + const MHWRender::MVertexBufferDescriptor vbDesc("", + MHWRender::MGeometry::kTexture, + MHWRender::MGeometry::kFloat, + 1); + + widthsBuffer = new MHWRender::MVertexBuffer(vbDesc); + drawItemData._primvarBuffers[HdTokens->widths].reset(widthsBuffer); + } + + unsigned int numWidths = widths.size(); + if (widthsBuffer && numWidths > 0) { + void* bufferData = widthsBuffer->acquire(numWidths, true); + stateToCommit._primvarBufferDataMap[HdTokens->widths] = bufferData; + + if (bufferData != nullptr) { + memcpy(bufferData, widths.cdata(), numWidths * sizeof(float)); + } + } + } + + // Prepare color buffer. + if (itemDirtyBits & HdChangeTracker::DirtyMaterialId) { + const HdVP2Material* material = static_cast( + renderIndex.GetSprim(HdPrimTypeTokens->material, GetMaterialId()) + ); + + if (material) { + MHWRender::MShaderInstance* shader = material->GetSurfaceShader(); + if (shader != nullptr && shader != drawItemData._shader) { + drawItemData._shader = shader; + stateToCommit._shader = shader; + stateToCommit._isTransparent = shader->isTransparent(); + } + + auto primitiveType = MHWRender::MGeometry::kLines; + int primitiveStride = 0; + + if (primitiveType != drawItemData._primitiveType || + primitiveStride != drawItemData._primitiveStride) { + + drawItemData._primitiveType = primitiveType; + stateToCommit._primitiveType = &drawItemData._primitiveType; + + drawItemData._primitiveStride = primitiveStride; + stateToCommit._primitiveStride = &drawItemData._primitiveStride; + } + } + } + + if (itemDirtyBits & (HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyDisplayStyle | + DirtySelectionHighlight)) { + // If color/opacity is not found, the 18% gray color will be used + // to match the default color of Hydra Storm. + VtVec3fArray colorArray(1, GfVec3f(0.18f, 0.18f, 0.18f)); + VtFloatArray alphaArray(1, 1.0f); + + auto itColor = primvarSourceMap.find(HdTokens->displayColor); + if (itColor != primvarSourceMap.end()) { + const VtValue& value = itColor->second.data; + if (value.IsHolding() && value.GetArraySize() > 0) { + colorArray = value.UncheckedGet(); + } + } + + auto itOpacity = primvarSourceMap.find(HdTokens->displayOpacity); + if (itOpacity != primvarSourceMap.end()) { + const VtValue& value = itOpacity->second.data; + if (value.IsHolding() && value.GetArraySize() > 0) { + alphaArray = value.UncheckedGet(); + } + } + + if (colorArray.size() == 1 && alphaArray.size() == 1) { + // Use fallback shader if there is no material binding or we + // failed to create a shader instance from the material. + if (!stateToCommit._shader) { + const GfVec3f& color = colorArray[0]; + const MColor clr(color[0], color[1], color[2], alphaArray[0]); + + MHWRender::MShaderInstance* shader = nullptr; + auto primitiveType = MHWRender::MGeometry::kLines; + int primitiveStride = 0; + + if (_curvesSharedData._displayStyle.refineLevel <= 0) { + shader = _delegate->Get3dSolidShader(clr); + } + else if (type == HdTokens->linear) { + shader = _delegate->GetBasisCurvesLinearFallbackShader(clr); + primitiveType = MHWRender::MGeometry::kPatch; + primitiveStride = 2; + } + else { + shader = _delegate->GetBasisCurvesCubicFallbackShader(clr); + primitiveType = MHWRender::MGeometry::kPatch; + primitiveStride = 4; + } + + if (shader != nullptr && shader != drawItemData._shader) { + drawItemData._shader = shader; + stateToCommit._shader = shader; + } + + if (primitiveType != drawItemData._primitiveType || + primitiveStride != drawItemData._primitiveStride) { + drawItemData._primitiveType = primitiveType; + stateToCommit._primitiveType = &drawItemData._primitiveType; + + drawItemData._primitiveStride = primitiveStride; + stateToCommit._primitiveStride = &drawItemData._primitiveStride; + } + } + } + else { + colorArray = _BuildInterpolatedArray(topology, colorArray); + alphaArray = _BuildInterpolatedArray(topology, alphaArray); + + const unsigned int numColors = colorArray.size(); + const unsigned int numAlphas = alphaArray.size(); + const unsigned int numVertices = + numColors <= numAlphas ? numColors : numAlphas; + + if (numColors != numAlphas) { + TF_CODING_ERROR("color and opacity do not match for BasisCurve %s", + id.GetName().c_str()); + } + + // Fill color and opacity into the float4 color stream. + if (!drawItemData._colorBuffer) { + const MHWRender::MVertexBufferDescriptor vbDesc("", + MHWRender::MGeometry::kColor, + MHWRender::MGeometry::kFloat, + 4); + + drawItemData._colorBuffer.reset( + new MHWRender::MVertexBuffer(vbDesc)); + } + + float* bufferData = static_cast( + drawItemData._colorBuffer->acquire(numVertices, true)); + + if (bufferData) { + unsigned int offset = 0; + for (unsigned int v = 0; v < numVertices; v++) { + const GfVec3f& color = colorArray[v]; + bufferData[offset++] = color[0]; + bufferData[offset++] = color[1]; + bufferData[offset++] = color[2]; + + bufferData[offset++] = alphaArray[v]; + } + + stateToCommit._colorBufferData = bufferData; + } + + // Use 3d CPV solid-color shader if there is no material binding or + // we failed to create a shader instance from the material. + if (!stateToCommit._shader) { + MHWRender::MShaderInstance* shader = _delegate->Get3dCPVSolidShader(); + + if (shader != nullptr && shader != drawItemData._shader) { + drawItemData._shader = shader; + stateToCommit._shader = shader; + } + + auto primitiveType = MHWRender::MGeometry::kLines; + int primitiveStride = 0; + + if (primitiveType != drawItemData._primitiveType || + primitiveStride != drawItemData._primitiveStride) { + + drawItemData._primitiveType = primitiveType; + stateToCommit._primitiveType = &drawItemData._primitiveType; + + drawItemData._primitiveStride = primitiveStride; + stateToCommit._primitiveStride = &drawItemData._primitiveStride; + } + } + } + + // It is possible that all elements in the opacity array are 1. + // Due to the performance indication about transparency, we have to + // traverse the array and enable transparency only when needed. + if (!stateToCommit._isTransparent) { + const size_t numAlphas = alphaArray.size(); + for (size_t i = 0; i < numAlphas; i++) { + if (alphaArray[i] < 0.999f) { + stateToCommit._isTransparent = true; + break; + } + } + } + } + } + + // Local bounds + const GfRange3d& range = _sharedData.bounds.GetRange(); + + // Bounds are updated through MPxSubSceneOverride::setGeometryForRenderItem() + // which is expensive, so it is updated only when it gets expanded in order + // to reduce calling frequence. + if (itemDirtyBits & HdChangeTracker::DirtyExtent) { + const GfRange3d& rangeToUse = + (drawMode == MHWRender::MGeometry::kBoundingBox) ? + _delegate->GetSharedBBoxGeom().GetRange() : range; + + bool boundingBoxExpanded = false; + + const GfVec3d& min = rangeToUse.GetMin(); + const MPoint pntMin(min[0], min[1], min[2]); + if (!drawItemData._boundingBox.contains(pntMin)) { + drawItemData._boundingBox.expand(pntMin); + boundingBoxExpanded = true; + } + + const GfVec3d& max = rangeToUse.GetMax(); + const MPoint pntMax(max[0], max[1], max[2]); + if (!drawItemData._boundingBox.contains(pntMax)) { + drawItemData._boundingBox.expand(pntMax); + boundingBoxExpanded = true; + } + + if (boundingBoxExpanded) { + stateToCommit._boundingBox = &drawItemData._boundingBox; + } + } + + // Local-to-world transformation + MMatrix& worldMatrix = drawItemData._worldMatrix; + _sharedData.bounds.GetMatrix().Get(worldMatrix.matrix); + + // The bounding box draw item uses a globally-shared unit wire cube as the + // geometry and transfers scale and offset of the bounds to world matrix. + if (drawMode == MHWRender::MGeometry::kBoundingBox) { + if ((itemDirtyBits & (HdChangeTracker::DirtyExtent | HdChangeTracker::DirtyTransform)) && + !range.IsEmpty()) { + const GfVec3d midpoint = range.GetMidpoint(); + const GfVec3d size = range.GetSize(); + + MTransformationMatrix transformation; + transformation.setScale(size.data(), MSpace::kTransform); + transformation.setTranslation(midpoint.data(), MSpace::kTransform); + worldMatrix = transformation.asMatrix() * worldMatrix; + stateToCommit._worldMatrix = &drawItemData._worldMatrix; + } + } + else if (itemDirtyBits & HdChangeTracker::DirtyTransform) { + stateToCommit._worldMatrix = &drawItemData._worldMatrix; + } + + // If the prim is instanced, create one new instance per transform. + // The current instancer invalidation tracking makes it hard for + // us to tell whether transforms will be dirty, so this code + // pulls them every time something changes. + if (!GetInstancerId().IsEmpty()) { + + // Retrieve instance transforms from the instancer. + HdInstancer *instancer = renderIndex.GetInstancer(GetInstancerId()); + VtMatrix4dArray transforms = static_cast(instancer)-> + ComputeInstanceTransforms(id); + + MMatrix instanceMatrix; + + if (isDedicatedSelectionHighlightItem) { + if (_selectionState == kFullySelected) { + stateToCommit._instanceTransforms.setLength(transforms.size()); + for (size_t i = 0; i < transforms.size(); ++i) { + transforms[i].Get(instanceMatrix.matrix); + instanceMatrix = worldMatrix * instanceMatrix; + stateToCommit._instanceTransforms[i] = instanceMatrix; + } + } + else if (auto state = drawScene.GetPrimSelectionState(id)) { + for (const auto& indexArray : state->instanceIndices) { + for (const auto index : indexArray) { + transforms[index].Get(instanceMatrix.matrix); + instanceMatrix = worldMatrix * instanceMatrix; + stateToCommit._instanceTransforms.append(instanceMatrix); + } + } + } + } + else { + const unsigned int instanceCount = transforms.size(); + stateToCommit._instanceTransforms.setLength(instanceCount); + for (size_t i = 0; i < instanceCount; ++i) { + transforms[i].Get(instanceMatrix.matrix); + instanceMatrix = worldMatrix * instanceMatrix; + stateToCommit._instanceTransforms[i] = instanceMatrix; + } + + // If the item is used for both regular draw and selection highlight, + // it needs to display both wireframe color and selection highlight + // with one color vertex buffer. + if (drawItem->ContainsUsage(HdVP2DrawItem::kSelectionHighlight)) { + const MColor& color = drawScene.GetWireframeColor(); + unsigned int offset = 0; + + stateToCommit._instanceColors.setLength(instanceCount * kNumColorChannels); + for (unsigned int i = 0; i < instanceCount; ++i) { + for (unsigned int j = 0; j < kNumColorChannels; j++) { + stateToCommit._instanceColors[offset++] = color[j]; + } + } + + if (auto state = drawScene.GetPrimSelectionState(id)) { + for (const auto& indexArray : state->instanceIndices) { + for (const auto i : indexArray) { + offset = i * kNumColorChannels; + for (unsigned int j = 0; j < kNumColorChannels; j++) { + stateToCommit._instanceColors[offset+j] = kSelectionHighlightColor[j]; + } + } + } + } + } + } + } + else { + // Non-instanced Rprims. + if (itemDirtyBits & (DirtySelectionHighlight | HdChangeTracker::DirtyDisplayStyle)) { + if (drawItem->ContainsUsage(HdVP2DrawItem::kRegular) && + drawItem->ContainsUsage(HdVP2DrawItem::kSelectionHighlight)) { + MHWRender::MShaderInstance* shader = nullptr; + + auto primitiveType = MHWRender::MGeometry::kLines; + int primitiveStride = 0; + + if (desc.geomStyle == HdBasisCurvesGeomStylePatch) { + if (_selectionState != kUnselected) { + if (_curvesSharedData._displayStyle.refineLevel <= 0) { + shader = _delegate->Get3dSolidShader(kSelectionHighlightColor); + } + else if (type == HdTokens->linear) { + shader = _delegate->GetBasisCurvesLinearFallbackShader(kSelectionHighlightColor); + primitiveType = MHWRender::MGeometry::kPatch; + primitiveStride = 2; + } + else { + shader = _delegate->GetBasisCurvesCubicFallbackShader(kSelectionHighlightColor); + primitiveType = MHWRender::MGeometry::kPatch; + primitiveStride = 4; + } + } + } + else { + shader = _delegate->Get3dSolidShader( + (_selectionState != kUnselected) ? + kSelectionHighlightColor : + drawScene.GetWireframeColor() + ); + } + + if (shader != nullptr && shader != drawItemData._shader) { + drawItemData._shader = shader; + stateToCommit._shader = shader; + stateToCommit._isTransparent = false; + + if (primitiveType != drawItemData._primitiveType || + primitiveStride != drawItemData._primitiveStride) { + drawItemData._primitiveType = primitiveType; + stateToCommit._primitiveType = &drawItemData._primitiveType; + + drawItemData._primitiveStride = primitiveStride; + stateToCommit._primitiveStride = &drawItemData._primitiveStride; + } + } + } + } + } + + if (itemDirtyBits & HdChangeTracker::DirtyVisibility) { + drawItemData._enabled = drawItem->GetVisible(); + stateToCommit._enabled = &drawItemData._enabled; + } + + if (isDedicatedSelectionHighlightItem) { + if (itemDirtyBits & DirtySelectionHighlight) { + const bool enable = + (_selectionState != kUnselected) && drawItem->GetVisible(); + if (drawItemData._enabled != enable) { + drawItemData._enabled = enable; + stateToCommit._enabled = &drawItemData._enabled; + } + } + } + else if (drawMode == MHWRender::MGeometry::kBoundingBox) { + if (itemDirtyBits & HdChangeTracker::DirtyExtent) { + const bool enable = !range.IsEmpty() && drawItem->GetVisible(); + if (drawItemData._enabled != enable) { + drawItemData._enabled = enable; + stateToCommit._enabled = &drawItemData._enabled; + } + } + } + + stateToCommit._geometryDirty = (itemDirtyBits & ( + HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyNormals | + HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyTopology)); + + // Reset dirty bits because we've prepared commit state for this draw item. + drawItem->ResetDirtyBits(); + + // Capture the valid position buffer and index buffer + MHWRender::MVertexBuffer* positionsBuffer = _curvesSharedData._positionsBuffer.get(); + MHWRender::MIndexBuffer* indexBuffer = drawItemData._indexBuffer.get(); + + if (drawMode == MHWRender::MGeometry::kBoundingBox) { + const HdVP2BBoxGeom& sharedBBoxGeom = _delegate->GetSharedBBoxGeom(); + positionsBuffer = const_cast( + sharedBBoxGeom.GetPositionBuffer()); + indexBuffer = const_cast( + sharedBBoxGeom.GetIndexBuffer()); + } + + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [drawItem, stateToCommit, param, positionsBuffer, indexBuffer]() + { + MHWRender::MRenderItem* renderItem = drawItem->GetRenderItem(); + if (ARCH_UNLIKELY(!renderItem)) + return; + + MProfilingScope profilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L2, drawItem->GetRenderItemName().asChar(), "Commit"); + + const HdVP2DrawItem::RenderItemData& drawItemData = stateToCommit._drawItemData; + + MHWRender::MVertexBuffer* colorBuffer = drawItemData._colorBuffer.get(); + MHWRender::MVertexBuffer* normalsBuffer = drawItemData._normalsBuffer.get(); + + const HdVP2DrawItem::PrimvarBufferMap& primvarBuffers = drawItemData._primvarBuffers; + + // If available, something changed + if (stateToCommit._colorBufferData) + colorBuffer->commit(stateToCommit._colorBufferData); + + // If available, something changed + if (stateToCommit._normalsBufferData) + normalsBuffer->commit(stateToCommit._normalsBufferData); + + // If available, something changed + for (const auto& entry : stateToCommit._primvarBufferDataMap) { + const TfToken& primvarName = entry.first; + void* primvarBufferData = entry.second; + if (primvarBufferData) { + const auto it = primvarBuffers.find(primvarName); + if (it != primvarBuffers.end()) { + MHWRender::MVertexBuffer* primvarBuffer = it->second.get(); + if (primvarBuffer) { + primvarBuffer->commit(primvarBufferData); + } + } + } + } + + // If available, something changed + if (stateToCommit._indexBufferData) + indexBuffer->commit(stateToCommit._indexBufferData); + + // If available, something changed + if (stateToCommit._shader != nullptr) { + renderItem->setShader(stateToCommit._shader); + renderItem->setTreatAsTransparent(stateToCommit._isTransparent); + } + + // If the enable state is changed, then update it. + if (stateToCommit._enabled != nullptr) { + renderItem->enable(*stateToCommit._enabled); + } + +#if defined(MAYA_ALLOW_PRIMITIVE_TYPE_SWITCH) + // If the primitive type and stride are changed, then update them. + if (stateToCommit._primitiveType != nullptr && + stateToCommit._primitiveStride != nullptr) { + auto primitive = *stateToCommit._primitiveType; + int stride = *stateToCommit._primitiveStride; + renderItem->setPrimitive(primitive, stride); + + const bool wantConsolidation = + !stateToCommit._drawItemData._usingInstancedDraw && + primitive != MHWRender::MGeometry::kPatch; + setWantConsolidation(*renderItem, wantConsolidation); + } +#endif + + ProxyRenderDelegate& drawScene = param->GetDrawScene(); + + if (stateToCommit._geometryDirty || stateToCommit._boundingBox) { + MHWRender::MVertexBufferArray vertexBuffers; + vertexBuffers.addBuffer(kPositionsStr, positionsBuffer); + + if (colorBuffer) + vertexBuffers.addBuffer(kDiffuseColorStr, colorBuffer); + + if (normalsBuffer) + vertexBuffers.addBuffer(kNormalsStr, normalsBuffer); + + for (auto& entry : primvarBuffers) { + const TfToken& primvarName = entry.first; + MHWRender::MVertexBuffer* primvarBuffer = entry.second.get(); + if (primvarBuffer) { + vertexBuffers.addBuffer(primvarName.GetText(), primvarBuffer); + } + } + + // The API call does three things: + // - Associate geometric buffers with the render item. + // - Update bounding box. + // - Trigger consolidation/instancing update. + drawScene.setGeometryForRenderItem(*renderItem, + vertexBuffers, *indexBuffer, stateToCommit._boundingBox); + } + + // Important, update instance transforms after setting geometry on render items! + auto& oldInstanceCount = stateToCommit._drawItemData._instanceCount; + auto newInstanceCount = stateToCommit._instanceTransforms.length(); + + // GPU instancing has been enabled. We cannot switch to consolidation + // without recreating render item, so we keep using GPU instancing. + if (stateToCommit._drawItemData._usingInstancedDraw) { + if (oldInstanceCount == newInstanceCount) { + for (unsigned int i = 0; i < newInstanceCount; i++) { + // VP2 defines instance ID of the first instance to be 1. + drawScene.updateInstanceTransform(*renderItem, + i+1, stateToCommit._instanceTransforms[i]); + } + } else { + drawScene.setInstanceTransformArray(*renderItem, + stateToCommit._instanceTransforms); + } + + if (stateToCommit._instanceColors.length() == + newInstanceCount * kNumColorChannels) { + drawScene.setExtraInstanceData(*renderItem, + kSolidColorStr, stateToCommit._instanceColors); + } + } + else if (newInstanceCount > 1) { + // Turn off consolidation to allow GPU instancing to be used for + // multiple instances. + setWantConsolidation(*renderItem, false); + drawScene.setInstanceTransformArray(*renderItem, + stateToCommit._instanceTransforms); + + if (stateToCommit._instanceColors.length() == + newInstanceCount * kNumColorChannels) { + drawScene.setExtraInstanceData(*renderItem, + kSolidColorStr, stateToCommit._instanceColors); + } + + stateToCommit._drawItemData._usingInstancedDraw = true; + } + else if (newInstanceCount == 1) { + // Special case for single instance prims. We will keep the original + // render item to allow consolidation. + renderItem->setMatrix(&stateToCommit._instanceTransforms[0]); + } + else if (stateToCommit._worldMatrix != nullptr) { + // Regular non-instanced prims. Consolidation has been turned on by + // default and will be kept enabled on this case. + renderItem->setMatrix(stateToCommit._worldMatrix); + } + + oldInstanceCount = newInstanceCount; + }); +} + +/*! \brief Add additional dirty bits + + This callback from Rprim gives the prim an opportunity to set + additional dirty bits based on those already set. This is done + before the dirty bits are passed to the scene delegate, so can be + used to communicate that extra information is needed by the prim to + process the changes. + + The return value is the new set of dirty bits, which replaces the bits + passed in. + + See HdRprim::PropagateRprimDirtyBits() +*/ +HdDirtyBits HdVP2BasisCurves::_PropagateDirtyBits(HdDirtyBits bits) const +{ + // Propagate dirty bits to all draw items. + for (const std::pair& pair : _reprs) { + const HdReprSharedPtr& repr = pair.second; + const HdRepr::DrawItems& items = repr->GetDrawItems(); + for (HdDrawItem* item : items) { + if (HdVP2DrawItem* drawItem = static_cast(item)) { + drawItem->SetDirtyBits(bits); + } + } + } + + return bits; +} + +/*! \brief Initialize the given representation of this Rprim. + + This is called prior to syncing the prim, the first time the repr + is used. + + \param reprToken the name of the repr to initalize. HdRprim has already + resolved the reprName to its final value. + + \param dirtyBits an in/out value. It is initialized to the dirty bits + from the change tracker. InitRepr can then set additional + dirty bits if additional data is required from the scene + delegate when this repr is synced. + + InitRepr occurs before dirty bit propagation. + + See HdRprim::InitRepr() +*/ +void HdVP2BasisCurves::_InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) +{ + auto* const param = static_cast(_delegate->GetRenderParam()); + MSubSceneContainer* subSceneContainer = param->GetContainer(); + if (ARCH_UNLIKELY(!subSceneContainer)) + return; + + // We don't create a repr for the selection token because it serves for + // selection state update only. Mark DirtySelection bit that will be + // automatically propagated to all draw items of the rprim. + if (reprToken == HdVP2ReprTokens->selection) { + const HdVP2SelectionStatus selectionState = + param->GetDrawScene().GetPrimSelectionStatus(GetId()); + if (_selectionState != selectionState) { + _selectionState = selectionState; + *dirtyBits |= DirtySelection; + } + else if (_selectionState == kPartiallySelected) { + *dirtyBits |= DirtySelection; + } + return; + } + + // If the repr has any draw item with the DirtySelection bit, mark the + // DirtySelectionHighlight bit to invoke the synchronization call. + _ReprVector::iterator it = std::find_if( + _reprs.begin(), _reprs.end(), _ReprComparator(reprToken)); + if (it != _reprs.end()) { + const HdReprSharedPtr& repr = it->second; + const HdRepr::DrawItems& items = repr->GetDrawItems(); + for (const HdDrawItem* item : items) { + const HdVP2DrawItem* drawItem = static_cast(item); + if (drawItem && (drawItem->GetDirtyBits() & DirtySelection)) { + *dirtyBits |= DirtySelectionHighlight; + break; + } + } + return; + } + + // add new repr + _reprs.emplace_back(reprToken, boost::make_shared()); + HdReprSharedPtr repr = _reprs.back().second; + + // set dirty bit to say we need to sync a new repr + *dirtyBits |= HdChangeTracker::NewRepr; + + _BasisCurvesReprConfig::DescArray descs = _GetReprDesc(reprToken); + + for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { + const HdBasisCurvesReprDesc& desc = descs[descIdx]; + if (desc.geomStyle == HdBasisCurvesGeomStyleInvalid) { + continue; + } + + auto* drawItem = new HdVP2DrawItem(_delegate, &_sharedData); + repr->AddDrawItem(drawItem); + + const MString& renderItemName = drawItem->GetRenderItemName(); + + MHWRender::MRenderItem* renderItem = nullptr; + + switch (desc.geomStyle) { + case HdBasisCurvesGeomStylePatch: + renderItem = _CreatePatchRenderItem(renderItemName); + drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); + break; + case HdBasisCurvesGeomStyleWire: + // The item is used for wireframe display and selection highlight. + if (reprToken == HdReprTokens->wire) { + renderItem = _CreateWireRenderItem(renderItemName); + drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); + } + // The item is used for bbox display and selection highlight. + else if (reprToken == HdVP2ReprTokens->bbox) { + renderItem = _CreateBBoxRenderItem(renderItemName); + drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); + } + break; + default: + TF_WARN("Unsupported geomStyle"); + break; + } + + if (renderItem) { + // Store the render item pointer to avoid expensive lookup in the + // subscene container. + drawItem->SetRenderItem(renderItem); + + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [subSceneContainer, renderItem]() { + subSceneContainer->add(renderItem); + } + ); + } + } +} + +/*! \brief Update the named repr object for this Rprim. + + Repr objects are created to support specific reprName tokens, and contain a list of + HdVP2DrawItems and corresponding RenderItems. +*/ +void HdVP2BasisCurves::_UpdateRepr( + HdSceneDelegate *sceneDelegate, + TfToken const &reprToken) +{ + HdReprSharedPtr const &repr = _GetRepr(reprToken); + if (!repr) { + return; + } + + const _BasisCurvesReprConfig::DescArray &descs = _GetReprDesc(reprToken); + const size_t numDescs = descs.size(); + int drawItemIndex = 0; + + for (size_t i = 0; i < numDescs; ++i) { + const HdBasisCurvesReprDesc &desc = descs[i]; + if (desc.geomStyle != HdBasisCurvesGeomStyleInvalid) { + HdVP2DrawItem *drawItem = static_cast( + repr->GetDrawItem(drawItemIndex++)); + if (drawItem) { + _UpdateDrawItem(sceneDelegate, drawItem, desc); + } + } + } +} + +/*! \brief Returns the minimal set of dirty bits to place in the + change tracker for use in the first sync of this prim. +*/ +HdDirtyBits HdVP2BasisCurves::GetInitialDirtyBitsMask() const +{ + constexpr HdDirtyBits bits = + HdChangeTracker::InitRepr | + HdChangeTracker::DirtyExtent | + HdChangeTracker::DirtyInstanceIndex | + HdChangeTracker::DirtyNormals | + HdChangeTracker::DirtyPoints | + HdChangeTracker::DirtyPrimID | + HdChangeTracker::DirtyPrimvar | + HdChangeTracker::DirtyDisplayStyle | + HdChangeTracker::DirtyRepr | + HdChangeTracker::DirtyMaterialId | + HdChangeTracker::DirtyTopology | + HdChangeTracker::DirtyTransform | + HdChangeTracker::DirtyVisibility | + HdChangeTracker::DirtyWidths | + HdChangeTracker::DirtyComputationPrimvarDesc; + + return bits; +} + +/*! \brief Update _primvarSourceMap, our local cache of raw primvar data. + + This function pulls data from the scene delegate, but defers processing. + + While iterating primvars, we skip "points" (vertex positions) because + the points primvar is processed separately for direct access later. We + only call GetPrimvar on primvars that have been marked dirty. +*/ +void HdVP2BasisCurves::_UpdatePrimvarSources( + HdSceneDelegate* sceneDelegate, + HdDirtyBits dirtyBits, + const TfTokenVector& requiredPrimvars) +{ + const SdfPath& id = GetId(); + + TfTokenVector::const_iterator begin = requiredPrimvars.cbegin(); + TfTokenVector::const_iterator end = requiredPrimvars.cend(); + + for (size_t i = 0; i < HdInterpolationCount; i++) { + const HdInterpolation interp = static_cast(i); + + const HdPrimvarDescriptorVector primvars = + GetPrimvarDescriptors(sceneDelegate, interp); + + for (const HdPrimvarDescriptor& pv: primvars) { + if (std::find(begin, end, pv.name) == end) { + _curvesSharedData._primvarSourceMap.erase(pv.name); + } + else if (HdChangeTracker::IsPrimvarDirty(dirtyBits, id, pv.name)) { + const VtValue value = GetPrimvar(sceneDelegate, pv.name); + _curvesSharedData._primvarSourceMap[pv.name] = { value, interp }; + } + } + } +} + +/*! \brief Create render item for wireframe repr. +*/ +MHWRender::MRenderItem* +HdVP2BasisCurves::_CreateWireRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::DecorationItem, + MHWRender::MGeometry::kLines + ); + + renderItem->setDrawMode(MHWRender::MGeometry::kWireframe); + renderItem->depthPriority(MHWRender::MRenderItem::sDormantWireDepthPriority); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dSolidShader(kOpaqueGray)); + renderItem->setSelectionMask(MSelectionMask::kSelectCurves); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +/*! \brief Create render item for bbox repr. +*/ +MHWRender::MRenderItem* +HdVP2BasisCurves::_CreateBBoxRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::DecorationItem, + MHWRender::MGeometry::kLines + ); + + renderItem->setDrawMode(MHWRender::MGeometry::kBoundingBox); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dSolidShader(kOpaqueGray)); + renderItem->setSelectionMask(MSelectionMask::kSelectCurves); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +/*! \brief Create render item for smoothHull repr. +*/ +MHWRender::MRenderItem* +HdVP2BasisCurves::_CreatePatchRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::MaterialSceneItem, + MHWRender::MGeometry::kLines + ); + + renderItem->setDrawMode(static_cast( + MHWRender::MGeometry::kShaded | MHWRender::MGeometry::kTextured)); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dSolidShader(kOpaqueGray)); + renderItem->setSelectionMask(MSelectionMask::kSelectCurves); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + +PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/basisCurves.h b/lib/render/vp2RenderDelegate/basisCurves.h new file mode 100644 index 0000000000..b9a9c99173 --- /dev/null +++ b/lib/render/vp2RenderDelegate/basisCurves.h @@ -0,0 +1,143 @@ +// +// Copyright 2020 Autodesk +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef HDVP2_BASIS_CURVES_H +#define HDVP2_BASIS_CURVES_H + +#include "pxr/pxr.h" +#include "pxr/base/vt/array.h" +#include "pxr/imaging/hd/basisCurves.h" +#include "pxr/imaging/hd/enums.h" +#include "pxr/usd/sdf/path.h" + +#include + +#include "proxyRenderDelegate.h" + +#include + +PXR_NAMESPACE_OPEN_SCOPE + +class HdSceneDelegate; +class HdVP2DrawItem; +class HdVP2RenderDelegate; + +/*! \brief HdVP2BasisCurves-specific data shared among all its draw items. + \class HdVP2BasisCurvesSharedData + + A Rprim can have multiple draw items. The shared data are extracted from + USD scene delegate during synchronization. Then each draw item can prepare + draw data from these shared data as needed. +*/ +struct HdVP2BasisCurvesSharedData +{ + //! Cached scene data. VtArrays are reference counted, so as long as we + //! only call const accessors keeping them around doesn't incur a buffer + //! copy. + HdBasisCurvesTopology _topology; + + //! A local cache of primvar scene data. "data" is a copy-on-write handle to + //! the actual primvar buffer, and "interpolation" is the interpolation mode + //! to be used. + struct PrimvarSource { + VtValue data; + HdInterpolation interpolation; + }; + TfHashMap _primvarSourceMap; + + //! A local cache of points. It is not cached in the above primvar map + //! but a separate VtArray for easier access. + VtVec3fArray _points; + + //! Position buffer of the Rprim to be shared among all its draw items. + std::unique_ptr _positionsBuffer; + + //! The display style. + HdDisplayStyle _displayStyle; +}; + +/*! \brief VP2 representation of basis curves. + \class HdVP2BasisCurves + + The prim object's main function is to bridge the scene description and the + renderable representation. The Hydra image generation algorithm will call + HdRenderIndex::SyncAll() before any drawing; this, in turn, will call + Sync() for each Rprim with new data. + + Sync() is passed a set of dirtyBits, indicating which scene buffers are + dirty. It uses these to pull all of the new scene data and constructs + updated geometry objects. Commit of changed buffers to GPU happens + in HdVP2RenderDelegate::CommitResources(), which runs on main-thread after + all Rprims have been updated. +*/ +class HdVP2BasisCurves final: public HdBasisCurves +{ +public: + HdVP2BasisCurves( + HdVP2RenderDelegate *delegate, + const SdfPath &id, + const SdfPath &instancerId = SdfPath()); + + //! Destructor. + ~HdVP2BasisCurves() override = default; + + void Sync(HdSceneDelegate *delegate, + HdRenderParam *renderParam, + HdDirtyBits *dirtyBits, + TfToken const &reprToken) override; + + HdDirtyBits GetInitialDirtyBitsMask() const override; + +protected: + HdDirtyBits _PropagateDirtyBits(HdDirtyBits bits) const override; + + void _InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBits) override; + +private: + void _UpdateRepr(HdSceneDelegate *sceneDelegate, + TfToken const &reprToken); + + void _UpdateDrawItem(HdSceneDelegate *sceneDelegate, + HdVP2DrawItem *drawItem, + HdBasisCurvesReprDesc const &desc); + + void _UpdatePrimvarSources( + HdSceneDelegate *sceneDelegate, + HdDirtyBits dirtyBits, + TfTokenVector const &requiredPrimvars); + + MHWRender::MRenderItem* _CreatePatchRenderItem(const MString& name) const; + MHWRender::MRenderItem* _CreateWireRenderItem(const MString& name) const; + MHWRender::MRenderItem* _CreateBBoxRenderItem(const MString& name) const; + + enum DirtyBits : HdDirtyBits { + DirtySelection = HdChangeTracker::CustomBitsBegin, + DirtySelectionHighlight = (DirtySelection << 1) + }; + + HdVP2RenderDelegate* _delegate { nullptr }; //!< VP2 render delegate for which this mesh was created + const MString _rprimId; //!< Rprim id cached as a maya string for easier debugging and profiling + + //! Shared data for all draw items of the Rprim + HdVP2BasisCurvesSharedData _curvesSharedData; + + //! Selection status of the Rprim + HdVP2SelectionStatus _selectionState { kUnselected }; +}; + +PXR_NAMESPACE_CLOSE_SCOPE + +#endif // HDVP2_BASIS_CURVES_H diff --git a/lib/render/vp2RenderDelegate/draw_item.cpp b/lib/render/vp2RenderDelegate/draw_item.cpp index 4f6f683d23..09bdb58235 100644 --- a/lib/render/vp2RenderDelegate/draw_item.cpp +++ b/lib/render/vp2RenderDelegate/draw_item.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,16 +24,12 @@ PXR_NAMESPACE_OPEN_SCOPE /*! \brief Constructor. Data holder for its corresponding render item to facilitate parallelized evaluation. - -Position buffer is held by HdVP2Mesh and shared among its render items. */ HdVP2DrawItem::HdVP2DrawItem( HdVP2RenderDelegate* delegate, - const HdRprimSharedData* sharedData, - const HdMeshReprDesc& desc) + const HdRprimSharedData* sharedData) : HdDrawItem(sharedData) , _delegate(delegate) -, _reprDesc(desc) { // In the case of instancing, the ID of a proto has an attribute at the end, // we keep this info in _renderItemName so if needed we can extract proto ID @@ -46,12 +42,6 @@ HdVP2DrawItem::HdVP2DrawItem( _renderItemData._indexBuffer.reset( new MHWRender::MIndexBuffer(MHWRender::MGeometry::kUnsignedInt32)); - - if (desc.geomStyle == HdMeshGeomStyleHull) { - const MHWRender::MVertexBufferDescriptor desc("", - MHWRender::MGeometry::kNormal, MHWRender::MGeometry::kFloat, 3); - _renderItemData._normalsBuffer.reset(new MHWRender::MVertexBuffer(desc)); - } } //! \brief Destructor. @@ -65,9 +55,4 @@ HdVP2DrawItem::~HdVP2DrawItem() { } } -//! \brief Get access to render item data. -HdVP2DrawItem::RenderItemData& HdVP2DrawItem::GetRenderItemData() { - return _renderItemData; -} - PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/draw_item.h b/lib/render/vp2RenderDelegate/draw_item.h index a9abfc40d6..2cbd72e56b 100644 --- a/lib/render/vp2RenderDelegate/draw_item.h +++ b/lib/render/vp2RenderDelegate/draw_item.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -67,6 +67,11 @@ class HdVP2DrawItem final : public HdDrawItem //! Whether or not the render item is enabled bool _enabled{ true }; + //! Primitive type of the render item + MHWRender::MGeometry::Primitive _primitiveType{ MHWRender::MGeometry::kInvalidPrimitive }; + //! Primitive stride of the render item (valid only if the primitive type is kPatch) + int _primitiveStride{ 0 }; + //! Number of instances currently allocated for render item unsigned int _instanceCount{ 0 }; @@ -83,11 +88,13 @@ class HdVP2DrawItem final : public HdDrawItem }; public: - HdVP2DrawItem(HdVP2RenderDelegate* delegate, const HdRprimSharedData* sharedData, const HdMeshReprDesc& desc); + HdVP2DrawItem(HdVP2RenderDelegate* delegate, const HdRprimSharedData* sharedData); ~HdVP2DrawItem(); - RenderItemData& GetRenderItemData(); + /*! \brief Get access to render item data. + */ + RenderItemData& GetRenderItemData() { return _renderItemData; } /*! \brief Get render item name */ @@ -101,10 +108,6 @@ class HdVP2DrawItem final : public HdDrawItem */ void SetRenderItem(MHWRender::MRenderItem* item) { _renderItem = item; } - /*! \brief Get the repr desc for which the draw item was created. - */ - const HdMeshReprDesc& GetReprDesc() const { return _reprDesc; } - /*! \brief Set a usage to the render item */ void SetUsage(RenderItemUsage usage) { _renderItemUsage = usage; } @@ -142,7 +145,6 @@ class HdVP2DrawItem final : public HdDrawItem private: HdVP2RenderDelegate* _delegate{ nullptr }; //!< VP2 render delegate for which this draw item was created - const HdMeshReprDesc _reprDesc; //!< The repr desc for which the draw item was created. MString _renderItemName; //!< Unique name for easier debugging and profiling. MHWRender::MRenderItem* _renderItem{ nullptr }; //!< Pointer of the render item for fast access. No ownership is held. RenderItemData _renderItemData; //!< VP2 render item data diff --git a/lib/render/vp2RenderDelegate/mesh.cpp b/lib/render/vp2RenderDelegate/mesh.cpp index 7335b05f1f..b1a89887e1 100644 --- a/lib/render/vp2RenderDelegate/mesh.cpp +++ b/lib/render/vp2RenderDelegate/mesh.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -110,25 +110,6 @@ namespace { CommitState() = delete; }; - //! Helper utility function to get number of draw items required for given representation - size_t _GetNumDrawItemsForDesc(const HdMeshReprDesc& reprDesc) - { - // By default, each repr desc item maps to 1 draw item - size_t numDrawItems = 1; - - // Different representations may require different number of draw items - // See HdSt for an example. - switch (reprDesc.geomStyle) { - case HdMeshGeomStyleInvalid: - numDrawItems = 0; - break; - default: - break; - } - - return numDrawItems; - } - //! Helper utility function to fill primvar data to vertex buffer. template void _FillPrimvarData(DEST_TYPE* vertexBuffer, @@ -656,59 +637,57 @@ void HdVP2Mesh::_InitRepr(const TfToken& reprToken, HdDirtyBits* dirtyBits) { for (size_t descIdx = 0; descIdx < descs.size(); ++descIdx) { const HdMeshReprDesc& desc = descs[descIdx]; + if (desc.geomStyle == HdMeshGeomStyleInvalid) { + continue; + } - size_t numDrawItems = _GetNumDrawItemsForDesc(desc); - if (numDrawItems == 0) continue; - - for (size_t itemId = 0; itemId < numDrawItems; itemId++) { - auto* drawItem = new HdVP2DrawItem(_delegate, &_sharedData, desc); - repr->AddDrawItem(drawItem); + auto* drawItem = new HdVP2DrawItem(_delegate, &_sharedData); + repr->AddDrawItem(drawItem); - const MString& renderItemName = drawItem->GetRenderItemName(); + const MString& renderItemName = drawItem->GetRenderItemName(); - MHWRender::MRenderItem* renderItem = nullptr; + MHWRender::MRenderItem* renderItem = nullptr; - switch (desc.geomStyle) { - case HdMeshGeomStyleHull: - renderItem = _CreateSmoothHullRenderItem(renderItemName); - break; - case HdMeshGeomStyleHullEdgeOnly: - // The smoothHull repr uses the wireframe item for selection - // highlight only. - if (reprToken == HdReprTokens->smoothHull) { - renderItem = _CreateSelectionHighlightRenderItem(renderItemName); - drawItem->SetUsage(HdVP2DrawItem::kSelectionHighlight); - } - // The item is used for wireframe display and selection highlight. - else if (reprToken == HdReprTokens->wire) { - renderItem = _CreateWireframeRenderItem(renderItemName); - drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); - } - // The item is used for bbox display and selection highlight. - else if (reprToken == HdVP2ReprTokens->bbox) { - renderItem = _CreateBoundingBoxRenderItem(renderItemName); - drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); - } - break; - case HdMeshGeomStylePoints: - renderItem = _CreatePointsRenderItem(renderItemName); - break; - default: - TF_WARN("Unsupported geomStyle"); - break; + switch (desc.geomStyle) { + case HdMeshGeomStyleHull: + renderItem = _CreateSmoothHullRenderItem(renderItemName); + break; + case HdMeshGeomStyleHullEdgeOnly: + // The smoothHull repr uses the wireframe item for selection + // highlight only. + if (reprToken == HdReprTokens->smoothHull) { + renderItem = _CreateSelectionHighlightRenderItem(renderItemName); + drawItem->SetUsage(HdVP2DrawItem::kSelectionHighlight); + } + // The item is used for wireframe display and selection highlight. + else if (reprToken == HdReprTokens->wire) { + renderItem = _CreateWireframeRenderItem(renderItemName); + drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); + } + // The item is used for bbox display and selection highlight. + else if (reprToken == HdVP2ReprTokens->bbox) { + renderItem = _CreateBoundingBoxRenderItem(renderItemName); + drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); } + break; + case HdMeshGeomStylePoints: + renderItem = _CreatePointsRenderItem(renderItemName); + break; + default: + TF_WARN("Unsupported geomStyle"); + break; + } - if (renderItem) { - // Store the render item pointer to avoid expensive lookup in the - // subscene container. - drawItem->SetRenderItem(renderItem); + if (renderItem) { + // Store the render item pointer to avoid expensive lookup in the + // subscene container. + drawItem->SetRenderItem(renderItem); - _delegate->GetVP2ResourceRegistry().EnqueueCommit( - [subSceneContainer, renderItem]() { - subSceneContainer->add(renderItem); - } - ); - } + _delegate->GetVP2ResourceRegistry().EnqueueCommit( + [subSceneContainer, renderItem]() { + subSceneContainer->add(renderItem); + } + ); } if (desc.geomStyle == HdMeshGeomStyleHull) { @@ -760,10 +739,17 @@ void HdVP2Mesh::_UpdateRepr(HdSceneDelegate *sceneDelegate, const TfToken& reprT } // For each relevant draw item, update dirty buffer sources. - const HdRepr::DrawItems& items = curRepr->GetDrawItems(); - for (HdDrawItem* item : items) { - if (auto* drawItem = static_cast(item)) { - _UpdateDrawItem(sceneDelegate, drawItem, + int drawItemIndex = 0; + for (size_t descIdx = 0; descIdx < reprDescs.size(); ++descIdx) { + const HdMeshReprDesc &desc = reprDescs[descIdx]; + if (desc.geomStyle == HdMeshGeomStyleInvalid) { + continue; + } + + auto* drawItem = static_cast( + curRepr->GetDrawItem(drawItemIndex++)); + if (drawItem) { + _UpdateDrawItem(sceneDelegate, drawItem, desc, requireSmoothNormals, requireFlatNormals); } } @@ -777,6 +763,7 @@ void HdVP2Mesh::_UpdateRepr(HdSceneDelegate *sceneDelegate, const TfToken& reprT void HdVP2Mesh::_UpdateDrawItem( HdSceneDelegate* sceneDelegate, HdVP2DrawItem* drawItem, + const HdMeshReprDesc& desc, bool requireSmoothNormals, bool requireFlatNormals) { @@ -802,7 +789,6 @@ void HdVP2Mesh::_UpdateDrawItem( HdVP2DrawItem::RenderItemData& drawItemData = stateToCommit._drawItemData; const SdfPath& id = GetId(); - const HdMeshReprDesc &desc = drawItem->GetReprDesc(); auto* const param = static_cast(_delegate->GetRenderParam()); ProxyRenderDelegate& drawScene = param->GetDrawScene(); @@ -853,8 +839,8 @@ void HdVP2Mesh::_UpdateDrawItem( } } - // Prepare normal buffer. - if (drawItemData._normalsBuffer) { + if (desc.geomStyle == HdMeshGeomStyleHull) { + // Prepare normal buffer. VtVec3fArray normals; HdInterpolation interp = HdInterpolationConstant; @@ -897,6 +883,16 @@ void HdVP2Mesh::_UpdateDrawItem( } if (prepareNormals) { + if (!drawItemData._normalsBuffer) { + const MHWRender::MVertexBufferDescriptor vbDesc("", + MHWRender::MGeometry::kNormal, + MHWRender::MGeometry::kFloat, + 3); + + drawItemData._normalsBuffer.reset( + new MHWRender::MVertexBuffer(vbDesc)); + } + void* bufferData = drawItemData._normalsBuffer->acquire(numVertices, true); if (bufferData) { _FillPrimvarData(static_cast(bufferData), @@ -906,10 +902,8 @@ void HdVP2Mesh::_UpdateDrawItem( stateToCommit._normalsBufferData = bufferData; } } - } - // Prepare color buffer. - if (desc.geomStyle == HdMeshGeomStyleHull) { + // Prepare color buffer. if ((itemDirtyBits & HdChangeTracker::DirtyMaterialId) != 0) { const HdVP2Material* material = static_cast( renderIndex.GetSprim(HdPrimTypeTokens->material, GetMaterialId()) diff --git a/lib/render/vp2RenderDelegate/mesh.h b/lib/render/vp2RenderDelegate/mesh.h index 659f751e5d..6c39d83bb9 100644 --- a/lib/render/vp2RenderDelegate/mesh.h +++ b/lib/render/vp2RenderDelegate/mesh.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -74,7 +74,7 @@ struct HdVP2MeshSharedData { Sync() is passed a set of dirtyBits, indicating which scene buffers are dirty. It uses these to pull all of the new scene data and constructs - updated embree geometry objects. Commit of changed buffers to GPU happens + updated geometry objects. Commit of changed buffers to GPU happens in HdVP2RenderDelegate::CommitResources(), which runs on main-thread after all prims have been updated. */ @@ -100,6 +100,7 @@ class HdVP2Mesh final : public HdMesh { void _UpdateDrawItem( HdSceneDelegate*, HdVP2DrawItem*, + const HdMeshReprDesc& desc, bool requireSmoothNormals, bool requireFlatNormals); void _UpdatePrimvarSources( diff --git a/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp b/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp index ae36b950e0..c3ef7e501c 100644 --- a/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp +++ b/lib/render/vp2RenderDelegate/proxyRenderDelegate.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ #include "pxr/imaging/hdx/renderTask.h" #include "pxr/imaging/hdx/selectionTracker.h" #include "pxr/imaging/hdx/taskController.h" +#include "pxr/imaging/hd/basisCurves.h" #include "pxr/imaging/hd/enums.h" #include "pxr/imaging/hd/mesh.h" #include "pxr/imaging/hd/repr.h" @@ -124,6 +125,15 @@ namespace // Special token for selection update and no need to create repr. Adding // the empty desc to remove Hydra warning. HdMesh::ConfigureRepr(HdVP2ReprTokens->selection, HdMeshReprDesc()); + + // Wireframe desc for bbox display. + HdBasisCurves::ConfigureRepr(HdVP2ReprTokens->bbox, + HdBasisCurvesGeomStyleWire); + + // Special token for selection update and no need to create repr. Adding + // the null desc to remove Hydra warning. + HdBasisCurves::ConfigureRepr(HdVP2ReprTokens->selection, + HdBasisCurvesGeomStyleInvalid); } #if defined(WANT_UFE_BUILD) @@ -364,6 +374,15 @@ void ProxyRenderDelegate::_UpdateSceneDelegate() SelectionChanged(); } } + + const int refineLevel = _proxyShape->getComplexity(); + if (refineLevel != _sceneDelegate->GetRefineLevelFallback()) + { + MProfilingScope subProfilingScope(HdVP2RenderDelegate::sProfilerCategory, + MProfiler::kColorC_L1, "SetRefineLevelFallback"); + + _sceneDelegate->SetRefineLevelFallback(refineLevel); + } } //! \brief Execute Hydra engine to perform minimal VP2 draw data update based on change tracker. diff --git a/lib/render/vp2RenderDelegate/render_delegate.cpp b/lib/render/vp2RenderDelegate/render_delegate.cpp index cde7047f67..c5837806c0 100644 --- a/lib/render/vp2RenderDelegate/render_delegate.cpp +++ b/lib/render/vp2RenderDelegate/render_delegate.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ #include "render_delegate.h" +#include "basisCurves.h" #include "bboxGeom.h" #include "material.h" #include "mesh.h" @@ -45,8 +46,12 @@ namespace /*! \brief List of supported Rprims by VP2 render delegate */ inline const TfTokenVector& _SupportedRprimTypes() { - static const TfTokenVector r{ HdPrimTypeTokens->mesh }; - return r; + static const TfTokenVector SUPPORTED_RPRIM_TYPES = + { + HdPrimTypeTokens->basisCurves, + HdPrimTypeTokens->mesh + }; + return SUPPORTED_RPRIM_TYPES; } /*! \brief List of supported Sprims by VP2 render delegate @@ -67,9 +72,16 @@ namespace const MString _diffuseColorParameterName = "diffuseColor"; //!< Shader parameter name const MString _solidColorParameterName = "solidColor"; //!< Shader parameter name const MString _pointSizeParameterName = "pointSize"; //!< Shader parameter name - const MString _fallbackShaderName = "FallbackShader"; //!< Name of the fallback shader const MString _structOutputName = "outSurfaceFinal"; //!< Output struct name of the fallback shader + //! Name of the fallback shaders + const MString _fallbackShaderNames[3] = + { + "FallbackShader", + "BasisCurvesLinearFallbackShader", + "BasisCurvesCubicFallbackShader" + }; + /*! \brief Color hash helper class, used by shader registry */ struct MColorHash @@ -119,6 +131,11 @@ namespace TF_VERIFY(_fallbackCPVShader); + _3dCPVSolidShader = shaderMgr->getStockShader( + MHWRender::MShaderManager::k3dCPVSolidShader); + + TF_VERIFY(_3dCPVSolidShader); + _3dFatPointShader = shaderMgr->getStockShader( MHWRender::MShaderManager::k3dFatPointShader); @@ -145,7 +162,13 @@ namespace return _3dFatPointShader; } - /*! \brief Returns a 3d green shader that can be used for selection highlight. + /*! \brief Returns a 3d CPV solid-color shader instance. + */ + MHWRender::MShaderInstance* Get3dCPVSolidShader() const { + return _3dCPVSolidShader; + } + + /*! \brief Returns a 3d solid shader with the specified color. */ MHWRender::MShaderInstance* Get3dSolidShader(const MColor& color) { @@ -192,16 +215,23 @@ namespace allowing only one instance per color which enables consolidation of draw calls with same shader instance. - \param color Color to set on given shader instance + \param color Color to set on given shader instance + \param index Index to the required shader name in _fallbackShaderNames \return A new or existing copy of shader instance with given color */ - MHWRender::MShaderInstance* GetFallbackShader(const MColor& color) + MHWRender::MShaderInstance* GetFallbackShader(const MColor& color, unsigned int index) { + if (index >= sizeof(_fallbackShaders) / sizeof(_fallbackShaders[0])) { + return nullptr; + } + + auto& shaderMap = _fallbackShaders[index]; + // Look for it first with reader lock - tbb::spin_rw_mutex::scoped_lock lock(_fallbackShaders._mutex, false/*write*/); - auto it = _fallbackShaders._map.find(color); - if (it != _fallbackShaders._map.end()) { + tbb::spin_rw_mutex::scoped_lock lock(shaderMap._mutex, false/*write*/); + auto it = shaderMap._map.find(color); + if (it != shaderMap._map.end()) { return it->second; } @@ -209,8 +239,8 @@ namespace lock.upgrade_to_writer(); // Double check that it wasn't inserted by another thread - it = _fallbackShaders._map.find(color); - if (it != _fallbackShaders._map.end()) { + it = shaderMap._map.find(color); + if (it != shaderMap._map.end()) { return it->second; } @@ -220,7 +250,7 @@ namespace const MHWRender::MShaderManager* shaderMgr = renderer ? renderer->getShaderManager() : nullptr; if (TF_VERIFY(shaderMgr)) { - shader = shaderMgr->getFragmentShader(_fallbackShaderName, + shader = shaderMgr->getFragmentShader(_fallbackShaderNames[index], _structOutputName, true); if (TF_VERIFY(shader)) { @@ -228,7 +258,7 @@ namespace shader->setParameter(_diffuseColorParameterName, diffuseColor); // Insert instance we just created - _fallbackShaders._map[color] = shader; + shaderMap._map[color] = shader; } } @@ -238,11 +268,12 @@ namespace private: bool _isInitialized { false }; //!< Whether the shader cache is initialized - MShaderMap _fallbackShaders; //!< Shader registry used by fallback shaders - MShaderMap _3dSolidShaders; //!< Shader registry used by fallback shaders + MShaderMap _fallbackShaders[3]; //!< Shader registry used by fallback shaders + MShaderMap _3dSolidShaders; //!< Shader registry used by fallback shaders MHWRender::MShaderInstance* _fallbackCPVShader { nullptr }; //!< Fallback shader with CPV support MHWRender::MShaderInstance* _3dFatPointShader { nullptr }; //!< 3d shader for points + MHWRender::MShaderInstance* _3dCPVSolidShader { nullptr }; //!< 3d CPV solid-color shader }; MShaderCache sShaderCache; //!< Global shader cache to minimize the number of unique shaders. @@ -468,6 +499,9 @@ HdRprim* HdVP2RenderDelegate::CreateRprim( if (typeId == HdPrimTypeTokens->mesh) { return new HdVP2Mesh(this, rprimId, instancerId); } + if (typeId == HdPrimTypeTokens->basisCurves) { + return new HdVP2BasisCurves(this, rprimId, instancerId); + } //if (typeId == HdPrimTypeTokens->volume) { // return new HdVP2Volume(this, rprimId, instancerId); //} @@ -649,7 +683,37 @@ MString HdVP2RenderDelegate::GetLocalNodeName(const MString& name) const { MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackShader( const MColor& color) const { - return sShaderCache.GetFallbackShader(color); + return sShaderCache.GetFallbackShader(color, 0); +} + +/*! \brief Returns a fallback shader instance when no material is bound. + + This method is keeping registry of all fallback shaders generated, keeping minimal + number of shader instances. + + \param color Color to set on given shader instance + + \return A new or existing copy of shader instance with given color parameter set +*/ +MHWRender::MShaderInstance* +HdVP2RenderDelegate::GetBasisCurvesLinearFallbackShader(const MColor& color) const +{ + return sShaderCache.GetFallbackShader(color, 1); +} + +/*! \brief Returns a fallback shader instance when no material is bound. + + This method is keeping registry of all fallback shaders generated, keeping minimal + number of shader instances. + + \param color Color to set on given shader instance + + \return A new or existing copy of shader instance with given color parameter set +*/ +MHWRender::MShaderInstance* +HdVP2RenderDelegate::GetBasisCurvesCubicFallbackShader(const MColor& color) const +{ + return sShaderCache.GetFallbackShader(color, 2); } /*! \brief Returns a fallback CPV shader instance when no material is bound. @@ -659,7 +723,7 @@ MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackCPVShader() const return sShaderCache.GetFallbackCPVShader(); } -/*! \brief Returns a 3d green shader that can be used for selection highlight. +/*! \brief Returns a 3d solid-color shader. */ MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dSolidShader( const MColor& color) const @@ -667,6 +731,13 @@ MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dSolidShader( return sShaderCache.Get3dSolidShader(color); } +/*! \brief Returns a 3d CPV solid-color shader. +*/ +MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dCPVSolidShader() const +{ + return sShaderCache.Get3dCPVSolidShader(); +} + /*! \brief Returns a white 3d fat point shader. */ MHWRender::MShaderInstance* HdVP2RenderDelegate::Get3dFatPointShader() const diff --git a/lib/render/vp2RenderDelegate/render_delegate.h b/lib/render/vp2RenderDelegate/render_delegate.h index 0a5845fbd3..0cf7736df9 100644 --- a/lib/render/vp2RenderDelegate/render_delegate.h +++ b/lib/render/vp2RenderDelegate/render_delegate.h @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -109,8 +109,12 @@ class HdVP2RenderDelegate final : public HdRenderDelegate { MHWRender::MShaderInstance* GetFallbackShader(const MColor& color) const; MHWRender::MShaderInstance* GetFallbackCPVShader() const; MHWRender::MShaderInstance* Get3dSolidShader(const MColor& color) const; + MHWRender::MShaderInstance* Get3dCPVSolidShader() const; MHWRender::MShaderInstance* Get3dFatPointShader() const; + MHWRender::MShaderInstance* GetBasisCurvesLinearFallbackShader(const MColor& color) const; + MHWRender::MShaderInstance* GetBasisCurvesCubicFallbackShader(const MColor& color) const; + const MHWRender::MSamplerState* GetSamplerState( const MHWRender::MSamplerStateDesc& desc) const; diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml new file mode 100644 index 0000000000..e5eda0ee7f --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml new file mode 100644 index 0000000000..ae612b7657 --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml new file mode 100644 index 0000000000..1ec72ce584 --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicFallbackShader.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicFallbackShader.xml new file mode 100644 index 0000000000..664dec486a --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicFallbackShader.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml new file mode 100644 index 0000000000..d980c58731 --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inputs, + uint primitiveID, + uint patchID) +{ + hullOutS output; + + // U0_1 being used as widths. + output.Pm = inputs[patchID].Pm; + output.Nm = inputs[patchID].Nm; + output.U0_1 = inputs[patchID].U0_1; + + return output; +} + +// line 185 ".../lib/usd/hdSt/resources/shaders/basisCurves.glslfx" + +// Use the length of the control points in screen space to determine how many +// times to subdivide the curve. +hullConstantsOutS BasisCurvesCubicHullConstants( + InputPatch inPatch, + OutputPatch outPatch, + uint primitiveID : SV_PrimitiveID) +{ + float2 v0 = projectToScreen(worldViewProj, inPatch[0].Pm, viewportPixelSize); + float2 v1 = projectToScreen(worldViewProj, inPatch[1].Pm, viewportPixelSize); + float2 v2 = projectToScreen(worldViewProj, inPatch[2].Pm, viewportPixelSize); + float2 v3 = projectToScreen(worldViewProj, inPatch[3].Pm, viewportPixelSize); + + float maxTess = GetMaxTess(); + + // Need to handle off screen + float dist = distance(v0, v1) + distance(v1, v2) + distance(v2, v3); + float level = clamp(dist / GetPixelToTessRatio(), 0, maxTess); + + hullConstantsOutS output; + + output.tessLevelOuter[0] = level; + output.tessLevelOuter[1] = 1; + output.tessLevelOuter[2] = level; + output.tessLevelOuter[3] = 1; + + output.tessLevelInner[0] = 1; + output.tessLevelInner[1] = level; + + return output; +} + ]]> + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_Cg.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_Cg.xml new file mode 100644 index 0000000000..ea2379f87d --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_Cg.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml new file mode 100644 index 0000000000..a075f8377f --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml new file mode 100644 index 0000000000..e2c7984c5a --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearFallbackShader.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearFallbackShader.xml new file mode 100644 index 0000000000..cab6c0b78c --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearFallbackShader.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml new file mode 100644 index 0000000000..a2d3db3b94 --- /dev/null +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inputs, + uint primitiveID, + uint patchID) +{ + hullOutS output; + + // U0_1 being used as widths. + output.Pm = inputs[patchID].Pm; + output.Nm = inputs[patchID].Nm; + output.U0_1 = inputs[patchID].U0_1; + + return output; +} + +// line 185 ".../lib/usd/hdSt/resources/shaders/basisCurves.glslfx" + +// Use the length of the control points in screen space to determine how many +// times to subdivide the curve. +hullConstantsOutS BasisCurvesLinearHullConstants( + InputPatch inPatch, + OutputPatch outPatch, + uint primitiveID : SV_PrimitiveID) +{ + hullConstantsOutS output; + + output.tessLevelOuter[0] = 1; + output.tessLevelOuter[1] = 1; + output.tessLevelOuter[2] = 1; + output.tessLevelOuter[3] = 1; + + output.tessLevelInner[0] = 1; + output.tessLevelInner[1] = 1; + + return output; +} + ]]> + + + + + + + diff --git a/lib/render/vp2ShaderFragments/shaderFragments.cpp b/lib/render/vp2ShaderFragments/shaderFragments.cpp index c704af4351..0a8f18bed4 100644 --- a/lib/render/vp2ShaderFragments/shaderFragments.cpp +++ b/lib/render/vp2ShaderFragments/shaderFragments.cpp @@ -32,6 +32,13 @@ PXR_NAMESPACE_OPEN_SCOPE TF_DEFINE_PRIVATE_TOKENS( _tokens, + (BasisCurvesCubicDomain) + (BasisCurvesCubicFallbackShader) + (BasisCurvesCubicHull) + (BasisCurvesLinearDomain) + (BasisCurvesLinearFallbackShader) + (BasisCurvesLinearHull) + (FallbackCPVShader) (FallbackShader) @@ -59,7 +66,15 @@ TF_DEFINE_PRIVATE_TOKENS( (UsdPreviewSurface) ); +static const TfTokenVector _LanguageSpecificFragmentNames = { + _tokens->BasisCurvesLinearDomain, + _tokens->BasisCurvesCubicDomain +}; + static const TfTokenVector _FragmentNames = { + _tokens->BasisCurvesLinearHull, + _tokens->BasisCurvesCubicHull, + _tokens->UsdUVTexture, _tokens->UsdPrimvarReader_float, @@ -83,6 +98,8 @@ static const TfTokenVector _FragmentNames = { }; static const TfTokenVector _FragmentGraphNames = { + _tokens->BasisCurvesCubicFallbackShader, + _tokens->BasisCurvesLinearFallbackShader, _tokens->FallbackCPVShader, _tokens->FallbackShader, _tokens->UsdPreviewSurface @@ -125,7 +142,41 @@ MStatus HdVP2ShaderFragments::registerFragments() return MS::kSuccess; } + std::string language; + + switch (theRenderer->drawAPI()) { + case MHWRender::kOpenGLCoreProfile: language = "GLSL"; break; + case MHWRender::kDirectX11: language = "HLSL"; break; + case MHWRender::kOpenGL: language = "Cg"; break; + default: MGlobal::displayError("Unknown draw API"); break; + } + // Register all fragments. + for (const TfToken& fragNameToken : _LanguageSpecificFragmentNames) { + const MString fragName(fragNameToken.GetText()); + + if (fragmentManager->hasFragment(fragName)) { + continue; + } + + const std::string fragXmlFile = + TfStringPrintf("%s_%s.xml", fragName.asChar(), language.c_str()); + const std::string fragXmlPath = _GetResourcePath(fragXmlFile); + + const MString addedName = + fragmentManager->addShadeFragmentFromFile( + fragXmlPath.c_str(), + false); + + if (addedName != fragName) { + MGlobal::displayError( + TfStringPrintf("Failed to register fragment '%s' from file: %s", + fragName.asChar(), + fragXmlPath.c_str()).c_str()); + return MS::kFailure; + } + } + for (const TfToken& fragNameToken : _FragmentNames) { const MString fragName(fragNameToken.GetText()); From e97f5776c3829a62bfd0ebf6aad4a8834a019d8d Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Fri, 31 Jan 2020 11:15:49 -0500 Subject: [PATCH 2/9] Curve refinement is not currently supported until MRenderItem::setPrimitive() is published. --- lib/render/vp2RenderDelegate/basisCurves.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp index a1eed09fa4..bbf87a28dc 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.cpp +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -35,11 +35,6 @@ #include #include -// Conditional compilation due to Maya API gap. -#if MAYA_API_VERSION >= 20210000 -#define MAYA_ALLOW_PRIMITIVE_TYPE_SWITCH -#endif - PXR_NAMESPACE_OPEN_SCOPE namespace { @@ -691,6 +686,12 @@ HdVP2BasisCurves::_UpdateDrawItem( const TfToken type = topology.GetCurveType(); const TfToken wrap = topology.GetCurveWrap(); +#if defined(MAYA_ALLOW_PRIMITIVE_TYPE_SWITCH) + const int refineLevel = _curvesSharedData._displayStyle.refineLevel; +#else + const int refineLevel = 0; +#endif + const MHWRender::MGeometry::DrawMode drawMode = renderItem->drawMode(); // The bounding box item uses a globally-shared geometry data therefore it @@ -701,8 +702,7 @@ HdVP2BasisCurves::_UpdateDrawItem( if (requiresIndexUpdate && (itemDirtyBits & HdChangeTracker::DirtyTopology)) { const bool forceLines = - (_curvesSharedData._displayStyle.refineLevel <= 0) || - (drawMode == MHWRender::MGeometry::kWireframe); + (refineLevel <= 0) || (drawMode == MHWRender::MGeometry::kWireframe); VtValue result; @@ -780,7 +780,7 @@ HdVP2BasisCurves::_UpdateDrawItem( } // Prepare widths buffer. - if ((_curvesSharedData._displayStyle.refineLevel > 0) && + if ((refineLevel > 0) && (itemDirtyBits & (HdChangeTracker::DirtyPrimvar | HdChangeTracker::DirtyDisplayStyle))) { VtFloatArray widths(1, 1.0f); @@ -883,7 +883,7 @@ HdVP2BasisCurves::_UpdateDrawItem( auto primitiveType = MHWRender::MGeometry::kLines; int primitiveStride = 0; - if (_curvesSharedData._displayStyle.refineLevel <= 0) { + if (refineLevel <= 0) { shader = _delegate->Get3dSolidShader(clr); } else if (type == HdTokens->linear) { @@ -1129,7 +1129,7 @@ HdVP2BasisCurves::_UpdateDrawItem( if (desc.geomStyle == HdBasisCurvesGeomStylePatch) { if (_selectionState != kUnselected) { - if (_curvesSharedData._displayStyle.refineLevel <= 0) { + if (refineLevel <= 0) { shader = _delegate->Get3dSolidShader(kSelectionHighlightColor); } else if (type == HdTokens->linear) { From 0e59271974b399b3ce103ef870021fdfd1ebe94a Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Fri, 31 Jan 2020 12:00:06 -0500 Subject: [PATCH 3/9] Fix compilation error in strict build mode. --- lib/render/vp2RenderDelegate/basisCurves.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp index bbf87a28dc..f762cb8694 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.cpp +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -679,10 +679,6 @@ HdVP2BasisCurves::_UpdateDrawItem( const auto& primvarSourceMap = _curvesSharedData._primvarSourceMap; const HdBasisCurvesTopology& topology = _curvesSharedData._topology; - const VtIntArray& curveVertexCounts = topology.GetCurveVertexCounts(); - const size_t numCurves = curveVertexCounts.size(); - const size_t numControlPoints = topology.CalculateNeededNumberOfControlPoints(); - const TfToken type = topology.GetCurveType(); const TfToken wrap = topology.GetCurveWrap(); From a801943cc4b0b8b5864e3e154d722a44cc92c974 Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Fri, 31 Jan 2020 16:22:41 -0500 Subject: [PATCH 4/9] Cleanup for shader fragment xml files. --- .../vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml | 5 ----- .../vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml | 5 ----- lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml | 9 --------- .../BasisCurvesLinearDomain_GLSL.xml | 5 ----- .../BasisCurvesLinearDomain_HLSL.xml | 5 ----- .../vp2ShaderFragments/BasisCurvesLinearHull.xml | 10 ---------- 6 files changed, 39 deletions(-) diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml index ae612b7657..706bfdf84f 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_GLSL.xml @@ -20,20 +20,15 @@ limitations under the License. - - - - - diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml index 1ec72ce584..9763f78d58 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_HLSL.xml @@ -20,20 +20,15 @@ limitations under the License. - - - - - diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml index d980c58731..250ec745c7 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicHull.xml @@ -18,11 +18,7 @@ limitations under the License. - - - - @@ -40,11 +36,6 @@ limitations under the License. - - - - - diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml index a075f8377f..1811070d9d 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_GLSL.xml @@ -20,20 +20,15 @@ limitations under the License. - - - - - diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml index e2c7984c5a..899c33205b 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearDomain_HLSL.xml @@ -20,20 +20,15 @@ limitations under the License. - - - - - diff --git a/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml b/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml index a2d3db3b94..b45974fe8f 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesLinearHull.xml @@ -18,11 +18,6 @@ limitations under the License. - - - - - @@ -39,11 +34,6 @@ limitations under the License. - - - - - From 1e1994b95c7f5d004702112a1a72375e65f73730 Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Fri, 31 Jan 2020 16:47:30 -0500 Subject: [PATCH 5/9] USD curves can provide snapping points. --- lib/render/vp2RenderDelegate/basisCurves.cpp | 28 ++++++++++++++++++++ lib/render/vp2RenderDelegate/basisCurves.h | 1 + 2 files changed, 29 insertions(+) diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp index f762cb8694..892850bf48 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.cpp +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -1489,6 +1489,9 @@ void HdVP2BasisCurves::_InitRepr(TfToken const &reprToken, HdDirtyBits *dirtyBit drawItem->AddUsage(HdVP2DrawItem::kSelectionHighlight); } break; + case HdBasisCurvesGeomStylePoints: + renderItem = _CreatePointsRenderItem(renderItemName); + break; default: TF_WARN("Unsupported geomStyle"); break; @@ -1667,4 +1670,29 @@ HdVP2BasisCurves::_CreatePatchRenderItem(const MString& name) const return renderItem; } +/*! \brief Create render item for points repr. +*/ +MHWRender::MRenderItem* +HdVP2BasisCurves::_CreatePointsRenderItem(const MString& name) const +{ + MHWRender::MRenderItem* const renderItem = MHWRender::MRenderItem::Create( + name, + MHWRender::MRenderItem::DecorationItem, + MHWRender::MGeometry::kPoints + ); + + renderItem->setDrawMode(MHWRender::MGeometry::kSelectionOnly); + renderItem->castsShadows(false); + renderItem->receivesShadows(false); + renderItem->setShader(_delegate->Get3dFatPointShader()); + + MSelectionMask selectionMask(MSelectionMask::kSelectPointsForGravity); + selectionMask.addMask(MSelectionMask::kSelectCurves); + renderItem->setSelectionMask(selectionMask); + + setWantConsolidation(*renderItem, true); + + return renderItem; +} + PXR_NAMESPACE_CLOSE_SCOPE diff --git a/lib/render/vp2RenderDelegate/basisCurves.h b/lib/render/vp2RenderDelegate/basisCurves.h index b9a9c99173..4c901fdc86 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.h +++ b/lib/render/vp2RenderDelegate/basisCurves.h @@ -122,6 +122,7 @@ class HdVP2BasisCurves final: public HdBasisCurves MHWRender::MRenderItem* _CreatePatchRenderItem(const MString& name) const; MHWRender::MRenderItem* _CreateWireRenderItem(const MString& name) const; MHWRender::MRenderItem* _CreateBBoxRenderItem(const MString& name) const; + MHWRender::MRenderItem* _CreatePointsRenderItem(const MString& name) const; enum DirtyBits : HdDirtyBits { DirtySelection = HdChangeTracker::CustomBitsBegin, From fb6054318efe4dba3c14aaeae699a8284243e995 Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Tue, 4 Feb 2020 18:38:21 -0500 Subject: [PATCH 6/9] Fix shader errors when assigning material to USD curves --- lib/CMakeLists.txt | 3 + lib/render/vp2RenderDelegate/basisCurves.cpp | 29 +++++---- lib/render/vp2RenderDelegate/material.cpp | 40 ++++++++++-- .../vp2ShaderFragments/NwFaceCameraIfNAN.xml | 64 +++++++++++++++++++ .../vp2ShaderFragments/UsdPreviewSurface.xml | 7 +- .../UsdPrimvarReader_color.xml | 63 ++++++++++++++++++ .../UsdPrimvarReader_vector.xml | 63 ++++++++++++++++++ .../vp2ShaderFragments/shaderFragments.cpp | 10 ++- 8 files changed, 256 insertions(+), 23 deletions(-) create mode 100644 lib/render/vp2ShaderFragments/NwFaceCameraIfNAN.xml create mode 100644 lib/render/vp2ShaderFragments/UsdPrimvarReader_color.xml create mode 100644 lib/render/vp2ShaderFragments/UsdPrimvarReader_vector.xml diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 81ce2e7be2..229b77281a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -197,10 +197,13 @@ list(APPEND mayaUsdShaderFragments_xmls render/vp2ShaderFragments/FallbackShader.xml render/vp2ShaderFragments/Float4ToFloat3.xml render/vp2ShaderFragments/Float4ToFloat4.xml + render/vp2ShaderFragments/NwFaceCameraIfNAN.xml + render/vp2ShaderFragments/UsdPrimvarReader_color.xml render/vp2ShaderFragments/UsdPrimvarReader_float.xml render/vp2ShaderFragments/UsdPrimvarReader_float2.xml render/vp2ShaderFragments/UsdPrimvarReader_float3.xml render/vp2ShaderFragments/UsdPrimvarReader_float4.xml + render/vp2ShaderFragments/UsdPrimvarReader_vector.xml render/vp2ShaderFragments/UsdUVTexture.xml # USD plug info render/vp2ShaderFragments/plugInfo.json diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp index 892850bf48..b7bcc99639 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.cpp +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -816,7 +816,8 @@ HdVP2BasisCurves::_UpdateDrawItem( } // Prepare color buffer. - if (itemDirtyBits & HdChangeTracker::DirtyMaterialId) { + if (itemDirtyBits & (HdChangeTracker::DirtyMaterialId | + DirtySelectionHighlight)) { const HdVP2Material* material = static_cast( renderIndex.GetSprim(HdPrimTypeTokens->material, GetMaterialId()) ); @@ -865,6 +866,19 @@ HdVP2BasisCurves::_UpdateDrawItem( const VtValue& value = itOpacity->second.data; if (value.IsHolding() && value.GetArraySize() > 0) { alphaArray = value.UncheckedGet(); + + // It is possible that all elements in the opacity array are 1. + // Due to the performance indication about transparency, we have to + // traverse the array and enable transparency only when needed. + if (!stateToCommit._isTransparent) { + const size_t numAlphas = alphaArray.size(); + for (size_t i = 0; i < numAlphas; i++) { + if (alphaArray[i] < 0.999f) { + stateToCommit._isTransparent = true; + break; + } + } + } } } @@ -974,19 +988,6 @@ HdVP2BasisCurves::_UpdateDrawItem( } } } - - // It is possible that all elements in the opacity array are 1. - // Due to the performance indication about transparency, we have to - // traverse the array and enable transparency only when needed. - if (!stateToCommit._isTransparent) { - const size_t numAlphas = alphaArray.size(); - for (size_t i = 0; i < numAlphas; i++) { - if (alphaArray[i] < 0.999f) { - stateToCommit._isTransparent = true; - break; - } - } - } } } diff --git a/lib/render/vp2RenderDelegate/material.cpp b/lib/render/vp2RenderDelegate/material.cpp index a08e56ae34..33b1e135e9 100644 --- a/lib/render/vp2RenderDelegate/material.cpp +++ b/lib/render/vp2RenderDelegate/material.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -80,6 +80,9 @@ TF_DEFINE_PRIVATE_TOKENS( (Float4ToFloatZ) (Float4ToFloatW) (Float4ToFloat3) + + (UsdPrimvarReader_color) + (UsdPrimvarReader_vector) ); //! Helper utility function to test whether a node is a UsdShade primvar reader. @@ -89,7 +92,8 @@ bool _IsUsdPrimvarReader(const HdMaterialNode& node) return (id == UsdImagingTokens->UsdPrimvarReader_float || id == UsdImagingTokens->UsdPrimvarReader_float2 || id == UsdImagingTokens->UsdPrimvarReader_float3 || - id == UsdImagingTokens->UsdPrimvarReader_float4); + id == UsdImagingTokens->UsdPrimvarReader_float4 || + id == _tokens->UsdPrimvarReader_vector); } //! Helper utility function to test whether a node is a UsdShade UV texture. @@ -148,8 +152,27 @@ void _ApplyVP2Fixes(HdMaterialNetwork& outNet, const HdMaterialNetwork& inNet) for (const HdMaterialNode &node : inNet.nodes) { + TfToken primvarToRead; + + const bool isUsdPrimvarReader = _IsUsdPrimvarReader(node); + if (isUsdPrimvarReader) { + auto it = node.parameters.find(_tokens->varname); + if (it != node.parameters.end()) { + primvarToRead = TfToken(TfStringify(it->second)); + } + } + outNet.nodes.push_back(node); + // If the primvar reader is reading color or opacity, change it to + // UsdPrimvarReader_color which can create COLOR stream requirement + // instead of generic TEXCOORD stream. + if (primvarToRead == HdTokens->displayColor || + primvarToRead == HdTokens->displayOpacity) { + auto& nodeToChange = outNet.nodes.back(); + nodeToChange.identifier = _tokens->UsdPrimvarReader_color; + } + // Copy outgoing connections and if needed add passthrough node/connection. for (const HdMaterialRelationship& rel : inNet.relationships) { if (rel.inputId != node.path) { @@ -172,6 +195,12 @@ void _ApplyVP2Fixes(HdMaterialNetwork& outNet, const HdMaterialNetwork& inNet) else if (rel.inputName == _tokens->a || rel.inputName == _tokens->w) { passThroughId = _tokens->Float4ToFloatW; } + else if (primvarToRead == HdTokens->displayColor) { + passThroughId = _tokens->Float4ToFloat3; + } + else if (primvarToRead == HdTokens->displayOpacity) { + passThroughId = _tokens->Float4ToFloatW; + } else { outNet.relationships.push_back(rel); continue; @@ -205,10 +234,9 @@ void _ApplyVP2Fixes(HdMaterialNetwork& outNet, const HdMaterialNetwork& inNet) // UsdImagingMaterialAdapter doesn't create primvar requirements as // expected. Workaround by manually looking up "varname" parameter. // https://groups.google.com/forum/#!msg/usd-interest/z-14AgJKOcU/1uJJ1thXBgAJ - else if (_IsUsdPrimvarReader(node)) { - auto it = node.parameters.find(_tokens->varname); - if (it != node.parameters.end()) { - outNet.primvars.push_back(TfToken(TfStringify(it->second))); + else if (isUsdPrimvarReader) { + if (!primvarToRead.IsEmpty()) { + outNet.primvars.push_back(primvarToRead); } } } diff --git a/lib/render/vp2ShaderFragments/NwFaceCameraIfNAN.xml b/lib/render/vp2ShaderFragments/NwFaceCameraIfNAN.xml new file mode 100644 index 0000000000..3eaf967ec3 --- /dev/null +++ b/lib/render/vp2ShaderFragments/NwFaceCameraIfNAN.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml b/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml index c03dfcde6a..be756e0f1a 100644 --- a/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml +++ b/lib/render/vp2ShaderFragments/UsdPreviewSurface.xml @@ -1,6 +1,8 @@ + @@ -49,6 +52,7 @@ limitations under the License. + @@ -91,9 +95,8 @@ limitations under the License. - + - diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_color.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_color.xml new file mode 100644 index 0000000000..6ada21f260 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_color.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/UsdPrimvarReader_vector.xml b/lib/render/vp2ShaderFragments/UsdPrimvarReader_vector.xml new file mode 100644 index 0000000000..74b77da207 --- /dev/null +++ b/lib/render/vp2ShaderFragments/UsdPrimvarReader_vector.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/render/vp2ShaderFragments/shaderFragments.cpp b/lib/render/vp2ShaderFragments/shaderFragments.cpp index 0a8f18bed4..8e74e71991 100644 --- a/lib/render/vp2ShaderFragments/shaderFragments.cpp +++ b/lib/render/vp2ShaderFragments/shaderFragments.cpp @@ -1,5 +1,5 @@ // -// Copyright 2019 Autodesk +// Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -49,6 +49,8 @@ TF_DEFINE_PRIVATE_TOKENS( (Float4ToFloat3) (Float4ToFloat4) + (NwFaceCameraIfNAN) + (lightingContributions) (scaledDiffusePassThrough) (scaledSpecularPassThrough) @@ -58,10 +60,12 @@ TF_DEFINE_PRIVATE_TOKENS( (UsdUVTexture) + (UsdPrimvarReader_color) (UsdPrimvarReader_float) (UsdPrimvarReader_float2) (UsdPrimvarReader_float3) (UsdPrimvarReader_float4) + (UsdPrimvarReader_vector) (UsdPreviewSurface) ); @@ -77,10 +81,12 @@ static const TfTokenVector _FragmentNames = { _tokens->UsdUVTexture, + _tokens->UsdPrimvarReader_color, _tokens->UsdPrimvarReader_float, _tokens->UsdPrimvarReader_float2, _tokens->UsdPrimvarReader_float3, _tokens->UsdPrimvarReader_float4, + _tokens->UsdPrimvarReader_vector, _tokens->Float4ToFloatX, _tokens->Float4ToFloatY, @@ -89,6 +95,8 @@ static const TfTokenVector _FragmentNames = { _tokens->Float4ToFloat3, _tokens->Float4ToFloat4, + _tokens->NwFaceCameraIfNAN, + _tokens->lightingContributions, _tokens->scaledDiffusePassThrough, _tokens->scaledSpecularPassThrough, From 4dd8081a75a2906ace77e578c26ceca6755fe409 Mon Sep 17 00:00:00 2001 From: Huidong Chen Date: Tue, 4 Feb 2020 19:48:46 -0500 Subject: [PATCH 7/9] Code review feedback --- lib/render/vp2RenderDelegate/basisCurves.cpp | 1 + .../vp2RenderDelegate/render_delegate.cpp | 29 +++++++++++++------ .../BasisCurvesCubicDomain_Cg.xml | 3 ++ .../BasisCurvesCubicDomain_GLSL.xml | 4 +++ .../BasisCurvesCubicDomain_HLSL.xml | 4 +++ .../BasisCurvesCubicFallbackShader.xml | 3 ++ .../BasisCurvesLinearDomain_Cg.xml | 3 ++ .../BasisCurvesLinearDomain_GLSL.xml | 4 +++ .../BasisCurvesLinearDomain_HLSL.xml | 4 +++ .../BasisCurvesLinearFallbackShader.xml | 3 ++ 10 files changed, 49 insertions(+), 9 deletions(-) diff --git a/lib/render/vp2RenderDelegate/basisCurves.cpp b/lib/render/vp2RenderDelegate/basisCurves.cpp index b7bcc99639..d96323ead8 100644 --- a/lib/render/vp2RenderDelegate/basisCurves.cpp +++ b/lib/render/vp2RenderDelegate/basisCurves.cpp @@ -1,4 +1,5 @@ // +// Copyright 2018 Pixar // Copyright 2020 Autodesk // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/lib/render/vp2RenderDelegate/render_delegate.cpp b/lib/render/vp2RenderDelegate/render_delegate.cpp index c5837806c0..9caaf91cf6 100644 --- a/lib/render/vp2RenderDelegate/render_delegate.cpp +++ b/lib/render/vp2RenderDelegate/render_delegate.cpp @@ -74,8 +74,17 @@ namespace const MString _pointSizeParameterName = "pointSize"; //!< Shader parameter name const MString _structOutputName = "outSurfaceFinal"; //!< Output struct name of the fallback shader - //! Name of the fallback shaders - const MString _fallbackShaderNames[3] = + //! Enum class for fallback shader types + enum class FallbackShaderType + { + Common = 0, + BasisCurvesLinear, + BasisCurvesCubic, + Count + }; + + //! Array of shader fragment names indexed by FallbackShaderType + const MString _fallbackShaderNames[FallbackShaderType::Count] = { "FallbackShader", "BasisCurvesLinearFallbackShader", @@ -220,12 +229,13 @@ namespace \return A new or existing copy of shader instance with given color */ - MHWRender::MShaderInstance* GetFallbackShader(const MColor& color, unsigned int index) + MHWRender::MShaderInstance* GetFallbackShader(const MColor& color, FallbackShaderType type) { - if (index >= sizeof(_fallbackShaders) / sizeof(_fallbackShaders[0])) { + if (type >= FallbackShaderType::Count) { return nullptr; } + const unsigned int index = static_cast(type); auto& shaderMap = _fallbackShaders[index]; // Look for it first with reader lock @@ -268,8 +278,9 @@ namespace private: bool _isInitialized { false }; //!< Whether the shader cache is initialized - MShaderMap _fallbackShaders[3]; //!< Shader registry used by fallback shaders - MShaderMap _3dSolidShaders; //!< Shader registry used by fallback shaders + //! Shader registry used by fallback shaders + MShaderMap _fallbackShaders[FallbackShaderType::Count]; + MShaderMap _3dSolidShaders; MHWRender::MShaderInstance* _fallbackCPVShader { nullptr }; //!< Fallback shader with CPV support MHWRender::MShaderInstance* _3dFatPointShader { nullptr }; //!< 3d shader for points @@ -683,7 +694,7 @@ MString HdVP2RenderDelegate::GetLocalNodeName(const MString& name) const { MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackShader( const MColor& color) const { - return sShaderCache.GetFallbackShader(color, 0); + return sShaderCache.GetFallbackShader(color, FallbackShaderType::Common); } /*! \brief Returns a fallback shader instance when no material is bound. @@ -698,7 +709,7 @@ MHWRender::MShaderInstance* HdVP2RenderDelegate::GetFallbackShader( MHWRender::MShaderInstance* HdVP2RenderDelegate::GetBasisCurvesLinearFallbackShader(const MColor& color) const { - return sShaderCache.GetFallbackShader(color, 1); + return sShaderCache.GetFallbackShader(color, FallbackShaderType::BasisCurvesLinear); } /*! \brief Returns a fallback shader instance when no material is bound. @@ -713,7 +724,7 @@ HdVP2RenderDelegate::GetBasisCurvesLinearFallbackShader(const MColor& color) con MHWRender::MShaderInstance* HdVP2RenderDelegate::GetBasisCurvesCubicFallbackShader(const MColor& color) const { - return sShaderCache.GetFallbackShader(color, 2); + return sShaderCache.GetFallbackShader(color, FallbackShaderType::BasisCurvesCubic); } /*! \brief Returns a fallback CPV shader instance when no material is bound. diff --git a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml index e5eda0ee7f..d906dc7300 100644 --- a/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml +++ b/lib/render/vp2ShaderFragments/BasisCurvesCubicDomain_Cg.xml @@ -1,10 +1,13 @@