舊文件

此處文件僅供參考,請自行考量時效性與適用程度,其他庫藏文件請參考文件頁面
我們亟需您的協助,進行共筆系統搬移、及文件整理工作,詳情請查閱參與我們

「C3dl」修訂間的差異

出自 MozTW Wiki

簡介
觀景窗 Scene
 
(未顯示同一使用者於中間所作的 26 次修訂)
行 1: 行 1:
請見 [[http://zenit.senecac.on.ca/wiki/index.php/Canvas3D_JS_Library|Canvas3D JS Library]]
+
請見 [http://zenit.senecac.on.ca/wiki/index.php/Canvas3D_JS_Library Canvas3D JS Library]
  
 
== 簡介 ==
 
== 簡介 ==
  
Canvas 3D JS Library (C3DL) 是 javascript 函式庫,也就是裡頭提供的全部是 Javascript, 必須安裝 [https://addons.mozilla.org/en-US/firefox/addon/7171|Canvas3D extension of firefox], [http://www.c3dl.org/|c3dl 程式碼在此]。主要目的是讓你在 Firefox/Mozilla 平台用 Canvas/OpenGL 的方式撰寫 3D 的網路應用。
+
Canvas 3D JS Library (C3DL) 是 javascript 函式庫,也就是裡頭提供的全部是 Javascript, 必須安裝 [https://addons.mozilla.org/en-US/firefox/addon/7171 Canvas3D extension of firefox], [http://www.c3dl.org/ c3dl 程式碼在此]。主要目的是讓你在 Firefox/Mozilla 平台用 Canvas/OpenGL 的方式撰寫 3D 的網路應用。
  
 
C3DL 提供一系列的數學、景觀、及3D物件類別,讓你在用 Canvas 會更有彈性,當然主要就是要縮短開發時間。
 
C3DL 提供一系列的數學、景觀、及3D物件類別,讓你在用 Canvas 會更有彈性,當然主要就是要縮短開發時間。
 +
 +
== 本專案開發人員 ==
 +
* Catherine Leung
 +
* Mark Paruzel (CodeBot)
 +
* Andrew Smith
 +
* Chris Bishop (Javascript)
 +
* Andor Salga
 +
 +
== 有用的連結 ==
 +
* [http://www.c3dl.org 我們的網站]
 +
* [http://littlesvr.ca/canvas3d/blog/ 我們的 blog]
 +
* Our SVN Repo: svn://cdot.senecac.on.ca/canvas3d
 +
* [http://vlad.off.net/hg/canvas3d/ 在 Vlad's hg repo 中的 canvas3d 源碼]
 +
* [http://www.opengl.org/documentation OpenGL 文件]
 +
* [http://nehe.gamedev.net/ Nehe 的 OpenGL 教學]
 +
* [http://shape.cs.princeton.edu/benchmark/ .off (object file format) format info]
 +
 +
== 類別繼承圖 ==
 +
* [http://img126.imageshack.us/img126/3032/layoutqe4.jpg Canvas 3D API 類別繼承圖]
 +
 +
== 數學運算 ==
 +
我的感覺是這份 c3dl 並不是非常有效率,可以稍微修正寫法,譬如參考 [http://sourceforge.net/projects/papervision3d paperVision3D]
 +
 +
=== Vector 向量類別 ===
 +
一個向量基本上就是在 3D 世界的 X, Y, Z 三個軸的座標系統描述一個「具備大小的方向」。3D 數學存在各種不同的座標系統,離開向量類別的封裝則不復存在所謂的 3D。向量類別具有下列的成員;
 +
 +
* isValidVector(vecArr) - '''判斷參數是否為一有效的向量'''
 +
* copyVector(srcVec) - '''從 srcVec 複製並傳回'''
 +
* copyVectorContents(srcVec, destVec) - '''效果相當於(不等於,因為有多作判斷是否為有效向量) destVec = copyVector(srcVec);'''
 +
* makeVector(newX, newY, newZ) - '''copyVector() 就是用這個函數實作向量複製'''
 +
* normalizeVector(vec) - '''計算與向量相同方向但長度為一的「單位向量」並傳回'''
 +
* vectorDotProduct(vecOne, vecTwo) - '''傳回兩向量的內積(點積),其值為純量'''
 +
* vectorCrossProduct(vecOne, vecTwo, dest) - '''將 vecOne 與 vecTwo 兩個向量做外積(叉積)後指定給 dest)'''
 +
* vectorLength(vec) - '''計算並傳回向量的長度(相當於與自己的內積開根號)'''
 +
* vectorLengthSq(vec) - '''計算向量長度的平方,相比於直接利用長度的運算上,少了一個根號後再平方的無用計算'''
 +
* addVectors(vecOne, vecTwo, dest) - '''相當於 dest = vecOne + vecTwo'''
 +
* subtractVectors(vecOne, vecTwo, dest) - '''相當於 dest = vecOne - vecTwo'''
 +
* multiplyVector(vec, scalar, dest) - '''相當於 dest = vec * scalar; 效果相當於將向量放大(scalar 小於1的正數則為縮小,負數則為反向)'''
 +
* divideVector(vec, scalar, dest) - '''相當於 dest = vec / scalar; 效果相當於將向量縮小(scalar 小於1的正數則為放大,負數則為反向)'''
 +
* multiplyVectorByVector(vecOne, vecTwo, dest) - '''既非內積也非外積,而是相當於 dest = [X1*X2, Y1*Y2, Z1*Z2]; 的乘法'''
 +
* isVectorEqual(vecOne, vecTwo) - '''判斷兩向量是否相等'''
 +
* isVectorZero(vec) - '''判斷向量長度是否為 0,正確的說法: 判斷是否極接近 0,每個軸向誤差在 0.00001 以內'''
 +
* getAngleBetweenVectors(vecOne, vecTwo) - '''計算兩向量間的夾角'''
 +
 +
=== Matrix 矩陣類別 ===
 +
c3dl 的矩陣在數學上是一個 4x4 的二維矩陣,但是在 Javascript 實作上是用一維陣列來表達,而不是二維陣列,其索引值如下:
 +
 +
      +-              -+
 +
      |  0,  4,  8, 12  |
 +
      |  1,  5,  9, 13  |
 +
      |  2,  6, 10, 14  |
 +
      |  3,  7, 11, 15  |
 +
      +-              -+
 +
 +
* isValidMatrix(mat) - '''判斷是否為有效的矩陣'''
 +
* makeIdentityMatrix() - '''產生單位矩陣,也就是斜對角都為 1 其餘為 0 的矩陣'''
 +
* makeZeroMatrix() - '''產生全部是0 的矩陣'''
 +
* makeMatrix(e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33) - '''利用參數產生矩陣,其索引值順序如上述,或由此處的宣告亦可得知'''
 +
* matricesEqual(matrix1, matrix2) - '''判斷兩矩陣是否相等'''
 +
* makePoseMatrix(vecLeft, vecUp, vecFrwd, vecPos) - '''位置矩陣,通常用來處理「手勢」,效果如下''':
 +
<pre>
 +
+-                            -+
 +
|  Left.x, Up.x, Fwd.x, Pos.x  |
 +
|  Left.y, Up.y, Fwd.y, Pos.y  |
 +
|  Left.z, Up.z, Fwd.z, Pos.z  |
 +
|  0.0,    0.0,  0.0,  1.0    |
 +
+-                            -+
 +
</pre>
 +
* transposeMatrix(mat) - '''傳回轉置矩陣''': 型如
 +
<pre>
 +
+-            -+
 +
|  A, B, C, D  |
 +
|  E, F, G, H  |
 +
|  I, J, K, L  |
 +
|  M, N, O, P  |
 +
+-            -+
 +
</pre>
 +
轉置結果為:
 +
<pre>
 +
+-            -+
 +
|  A, E, I, M  |
 +
|  B, F, J, N  |
 +
|  C, G, K, O  |
 +
|  D, H, L, P  |
 +
+-            -+
 +
</pre>
 +
* inverseMatrix(mat) - '''計算並傳回 mat 的反矩陣,使得 res * mat = I, 其中 I 是單位矩陣,參考 [http://mathworld.wolfram.com/MatrixInverse.html 反矩陣]'''
 +
* matrixDeterminant(mat) - '''計算並傳回 mat 的行列式,通常用來算面積或體積,其值為純量,參考 [http://en.wikipedia.org/wiki/Determinant 行列式]'''
 +
* matrixAdjoint(mat) - '''不知道怎麼翻,伴隨矩陣?共軛矩陣?參考 [http://www.ee.ic.ac.uk/hp/staff/dmb/matrix/property.html#adjoint adjoint matrix]'''
 +
* multiplyMatrixByScalar(mat, scalar) - '''每個元素都乘以 scalar'''
 +
* divideMatrixByScalar(mat, scalar) - '''每個元素都除以 scalar'''
 +
* multiplyMatrixByMatrix(matOne, matTwo) - '''矩陣乘法,結果亦為矩陣'''
 +
* multiplyMatrixByVector(mat, vec) - '''將矩陣乘以向量,通常用來作向量的旋轉之類用途,結果亦為向量(其實是 4x4 矩陣與 4x1 矩陣相乘)'''
 +
* addMatrices(matOne, matTwo) - '''兩矩陣相對應元素相加'''
 +
* subtractMatrices(matOne, matTwo) - '''兩矩陣相對應元素相減'''
 +
 +
=== Quaternion 四元數 ===
 +
四元數顧名思義就是四個元素的數,請參考 [http://en.wikipedia.org/wiki/Quaternion 四元數]
 +
 +
* isValidQuat(quat) - '''傳回是否為有效的四元數'''
 +
* makeQuat(newW, newX, newY, newZ) - '''傳回四元數 Quat = W + X * i + Y * j + Z * k, 其中 i, j, k 是虛部'''
 +
* quatToMatrix(quat) - '''將四元數以矩陣來表示,其轉換如下:'''
 +
<pre>
 +
+ ------------  ----------  ----------  --- +
 +
  1 - 2(YY+ZZ)  2(XY+WZ)    2(XZ-WY)    0
 +
  2(XY-WZ)      1-2(XX+ZZ)  2(YZ+WX)    0
 +
  2(XZ+WY)      2(YZ-WX)    1-2(XX+YY)  0
 +
  0            0          0            1
 +
+ ------------  ----------  ----------  --- +
 +
</pre>
 +
* quatToAxisAngle(axisVec, angleScalar) - '''用來將四元素的旋轉變成軸角的旋轉,不過似乎有 bug'''
 +
* axisAngleToQuat(axisVec, angleScalar) - '''轉換軸角的旋轉為四元數的旋轉'''
 +
* matrixToQuat(newMat) - '''將矩陣轉為四元數'''
 +
* quatLengthSq(quat) - '''四元數的長度平方,等於 XX+YY+ZZ'''
 +
* quatLength(quat) - '''四元數的長度 sqrt(XX+YY+ZZ)'''
 +
* addQuats(quatOne, quatTwo) - '''兩個四元數相加'''
 +
* subtractQuats(quatOne, quatTwo) - '''兩個四元數相減'''
 +
* multiplyQuatByScalar(quatOne, scalar) - '''兩個四元數相減'''
 +
* getQuatConjugate(quat) - '''四元數的共軛四元數(虛部分別為其負值)'''
 +
* quatDotProduct(quatOne, quatTwo) - '''四元數的內積,其值為純量,但是並不等於 3D 意義中的長度'''
 +
* normalizeQuat(quat) - '''四元數的正規化'''
 +
* inverseQuat(quat) - '''反四元數'''
 +
 +
== Camera 相機 ==
 +
Camera 有分 ChaseCamera, FixedCamera, FreeCamera, PanCamera,就讓我們一個一個來看吧
 +
 +
=== ChaseCamera ===
 +
尚未實作,空的
 +
 +
=== FixedCamera ===
 +
嗚嗚,似乎也是未實作,看 code 似乎也沒人用到
 +
 +
* 屬性
 +
** globalPos - '''相機位置,向量'''
 +
** globalOri - '''相機方向,矩陣'''
 +
** nearClipping - '''預設值 1.0'''
 +
** farClipping - '''預設值 500'''
 +
** fieldView - '''預設值 60'''
 +
** aspectRatio - '''預設值 0'''
 +
 +
* 方法
 +
** setGlobalPos(posVec) - '''未實作'''
 +
** setGlobalOri(oriMat) - '''未實作'''
 +
 +
=== PanCamera ===
 +
尚未實作,空的
 +
 +
=== FreeCamera ===
 +
 +
* 方法: 讀值
 +
** getPosition() - '''傳回位置向量'''
 +
** getUp() - '''傳回相機的 up vector(老實說我不知道這是啥或是要幹嘛)'''
 +
** getDir() - '''傳回相機瞧的方向 vector'''
 +
** getLeft() - '''傳回相機的 left vector(老實說我不知道這是啥或是要幹嘛)'''
 +
** getLinearVel() - '''註解說是 Animation of positions,其值是向量'''
 +
** getAngularVel() - '''Animations of rotation around (side Vector, up Vector, dir Vector)'''
 +
 +
* 方法: 設定
 +
** setPosition(newVec) - '''設定相機位置'''
 +
** setLookAtPoint(newVec) - '''設定相機看的點,必須移(應該是沒有轉)動相機(其實是轉動所有物件)'''
 +
** setUpVector(newVec) - '''設定 up vector'''
 +
** setLinearVel(newVec) - '''設定相機的旋轉速度?,其值是向量'''
 +
** setAngularVel(newVec) - '''設定相機轉動軸?'''
 +
 +
* 其他功能
 +
** rotateOnAxis(axis, angle) - '''讓相機沿著某個向量軸 axis 繞行 angle 角度'''
 +
** yaw(angle) - '''讓相機沿著其 Up vector 轉動 angle 角度'''
 +
** roll(angle) - '''讓相機沿著其方向向量轉動 angle 角度'''
 +
** pitch(angle) - '''讓相機沿著其 left vector 轉動 angle 角度'''
 +
** update(timeElapsed) - '''這個函數跟設定旋轉速度有關,我猜是供內部呼叫'''
 +
** applyToWorld(glCanvas3D, scene) - '''應該是「畫」出來的意思'''
 +
 +
== 畫布 Scene ==
 +
* 方法: 讀取
 +
** getCamera()
 +
** getObjListSize()
 +
** getGL() - '''傳回 Canvas3D 引擎
 +
** getTotalFrameCount()
 +
** getRenderer()
 +
** getTextureManager()
 +
** getScene()
 +
** getSkyModel()
 +
** getAmbientLight() - '''內部有個 ambientLight 陣列變數均為浮點數,假設為 a, 傳回值卻是 [a[0]/5, a[1]/5, a[2]/5, a[3]]
 +
** getObj(indxNum) - '''傳回 Scene 中的物件'''
 +
* 方法: 設定
 +
** setKeyboardCallback(keyUpCB, keyDownCB) - '''註冊鍵盤按鍵事件的聆聽函式'''
 +
** setMouseCallback(mouseUpCB, mouseDownCB, mouseMoveCB, mouseScrollCB) - '''註冊滑鼠事件的聆聽函式'''
 +
** setSkyModel(sky)
 +
** setUpdateCallback(updateCB) - '''每次 Scene 重刷時叫用'''
 +
** setRenderer(renderType)
 +
** setCanvasTag(canvasTag)
 +
** setCamera(cam)
 +
** addFloatingText(text, fontStyle, fontColour, backgroundColour)
 +
** addTextToModel(model, text, fontStyle, fontColour, backgroundColour)
 +
** create2Dcanvas(width, height) - '''Create a 2D canvas for drawing text and other stuff'''
 +
** setBackgroundColor(bgColor)
 +
** setAmbientLight(light)
 +
** init(name)
 +
** addObjectToScene(obj)
 +
** removeObjectFromScene(obj)
 +
** startScene()
 +
** render()
 +
** updateObjects(timeElapsed, camera)
 +
** renderObjects()
 +
** stopScene()
 +
** preloadImages(imagePaths)
 +
 +
== 虛擬世界的物件 ==
 +
 +
=== 物體 ===
 +
 +
==== 基本物件 Primitive ====
 +
 +
* 基本屬性
 +
** visible: true - '''物件是否可見'''
 +
** textureName - '''紋理,譬如木頭?鐵?'''
 +
** name - '''每個物件都有自己的名字'''
 +
 +
* 原始位置,所有物件含相機都有 left, up, dir, pos 等資訊
 +
** left: (1, 0, 0) - '''left vector'''
 +
** up: (0, 1, 0) - '''up vector'''
 +
** dir: (0, 0, 1) - '''forward vector'''
 +
** pos: (0, 0, 0) - '''位置'''
 +
** scaleVec: (1, 1, 1) - '''放大率,預設就是 1'''
 +
 +
* 移動資訊
 +
** linVel: (0, 0, 0) - '''移動"速度"為 0, 預設是靜止'''
 +
** angVel: (0, 0, 0) - '''轉動方向為 0, 預設是不轉動'''
 +
 +
* 取值
 +
** getPosition() - '''傳回 pos 值'''
 +
** getUp() - '''傳回 up vector'''
 +
** getDirection() - '''傳回 dir vector'''
 +
** getLeft() - '''傳回 left vector'''
 +
** getLinearVel() - '''傳回速度 linVel 向量值'''
 +
** getAngularVel() - '''傳迴旋轉向量 angVel'''
 +
** isVisible() - '''傳回是否可見'''
 +
** getScale() - '''傳回放大率'''
 +
** getName() - '''傳回物件名稱'''
 +
** getTextureName() - '''傳迴紋理名稱'''
 +
 +
* 設定
 +
** setTexture(imageFilename) - '''設定紋理檔案名稱'''
 +
** setTextureFromCanvas2D(sourceCanvas) - '''從 Canvas2D 設定紋理'''
 +
** unsetTexture() - '''重設紋理為空的'''
 +
** setName(name) - '''設定物件名稱'''
 +
** setVisible(show) - '''設定物件是否可見'''
 +
** scale(scaleVec) - '''設定物件放大比例'''
 +
** setPosition(vecPos) - '''設定物件位置 pos 值'''
 +
** translate(translation) - '''將物件放到新位置(相當於 pos+translation)'''
 +
** setForward(newVec) - '''將物件往 newVec 方向移動,這會影響到 up, left 等向量'''
 +
** setUpVector(newVec) - '''設定 up vector 成 newVec 值'''
 +
** setLinearVel(newVec) - '''設定速度值為 newVec 值'''
 +
** setAngularVel(newVec) - '''設定旋轉方向為 newVec 值'''
 +
** rotateOnAxis(axisVec, angle) - '''以四元數及矩陣來計算物件的旋轉, 先移動 dir, 再計算相對應的 left, up 值'''
 +
** yaw(angle) - '''效果是 rotateOnAxis(up, angle)'''
 +
** roll(angle) - '''效果是 rotateOnAxis(dir, angle)'''
 +
** pitch(angle) - '''效果是 rotateOnAxis(left, angle)'''
 +
** update(timeStep) - '''依照速度向量 linVel 移動物體的 pos 位置向量,並調整 up, dir, left 等向量值'''
 +
** render(glCanvas3D) - '''透過 glCanvas3D 這個 plugin 把物件畫出來,這邊會有顏色,只是怪怪的'''
 +
 +
==== Model (繼承自 Primitive) ====
 +
* 屬性
 +
** loadedTexture: false - '''是否已載入紋理'''
 +
** expandedVertices - '''似乎要用來放大縮小用的'''
 +
** expandedNormals
 +
** expandedUVs
 +
** buffers
 +
** firstTimeRender: true - '''第一次畫出來'''
 +
** stayInFrontOfCamera: false - '''是否在相機前,應該是與是否可見有關'''
 +
* 方法
 +
** init(vertices, normals, texcoords, faces) - '''必要參數是 vertices, faces。normal是單位大小,或許與燈光有關,texcoords 是紋理座標(不懂),而 faces 則是引索陣列,引用 texcoords 來當其表面紋理'''
 +
** initDAE(path) - '''dae是Collada的檔案副檔名,是用xml去儲存3d的模型'''
 +
** createBuffers(glCanvas3D) - '''應該是在根據 expandedVertices 準備畫布,若有設定 expandedUVs, expandedNormals, 也會準備相對應的 Buffer'''
 +
** update(timeStep, camera) - '''會先根據相機移動相對位置後,再根據自己的速度與旋轉來移動自己'''
 +
** render(glCanvas3D, scene) - '''要把物體畫出來,相對上麻煩的多'''
 +
 +
==== 立方體 Cube ====
 +
繼承自基本物件 Primitive
 +
 +
===== 轉換矩陣 =====
 +
為了效率考量,定義了幾個轉換用的矩陣:
 +
 +
* cube_transition_Vertices =
 +
<pre>
 +
[
 +
[-1, -1, 1], // 0 - front, bottom, left
 +
[-1,  1, 1], // 1 - front, top, left
 +
[ 1,  1, 1], // 2 - front, top, right
 +
[ 1, -1, 1], // 3 - front, bottom, right
 +
 +
[-1, -1, -1], // 4 - back, bottom, left
 +
[-1,  1, -1], // 5 - back, top, left
 +
[ 1,  1, -1], // 6 - back, top, right
 +
[ 1, -1, -1] // 7 - back, bottom, right
 +
];
 +
</pre>
 +
* cube_transition_Normals =
 +
<pre>
 +
[
 +
[-0.57735,-0.57735, 0.57735], // front, bottom, left
 +
[-0.57735, 0.57735, 0.57735], // front, top, left
 +
[ 0.57735, 0.57735, 0.57735], // front, top, right
 +
[ 0.57735,-0.57735, 0.57735], // front, bottom, right
 +
 +
[-0.57735,-0.57735, -0.57735], // back, bottom, left
 +
[-0.57735, 0.57735, -0.57735], // back, top, left
 +
[ 0.57735, 0.57735, -0.57735], // back, top, right
 +
[ 0.57735,-0.57735, -0.57735] // back, bottom, right
 +
];
 +
</pre>
 +
* cube_transition_UVs =
 +
<pre>
 +
[
 +
[0.0,1.0], // 0 - bottom left
 +
[0.0,0.0], // 1 - top left
 +
[1.0,0.0], // 2 - top right
 +
[1.0,1.0] // 3 - bottom right
 +
];
 +
</pre>
 +
* cube_transition_Faces =
 +
<pre>
 +
[
 +
[0,0,0], [3,3,3], [2,2,2], // front
 +
[0,0,0], [2,2,2], [1,1,1],
 +
 +
[5,2,5], [6,1,6], [7,0,7], // back
 +
[5,2,5], [7,0,7], [4,3,4],
 +
 +
[4,0,4], [7,3,7], [3,2,3], // bottom
 +
[4,0,4], [3,2,3], [0,1,0],
 +
 +
[1,0,1], [2,3,2], [6,2,6], // top
 +
[1,0,1], [6,2,6], [5,1,5],
 +
 +
[4,0,4], [0,3,0], [1,2,1], // left side
 +
[4,0,4], [1,2,1], [5,1,5],
 +
 +
[3,0,3], [7,3,7], [6,2,6], // right side
 +
[3,0,3], [6,2,6], [2,1,2]
 +
];
 +
</pre>
 +
 +
===== 屬性與方法 =====
 +
 +
* 屬性
 +
** m - '''就是 Model 物件'''
 +
** 其餘均繼承自 Model
 +
 +
* 方法 - 除 scale 外,全部繼承自 Model
 +
** init(), isVisible()
 +
** getPosition(), getUp(), getDirection(), getLeft(), getLinearVel(), getAngularVel(), getScale(), getTextureName(),
 +
** setTexture(imageFilename), setTextureFromCanvas2D(sourceCanvas), unsetTexture(), setVisible(show)
 +
** setPosition(vecPos), setForward(newVec), setUpVector(newVec),
 +
** translate(translation), setLinearVel(newVec), setAngularVel(newVec), rotateOnAxis(axisVec, angle)
 +
** yaw(angle), roll(angle), pitch(angle), update(timeStep), render(glCanvas3D, scene)
 +
** scale(scaleVec, scaleY, scaleZ) - '''多了 Y, Z 二個軸向的放大縮小?忽略的話就跟 Model 一樣'''
 +
 +
=== Primitive Class ===
 +
=== Model Class ===

於 2008年10月9日 (四) 17:25 的最新修訂

請見 Canvas3D JS Library

簡介

Canvas 3D JS Library (C3DL) 是 javascript 函式庫,也就是裡頭提供的全部是 Javascript, 必須安裝 Canvas3D extension of firefoxc3dl 程式碼在此。主要目的是讓你在 Firefox/Mozilla 平台用 Canvas/OpenGL 的方式撰寫 3D 的網路應用。

C3DL 提供一系列的數學、景觀、及3D物件類別,讓你在用 Canvas 會更有彈性,當然主要就是要縮短開發時間。

本專案開發人員

  • Catherine Leung
  • Mark Paruzel (CodeBot)
  • Andrew Smith
  • Chris Bishop (Javascript)
  • Andor Salga

有用的連結

類別繼承圖

數學運算

我的感覺是這份 c3dl 並不是非常有效率,可以稍微修正寫法,譬如參考 paperVision3D

Vector 向量類別

一個向量基本上就是在 3D 世界的 X, Y, Z 三個軸的座標系統描述一個「具備大小的方向」。3D 數學存在各種不同的座標系統,離開向量類別的封裝則不復存在所謂的 3D。向量類別具有下列的成員;

  • isValidVector(vecArr) - 判斷參數是否為一有效的向量
  • copyVector(srcVec) - 從 srcVec 複製並傳回
  • copyVectorContents(srcVec, destVec) - 效果相當於(不等於,因為有多作判斷是否為有效向量) destVec = copyVector(srcVec);
  • makeVector(newX, newY, newZ) - copyVector() 就是用這個函數實作向量複製
  • normalizeVector(vec) - 計算與向量相同方向但長度為一的「單位向量」並傳回
  • vectorDotProduct(vecOne, vecTwo) - 傳回兩向量的內積(點積),其值為純量
  • vectorCrossProduct(vecOne, vecTwo, dest) - 將 vecOne 與 vecTwo 兩個向量做外積(叉積)後指定給 dest)
  • vectorLength(vec) - 計算並傳回向量的長度(相當於與自己的內積開根號)
  • vectorLengthSq(vec) - 計算向量長度的平方,相比於直接利用長度的運算上,少了一個根號後再平方的無用計算
  • addVectors(vecOne, vecTwo, dest) - 相當於 dest = vecOne + vecTwo
  • subtractVectors(vecOne, vecTwo, dest) - 相當於 dest = vecOne - vecTwo
  • multiplyVector(vec, scalar, dest) - 相當於 dest = vec * scalar; 效果相當於將向量放大(scalar 小於1的正數則為縮小,負數則為反向)
  • divideVector(vec, scalar, dest) - 相當於 dest = vec / scalar; 效果相當於將向量縮小(scalar 小於1的正數則為放大,負數則為反向)
  • multiplyVectorByVector(vecOne, vecTwo, dest) - 既非內積也非外積,而是相當於 dest = [X1*X2, Y1*Y2, Z1*Z2]; 的乘法
  • isVectorEqual(vecOne, vecTwo) - 判斷兩向量是否相等
  • isVectorZero(vec) - 判斷向量長度是否為 0,正確的說法: 判斷是否極接近 0,每個軸向誤差在 0.00001 以內
  • getAngleBetweenVectors(vecOne, vecTwo) - 計算兩向量間的夾角

Matrix 矩陣類別

c3dl 的矩陣在數學上是一個 4x4 的二維矩陣,但是在 Javascript 實作上是用一維陣列來表達,而不是二維陣列,其索引值如下:

      +-               -+
      |  0,  4,  8, 12  |
      |  1,  5,  9, 13  |
      |  2,  6, 10, 14  |
      |  3,  7, 11, 15  |
      +-               -+
  • isValidMatrix(mat) - 判斷是否為有效的矩陣
  • makeIdentityMatrix() - 產生單位矩陣,也就是斜對角都為 1 其餘為 0 的矩陣
  • makeZeroMatrix() - 產生全部是0 的矩陣
  • makeMatrix(e00, e01, e02, e03, e10, e11, e12, e13, e20, e21, e22, e23, e30, e31, e32, e33) - 利用參數產生矩陣,其索引值順序如上述,或由此處的宣告亦可得知
  • matricesEqual(matrix1, matrix2) - 判斷兩矩陣是否相等
  • makePoseMatrix(vecLeft, vecUp, vecFrwd, vecPos) - 位置矩陣,通常用來處理「手勢」,效果如下:
		 +-                            -+
		 |  Left.x, Up.x, Fwd.x, Pos.x  |
		 |  Left.y, Up.y, Fwd.y, Pos.y  |
		 |  Left.z, Up.z, Fwd.z, Pos.z  |
		 |  0.0,    0.0,  0.0,   1.0    |
		 +-                            -+
  • transposeMatrix(mat) - 傳回轉置矩陣: 型如
	+-            -+ 
	|  A, B, C, D  |
	|  E, F, G, H  |
	|  I, J, K, L  |
	|  M, N, O, P  |
	+-            -+

轉置結果為:

	+-            -+
	|  A, E, I, M  |
	|  B, F, J, N  |
	|  C, G, K, O  |
	|  D, H, L, P  |
	+-            -+
  • inverseMatrix(mat) - 計算並傳回 mat 的反矩陣,使得 res * mat = I, 其中 I 是單位矩陣,參考 反矩陣
  • matrixDeterminant(mat) - 計算並傳回 mat 的行列式,通常用來算面積或體積,其值為純量,參考 行列式
  • matrixAdjoint(mat) - 不知道怎麼翻,伴隨矩陣?共軛矩陣?參考 adjoint matrix
  • multiplyMatrixByScalar(mat, scalar) - 每個元素都乘以 scalar
  • divideMatrixByScalar(mat, scalar) - 每個元素都除以 scalar
  • multiplyMatrixByMatrix(matOne, matTwo) - 矩陣乘法,結果亦為矩陣
  • multiplyMatrixByVector(mat, vec) - 將矩陣乘以向量,通常用來作向量的旋轉之類用途,結果亦為向量(其實是 4x4 矩陣與 4x1 矩陣相乘)
  • addMatrices(matOne, matTwo) - 兩矩陣相對應元素相加
  • subtractMatrices(matOne, matTwo) - 兩矩陣相對應元素相減

Quaternion 四元數

四元數顧名思義就是四個元素的數,請參考 四元數

  • isValidQuat(quat) - 傳回是否為有效的四元數
  • makeQuat(newW, newX, newY, newZ) - 傳回四元數 Quat = W + X * i + Y * j + Z * k, 其中 i, j, k 是虛部
  • quatToMatrix(quat) - 將四元數以矩陣來表示,其轉換如下:
+ ------------  ----------  ----------  --- +
  1 - 2(YY+ZZ)  2(XY+WZ)    2(XZ-WY)     0
  2(XY-WZ)      1-2(XX+ZZ)  2(YZ+WX)     0
  2(XZ+WY)      2(YZ-WX)    1-2(XX+YY)   0
  0             0           0            1
+ ------------  ----------  ----------  --- +
  • quatToAxisAngle(axisVec, angleScalar) - 用來將四元素的旋轉變成軸角的旋轉,不過似乎有 bug
  • axisAngleToQuat(axisVec, angleScalar) - 轉換軸角的旋轉為四元數的旋轉
  • matrixToQuat(newMat) - 將矩陣轉為四元數
  • quatLengthSq(quat) - 四元數的長度平方,等於 XX+YY+ZZ
  • quatLength(quat) - 四元數的長度 sqrt(XX+YY+ZZ)
  • addQuats(quatOne, quatTwo) - 兩個四元數相加
  • subtractQuats(quatOne, quatTwo) - 兩個四元數相減
  • multiplyQuatByScalar(quatOne, scalar) - 兩個四元數相減
  • getQuatConjugate(quat) - 四元數的共軛四元數(虛部分別為其負值)
  • quatDotProduct(quatOne, quatTwo) - 四元數的內積,其值為純量,但是並不等於 3D 意義中的長度
  • normalizeQuat(quat) - 四元數的正規化
  • inverseQuat(quat) - 反四元數

Camera 相機

Camera 有分 ChaseCamera, FixedCamera, FreeCamera, PanCamera,就讓我們一個一個來看吧

ChaseCamera

尚未實作,空的

FixedCamera

嗚嗚,似乎也是未實作,看 code 似乎也沒人用到

  • 屬性
    • globalPos - 相機位置,向量
    • globalOri - 相機方向,矩陣
    • nearClipping - 預設值 1.0
    • farClipping - 預設值 500
    • fieldView - 預設值 60
    • aspectRatio - 預設值 0
  • 方法
    • setGlobalPos(posVec) - 未實作
    • setGlobalOri(oriMat) - 未實作

PanCamera

尚未實作,空的

FreeCamera

  • 方法: 讀值
    • getPosition() - 傳回位置向量
    • getUp() - 傳回相機的 up vector(老實說我不知道這是啥或是要幹嘛)
    • getDir() - 傳回相機瞧的方向 vector
    • getLeft() - 傳回相機的 left vector(老實說我不知道這是啥或是要幹嘛)
    • getLinearVel() - 註解說是 Animation of positions,其值是向量
    • getAngularVel() - Animations of rotation around (side Vector, up Vector, dir Vector)
  • 方法: 設定
    • setPosition(newVec) - 設定相機位置
    • setLookAtPoint(newVec) - 設定相機看的點,必須移(應該是沒有轉)動相機(其實是轉動所有物件)
    • setUpVector(newVec) - 設定 up vector
    • setLinearVel(newVec) - 設定相機的旋轉速度?,其值是向量
    • setAngularVel(newVec) - 設定相機轉動軸?
  • 其他功能
    • rotateOnAxis(axis, angle) - 讓相機沿著某個向量軸 axis 繞行 angle 角度
    • yaw(angle) - 讓相機沿著其 Up vector 轉動 angle 角度
    • roll(angle) - 讓相機沿著其方向向量轉動 angle 角度
    • pitch(angle) - 讓相機沿著其 left vector 轉動 angle 角度
    • update(timeElapsed) - 這個函數跟設定旋轉速度有關,我猜是供內部呼叫
    • applyToWorld(glCanvas3D, scene) - 應該是「畫」出來的意思

畫布 Scene

  • 方法: 讀取
    • getCamera()
    • getObjListSize()
    • getGL() - 傳回 Canvas3D 引擎
    • getTotalFrameCount()
    • getRenderer()
    • getTextureManager()
    • getScene()
    • getSkyModel()
    • getAmbientLight() - 內部有個 ambientLight 陣列變數均為浮點數,假設為 a, 傳回值卻是 [a[0]/5, a[1]/5, a[2]/5, a[3]]
    • getObj(indxNum) - 傳回 Scene 中的物件
  • 方法: 設定
    • setKeyboardCallback(keyUpCB, keyDownCB) - 註冊鍵盤按鍵事件的聆聽函式
    • setMouseCallback(mouseUpCB, mouseDownCB, mouseMoveCB, mouseScrollCB) - 註冊滑鼠事件的聆聽函式
    • setSkyModel(sky)
    • setUpdateCallback(updateCB) - 每次 Scene 重刷時叫用
    • setRenderer(renderType)
    • setCanvasTag(canvasTag)
    • setCamera(cam)
    • addFloatingText(text, fontStyle, fontColour, backgroundColour)
    • addTextToModel(model, text, fontStyle, fontColour, backgroundColour)
    • create2Dcanvas(width, height) - Create a 2D canvas for drawing text and other stuff
    • setBackgroundColor(bgColor)
    • setAmbientLight(light)
    • init(name)
    • addObjectToScene(obj)
    • removeObjectFromScene(obj)
    • startScene()
    • render()
    • updateObjects(timeElapsed, camera)
    • renderObjects()
    • stopScene()
    • preloadImages(imagePaths)

虛擬世界的物件

物體

基本物件 Primitive

  • 基本屬性
    • visible: true - 物件是否可見
    • textureName - 紋理,譬如木頭?鐵?
    • name - 每個物件都有自己的名字
  • 原始位置,所有物件含相機都有 left, up, dir, pos 等資訊
    • left: (1, 0, 0) - left vector
    • up: (0, 1, 0) - up vector
    • dir: (0, 0, 1) - forward vector
    • pos: (0, 0, 0) - 位置
    • scaleVec: (1, 1, 1) - 放大率,預設就是 1
  • 移動資訊
    • linVel: (0, 0, 0) - 移動"速度"為 0, 預設是靜止
    • angVel: (0, 0, 0) - 轉動方向為 0, 預設是不轉動
  • 取值
    • getPosition() - 傳回 pos 值
    • getUp() - 傳回 up vector
    • getDirection() - 傳回 dir vector
    • getLeft() - 傳回 left vector
    • getLinearVel() - 傳回速度 linVel 向量值
    • getAngularVel() - 傳迴旋轉向量 angVel
    • isVisible() - 傳回是否可見
    • getScale() - 傳回放大率
    • getName() - 傳回物件名稱
    • getTextureName() - 傳迴紋理名稱
  • 設定
    • setTexture(imageFilename) - 設定紋理檔案名稱
    • setTextureFromCanvas2D(sourceCanvas) - 從 Canvas2D 設定紋理
    • unsetTexture() - 重設紋理為空的
    • setName(name) - 設定物件名稱
    • setVisible(show) - 設定物件是否可見
    • scale(scaleVec) - 設定物件放大比例
    • setPosition(vecPos) - 設定物件位置 pos 值
    • translate(translation) - 將物件放到新位置(相當於 pos+translation)
    • setForward(newVec) - 將物件往 newVec 方向移動,這會影響到 up, left 等向量
    • setUpVector(newVec) - 設定 up vector 成 newVec 值
    • setLinearVel(newVec) - 設定速度值為 newVec 值
    • setAngularVel(newVec) - 設定旋轉方向為 newVec 值
    • rotateOnAxis(axisVec, angle) - 以四元數及矩陣來計算物件的旋轉, 先移動 dir, 再計算相對應的 left, up 值
    • yaw(angle) - 效果是 rotateOnAxis(up, angle)
    • roll(angle) - 效果是 rotateOnAxis(dir, angle)
    • pitch(angle) - 效果是 rotateOnAxis(left, angle)
    • update(timeStep) - 依照速度向量 linVel 移動物體的 pos 位置向量,並調整 up, dir, left 等向量值
    • render(glCanvas3D) - 透過 glCanvas3D 這個 plugin 把物件畫出來,這邊會有顏色,只是怪怪的

Model (繼承自 Primitive)

  • 屬性
    • loadedTexture: false - 是否已載入紋理
    • expandedVertices - 似乎要用來放大縮小用的
    • expandedNormals
    • expandedUVs
    • buffers
    • firstTimeRender: true - 第一次畫出來
    • stayInFrontOfCamera: false - 是否在相機前,應該是與是否可見有關
  • 方法
    • init(vertices, normals, texcoords, faces) - 必要參數是 vertices, faces。normal是單位大小,或許與燈光有關,texcoords 是紋理座標(不懂),而 faces 則是引索陣列,引用 texcoords 來當其表面紋理
    • initDAE(path) - dae是Collada的檔案副檔名,是用xml去儲存3d的模型
    • createBuffers(glCanvas3D) - 應該是在根據 expandedVertices 準備畫布,若有設定 expandedUVs, expandedNormals, 也會準備相對應的 Buffer
    • update(timeStep, camera) - 會先根據相機移動相對位置後,再根據自己的速度與旋轉來移動自己
    • render(glCanvas3D, scene) - 要把物體畫出來,相對上麻煩的多

立方體 Cube

繼承自基本物件 Primitive

轉換矩陣

為了效率考量,定義了幾個轉換用的矩陣:

  • cube_transition_Vertices =
	[
		[-1, -1, 1],	// 0 - front, bottom, left
		[-1,  1, 1],	// 1 - front, top, left
		[ 1,  1, 1],	// 2 - front, top, right
		[ 1, -1, 1],	// 3 - front, bottom, right
		
		[-1, -1, -1],	// 4 - back, bottom, left
		[-1,  1, -1],	// 5 - back, top, left
		[ 1,  1, -1],	// 6 - back, top, right
		[ 1, -1, -1]	// 7 - back, bottom, right	
	];
  • cube_transition_Normals =
	[
		[-0.57735,-0.57735, 0.57735],	// front, bottom, left
		[-0.57735, 0.57735, 0.57735],	// front, top, left	
		[ 0.57735, 0.57735, 0.57735],	// front, top, right	
		[ 0.57735,-0.57735, 0.57735],	// front, bottom, right		
		
		[-0.57735,-0.57735, -0.57735],	// back, bottom, left
		[-0.57735, 0.57735, -0.57735],	// back, top, left
		[ 0.57735, 0.57735, -0.57735],	// back, top, right	
		[ 0.57735,-0.57735, -0.57735]	// back, bottom, right	
	];
  • cube_transition_UVs =
	[
		[0.0,1.0],	// 0 - bottom left
		[0.0,0.0],	// 1 - top left
		[1.0,0.0],	// 2 - top right
		[1.0,1.0]		// 3 - bottom right
	];
  • cube_transition_Faces =
	[
		[0,0,0], [3,3,3], [2,2,2],	// front
		[0,0,0], [2,2,2], [1,1,1],
			
		[5,2,5], [6,1,6], [7,0,7],	// back
		[5,2,5], [7,0,7], [4,3,4],

		[4,0,4], [7,3,7], [3,2,3],	// bottom
		[4,0,4], [3,2,3], [0,1,0],

		[1,0,1], [2,3,2], [6,2,6],	// top
		[1,0,1], [6,2,6], [5,1,5],
		
		[4,0,4], [0,3,0], [1,2,1],	// left side
		[4,0,4], [1,2,1], [5,1,5],
		
		[3,0,3], [7,3,7], [6,2,6],	// right side
		[3,0,3], [6,2,6], [2,1,2]
	];
屬性與方法
  • 屬性
    • m - 就是 Model 物件
    • 其餘均繼承自 Model
  • 方法 - 除 scale 外,全部繼承自 Model
    • init(), isVisible()
    • getPosition(), getUp(), getDirection(), getLeft(), getLinearVel(), getAngularVel(), getScale(), getTextureName(),
    • setTexture(imageFilename), setTextureFromCanvas2D(sourceCanvas), unsetTexture(), setVisible(show)
    • setPosition(vecPos), setForward(newVec), setUpVector(newVec),
    • translate(translation), setLinearVel(newVec), setAngularVel(newVec), rotateOnAxis(axisVec, angle)
    • yaw(angle), roll(angle), pitch(angle), update(timeStep), render(glCanvas3D, scene)
    • scale(scaleVec, scaleY, scaleZ) - 多了 Y, Z 二個軸向的放大縮小?忽略的話就跟 Model 一樣

Primitive Class

Model Class

個人工具