#include <numeric>
#include "hdPrman/mesh.h"
#include "hdPrman/context.h"
#include "hdPrman/coordSys.h"
#include "hdPrman/instancer.h"
#include "hdPrman/material.h"
#include "hdPrman/renderParam.h"
#include "hdPrman/renderPass.h"
#include "hdPrman/rixStrings.h"
#include "pxr/base/gf/matrix4d.h"
#include "pxr/base/gf/matrix4f.h"
#include "pxr/base/gf/vec2f.h"
#include "pxr/base/gf/vec3f.h"
#include "pxr/base/gf/vec4f.h"
#include "pxr/imaging/hd/coordSys.h"
#include "pxr/imaging/hd/meshTopology.h"
#include "pxr/imaging/hd/meshUtil.h"
#include "pxr/imaging/pxOsd/subdivTags.h"
#include "pxr/imaging/pxOsd/tokens.h"
#include "pxr/usd/usdRi/rmanUtilities.h"
#include "Riley.h"
#include "RtParamList.h"
#include "RixShadingUtils.h"
#include "RixPredefinedStrings.hpp"
#include <algorithm>
PXR_NAMESPACE_OPEN_SCOPE
HdPrman_Mesh::HdPrman_Mesh(SdfPath const& id,
SdfPath const& instancerId)
: BASE(id, instancerId)
{
}
HdDirtyBits
HdPrman_Mesh::GetInitialDirtyBitsMask() const
{
int mask = HdChangeTracker::Clean
| HdChangeTracker::DirtyPoints
| HdChangeTracker::DirtyTopology
| HdChangeTracker::DirtyTransform
| HdChangeTracker::DirtyVisibility
| HdChangeTracker::DirtyCullStyle
| HdChangeTracker::DirtyDoubleSided
| HdChangeTracker::DirtySubdivTags
| HdChangeTracker::DirtyPrimvar
| HdChangeTracker::DirtyNormals
| HdChangeTracker::DirtyMaterialId
| HdChangeTracker::DirtyInstancer
;
return (HdDirtyBits)mask;
}
RtParamList
HdPrman_Mesh::_ConvertGeometry(HdPrman_Context *context,
HdSceneDelegate *sceneDelegate,
const SdfPath &id,
RtUString *primType,
HdGeomSubsets *geomSubsets)
{
const HdMeshTopology topology = GetMeshTopology(sceneDelegate);
const size_t npoints = topology.GetNumPoints();
const VtIntArray verts = topology.GetFaceVertexIndices();
const VtIntArray nverts = topology.GetFaceVertexCounts();
*geomSubsets = topology.GetGeomSubsets();
if (!geomSubsets->empty()) {
const int numFaces = topology.GetNumFaces();
std::vector<bool> faceMask(numFaces, true);
size_t numUnusedFaces = faceMask.size();
for (HdGeomSubset const& subset: *geomSubsets) {
for (int index: subset.indices) {
if (TF_VERIFY(index < numFaces) && faceMask[index]) {
faceMask[index] = false;
numUnusedFaces--;
}
}
}
if (numUnusedFaces) {
geomSubsets->push_back(HdGeomSubset());
HdGeomSubset &unusedSubset = geomSubsets->back();
unusedSubset.type = HdGeomSubset::TypeFaceSet;
unusedSubset.id = id;
unusedSubset.materialId = SdfPath();
unusedSubset.indices.resize(numUnusedFaces);
size_t count = 0;
for (size_t i=0;
i < faceMask.size() && count < numUnusedFaces; ++i) {
if (faceMask[i]) {
unusedSubset.indices[count] = i;
count++;
}
}
}
}
RtParamList primvars(
nverts.size(),
npoints,
npoints,
verts.size() );
HdTimeSampleArray<VtVec3fArray, HDPRMAN_MAX_TIME_SAMPLES> points;
{
HdTimeSampleArray<VtValue, HDPRMAN_MAX_TIME_SAMPLES> boxedPoints;
sceneDelegate->SamplePrimvar(id, HdTokens->points, &boxedPoints);
points.UnboxFrom(boxedPoints);
}
primvars.SetTimeSamples(points.count, &points.times[0]);
for (size_t i=0; i < points.count; ++i) {
if (points.values[i].size() == npoints) {
primvars.SetPointDetail(
RixStr.k_P,
(RtPoint3*) points.values[i].cdata(),
RtDetailType::k_vertex,
i);
} else {
TF_WARN("<%s> primvar 'points' size (%zu) did not match "
"expected (%zu)",
id.GetText(),
points.values[i].size(),
npoints);
}
}
primvars.SetIntegerDetail(RixStr.k_Ri_nvertices, nverts.cdata(),
RtDetailType::k_uniform);
primvars.SetIntegerDetail(RixStr.k_Ri_vertices, verts.cdata(),
RtDetailType::k_facevarying);
if (topology.GetScheme() == PxOsdOpenSubdivTokens->catmullClark) {
*primType = RixStr.k_Ri_SubdivisionMesh;
primvars.SetString(RixStr.k_Ri_scheme, RixStr.k_catmullclark);
} else if (topology.GetScheme() == PxOsdOpenSubdivTokens->loop) {
*primType = RixStr.k_Ri_SubdivisionMesh;
primvars.SetString(RixStr.k_Ri_scheme, RixStr.k_loop);
} else if (topology.GetScheme() == PxOsdOpenSubdivTokens->bilinear) {
*primType = RixStr.k_Ri_SubdivisionMesh;
primvars.SetString(RixStr.k_Ri_scheme, RixStr.k_bilinear);
} else { *primType = RixStr.k_Ri_PolygonMesh;
}
VtIntArray holeIndices = topology.GetHoleIndices();
if (*primType == RixStr.k_Ri_PolygonMesh &&
!holeIndices.empty()) {
*primType = RixStr.k_Ri_SubdivisionMesh;
primvars.SetString(RixStr.k_Ri_scheme, RixStr.k_bilinear);
}
if (IsDoubleSided(sceneDelegate)) {
primvars.SetInteger(RixStr.k_Ri_Sides, 2);
}
if (topology.GetOrientation() == PxOsdOpenSubdivTokens->leftHanded) {
primvars.SetString(RixStr.k_Ri_Orientation, RixStr.k_rh);
} else {
primvars.SetString(RixStr.k_Ri_Orientation, RixStr.k_lh);
}
if (*primType == RixStr.k_Ri_SubdivisionMesh) {
std::vector<RtUString> tagNames;
std::vector<RtInt> tagArgCounts;
std::vector<RtInt> tagIntArgs;
std::vector<RtFloat> tagFloatArgs;
std::vector<RtToken> tagStringArgs;
if (!holeIndices.empty()) {
tagNames.push_back(RixStr.k_hole);
tagArgCounts.push_back(holeIndices.size()); tagArgCounts.push_back(0); tagArgCounts.push_back(0); tagIntArgs.insert(tagIntArgs.end(),
holeIndices.begin(), holeIndices.end());
}
PxOsdSubdivTags osdTags = GetSubdivTags(sceneDelegate);
VtIntArray creaseLengths = osdTags.GetCreaseLengths();
VtIntArray creaseIndices = osdTags.GetCreaseIndices();
VtFloatArray creaseWeights = osdTags.GetCreaseWeights();
if (!creaseIndices.empty()) {
for (int creaseLength: creaseLengths) {
tagNames.push_back(RixStr.k_crease);
tagArgCounts.push_back(creaseLength); tagArgCounts.push_back(1); tagArgCounts.push_back(0); }
tagIntArgs.insert(tagIntArgs.end(),
creaseIndices.begin(), creaseIndices.end());
tagFloatArgs.insert(tagFloatArgs.end(),
creaseWeights.begin(), creaseWeights.end());
}
VtIntArray cornerIndices = osdTags.GetCornerIndices();
VtFloatArray cornerWeights = osdTags.GetCornerWeights();
if (cornerIndices.size()) {
tagNames.push_back(RixStr.k_corner);
tagArgCounts.push_back(cornerIndices.size()); tagArgCounts.push_back(cornerWeights.size()); tagArgCounts.push_back(0); tagIntArgs.insert(tagIntArgs.end(),
cornerIndices.begin(), cornerIndices.end());
tagFloatArgs.insert(tagFloatArgs.end(),
cornerWeights.begin(), cornerWeights.end());
}
TfToken vInterp = osdTags.GetVertexInterpolationRule();
if (vInterp.IsEmpty()) {
vInterp = PxOsdOpenSubdivTokens->edgeAndCorner;
}
if (UsdRiConvertToRManInterpolateBoundary(vInterp) != 0) {
tagNames.push_back(RixStr.k_interpolateboundary);
tagArgCounts.push_back(0); tagArgCounts.push_back(0); tagArgCounts.push_back(0); }
TfToken fvInterp = osdTags.GetFaceVaryingInterpolationRule();
if (fvInterp.IsEmpty()) {
fvInterp = PxOsdOpenSubdivTokens->cornersPlus1;
}
tagNames.push_back(RixStr.k_facevaryinginterpolateboundary);
tagArgCounts.push_back(1); tagArgCounts.push_back(0); tagArgCounts.push_back(0); tagIntArgs.push_back(
UsdRiConvertToRManFaceVaryingLinearInterpolation(fvInterp));
TfToken triSubdivRule = osdTags.GetTriangleSubdivision();
if (triSubdivRule == PxOsdOpenSubdivTokens->smooth) {
tagNames.push_back(RixStr.k_smoothtriangles);
tagArgCounts.push_back(1); tagArgCounts.push_back(0); tagArgCounts.push_back(0); tagIntArgs.push_back(
UsdRiConvertToRManTriangleSubdivisionRule(triSubdivRule));
}
primvars.SetStringArray(RixStr.k_Ri_subdivtags,
&tagNames[0], tagNames.size());
primvars.SetIntegerArray(RixStr.k_Ri_subdivtagnargs,
&tagArgCounts[0], tagArgCounts.size());
primvars.SetFloatArray(RixStr.k_Ri_subdivtagfloatargs,
&tagFloatArgs[0], tagFloatArgs.size());
primvars.SetIntegerArray(RixStr.k_Ri_subdivtagintargs,
&tagIntArgs[0], tagIntArgs.size());
}
std::vector<int32_t> elementId(nverts.size());
std::iota(elementId.begin(), elementId.end(), 0);
primvars.SetIntegerDetail(RixStr.k_faceindex, elementId.data(),
RtDetailType::k_uniform);
HdPrman_ConvertPrimvars(sceneDelegate, id, primvars, nverts.size(),
npoints, npoints, verts.size());
return primvars;
}
PXR_NAMESPACE_CLOSE_SCOPE