WebGL——osg框架學習一

  從今天開始,我們開始正式的學習osg框架,今天我們學習的是osg的渲染模塊,我們來看一下代碼結構。

所有DrawXXX的js模塊都是渲染的模塊,我們逐一來簡單介紹一下,第一個Drawable.js,這個模塊是描述可繪制對象的類,也是我們今天要討論的類。在osg框架中,渲染管道在準備時期首先要統計管理可繪制對象,我們來看看Drawable模塊到底做了什么操作,進行了哪些管理。先貼出代碼。

/*
可繪制對象*/
let StateBin = require('./StateBin');
let BoundingBox = require('../util/BoundingBox');
let BoundingSphere = require('../util/BoundingSphere');
let Vec3 = require('../util/Vec3');let Drawable = function (actor) {this._drawActor = actor;//關聯的DrawActorthis._geometry = undefined;//渲染的幾何Geometrythis._transform = undefined;//世界變換 FloatArray(16)this._statebin = undefined;//狀態結點,原始的狀態,沒有額外功能時的狀態this._curStatebin = undefined;//如果狀態會動態變化,這里存儲每一幀繪制時的狀態結點this._depth = 0.0;//場景深度值,透明需要按深度排序繪制this._boundingBox = undefined;//包圍盒this._boundingSphere = undefined;//包圍球
};
Drawable.prototype = {setGeometry: function (g, transform) {this._geometry = g;this._transform = transform;},getGeometry: function () {return this._geometry;},getTransform: function () {return this._transform;},setStateBin: function (sb) {this._statebin = sb;},getStateBin: function () {return this._statebin;},getCurrentStateBin: function () {return this._curStatebin;},// setDepth: function (d) {//     this._depth = d;// },getDepth: function () {return this._depth;},reset: function () {this._geometry = undefined;this._transform = undefined;this._statebin = undefined;this._curStatebin = undefined;this._depth = 0.0;this._boundingBox = undefined;this._boundingSphere = undefined;},valid: function () {if (this._drawActor.getBaseCamera().isBoundingBoxCulled(this.getBoundingBox())) {return false;}return true;},isTransparent: function () {return false;},//計算深度值computeDepth: function () {//根據包圍盒和相機變換矩陣,確認中心點的Z值let mvmatrix = this._drawActor.getBaseCamera().getModelViewMatrix();let temp = Vec3.MemoryPool.alloc();this._depth = this.distanceZ(this.getBoundingBox().getCenter(temp), mvmatrix);Vec3.MemoryPool.free(temp);//drawable.setDepth(depth);
    },//相機的矩陣要取反distanceZ: function (coord, matrix) {return -(coord[0] * matrix[2] + coord[1] * matrix[6] + coord[2] * matrix[10] + matrix[14]);},getBoundingBox: function () {if(this._boundingBox === undefined){this._boundingBox = new BoundingBox();this._boundingBox.copy(this._geometry.getBoundingBox(true));if(this._transform){this._boundingBox.transformMat4(this._transform);}}return this._boundingBox;},getBoundingSphere: function () {if(this._boundingSphere === undefined) {this._boundingSphere = new BoundingSphere();let bb = this.getBoundingBox();this._boundingSphere.expandByBoundingBox(bb);}return this._boundingSphere;},getRadius: function () {return this.getBoundingSphere().getRadius();},// There are 3 cases when there is a prev / current render leaf// pSG: previousStateGraph// cSG: currentStateGraph// pRL: previousRenderLeaf// cRL: currentRenderLeaf//
    //          A                        B                       C// +-----+     +-----+            +-----+                 +-----+// | pSG |     | cSG |         +--+ SG  +--+              | SG  |// +--+--+     +--+--+         |  +-----+  |              +--+--+//    |           |            |           |                 |// +--v--+     +--v--+      +--v--+     +--v--+           +--v--+// | pSG |     | cSG |      | pSG |     | cSG |        +--+ SG  +--+// +--+--+     +--+--+      +--+--+     +--+--+        |  +-----+  |//    |           |            |           |           |           |// +--v--+     +--v--+      +--v--+     +--v--+     +--v--+     +--v--+// | pRL |     | cRL |      | pRL |     | cRL |     | pRL |     | cRL |// +-----+     +-----+      +-----+     +-----+     +-----+     +-----+//
    //
    // Case A// no common parent StateGraphNode we need to// popStateSet until we find the common parent and then// pushStateSet from the common parent to the current RenderLeaf//
    // Case B// common parent StateGraphNode so we apply the current stateSet//
    // Case C// the StateGraphNode is common to the previous RenderLeaf so we dont need// to do anything except if we used an insertStateSetdraw: function (glstate, preDrawable) {//先接受狀態,再渲染幾何let curStateGraph = this._statebin;let curStateGraphStateSet = curStateGraph.getStateSet();let curStateGraphParent = curStateGraph.getParent();let preStateGraph;let preStateGraphParent;if(preDrawable !== undefined){preStateGraph = preDrawable._statebin;preStateGraphParent = preStateGraph.getParent();if(preStateGraphParent !== curStateGraphParent){//A
                StateBin.moveStateBin(glstate, preStateGraphParent, curStateGraphParent);glstate.applyStateSet(curStateGraphStateSet);}else if(preStateGraph !== curStateGraph){//B
                glstate.applyStateSet(curStateGraphStateSet);}else{// in osg we call apply but actually we dont need// except if the stateSetStack changed.// for example if insert/remove StateSet has been used// if (glstate._stateSetStackChanged(idLastDraw, lastStateSetStackSize )) {//     glstate.applyStateSet(curStateGraphStateSet);// }
            }}else{//如果preLeaf為空,第一個繪制的幾何,狀態遍歷到根節點全部push到GLState中
            StateBin.moveStateBin(glstate, undefined, curStateGraphParent);glstate.applyStateSet(curStateGraphStateSet);}let camera = this._drawActor.getBaseCamera();glstate.applyModelMatrix(this._transform, camera.getModelViewMatrix(), camera.getProjectionMatrix());this._geometry.draw(glstate);return true;},
};
module.exports = Drawable;// set: function (stateGraph, geometry, , depth) {
//     this._statebin = stateGraph;
//     this._geometry = geometry;
//
//     this._depth = depth;
// },
// drawGeometry: function (glstate) {
//     //let program = glstate.getLastProgramApplied();
//     //let programID = program.getID();
//     //let programCaches = glstate.getProgramCaches();
//     //let obj = programCaches[programID];
//     // if(!obj){//程序不存在,創建一個新的
//     //     obj = new CacheUniformApply(glstate, program);
//     //     programCaches[programID] = obj;
//     // }
//
//     //從相機獲取modelview和projection
//     //著色器暫時不需要透視矩陣
//     //let modelview = this._camera.get
//
//
//
//     //glstate.applyModelViewMatrix(this._modelview);
//     //glstate.applyProjectionMatrix(this._projection);
//     glstate.applyTransformMatrix(this._transform);
//     //this._modelview = this._camera.getModelViewMatrix();
//     //Mat4.mul(this._modelview, this._modelview, this._transform);
//     //this._projection = this._camera.getProjectionMatrix();
//     glstate.applyModelMatrix(this._transform, this._camera.getModelViewMatrix(), this._camera.getProjectionMatrix());
//
//
//     //let gluniforms = program.getGLUniformsCache();
//     //let modelviewloc = gluniforms[glstate._modelViewMatrixUniform.getName()];
//     //let viewloc = gluniforms[glstate._viewMatrixUniform.getName()];
//
//     //obj.apply(glstate, this._modelview, this._modelworld, this._view, this._projection, this._normal);
//     this._geometry.draw(glstate);
// },

