4.2 Geometric State及其更新

来源:互联网 发布:移动电玩城源码 编辑:程序博客网 时间:2024/05/16 04:20

与此相关的四个基本类是 vertexbufferindex buffertransformationsboundingvolumes

一,   VB IB

  VB包含了positioncolortexture coordinatesnormalsIB包含了点的邻接信息。VBIB共同组成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部分)分解为RS几乎是不可能的(详见p236

若引入nonunifrom scale,在每一个transformation中分别存储R,S,T显然是不现实的,因此,应以M,T的形式存储,这样便无法分别获得R,S,不仅如此,计算量也会增加,一种解决办法(不完美)是写成(L,S,R,T)的形式,并计算

          M=LDRsingular value decomposition),但计算量也不小。

作者的思路是为了运算方便,在Node中不支持nonuniform scale,只在Geometry中支持nonuniform scale,这样一来,除了最底层的节点,每节都可分别获得R,,T,也避免了完全不支持nonunifrom scale 的缺点。

 

 2Transformation类简介(详见p237-244

  现仅简述关键问题若干。

(1)       Set系列函数有side effect,它不准确的设置了3bool变量,但换来的是安全性。

(2)       GetNorm()的作用是将3nonuniform 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 position2bounding volumes 3transformation 4)场景图的拓扑结构

三个核心类均参与了该过程,该过程是在自顶向下和自下及顶两步对场景图的遍历中完成的。

相关成员变量及成员函数简介如下:

先看成员变量

ClassSpatial::public Object

{

Public:

Transformation  Local;//这里存储了每个GeometryNodelocal transformation

Transformation  World//这里存储了每个NodeGeometryworldtransformation

bool  WorldIsCurrent//该变量决定World是否需要更新。若为true,则不更新。该变量为编程带来了极大的灵活性,例如,Controller可能直接对world进行更新,这样就没有必要通过父节点计算world将该变量设为true即可实现这一点。

BoundingVolumePtr  WorldBound//存储了world bounding volume

bool  WorldBoundIsCurrent //该变量决定WorldBound是否需要更新。设为true,则不需要更新。例如:(1Controller可能直接对worldbound进行更新,此时便没必要通过worldtransformation*local boundgrowtocontain()计算WorldBound。(2)某节点worldbound已经确定为固定不变,如一个房间,已知房间内的物体无论如何移动都不会移动出房间。

}

Class  Geometrypublic Spatial

{

Public

BoundingVolumePtr  ModelBound//该变量存储了model boundingvolume

}

再看成员函数。

三大顶层函数:updateGS  updateBS   updateMS

Class  Spatialpublic  Object

{

Public

Void  UpdateGSdouble dAppTime=-Mathd::MAX_REAL, bool bInitiator=true;

//该函数为三大顶层函数之一,公共接口由程序员调用,该函数负责nodegeometrygeometry state的更新,既包括自顶向下的worldtransformation的计算,底层的world boundingvolume的计算,又包括自底向上的Node worldbounding volume的计算,该函数的定义见下文的函数调用图。

Void  UpdateBS();//三大顶层函数之一,只负责worldbounding volume 的更新。例如,在某些情况下,localtransformation没有变化,worldtransformation没变,只有一些几何操作导致了worldbounding volume的变化,因此,只需要更新wvb,而不必向下遍历,此时调用UpdateBS()即可。

Protected

     Virtual  void UpdateWorldDatadouble dAppTime;//虚函数,具体的实现怎样要看调用者是Node 还是Geometry。若是Node,先调用基类的Spatial的同名函数,在调用每个子类的UpdateGS,进行递归;若是Geometry,直接调用Spatial中的UpdateGS该函数调用controller,在更新global statelights,再计算world transformation

      Virtual  void UpdateWorldBound()=0//纯虚函数,因为NodeGeometry各有不同的实现,两者毫无关系,若为Node,则根据子节点的world bound 计算Nodeworld bound,若为Geometry,则直接通过worldbound*world transformation计算world bound

     Void  propagateTOROOT();//该函数是否执行取决于bInitiator是否为true。负责向上遍历以更新父节点的world bound

}

 

 Class Geometrypublic spatial

{

   Public

      Void UpdateMSbool  bUpdateNormals=true;//三大顶层函数之一。该函数负责更新modelbound,并根据参数是否为true,决定是否更新normal

   Protected

       Virtual  void   UpdateModelBound();

       Virtual  void   UpdateModelNormals();

       Virtual    void  Updateworldbound();//计算geometryworld bound

}

 

Class Nodepublic spatial

{

   Protected

        Virtual   void  UpdateWorldDatadouble 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的个数。

原创粉丝点击