Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[usdMaya] Adding an attribute converter for UsdGeom purpose. #215

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions third_party/maya/lib/usdMaya/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pxr_shared_library(${PXR_PACKAGE}
translatorXformable_decompose.cpp
usdReadJob_ImportWithProxies.cpp
UsdMetadataAttributeConverters.cpp
UsdGeomAttributeConverters.cpp

PYMODULE_CPPFILES
module.cpp
Expand Down Expand Up @@ -179,6 +180,7 @@ pxr_test_scripts(
testenv/testUsdMayaReferenceAssemblyEdits.py
testenv/testUsdMayaUserExportedAttributes.py
testenv/testUsdMayaXformStack.py
testenv/testUsdGeomAttributeConverters.py
testenv/testUsdMetadataAttributeConverters.py
testenv/testUsdReferenceAssemblyChangeRepresentations.py
testenv/testUsdReferenceAssemblySelection.py
Expand Down Expand Up @@ -637,6 +639,19 @@ pxr_register_test(testUsdMayaUserExportedAttributes
MAYA_DISABLE_CIP=1
)

pxr_install_test_dir(
SRC testenv/UsdGeomAttributeConvertersTest
DEST testUsdGeomAttributeConverters
)
pxr_register_test(testUsdGeomAttributeConverters
COMMAND "${MAYA_BASE_DIR}/bin/mayapy ${CMAKE_INSTALL_PREFIX}/tests/testUsdGeomAttributeConverters"
TESTENV testUsdGeomAttributeConverters
ENV
MAYA_PLUG_IN_PATH=${CMAKE_INSTALL_PREFIX}/third_party/maya/plugin
MAYA_SCRIPT_PATH=${CMAKE_INSTALL_PREFIX}/third_party/maya/share/usd/plugins/usdMaya/resources
MAYA_DISABLE_CIP=1
)

pxr_install_test_dir(
SRC testenv/UsdMetadataAttributeConvertersTest
DEST testUsdMetadataAttributeConverters
Expand Down
84 changes: 84 additions & 0 deletions third_party/maya/lib/usdMaya/UsdGeomAttributeConverters.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//
// Copyright 2018 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//

/// \file UsdGeomAttributeConverters.cpp
/// This file registers converters for storing USDGeom-specific metadata, such
/// as purpose, in extra "USDGeom_" attributes on Maya nodes.

#include "pxr/pxr.h"
#include "usdMaya/AttributeConverter.h"
#include "usdMaya/AttributeConverterRegistry.h"
#include "usdMaya/util.h"

#include "pxr/base/tf/registryManager.h"
#include "pxr/usd/usd/prim.h"
#include "pxr/usd/usdGeom/imageable.h"

PXR_NAMESPACE_OPEN_SCOPE

TF_DEFINE_PRIVATE_TOKENS(
_tokens,
(USD_purpose)
);

// USD_purpose <-> UsdGeomImageable.GetPurposeAttr()
TF_REGISTRY_FUNCTION(AttributeConverterRegistry) {
FunctionalAttributeConverter* converter = new FunctionalAttributeConverter(
[](const MFnDependencyNode& srcNode, UsdPrim& destPrim,
const UsdTimeCode) {
if (!destPrim.IsA<UsdGeomImageable>()) { return true; }
MString purpose;
if (PxrUsdMayaUtil::getPlugValue(srcNode,
_tokens->USD_purpose.GetText(), &purpose)) {
UsdGeomImageable imageable(destPrim);
if (imageable) {
TfToken purposeToken(purpose.asChar());
imageable.GetPurposeAttr().Set(purposeToken);
}
}
return true;
},
[](const UsdPrim& srcPrim, MFnDependencyNode& destNode,
const UsdTimeCode) {
if (!srcPrim.IsA<UsdGeomImageable>()) { return true; }
UsdGeomImageable imageable(srcPrim);
if (!imageable) { return true; }
const auto purposeAttr = imageable.GetPurposeAttr();
if (!purposeAttr.HasAuthoredValueOpinion()) { return true; }
TfToken purpose;
if (purposeAttr.Get(&purpose)) {
PxrUsdMayaUtil::createStringAttribute(destNode,
_tokens->USD_purpose.GetText());
MString purposeString(purpose.GetText());
PxrUsdMayaUtil::setPlugValue(destNode,
_tokens->USD_purpose.GetText(), purposeString);
}
return true;
}
);
AttributeConverterRegistry::Register(converter);
}

PXR_NAMESPACE_CLOSE_SCOPE

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#usda 1.0
(
defaultPrim = "World"
endTimeCode = 1
startTimeCode = 1
upAxis = "Z"
)

def Xform "World" (
kind = "component"
)
{
def Mesh "pCube1"
{
token purpose = "default"
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)]
float2[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.625, 0.5), (0.375, 0.5), (0.625, 0.75), (0.375, 0.75), (0.625, 1), (0.375, 1), (0.875, 0), (0.875, 0.25), (0.125, 0), (0.125, 0.25)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 3, 3, 2, 4, 5, 5, 4, 6, 7, 7, 6, 8, 9, 1, 10, 11, 2, 12, 0, 3, 13]
}

def Mesh "pCube2"
{
token purpose = "render"
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)]
float2[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.625, 0.5), (0.375, 0.5), (0.625, 0.75), (0.375, 0.75), (0.625, 1), (0.375, 1), (0.875, 0), (0.875, 0.25), (0.125, 0), (0.125, 0.25)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 3, 3, 2, 4, 5, 5, 4, 6, 7, 7, 6, 8, 9, 1, 10, 11, 2, 12, 0, 3, 13]
double3 xformOp:translate = (0, 2, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
}

