Try   HackMD

電腦圖學筆記

Windows 的屬性

  • 背景(Background)或前景(Forceground)顏色
  • 字體顏色(Font color)、字形(Font family)、大小(Font size)
  • 位置(position)
  • 大小(size)
  • 標題(title)

Event Driven Programming

Event queue、Arbiter(Loop)、Callback

事件觸發(Event)

Mouse event

滑鼠按鍵事件,當按下或放開滑鼠任一個按鍵時觸發,會回傳按鍵編號、狀態以及鼠標位置。

void mouse(int button, int state, int x, int y);

glutMouseFunc(mouse);

Motion event

滑鼠移動事件,當按住滑鼠任一按鍵時並移動時觸發,會回傳鼠標位置。

void motion(int x, int y);

glutMotionFunc(motion);

Keyboard event

鍵盤事件,當按下鍵盤上任一個按鍵時觸發且滑鼠在視窗內,回傳按鍵編號以及滑鼠位置。

void keyboard(unsigned char key, int x, int y);

glutKeyboardFunc(keyboard);

Display event

當視窗顯示時、或部分露出、移動視窗都會觸發。
通常會設定清除顏色以及一些緩衝,並開始渲染與繪製物體。

void display(void);

glutDisplayFunc(reshape);

Resphape event

當視窗跳出時、或大小被改變時觸發,會回傳改變後的視窗寬與高。
通常會重設 projection 矩陣、viewport 以及再次呼叫 display event。

void reshape(int w, int h);

glutReshapeFunc(reshape);

緩衝區(Buffer)

Color buffer

顏色緩衝,用來存放要填入顏色的緩衝,分Front與Back兩種,裡面各有4個channel,數值介於0~1之間,分別為RGBA。RGBA各別代表為:Red、Green、Blue和Alpha。每一個大小為8個bits,可以表示

224種顏色。

Depth buffer

深度緩衝,用來儲存物體距離攝影機的距離,數值介於0~1之間,0為最近;反之1為最遠,較近的物體會覆蓋較遠的物體,通常是32位元深。

Stencil buffer

樣板緩衝,基本上功能類似於遮罩,只有特定區塊可以通過並繪製出來(通過顏色與深度緩衝),其餘部分將不會被繪製。

OpenGL Pipeline

  1. Local Coordinate System 在地坐標系
  2. World Coordinate System 世界坐標系 (乘上Model Transform Matrix)
  3. Eyes Coordinate System 眼睛坐標系 (乘上View Transform Matrix)
  4. Clip Coordinate System 裁剪坐標系 (乘上Projection Transform Matrix)
  5. Normalize Device Coordinate 標準化設備座標 (從齊次座標轉回三維空間)
  6. Screen Coordinate System 螢幕坐標系 (Viewport之後)

幾何轉換(Geometrical Transformations)

Translate aka. shift

位移,注意此轉換不是一個縣性轉換。
參數:一個三維的向量,上面的值代表在各xyz軸移動的量。
假設愈要一個物體平移

T(xt,yt,zt),轉換矩陣為:
[100xt010yt001zt0001]

平移如果用矩陣來表示就一定要採用齊次坐標(Homogeneous Coordinates)。

Rotation

旋轉,一般來說都是以原點為中心來選轉,旋轉軸為x、y和z其中一軸,而旋轉方向為逆時針。
該轉換矩陣是正交矩陣(Orthonormal Matrix)。
參數:旋轉中心、旋轉軸、選轉的度數(角度或徑度)。
假設愈要一個物體沿著x軸選轉

θ度,記做
Rx(θ)
,轉換矩陣為:
[10000cos(θ)sin(θ)00sin(θ)cos(θ)00001]

訣竅:沿著x軸轉動代表x軸不會有任何變動,所以只需要在y與z軸上填入對應的值即可。

如果是沿著z軸選轉

θ度,記做
Rz(θ)
,轉換矩陣為:
[cos(θ)sin(θ)00sin(θ)cos(θ)0000100001]

訣竅:沿著z軸轉動代表z軸不會有任何變動,所以只需要在x與y軸上填入對應的值即可。

如果是沿著y軸選轉

θ度,記做
Ry(θ)
,轉換矩陣為:
[cos(θ)0sin(θ)00100sin(θ)0cos(θ)00001]

注意:sin與-sin的位置顛倒了。

Scale

縮放,小於1代表縮小,大於1代表放大,1代表不變,並以原點為縮放中心。
參數:一個三維的向量,上面的值代表在各xyz軸縮放的倍數。
假設愈要一個物體要縮放,記做

S(xs,ys,zs),轉換矩陣為:
[xs0000ys0000zs00001]

如果
xs=ys=zs
,就代表為Uniform Scaling。

Shearing

