WebGL------osg框架学习二
今天我们继续来学习osg.js框架。上一篇我们介绍了DrawActor对象绘制操作类和Drawable可绘制对象类,我们大致知道了osg对Drawable可绘制对象的绘制流程管理。今天我们要继续介绍StateBin状态树节点类。我们来看一下StateBin,他管理的是StateSet状态,他将每个模型节点的StateSet状态信息(shaderLink,材质,depth等)包装成树节点,从而能够将状态节点递归组装成一棵状态树。我们来看看StateBin的构造函数。
/*
状态树结点
保存一个StateSet,每个StateSet都有一个唯一ID
*/
//let MemoryPool = require('../util/MemoryPool'); let StateBin = function () {
this._stateset = undefined;
this._parent = undefined;//StateBin
this._children = {};//属性名为StateSet的ID,值为StateBin
//this._children._keys = [];//StateSet的ID
this._depth = 0;//树的深度值
};
首先我们可以看到StateBin的成员,this._stateset这就是模型节点的状态信息(shaderLink,材质,depth),this._parent该树节点的父节点,this._children该树节点的子节点,this._depth树的深度。这是一个典型的树节点类,熟悉数据结构的同学都明白如何递归构造一棵树,鲫鱼就不再啰嗦了。我们接下来看看StateBin的成员函数有哪些。
StateBin.prototype = {
getStateSet: function () {
return this._stateset;
},
setStateSet: function (s) {
this._stateset = s;
},
getParent: function () {
return this._parent;
},
reset: function () {//重置数据,一般都是根节点调用
this._stateset = undefined;
this._parent = undefined;
//之所以遍历是为了StateGraph不被析构以内存复用,而不是每次都重新创建
//然后是StateGraph的数据必须被清空,重新使用时不会出错
// let keys = this._children.keys();
// let l = keys.length;
// for (let i = 0; i < l; i++) {
// let key = keys[i];
// let child = this._children[key];
// child.reset();
// //内存池
// //MemoryPool.StateBin.put(child);
// }
this._children = {};
//this._children._keys.length = 0;
//this._children._keys = [];
this._depth = 0;
},
addStateBinChild: function (bin) {
bin._parent = this;
bin._depth = this._depth + 1;
let id = bin._stateset.getID();
this._children[id] = bin;
},
addStateSetChild: function (stateset) {//添加子节点,以stateset的id为key,返回新创建或者已经存在的StateBin
let id = stateset.getID();
let child = this._children[id];
if (child) {
return child;
} else {
let sg = new StateBin();
//let sg = MemoryPool.StateBin.get();
sg._parent = this;
sg._depth = this._depth + 1;
sg._stateset = stateset;
this._children[id] = sg;
//children._keys.push(id);
return sg;
}
},
removeStateBinChild: function (bin) {
let id = bin._stateset.getID();
let cbin = this._children[id];
if (cbin) {
cbin.parent = undefined;
delete this._children[id];
}
},
removeStateSetChild: function (stateset) {
let id = stateset.getID();
let cbin = this._children[id];
if (cbin) {
cbin.parent = undefined;
delete this._children[id];
}
},
removeChildren: function () {
this._children = {};
},
};
我们一个一个来看,getStateSet获取当前树节点的渲染状态信息this._stateset;setStateSet设置当前树节点的渲染状态信息即修改this._stateset;getParent获取当前树节点的父节点;reset初始化节点数据,将节点属性清空析构;addStateBinChild向当前树节点中加入一个子节点;addStateSetChild如果当前树节点存在id是stateset的id的子节点,就返回该子节点,如果不存在就创建一个stateset状态的子节点并返回;removeStateBinChild删除当前节点的确定id的某个子节点;removeStateSetChild删除当前节点某个状态是stateset的子节点;removeChildren删除该树节点的所有子节点。
我们可以清楚的看到,成员函数基本都是对树结构的操作,最后还有一个方法是对父状态的遍历继承,我们来看一下。
//父状态的匹配
StateBin.moveStateBin = function (glstate, preStateBin, curStateBin) {
if (curStateBin === preStateBin) {//两个相同什么都不做
return;
} if (curStateBin === undefined) {
//curStateBin已经到顶,弹出preStateBin的所有状态
do {
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
preStateBin = preStateBin._parent;
} while (preStateBin);
return;
} if (preStateBin === undefined) {
//preStateBin已经到顶,压入curStateBin的所有状态
//从子节点往根节点遍历获取所有的状态,但是推给glstate必须从根节点往子节点遍历
//所以这里先塞到一个stack里面,然后再遍历stack推给glstate
let stack = [];
do {
if (curStateBin._stateset !== undefined) {
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} while (curStateBin); let size = stack.length - 1;
for (let i = size; i >= 0; --i) {
glstate.pushStateSet(stack[i]);
}
return;
} else if (preStateBin._parent === curStateBin._parent) {
// first handle the typical case which is two glstate groups
// are neighbours. // glstate has changed so need to pop old glstate.
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
// and push new glstate.
if (curStateBin._stateset !== undefined) {
glstate.pushStateSet(curStateBin._stateset);
}
return;
} //先弹出状态,保证preStateBin和curStateBin达到树节点平级
//无法确定两个树节点谁的深度值更多,两个都做一次循环
while (preStateBin._depth > curStateBin._depth) {
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
preStateBin = preStateBin._parent;
} // use return path to trace back steps to curStateBin.
let stack = [];
// need to pop back up to the same depth as the curr glstate group.
while (curStateBin._depth > preStateBin._depth) {
if (curStateBin._stateset !== undefined) {
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} // now pop back up both parent paths until they agree.
// should be this to conform with above case where two StateBin
// nodes have the same parent
//继续遍历直到两个树节点相同
while (preStateBin !== curStateBin) {
if (preStateBin._stateset !== undefined) {//pre的从GLState中出栈
glstate.popStateSet();
}
preStateBin = preStateBin._parent; if (curStateBin._stateset !== undefined) {//当前的入栈,临时保存
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} //遍历结束后,从临时栈中推入GLState里
for (let i = stack.length - 1, l = 0; i >= l; --i) {
glstate.pushStateSet(stack[i]);
}
};
这段代码我们仔细来看一下。
第一件事比较当前节点状态和前一个节点状态,相同则直接返回。
if (curStateBin === preStateBin) {//两个相同什么都不做
return;
}
接下来如果前后节点状态不同,就继续下面的事情,我们来看下面接下来做了什么事。接下来是判断当前遍历到的状态节点是否已经是树的叶子节点,如果是叶子节点就向树根部遍历,依次弹出上一级父节点直到遍历到整棵树的根节点。弹出是靠glstate这个参数来操作实现的注意一下。遍历到根节点并弹出状态后就直接返回了。
if (curStateBin === undefined) {
//curStateBin已经到顶,弹出preStateBin的所有状态
do {
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
preStateBin = preStateBin._parent;
} while (preStateBin);
return;
}
我们再看看接下来还做了什么操作,这个看注释就能理解他的操作。
if (preStateBin === undefined) {
//preStateBin已经到顶,压入curStateBin的所有状态
//从子节点往根节点遍历获取所有的状态,但是推给glstate必须从根节点往子节点遍历
//所以这里先塞到一个stack里面,然后再遍历stack推给glstate
let stack = [];
do {
if (curStateBin._stateset !== undefined) {
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} while (curStateBin);
let size = stack.length - 1;
for (let i = size; i >= 0; --i) {
glstate.pushStateSet(stack[i]);
}
return;
} else if (preStateBin._parent === curStateBin._parent) {
// first handle the typical case which is two glstate groups
// are neighbours.
// glstate has changed so need to pop old glstate.
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
// and push new glstate.
if (curStateBin._stateset !== undefined) {
glstate.pushStateSet(curStateBin._stateset);
}
return;
}
随后我们看看最后的操作。这波操作就是为了比较currStateBin和preStateBin这两个树节点的深度和对其向树根部的操作。
//先弹出状态,保证preStateBin和curStateBin达到树节点平级
//无法确定两个树节点谁的深度值更多,两个都做一次循环
while (preStateBin._depth > curStateBin._depth) {
if (preStateBin._stateset !== undefined) {
glstate.popStateSet();
}
preStateBin = preStateBin._parent;
} // use return path to trace back steps to curStateBin.
let stack = [];
// need to pop back up to the same depth as the curr glstate group.
while (curStateBin._depth > preStateBin._depth) {
if (curStateBin._stateset !== undefined) {
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} // now pop back up both parent paths until they agree.
// should be this to conform with above case where two StateBin
// nodes have the same parent
//继续遍历直到两个树节点相同
while (preStateBin !== curStateBin) {
if (preStateBin._stateset !== undefined) {//pre的从GLState中出栈
glstate.popStateSet();
}
preStateBin = preStateBin._parent; if (curStateBin._stateset !== undefined) {//当前的入栈,临时保存
stack.push(curStateBin._stateset);
}
curStateBin = curStateBin._parent;
} //遍历结束后,从临时栈中推入GLState里
for (let i = stack.length - 1, l = 0; i >= l; --i) {
glstate.pushStateSet(stack[i]);
}
StateBin渲染状态树是对osg的StateSet单个模型渲染状态的管理数据结构,几乎在整个DrawActor的过程中都要大量应用,他的重要性不言而喻,鲫鱼也是一知半解的在学习这个数据结构,希望大家多提出宝贵的见解,多多斧正,谢谢同学们的支持关注。今天就到这里,下周再见。本文系原创,引用请注明出处:https://www.cnblogs.com/ccentry/p/10224312.html
WebGL------osg框架学习二的更多相关文章
- WebGL——osg框架学习一
从今天开始,我们开始正式的学习osg框架,今天我们学习的是osg的渲染模块,我们来看一下代码结构. 所有DrawXXX的js模块都是渲染的模块,我们逐一来简单介绍一下,第一个Drawable.js,这 ...
- WebGL——osg框架学习三
今天继续来Draw绘制的osg模块的学习,昨天我们学习的是StateBin渲染状态树节点类,今天我们来继续学习下一个Draw的基础类DrawableEntity渲染对象实体类.这个类和Drawable ...
- WebGL——osg框架学习四
这篇我们接着来看一下DrawEntityActor类,我们来看看这个继承DrawActor的类到底做了什么事.我们之前学习了Drawable对应的DrawActor,那么我们类比的来看Drawable ...
- Struts2框架学习(二) Action
Struts2框架学习(二) Action Struts2框架中的Action类是一个单独的javabean对象.不像Struts1中还要去继承HttpServlet,耦合度减小了. 1,流程 拦截器 ...
- Android 学习笔记之AndBase框架学习(二) 使用封装好的进度框,Toast框,弹出框,确认框...
PS:渐渐明白,在实验室呆三年都不如在企业呆一年... 学习内容: 1.使用AbActivity内部封装的方法实现进度框,Toast框,弹出框,确认框... AndBase中AbActivity封 ...
- Hibernate框架学习(二)——api详解
一.Configuration对象 功能:配置加载类,用于加载主配置,orm元数据加载. //1.创建,调用空参构造(还没有读配置文件) Configuration conf=new Configur ...
- python flask框架学习(二)——第一个flask程序
第一个flask程序 学习自:知了课堂Python Flask框架——全栈开发 1.用pycharm新建一个flask项目 2.运行程序 from flask import Flask # 创建一个F ...
- Castle ActiveRecord框架学习(二):快速搭建简单博客网站
一.数据库 1.数据表 Category:类别标签表(字段Type=1为类别,Type=2为标签) Category_Post:类别标签与文章中间表 Post:文章表 Comment:评论表 2.数据 ...
- Spring框架学习(二)
一.依赖注入的三种注入方式 Spring框架为我们提供了三种注入方式:set注入.构造方法注入和接口注入. 1.set注入 规律:无论给什么赋值,配置文件中<property>标签的nam ...
随机推荐
- codeforces 547E Mike and Friends
codeforces 547E Mike and Friends 题意 题解 代码 #include<bits/stdc++.h> using namespace std; #define ...
- Alpha 冲刺报告
Alpha 冲刺报告(4/10) 队名:洛基小队 峻雄(组长) 已完成:继续行动脚本的编写 明日计划:尽量完成角色的移动 剩余任务:物品背包交互代码 困难:具体编码进展比较缓慢 ----------- ...
- 【openjudge】【递推】例3.4 昆虫繁殖
[题目描述] 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强.每对成虫过x个月产y对卵,每对卵要过两个月长成成虫.假设每个成虫不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵 ...
- 20155314 2016-2017-2 《Java程序设计》第10周学习总结
20155314 2016-2017-2 <Java程序设计>第10周学习总结 教材学习内容总结 了解计算机网络基础 掌握Java Socket编程 理解混合密码系统 掌握Java 密码技 ...
- Zookeeper入门(四)之Leader选举
让我们分析如何在ZooKeeper集合中选举leader节点.考虑一个集群中有N个节点.leader选举的过程如下: 所有节点创建具有相同路径 /app/leader_election/guid_ 的 ...
- dbcp最终版本
注意:我们在使用有参的queryrunner的时候,不需要关闭connection和DataSource 这些都queryrunner 都替我们完成.我们不需要关系资源释放. 工具类: package ...
- BI之报表测试总结
报表测试总结: 1.测试准备工作: 数据准备 保证足够多的有效数据 清楚报表中涉及到的算法.公式 清楚业务功能接口 2.报表测试点 基本测试点:界面.控件.格式.布局.明显的数据错误.js报错.报表标 ...
- 第7章 使用寄存器点亮LED灯—零死角玩转STM32-F429系列
第7章 使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...
- [教程] 【【【【odex教程之jar】】】】/system/framework里面的jar做odex g13
dexopt-wrapper core.jar core.odex dexopt-wrapper ext.jar ext.odex dexopt-wrapper framework.jar frame ...
- FullCalendar Timeline View 使用
FullCalendar Timeline View(v4) The Scheduler add-on provides a new view called “timeline view” with ...