我們先來看看Drawable的構造函數,截取構造函數代碼

let Drawable = function (actor) {this._drawActor = actor;//關聯的DrawActorthis._geometry = undefined;//渲染的幾何Geometrythis._transform = undefined;//世界變換 FloatArray(16)this._statebin = undefined;//狀態結點,原始的狀態,沒有額外功能時的狀態this._curStatebin = undefined;//如果狀態會動態變化,這里存儲每一幀繪制時的狀態結點this._depth = 0.0;//場景深度值,透明需要按深度排序繪制this._boundingBox = undefined;//包圍盒this._boundingSphere = undefined;//包圍球
};

首先我們看到第一個私有屬性是DrawActor,我們看看DrawActor是個什么模塊,先貼出DrawActor類代碼。

/*
繪制對象角色每個DrawActor管理自己的渲染數據,自己的狀態樹,自己的相機樹
如果該功能銷毀直接銷毀對應的DrawActor資源
但是他引用的狀態,相機并不是他管理
不想把各個DrawActor攪和在一起,邏輯混亂繪制分幾種情況,全自動,全手動,半自動
全自動-所有的繪制流程從一開始數據構造好后就不會再變更,只需在初始化時確認好 后續直接渲染即可
半自動-部分繪制流程是固定的,部分繪制流程是動態的,比如構件場景下,需要點選高亮等功能變化
全手動-所有的繪制流程都是動態的,每一幀都需要重新構造每個drawable,部分功能數據*/
let Drawable = require('./Drawable');
let StateBin = require('./StateBin');
let NodeVisitor = require('../util/NodeVisitor');
let CullStack = require('./CullStack');
let Mat4 = require('../util/Mat4');
let Group = require('../core/Group');
let Geode = require('../core/Geode');
let MatrixTrasform = require('../core/MatrixTransform');
let SceneRoot = require('../scene/SceneRoot');
let Geometry = require('../core/Geometry');let DrawActor = function (renderer) {NodeVisitor.call(this, NodeVisitor.TRAVERSE_CHILDREN);CullStack.call(this);//為正確渲染準備的數據this._renderer = renderer;//所屬的渲染器,固有資產,不會變更this._baseCamera = this._renderer.getMainCamera();//相機,默認為主相機this._baseState = new StateBin();//狀態this._sceneRoot = undefined;//所屬的場景根節點//渲染的對象this._drawables = [];//
    this._drawIndex = 0;//當前繪制的索引數,需要固定幀率渲染的地方使用//
    this._currentStateBin = undefined;//當前處理的狀態樹結點,臨時數據//
    //this._fixed = false;//是否啟用固定幀率this._valid = true;//直接屏蔽渲染的標記
};DrawActor.prototype = Object.create(NodeVisitor.prototype);
Object.assign(DrawActor.prototype, CullStack.prototype);
DrawActor.prototype.constructor = DrawActor;
Object.assign(DrawActor.prototype, {setBaseCamera: function (camera) {//設置當前相機,可以自由設置自己獨特的相機this._baseCamera = camera;},getBaseCamera: function () {return this._baseCamera;},getBaseStateBin: function () {return this._baseState;},getBaseStateSet: function () {return this._baseState.getStateSet();},//復原場景根節點的狀態revertBaseState: function () {if (this._sceneRoot) {this._baseState.setStateSet(this._sceneRoot.getStateSet());}},//與場景的唯一聯系,一定要先定義好場景的幾何和狀態再調用setSceneRootsetSceneRoot: function (root) {this._sceneRoot = root;//一定要先定義好場景根節點的狀態,否則會出錯!!!//this._baseState.setStateSet(root.getStateSet());
    },createDrawable: function () {//base overridereturn new Drawable(this);//創建對應類型的Drawable
    },addDrawable: function (drawable) {this._drawables.push(drawable);},getDrawables: function () {return this._drawables;},valid: function (valid) {if (valid !== undefined) {this._valid = valid;}return this._valid;},//遍歷apply: function (node) {this[node.typeID](node);},//重載,壓入一個狀態pushStateSet: function (stateset) {if (stateset) {//添加StateGraph子節點,更新當前活動的StateGraph為新的狀態this._currentStateBin = this._currentStateBin.addStateSetChild(stateset);}},//重載,彈出一個狀態popStateSet: function (stateset) {if (stateset) {this._currentStateBin = this._currentStateBin.getParent();}},//重載pushDrawable: function (geometry) {let drawable = this.createDrawable();drawable.setStateBin(this._currentStateBin);drawable.setGeometry(geometry, this.getCurrentTransformMatrix());this.addDrawable(drawable);},//根重載,繪制當前Actor下的drawables,繪制不需要固定幀率,永遠在第一幀里繪制完畢draw: function (glstate, preCamera) {if (!this._valid) {//不再繪制return preCamera;}this.drawCamera(preCamera);//循環遍歷一遍drawables,繪制實體let preDrawable = undefined;let l = this._drawables.length;for (let i = this._drawIndex; i < l; i++) {let drawable = this._drawables[i];if (drawable.valid()) {drawable.draw(glstate, preDrawable);//成功繪制的preDrawable = drawable;}this._drawIndex++;}return this._baseCamera;},//每個新幀繪制之前的重置工作drawReset: function () {this._baseCamera.setClearFlag(false);this._drawIndex = 0;},//當前Actor的對象是否全部繪制完畢drawFinished: function () {return this._drawables.length === this._drawIndex;},//繪制相機狀態(視口,清空)drawCamera: function (preCamera) {if (preCamera === this._baseCamera) {//重復的不再處理return;}//視口何時都需要設置let glstate = this._renderer.getGLState();glstate.applyAttribute(this._baseCamera.getViewport());//以下是每個相機只需要處理一次的事情if (!this._baseCamera.getClearFlag()) {//更新視錐體,確保剔除正確,每幀相機的投影矩陣和視圖矩陣可能都會變化this._baseCamera.updateCullFrustum();//清空顏色和深度,但如果是主相機不再需要,在最開始就已經清空let clearmask = this._baseCamera.getClearMask();if (clearmask !== 0x0) {let gl = glstate.getWebGLContext();if (clearmask & gl.COLOR_BUFFER_BIT) {let color = this._baseCamera.getClearColor();//清空顏色gl.clearColor(color[0], color[1], color[2], color[3]);}if (clearmask & gl.DEPTH_BUFFER_BIT) {let depth = this._baseCamera.getClearDepth();//清空深度gl.depthMask(true);gl.clearDepth(depth);}gl.clear(clearmask);}this._baseCamera.setClearFlag(true);}},//根重載,線段求交,返回相交的drawable對象linesegmentIntersect: function (start, end, threshold) {let LineSegmentIntersector = require('../util/LineSegmentIntersector');let intersector = new LineSegmentIntersector();intersector.initialize(start, end, threshold);let length = this._drawables.length;for (let i = 0; i < length; i++) {let drawable = this._drawables[i];if (drawable.valid()) {//沒有隱藏,沒有被剔除的drawable進行相交運算
                intersector.intersect(drawable);}}//線段求交結果需要根據ratio排序return intersector.getIntersections();},
});DrawActor.prototype[SceneRoot.typeID] = function (root) {this._baseState.removeChildren();this._baseState.setStateSet(root.getStateSet());this._currentStateBin = this._baseState;this.pushTransformMatrix(root.getRootTransform());//變換矩陣中先推入一個單位矩陣作為根節點,非常重要this.traverse(root);this.popTransformMatrix();this._currentStateBin = undefined;
};
DrawActor.prototype[MatrixTrasform.typeID] = function (node) {//模型矩陣變換let lastModelMatrix = this.getCurrentTransformMatrix();let mmatrix = undefined;if (lastModelMatrix) {mmatrix = Mat4.clone(lastModelMatrix);} else {mmatrix = Mat4.new();}node.computeLocalToWorldMatrix(mmatrix);this.pushTransformMatrix(mmatrix);//狀態let stateset = node.getStateSet();this.pushStateSet(stateset);this.traverse(node);this.popStateSet(stateset);this.popTransformMatrix();
};
DrawActor.prototype[Geode.typeID] = function (geode) {this[Group.typeID](geode);
};
DrawActor.prototype[Group.typeID] = function (group) {let stateset = group.getStateSet();this.pushStateSet(stateset);this.traverse(group);this.popStateSet(stateset);
};
DrawActor.prototype[Geometry.typeID] = function (geometry) {//Geometry已經是葉子,不需要繼續遞歸了let stateset = geometry.getStateSet();this.pushStateSet(stateset);this.pushDrawable(geometry);this.popStateSet(stateset);
};
module.exports = DrawActor;
// reset: function () {
//     this._drawables.length = 0;//置空
//     this._sceneRoot = undefined;
// },
// polytopeIntersect: function () {
//
// },
// sphereIntersect: function () {
//
// },

  我們可以看到,DrawActor是將要被繪制的對象,分成全自動(初始化模型數據就構造Drawable,準備渲染)、半自動(事件觸發后構造Drawable,等待渲染)、全手動(用戶自己構造Drawable,用戶自己將Drawable排入渲染隊列)。我們看到,DrawActor的構造函數包含的私有屬性有this._renderer渲染器、this._baseCamera待渲染模塊所屬相機、this._baseState狀態(對應shader里的uniform參數)、this._sceneRoot所屬場景根節點、this._drawables包含的渲染對象、this._drawIndex當前繪制的索引數(代表本次繪制是第幾次繪制,如果一此不能全部繪制完,就分多次繪制,例如模型增長)、this._currentStateBin當前處理的狀態樹節點、this._valid屏蔽渲染的標記(true:加入渲染隊列,false:不加入渲染隊列)。

  我們再來看看DrawActor的成員函數都做了什么,我們依次來看。

