diff --git a/.gitignore b/.gitignore index 3fd5a4af2b..554f52231f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ *.lib *.ilk *.exp -.sconsign.dblite +.sconsign*.dblite .sconf_temp .cproject .project diff --git a/Changes b/Changes index d0a2c115d5..8be06eb1af 100644 --- a/Changes +++ b/Changes @@ -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) ======== diff --git a/src/IECoreMaya/ToMayaMeshConverter.cpp b/src/IECoreMaya/ToMayaMeshConverter.cpp index cf31c75187..39fb938e4c 100644 --- a/src/IECoreMaya/ToMayaMeshConverter.cpp +++ b/src/IECoreMaya/ToMayaMeshConverter.cpp @@ -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( from ); @@ -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(it->second.data); + if (n) + { + IECoreScene::PrimitiveVariable::IndexedView normalView = IECoreScene::PrimitiveVariable::IndexedView( it->second ); + vertexNormalsArray.setLength( normalView.size() ); + + size_t i = 0; + for(const auto& normal : normalView) + { + vertexNormalsArray[i++] = IECore::convert( normal ); + } + } + else + { + IECore::ConstV3dVectorDataPtr n = IECore::runTimeCast(it->second.data); + if (n) + { + IECoreScene::PrimitiveVariable::IndexedView normalView = IECoreScene::PrimitiveVariable::IndexedView( it->second ); + vertexNormalsArray.setLength( normalView.size() ); + + size_t i = 0; + for(const auto& normal : normalView) + { + vertexNormalsArray[i++] = IECore::convert( 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 ) { diff --git a/test/IECoreMaya/ParameterisedHolder.py b/test/IECoreMaya/ParameterisedHolder.py index 7fd5b4066e..c40c4579b8 100644 --- a/test/IECoreMaya/ParameterisedHolder.py +++ b/test/IECoreMaya/ParameterisedHolder.py @@ -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() @@ -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 ) : diff --git a/test/IECoreMaya/ToMayaMeshConverterTest.py b/test/IECoreMaya/ToMayaMeshConverterTest.py index cfb813b217..245b1f189c 100644 --- a/test/IECoreMaya/ToMayaMeshConverterTest.py +++ b/test/IECoreMaya/ToMayaMeshConverterTest.py @@ -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 )