Skip to content

Commit

Permalink
ToMayaMeshConverter : Reverts "ToMayaMeshConverter : No longer set no…
Browse files Browse the repository at this point in the history
…rmals"

Reverts changes to no longer set normals when reading from a Cortex
object to Maya mesh since by not reading the normals, we don't take
into account the difference between face and vertex normals meaning
Maya may not recompute the normals as expected. Also, SCCs
published from outside Maya are also likely to be read into Maya with
different than expected normals.
  • Loading branch information
chrisc-lee committed Aug 29, 2024
1 parent 897a4dd commit e1ee2c8
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 13 deletions.
1 change: 1 addition & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Fixes
- USDScene :
- Fixed round-tripping of colons in set names.
- Fixed `hash()` to consider animation on ModelAPI extents when hashing the bound.
- ToMayaMeshConverter : Reverted #1386 that no longer locked normals set on the Mesh from the scc to fix issues with Maya incorrectly recomputing normals as Vertex normals when they were originally computed as Face normals

10.5.9.1 (relative to 10.5.9.0)
========
Expand Down
77 changes: 73 additions & 4 deletions src/IECoreMaya/ToMayaMeshConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,6 @@ void ToMayaMeshConverter::addUVSet( MFnMesh &fnMesh, const MIntArray &polygonCou

bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to, IECore::ConstCompoundObjectPtr operands ) const
{
// Note: Normals are not set on the Mesh from the scc as by setting them
// explicitly we are implying they should be locked which is not
// supported, instead we rely on Maya computing the normals everytime

MStatus s;

IECoreScene::ConstMeshPrimitivePtr mesh = IECore::runTimeCast<const IECoreScene::MeshPrimitive>( from );
Expand Down Expand Up @@ -267,6 +263,79 @@ bool ToMayaMeshConverter::doConversion( IECore::ConstObjectPtr from, MObject &to
return false;
}

it = mesh->variables.find("N");
if ( it != mesh->variables.end() )
{
if (it->second.interpolation == IECoreScene::PrimitiveVariable::FaceVarying )
{
/// \todo Employ some M*Array converters to simplify this
MVectorArray vertexNormalsArray;
IECore::ConstV3fVectorDataPtr n = IECore::runTimeCast<const IECore::V3fVectorData>(it->second.data);
if (n)
{
IECoreScene::PrimitiveVariable::IndexedView<Imath::V3f> normalView = IECoreScene::PrimitiveVariable::IndexedView<Imath::V3f>( it->second );
vertexNormalsArray.setLength( normalView.size() );

size_t i = 0;
for(const auto& normal : normalView)
{
vertexNormalsArray[i++] = IECore::convert<MVector, Imath::V3f>( normal );
}
}
else
{
IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast<const IECore::V3dVectorData>(it->second.data);
if (n)
{
IECoreScene::PrimitiveVariable::IndexedView<Imath::V3d> normalView = IECoreScene::PrimitiveVariable::IndexedView<Imath::V3d>( it->second );
vertexNormalsArray.setLength( normalView.size() );

size_t i = 0;
for(const auto& normal : normalView)
{
vertexNormalsArray[i++] = IECore::convert<MVector, Imath::V3d>( normal );
}
}
else
{
IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", boost::format( "PrimitiveVariable \"N\" has unsupported type \"%s\"." ) % it->second.data->typeName() );
}
}

if ( vertexNormalsArray.length() )
{
MStatus status;
MItMeshPolygon itPolygon( mObj, &status );
if( status != MS::kSuccess )
{
IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Failed to create mesh iterator" );
}

unsigned v = 0;
MIntArray vertexIds;
MIntArray faceIds;

for ( ; !itPolygon.isDone(); itPolygon.next() )
{
for ( v=0; v < itPolygon.polygonVertexCount(); ++v )
{
faceIds.append( itPolygon.index() );
vertexIds.append( itPolygon.vertexIndex( v ) );
}
}

if( !fnMesh.setFaceVertexNormals( vertexNormalsArray, faceIds, vertexIds ) )
{
IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "Setting normals failed" );
}
}
}
else
{
IECore::msg( IECore::Msg::Warning, "ToMayaMeshConverter::doConversion", "PrimitiveVariable \"N\" has unsupported interpolation (expected FaceVarying)." );
}
}

/// Add UV sets
for ( it = mesh->variables.begin(); it != mesh->variables.end(); ++it )
{
Expand Down
7 changes: 1 addition & 6 deletions test/IECoreMaya/ParameterisedHolder.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ def testMeshParameterIOProblem( self ) :
op = fnOP.getOp()

mesh = IECoreScene.MeshPrimitive.createBox( imath.Box3f( imath.V3f( -2, -2, -2 ), imath.V3f( 2, 3, 4 ) ) )
mesh[ "N" ] = IECoreScene.PrimitiveVariable( mesh[ "N" ].interpolation, mesh[ "N" ].expandedData() )
op.parameters()[ "input" ].setValue( mesh )
fnOP.setNodeValues()

Expand All @@ -300,13 +301,7 @@ def testMeshParameterIOProblem( self ) :
op = fnOP.getOp()

mesh2 = op.parameters()["input"].getValue()

self.assertTrue( mesh2.arePrimitiveVariablesValid() )
# The ToMayaMeshConverter relies on Maya to calculate the normals
# whereas createBox uses indexed normals so we cannot include them
# in the comparison otherwise they will never be the same
del mesh[ "N" ]
del mesh2[ "N" ]
self.assertEqual( mesh2, mesh )

def testOpHolder( self ) :
Expand Down
3 changes: 0 additions & 3 deletions test/IECoreMaya/ToMayaMeshConverterTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,6 @@ def testNormals( self ) :
self.assertAlmostEqual( origNormal[j], normal3f[j], 6 )
self.assertAlmostEqual( origNormal[j], normal3d[j], 6 )

# normals should always be unlocked when reading from scc
self.assertFalse( any( maya.cmds.polyNormalPerVertex( newSphere+".vtx[*]", query=True, allLocked=True ) ) )

def testSetMeshInterpolation( self ) :

sphere = maya.cmds.polySphere( subdivisionsX=10, subdivisionsY=5, constructionHistory=False )
Expand Down

0 comments on commit e1ee2c8

Please sign in to comment.