1.setBaseCamera設置參考相機,這就是設置當前繪制對象的觀察相機。2.getBaseCamera獲取參考相機。3.getbaseStateBin獲取狀態信息,包括當前渲染對象綁定的shader,uniform參數以及frameBuffer材質。4.getBaseStateSet同樣是獲取當前渲染對象的狀態信息,shader,uniform,材質信息,depth深度緩沖等。5.revertBaseState恢復場景根節點狀態,包括shader,uniform參數,材質信息,depth深度緩存。6.setSceneRoot設置場景根節點。7.createDrawable創建渲染對象。8.addDrawable追加渲染對象進入繪制對象數組。9.getDrawable返回渲染對象數組。10.valid標記當前渲染對象是否被屏蔽。11.apply取出每個渲染節點。12.pushStateSet向stateBin中加入stateSet,這里說明一點,stateSet是stateBin的屬性。13.popStateSet從stateBin中取出stateSet屬性參數。14.pushDrawable創建渲染對象drawable然后加入drawActor的drawable渲染對象數組。15.draw這才是drawActor的核心功能函數,同學們,鯽魚為大家隆重介紹繪制函數,或者叫渲染函數,這就是將所有的drawable渲染對象進行遍歷渲染的功能函數。16.drawReset每一幀繪制之前的整理重置。17.drawFinished判斷當前drawActor繪制對象是否全部將drawable數組中的渲染對象繪制完畢。18.drawCamera繪制相機狀態(視口,深度緩沖),如果沒有渲染對象私有獨立的相機,就操作主相機。19.linesegmentIntersection射線碰撞,重載父類方法。

  依次看一下上面的函數,我們大致了解了DrawActor類處理的是渲染流程管理的工作。我們接下來繼續看Drawable類的其他屬性。我們再貼出一次drawable的構造函數。

