4.2 Geometric State及其更新

前端之家收集整理的这篇文章主要介绍了4.2 Geometric State及其更新前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

与此相关的四个基本类是 vertex buffer index buffer transformations bounding volumes

一, 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,R,T )的形式,并计算

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

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

2 Transformation 类简介(详见 p237-244

现仅简述关键问题若干。

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

@H_619_404@(2) GetNorm ()的作用是将 3 nonuniform scale 分量强制转换为一个 uniform scale

专用于包围球的变换,因为球体经 nonuniform scale 会变为椭球,而 WM 不支持此种类型的包围体。

@H_619_404@(3) Transformation :: ApplyInverse ()与 Transformation :: InvertVector ()的区别。前者作用于点,后者作用于向量(如法线)。

对于点 P , 对于向量 V ,V-..=RSV (向量不需要平移)。

@H_619_404@(4) Transformation :: Inverse ()的特殊性。

函数功能仅仅是获取逆变换中的 , −,S-−1.,R-T.T , 考虑到 X= ,因此参数中返回的 Transformation 只能作为一个容器,而不能用于对点进行逆变换,若要对点进行逆变换,用 ApplyInverse.

(5) 对平面 ,N-0.∙X=,C-0. 进行变换。

(Y-T) 代入上式,得

,N-1.=,N-0.-.-|R,N-0.|.

,C-1.=,C-0.-.-|R,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 :包围体的中心,如球的球心, oriented Box 的中心,凸多面体的重心等等。

(2) radius :包围体的大小。如球的半径, oriented Box 的顶点到中心的最大距离,凸多面体的顶点到重心的最大距离。

实际上,我们可以发现,该抽象类的默认形状是球体。

一些说明: 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....-|,N-i....|.

Particles

详见第五章。

五, Geometric State 的更新。

当以下任何一项改变时, geometry state 需要更新:

(1) vertex position 2 bounding volumes 3 transformation 4 )场景图的拓扑结构

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

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

先看成员变量

Class Spatial::public Object

{

Public:

Transformation Local;// 这里存储了每个 Geometry Node local transformation

Transformation World // 这里存储了每个 Node Geometry world transformation

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 bounding volume

}

再看成员函数

三大顶层函数 updateGS updateBS updateMS

Class Spatial public Object

{

Public

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

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

Void UpdateBS (); // 三大顶层函数之一,只负责 world bounding volume 的更新。例如,在某些情况下, local transformation 没有变化, world transformation 没变,只有一些几何操作导致了 world bounding 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 ,则直接通过 world bound*world transformation 计算 world bound

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

}

Class Geometry public spatial

{

Public

Void UpdateMS bool bUpdateNormals=true ;// 三大顶层函数之一。该函数负责更新 model bound ,并根据参数是否为 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 的个数。

猜你在找的VB相关文章