今天继续来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