4.2 Geometric State及其更新
来源:互联网 发布:移动电玩城源码 编辑:程序博客网 时间:2024/05/16 04:20
与此相关的四个基本类是 vertexbuffer,index buffer,transformations和boundingvolumes。
一, VB 和IB
VB包含了position,color,texture coordinates,normals,IB包含了点的邻接信息。VB和IB共同组成geometric primitive,它可以是点集,多边形,和三角网格等。Geometry类便是其容器。
二, Transformation
1.原理
R代表旋转矩阵,T代表平移向量,>0代表uniform scaling。
变换方程为Y=R( X)+T 逆变换为 X=,1-σ.,.,R-T.(Y−T)
若为nonuniform scaling,则
Y=RSX+T, 逆变换为X=,其中,S=diag(,σ-0.,,σ-1.,,σ-2.)
若引入nonuniform S,则计算量很大,同时,将M(齐次矩阵左上角的3x3部分)分解为R和S几乎是不可能的(详见p236)
若引入nonunifrom scale,在每一个transformation中分别存储R,S,T显然是不现实的,因此,应以M,T的形式存储,这样便无法分别获得R,S,不仅如此,计算量也会增加,一种解决办法(不完美)是写成(L,S,R,T)的形式,并计算
M=LDR(singular value decomposition),但计算量也不小。
作者的思路是为了运算方便,在Node中不支持nonuniform scale,只在Geometry中支持nonuniform scale,这样一来,除了最底层的节点,每节都可分别获得R,,T,也避免了完全不支持nonunifrom scale 的缺点。
2.Transformation类简介(详见p237-244)
现仅简述关键问题若干。
(1) Set系列函数有side effect,它不准确的设置了3个bool变量,但换来的是安全性。
(2) GetNorm()的作用是将3个nonuniform scale分量强制转换为一个uniformscale。
专用于包围球的变换,因为球体经nonuniform scale会变为椭球,而WM不支持此种类型的包围体。
(3) Transformation::ApplyInverse()与Transformation::InvertVector()的区别。前者作用于点,后者作用于向量(如法线)。
对于点P,, 对于向量V,,V-..=RSV(向量不需要平移)。
(4) Transformation::Inverse()的特殊性。
该函数的功能仅仅是获取逆变换中的,和−,S-−1.,.,R-T.T,考虑到X=,因此参数中返回的Transformation只能作为一个容器,而不能用于对点进行逆变换,若要对点进行逆变换,用ApplyInverse.
(5) 对平面,N-0.∙X=,C-0.进行变换。
将(Y-T)代入上式,得
,N-1.=,R,S-−1.,.,N-0.-.-|R,S-−1.,.,N-0.|.
,C-1.=,,,,C-0.-.-|R,S-−1.,.,N-0.|.+
(6)除法对CPU的开销远大于乘法,因此对于a/d,b/d,c/d,应改为
P=1/d,ap,bp,cp.
三, bounding volumes
bounding volumes的作用有二:剔除,碰撞检测。
1. 剔除
Inexact query 基本思路:当检测到包围体完全位于某一个截面之外时,即判定该包围体位于整个视景体之外。
Inexact体现在存在边角物体,虽然其包围体不在任何截面之外,但该物体仍在视景体之外,不过值得庆幸的是,这样的情况并不多见。
Scene graph的好处体现在一旦检测到某节点完全位于视景体之外或之内,那么节点下的每一层物体均位于视景体之外或之内,scene graph便会通知下面的每一层没有必要再检测,可通过传递位数组实现。
一个问题是应该选尽量复杂的包围体还是尽量简单的包围体,这个没有一般规律可循,多加调试即可。
2. 碰撞检测,3D拾取 详见第八章。
3. 抽象类BoundingVolume
这个类是抽象类,在开发阶段我们必须继承这个类而不能直接使用。这样做的目的是让该核心类可支持各种类型的包围体以及满足各种形式的几何操作。
但该类还是保留了一些基本信息:
(1) center:包围体的中心,如球的球心,orientedbox 的中心,凸多面体的重心等等。
(2) radius:包围体的大小。如球的半径,orientedbox的顶点到中心的最大距离,凸多面体的顶点到重心的最大距离。
实际上,我们可以发现,该抽象类的默认形状是球体。
一些说明:static BoundingVolume * Create()
该函数的功能是在不知道引擎中存在哪些类型的包围体时,批量生成大量对象,待研究!!!若要把抽象类换成其他类,须重载Create()
两个说明:(1)该抽象类只支持同种类型包围体之间的操作,为了简化引擎,若要支持,需派生类。
(2) 包围体的合并是很复杂的算法。
四, Geometry TYPES
如点集,线段集,linestrip,多边形,三角网格等。
Points
点集存在于VB中,但实际绘制通常是激活的那部分。
m_iActiveQuantity用于存储激活数目。
IBuffer->GetIndexQuantity用于获得ID中所有索引数,但我们通过SetIndexQuantity将其设为激活的索引数,但须自己记住原值,以便恢复。
LineSegments
构造函数会根据参数值调用SetGeometryType,设置类型。关于激活数目,原理同上。
TriangleMeshes(最常见的类型)
该类中实现了计算法向量的函数:
N=,,,,V-1.−,V-0....X(,V-2.−,V-0.)
,N.=,,i=1-M-,-,N-i....-|,i=1-M-,-,N-i....|.
Particles
详见第五章。
五, Geometric State的更新。
当以下任何一项改变时,geometry state需要更新:
(1) vertex position(2)bounding volumes (3)transformation (4)场景图的拓扑结构
三个核心类均参与了该过程,该过程是在自顶向下和自下及顶两步对场景图的遍历中完成的。
相关成员变量及成员函数简介如下:
先看成员变量
ClassSpatial::public Object
{
Public:
Transformation Local;//这里存储了每个Geometry或Node的local transformation。
Transformation World;//这里存储了每个Node或Geometry的worldtransformation。
bool WorldIsCurrent;//该变量决定World是否需要更新。若为true,则不更新。该变量为编程带来了极大的灵活性,例如,Controller可能直接对world进行更新,这样就没有必要通过父节点计算world将该变量设为true即可实现这一点。
BoundingVolumePtr WorldBound;//存储了world bounding volume。
bool WorldBoundIsCurrent; //该变量决定WorldBound是否需要更新。设为true,则不需要更新。例如:(1)Controller可能直接对worldbound进行更新,此时便没必要通过worldtransformation*local bound或growtocontain()计算WorldBound。(2)某节点worldbound已经确定为固定不变,如一个房间,已知房间内的物体无论如何移动都不会移动出房间。
}
Class Geometry:public Spatial
{
Public:
BoundingVolumePtr ModelBound;//该变量存储了model boundingvolume。
}
再看成员函数。
三大顶层函数:updateGS, updateBS, updateMS
Class Spatial:public Object
{
Public:
Void UpdateGS(double dAppTime=-Mathd::MAX_REAL, bool bInitiator=true);
//该函数为三大顶层函数之一,公共接口由程序员调用,该函数负责node或geometry的geometry state的更新,既包括自顶向下的worldtransformation的计算,底层的world boundingvolume的计算,又包括自底向上的Node worldbounding volume的计算,该函数的定义见下文的函数调用图。
Void UpdateBS();//三大顶层函数之一,只负责worldbounding volume 的更新。例如,在某些情况下,localtransformation没有变化,worldtransformation没变,只有一些几何操作导致了worldbounding volume的变化,因此,只需要更新wvb,而不必向下遍历,此时调用UpdateBS()即可。
Protected:
Virtual void UpdateWorldData(double dAppTime);//虚函数,具体的实现怎样要看调用者是Node 还是Geometry。若是Node,先调用基类的Spatial的同名函数,在调用每个子类的UpdateGS,进行递归;若是Geometry,直接调用Spatial中的UpdateGS该函数调用controller,在更新global state和lights,再计算world transformation。
Virtual void UpdateWorldBound()=0;//纯虚函数,因为Node和Geometry各有不同的实现,两者毫无关系,若为Node,则根据子节点的world bound 计算Node的world bound,若为Geometry,则直接通过worldbound*world transformation计算world bound。
Void propagateTOROOT();//该函数是否执行取决于bInitiator是否为true。负责向上遍历以更新父节点的world bound。
}
Class Geometry:public spatial
{
Public:
Void UpdateMS(bool bUpdateNormals=true);//三大顶层函数之一。该函数负责更新modelbound,并根据参数是否为true,决定是否更新normal。
Protected:
Virtual void UpdateModelBound();
Virtual void UpdateModelNormals();
Virtual void Updateworldbound();//计算geometry的world bound。
}
Class Node:public spatial
{
Protected:
Virtual void UpdateWorldData(double dAppTime);
Virtual void UpdateWorldBound();//此两个函数上文已说明。
}
附:三大顶层函数的函数调用图。
Node Spatial::UpdateGS
UpdateWorldData Spatial::UpdateWorldData
调用每个子节点的UpdateGS(递归开始)
UpdateWorldBound 调用WorldBound---àGrowToContain
PropagateBoundToRoot() m_pkParent->UpdateWorldBound()
m->pkParent->PropagateBoundToRoot()(递归开始)
Geometry Spatial::UpdateGS
controller
Spatial::UpdateWorldData 更新global state 及lights
计算WorldTransformation
UpdateWorldBound(递归返回)
PropagateBoundToRoot
UpdateWorldBound();
Node/Geometry->Spatial::UpdateBS
PropagateBoundToRoot();
UpdateModelBound()
Geometry->UpdateMS
UpdateModelNormals()//调用与否由参数决定。
调用原则见表p279
UpdateGS调用次数为本身需要更新且更上层的所有节点均不需要更新的Node的个数。
- 4.2 Geometric State及其更新
- wild magic3的Scene graph结构和Geometric State更新体系
- wild magic3的Scene graph结构和Geometric State更新体系(转载)
- 4.3RenderState及其更新
- ReactNative FlatList state更新,视图不更新的问题
- Geometric Scaling
- State
- state
- State
- state
- State
- state
- STATE
- State
- state
- state
- state
- state
- 主题:北京亿阳信通Oracle笔试题
- 读书笔记一则
- 4.1 scene graph构建的基本问题
- log4j 1.3 配置
- 猛料真相大白:云计算 梦幻的泡影
- 4.2 Geometric State及其更新
- BlackBerry模拟器中文转换
- 4.3RenderState及其更新
- log4j 1.2 配置 xml
- 4.5the Culing Pass
- BlackBerry资源网站
- win7开机黑屏开计算机无桌面图标任务栏
- interface ---接口 的简单应用
- 4.6the Drawing Pass