第02章 幾何和變換_第1頁
第02章 幾何和變換_第2頁
第02章 幾何和變換_第3頁
第02章 幾何和變換_第4頁
第02章 幾何和變換_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、第二章 幾何和變換幾乎所有圖形軟件都以幾何類(geometric classes, 這里指c+類)為基礎(chǔ).這些類表示了諸如點,向量,光線等等的數(shù)學(xué)構(gòu)件. 由于我們在系統(tǒng)中會到處用到這些類, 良好的抽象和有效的實現(xiàn)至關(guān)重要. 本章會講解pbrt的幾何基礎(chǔ)的接口和實現(xiàn).幾何類見文件 core/geometry.h 和core/geometry.cpp.變換矩陣見文件 core/transform.h 和core/transform.cpp.2.1 坐標(biāo)系統(tǒng)pbrt用三個浮點數(shù)坐標(biāo)值x,y,z來表示三維點,向量和法向量. 當(dāng)然,這些值只有在一個給定的坐標(biāo)系下才有意義: 給定一個原點和三個定義x,y,

2、z軸的向量,就定義了這個坐標(biāo)系(frame).在n維空間中, 坐標(biāo)系的原點P0和其n個線性無關(guān)的基向量定義了n維仿射空間(affine space).所有空間中的向量V可以被表達(dá)成為基向量(V1,V2, ., Vn)的線性組合: V = s1V1 + s2V2 + . + snVn (s1, s2, . sn是唯一存在的一組純量, 被稱為V關(guān)于基(V1,V2.Vn)的表達(dá)).同樣地, 對與點P而言, 它可用原點P0和基向量(V1,V2, ., Vn)表達(dá): P = P0 +s1V1 + s2V2 + . + snVn以上討論有點循環(huán)定義的味道: 要定義坐標(biāo)系我們需要定義一個點和一組向量, 而點

3、和向量只有在給定的一個坐標(biāo)系下才有意義. 因此,我們需要一個標(biāo)準(zhǔn)坐標(biāo)系, 其原點是(0,0,0), 基向量為(1,0,0), (0,1,0) 和(0,0,1).2.1.1 左/右手坐標(biāo)系我們知道坐標(biāo)系分左手坐標(biāo)系和右手坐標(biāo)系,pbrt用左手坐標(biāo)系.2.2 向量 = class COREDLL Vector public: ;一個向量表達(dá)了三維空間內(nèi)的一個方向, 它由三個浮點數(shù)定義:= float x, y, z; x,y,z被定義為公共成員, 不太符合C+的封裝原則, 但我們這樣做是為了代碼的清晰和效率.缺省情況下, (x,y,z)被設(shè)成0. 用戶可以選擇給定任意值:= Vector(floa

4、t _x = 0, float _y = 0, float _z = 0) : x(_x), y(_y), z(_z) 2.2.1 向量運算向量加法運算: += Vector operator+(const Vector &v) const return Vector(x+v.x, y + v.y, z + v.z); Vector& operator+=(const Vector &v) const x += v.x;y += v.y;z += v.z; return *this; 向量減法運算與上類似, 略.2.2.2 比例運算比例運算是純量乘法, 即是將向量每個分量乘以一個純量, 從而改

5、變了它的長度. += Vector operator*(float f) const return Vector(f*x,f*y, f*z); Vector& operator*=(const Vector &v) const x*=f;y *= f;z*= f; return *this; = inline Vector operator*(float f, const Vector &v) return v*f; 類似地,我們可以定義純量除法 operator/ 和 operator /=, 此略. Vector類還有一個取負(fù)值的單操作符定義, 用來返回一個方向相反的向量: += Vect

6、or operator-() const return Vector(-x, -y, -z); 下面兩個函數(shù)可以用索引值0,1,2方便地使用向量的各個分量: v0得到x值, v1得到y(tǒng)值, v2得到z值. += float operator(int i) const Assert(i = 0 & i = 0 & i = 2); return (&x); 2.2.3 點積和叉積對于兩個向量V和W, 它們的點積(V . W)定義為:Vx*Wx + Vy*Wy + Vy*Wy. = inline float Dot(const Vector &v1, const Vector &v2) return