let Drawable = function (actor) {this._drawActor = actor;//關聯的DrawActorthis._geometry = undefined;//渲染的幾何Geometrythis._transform = undefined;//世界變換 FloatArray(16)this._statebin = undefined;//狀態結點,原始的狀態,沒有額外功能時的狀態this._curStatebin = undefined;//如果狀態會動態變化,這里存儲每一幀繪制時的狀態結點this._depth = 0.0;//場景深度值,透明需要按深度排序繪制this._boundingBox = undefined;//包圍盒this._boundingSphere = undefined;//包圍球
};

我們已經看過了this._drawActor,也知道了drawActor是管理渲染的類。接下來我們看this._geometry渲染的幾何體成員對象。this._transform空間變換矩陣。this._statebin狀態節點,用來添加stateSet狀態參數對象。this._currStatebin,保存每一幀的臨時狀態stateSet。this._depth場景深度值,作用于主相機或渲染對象私有相機(如果有私有相機的話)。this._boundingBox包圍盒。this._boundingSphere包圍球。這些就是Drawable類的成員。我們馬上來看一下Drawable的成員函數。
  Drawable成員函數。貼出代碼。

setGeometry: function (g, transform) {this._geometry = g;this._transform = transform;},getGeometry: function () {return this._geometry;},getTransform: function () {return this._transform;},setStateBin: function (sb) {this._statebin = sb;},getStateBin: function () {return this._statebin;},getCurrentStateBin: function () {return this._curStatebin;},// setDepth: function (d) {//     this._depth = d;// },getDepth: function () {return this._depth;},reset: function () {this._geometry = undefined;this._transform = undefined;this._statebin = undefined;this._curStatebin = undefined;this._depth = 0.0;this._boundingBox = undefined;this._boundingSphere = undefined;},valid: function () {if (this._drawActor.getBaseCamera().isBoundingBoxCulled(this.getBoundingBox())) {return false;}return true;},isTransparent: function () {return false;},//計算深度值computeDepth: function () {//根據包圍盒和相機變換矩陣,確認中心點的Z值let mvmatrix = this._drawActor.getBaseCamera().getModelViewMatrix();let temp = Vec3.MemoryPool.alloc();this._depth = this.distanceZ(this.getBoundingBox().getCenter(temp), mvmatrix);Vec3.MemoryPool.free(temp);//drawable.setDepth(depth);
    },//相機的矩陣要取反distanceZ: function (coord, matrix) {return -(coord[0] * matrix[2] + coord[1] * matrix[6] + coord[2] * matrix[10] + matrix[14]);},getBoundingBox: function () {if(this._boundingBox === undefined){this._boundingBox = new BoundingBox();this._boundingBox.copy(this._geometry.getBoundingBox(true));if(this._transform){this._boundingBox.transformMat4(this._transform);}}return this._boundingBox;},getBoundingSphere: function () {if(this._boundingSphere === undefined) {this._boundingSphere = new BoundingSphere();let bb = this.getBoundingBox();this._boundingSphere.expandByBoundingBox(bb);}return this._boundingSphere;},getRadius: function () {return this.getBoundingSphere().getRadius();},

