Skip to content

Commit

Permalink
HYDRA-955 : Pass normals and tangents to Hydra from render item and m…
Browse files Browse the repository at this point in the history
…esh adapters (#116)

* HYDRA-955 : Pass normals and tangents to Hydra from render item and mesh adapters.

* HYDRA-955 : Standardize the methods GetPoints, GetNormals, getUVs, GetTangents

* Various cleanup.

* Add a unit test to check that passing normals works fine

* Update MaterialX test result with normals.

* Fix Linux compile error.

* fix the normal update issue

---------

Co-authored-by: Keli Li <[email protected]>
  • Loading branch information
lanierd-adsk and lilike-adsk authored Apr 19, 2024
1 parent c0e1358 commit 9954a48
Show file tree
Hide file tree
Showing 12 changed files with 2,067 additions and 114 deletions.
9 changes: 8 additions & 1 deletion lib/mayaHydra/hydraExtensions/adapters/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,14 @@ class MayaHydraAdapter
MAYAHYDRALIB_API
virtual HdCullStyle GetCullStyle() const { return HdCullStyleNothing; }
MAYAHYDRALIB_API
virtual HdDisplayStyle GetDisplayStyle() { return { 0, false, false }; }
virtual HdDisplayStyle GetDisplayStyle() {
constexpr int refineLevel = 0;
constexpr bool flatShading = false;
constexpr bool displacement = false;
constexpr bool occludedSelectionShowsThrough = false;
constexpr bool pointsShadingEnabled = false;
constexpr bool materialIsFinal = false;
return HdDisplayStyle(refineLevel, flatShading, displacement, occludedSelectionShowsThrough, pointsShadingEnabled, materialIsFinal); }
MAYAHYDRALIB_API
virtual GfBBox3d GetBoundingBox() const { return GfBBox3d(); }
MAYAHYDRALIB_API
Expand Down
155 changes: 119 additions & 36 deletions lib/mayaHydra/hydraExtensions/adapters/meshAdapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ namespace {
const std::pair<MObject&, HdDirtyBits> _dirtyBits[] {
{ MayaAttrs::mesh::pnts,
// This is useful when the user edits the mesh.
HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent
HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent | HdChangeTracker::DirtyNormals
| HdChangeTracker::DirtySubdivTags },
{ MayaAttrs::mesh::inMesh,
// We are tracking topology changes and uv changes separately
HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent
HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyExtent | HdChangeTracker::DirtyNormals
| HdChangeTracker::DirtySubdivTags },
{ MayaAttrs::mesh::worldMatrix, HdChangeTracker::DirtyTransform },
{ MayaAttrs::mesh::doubleSided, HdChangeTracker::DirtyDoubleSided },
Expand Down Expand Up @@ -160,23 +160,64 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
if (ARCH_UNLIKELY(!status)) {
return {};
}

//Uvs are face varying
VtArray<GfVec2f> uvs;
uvs.reserve(static_cast<size_t>(mesh.numFaceVertices()));
const size_t numFacesVertices = mesh.numFaceVertices();
uvs.resize(numFacesVertices);
float2* uvsPointer = (float2*)uvs.cdata();
size_t numUVsFloat2 = 0;
for (MItMeshPolygon pit(GetDagPath()); !pit.isDone(); pit.next()) {
const auto vertexCount = pit.polygonVertexCount();
for (auto i = decltype(vertexCount) { 0 }; i < vertexCount; ++i) {
float2 uv = { 0.0f, 0.0f };
pit.getUV(i, uv);
uvs.push_back(GfVec2f(uv[0], uv[1]));
pit.getUV(i, *uvsPointer);
++uvsPointer;
++numUVsFloat2;
}
}

if (numUVsFloat2 != numFacesVertices){
TF_CODING_ERROR("Number of UVs does not match number of face vertices" );
}

return VtValue(uvs);
}

VtValue GetPoints(const MFnMesh& mesh)
VtValue GetTangents()
{
MStatus status;
MStatus status;
MFnMesh mesh(GetDagPath(), &status);
if (ARCH_UNLIKELY(!status)) {
return {};
}

//Tangents are face varying
const size_t numFacesVertices = mesh.numFaceVertices();
MFloatVectorArray mayaTangents;
mesh.getTangents(mayaTangents);
const size_t tangentsCount = mayaTangents.length();
if (0 == tangentsCount){
return {};
}

if (tangentsCount != numFacesVertices){
TF_CODING_ERROR("Number of tangents does not match number of face vertices" );
}

const auto* tangentsArray = reinterpret_cast<const GfVec2f*>(&mayaTangents[0]);
VtVec2fArray ret;
ret.assign(tangentsArray, tangentsArray + numFacesVertices);
return VtValue(ret);
}

VtValue GetPoints()
{
MStatus status;
MFnMesh mesh(GetDagPath(), &status);
if (ARCH_UNLIKELY(!status)) {
return {};
}

const auto* rawPoints = reinterpret_cast<const GfVec3f*>(mesh.getRawPoints(&status));
if (ARCH_UNLIKELY(!status)) {
return {};
Expand All @@ -186,6 +227,24 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
return VtValue(ret);
}

VtValue GetNormals()
{
MStatus status;
MFnMesh mesh(GetDagPath(), &status);
if (ARCH_UNLIKELY(!status)) {
return {};
}

//Normals are per vertex
MFloatVectorArray normals;
constexpr bool angleWeighted = false;
mesh.getVertexNormals(angleWeighted, normals);
const auto* rawNormals = reinterpret_cast<const GfVec3f*>(&normals[0]);
VtVec3fArray ret;
ret.assign(rawNormals, rawNormals + mesh.numVertices());
return VtValue(ret);
}

VtValue Get(const TfToken& key) override
{
TF_DEBUG(MAYAHYDRALIB_ADAPTER_GET)
Expand All @@ -195,15 +254,21 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
GetDagPath().partialPathName().asChar());

if (key == HdTokens->points) {
MStatus status;
MFnMesh mesh(GetDagPath(), &status);
if (ARCH_UNLIKELY(!status)) {
return {};
}
return GetPoints(mesh);
} else if (key == MayaHydraAdapterTokens->st) {
return GetPoints();
}

if (key == HdTokens->normals) {
return GetNormals();
}

if (key == MayaHydraAdapterTokens->tangents) {
return GetTangents();
}

if (key == MayaHydraAdapterTokens->st) {
return GetUVs();
}

return {};
}

Expand All @@ -215,18 +280,27 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
}

if (key == HdTokens->points) {
MStatus status;
MFnMesh mesh(GetDagPath(), &status);
if (ARCH_UNLIKELY(!status)) {
return 0;
}
return GetMayaHydraSceneIndex()->SampleValues(
maxSampleCount, times, samples, [&]() -> VtValue { return GetPoints(mesh); });
} else if (key == MayaHydraAdapterTokens->st) {
maxSampleCount, times, samples, [&]() -> VtValue { return GetPoints(); });
}