剪切轉換(推移轉換),需要三個參數:要推移的座標(the coordinate to be shear)、推移方向(direction)、以及推移斜率(slope)

k
假設愈要沿y軸方向,推移x座標的k倍,記做
Hxy(k)
,轉換矩陣為(Shear X coordinate in Y direction):
[1k00010000100001]

訣竅:x = x + ky;

假設愈要沿著z軸方向,推移y座標的k倍,記做

Hyz(k),轉換矩陣為(Shear Y coordinate in Z direction):
[100001k000100001]

訣竅:y = y + kz;

假設愈要沿著x軸方向,推移z座標的k倍,記做

Hzx(k),轉換矩陣為(Shear Z coordinate in X direction):
[10000100k0100001]

訣竅:z = z + kx;

Reflection

鏡射,基本上就是反射,需要選定一個鏡射軸,而其他兩個軸所形成的平面就會反射兩邊對稱。
假設愈鏡射y軸,此時的鏡射軸為xz平面,轉換矩陣為:

[1000010000100001]

假設愈鏡射z軸,此時的鏡射軸為xy平面,轉換矩陣為:

[1000010000100001]

假設愈鏡射x軸,此時的鏡射軸為yz平面,轉換矩陣為:

[1000010000100001]

線性轉換(Linear Transformation)

意思是經過轉換後,依舊能保持向量加法以及純量乘法的一種轉換,所以必須要滿足以下2個條件:

  • 可加性(additivity):
    f(u+v)=f(u)+f(v)
  • 齊次性(homogeneity):
    f(ku)=kf(u)

f(x)為某轉換,u和v為向量,k為純量。

旋轉、縮放、推移、反射都算是線性轉換,而且轉換後的原點依舊是不變的。

映射轉換(Affine Transformation)

對一個向量空間,進行一次線性轉換後並接上一個位移,轉換成另一個空間。
除了要先滿足線性轉換的定義後,還需多滿足一個條件:

  • g(u) = f(u) + c

映射轉換:加法函數、倍數函數、常數項;線性轉換:加法函數、倍數函數。
映射轉換要使用齊次坐標(Homogeneous Coordinates),因為位移的關係。

剛體轉換(Rigid-body Transformation)

指的是物體的大小形狀不會被改變,但位置與方向會被改變。
所以泛指平移+旋轉,也是我們常說的6個自由度(Degrees of freedom),分別為:

  • Surge(縱移):前後移動(沿z軸平移)。
  • Sway(橫移):左右移動(沿x軸平移)。
  • Heave(垂盪):上下移動(沿y軸平移)。
  • Pitch(俯仰):上看或下看旋轉(沿x軸旋轉)。
  • Yaw(偏航):往左看或往右看旋轉(沿y軸旋轉)。
  • Roll(側滾):往左翻或往右翻(沿z軸旋轉)。

反轉換(Inverse Transformation)

Translate

T(xt,xy,xz) 的反矩陣就是
T(xt,xy,xz)

Rotation

Rx(θ) 的反矩陣就是
Rx(θ)
,其他依此類推。

Scale

S(xs,ys,zs) 的反矩陣就是
S(1xs,1ys,1zs)
,其他依此類推。

Shear

Hxy(k) 的反矩陣就是
Hxy(k)
,其他依此類推。

Reflection

鏡射矩陣的反矩陣依舊不變,所以執行兩次就是會相互抵銷,它是一個對偶轉換(Dual Transformation)。

View Transformation

LookAt 矩陣計算方式

定義出攝影機位置

C(1,1,1)

定義出目標物位置

T(0,1,0)

求出攝影機之z正軸向量

z^=CT=(1,1,1)(0,1,0)=(1,0,1)
正規化後:
z^=[12012]

求出攝影機之x正軸向量

其中

Wup=[100]
x=Wup^×z^=[100]×[12012]=[0120]

正規化:
x^=[010]

求出攝影機之y正軸向量

y=z^×x^=[12012]×[010]=[12012]

寫入View Matrix

[01001201201201200001][1001010100110001]

Projection

投影矩陣的效果:

  1. 把眼睛坐標系轉換至投影坐標系,且會從右手坐標系變成左手坐標系。
  2. 在眼睛坐標系定義好 View Volume 後,超過此範圍的物體將會被裁切掉。
  3. 深度資訊會被扭曲。

詳情介紹可看這篇:Projection Matrix

Orthogonal

[2rl00r+lrl02tb0t+btb002fnf+nfn0001]

Perspective

透視矩陣為:

[2nrl0r+lrl002ntbt+btb000f+nfn2fnfn0010]
而其深度資訊(z)從眼睛坐標系轉換至投影坐標系的公式為,此轉換是非線性的:
zndc=(f+nnfze+2fnnf)1ze

Viewport

原點在視窗左下角,為(0,0)。