7、 v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; 點積跟兩向量的夾角關(guān)系是: (v.w) = |v| |w| cos 如果兩個非退化(即非(0,0,0)的向量相互垂直, 則(v.w)為零; 反之,也成立. 兩個或多個相互垂直的向量被稱為是正交的(orthogonal), 一組正交的單位向量被稱為規(guī)格化正交的(orthonormal).假定u,v,w是向量, s是純量, 則有下列性質(zhì): (u . v) = (v . u) (su . v) = s(v . u) (u . (v + w) = (u . v) + (u . w)我們常常要計算點積的絕對值, 故有如下

8、函數(shù): = inline float AbsDot(const Vector &v1, const Vector &v2) return fabsf(Dot(v1,v2); 叉 積是另一個很有用的向量操作. 給定三維空間的兩個向量, 叉積v w 是垂直于兩者的向量. 注意這個新向量的朝向是由坐標(biāo)系的左右手定則(handedness)決定的.給定兩個正交的向量 v 和 w, 那么, (v, w, v w) 就按照給定的左右手定則形成一個坐標(biāo)系.在左手系中, 叉積定義為: (v w)x = vy wz vz wy (v w)y = vz wx vx wz (v w)z = vx wy vy wx有

9、一個幫助記憶的公式是計算下面矩陣的行列式值:其中i, j, k分別代表軸(1, 0, 0), (0, 1, 0), (0, 0, 1). 注意這只是一個記憶工具, 而不是嚴(yán)格的數(shù)學(xué)表達(dá), 因為矩陣把純量和向量混合在一起用了. += inline Vector Cross(const Vector &v1, const Vector &v2) return Vector(v1.y * v2.z) (v1.z * v2.y), (v1.z * v2.x) (v1.x * v2.z), (v1.x* v2.y) (v1.y * v2.z);從叉積的定義中,我們得出: | v w | =| v | |

10、w| sin (是v和w的夾角)從上式可以看出, 兩個相互垂直的單位向量的叉積也是一個單位向量. 如果兩個向量平行, 則它們的叉積是個退化的向量.另外, 可以看出, 以兩個向量v1 , v2為邊的平行四變形面積是| v1 v2 |.2.2.4 向量正規(guī)化把一個向量變換成具有相同方向的單位向量就是向量的正規(guī)化, 方法是將向量的各個分量除以向量的長度: += float LengthSquared() const return x * x + y * y + z * z; float Length() const return sqrtf(LengthSquared(); += inline Ve

11、ctor Normalize (const Vector &v) Return v / v.Length(); 2.2.5 由一個向量建立的坐標(biāo)系我們會經(jīng)常用一個向量構(gòu)造一個坐標(biāo)系. 由于叉積跟兩個向量垂直, 我們可以通過兩次叉積(該向量跟任意一個向量叉積得到第二個向量, 第一和第二向量叉積得到第三個向量) 來得到三個相互垂直的向量,因而得到一個坐標(biāo)系.Pbrt所用的方法是: 給定一個正規(guī)化的向量v1, 把該向量其中一個分量置零并互換另外兩個分量的值, 然后對之正規(guī)化,就得到第二個向量 v2 (可以驗證v1和v2相互垂直), 再由v1和v2的叉積得到第三個向量: += inline void

12、CoordinateSystem(const Vector &v1, Vector *v2, Vector *v3) if(fabsf(v1.x) fabsf(v1.y) Float invLen = 1.f/sqrtf(v1.x * v1.x + v1.z * v1.z); *v2 = Vector(-v1.z * invLen, 0.f, v1.x * invLen); else Float invLen = 1.f/sqrtf(v1.y * v1.y + v1.z * v1.z); *v2 = Vector(0.f,v1.z * invLen, -v1.y* invLen); *v3 =

13、 Cross(v1, *v2); 2.3 點 += Class COREDLL Point Public: ;點是三維空間的位置.雖然它跟向量一樣也是用(x,y,z)三個坐標(biāo)值表示, 但由于它們本質(zhì)上的不同, 處理它們的方式也是不同的. = Float x, y, z;跟Vector的構(gòu)造器一樣, Point構(gòu)造器也是用可選的參數(shù)設(shè)置x,y,z的坐標(biāo)值: = Point(float _x = 0, float _y = 0, float _z = 0) : x(_x), y(_y), z(_z) 有一些Point的函數(shù)返回一個Vector,或者用一個Vector作為參數(shù). 比如, 把一個向量加

14、到一個點上, 就是相當(dāng)于將它在給定的方向上偏移而得到一個新的向量. 同樣地, 兩個點相減,得到它們之間的向量: += Point operator+ (const Vector &v) const return Point(x + v.x, y + v.y, z + v.z); Point &operator += (const Vector &v) x += v.x; y += v.y; z += v.z; return *this; += Vectoroperator- (const Point &p) const return Vector(x - p.x, y -p.y, z- p.z

15、); Point operator- (const Vector &v) const return Point(x -v.x, y - v.y, z - v.z); Point &operator -= (const Vector &v) x -= v.x; y -= v.y; z -= v.z; Return *this;下面是求兩點之間距離的函數(shù): += inline float Distance(const Point &p1, const Point &p2) return (p1- p2).Length(); inline float DistanceSquared(const Po

16、int &p1, const Point &p2) return (p1- p2).LengthSquared(); 雖然點乘以純量不具數(shù)學(xué)意義, 但是Point類仍然支持純量乘的定義, 用以求多個點的加權(quán)和. 其實現(xiàn)跟Vector中的實現(xiàn)類似, 從略.2.4 法向量+= class COREDLL Normal public: ;法向量是在給定點上垂直于表面的向量。它可以被定義成兩個互相不平行的表面切向量的叉積。雖然法向量跟向量很相似,但是應(yīng)知它們的不同:因為法向量是根據(jù)它跟特定的曲面來定義的,在某些情況下跟向量是不同的,特別是使用變換的時候。(見第2.8節(jié))。Normal和Vector的實

17、現(xiàn)很相似,都是用三個浮點數(shù)x,y,z表示,并定義了法向量之間的加,減,純量乘,正規(guī)化等運算。但是,法向量不能跟一個點相加,也不能取兩個法向量的叉積。還有,法向量不一定是正規(guī)化的。Normal提供了由一個Vector初始化一個Normal的構(gòu)造器。由于Normal和Vector有細(xì)微的差別,我們不希望它們之間有隱性的轉(zhuǎn)換。為此,C+的explicit關(guān)鍵詞可以保證它們之間顯性的轉(zhuǎn)換。 = explict Normal(const Vector &v) : x(v.x),y(v.y), z(v.z) += explict Vector(const Normal &n); += inline Vec

18、tor:Vector(const Normal &n) :x(n.x), y(n.y), z(n.z) 這樣一來,如果聲明了Vectorv; Normaln; 那么 n = v 就是非法的,必須用顯式的轉(zhuǎn)換:n = Normal(v).我們還重載了Dot()和AbsDot() 函數(shù)來覆蓋求法向量和向量之間的求點積的各種組合情況, 另外,其它跟Vector類似的函數(shù)都不提及了。2.5 光線 += class COREDLL Ray public: ;光線是一條由其原點和方向定義的射線。pbrt用Ray類來表達(dá)光線,其中用一個Point成員變量表示其原點,用一個Vector表示其方向: = Poi

19、nto; Vector d;光線的參數(shù)化形式是一個關(guān)于純量t的方程: r(t) = o + t d 0t Ray 類還包含兩個值mint和maxt,把光線限定在r(mint), r(maxt)區(qū)間之間。 它們聲明為mutable, 這意味著即使它們所在的Ray是const, 也是可以被改變的。其目的就是方便光線/物體的求交, 因為在這過程中,總是要記錄最近的交點所對應(yīng)的t值。 += mutable float mint, maxt;為了模擬運動模糊效果, 每條光線還需要一個時間值: += float time;Ray的構(gòu)造器很簡單明了: = Ray() : mint(RAY_EPSILON),

20、 maxt(INFINITY), time(0.f) Ray(const Point &origin, const Vector &direction, float start = RAY_EPSION, float end = INFINITY, float t = 0.f) : o(origin), d(direction), mint(start), maxt(end), time(t) = #defineRAY_EPSILON 1e-3f注意我們用一個極小的數(shù)(RAY_EPSILON)來初始化mint, 而不是用0, 原因是避免因浮點計算精度而引起的自相交的錯誤, 這是一個在光線追蹤中

21、的很典型的手法。我們還重載函數(shù)操作符“()”, 來求和參數(shù)t對應(yīng)的點: += Point operator() (float t) const return o + d * t;這樣,我們可以很方便地寫類似下面的代碼: Ray r(Point(0,0,0), Vector(1,2,3); Point p = r(1.7);2.5.1 光線微分為 了更好地利用第11章定義的紋理函數(shù)進(jìn)行反走樣,pbrt對每條被追蹤的光線都保持著一些附加的信息。 在第11.1節(jié), 這些信息用在Texture類中估算一小部分的場景在圖像平面上的投影面積。這樣,Texture類就可以計算出紋理在這個面積上的平均值,從而

22、得到更好 的圖像。RayDifferential是Ray的子類, 并包含兩條輔助光線的附加信息。 這兩條光線表示從主光線向x和y方向分別偏置一個像素而得到的相機光線。確定了這三條光線投射到被著色物體上的區(qū)域,Texture就可以估算出用于反走樣的平均值。 += class COREDLL RayDifferential : public Ray public: ; = RayDifferential() hasDifferentials = false; RayDifferential(const Point &org, const Vector &dir) : Ray(org, dir) h

23、asDifferentials = false; 注意我們用到關(guān)鍵字explicit,防止不經(jīng)意的Ray到RayDifferential的轉(zhuǎn)換。 變量hasDifferentials被初始化為false, 表示相鄰的兩條光線還是未知的。 += explicit RayDifferential(const Ray &ray) : Ray(ray) hasDifferentials = false; = bool hasDifferentials; Ray rx, ry;2.6 三維包圍盒 += class COREDLL BBOX public: ;pbrt所要渲染的場景經(jīng)常包含計算很費時的物體

24、。 一個包含整個物體的三維包圍體對很多操作而言都會非常有用。比如, 如果光線沒有穿過包圍盒, 就不必求光線和其中所包圍的物體的交點了。包圍體的有效性跟兩個因素有關(guān):計算包圍體的時間化費和包圍盒包圍物體的緊密程度。如果哦包圍體太“寬松”了,就會浪費很多不必要的計算;反過來, 如果強求非常緊密的包圍體,那么包圍體很可能變得太復(fù)雜,時間耗費也會不菲。包 圍體有很多種, pbrt用到沿軸的包圍盒(axis-aligned bounding boxes, AABB). 其他的常見的選擇包括沿方向的包圍盒(oriented bounding boxes, OBB)和包圍球。AABB可以由一個頂點和分別沿x

25、,y,z軸方向的三個長度值來表示, 也可以由包圍盒上兩個相對的頂點來表示。pbrt就是用兩點表示的,一個點的坐標(biāo)是x,y,z的最小值,另一個是x,y,z的最大值。BBOX缺省構(gòu)造器把包圍盒的范圍定義成退化的 : pMin.x pMax.x, 即是空包圍盒。 = BBox() pMin = Point (INFINITY, INFINITY, INFINITY); pMax= Point (-INFINITY, -INFINITY, -INFINITY); ; = Point pMin, pMax;有時我們用到包含一個點的包圍盒: += BBox(const Point &p) : pMin(p

26、), pMax(p) 我們還可以用兩個點p1, p2來構(gòu)造BBOX, p1和p2不必滿足p1.x = p2.x等條件, 構(gòu)造器可以計算出最大、最小值: += BBox(const Point &p1,const Point &p2 ) pMin = Point(min(p1.x, p2.x), min(p1.y, p2.y), min(p1.z, p2.z); pMax = Point(max(p1.x, p2.x), max(p1.y, p2.y), max(p1.z, p2.z); 給定一個包圍盒和一個點,BBox:Union()計算并返回一個包含該點和原包圍盒的新包圍盒: = CORED

27、LL BBox Union(const BBOX &b, const Point &p) BBox ret = b; ret.pMin.x = min(b.pMin.x, p.x); ret.pMin.y = min(b.pMin.y, p.y); ret.pMin.z = min(b.pMin.z, p.z); ret.pMax.x = min(b.pMax.x, p.x); ret.pMax.y = min(b.pMax.y, p.y); ret.pMax.z = min(b.pMax.z, p.z); return ret; 同樣地,我們可以構(gòu)造一個包含兩個包圍盒的包圍盒: += fri

28、end COREDLL BBox Union(const BBox &b, const BBox &b2);很容易判定兩個包圍盒是否重疊: += bool Overlaps(const BBox &b) bool x = (pMax.x = b.pMin.x) & (pMin.x = b.pMin.y) & (pMin.y = b.pMin.z)& (pMin.z = b.pMax.z); return (x & y & z); 下面函數(shù)判定一個點是否在包圍盒內(nèi): += boolInside(const Point &pt)const return (pt.x = pMin.x & pt.x

29、= pMin.y & pt.y= pMin.z & pt.z= pMax.z); BBox:Expand()用來擴(kuò)張包圍盒, BBox:Volume()用來計算包圍盒的體積: += void Expand(float delta) pMin -= Vector(delta, delta, delta); pMax += Vector(delta, delta, delta); += float Volume() const Vector d = pMax - pMin; return d.x * d.y * d.z; BBox:MaximumExtent()返回最長的那個軸。在建造kd樹時,我

30、們用它決定沿那個軸劃分。 += int BBox:MaximumExtent() const Vector diag = pMax - pMin; if (diag.x diag.y & diag.x diag.z) return 0; else if (diag.y diag.z) return 1; else return 2; BBox:BoundingSphere()返回包含該包圍盒的球的中心和半徑。 雖然包圍球比對應(yīng)的包圍盒要寬松得多, 但有時仍是很有用的。在第15章, 我們用它得到包含整個場景的包圍球,用以生成可能跟場景相交的隨機光線。 += int BBox:BoundingSp

31、here(Point *c, float *rad) const *c = 0.5f * pMin + 0.5*pMax; *rad = Distance(*c, pMax); 2.7 變換一般地說, 變換T是從點到點或從向量到向量的映射: p = T(p) v = T(v).變換可以是任意的,但我們只考慮滿足下面條件的變換:1. 線性: 如果T是任意一個線性變換, s是任意純量,那么 T(sv) = sT(v), T(v1+v2) = T(v1)+T(v2).這兩個性質(zhì)可以極大地簡化變換的推導(dǎo)。2. 連續(xù)性: 粗略地講, T把p或v的鄰近點或向量變換后,結(jié)果仍與p或v鄰近。3. 一一對應(yīng)和可

32、逆性:對每個點p, T把p映射到唯一的點p.近一步地,存在可逆變換T-1把p變換回p.我們常常要計算一個點,向量或法向量在另一個坐標(biāo)系下的坐標(biāo)值。由線性代數(shù)中的知識可以知道,4乘4矩陣可以表達(dá)點或向量從一個坐標(biāo)系到另一個坐標(biāo)系的線性變換。另外,這樣的4乘4矩陣可以表達(dá)同一坐標(biāo)系下的所有關(guān)于點或向量的線性變換。所以,有下面關(guān)于矩陣的不同解釋: 坐標(biāo)系內(nèi)的變換: 給定一個點,矩陣可以表達(dá)如何計算在同一坐標(biāo)系下變換(比如平移)后的新點。 坐標(biāo)系之間的變換: 一個矩陣可以表達(dá)在原坐標(biāo)系下的點或向量在新坐標(biāo)系下的坐標(biāo)。一 般說來,變換可以讓我們利用最方便的坐標(biāo)系。舉例來說,我們定義一個虛擬相機,它位于原

33、點,朝向z軸,y軸指向上方,x軸指向右方。這可以極大地方便了相 機的實現(xiàn)。然后,我們可以把相機放在場景的任何位置,令其朝向任何方向,我們只需定義一個變換,把在場景坐標(biāo)系下的點映射到相機坐標(biāo)系。2.7.1 齊次坐標(biāo)給 定有(p,v1,v2,v3)定義的坐標(biāo)系,用(x,y,z)既可以表示點(Px,Py,Pz)也可以表示向量(Vx,Vy,Vz)。為了避免這兩種表示 的模糊性,我們利用本章開始介紹的點和向量的表達(dá)方式,把點寫成內(nèi)積形式S1 S2 S3 1 v1 v2 v3 P0T, 把向量寫成內(nèi)積形式S1 S2 S3 0 v1 v2 v3 P0T。S1 S2 S3 1被稱為點的齊次表示,S1 S2 S

34、3 0 被稱為向量的齊次表示。第四個坐標(biāo)值有時被稱作權(quán)值。對于點而言,任何非零的純量都可以做為權(quán)值:齊次點(1,3,-2,1)和(-2,-6,4,-2) 代表同一個點(1,3,-2). 一般地說,齊次點和所表達(dá)的三維點有下列關(guān)系: (x, y, z, w) = (x/w, y/w, z/w)有了上面的基礎(chǔ),我們可以考察一個變換矩陣如何把點和向量變換到另一個坐標(biāo)系的。設(shè)有矩陣M描述從一個坐標(biāo)系到另一個坐標(biāo)系的變換: 將M作用到x軸向量(1, 0, 0),有: M 1 0 0 0T = m00 m10 m20 m30T所以,矩陣的四列就是變換下面的x,y,z軸和原點的結(jié)果: x = 1 0 0 0

35、T y = 0 1 0 0T z = 0 0 1 0T p = 0 0 0 1T我們不顯式地使用齊次坐標(biāo),沒有Homogeneous類。然而,下節(jié)定義的變換例程會隱式地把點,向量,法向量轉(zhuǎn)換成齊次坐標(biāo)形式,然后使用齊次坐標(biāo)變換,再轉(zhuǎn)換回三維坐標(biāo)形式。這樣,所有的齊次坐標(biāo)處理都集中在一個地方(即在變換的實現(xiàn)中)。 = class COREDLL Transform public: private: ;一個變換由一個對Matrix4x4對象的引用m來表示。底層的Matrix4x4定義在A.3.2節(jié)。m是以行為主(row-major)的形式存儲的,就是說, 元素mj對應(yīng)第i行,第j列的元素。為了方便

36、,Transform類還保持了m的逆陣mInv.使用引用計數(shù)的模版類Reference在A.2.2節(jié)中有所介紹。它自動記錄有多少個對象保持對該對象的引用,并當(dāng)引用計數(shù)為零時自動釋放內(nèi)存。Transform 類保持對矩陣的引用,而不是直接存儲矩陣本身,這樣多個Transform對象可以指向同一個矩陣。這意味著一個Transform的實例占很少的內(nèi)存空 間。如果場景中有非常多的形體,且擁有同一個物體/世界變換,那么它們都有自己的Transform對象,但是卻共享同一個矩陣,這樣所節(jié)省的空間是很可 觀的。當(dāng)然,這也會犧牲一些靈活性, 特別是矩陣一但建立就無法修改。在實際情況中,這不是問題,因為場景中

37、的變換通常是當(dāng)pbrt讀場景描述文件時建立的,以后在渲染過程中也不需要修改。在這樣的設(shè)計決定下,每次修改矩陣,都要創(chuàng)建一個新的矩陣。 = Reference m, mInv;2.7.2 基本操作新變換被創(chuàng)建時,被初始化為單位變換:把點和向量映射到它自己的變換。這種變換用單位矩陣表示(即對角線上的元素都為1,而其它元素為0的矩陣)。 = Transform() m = mInv = new Matrix4x4; 一個變換也可以由一個矩陣來初始化: += Transform(float mat44) m = new Matrix4x4(mat00, mat01, mat02, mat03, mat

38、10, mat11, mat12, mat13, mat20, mat21, mat22, mat23, mat30, mat31, mat32, mat33); mInv = m-Inverse(); += Transform(const Reference &mat) m = mat; mInv = m-Inverse(); 最后,我們給出最常用的Transform的構(gòu)造器: 其參數(shù)是一個變換矩陣和已經(jīng)計算好的逆陣。這種方法很不錯,因為很多的幾何變換的矩陣的逆陣是很簡單的,我們就省去了計算逆陣的通用算法所產(chǎn)生的開銷。當(dāng)然,調(diào)用者要保證所提供的逆陣是正確的。 += Transform(con

39、st Reference &mat, const Reference &minv) m = mat; mInv = minv; += Transform GetInverse() const return Transform(mInv, m); 2.7.3 平移變換平移變換是最簡單的變換之一。對于點P,平移變換把點的坐標(biāo)平移x, y, z, 記作T(x, y, z). 比如, T(2,2,1)(x,y,z) = (x+2, y+2, z+1). 平移變換有下列性質(zhì): T(0,0,0) = I T(x1,y1,z1) T(x2,y2,z2) = T(x1+x2, y1+y2, z1+z2) T(

40、x1,y1,z1) T(x2,y2,z2) = T(x2,y2,z2) T(x1,y1,z1) T-1(x,y,z) = T(-x, -y, -z)寫成矩陣形式就是: 如果對點(x,y,z,1)進(jìn)行平移變換,則有:如果對向量(x,y,z,0)進(jìn)行平移變換,則有:可以看出,平移的結(jié)果跟原向量相同,因為平移并不改變向量的方向,故也不改變向量的值。平移變換的實現(xiàn)很簡單: = COREDLL Transform Translate(const Vector &delta) Matrix4x4 *m, *minv; m = new Matrix4x4(1, 0, 0, deltax, 0,1,0, de

41、ltay, 0,0,1,deltaz, 0,0,0,1); mInv = new Matrix4x4(1, 0, 0, -deltax, 0,1,0, -deltay, 0,0,1,-deltaz, 0,0,0,1); return Transform(m, minv);2.7.4 比例變換L另一個基本變換是比例變換, S(sx,sy,sz).其變換的結(jié)果等同于把點或向量的分量分別乘以比例因子. 比如: S(2, 2, 1)(x, y, z) = (2x, 2y, z).它有如下基本性質(zhì): S(1, 1, 1) = I S(x1, y1, z1) S(x2, y2, z2) = S(x1x1,

42、 y1y2, z1z2) S-1(x,y,z) = S(1/x, 1/y, 1/z)比例變換分等比例變換(uniform scaling, 三個比例因子相等), 和非等比例變換(nonuniform scaling, 三個比例因子不相等). 矩陣形式如下: 比例變換的實現(xiàn)很簡單: += COREDLL Transform Scale(float x, float y, float z) Matrix4x4 *m, *minv; m = new Matrix4x4( x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1); minv = new Matrix4x4(1.0f/x, 0, 0, 0, 0,1.0f/y,0, 0, 0,0,1.0f/z,0, 0,0,0,1);return Transform(m, minv); 2.7.5 繞x,y,z軸的旋轉(zhuǎn)變換另一個變換類型是旋轉(zhuǎn)變換R。一般地說,我們可以定義繞一個起始于原點的任意方向上的任意軸旋轉(zhuǎn)任意角度的變換。最常用的變換還是繞x,y或z軸的變換,我們分別記為Rx(), Ry(), Rz(). 繞任意軸(x,y,z)旋轉(zhuǎn)的變換記為R(

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論