if (key == HdTokens->normals) {
return GetMayaHydraSceneIndex()->SampleValues(
maxSampleCount, times, samples, [&]() -> VtValue { return GetNormals(); });
}

if (key == MayaHydraAdapterTokens->tangents) {
times[0] = 0.0f;
samples[0] = GetTangents();
return 1;
}

if (key == MayaHydraAdapterTokens->st) {
times[0] = 0.0f;
samples[0] = GetUVs();
return 1;
}

return 0;
}

Expand All @@ -246,11 +320,17 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
}
}

return HdMeshTopology(
static const bool passNormalsToHydra = MayaHydraSceneIndex::passNormalsToHydra();
return (passNormalsToHydra) ?
HdMeshTopology(
PxOsdOpenSubdivTokens->none,//For the OGS normals vertex buffer to be used, we need to use PxOsdOpenSubdivTokens->none
UsdGeomTokens->rightHanded,
faceVertexCounts,
faceVertexIndices) :
HdMeshTopology(
(GetMayaHydraSceneIndex()->GetParams().displaySmoothMeshes || GetDisplayStyle().refineLevel > 0)
? PxOsdOpenSubdivTokens->catmullClark
: PxOsdOpenSubdivTokens->none,

UsdGeomTokens->rightHanded,
faceVertexCounts,
faceVertexIndices);
Expand Down Expand Up @@ -339,20 +419,23 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
HdPrimvarDescriptorVector GetPrimvarDescriptors(HdInterpolation interpolation) override
{
if (interpolation == HdInterpolationVertex) {
HdPrimvarDescriptor desc;
desc.name = UsdGeomTokens->points;
desc.interpolation = interpolation;
desc.role = HdPrimvarRoleTokens->point;
return { desc };
static const bool passNormalsToHydra = MayaHydraSceneIndex::passNormalsToHydra();
return passNormalsToHydra ?
HdPrimvarDescriptorVector{
{UsdGeomTokens->points, interpolation, HdPrimvarRoleTokens->point},//Vertices
{UsdGeomTokens->normals, interpolation, HdPrimvarRoleTokens->normal}//Normals
} :
HdPrimvarDescriptorVector{
{UsdGeomTokens->points, interpolation, HdPrimvarRoleTokens->point}//Vertices only
};
} else if (interpolation == HdInterpolationFaceVarying) {
// UVs are face varying in maya.
// UVs and tangents are face varying in maya.
MFnMesh mesh(GetDagPath());
if (mesh.numUVs() > 0) {
HdPrimvarDescriptor desc;
desc.name = MayaHydraAdapterTokens->st;
desc.interpolation = interpolation;
desc.role = HdPrimvarRoleTokens->textureCoordinate;
return { desc };
return HdPrimvarDescriptorVector{
{MayaHydraAdapterTokens->st, interpolation, HdPrimvarRoleTokens->textureCoordinate},//uvs
{MayaHydraAdapterTokens->tangents, interpolation, HdPrimvarRoleTokens->textureCoordinate},//tangents
};
}
}
return {};
Expand Down Expand Up @@ -422,7 +505,7 @@ class MayaHydraMeshAdapter : public MayaHydraShapeAdapter
auto* adapter = reinterpret_cast<MayaHydraMeshAdapter*>(clientData);
adapter->MarkDirty(
HdChangeTracker::DirtyTopology | HdChangeTracker::DirtyPrimvar
| HdChangeTracker::DirtyPoints);
| HdChangeTracker::DirtyPoints | HdChangeTracker::DirtyNormals);
}

static void ComponentIdChanged(MUintArray componentIds[], unsigned int count, void* clientData)
Expand Down
Loading

0 comments on commit 9954a48

Please sign in to comment.