分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 前端开发

WebGL------osg框架学习二

发布时间:2023-09-06 02:28责任编辑:彭小芳关键词:WebWebGL

  今天我们继续来学习osg.js框架。上一篇我们介绍了DrawActor对象绘制操作类和Drawable可绘制对象类,我们大致知道了osg对Drawable可绘制对象的绘制流程管理。今天我们要继续介绍StateBin状态树节点类。我们来看一下StateBin,他管理的是StateSet状态,他将每个模型节点的StateSet状态信息(shaderLink,材质,depth等)包装成树节点,从而能够将状态节点递归组装成一棵状态树。我们来看看StateBin的构造函数。

 1 /* 2 状态树结点 3 保存一个StateSet,每个StateSet都有一个唯一ID 4 ?*/ 5 //let MemoryPool = require(‘../util/MemoryPool‘); 6 ?7 let StateBin = function () { 8 ????this._stateset = undefined; 9 ????this._parent = undefined;//StateBin10 ????this._children = {};//属性名为StateSet的ID,值为StateBin11 ????//this._children._keys = [];//StateSet的ID12 ????this._depth = 0;//树的深度值13 };

  首先我们可以看到StateBin的成员,this._stateset这就是模型节点的状态信息(shaderLink,材质,depth),this._parent该树节点的父节点,this._children该树节点的子节点,this._depth树的深度。这是一个典型的树节点类,熟悉数据结构的同学都明白如何递归构造一棵树,鲫鱼就不再啰嗦了。我们接下来看看StateBin的成员函数有哪些。

 1 StateBin.prototype = { 2 ????getStateSet: function () { 3 ????????return this._stateset; 4 ????}, 5 ????setStateSet: function (s) { 6 ????????this._stateset = s; 7 ????}, 8 ????getParent: function () { 9 ????????return this._parent;10 ????},11 ????reset: function () {//重置数据,一般都是根节点调用12 ????????this._stateset = undefined;13 ????????this._parent = undefined;14 15 ????????//之所以遍历是为了StateGraph不被析构以内存复用,而不是每次都重新创建16 ????????//然后是StateGraph的数据必须被清空,重新使用时不会出错17 ????????// let keys = this._children.keys();18 ????????// let l = keys.length;19 ????????// for (let i = 0; i < l; i++) {20 ????????// ????let key = keys[i];21 ????????// ????let child = this._children[key];22 ????????// ????child.reset();23 ????????// ????//内存池24 ????????// ????//MemoryPool.StateBin.put(child);25 ????????// }26 ????????this._children = {};27 ????????//this._children._keys.length = 0;28 ????????//this._children._keys = [];29 ????????this._depth = 0;30 ????},31 ????addStateBinChild: function (bin) {32 ????????bin._parent = this;33 ????????bin._depth = this._depth + 1;34 ????????let id = bin._stateset.getID();35 ????????this._children[id] = bin;36 ????},37 ????addStateSetChild: function (stateset) {//添加子节点,以stateset的id为key,返回新创建或者已经存在的StateBin38 ????????let id = stateset.getID();39 ????????let child = this._children[id];40 ????????if (child) {41 ????????????return child;42 ????????} else {43 ????????????let sg = new StateBin();44 ????????????//let sg = MemoryPool.StateBin.get();45 ????????????sg._parent = this;46 ????????????sg._depth = this._depth + 1;47 ????????????sg._stateset = stateset;48 ????????????this._children[id] = sg;49 ????????????//children._keys.push(id);50 ????????????return sg;51 ????????}52 ????},53 ????removeStateBinChild: function (bin) {54 ????????let id = bin._stateset.getID();55 ????????let cbin = this._children[id];56 ????????if (cbin) {57 ????????????cbin.parent = undefined;58 ????????????delete this._children[id];59 ????????}60 ????},61 ????removeStateSetChild: function (stateset) {62 ????????let id = stateset.getID();63 ????????let cbin = this._children[id];64 ????????if (cbin) {65 ????????????cbin.parent = undefined;66 ????????????delete this._children[id];67 ????????}68 ????},69 ????removeChildren: function () {70 ????????this._children = {};71 ????},72 };

我们一个一个来看,getStateSet获取当前树节点的渲染状态信息this._stateset;setStateSet设置当前树节点的渲染状态信息即修改this._stateset;getParent获取当前树节点的父节点;reset初始化节点数据,将节点属性清空析构;addStateBinChild向当前树节点中加入一个子节点;addStateSetChild如果当前树节点存在id是stateset的id的子节点,就返回该子节点,如果不存在就创建一个stateset状态的子节点并返回;removeStateBinChild删除当前节点的确定id的某个子节点;removeStateSetChild删除当前节点某个状态是stateset的子节点;removeChildren删除该树节点的所有子节点。

  我们可以清楚的看到,成员函数基本都是对树结构的操作,最后还有一个方法是对父状态的遍历继承,我们来看一下。

 1 //父状态的匹配 2 StateBin.moveStateBin = function (glstate, preStateBin, curStateBin) { 3 ????if (curStateBin === preStateBin) {//两个相同什么都不做 4 ????????return; 5 ????} 6 ?7 ????if (curStateBin === undefined) { 8 ????????//curStateBin已经到顶,弹出preStateBin的所有状态 9 ????????do {10 ????????????if (preStateBin._stateset !== undefined) {11 ????????????????glstate.popStateSet();12 ????????????}13 ????????????preStateBin = preStateBin._parent;14 ????????} while (preStateBin);15 ????????return;16 ????}17 18 ????if (preStateBin === undefined) {19 ????????//preStateBin已经到顶,压入curStateBin的所有状态20 ????????//从子节点往根节点遍历获取所有的状态,但是推给glstate必须从根节点往子节点遍历21 ????????//所以这里先塞到一个stack里面,然后再遍历stack推给glstate22 ????????let stack = [];23 ????????do {24 ????????????if (curStateBin._stateset !== undefined) {25 ????????????????stack.push(curStateBin._stateset);26 ????????????}27 ????????????curStateBin = curStateBin._parent;28 ????????} while (curStateBin);29 30 ????????let size = stack.length - 1;31 ????????for (let i = size; i >= 0; --i) {32 ????????????glstate.pushStateSet(stack[i]);33 ????????}34 ????????return;35 ????} else if (preStateBin._parent === curStateBin._parent) {36 ????????// first handle the typical case which is two glstate groups37 ????????// are neighbours.38 39 ????????// glstate has changed so need to pop old glstate.40 ????????if (preStateBin._stateset !== undefined) {41 ????????????glstate.popStateSet();42 ????????}43 ????????// and push new glstate.44 ????????if (curStateBin._stateset !== undefined) {45 ????????????glstate.pushStateSet(curStateBin._stateset);46 ????????}47 ????????return;48 ????}49 50 ????//先弹出状态,保证preStateBin和curStateBin达到树节点平级51 ????//无法确定两个树节点谁的深度值更多,两个都做一次循环52 ????while (preStateBin._depth > curStateBin._depth) {53 ????????if (preStateBin._stateset !== undefined) {54 ????????????glstate.popStateSet();55 ????????}56 ????????preStateBin = preStateBin._parent;57 ????}58 59 ????// use return path to trace back steps to curStateBin.60 ????let stack = [];61 ????// need to pop back up to the same depth as the curr glstate group.62 ????while (curStateBin._depth > preStateBin._depth) {63 ????????if (curStateBin._stateset !== undefined) {64 ????????????stack.push(curStateBin._stateset);65 ????????}66 ????????curStateBin = curStateBin._parent;67 ????}68 69 ????// now pop back up both parent paths until they agree.70 ????// should be this to conform with above case where two StateBin71 ????// nodes have the same parent72 ????//继续遍历直到两个树节点相同73 ????while (preStateBin !== curStateBin) {74 ????????if (preStateBin._stateset !== undefined) {//pre的从GLState中出栈75 ????????????glstate.popStateSet();76 ????????}77 ????????preStateBin = preStateBin._parent;78 79 ????????if (curStateBin._stateset !== undefined) {//当前的入栈,临时保存80 ????????????stack.push(curStateBin._stateset);81 ????????}82 ????????curStateBin = curStateBin._parent;83 ????}84 85 ????//遍历结束后,从临时栈中推入GLState里86 ????for (let i = stack.length - 1, l = 0; i >= l; --i) {87 ????????glstate.pushStateSet(stack[i]);88 ????}89 };

这段代码我们仔细来看一下。

第一件事比较当前节点状态和前一个节点状态,相同则直接返回。

1 if (curStateBin === preStateBin) {//两个相同什么都不做2 ????????return;3 ????}

接下来如果前后节点状态不同,就继续下面的事情,我们来看下面接下来做了什么事。接下来是判断当前遍历到的状态节点是否已经是树的叶子节点,如果是叶子节点就向树根部遍历,依次弹出上一级父节点直到遍历到整棵树的根节点。弹出是靠glstate这个参数来操作实现的注意一下。遍历到根节点并弹出状态后就直接返回了。

 1 if (curStateBin === undefined) { 2 ????????//curStateBin已经到顶,弹出preStateBin的所有状态 3 ????????do { 4 ????????????if (preStateBin._stateset !== undefined) { 5 ????????????????glstate.popStateSet(); 6 ????????????} 7 ????????????preStateBin = preStateBin._parent; 8 ????????} while (preStateBin); 9 ????????return;10 ????}

我们再看看接下来还做了什么操作,这个看注释就能理解他的操作。

 1 if (preStateBin === undefined) { 2 ????????//preStateBin已经到顶,压入curStateBin的所有状态 3 ????????//从子节点往根节点遍历获取所有的状态,但是推给glstate必须从根节点往子节点遍历 4 ????????//所以这里先塞到一个stack里面,然后再遍历stack推给glstate 5 ????????let stack = []; 6 ????????do { 7 ????????????if (curStateBin._stateset !== undefined) { 8 ????????????????stack.push(curStateBin._stateset); 9 ????????????}10 ????????????curStateBin = curStateBin._parent;11 ????????} while (curStateBin);12 13 ????????let size = stack.length - 1;14 ????????for (let i = size; i >= 0; --i) {15 ????????????glstate.pushStateSet(stack[i]);16 ????????}17 ????????return;18 ????} else if (preStateBin._parent === curStateBin._parent) {19 ????????// first handle the typical case which is two glstate groups20 ????????// are neighbours.21 22 ????????// glstate has changed so need to pop old glstate.23 ????????if (preStateBin._stateset !== undefined) {24 ????????????glstate.popStateSet();25 ????????}26 ????????// and push new glstate.27 ????????if (curStateBin._stateset !== undefined) {28 ????????????glstate.pushStateSet(curStateBin._stateset);29 ????????}30 ????????return;31 ????}

随后我们看看最后的操作。这波操作就是为了比较currStateBin和preStateBin这两个树节点的深度和对其向树根部的操作。

 1 //先弹出状态,保证preStateBin和curStateBin达到树节点平级 2 ????//无法确定两个树节点谁的深度值更多,两个都做一次循环 3 ????while (preStateBin._depth > curStateBin._depth) { 4 ????????if (preStateBin._stateset !== undefined) { 5 ????????????glstate.popStateSet(); 6 ????????} 7 ????????preStateBin = preStateBin._parent; 8 ????} 9 10 ????// use return path to trace back steps to curStateBin.11 ????let stack = [];12 ????// need to pop back up to the same depth as the curr glstate group.13 ????while (curStateBin._depth > preStateBin._depth) {14 ????????if (curStateBin._stateset !== undefined) {15 ????????????stack.push(curStateBin._stateset);16 ????????}17 ????????curStateBin = curStateBin._parent;18 ????}19 20 ????// now pop back up both parent paths until they agree.21 ????// should be this to conform with above case where two StateBin22 ????// nodes have the same parent23 ????//继续遍历直到两个树节点相同24 ????while (preStateBin !== curStateBin) {25 ????????if (preStateBin._stateset !== undefined) {//pre的从GLState中出栈26 ????????????glstate.popStateSet();27 ????????}28 ????????preStateBin = preStateBin._parent;29 30 ????????if (curStateBin._stateset !== undefined) {//当前的入栈,临时保存31 ????????????stack.push(curStateBin._stateset);32 ????????}33 ????????curStateBin = curStateBin._parent;34 ????}35 36 ????//遍历结束后,从临时栈中推入GLState里37 ????for (let i = stack.length - 1, l = 0; i >= l; --i) {38 ????????glstate.pushStateSet(stack[i]);39 ????}

  StateBin渲染状态树是对osg的StateSet单个模型渲染状态的管理数据结构,几乎在整个DrawActor的过程中都要大量应用,他的重要性不言而喻,鲫鱼也是一知半解的在学习这个数据结构,希望大家多提出宝贵的见解,多多斧正,谢谢同学们的支持关注。今天就到这里,下周再见。本文系原创,引用请注明出处:https://www.cnblogs.com/ccentry/p/10224312.html                       

WebGL------osg框架学习二

原文地址:https://www.cnblogs.com/ccentry/p/10224312.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved