2013-11-13 22:49:33 +00:00
//
// Copyright 2013 Autodesk, Inc.
//
// 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.
//
# include "osdPolySmooth.h"
# include <maya/MFnNumericAttribute.h>
# include <maya/MFnTypedAttribute.h>
# include <maya/MFnEnumAttribute.h>
# include <maya/MFnUnitAttribute.h>
# include <maya/MFnMatrixAttribute.h>
# include <maya/MFnMessageAttribute.h>
# include <maya/MFnCompoundAttribute.h>
# include <maya/MFnGenericAttribute.h>
# include <maya/MFnLightDataAttribute.h>
# include <maya/MDataHandle.h>
# include <maya/MDataBlock.h>
# include <maya/MPlug.h>
# include <maya/MIOStream.h>
# include <maya/MGlobal.h>
# include <maya/MFnMesh.h>
# include <maya/MFnMeshData.h>
# include <maya/MItMeshPolygon.h>
# include <maya/MFloatArray.h>
# include <maya/MFnSingleIndexedComponent.h>
# include <maya/MPointArray.h>
# include <maya/MFloatPointArray.h>
# include <maya/MDoubleArray.h>
# include <maya/MUintArray.h>
# include <maya/MFnPlugin.h>
# include <stdexcept>
# include <map>
2013-11-13 23:27:43 +00:00
# if defined(_MSV_VER) and (not defined(__INTEL_COMPILER))
# pragma warning( disable : 174 593 )
# endif
2013-11-13 22:49:33 +00:00
// OpenSubdiv includes
# include <osd/vertex.h>
# include <osd/vertex.h>
# include <osd/mesh.h>
# include <osd/cpuComputeContext.h>
2013-11-15 22:55:46 +00:00
# include <osd/cpuComputeController.h>
2013-11-13 22:49:33 +00:00
# include <osd/cpuVertexBuffer.h>
// ====================================
// Static Initialization
// ====================================
// MAYA_NODE_BUILDER:BEG [ATTRIBUTE INITIALIZATION] ==========
const MTypeId OsdPolySmooth : : id ( 0x0010a25b ) ;
const MString OsdPolySmooth : : typeNameStr ( " osdPolySmooth " ) ;
2013-11-13 23:27:43 +00:00
MObject OsdPolySmooth : : a_inputPolymesh ;
MObject OsdPolySmooth : : a_output ;
MObject OsdPolySmooth : : a_subdivisionLevels ;
2013-11-26 01:12:57 +00:00
MObject OsdPolySmooth : : a_recommendedIsolation ;
2013-11-13 23:27:43 +00:00
MObject OsdPolySmooth : : a_vertBoundaryMethod ;
MObject OsdPolySmooth : : a_fvarBoundaryMethod ;
MObject OsdPolySmooth : : a_fvarPropagateCorners ;
MObject OsdPolySmooth : : a_smoothTriangles ;
MObject OsdPolySmooth : : a_creaseMethod ;
2013-11-13 22:49:33 +00:00
// MAYA_NODE_BUILDER:END [ATTRIBUTE INITIALIZATION] ==========
// ATTR ENUMS
// Note: Do not change these values as these are serialized numerically in the Maya scenes)
//
enum BoundaryMethod {
k_BoundaryMethod_InterpolateBoundaryNone = 0 ,
k_BoundaryMethod_InterpolateBoundaryEdgeOnly = 1 ,
k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner = 2 ,
k_BoundaryMethod_InterpolateBoundaryAlwaysSharp = 3
} ;
enum CreaseMethod {
k_creaseMethod_normal = 0 ,
k_creaseMethod_chaikin = 1
} ;
2013-11-15 22:55:46 +00:00
typedef OpenSubdiv : : HbrMesh < OpenSubdiv : : OsdVertex > HMesh ;
typedef OpenSubdiv : : HbrFace < OpenSubdiv : : OsdVertex > HFace ;
typedef OpenSubdiv : : HbrVertex < OpenSubdiv : : OsdVertex > HVertex ;
typedef OpenSubdiv : : HbrHalfedge < OpenSubdiv : : OsdVertex > HHalfedge ;
typedef OpenSubdiv : : HbrFVarData < OpenSubdiv : : OsdVertex > HFvarData ;
typedef OpenSubdiv : : HbrCatmarkSubdivision < OpenSubdiv : : OsdVertex > HCatmark ;
typedef OpenSubdiv : : FarMesh < OpenSubdiv : : OsdVertex > FMesh ;
typedef OpenSubdiv : : FarMeshFactory < OpenSubdiv : : OsdVertex > FMeshFactory ;
HMesh : : InterpolateBoundaryMethod
2013-11-13 22:49:33 +00:00
ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod ( short boundaryMethod ) {
2013-11-15 22:55:46 +00:00
switch ( boundaryMethod ) {
case k_BoundaryMethod_InterpolateBoundaryNone : return HMesh : : k_InterpolateBoundaryNone ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
case k_BoundaryMethod_InterpolateBoundaryEdgeOnly : return HMesh : : k_InterpolateBoundaryEdgeOnly ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
case k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner : return HMesh : : k_InterpolateBoundaryEdgeAndCorner ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
case k_BoundaryMethod_InterpolateBoundaryAlwaysSharp : return HMesh : : k_InterpolateBoundaryAlwaysSharp ;
default : ;
2013-11-13 22:49:33 +00:00
}
2013-11-15 22:55:46 +00:00
MGlobal : : displayError ( " InterpolateBoundaryMethod value out of range. Using \" none \" " ) ;
2013-11-13 22:49:33 +00:00
return OpenSubdiv : : HbrMesh < OpenSubdiv : : OsdVertex > : : k_InterpolateBoundaryNone ;
}
// ====================================
// Macros
// ====================================
# define MCHECKERR(status,message) \
if ( MStatus : : kSuccess ! = status ) { \
cerr < < " ERROR: " < < message < < " [ " < < status < < " ] " < < endl ; \
return status ; \
}
# define MWARNERR(status,message) \
if ( MStatus : : kSuccess ! = status ) { \
cerr < < " ERROR: " < < message < < " [ " < < status < < " ] " < < endl ; \
}
// ====================================
// Constructors/Destructors
// ====================================
OsdPolySmooth : : OsdPolySmooth ( ) { }
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
OsdPolySmooth : : ~ OsdPolySmooth ( ) { }
// ====================================
// Helper Functions
// ====================================
// Create component groups
2013-11-15 22:55:46 +00:00
void
createComp ( MFnMeshData & dataCreator , MFn : : Type compType , unsigned compId , MIntArray & compList ) {
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
MFnSingleIndexedComponent comp ;
MObject compObj = comp . create ( compType , & returnStatus ) ;
MWARNERR ( returnStatus , " cannot create MFnSingleIndexedComponent " ) ;
returnStatus = comp . addElements ( compList ) ;
MWARNERR ( returnStatus , " Error in addElements() for MFnSingleIndexedComponent " ) ;
returnStatus = dataCreator . addObjectGroup ( compId ) ;
MWARNERR ( returnStatus , " Error in addObjectGroup() " ) ;
returnStatus = dataCreator . setObjectGroupComponent ( compId , compObj ) ;
MWARNERR ( returnStatus , " Error in setObjectGroupComponent() " ) ;
}
// ====================================
// OpenSubdiv Functions
// ====================================
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Reference: OSD shape_utils.h:: applyTags() "crease"
2013-11-15 22:55:46 +00:00
float
applyCreaseEdges ( MFnMesh const & inMeshFn , HMesh * hbrMesh ) {
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
MUintArray tEdgeIds ;
MDoubleArray tCreaseData ;
2013-11-15 22:55:46 +00:00
float maxCreaseValue = 0.0f ;
if ( inMeshFn . getCreaseEdges ( tEdgeIds , tCreaseData ) ) {
2013-11-13 22:49:33 +00:00
assert ( tEdgeIds . length ( ) = = tCreaseData . length ( ) ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Has crease edges
int2 edgeVerts ;
for ( unsigned int j = 0 ; j < tEdgeIds . length ( ) ; j + + ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Get vert ids from maya edge
int edgeId = tEdgeIds [ j ] ;
returnStatus = inMeshFn . getEdgeVertices ( edgeId , edgeVerts ) ;
// Assumption: The OSD vert ids are identical to those of the Maya mesh
2013-11-15 22:55:46 +00:00
HVertex const * v = hbrMesh - > GetVertex ( edgeVerts [ 0 ] ) ,
* w = hbrMesh - > GetVertex ( edgeVerts [ 1 ] ) ;
HHalfedge * e = 0 ;
if ( v and w ) {
2013-11-13 22:49:33 +00:00
if ( ( e = v - > GetEdge ( w ) ) = = 0 ) {
e = w - > GetEdge ( v ) ;
}
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
if ( e ) {
assert ( tCreaseData [ j ] > = 0.0 ) ;
e - > SetSharpness ( ( float ) tCreaseData [ j ] ) ;
2013-11-15 22:55:46 +00:00
maxCreaseValue = std : : max ( float ( tCreaseData [ j ] ) , maxCreaseValue ) ;
} else {
fprintf ( stderr ,
" warning: cannot find edge for crease tag (%d,%d) \n " ,
edgeVerts [ 0 ] , edgeVerts [ 1 ] ) ;
2013-11-13 22:49:33 +00:00
}
}
}
}
return maxCreaseValue ;
}
// Reference: OSD shape_utils.h:: applyTags() "corner"
2013-11-15 22:55:46 +00:00
float
applyCreaseVertices ( MFnMesh const & inMeshFn , HMesh * hbrMesh ) {
2013-11-13 22:49:33 +00:00
MUintArray tVertexIds ;
MDoubleArray tCreaseData ;
2013-11-15 22:55:46 +00:00
float maxCreaseValue = 0.0f ;
2013-11-13 22:49:33 +00:00
if ( inMeshFn . getCreaseVertices ( tVertexIds , tCreaseData ) ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
assert ( tVertexIds . length ( ) = = tCreaseData . length ( ) ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Has crease vertices
for ( unsigned int j = 0 ; j < tVertexIds . length ( ) ; j + + ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Assumption: The OSD vert ids are identical to those of the Maya mesh
2013-11-15 22:55:46 +00:00
HVertex * v = hbrMesh - > GetVertex ( tVertexIds [ j ] ) ;
2013-11-13 22:49:33 +00:00
if ( v ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
assert ( tCreaseData [ j ] > = 0.0 ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
v - > SetSharpness ( ( float ) tCreaseData [ j ] ) ;
2013-11-15 22:55:46 +00:00
maxCreaseValue = std : : max ( float ( tCreaseData [ j ] ) , maxCreaseValue ) ;
} else {
fprintf ( stderr ,
" warning: cannot find vertex for corner tag (%d) \n " ,
tVertexIds [ j ] ) ;
2013-11-13 22:49:33 +00:00
}
}
}
return maxCreaseValue ;
}
// XXX -- Future Data Optimization: Implement varying data instead of forcing face-varying for ColorSets.
// Collect UVs and ColorSet info to represent them as face-varying in OpenSubdiv
2013-11-15 22:55:46 +00:00
MStatus
getMayaFvarFieldParams (
MFnMesh const & inMeshFn ,
MStringArray & uvSetNames ,
MStringArray & colorSetNames ,
std : : vector < int > & colorSetChannels ,
std : : vector < MFnMesh : : MColorRepresentation > & colorSetReps ,
int & totalColorSetChannels ) {
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
returnStatus = inMeshFn . getUVSetNames ( uvSetNames ) ;
MCHECKERR ( returnStatus , " Cannot get uvSet names " ) ;
returnStatus = inMeshFn . getColorSetNames ( colorSetNames ) ;
MCHECKERR ( returnStatus , " Cannot get colorSet names " ) ;
colorSetChannels . resize ( colorSetNames . length ( ) ) ;
colorSetReps . resize ( colorSetNames . length ( ) ) ;
totalColorSetChannels = 0 ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
for ( unsigned int i = 0 ; i < colorSetNames . length ( ) ; i + + ) {
2013-11-15 22:55:46 +00:00
colorSetReps [ i ] = inMeshFn . getColorRepresentation ( colorSetNames [ i ] , & returnStatus ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( returnStatus , " Cannot get colorSet representation " ) ;
2013-11-15 22:55:46 +00:00
if ( colorSetReps [ i ] = = MFnMesh : : kAlpha ) {
2013-11-13 22:49:33 +00:00
colorSetChannels [ i ] = 1 ;
2013-11-15 22:55:46 +00:00
} else if ( colorSetReps [ i ] = = MFnMesh : : kRGB ) {
2013-11-13 22:49:33 +00:00
colorSetChannels [ i ] = 3 ;
2013-11-15 22:55:46 +00:00
} else {
colorSetChannels [ i ] = 4 ; // kRGBA
2013-11-13 22:49:33 +00:00
}
totalColorSetChannels + = colorSetChannels [ i ] ;
}
return MS : : kSuccess ;
}
2013-11-13 23:27:43 +00:00
//! Create OSD HBR mesh.
2013-11-15 22:55:46 +00:00
//! Caller is expected to delete the resulting hbrMesh returned
HMesh *
createOsdHbrFromPoly ( MFnMesh const & inMeshFn ,
MItMeshPolygon & inMeshItPolygon ,
std : : vector < int > & fvarIndices ,
2013-11-26 01:12:57 +00:00
std : : vector < int > & fvarWidths ,
float * maxCreaseSharpness = 0 )
2013-11-13 22:49:33 +00:00
{
MStatus returnStatus ;
// == Mesh Properties
2013-11-15 22:55:46 +00:00
// Gather FVarData
2013-11-13 22:49:33 +00:00
MStringArray uvSetNames ;
MStringArray colorSetNames ;
std : : vector < int > colorSetChannels ;
std : : vector < MFnMesh : : MColorRepresentation > colorSetReps ;
int totalColorSetChannels = 0 ;
returnStatus = getMayaFvarFieldParams ( inMeshFn , uvSetNames , colorSetNames , colorSetChannels , colorSetReps , totalColorSetChannels ) ;
MWARNERR ( returnStatus , " Failed to retrieve Maya face-varying parameters " ) ;
// Create face-varying data with independent float channels of dimension 1
// Note: This FVarData needs to be kept around for the duration of the HBR mesh
int totalFvarWidth = 2 * uvSetNames . length ( ) + totalColorSetChannels ;
fvarIndices . resize ( totalFvarWidth ) ;
fvarWidths . resize ( totalFvarWidth ) ;
for ( int i = 0 ; i < totalFvarWidth ; + + i ) {
fvarIndices [ i ] = i ;
fvarWidths [ i ] = 1 ;
}
2013-11-15 22:55:46 +00:00
// temp storage for UVs and ColorSets for a face
MIntArray fvArray ; // face vertex array
std : : vector < MFloatArray > uvSet_uCoords ( uvSetNames . length ( ) ) ;
std : : vector < MFloatArray > uvSet_vCoords ( uvSetNames . length ( ) ) ;
std : : vector < MColorArray > colorSet_colors ( colorSetNames . length ( ) ) ;
// =====================================
// Init HBR
// =====================================
2013-11-13 22:49:33 +00:00
// Determine HBR Subdiv Method
2013-11-15 22:55:46 +00:00
static HCatmark _catmark ;
2013-11-13 22:49:33 +00:00
// Create HBR mesh
assert ( fvarIndices . size ( ) = = fvarWidths . size ( ) ) ;
2013-11-15 22:55:46 +00:00
HMesh * hbrMesh = new HMesh ( & _catmark ,
( int ) fvarIndices . size ( ) ,
( fvarIndices . size ( ) > 0 ) ? & fvarIndices [ 0 ] : NULL ,
( fvarWidths . size ( ) > 0 ) ? & fvarWidths [ 0 ] : NULL ,
totalFvarWidth ) ;
2013-11-13 22:49:33 +00:00
// Create Stub HBR Vertices
int numVerts = inMeshFn . numVertices ( ) ;
2013-11-15 22:55:46 +00:00
OpenSubdiv : : OsdVertex v ;
2013-11-13 22:49:33 +00:00
for ( int i = 0 ; i < numVerts ; i + + ) {
hbrMesh - > NewVertex ( i , v ) ;
}
2013-11-15 22:55:46 +00:00
// ===================================================
2013-11-13 22:49:33 +00:00
// Create HBR Topology
// ===================================================
assert ( totalFvarWidth = = hbrMesh - > GetTotalFVarWidth ( ) ) ;
unsigned int ptxidx = 0 ;
2013-11-13 23:27:43 +00:00
2013-11-13 22:49:33 +00:00
for ( inMeshItPolygon . reset ( ) ; ! inMeshItPolygon . isDone ( ) ; inMeshItPolygon . next ( ) ) {
// Verts for this face
inMeshItPolygon . getVertices ( fvArray ) ;
unsigned int nv = fvArray . length ( ) ;
2013-11-15 22:55:46 +00:00
bool valid = true ;
2013-11-13 22:49:33 +00:00
for ( unsigned int j = 0 ; j < fvArray . length ( ) ; j + + ) {
2013-11-15 22:55:46 +00:00
HVertex const * origin = hbrMesh - > GetVertex ( fvArray [ j ] ) ,
* destination = hbrMesh - > GetVertex ( fvArray [ ( j + 1 ) % nv ] ) ;
HHalfedge const * opposite = destination - > GetEdge ( origin ) ;
2013-11-13 22:49:33 +00:00
if ( origin = = NULL | | destination = = NULL ) {
fprintf ( stderr , " Skipping face: An edge was specified that connected a nonexistent vertex \n " ) ;
2013-11-15 22:55:46 +00:00
valid = false ;
2013-11-13 22:49:33 +00:00
break ;
}
if ( origin = = destination ) {
fprintf ( stderr , " Skipping face: An edge was specified that connected a vertex to itself \n " ) ;
2013-11-15 22:55:46 +00:00
valid = false ;
2013-11-13 22:49:33 +00:00
break ;
}
if ( opposite & & opposite - > GetOpposite ( ) ) {
fprintf ( stderr , " Skipping face: A non-manifold edge incident to more than 2 faces was found \n " ) ;
2013-11-15 22:55:46 +00:00
valid = false ;
2013-11-13 22:49:33 +00:00
break ;
}
if ( origin - > GetEdge ( destination ) ) {
fprintf ( stderr , " Skipping face: An edge connecting two vertices was specified more than once. "
" It's likely that an incident face was flipped \n " ) ;
2013-11-15 22:55:46 +00:00
valid = false ;
2013-11-13 22:49:33 +00:00
break ;
}
}
// Update faces
const int * fvArrayPtr = & ( fvArray [ 0 ] ) ; // get the raw int* array from std::vector<int>
OpenSubdiv : : HbrFace < OpenSubdiv : : OsdVertex > * face = hbrMesh - > NewFace ( nv , fvArrayPtr , 0 ) ;
// Increment ptex index
face - > SetPtexIndex ( ptxidx ) ;
// Add FaceVaryingData (UVSets, ...)
2013-11-15 22:55:46 +00:00
if ( totalFvarWidth > 0 ) {
2013-11-13 22:49:33 +00:00
// Retrieve all UV and ColorSet data
for ( unsigned int i = 0 ; i < uvSetNames . length ( ) ; + + i ) {
2014-02-28 00:45:34 +00:00
inMeshItPolygon . getUVs ( uvSet_uCoords [ i ] , uvSet_vCoords [ i ] , & uvSetNames [ i ] ) ;
2013-11-13 22:49:33 +00:00
}
for ( unsigned int i = 0 ; i < colorSetNames . length ( ) ; + + i ) {
2014-02-28 00:45:34 +00:00
inMeshItPolygon . getColors ( colorSet_colors [ i ] , & colorSetNames [ i ] ) ;
2013-11-13 22:49:33 +00:00
}
std : : vector < float > fvarItem ( totalFvarWidth ) ; // storage for all the face-varying channels for this face-vertex
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// loop over each uvSet and the uvs within
for ( unsigned int fvid = 0 ; fvid < fvArray . length ( ) ; + + fvid ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
int fvarItemIndex = 0 ;
// Handle uvSets
for ( unsigned int uvSetIt = 0 ; uvSetIt < uvSetNames . length ( ) ; + + uvSetIt ) {
2014-02-28 00:45:34 +00:00
if ( fvid < uvSet_uCoords [ uvSetIt ] . length ( ) ) {
fvarItem [ fvarItemIndex ] = uvSet_uCoords [ uvSetIt ] [ fvid ] ;
fvarItem [ fvarItemIndex + 1 ] = uvSet_vCoords [ uvSetIt ] [ fvid ] ;
} else {
// getUVs() can return incomplete or empty arrays
fvarItem [ fvarItemIndex ] = 0.0f ;
fvarItem [ fvarItemIndex + 1 ] = 0.0f ;
}
fvarItemIndex + = 2 ;
2013-11-13 22:49:33 +00:00
}
// Handle colorSets
for ( unsigned int colorSetIt = 0 ; colorSetIt < colorSetNames . length ( ) ; + + colorSetIt ) {
2014-02-28 00:45:34 +00:00
int nchannels = colorSetChannels [ colorSetIt ] ;
for ( int channel = 0 ; channel < nchannels ; + + channel ) {
if ( fvid < colorSet_colors [ colorSetIt ] . length ( ) ) {
fvarItem [ fvarItemIndex + channel ] = colorSet_colors [ colorSetIt ] [ fvid ] [ channel ] ;
} else {
// getColors() can return incomplete or empty arrays
fvarItem [ fvarItemIndex + channel ] = 0.0f ;
}
2013-11-13 22:49:33 +00:00
}
2014-02-28 00:45:34 +00:00
fvarItemIndex + = nchannels ;
2013-11-13 22:49:33 +00:00
}
assert ( ( fvarItemIndex ) = = totalFvarWidth ) ; // For UVs, sanity check the resulting value
2013-11-13 23:27:43 +00:00
// Insert into the HBR structure for that face
2013-11-15 22:55:46 +00:00
HVertex * hbrVertex = hbrMesh - > GetVertex ( fvArray [ fvid ] ) ;
HFvarData & fvarData = hbrVertex - > GetFVarData ( face ) ;
if ( not fvarData . IsInitialized ( ) ) {
fvarData . SetAllData ( totalFvarWidth , & fvarItem [ 0 ] ) ;
} else if ( not fvarData . CompareAll ( totalFvarWidth , & fvarItem [ 0 ] ) ) {
2013-11-13 22:49:33 +00:00
// If data exists for this face vertex, but is different
// (e.g. we're on a UV seam) create another fvar datum
OpenSubdiv : : HbrFVarData < OpenSubdiv : : OsdVertex > & fvarData_new = hbrVertex - > NewFVarData ( face ) ;
fvarData_new . SetAllData ( totalFvarWidth , & fvarItem [ 0 ] ) ;
}
}
}
// Increment ptxidx and store off ptex index values
2013-11-13 23:27:43 +00:00
// The number of ptexIds needed is 1 if a quad. Otherwise it is the number of
2013-11-13 22:49:33 +00:00
// vertices for the face.
int numPtexIdsForFace ;
2013-11-15 22:55:46 +00:00
if ( valid ) {
2013-11-13 22:49:33 +00:00
numPtexIdsForFace = ( nv ! = 4 ) ? nv : 1 ;
}
else {
numPtexIdsForFace = 0 ;
}
ptxidx + = numPtexIdsForFace ;
}
// Apply Creases
2013-11-26 01:12:57 +00:00
float maxEdgeCrease = applyCreaseEdges ( inMeshFn , hbrMesh ) ;
float maxVertexCrease = applyCreaseVertices ( inMeshFn , hbrMesh ) ;
if ( maxCreaseSharpness ) {
* maxCreaseSharpness = std : : max ( maxEdgeCrease , maxVertexCrease ) ;
}
2013-11-13 22:49:33 +00:00
// Return the resulting HBR Mesh
// Note that boundaryMethods and hbrMesh->Finish() still need to be called
return hbrMesh ;
}
MStatus convertOsdFarToMayaMeshData (
2013-11-15 22:55:46 +00:00
FMesh const * farMesh ,
OpenSubdiv : : OsdCpuVertexBuffer * vertexBuffer ,
int subdivisionLevel ,
MFnMesh const & inMeshFn ,
MObject newMeshDataObj ) {
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
// Get sizing data from OSD
const OpenSubdiv : : FarPatchTables * farPatchTables = farMesh - > GetPatchTables ( ) ;
int numPolygons = farPatchTables - > GetNumFaces ( ) ; // use the highest level stored in the patch tables
const unsigned int * polygonConnects_orig = farPatchTables - > GetFaceVertices ( ) ; // use the highest level stored in the patch tables
2014-03-19 18:44:51 +00:00
const OpenSubdiv : : FarSubdivisionTables * farSubdivTables = farMesh - > GetSubdivisionTables ( ) ;
2013-11-13 22:49:33 +00:00
unsigned int numVertices = farSubdivTables - > GetNumVertices ( subdivisionLevel ) ;
unsigned int vertexOffset = farSubdivTables - > GetFirstVertexOffset ( subdivisionLevel ) ;
// Init Maya Data
MFloatPointArray points ( numVertices ) ;
2013-11-15 22:55:46 +00:00
MIntArray faceCounts ( numPolygons ) ; // number of edges for each polygon. Assume quads (4-edges per face)
MIntArray faceConnects ( numPolygons * 4 ) ; // array of vertex ids for all edges. assuming quads
2013-11-13 22:49:33 +00:00
// -- Face Counts
for ( int i = 0 ; i < numPolygons ; + + i ) {
faceCounts [ i ] = 4 ;
}
// -- Face Connects
for ( unsigned int i = 0 ; i < faceConnects . length ( ) ; i + + ) {
faceConnects [ i ] = polygonConnects_orig [ i ] - vertexOffset ; // adjust vertex indices so that v0 is at index 0
}
// -- Points
// Number of floats in each vertex. (positions, normals, etc)
int numFloatsPerVertex = vertexBuffer - > GetNumElements ( ) ;
assert ( numFloatsPerVertex = = 3 ) ; // assuming only xyz stored for each vertex
const float * vertexData = vertexBuffer - > BindCpuBuffer ( ) ;
float * ptrVertexData ;
2013-11-15 22:55:46 +00:00
for ( unsigned int i = 0 ; i < numVertices ; i + + ) {
// make sure to offset to the first osd vertex for that subd level
unsigned int osdRawVertexIndex = i + vertexOffset ;
2013-11-13 22:49:33 +00:00
// Lookup the data in the vertexData
ptrVertexData = ( float * ) vertexData + ( ( osdRawVertexIndex ) * numFloatsPerVertex ) ;
points . set ( i , ptrVertexData [ 0 ] , ptrVertexData [ 1 ] , ptrVertexData [ 2 ] ) ;
}
// Create New Mesh from MFnMesh
MFnMesh newMeshFn ;
2013-11-15 22:55:46 +00:00
MObject newMeshObj = newMeshFn . create ( points . length ( ) , faceCounts . length ( ) ,
points , faceCounts , faceConnects , newMeshDataObj , & returnStatus ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( returnStatus , " Cannot create new mesh " ) ;
// Attach UVs (if present)
// ASSUMPTION: Only tracking UVs as FVar data. Will need to change this
// ASSUMPTION: OSD has a unique UV for each face-vertex
2014-04-05 02:10:34 +00:00
int fvarTotalWidth = farMesh - > GetPatchTables ( ) - > GetFVarData ( ) . GetFVarWidth ( ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
if ( fvarTotalWidth > 0 ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Get face-varying set names and other info from the inMesh
MStringArray uvSetNames ;
MStringArray colorSetNames ;
std : : vector < int > colorSetChannels ;
std : : vector < MFnMesh : : MColorRepresentation > colorSetReps ;
int totalColorSetChannels = 0 ;
returnStatus = getMayaFvarFieldParams ( inMeshFn , uvSetNames , colorSetNames , colorSetChannels , colorSetReps , totalColorSetChannels ) ;
int numUVSets = uvSetNames . length ( ) ;
int expectedFvarTotalWidth = numUVSets * 2 + totalColorSetChannels ;
assert ( fvarTotalWidth = = expectedFvarTotalWidth ) ;
2014-04-05 02:10:34 +00:00
std : : vector < float > const & fvarData = farPatchTables - > GetFVarData ( ) . GetAllData ( ) ;
if ( fvarData . size ( ) ! = expectedFvarTotalWidth * faceConnects . length ( ) ) {
2014-01-22 22:26:42 +00:00
MCHECKERR ( MS : : kFailure , " Incorrect face-varying table length " ) ;
}
2013-11-13 22:49:33 +00:00
// Create an array of indices to map each face-vert to the UV and ColorSet Data
MIntArray fvarConnects ( faceConnects . length ( ) ) ;
for ( unsigned int i = 0 ; i < faceConnects . length ( ) ; i + + ) {
fvarConnects [ i ] = i ;
}
MFloatArray uCoord ( faceConnects . length ( ) ) ;
MFloatArray vCoord ( faceConnects . length ( ) ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
for ( int uvSetIndex = 0 ; uvSetIndex < numUVSets ; uvSetIndex + + ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
for ( unsigned int vertid = 0 ; vertid < faceConnects . length ( ) ; vertid + + ) {
int fvarItem = vertid * fvarTotalWidth + uvSetIndex * 2 ; // stride per vertex is the fvarTotalWidth
2014-04-05 02:10:34 +00:00
uCoord [ vertid ] = fvarData [ fvarItem ] ;
vCoord [ vertid ] = fvarData [ fvarItem + 1 ] ;
2013-11-13 22:49:33 +00:00
}
// Assign UV buffer and map the uvids for each face-vertex
2014-02-28 00:45:34 +00:00
if ( uvSetIndex > 0 ) {
2013-11-13 22:49:33 +00:00
returnStatus = newMeshFn . createUVSetDataMesh ( uvSetNames [ uvSetIndex ] ) ;
2014-02-28 00:45:34 +00:00
MCHECKERR ( returnStatus , " Cannot create UVSet " ) ;
2013-11-13 22:49:33 +00:00
}
2014-02-28 00:45:34 +00:00
static MString defaultUVName ( " map1 " ) ;
MString const * uvname = uvSetIndex = = 0 ? & defaultUVName : & uvSetNames [ uvSetIndex ] ;
returnStatus = newMeshFn . setUVs ( uCoord , vCoord , uvname ) ;
MCHECKERR ( returnStatus , " Cannot set UVs for set : " + * uvname ) ;
newMeshFn . assignUVs ( faceCounts , fvarConnects , uvname ) ;
2013-11-13 22:49:33 +00:00
}
MColorArray colorArray ( faceConnects . length ( ) ) ;
int colorSetRelativeStartIndex = numUVSets * 2 ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
for ( unsigned int colorSetIndex = 0 ; colorSetIndex < colorSetNames . length ( ) ; colorSetIndex + + ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
for ( unsigned int vertid = 0 ; vertid < faceConnects . length ( ) ; vertid + + ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
int fvarItem = vertid * fvarTotalWidth + colorSetRelativeStartIndex ;
2014-02-28 00:45:34 +00:00
int nchannels = colorSetChannels [ colorSetIndex ] ;
for ( int channel = 0 ; channel < nchannels ; + + channel ) {
2014-04-05 02:10:34 +00:00
colorArray [ vertid ] [ channel ] = fvarData [ fvarItem + channel ] ;
2013-11-13 22:49:33 +00:00
}
}
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
// Assign UV buffer and map the uvids for each face-vertex
2013-11-15 22:55:46 +00:00
// API Limitation: Cannot set MColorRepresentation here
returnStatus = newMeshFn . createColorSetDataMesh ( colorSetNames [ colorSetIndex ] ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( returnStatus , " Cannot create ColorSet " ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
bool isColorClamped = inMeshFn . isColorClamped ( colorSetNames [ colorSetIndex ] , & returnStatus ) ;
newMeshFn . setIsColorClamped ( colorSetNames [ colorSetIndex ] , isColorClamped ) ;
newMeshFn . setColors ( colorArray , & colorSetNames [ colorSetIndex ] , colorSetReps [ colorSetIndex ] ) ;
newMeshFn . assignColors ( fvarConnects , & colorSetNames [ colorSetIndex ] ) ;
// Increment colorSet start location in fvar buffer
colorSetRelativeStartIndex + = colorSetChannels [ colorSetIndex ] ;
}
}
return MS : : kSuccess ;
}
2014-03-13 21:49:19 +00:00
static inline int
computeNumSubfaces ( int nverts , int level ) {
return nverts = = 4 ? 1 < < ( level < < 1 ) : nverts * ( 1 < < ( ( level - 1 ) < < 1 ) ) ;
}
2013-11-13 22:49:33 +00:00
// Propagate objectGroups from inMesh to subdivided outMesh
// Note: Currently only supporting facet groups (for per-facet shading)
2013-11-15 22:55:46 +00:00
MStatus
2014-03-13 21:49:19 +00:00
createSmoothMesh_objectGroups ( FMesh const * farMesh , MFnMesh const & inMeshFn ,
MFnMeshData const & inMeshDat , MFnMeshData & newMeshDat , int level ) {
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
MIntArray newCompElems ;
2013-11-15 22:55:46 +00:00
2014-03-13 21:49:19 +00:00
int numSubfaces = farMesh - > GetPatchTables ( ) - > GetNumFaces ( ) ;
std : : vector < unsigned int > offsets ; // mapping of offsets for subdivided faces
for ( unsigned int gi = 0 ; gi < inMeshDat . objectGroupCount ( ) ; gi + + ) {
2013-11-13 22:49:33 +00:00
unsigned int compId = inMeshDat . objectGroup ( gi , & returnStatus ) ;
MCHECKERR ( returnStatus , " cannot get objectGroup() comp ID. " ) ;
2014-03-13 21:49:19 +00:00
2013-11-13 22:49:33 +00:00
MFn : : Type compType = inMeshDat . objectGroupType ( compId , & returnStatus ) ;
MCHECKERR ( returnStatus , " cannot get objectGroupType(). " ) ;
// Only supporting kMeshPolygonComponent ObjectGroups at this time
// Skip the other types
if ( compType = = MFn : : kMeshPolygonComponent ) {
2013-11-15 22:55:46 +00:00
2014-03-13 21:49:19 +00:00
// get elements from inMesh objectGroupComponent
MIntArray compElems ;
MFnSingleIndexedComponent compFn ( inMeshDat . objectGroupComponent ( compId ) , & returnStatus ) ;
MCHECKERR ( returnStatus , " cannot get MFnSingleIndexedComponent for inMeshDat.objectGroupComponent(). " ) ;
compFn . getElements ( compElems ) ;
if ( compElems . length ( ) = = 0 ) {
continue ;
}
// over-allocation to maximum possible length
newCompElems . setLength ( numSubfaces ) ;
if ( offsets . empty ( ) ) {
// lazy population of the subface offsets table
int nfaces = inMeshFn . numPolygons ( ) ;
offsets . resize ( nfaces ) ;
for ( int i = 0 , count = 0 ; i < nfaces ; + + i ) {
int nverts = inMeshFn . polygonVertexCount ( i ) ,
nsubfaces = computeNumSubfaces ( nverts , level ) ;
offsets [ i ] = count ;
count + = nsubfaces ;
}
}
unsigned int idx = 0 ;
2013-11-15 22:55:46 +00:00
// convert/populate newCompElems from compElems of inMesh
// (with new face indices) to outMesh
2013-11-13 22:49:33 +00:00
for ( unsigned int i = 0 ; i < compElems . length ( ) ; i + + ) {
2013-11-15 22:55:46 +00:00
2014-03-13 21:49:19 +00:00
int nverts = inMeshFn . polygonVertexCount ( compElems [ i ] ) ,
nsubfaces = computeNumSubfaces ( nverts , level ) ;
unsigned int subFaceOffset = offsets [ compElems [ i ] ] ;
2013-11-15 22:55:46 +00:00
2014-03-13 21:49:19 +00:00
for ( int j = 0 ; j < nsubfaces ; + + j ) {
newCompElems [ idx + + ] = subFaceOffset + + ;
2013-11-13 22:49:33 +00:00
}
}
2014-03-13 21:49:19 +00:00
// resize to actual length
newCompElems . setLength ( idx ) ;
2013-11-13 22:49:33 +00:00
// create comp
createComp ( newMeshDat , compType , compId , newCompElems ) ;
}
}
return MS : : kSuccess ;
}
// ====================================
// Compute
// ====================================
//
// Description:
// This method computes the value of the given output plug based
// on the values of the input attributes.
//
// Arguments:
// plug - the plug to compute
// data - object that provides access to the attributes for this node
//
2013-11-15 22:55:46 +00:00
MStatus OsdPolySmooth : : compute ( const MPlug & plug , MDataBlock & data ) {
2013-11-13 22:49:33 +00:00
MStatus returnStatus ;
2013-11-15 22:55:46 +00:00
2013-11-13 23:27:43 +00:00
// Check which output attribute we have been asked to compute. If this
// node doesn't know how to compute it, we must return
2013-11-13 22:49:33 +00:00
// MS::kUnknownParameter.
2013-11-13 23:27:43 +00:00
//
2013-11-13 22:49:33 +00:00
if ( plug = = a_output ) {
bool createdSubdMesh = false ;
2013-11-15 22:55:46 +00:00
int subdivisionLevel = data . inputValue ( a_subdivisionLevels ) . asInt ( ) ;
short stateH = data . inputValue ( state ) . asShort ( ) ;
if ( ( subdivisionLevel > 0 ) and ( stateH ! = 1 ) ) {
2013-11-13 22:49:33 +00:00
// == Retrieve input mesh ====================================
// Get attr values
MObject inMeshObj = data . inputValue ( a_inputPolymesh ) . asMesh ( ) ;
short vertBoundaryMethod = data . inputValue ( a_vertBoundaryMethod ) . asShort ( ) ;
short fvarBoundaryMethod = data . inputValue ( a_fvarBoundaryMethod ) . asShort ( ) ;
bool fvarPropCorners = data . inputValue ( a_fvarPropagateCorners ) . asBool ( ) ;
bool smoothTriangles = data . inputValue ( a_smoothTriangles ) . asBool ( ) ;
short creaseMethodVal = data . inputValue ( a_creaseMethod ) . asShort ( ) ;
// Convert attr values to OSD enums
2013-11-15 22:55:46 +00:00
HMesh : : InterpolateBoundaryMethod vertInterpBoundaryMethod =
2013-11-13 22:49:33 +00:00
ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod ( vertBoundaryMethod ) ;
2013-11-15 22:55:46 +00:00
HMesh : : InterpolateBoundaryMethod fvarInterpBoundaryMethod =
2013-11-13 22:49:33 +00:00
ConvertMayaBoundaryMethodShortToOsdInterpolateBoundaryMethod ( fvarBoundaryMethod ) ;
2013-11-15 22:55:46 +00:00
HCatmark : : CreaseSubdivision creaseMethod =
( creaseMethodVal = = k_creaseMethod_chaikin ) ?
HCatmark : : k_CreaseChaikin : HCatmark : : k_CreaseNormal ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
HCatmark : : TriangleSubdivision triangleSubdivision =
smoothTriangles ? HCatmark : : k_New : HCatmark : : k_Normal ;
2013-11-13 22:49:33 +00:00
// == Get Mesh Functions and Iterators ==========================
MFnMeshData inMeshDat ( inMeshObj ) ;
MFnMesh inMeshFn ( inMeshObj , & returnStatus ) ;
MCHECKERR ( returnStatus , " ERROR getting inMeshFn \n " ) ;
MItMeshPolygon inMeshItPolygon ( inMeshObj , & returnStatus ) ;
MCHECKERR ( returnStatus , " ERROR getting inMeshItPolygon \n " ) ;
// == Convert MFnMesh to OpenSubdiv =============================
// Create the hbrMesh
// Note: These fvar values only need to be kept alive through the life of the farMesh
std : : vector < int > fvarIndices ;
std : : vector < int > fvarWidths ;
2013-11-26 01:12:57 +00:00
float maxCreaseSharpness = 0.0 ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
HMesh * hbrMesh = createOsdHbrFromPoly (
2013-11-26 01:12:57 +00:00
inMeshFn , inMeshItPolygon , fvarIndices , fvarWidths , & maxCreaseSharpness ) ;
2013-11-13 22:49:33 +00:00
assert ( hbrMesh ) ;
2013-11-15 22:55:46 +00:00
// Create the farMesh if successfully created the hbrMesh
2013-11-13 22:49:33 +00:00
if ( hbrMesh ) {
// Set Boundary methods and other hbr paramters
hbrMesh - > SetInterpolateBoundaryMethod ( vertInterpBoundaryMethod ) ;
hbrMesh - > SetFVarInterpolateBoundaryMethod ( fvarInterpBoundaryMethod ) ;
hbrMesh - > SetFVarPropagateCorners ( fvarPropCorners ) ;
hbrMesh - > GetSubdivision ( ) - > SetCreaseSubdivisionMethod ( creaseMethod ) ;
// Set HBR Catmark Subdivision parameters
2013-11-15 22:55:46 +00:00
HCatmark * catmarkSubdivision = dynamic_cast < HCatmark * > ( hbrMesh - > GetSubdivision ( ) ) ;
2013-11-13 22:49:33 +00:00
if ( catmarkSubdivision ) {
catmarkSubdivision - > SetTriangleSubdivisionMethod ( triangleSubdivision ) ;
}
// Finalize subd calculations -- apply boundary interpolation rules and resolves singular verts, etc.
// NOTE: This HAS to be called after all HBR parameters are set
hbrMesh - > Finish ( ) ;
2013-11-13 23:27:43 +00:00
// Create a FarMesh from the HBR mesh and pass into
2013-11-13 22:49:33 +00:00
// It will be owned by the OsdMesh and deleted in the ~OsdMesh()
2013-11-15 22:55:46 +00:00
FMeshFactory meshFactory ( hbrMesh , subdivisionLevel , false ) ;
FMesh * farMesh = meshFactory . Create ( ( hbrMesh - > GetTotalFVarWidth ( ) > 0 ) ) ;
2013-11-13 22:49:33 +00:00
// == Setup OSD Data Structures =========================
int numVertexElements = 3 ; // only track vertex positions
int numVaryingElements = 0 ; // XXX Future: Revise to include varying ColorSets
int numVertices = inMeshFn . numVertices ( ) ;
int numFarVerts = farMesh - > GetNumVertices ( ) ;
2013-11-15 22:55:46 +00:00
2013-11-13 22:49:33 +00:00
static OpenSubdiv : : OsdCpuComputeController computeController = OpenSubdiv : : OsdCpuComputeController ( ) ;
2013-11-15 22:55:46 +00:00
OpenSubdiv : : OsdCpuComputeController : : ComputeContext * computeContext =
2014-03-28 19:10:13 +00:00
OpenSubdiv : : OsdCpuComputeController : : ComputeContext : : Create ( farMesh - > GetSubdivisionTables ( ) , farMesh - > GetVertexEditTables ( ) ) ;
2013-11-15 22:55:46 +00:00
OpenSubdiv : : OsdCpuVertexBuffer * vertexBuffer =
OpenSubdiv : : OsdCpuVertexBuffer : : Create ( numVertexElements , numFarVerts ) ;
OpenSubdiv : : OsdCpuVertexBuffer * varyingBuffer =
( numVaryingElements ) ? OpenSubdiv : : OsdCpuVertexBuffer : : Create ( numVaryingElements , numFarVerts ) : NULL ;
2013-11-13 22:49:33 +00:00
// == UPDATE VERTICES (can be done after farMesh generated from topology) ==
2013-11-15 22:55:46 +00:00
float const * vertex3fArray = inMeshFn . getRawPoints ( & returnStatus ) ;
2013-11-13 22:49:33 +00:00
vertexBuffer - > UpdateData ( vertex3fArray , 0 , numVertices ) ;
2013-11-15 22:55:46 +00:00
// == Delete HBR
// Can now delete the hbrMesh as we will only be referencing the farMesh from this point on
delete hbrMesh ;
hbrMesh = NULL ;
2013-11-13 22:49:33 +00:00
// == Subdivide OpenSubdiv mesh ==========================
computeController . Refine ( computeContext , farMesh - > GetKernelBatches ( ) , vertexBuffer , varyingBuffer ) ;
computeController . Synchronize ( ) ;
// == Convert subdivided OpenSubdiv mesh to MFnMesh Data outputMesh =============
// Create New Mesh Data Object
MFnMeshData newMeshData ;
MObject newMeshDataObj = newMeshData . create ( & returnStatus ) ;
MCHECKERR ( returnStatus , " ERROR creating outputData " ) ;
// Create out mesh
returnStatus = convertOsdFarToMayaMeshData ( farMesh , vertexBuffer , subdivisionLevel , inMeshFn , newMeshDataObj ) ;
MCHECKERR ( returnStatus , " ERROR convertOsdFarToMayaMesh " ) ;
// Propagate objectGroups from inMesh to outMesh (for per-facet shading, etc)
2014-03-13 21:49:19 +00:00
returnStatus = createSmoothMesh_objectGroups ( farMesh , inMeshFn , inMeshDat , newMeshData , subdivisionLevel ) ;
2013-11-13 22:49:33 +00:00
// Write to output plug
MDataHandle outMeshH = data . outputValue ( a_output , & returnStatus ) ;
MCHECKERR ( returnStatus , " ERROR getting polygon data handle \n " ) ;
outMeshH . set ( newMeshDataObj ) ;
2014-01-22 22:26:42 +00:00
2013-11-26 01:12:57 +00:00
int isolation = std : : min ( 10 , ( int ) ceil ( maxCreaseSharpness ) + 1 ) ;
data . outputValue ( a_recommendedIsolation ) . set ( isolation ) ;
2013-11-13 22:49:33 +00:00
// == Cleanup OSD ============================================
// REVISIT: Re-add these deletes
delete ( vertexBuffer ) ;
delete ( varyingBuffer ) ;
delete ( computeContext ) ;
delete ( farMesh ) ;
// note that the subd mesh was created (see the section below if !createdSubdMesh)
createdSubdMesh = true ;
}
}
// Pass-through inMesh to outMesh if not created the subd mesh
if ( ! createdSubdMesh ) {
MDataHandle outMeshH = data . outputValue ( a_output , & returnStatus ) ;
returnStatus = outMeshH . copy ( data . outputValue ( a_inputPolymesh , & returnStatus ) ) ;
MCHECKERR ( returnStatus , " ERROR getting polygon data handle \n " ) ;
}
// Clean up Maya Plugs
data . setClean ( plug ) ;
}
else {
// Unhandled parameter in this compute function, so return MS::kUnknownParameter
// so it is handled in a parent compute() function.
return MS : : kUnknownParameter ;
}
return MS : : kSuccess ;
}
// Creator
//
// Description:
// this method exists to give Maya a way to create new objects
2013-11-13 23:27:43 +00:00
// of this type.
2013-11-13 22:49:33 +00:00
//
// Return Value:
// a new object of this type
//
2013-11-15 22:55:46 +00:00
void * OsdPolySmooth : : creator ( ) {
2013-11-13 22:49:33 +00:00
return new OsdPolySmooth ;
}
// Create and Add Attributes
//
// Description:
// This method is called to create and initialize all of the attributes
2013-11-13 23:27:43 +00:00
// and attribute dependencies for this node type. This is only called
2013-11-13 22:49:33 +00:00
// once when the node type is registered with Maya.
//
// Return Values:
// MS::kSuccess
// MS::kFailure
2013-11-13 23:27:43 +00:00
//
2013-11-15 22:55:46 +00:00
MStatus OsdPolySmooth : : initialize ( ) {
2013-11-13 22:49:33 +00:00
MStatus stat ;
MFnCompoundAttribute cAttr ;
MFnEnumAttribute eAttr ;
MFnGenericAttribute gAttr ;
MFnLightDataAttribute lAttr ;
MFnMatrixAttribute mAttr ;
MFnMessageAttribute msgAttr ;
MFnNumericAttribute nAttr ;
MFnTypedAttribute tAttr ;
MFnUnitAttribute uAttr ;
2013-11-13 23:27:43 +00:00
2013-11-13 22:49:33 +00:00
// MAYA_NODE_BUILDER:BEG [ATTRIBUTE CREATION] ==========
// a_inputPolymesh : This is a description for this attribute
a_inputPolymesh = tAttr . create ( " inputPolymesh " , " ip " , MFnData : : kMesh , MObject : : kNullObj , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::inputPolymesh " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::inputPolymesh.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::inputPolymesh.setWritable() " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setHidden ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::inputPolymesh.setHidden() " ) ;
stat = addAttribute ( a_inputPolymesh ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_inputPolymesh) " ) ;
// a_output : This is a description for this attribute
a_output = tAttr . create ( " output " , " out " , MFnData : : kMesh , MObject : : kNullObj , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::output " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::output.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setWritable ( false ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::output.setWritable() " ) ;
2013-11-13 23:27:43 +00:00
stat = tAttr . setHidden ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::output.setHidden() " ) ;
stat = addAttribute ( a_output ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_output) " ) ;
// a_subdivisionLevels : The number of recursive quad subdivisions to perform on each face.
a_subdivisionLevels = nAttr . create ( " subdivisionLevels " , " sl " , MFnNumericData : : kInt , 0.0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::subdivisionLevels " ) ;
stat = nAttr . setDefault ( 2 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setDefault(2) " ) ;
stat = nAttr . setMin ( 0 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setMin(0) " ) ;
stat = nAttr . setMax ( 10 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setMax(10) " ) ;
stat = nAttr . setSoftMax ( 4 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setSoftMax(4) " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::subdivisionLevels.setWritable() " ) ;
stat = addAttribute ( a_subdivisionLevels ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_subdivisionLevels) " ) ;
2013-11-26 01:12:57 +00:00
// a_recommendedIsolation : The number of recursive quad subdivisions to perform on each face.
a_recommendedIsolation = nAttr . create ( " recommendedIsolation " , " ri " , MFnNumericData : : kInt , 0.0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::recommendedIsolation " ) ;
stat = nAttr . setDefault ( 2 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setDefault(0) " ) ;
stat = nAttr . setMin ( 0 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setMin(0) " ) ;
stat = nAttr . setMax ( 10 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setSoftMax(10) " ) ;
stat = nAttr . setReadable ( true ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setReadable() " ) ;
stat = nAttr . setWritable ( false ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setWritable() " ) ;
stat = nAttr . setHidden ( false ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::recommendedIsolation.setHidden() " ) ;
stat = addAttribute ( a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_recommendedIsolation) " ) ;
2013-11-13 22:49:33 +00:00
// a_vertBoundaryMethod : Controls how boundary edges and vertices are interpolated. <ul> <li>Smooth, Edges: Renderman: InterpolateBoundaryEdgeOnly</li> <li>Smooth, Edges and Corners: Renderman: InterpolateBoundaryEdgeAndCorner</li> </ul>
a_vertBoundaryMethod = eAttr . create ( " vertBoundaryMethod " , " vbm " , 0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::vertBoundaryMethod " ) ;
stat = eAttr . addField ( " Interpolate Edges " , k_BoundaryMethod_InterpolateBoundaryEdgeOnly ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::vertBoundaryMethod.addField(Interpolate Edges, k_BoundaryMethod_InterpolateBoundaryEdgeOnly) " ) ;
stat = eAttr . addField ( " Interpolate Edges And Corners " , k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::vertBoundaryMethod.addField(Interpolate Edges And Corners, k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner) " ) ;
stat = eAttr . setDefault ( k_BoundaryMethod_InterpolateBoundaryEdgeOnly ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::vertBoundaryMethod.setDefault(k_BoundaryMethod_InterpolateBoundaryEdgeOnly) " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::vertBoundaryMethod.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::vertBoundaryMethod.setWritable() " ) ;
stat = addAttribute ( a_vertBoundaryMethod ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_vertBoundaryMethod) " ) ;
// a_fvarBoundaryMethod : Controls how boundaries are treated for face-varying data (UVs and Vertex Colors). <ul> <li>Bi-linear (None): Renderman: InterpolateBoundaryNone</li> <li>Smooth, (Edge Only): Renderman: InterpolateBoundaryEdgeOnly</li> <li>Smooth, (Edges and Corners: Renderman: InterpolateBoundaryEdgeAndCorner</li> <li>Smooth, (ZBrush and Maya "Smooth Internal Only"): Renderman: InterpolateBoundaryAlwaysSharp</li> </ul>
a_fvarBoundaryMethod = eAttr . create ( " fvarBoundaryMethod " , " fvbm " , 0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::fvarBoundaryMethod " ) ;
stat = eAttr . addField ( " Bi-linear (None) " , k_BoundaryMethod_InterpolateBoundaryNone ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.addField(Bi-linear (None), k_BoundaryMethod_InterpolateBoundaryNone) " ) ;
stat = eAttr . addField ( " Smooth (Edge Only) " , k_BoundaryMethod_InterpolateBoundaryEdgeOnly ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.addField(Smooth (Edge Only), k_BoundaryMethod_InterpolateBoundaryEdgeOnly) " ) ;
stat = eAttr . addField ( " Smooth (Edge and Corner) " , k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.addField(Smooth (Edge and Corner), k_BoundaryMethod_InterpolateBoundaryEdgeAndCorner) " ) ;
stat = eAttr . addField ( " Smooth (Always Sharp) " , k_BoundaryMethod_InterpolateBoundaryAlwaysSharp ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.addField(Smooth (Always Sharp), k_BoundaryMethod_InterpolateBoundaryAlwaysSharp) " ) ;
stat = eAttr . setDefault ( k_BoundaryMethod_InterpolateBoundaryNone ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.setDefault(k_BoundaryMethod_InterpolateBoundaryNone) " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarBoundaryMethod.setWritable() " ) ;
stat = addAttribute ( a_fvarBoundaryMethod ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_fvarBoundaryMethod) " ) ;
2013-11-13 23:27:43 +00:00
// a_fvarPropagateCorners :
2013-11-13 22:49:33 +00:00
a_fvarPropagateCorners = nAttr . create ( " fvarPropagateCorners " , " fvpc " , MFnNumericData : : kBoolean , 0.0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::fvarPropagateCorners " ) ;
stat = nAttr . setDefault ( false ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarPropagateCorners.setDefault(false) " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarPropagateCorners.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::fvarPropagateCorners.setWritable() " ) ;
stat = addAttribute ( a_fvarPropagateCorners ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_fvarPropagateCorners) " ) ;
// a_smoothTriangles : Apply a special subdivision rule be applied to all triangular faces that was empirically determined to make triangles subdivide more smoothly.
a_smoothTriangles = nAttr . create ( " smoothTriangles " , " stri " , MFnNumericData : : kBoolean , 0.0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::smoothTriangles " ) ;
stat = nAttr . setDefault ( true ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::smoothTriangles.setDefault(true) " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::smoothTriangles.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = nAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::smoothTriangles.setWritable() " ) ;
stat = addAttribute ( a_smoothTriangles ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_smoothTriangles) " ) ;
// a_creaseMethod : Controls how boundary edges and vertices are interpolated. <ul> <li>Normal</li> <li>Chaikin: Improves the appearance of multiedge creases with varying weight</li> </ul>
a_creaseMethod = eAttr . create ( " creaseMethod " , " crm " , 0 , & stat ) ;
MCHECKERR ( stat , " cannot create OsdPolySmooth::creaseMethod " ) ;
stat = eAttr . addField ( " Normal " , k_creaseMethod_normal ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::creaseMethod.addField(Normal, k_creaseMethod_normal) " ) ;
stat = eAttr . addField ( " Chaikin " , k_creaseMethod_chaikin ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::creaseMethod.addField(Chaikin, k_creaseMethod_chaikin) " ) ;
stat = eAttr . setDefault ( 0 ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::creaseMethod.setDefault(0) " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setReadable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::creaseMethod.setReadable() " ) ;
2013-11-13 23:27:43 +00:00
stat = eAttr . setWritable ( true ) ;
2013-11-13 22:49:33 +00:00
MCHECKERR ( stat , " cannot OsdPolySmooth::creaseMethod.setWritable() " ) ;
stat = addAttribute ( a_creaseMethod ) ;
MCHECKERR ( stat , " cannot OsdPolySmooth::addAttribute(a_creaseMethod) " ) ;
// MAYA_NODE_BUILDER:END [ATTRIBUTE CREATION] ==========
// Set up a dependency between the input and the output. This will cause
// the output to be marked dirty when the input changes. The output will
// then be recomputed the next time the value of the output is requested.
//
// MAYA_NODE_BUILDER:BEG [ATTRIBUTE DEPENDS] ==========
stat = attributeAffects ( a_creaseMethod , a_output ) ;
MCHECKERR ( stat , " cannot have attribute creaseMethod affect output " ) ;
stat = attributeAffects ( a_inputPolymesh , a_output ) ;
MCHECKERR ( stat , " cannot have attribute inputPolymesh affect output " ) ;
stat = attributeAffects ( a_subdivisionLevels , a_output ) ;
MCHECKERR ( stat , " cannot have attribute subdivisionLevels affect output " ) ;
stat = attributeAffects ( a_smoothTriangles , a_output ) ;
MCHECKERR ( stat , " cannot have attribute smoothTriangles affect output " ) ;
stat = attributeAffects ( a_fvarPropagateCorners , a_output ) ;
MCHECKERR ( stat , " cannot have attribute fvarPropagateCorners affect output " ) ;
stat = attributeAffects ( a_vertBoundaryMethod , a_output ) ;
MCHECKERR ( stat , " cannot have attribute vertBoundaryMethod affect output " ) ;
stat = attributeAffects ( a_fvarBoundaryMethod , a_output ) ;
MCHECKERR ( stat , " cannot have attribute fvarBoundaryMethod affect output " ) ;
2013-11-26 01:12:57 +00:00
stat = attributeAffects ( a_creaseMethod , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute creaseMethod affect .si output " ) ;
stat = attributeAffects ( a_inputPolymesh , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute inputPolymesh affect .si output " ) ;
stat = attributeAffects ( a_subdivisionLevels , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute subdivisionLevels affect .si output " ) ;
stat = attributeAffects ( a_smoothTriangles , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute smoothTriangles affect .si output " ) ;
stat = attributeAffects ( a_fvarPropagateCorners , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute fvarPropagateCorners affect .si output " ) ;
stat = attributeAffects ( a_vertBoundaryMethod , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute vertBoundaryMethod affect .si output " ) ;
stat = attributeAffects ( a_fvarBoundaryMethod , a_recommendedIsolation ) ;
MCHECKERR ( stat , " cannot have attribute fvarBoundaryMethod affect .si output " ) ;
2013-11-13 22:49:33 +00:00
// MAYA_NODE_BUILDER:END [ATTRIBUTE DEPENDS] ==========
return MS : : kSuccess ;
}
// ==========================================
// Plugin
// ==========================================
MStatus initializePlugin ( MObject obj )
{
2013-11-15 22:55:46 +00:00
MStatus status = MS : : kSuccess ;
MFnPlugin plugin ( obj , " OsdPolySmooth " , " 1.0 " , " Any " ) ;
status = plugin . registerNode (
OsdPolySmooth : : typeNameStr ,
OsdPolySmooth : : id ,
OsdPolySmooth : : creator ,
OsdPolySmooth : : initialize ) ;
MCHECKERR ( status , " registerNode " ) ;
// Source UI scripts
MString path = plugin . loadPath ( ) + " /osdPolySmooth.mel " ;
if ( not MGlobal : : sourceFile ( path ) ) {
path = " osdPolySmooth.mel " ;
if ( not MGlobal : : sourceFile ( path ) ) {
2013-11-13 22:49:33 +00:00
MGlobal : : displayWarning ( " Failed to source osdPolySmooth.mel. " ) ;
}
2013-11-15 22:55:46 +00:00
}
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
// RegisterUI
status = plugin . registerUI ( " osdPolySmooth_addUI() " , " osdPolySmooth_removeUI() " ) ;
MCHECKERR ( status , " registerUI " ) ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
return status ;
2013-11-13 22:49:33 +00:00
}
MStatus uninitializePlugin ( MObject obj )
{
2013-11-15 22:55:46 +00:00
MStatus returnStatus = MS : : kSuccess ;
MFnPlugin plugin ( obj ) ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
returnStatus = plugin . deregisterNode ( OsdPolySmooth : : id ) ;
MCHECKERR ( returnStatus , " deregisterNode " ) ;
2013-11-13 22:49:33 +00:00
2013-11-15 22:55:46 +00:00
return returnStatus ;
2013-11-13 22:49:33 +00:00
}