def Mesh "pCube3"
{
token purpose = "proxy"
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)]
float2[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.625, 0.5), (0.375, 0.5), (0.625, 0.75), (0.375, 0.75), (0.625, 1), (0.375, 1), (0.875, 0), (0.875, 0.25), (0.125, 0), (0.125, 0.25)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 3, 3, 2, 4, 5, 5, 4, 6, 7, 7, 6, 8, 9, 1, 10, 11, 2, 12, 0, 3, 13]
double3 xformOp:translate = (0, 4, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
}

def Mesh "pCube4"
{
float3[] extent = [(-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)]
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
int[] faceVertexIndices = [0, 1, 3, 2, 2, 3, 5, 4, 4, 5, 7, 6, 6, 7, 1, 0, 1, 7, 5, 3, 6, 0, 2, 4]
point3f[] points = [(-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5)]
color3f[] primvars:displayColor = [(0.217638, 0.217638, 0.217638)]
float2[] primvars:st = [(0.375, 0), (0.625, 0), (0.625, 0.25), (0.375, 0.25), (0.625, 0.5), (0.375, 0.5), (0.625, 0.75), (0.375, 0.75), (0.625, 1), (0.375, 1), (0.875, 0), (0.875, 0.25), (0.125, 0), (0.125, 0.25)] (
interpolation = "faceVarying"
)
int[] primvars:st:indices = [0, 1, 2, 3, 3, 2, 4, 5, 5, 4, 6, 7, 7, 6, 8, 9, 1, 10, 11, 2, 12, 0, 3, 13]
double3 xformOp:translate = (0, 6, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/pxrpythonsubst
#
# Copyright 2018 Pixar
#
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the trade
# names, trademarks, service marks, or product names of the Licensor
# and its affiliates, except as required to comply with Section 4(c) of
# the License and to reproduce the content of the NOTICE file.
#
# You may obtain a copy of the Apache License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
#

from maya import cmds
from maya import standalone

import os
import unittest
from pxr import Usd, UsdGeom


class testUsdGeomAttributeConverters(unittest.TestCase):

@classmethod
def tearDownClass(cls):
standalone.uninitialize()

@classmethod
def setUpClass(cls):
standalone.initialize('usd')
cmds.loadPlugin('pxrUsd')

usdFile = os.path.abspath('UsdAttrs.usda')
cmds.usdImport(file=usdFile, shadingMode='none')

def testImport(self):
"""
Tests that the built-in geom attribute converter can import
the purpose attribute properly.
"""
# Testing for the different purpose attributes
self.assertEqual(cmds.getAttr('pCube1.USD_purpose'), 'default')
self.assertEqual(cmds.getAttr('pCube2.USD_purpose'), 'render')
self.assertEqual(cmds.getAttr('pCube3.USD_purpose'), 'proxy')

# pCube4 does not have a purpose attribute
self.assertFalse(cmds.objExists('pCube4.USD_purpose'))

def testExport(self):
"""
Test that the built-in geom attribute converter can export
the purpose attribute properly.
"""
newUsdFilePath = os.path.abspath('UsdAttrsNew.usda')
cmds.usdExport(file=newUsdFilePath, shadingMode='none')
newUsdStage = Usd.Stage.Open(newUsdFilePath)

# Testing the exported purpose attributes
geom1 = UsdGeom.Imageable(newUsdStage.GetPrimAtPath('/World/pCube1'))
self.assertEqual(geom1.GetPurposeAttr().Get(), 'default')
geom2 = UsdGeom.Imageable(newUsdStage.GetPrimAtPath('/World/pCube2'))
self.assertEqual(geom2.GetPurposeAttr().Get(), 'render')
geom3 = UsdGeom.Imageable(newUsdStage.GetPrimAtPath('/World/pCube3'))
self.assertEqual(geom3.GetPurposeAttr().Get(), 'proxy')

# Testing that there is no authored attribute
geom4 = UsdGeom.Imageable(newUsdStage.GetPrimAtPath('/World/pCube4'))
self.assertFalse(geom4.GetPurposeAttr().HasAuthoredValueOpinion())

if __name__ == '__main__':
unittest.main(verbosity=2)