WebGL——osg框架學習三
今天繼續來Draw繪製的osg模組的學習,昨天我們學習的是StateBin渲染狀態樹節點類,今天我們來繼續學習下一個Draw的基礎類DrawableEntity渲染物件實體類。這個類和Drawable和繪製物件關係是並列的,DrawableEntity同樣有自己的DrawEntityActor。但是要注意的是,DrawableEntity和Drawable的功能是完全不同的,Drawable是繪製物件,包含geometry,transform,stateBin等幾何屬性空間屬性和狀態樹屬性;DrawableEntity則是管理render渲染實體的,和將要繪製的物件有著天壤之別。我們今天研究的是渲染管理模組,先理清概念。
接下來老辦法,鯽魚繼續帶大家看看DrawableEntity的建構函式,看看DrawableEntity的私有屬性有哪些。先貼出DrawableEntity建構函式的程式碼,由於採用的是require(module)方式引入依賴模組,所以鯽魚將DrawableEntity依賴的類也一起截出來,但在本文不加討論,以後會逐一介紹。
1 /* 2 渲染實體的可繪製物件 3 */ 4 let Drawable = require('./Drawable'); 5 let StateBin = require('./StateBin'); 6 7 let DrawableEntity = function(actor) { 8 Drawable.call(this, actor); 9 10 this._renderEntity = undefined;//關聯的渲染實體 11 this._material = undefined;//原本的顏色狀態 12 };
我們看到,DrawableEntity依賴Drawable可繪製物件類,依賴StateBin狀態樹節點類。前文已經討論過這兩個類,這裡不再敘述。我們還是來看DrawableEntity的屬性,this._renderEntity渲染實體屬性;this._material初始顏色屬性。我們接下來繼續看看DrawableEntity的成員函式。
1 reset: function () { 2 Drawable.prototype.reset.call(this); 3 4 this._renderEntity = undefined; 5 //this._radius = 0; 6 },
重置函式,重構原型物件中的reset函式,將私有成員this._renderEntity置空。
1 setRenderEntity: function (entity) { 2 this._renderEntity = entity; 3 },
設定渲染物件,設定私有成員this._renderEntity渲染實體。
1 getRenderEntity: function () { 2 return this._renderEntity; 3 },
獲取渲染物件。
1 setMaterial: function (s) { 2 this._material = s; 3 },
設定材質。
1 getMaterial: function () { 2 return this._material; 3 },
獲取材質屬性。
1 valid: function () { 2 // if(this._frameNumber === Drawable.FrameNumber){//已經繪製過,不再處理 3 // return false; 4 // } 5 //是否後面的不需再判斷了 6 7 if (!this._renderEntity.isShown()) {//隱藏的直接跳過 8 return false; 9 } 10 11 if (this._drawActor.getBaseCamera().isBoundingBoxCulled(this.getBoundingBox())) { 12 return false; 13 } 14 15 return true; 16 },
這個就類似Drawable了,valid成員函式用來判斷render渲染物件是否需要被繪製,這裡排除了2種不需要繪製的情況,第一種是標記為隱藏的渲染物件;第二種被剔除的則是包圍盒不在相機可視稜臺範圍內的可渲染物件,簡單來說就是不在當前視口範圍內的渲染物件。剩下的都是符合渲染條件的renderEntity,通過valid校驗。我們繼續看下一個函式。
1 isTransparent: function () { 2 let result = false; 3 let hasmaterial = false; 4 //this._stateBin不能變 5 this._statebin.removeChildren(); 6 this._curStatebin = this._statebin; 7 if (this._renderEntity !== undefined) {//有關聯的渲染實體,渲染實體的狀態優先順序最高 8 let statesets = this._renderEntity.getStateSets(); 9 let size = statesets.size; 10 if (size !== 0) { 11 statesets.forEach((stateset) => { 12 if (stateset) { 13 let mat = stateset.getMaterialAttribute();//一般不存在多個Material的情況,邏輯上避免,如果存在使用最後一個 14 if (mat) {//如果有Material,當前this._material就不再考慮 15 hasmaterial = true; 16 result = mat.isTransparent(); 17 } 18 this._curStatebin = this._curStatebin.addStateSetChild(stateset); 19 } 20 }); 21 } 22 } 23 24 //當前材質狀態 25 if (this._material) { 26 if (!hasmaterial) { 27 this._curStatebin = this._curStatebin.addStateSetChild(this._material); 28 let mat = this._material.getMaterialAttribute(); 29 if (mat) { 30 result = mat.isTransparent(); 31 } 32 } 33 } 34 35 return result; 36 },
該函式是用來判斷當前渲染物件是否為透明的材質物件。由於webgl和opengl中對透明材質的處理很特殊,要按照深度排序由遠到近依次繪製而且我們都是在非透明材質繪製完成後才繪製透明材質,否則材質混合會出問題,所以我們在管理renderEntity時一定要判斷渲染物件是否透明。這當中還要對當前渲染物件的StateSet狀態優先順序進行排序,其中判斷材質是否透明的函式是Material的成員函式,這個api是this._material.getMaterialAttribute().isTransparent()。我們再來看最後一個函式。
1 draw: function (glstate, preDrawable) {//過載 2 //先接受狀態,再渲染幾何 3 let curStatebin = this._curStatebin; 4 let curStateset = curStatebin.getStateSet();//當前的狀態 5 let curStatebinParent = curStatebin.getParent();//父節點 6 //let curStatesetParent = undefined;//父節點的狀態 7 //if(curStatebinParent){//自從加了總根節點後,這個情況不存在了吧! 8 //let curStatesetParent = curStatebinParent.getStateSet();//父節點的狀態 9 //} 10 11 if (preDrawable !== undefined) { 12 let preStatebin = preDrawable.getCurrentStateBin(); 13 let preStateset = preStatebin.getStateSet(); 14 let preStatebinParent = preStatebin.getParent(); 15 //let preStatesetParent = undefined; 16 //if(preStatebinParent){//自從加了總根節點後,這個情況不存在了吧! 17 //let preStatesetParent = preStatebinParent.getStateSet();//父節點的狀態 18 //} 19 20 //RenderEntity下的狀態隨時會變,在isTransparent中會實時更新StateBin 21 //所以每次StateBin的結果可能都是臨時建立的沒有可比性,還是比較stateset靠譜點 22 if (preStatebinParent !== curStatebinParent) {//A 23 StateBin.moveStateBin(glstate, preStatebinParent, curStatebinParent); 24 glstate.applyStateSet(curStateset); 25 } else if (preStateset !== curStateset) {//B 26 glstate.applyStateSet(curStateset); 27 } else { 28 // we call apply but actually we dont need 29 // except if the stateSetStack changed. 30 // for example if insert/remove StateSet has been used 31 // if (glstate._stateSetStackChanged(idLastDraw, lastStateSetStackSize )) { 32 // glstate.applyStateSet(curStateset); 33 // } 34 } 35 } 36 else {//如果preLeaf為空,第一個繪製的幾何,狀態遍歷到根節點全部push到GLState中 37 StateBin.moveStateBin(glstate, undefined, curStatebinParent); 38 glstate.applyStateSet(curStateset); 39 } 40 //state._setStateSetsDrawID( ++idLastDraw ); 41 //lastStateSetStackSize = state.getStateSetStackSize(); 42 43 //this.drawGeometry(glstate); 44 let camera = this._drawActor.getBaseCamera(); 45 glstate.applyModelMatrix(this._transform, camera.getModelViewMatrix(), camera.getProjectionMatrix()); 46 this._geometry.draw(glstate); 47 //return true; 48 49 //_stateBin新新增的兒子要刪除,不影響下一幀的繪製 50 //this._statebin.removeChildren(); 51 //this._curStatebin = undefined;//千萬不要重置。。每幀繪製時的Drawable會取前一個的狀態 52 //this._frameNumber = Drawable.FrameNumber;//已經繪製過,不再繪製 53 },
繪製函式draw。這個繪製draw就是用glstate來繪製當前渲染物件。
好了,以上就是DrawableEntity渲染物件的管理操作類的所有成員屬性和成員函式的介紹。我們又瞭解了osg的DrawableEntity的構造,再接再厲,下一篇鯽魚帶領大家繼續學習DrawEntityActor類。今天先到這裡,下週再見。本文系原創,如需引用,請註明出處:https://www.cnblogs.com/ccentry/p/10227152.html