都是設置和獲取屬性的函數,包括包圍盒和包圍球。接下來我們來看看最核心的部分,隆重介紹draw繪制函數,請看代碼。

// There are 3 cases when there is a prev / current render leaf// pSG: previousStateGraph// cSG: currentStateGraph// pRL: previousRenderLeaf// cRL: currentRenderLeaf//
    //          A                        B                       C// +-----+     +-----+            +-----+                 +-----+// | pSG |     | cSG |         +--+ SG  +--+              | SG  |// +--+--+     +--+--+         |  +-----+  |              +--+--+//    |           |            |           |                 |// +--v--+     +--v--+      +--v--+     +--v--+           +--v--+// | pSG |     | cSG |      | pSG |     | cSG |        +--+ SG  +--+// +--+--+     +--+--+      +--+--+     +--+--+        |  +-----+  |//    |           |            |           |           |           |// +--v--+     +--v--+      +--v--+     +--v--+     +--v--+     +--v--+// | pRL |     | cRL |      | pRL |     | cRL |     | pRL |     | cRL |// +-----+     +-----+      +-----+     +-----+     +-----+     +-----+//
    //
    // Case A// no common parent StateGraphNode we need to// popStateSet until we find the common parent and then// pushStateSet from the common parent to the current RenderLeaf//
    // Case B// common parent StateGraphNode so we apply the current stateSet//
    // Case C// the StateGraphNode is common to the previous RenderLeaf so we dont need// to do anything except if we used an insertStateSetdraw: function (glstate, preDrawable) {//先接受狀態,再渲染幾何let curStateGraph = this._statebin;let curStateGraphStateSet = curStateGraph.getStateSet();let curStateGraphParent = curStateGraph.getParent();let preStateGraph;let preStateGraphParent;if(preDrawable !== undefined){preStateGraph = preDrawable._statebin;preStateGraphParent = preStateGraph.getParent();if(preStateGraphParent !== curStateGraphParent){//A
                StateBin.moveStateBin(glstate, preStateGraphParent, curStateGraphParent);glstate.applyStateSet(curStateGraphStateSet);}else if(preStateGraph !== curStateGraph){//B
                glstate.applyStateSet(curStateGraphStateSet);}else{// in osg we call apply but actually we dont need// except if the stateSetStack changed.// for example if insert/remove StateSet has been used// if (glstate._stateSetStackChanged(idLastDraw, lastStateSetStackSize )) {//     glstate.applyStateSet(curStateGraphStateSet);// }
            }}else{//如果preLeaf為空,第一個繪制的幾何,狀態遍歷到根節點全部push到GLState中
            StateBin.moveStateBin(glstate, undefined, curStateGraphParent);glstate.applyStateSet(curStateGraphStateSet);}let camera = this._drawActor.getBaseCamera();glstate.applyModelMatrix(this._transform, camera.getModelViewMatrix(), camera.getProjectionMatrix());this._geometry.draw(glstate);return true;},

