물론 플러그인의 계산 퍼포먼스를 올리기위한 방법이 좀더 있을거라고 생각은 되지만
아래의 기본적인 deformer를 불러와 마야에서 sphere subdivision 200/200에
적용한 결과는 암담하다.
무려 5fps의 속도로 거의 쓰레기같은 계산 퍼포먼스를 보여준다.
( 마야에서 제공하는 기본 디포머들은 저정도 subdivision엔 거의 퍼포먼스 저하가 없다.
물론 sphere 딱 하나로만 계산했을 경우지만,, 어쨌든 거기에 비하면 전혀 쓸모없는 deformer라고 볼 수있다. )
아무리 python이라지만 나름 API이름을 달고 있는데
마치 기본 python 스크립트로 script단에서 class로 버텍스를 움직이는 것과 별반 달라보이지 않는
퍼포먼스를 보여주니 매우 실망스럽다.
이 정도 테스트 해봤으면 파이썬으로 속도와 연관되는 플러그인을 개발하는건
거의 시간을 버리는 거라 결론되어 진다.
maya python - 아주 단순 반복작업과 UI정도에 사용
maya python API - 버전을 타지않고 다소 쉬운코딩때문에 가벼운 계산의 노드에서만 사용
ex) 가이드용 노드 등
maya API - 속도와 관계된 모든 플러그인에 사용
해야할거 같다..
즉,
아,, 공부하기 싫어 시방
////////////////////////////////////////////////////
c++로 넘어가면 좀 다를 순 있겠지만
pythonAPI로 노드를 구성하는 코딩이 생각보다
복잡하지 않은건 다행이다.
각 플러그인들 마다 반복되는 구문들을 제외하면
개발시간이 오래걸리지는 않는듯.
script에서 dag에서 겹치는 이름들과 namesapce문제, freeze문제
world, local시에 달라지는 좌표들, 간단한 계산 구문을 짤려고 해도 expression이 아니면
수천개의 muliply, plus노드들을 만들고 관리해야하는 문제들
때문에 어느 상황에서나 완벽하게
구동하는 script를 짜려면 말도 못하게 쓸데없는 노력이 들어가는걸 생각한다면 이정도야,,
#-*- coding: utf-8 -*-
import sys
import maya.OpenMaya as om
import maya.OpenMayaMPx as omMPx
import math
nodeName = 'RippleDeformer'
nodeId = om.MTypeId(0x102fff)
class Ripple( omMPx.MPxDeformerNode ):
'''
Commands ----> MPxCommand
Custom ----> MPxNode
Deformer ----> MPxDeformerNode
'''
mObj_Amplitude = om.MObject()
mObj_Displace = om.MObject()
def __init__( self ):
omMPx.MPxDeformerNode.__init__( self )
def deform( self, dataBlock,geoIterator, matrix, geometryIndex ):
input = omMPx.cvar.MPxDeformerNode_input
#____ 1. input Array Attribute에 handle을 붙인다
dataHandleInputArray = dataBlock.inputArrayValue( input )
#____ 2. 각각의 element로 넘어간다
dataHandleInputArray.jumpToElement( geometryIndex )
#____ 3. Attach a handle to specific data block
dataHandleInputElement = dataHandleInputArray.inputValue()
#____ 4. Reach to the child - inputGeom
inputGeom = omMPx.cvar.MPxDeformerNode_inputGeom
dataHandleInputGeom = dataHandleInputElement.child( inputGeom )
inMesh = dataHandleInputGeom.asMesh()
#____ Envelope
envelope = omMPx.cvar.MPxDeformerNode_envelope
dataHandleEnvelope = dataBlock.inputValue( envelope )
envelopeValue = dataHandleEnvelope.asFloat()
#____ Amplitude
dataHandleAmplitude = dataBlock.inputValue( Ripple.mObj_Amplitude )
amplitudeValue = dataHandleAmplitude.asFloat()
#____ Displace
dataHandleDisplace = dataBlock.inputValue( Ripple.mObj_Displace )
displaceValue = dataHandleDisplace.asFloat()
mFloatVectorArray_normal = om.MFloatVectorArray()
mFnMesh = om.MFnMesh( inMesh )
mFnMesh.getVertexNormals( False, mFloatVectorArray_normal, om.MSpace.kObject )
while( not geoIterator.isDone() ):
pointPosition = geoIterator.position()
pointPosition.x = pointPosition.x + math.sin( geoIterator.index() + displaceValue ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].x * envelopeValue
pointPosition.y = pointPosition.y + math.sin( geoIterator.index() + displaceValue ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].y * envelopeValue
pointPosition.z = pointPosition.z + math.sin( geoIterator.index() + displaceValue ) * amplitudeValue * mFloatVectorArray_normal[ geoIterator.index()].z * envelopeValue
geoIterator.setPosition( pointPosition )
geoIterator.next()
def deformerCreator():
nodePtr = omMPx.asMPxPtr( Ripple() )
return nodePtr
def nodeInitializer():
'''
구성순서
Create Attributes
Attach Attributes
Design Circuitry
'''
#____Create Attributes
mFnAttr = om.MFnNumericAttribute()
Ripple.mObj_Amplitude = mFnAttr.create( 'AmplitudeValue', 'AmplitudeVal',
om.MFnNumericData.kFloat, 0.0 )
mFnAttr.setKeyable( 1 )
mFnAttr.setMin( 0.0 )
mFnAttr.setMax( 1.0 )
Ripple.mObj_Displace = mFnAttr.create( 'DisplaceValue', 'DispVal',
om.MFnNumericData.kFloat, 0.0 )
mFnAttr.setKeyable( 1 )
mFnAttr.setMin( 0.0 )
mFnAttr.setMax( 10.0 )
#____Attach Attributes
Ripple.addAttribute( Ripple.mObj_Amplitude )
Ripple.addAttribute( Ripple.mObj_Displace )
'''
SWIG - simplified Wrapper Interface Generator
'''
#____Design Circuitry
outputGeom = omMPx.cvar.MPxDeformerNode_outputGeom
Ripple.attributeAffects( Ripple.mObj_Amplitude, outputGeom )
Ripple.attributeAffects( Ripple.mObj_Displace, outputGeom )
def initializePlugin( mobject ):
mplugin = omMPx.MFnPlugin( mobject )
try:
mplugin.registerNode( nodeName, nodeId, deformerCreator, nodeInitializer, omMPx.MPxNode.kDeformerNode )
except:
sys.stderr.write( 'Failed to register command: %s\n' %nodeName )
raise