這篇文章屬于典型的剝洋蔥文,由表及里,逐步引入新的知識點(diǎn),挖掘最本質(zhì)的原因。這篇文的邏輯是先假設(shè)再證明,按照這個(gè)思路去閱讀會(huì)比較輕松。
Maya里的GPU Cache導(dǎo)入的幾何體為什么不能編輯頂點(diǎn)?這可以算是一個(gè)高頻問題了,這個(gè)問題可以轉(zhuǎn)換為:GPU Cache導(dǎo)入的幾何體為什么不能編輯Mesh(不僅不能編輯頂點(diǎn),為它添加bevel一類的節(jié)點(diǎn)也不可以)?實(shí)際上這個(gè)問題在Maya的幫助文檔中是有明確答案的。
我們來看看官方是如何解釋的:
GPU caches are Alembic-based files that are optimized for fast playback performance in Maya. These performance gains come from the way GPU cache files are evaluated. The GPU cache node routes cached data directly to the system graphics card for processing, bypassing Maya dependency graph evaluation.
GPU cache是由Alembic文件派生出來的一種文件格式,為獲取Maya中快速播放的性能專門做了優(yōu)化。這些性能的提升來自于GPU cache文件求值的方式。GPU cache節(jié)點(diǎn)會(huì)避開Maya的dependency graph求值機(jī)制,把緩存數(shù)據(jù)直接發(fā)送到系統(tǒng)的圖形卡接口進(jìn)行處理。
現(xiàn)今的圖形卡都有著比cpu夸張很多的線程數(shù)量,在并行計(jì)算的應(yīng)用上有著極大優(yōu)勢,而圖形處理的計(jì)算幾乎都是線性計(jì)算,與圖形卡的多線程簡直是天作之合,GPU cache利用了圖形卡的優(yōu)勢,把GPU cache文件中的緩存數(shù)據(jù)直接發(fā)送給圖形卡進(jìn)行計(jì)算,效率自然與基于傳統(tǒng)計(jì)算框架cpu《--》memory的DG(dependency graph)機(jī)制不可同日而語。
但仔細(xì)一想,這段話有一個(gè)漏洞:雖然GPU cache導(dǎo)入的geometry無法編輯頂點(diǎn),但整體移動(dòng)還是可以的。這就與官方的解釋相悖了,說好了會(huì)避開DG求值機(jī)制呢?
為了在這個(gè)問題上做更深層次的分析,我們插播一個(gè)DAG的小廣告,快速的了解一下DAG的概念:
In Maya, a directed acyclic graph (DAG), defines elements such as the position, orientation, and scale of geometry. The DAG is composed of two types of DAG nodes, transforms and shapes. Maya‘s Directed Acyclic Graph (DAG) scene architecture, organized as a tree of transform nodes and shape nodes.
在Maya中,有向非循環(huán)圖(Directed Acyclic Graph,DAG),定義了諸如幾何體的位置、方向和大小等元素。有向非循環(huán)圖由兩種DAG節(jié)點(diǎn)構(gòu)成,分別是Transform和Shape。Maya的有向非循環(huán)圖(Directed Acyclic Graph,DAG)場景結(jié)構(gòu)就是由transform和shape節(jié)點(diǎn)組成的一顆層級樹。
A DAG node is simply an entity in the DAG. It may have and know about parents, siblings, and children, but it does not necessarily know about transformations or geometry. Transforms and Shapes are two types of nodes derived from a DAG node. A transform node is a type of DAG node which handles transformations (translate, rotate, and scale), while a shape node is a type of DAG node which handles geometry. A shape node does not maintain transformation information, and geometry cannot be hung below a transform node. This means that any piece of geometry requires two DAG nodes above it, a shape node immediately above it, and a transform node above the shape node.
DAG節(jié)點(diǎn)就是有向非循環(huán)圖中的實(shí)體,該節(jié)點(diǎn)有且知道有哪些父節(jié)點(diǎn)、鄰節(jié)點(diǎn)和子節(jié)點(diǎn),但它并不必需要知道相關(guān)的transform信息和幾何體信息。Transform和Shape是兩種派生自DAG節(jié)點(diǎn)的節(jié)點(diǎn),Transform節(jié)點(diǎn)是一種能處理transformation(譯作變換,屬于線性計(jì)算,包含translate、rotate、scale信息)信息的DAG節(jié)點(diǎn),Shape節(jié)點(diǎn)是一種能處理geometry(幾何體)信息的DAG節(jié)點(diǎn)。Shape節(jié)點(diǎn)不會(huì)維護(hù)transformation信息,geometry也不能放在Tranform節(jié)點(diǎn)下面。這意味著任意一片geometry都需要有兩個(gè)DAG節(jié)點(diǎn)放在它的層級之上,Shape節(jié)點(diǎn)放置在geometry上面,transform放置在Shape節(jié)點(diǎn)上面,通過這種方式構(gòu)造出一個(gè)層級關(guān)系樹,供DAG使用。
Geometry層級示例:
Transform Node --》 處理transformation信息
|
Shape Node --》 處理下方Geometry信息
|
Geometry Data --》 可能存放在內(nèi)存中,也可能存放在GPU顯存中
根據(jù)DAG的概念,我們可以推論:對于GPU cache導(dǎo)入進(jìn)來的geometry來說,必然會(huì)為它創(chuàng)建兩個(gè)DAG節(jié)點(diǎn),一個(gè)是Transform Node,一個(gè)是Shape Node。其中Tramsform節(jié)點(diǎn)中的tramsformation信息是可以編輯的,可以接受外部的位移操作,而Shape節(jié)點(diǎn)持有的geometry信息是不可編輯的。
但現(xiàn)在這個(gè)推論還是不夠深入,為什么Alembic Cache既能編輯transformation又能編輯geometry信息,唯獨(dú)GPU cache只能編輯transformation?
下面我們再引入DG(dependency graph)的概念,更進(jìn)一步的,去Maya的底層找答案。
The dependency graph lies at the heart of Maya. It maintains the construction history of the scene: a record of what operations you have applied in what order. The graph is made up of a series of interconnected nodes, each of which encapsulates a single operation or a single set of calculations. Each node accepts a limited set of well-defined input data, performs its calculations based on that data, and produces one or more output values.
Dependency graph(依賴圖)位于Maya核心,它維護(hù)著場景的構(gòu)造歷史,在這里,構(gòu)造歷史指的是你以某種順序應(yīng)用的操作記錄。該圖由一系列相互連接的節(jié)點(diǎn)組成,每一個(gè)節(jié)點(diǎn)封裝一個(gè)操作或一組計(jì)算。每個(gè)節(jié)點(diǎn)接受有限的一組定義好的輸入數(shù)據(jù),再根據(jù)該數(shù)據(jù)執(zhí)行計(jì)算,并生成一個(gè)或多個(gè)輸出值。
Most objects in Maya are dependency graph nodes, or networks of nodes (several nodes connected together)。 For example, DAG nodes are dependency graph nodes, and shaders are networks of nodes.
Maya中的大多數(shù)對象都是依賴圖節(jié)點(diǎn)或是由多個(gè)節(jié)點(diǎn)連接到一起構(gòu)成的子網(wǎng)絡(luò)。例如,DAG節(jié)點(diǎn)是依賴圖節(jié)點(diǎn),著色器是節(jié)點(diǎn)網(wǎng)絡(luò)。
Certain events cause the dependency graph to re-evaluate itself, examples being screen refresh, and animation playback. During a refresh for example, the system will walk down the DAG and for each DAG node check to see whether it needs to be re-evaluated.
某些事件會(huì)觸發(fā)依賴圖重新對自己求值,例如屏幕刷新和動(dòng)畫回放。在屏幕刷新期間,Maya底層將遍歷DAG層級結(jié)構(gòu),并檢查每一個(gè)經(jīng)過的DAG節(jié)點(diǎn)是否需要重新求值。
由上可知,Transform和Shape節(jié)點(diǎn)實(shí)際上就是DG節(jié)點(diǎn)的一種,我們可以猜測,“The GPU cache node routes cached data directly to the system graphics card for processing, bypassing Maya dependency graph evaluation. ”這句話指的是,在viewport顯示geometry的時(shí)候,GPU cache構(gòu)造的Shape node所持有的geometry數(shù)據(jù)會(huì)直接發(fā)送到系統(tǒng)的圖形卡接口進(jìn)行直接處理,避開DG的求值;而GPU cache構(gòu)造的Transform node則依然會(huì)進(jìn)入DG的求值機(jī)制,用戶可以像使用Polygon一樣,在Transform node上添加歷史節(jié)點(diǎn),比如Time node來key關(guān)鍵幀。
實(shí)際上,在GPU cache的開發(fā)文檔中還提到了這樣一句:
The gpuCache node is a Shape node that holds baked animated geometry in memory.The node can stream the animated geometry to the viewport without triggering any DG evaluation of geometry attributes (mesh, nurbs or subd surface data)。
gpuCache 節(jié)點(diǎn)是一個(gè)在內(nèi)存中持有幾何體數(shù)據(jù)的Shape節(jié)點(diǎn),當(dāng)然這個(gè)幾何體數(shù)據(jù)是烘焙后的、有動(dòng)畫的幾何體數(shù)據(jù)。gpuCahe節(jié)點(diǎn)可以把幾何體數(shù)據(jù)傳遞給viewport(就是hardware renderer或者viewport2.0),而不會(huì)觸發(fā)任何幾何體屬性的DG求值行為。
這條說明就充分佐證了我們的猜測,這個(gè)解釋無疑比文章最開始的答案要更深入。但我們依然還有一個(gè)疑惑,這種特性是如何實(shí)現(xiàn)的呢?為什么Alembic Cache導(dǎo)入abc文件可以編輯頂點(diǎn),GPU Cache就不行?下面我們打破砂鍋問到底,去GPU Cache的源碼里尋找答案。
GPU cache的源碼是公開的,你可以通過下載對應(yīng)Maya版本的devkit來獲取,附個(gè)鏈接:Maya2017 devkit下載地址。現(xiàn)在我們閱讀GPU cache的源碼來驗(yàn)證這個(gè)猜測是否為真。
首先,在doGpuCacheExportArgList.mel中有這樣一段代碼可以展示GPU cache創(chuàng)建DAG節(jié)點(diǎn)的過程:
3string $xformNode = `createNode transform -name $nodeName`;
createNode gpuCache -name ($nodeName + “Shape”) -parent $xformNode;
setAttr “.cacheFileName” -type “string” $fileFullPath;
其中第一行創(chuàng)建transform節(jié)點(diǎn);第二行創(chuàng)建gpuCache節(jié)點(diǎn),gpuCache節(jié)點(diǎn)就是shape節(jié)點(diǎn),下面會(huì)講到;第三行為gpuCache節(jié)點(diǎn)制定abc文件路徑。這就印證了我們在DAG環(huán)節(jié)的推論,GPU cache導(dǎo)入abc數(shù)據(jù)時(shí)會(huì)分別創(chuàng)建一個(gè)transform節(jié)點(diǎn),一個(gè)shape節(jié)點(diǎn)。而transform節(jié)點(diǎn)就是Maya內(nèi)置的transform節(jié)點(diǎn),所以當(dāng)然可以提供位移、旋轉(zhuǎn)、縮放等操作。
我們再看下一段代碼,在gpuCacheShapeNode.cpp中有如下定義:
這段代碼這足以證明gpuCache是一個(gè)標(biāo)準(zhǔn)的Shape node。倒數(shù)第一行意為ShapeNode的類型名是“gpuCache”,倒數(shù)第二行意為ShapeNode繼承自MPxSurfaceShape。這這里簡單介紹一下MPxSurfaceShape,該類主要用于實(shí)現(xiàn)新的shape,并且有可選、可操作的組件,還有與Maya中默認(rèn)shape相似的行為。也就是說,ShapeNode是可以提供與默認(rèn)Shape相似功能的,比如,在viewport2.0中能顯示并編輯點(diǎn)線面,能添加bevel一類的歷史節(jié)點(diǎn)。
但顯然gpuCache并沒有顯示頂點(diǎn),在被選中時(shí),顯示的邊緣也是dashed line,不是正常的實(shí)線。在這里我們應(yīng)該去查看MPxSurfaceShapeUI類,MPxSurfaceShape和MPxSurfaceShapeUI是需要一并實(shí)現(xiàn)的,MPxSurfaceShape主要用于操作幾何體數(shù)據(jù),MPxSurfaceShapeUI則用于顯示幾何體。在gpuCache中這兩個(gè)類分別由ShapeNode、ShapeUI實(shí)現(xiàn)。
在ShapeNode中沒有實(shí)現(xiàn)setInternalValue()方法,而MPxSurfaceShape類中對頂點(diǎn)的編輯都是通過setInternalValue()來處理的,顯然ShapeNode不具備編輯頂點(diǎn)的接口,自然gpuCache也就無法編輯頂點(diǎn)了;
在ShapeUI只有drawBoundingBox()、drawWireframe()、drawShaded()三個(gè)繪制函數(shù),分別繪制boundingbox、模型線框及表面。在這個(gè)類里并沒有找到繪制頂點(diǎn)的函數(shù),這就是你在Viewport 2.0中無法看到gpuCache頂點(diǎn)的原因,無法看到頂點(diǎn),自然也無法操作頂點(diǎn)。另外drawWireframe()函數(shù)中也指定了線框的繪制方式:kLineStippleShortDashed,強(qiáng)制Maya以虛線的方式繪制線框。
可以斷定,gpuCache的源碼中一定重寫相關(guān)方法。繼續(xù)閱讀源碼能夠看到在gpuCacheSubSceneOverrride.h文件中有如下聲明:
1class SubSceneOverride : public MHWRender::MPxSubSceneOverride
MPxSubSceneOverride是Viewport 2.0的繪圖基類,該類允許用戶完整的定義渲染單元(MRenderItem),通過update()方法將計(jì)算后的geometry數(shù)據(jù)添加到MRenderItem,再通過繪圖函數(shù)進(jìn)行繪制。該類主要用于在使用Viewport 2.0時(shí)繪制sub-scene類型的DAG節(jié)點(diǎn)。SubSceneOverride子類在gpuCachePluginMain.cpp中通過MHWRender::MDrawRegistry::registerSubSceneOverrideCreator()方法注冊到了Maya中,并與ShapeNode建立關(guān)系。這就意味著一旦創(chuàng)建了gpuCache的DAG Shape Node實(shí)例,就會(huì)有SubSceneOverride負(fù)責(zé)它在Viewport 2.0中的繪制工作。當(dāng)然具體的點(diǎn)線面繪制工作由Viewport 2.0來執(zhí)行,SubSceneOverride主要負(fù)責(zé)獲取renderitem,并將處理過的renderitem推送至Viewport 2.0。
而幾何體數(shù)據(jù)就是在MPxSubSceneOverride中發(fā)送到GPU memory中的。這個(gè)過程會(huì)涉及到更多的開發(fā)細(xì)節(jié),以后有時(shí)間再做分享吧。
另外,為什么不能在gpuCache上添加諸如bevel之類的歷史節(jié)點(diǎn)呢?答案很簡單,因?yàn)間puCache節(jié)點(diǎn)沒有outmesh屬性,bevel這類節(jié)點(diǎn)是無法連上去的。
以上,就是gpuCache不能編輯頂點(diǎn)的真相。
評論
查看更多