我將注釋也貼了出來,我們可以看到,渲染繪制是分三種情況的,首先我們要了解一下StateGraph渲染屬性這個來源于osg的概念。stateGraph是渲染的狀態屬性,包括本次渲染綁定的shader,uniform參數,frameBuffer材質屬性,depth深度屬性。好了,大致了解了StateGraph后我們再來了解一下RenderLeaf渲染葉這個同樣來自osg的概念。RenderLeaf是渲染葉,需要注意的是渲染葉保存的是sceneTree的節點狀態,而不是場景樹的幾何和transform信息。好了,了解了這兩個概念我們來看看這三種情況。A.前一幀stateGraph和后一幀stateGraph沒有同一個父節點;B.前后兩幀stateGraph有同一個父節點;C.前后兩幀renderLeaf有共同父節點。針對這三種情況,處理的方式不同,需要注意。鯽魚也才開始逐步研究osg框架,理解不到位之處請各位方家海涵。
  好了,今天講述的是osg的渲染模塊中的一部分DrawActor和Drawable兩個模塊。下一篇會進一步講述渲染模塊。歡迎大家討論,祝大家元旦快樂。本文系原創,如需引用,請注明出處:https://www.cnblogs.com/ccentry/p/10199157.html???????????????????????

?

轉載于:https://www.cnblogs.com/ccentry/p/10199157.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387669.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387669.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387669.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

