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 ...
随机推荐
- libcurl-7.54.1附加zlib1.2.11的编译
手上有个小程序需要通过HTTP协议通信,选择了出名的libcurl作为支持库.由于网上的教程多是命令行编译,本人记性不好,比较讨厌记住一堆命令,因此折腾了一天通过VS对libcurl和zlib进行了编 ...
- 手写阻塞队列(Condition实现)
自己实现阻塞队列的话可以采用Object下的wait和notify方法,也可以使用Lock锁提供的Condition来实现,本文就是自己手撸的一个简单的阻塞队列,部分借鉴了JDK的源码.Ps:最近看面 ...
- bin/hdfs dfs命令
appendToFile Usage: hdfs dfs -appendToFile <localsrc> ... <dst> 追加一个或者多个文件到hdfs制定文件中.也可以 ...
- Weblogic web应用中获取文件的绝对路径
注意点: 1. file必须在/下,或者/WEB-INF/,不能在classes下 2. weblogic中进行如下配置,以获取绝对路径: <wls:container-descriptor&g ...
- centos安装不上的问题
Installing VMware Tools, please wait...mount: special device /dev/hda does not existmount: block dev ...
- HDU5343:MZL's Circle Zhou(SAM,记忆化搜索DP)
Description Input Output Sample Input Sample Output Solution 题意:给你两个串,分别从两个里面各选出一个子串拼到一起,问能构成多少个本质不同 ...
- [AHOI2009]飞行棋
嘟嘟嘟 刚开始想这道题的时候确实很蒙,只想到矩形对边做对应的弧长相等,然后想办法凑出相等的弧长.其实正解很简单,不要去想边,应该想对角线,因为根据初中园的知识,这个矩形的对角线是圆的直径,而直径所对的 ...
- Redis基本数据类型命令汇总
前言 前阶段写Redis客户端作为学习和了解Redis Protocol,基本上把Strintg,List,Hash,Set,SortedSet五种基础类型的命令都写完了,本篇进行总结,也相当于复 ...
- fiddler的inspectors传入的参数乱码
问题描述:如图Q1所示.传入的参数存在中文乱码问题. 本机:win7 系统,解决方法如下 1.windows按钮+R 2.输入regedit +回车+是 3.HKEY_CURRENT_USER\So ...
- springboot不使用内置tomcat启动,用jetty或undertow
Spring Boot启动程序通常使用Tomcat作为默认的嵌入式服务器.如果需要更改 - 您可以排除Tomcat依赖项并改为包含Jetty或Undertow: jetty配置: <depend ...