Shade

Phong illumination

Ambient

環境光。

vec3 ambient = light.ambient * material.ambient;

Diffuse

漫射,光的強度取決於【物體到光源的方向】和【物體表面的法向量】之間的 cos 夾角,當兩者之間角度為

0時,亮度最強為1;反之角度為
90
時,亮度最弱為0。

vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(normal, lightDir), 0.0);
vec3 diffuse = light.diffuse * material.diffuse * diff;

這邊的 normal 和 lightDir 都必須要正規化,計算出來的才會是 cos 角度值哦!
向量點乘公式:

ab=|a||b|cos(θ)

Specular

高光,可以看出光的強度取決於【物體到眼睛的方向】和【光反射的方向】之間的的夾角,以及【物體的 shininess 程度】。

vec3 viewDir = normalize(viewPos - FragPos);
float reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * material.specular * spec;

注意 lightDir 此向量是由物體指向光源方向,在計算 reflectDir 時必須要先將 lightDir 取反(變成從光源指向物體),這樣使用 reflect() 時計算出來的 reflectDir 方向才會正確。
此計算方式是使用 Snell's law,入射角等於反射角。

如果是使用 Blinn-Phong 光照模型的話,高光的計算方式為:

vec3 viewDir = normalize(viewPos - FragPos);
float halfway = normalize((lightDir + viewDir) / 2);
float spec = pow(max(dot(normal, halfway), 0.0), material.shininess);
vec3 specular = light.specular * material.specular * spec;

Attenuation

光衰弱,光的衰弱跟距離成反比,通常表示:

1d2
但這通常會太暗,只比較適合晚上或水下場景。
比較完整的衰弱公式為:
1ad2+bd+c
,其中C通常都是固定為1。

Caster

光可以分為:Direcitonal Light、Point Light、Spot Light。

  • Direcitonal Light:沒有 Position 只有 Direction(等於lightDir),且不會衰弱。
  • Point Light:只有 Position,會衰弱,光會以360度的方式散發。
  • Spot Light:有 Position 跟 Direction,但這邊的 Direction 指的是聚光燈的向前的向量(不等於lightDir),通常還會有 Cutoff Angle 和 Exponent 兩個變數,前者控制聚光燈的範圍,Exponent 則控制光的柔化(數值越小光源邊緣越明顯)。

Shade & Fill

在 Viewport 之後就會進行 Polygon Filling 和 Shading。

Resterization

找出多邊形的像素有哪些:Resterization(柵格化)。

Shade

計算像素的顏色、光與暗等。

  • Flat Shade:一個平面只有一個法向量(只選擇一個點去計算,之後只用該顏色填滿整個形狀)。
  • Goraud Shade:該平面頂點上的法向量,先各別計算光照計算後,其他都是雙線性插值。
  • Phong Shade:先將該平面頂點上的進行線性插值,計算出其他頂點後,再計算光照。
  • Bump Shade:使用 Normal Texture。

Texture

Texture Map

Fliter

Minification

材質的解析度【大於】多邊形的解析度,有 Nearest 和 Linear(Box Fliter)兩種模式。

Magnification

材質的解析度【小於】多邊形的解析度,有 Nearest interpolation 和 Linear interpolation 兩種模式。

Alpha Testing

Blend

Billboard

Fog

Depth Cue

用 Perspective 投影矩陣的 Depth Cue 的效果為:

  1. 物件的大小會隨著物體距離攝影機的距離成反比(越遠的物體越小)。
  2. 平行線不會被保存完好。
  3. 角度不會被保存完好。

如果用 Orthogonal 投影矩陣是無法令人產生 Depth Cue 的。

  1. 物件的大小會跟物體距離攝影機的距離完全無關。
  2. 平行線會被保存完好。
  3. 角度可能會也可能不會被保存完好。

使用 Fog 效果會讓越遠的物體會越模糊不清,這可以提升 Depth Cue。

物體越遠看起來越暗,顏色越不清楚,漸漸淡入霧中。

霧的計算方式

Cfinal=(1f)Cpixel+fCfog
其中,
Cpixel
代表該Pixel的顏色,
Cfog
則是霧的顏色。

模式

f是霧的強度參數,而計算方式根據模式不同有不同的計算:

  • EXP:
    f=ead
    ,跟一般物理模型近似。
  • EXP2:
    f=ead2
    ,衰弱很快,適合晚上視野。
  • LINEAR:
    f=endzendstart
    ,運算速度快。

其中的

a 是指每一個單位距離中霧的密度。

但是注意,這邊的

d 是使用 Depth Buffer 中的沒錯,但這樣是線性內插,並不準確。
所以可以用另一個方法:Range Based,距離看的是眼睛看過去的總長度(使用length())。

tags: OpenGL