EmguCV 一些基本操作

一、先是在程序中圖像的導入&#xff0c;我是根據圖像路徑實現&#xff0c;其中path是string類型&#xff0c;是圖像路徑。 IntPtr imgCvInvoke.cvLoadImage(path, Emgu.CV.CvEnum.LOAD_IMAGE_TYPE.CV_LOAD_IMAGE_ANYCOLOR); 二、圖像灰度化處理&#xff0c;先創建一幅尺寸大小…

Java字符串分割

java中字符串的分割函數&#xff0c;split("你想要分割的字符", 你想要最多分割為多少段&#xff0c;正整數&#xff09; 注意事項&#xff1a; 1.分割特殊字符考慮轉義字符的使用。如&#xff1a; . \ | 2.第二個參數&#xff1a; 無&#xff1a; 不傳默認分割全部…

OpenCV人臉識別的原理 .

在之前講到的人臉測試后&#xff0c;提取出人臉來&#xff0c;并且保存下來&#xff0c;以供訓練或識別是用&#xff0c;提取人臉的代碼如下&#xff1a; [html] view plaincopy print?void GetImageRect(IplImage* orgImage, CvRect rectInImage, IplImage* imgRect,double s…

說一下SEO和SEM到底有哪些區別?

開場白免了&#xff0c;我們直接說與主題相關的。 SEO和SEM到底有什么區別&#xff1f; SEO和SEM到底有什么區別 我們先理解字面意思&#xff1a; SEO&#xff08;Search Engine Optimization&#xff09;&#xff1a;漢譯為搜索引擎優化。 SEM&#xff08;Search Engine Marke…

django模型的繼承

很多時候&#xff0c;我們都不是從‘一窮二白’開始編寫模型的&#xff0c;有時候可以從第三方庫中繼承&#xff0c;有時候可以從以前的代碼中繼承&#xff0c;甚至現寫一個模型用于被其它模型繼承。這樣做的好處&#xff0c;我就不贅述了&#xff0c;每個學習Django的人都非常…

SpringBoot部署項目到Docker倉庫

SpringBoot部署項目到Docker倉庫1.開啟遠程控制端口Centos7開啟方式&#xff1a; vim /lib/systemd/system/docker.service找到ExecStart行 ExecStart/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock 重啟docker 啟動 systemctl start docker守護進程…

人臉識別經典方法

這篇文章是擼主要介紹人臉識別經典方法的第一篇&#xff0c;后續會有其他方法更新。特征臉方法基本是將人臉識別推向真正可用的第一種方法&#xff0c;了解一下還是很有必要的。特征臉用到的理論基礎PCA在另一篇博客里&#xff1a;特征臉(Eigenface)理論基礎-PCA(主成分分析法)…

Jquery常用正則驗證

