整個繪製的流程可分為三個大階段
1. Initialization phase:
- 當一個 shader 被指定到物件上或是 shader 的資料被更改的時候,就需要透過 addGeometryRequirement() 這個函式來重新建立 shader 會用到的 geometry stream requirements。
- initialize() 一定要回傳一個 shader key 的字串,用來分別同一份 MPxShaderOverride 但是可以有很多的分身,每一個分身都可以有自已的參數,Maya 會將相同 shader key 的物件分到同一個群組中,所以只需做一次初始化的動作也可以將多個使用同樣 shader key 的物件做一次繪出的動作來增進效能。
2. Data update phase:
資料更新也可以分三個階段
- updateDG() : 將 input node 的 attribute 暫存起來
- updateDevice() : 將暫存起來的資料送到 graphics device
- endUpdate() : 清除暫存的資料
- 真正執行繪圖動作的指令都是做在這個函式中,回傳值是 true 的話就是繪圖成功,如果回傳 false,則 Maya 會使用預設的方法來畫這個物件。雖然說 shader 的設定和 render 的動作理論上可以在 draw() 的函式中一起作完,但 Maya 還是建議在 draw() 只做 shader 的設定,而在 drawGeometry() 再做最後 render 的動作。
- activateKey 和 terminateKey 可以用來處理擁有多個 shader key ( multi-pass rendering) 的 render item,由於有相同 shader key 的 shader 只需處理一次,所需的 render state 切換也只需要做一次,多個物件多個 shader 也不會造成額外的負擔。
以上是在繼承 MPxShaderOverride 時一定需要實作的函式,這樣一來 Maya 才知道要如何處理使用者自定的 MPxShaderOverride,我們以 devkit 中的 HwPhongShader 範例來看看要怎樣使用 MPxShaderOverride。
首先,在 registerNode 指定這個 phongShaderNode 要用什麼方法來畫,
const MString UserClassify( "shader/surface/utility/:drawdb/shader/surface/hwPhongShader:swatch/"+swatchName ); MFnPlugin plugin( obj, PLUGIN_COMPANY, "4.5", "Any"); status = plugin.registerNode( ... &UserClassify );
接下來就是註冊 phongShaderOverride
// Register a shader override for this node MHWRender::MDrawRegistry::registerShaderOverrideCreator( "drawdb/shader/surface/hwPhongShader", sHWPhongShaderRegistrantId, hwPhongShaderOverride::Creator);
在 hwPhongShader::initialize(),設定這個 hwPhongShader 的屬性
aColor = nAttr.createColor( "color", "c"); aTransparency = nAttr.create( "transparency", "tr", MFnNumericData::kFloat ); aDiffuseColor = nAttr.createColor( "diffuseColor", "dc" ); aSpecularColor = nAttr.createColor( "specularColor", "sc" ); aShininess = nAttr.createPoint( "shininess", "sh" );
當切換到 Viewport 2.0 時,第一個進入的函式就是
MString hwPhongShaderOverride::initialize(MObject object)
MString empty; addGeometryRequirement( MHWRender::MVertexBufferDescriptor( empty, MHWRender::MGeometry::kPosition, MHWRender::MGeometry::kFloat, 3)); addGeometryRequirement( MHWRender::MVertexBufferDescriptor( empty, MHWRender::MGeometry::kNormal, MHWRender::MGeometry::kFloat, 3));設定畫 geometry 時所需的資料 ( Position 和 Normal )
MString hwPhongShaderOverride::updateDG(MObject object) { // Get the hardware shader node from the MObject. fShaderNode = (hwPhongShader *) MPxHwShaderNode::getHwShaderNodePtr( object ); if (fShaderNode) fTransparency = fShaderNode->Transparency(); else fTransparency = 0.0f; }在 updateDG 中從 node 中更新了 fTransparency 的屬性資料
在 draw phase 中,我覺得最有用的就是 customDraw 和 printContextInformation 這二個 debug 用的函式,customDraw基本上是用來模擬
MHWRender::MPxShaderOverride::drawGeometry(context);所以透過這個函式我們就可以一窺 Maya 內部是如何實作 drawGeometry,至於 printContextInformation 是用來秀出 MDrawContext 的資訊,在 customDraw 的函式裡,可以看到如何拿到每一個 render item 的 geometry 資料,如何得到每一個 geometry 的 vertex 和 index buffer 的描述和內部資料,如何將 geometry 的資料 bind 到 OpenGL 到最後呼叫 glDrawElements 畫出這個 geometry,我個人是覺得在學習上非常的有幫助。
No comments:
Post a Comment