常用校驗的正則表達式var rulesConfig { /** * str.replace(/^\s|\s$/g, ) 解析&#xff1a; str&#xff1a;要替換的字符串 \s : 表示 space &#xff0c;空格 &#xff1a; 一個或多個 ^&#xff1a; 開始&#xff0c;^\s&#xff0c;以空格開始 $&#xff1a; 結束&#x…

svm參數說明

svm參數說明---------------------- 如果你要輸出類的概率&#xff0c;一定要有-b參數 svm-train training_set_file model_file svm-predict test_file model_fileoutput_file 自動腳本&#xff1a;Python easy.py train_data test_data 自動選擇最優參數&#xff0c;自動進行…

poj-3667(線段樹區間合并)

題目鏈接&#xff1a;傳送門 參考文章&#xff1a;傳送門 思路&#xff1a;線段樹區間合并問題&#xff0c;每次查詢到滿足線段樹的區間最左值&#xff0c;然后更新線段樹。 #include<iostream> #include<cstdio> #include<cstring> using namespace std; co…

面試題編程題11-python 生成隨機數

隨機整數&#xff1a; random.randint(a,b), [a,b] random.randrange(a,b,step) [a,b) 隨機實數 random.random()返回0 到1 之間的浮點數轉載于:https://www.cnblogs.com/feihujiushiwo/p/10922454.html

車牌識別之顏色選取

車牌定位是車牌識別中第一步&#xff0c;也是最重要的一步。 由于中國車牌種類多樣&#xff0c;顏色不一&#xff0c; 再加上車牌經常有污損&#xff0c;以及車牌周圍干擾因素太多&#xff0c;都成為了車牌定位的難點。 這里首先使用最簡單算法來描述車牌定位&#xff0c;以及他…

Python - 排序( 插入, 冒泡, 快速, 二分 )

插入排序 算法分析 兩次循環, 大循環對隊列中的每一個元素拿出來作為小循環的裁定對象 小循環對堆當前循環對象在有序隊列中尋找插入的位置 性能參數 空間復雜度  O(1) 時間復雜度  O(n^2) 詳細代碼解讀 import randomdef func(l):# 外層循環: 對應遍歷所有的無序數據for i…

[EmguCV|C#]使用CvInvoke自己繪製色彩直方圖-直方圖(Hitsogram)系列(4)

2014-02-0610325 0C# 檢舉文章 過年結束了&#xff0c;雖然還是學生所以其實還有兩個禮拜的假期&#xff0c;不過為了不讓自己發慌&#xff0c;趁著假期多利用充實自己&#xff0c;所以提早回到開工狀態&#xff0c;而這次總算要把一直說的自己動手繪製猜色直方圖文章寫出。 …

G.點我

鏈接&#xff1a;https://ac.nowcoder.com/acm/contest/903/G 題意&#xff1a; X腿與隊友到河北省來參加2019河北省大學生程序設計競賽&#xff0c;然而這場比賽的題目難度實在是太高了。比賽開始一個小時后&#xff0c;X腿仍然沒有做出一個題。這時候&#xff0c;X腿驚訝的發…

輪廓的查找、表達、繪制、特性及匹配(How to Use Contour? Find, Component, Construct, Features Match)

前言 輪廓是構成任何一個形狀的邊界或外形線。前面講了如何根據色彩及色彩的分布&#xff08;直方圖對比和模板匹配&#xff09;來進行匹配&#xff0c;現在我們來看看如何利用物體的輪廓。包括以下內容&#xff1a;輪廓的查找、表達方式、組織方式、繪制、特性、匹配。 查…

Android:IntentService的學習

在Android的四大組件中&#xff0c;Service排行老二&#xff0c;在Android中的主要作用是后臺服務&#xff0c;進行與界面無關的操作。由于Service運行在主線程&#xff0c;所以進行異步操作需要在子線進行。為此Android為我們提供了IntentService。 IntentService是一個抽象類…

智能商業大會構造信息化交流平臺

在快速發展的當今社會&#xff0c;所有事物都在日新月異地變化著&#xff0c;相較于過去的傳統商業的變化速度&#xff0c;現今基于數據的互聯網商業變化速度高出了一個量級&#xff0c;同時市場對于企業的應對速度也有了更高的要求&#xff0c;然而面對大體量的數據&#xff0…

itcast-ssh-crm實踐

分析 BaseDao 文件上傳 轉載于:https://www.cnblogs.com/hellowq/p/10209761.html

分類器大牛們

David Lowe&#xff1a;Sift算法的發明者&#xff0c;天才。 Rob Hess&#xff1a;sift的源碼OpenSift的作者&#xff0c;個人主頁上有openSift的下載鏈接&#xff0c;Opencv中sift的實現&#xff0c;也是參考這個。 Koen van de Sande&#xff1a;作者給出了sift,densesift,co…