舊文件

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

C3dl

出自 MozTW Wiki

於 2008年10月9日 (四) 11:39 由 Wade.fs對話 | 貢獻 所做的修訂 Model

請見 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) - 應該是「畫」出來的意思

虛擬世界的物件

物體

基本物件 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

/*Copyright (c) 2008 Seneca College

Licenced under the MIT License (http://www.c3dl.org/index.php/mit-license/)
*/
Model.prototype = new Primitive;

/**
	@class A Model is an object which has a geometric representation composed of 
	vertices, normals and uv coordinates. Models may also  have textures
	applied to them.
*/
function Model()
{
	var loadedTexture	= false;
	
	this.expandedVertices = new Array();
	this.expandedNormals = null;
	this.expandedUVs = null;
	
	this.buffers = {};
	this.firstTimeRender = true;
	
	this.stayInFrontOfCamera = false;
	
	/**
		<p>
		This method should be called after a model object has been 
		created using:
		</p>

		<p>
			<code>
			var model = new Model();
			</code>
		</p>

		<p>
		null values may be provided for the normals and texcoord arguments,
		however the vertices and faces arrays are required.
		</p>

		@param {Array} vertices Array of the unique vertices of the model.

		@param {Array} [normals] Array of the unique normals of the 
		model, if null lighting will not work correctly for this model.

		@param {Array} [texcoords] Array of texture coordinates of 
		the model. If null, textures cannot be applied to this model.

		@param {Array of Arrays} faces Array of arrays which contains index 
		values which refer to values in the previous arrays.
	*/
	this.init = function(vertices, normals, texcoords, faces)
	{
		var texCoordsPresent = false;
		var normalsPresent = false;


		if(typeof vertices == "string")
		{
			this.initDAE(vertices);
		}
	
		else{
			// At the least, vertices and faces must be present
			if( vertices instanceof Array && faces instanceof Array)
			{
				if( texcoords instanceof Array)
				{
					texCoordsPresent = true;
					this.expandedUVs = new Array();
				}

				if( normals instanceof Array)
				{
					normalsPresent = true;
					this.expandedNormals = new Array();
				}

				for( var i =0; i < faces.length; i++)
				{
					// get vert index
					var vertIndex = faces[i][0];
					var cvert = vertices[vertIndex];
					this.expandedVertices.push(cvert[0]);
					this.expandedVertices.push(cvert[1]);
					this.expandedVertices.push(cvert[2]);
								
					// push on uvs
					if( texcoords instanceof Array)
					{
						var texIndex =  faces[i][1];
						var ctex =  texcoords[texIndex];
						this.expandedUVs.push(ctex[0]);
						this.expandedUVs.push(ctex[1]);
					}
					
					// push on normals
					if( normals instanceof Array)
					{					
						var offset = (texCoordsPresent == false) ? 1: 2;

						var normIndex = faces[i][offset];
						var cnorm = normals[normIndex];
						this.expandedNormals.push(cnorm[0]);
						this.expandedNormals.push(cnorm[1]);
						this.expandedNormals.push(cnorm[2]);
					}
				}
			}
		}
		this.initDone = true;				
	}


	this.initDAE = function(path)
	{
		// add the model to the model pool.
		// it is either added or is already present.
		ModelManager.addModel(path);

		// now, get the data
	//	this.expandedNormals = ModelManager.getNormals(path);
	//	this.expandedUVs = ModelManager.getUVs(path);
		this.expandedVertices = ModelManager.getModel(path);
	}

	/**
		@private

		@param {context} glCanvas3D
	*/
	this.createBuffers = function(glCanvas3D)
	{
		this.buffers.vertex = glCanvas3D.createBuffer(glCanvas3D.STATIC_DRAW, 3, glCanvas3D.FLOAT, this.expandedVertices);

		if( this.expandedUVs )
		{
			this.buffers.tex = glCanvas3D.createBuffer(glCanvas3D.STATIC_DRAW, 2, glCanvas3D.FLOAT, this.expandedUVs);
		}

		if( this.expandedNormals )
		{
			this.buffers.normal = glCanvas3D.createBuffer(glCanvas3D.STATIC_DRAW, 3, glCanvas3D.FLOAT, this.expandedNormals);
		}
	}


	/**
		Update animations for linear velocity and angular velocity.

		@param {float} timeStep

		@returns {boolean} true.
	*/
	this.update = function(timeStep, camera)
	{
		if (this.stayInFrontOfCamera)
		{
			//!! All this math is crap because it does't work when the camera rotates
			
			var camUp = camera.getUp();
			var camLeft = camera.getLeft();
			var camDir = camera.getDir();
			this.up = makeVector(-camUp[0], -camUp[1], -camUp[2]);
			this.left = makeVector(-camLeft[0], -camLeft[1], -camLeft[2]);
			this.dir = makeVector(-camDir[0], -camDir[1], -camDir[2]);
			
			var camPos = camera.getPosition();
			//!! These hard-coded values are a hack, need to set them based
			//!! on where we want the floating thing to be in the canvas
			this.pos = makeVector(camPos[0] + 10, camPos[1] - 15, camPos[2] + 10);
			
			//logWarning('camera ' + camPos);
			//logWarning('plane ' + this.pos);
			
			return true;
		}
		
		// if the texture is loaded, it requires and update.
		if (this.loadedTexture == true)
		{
			//this.loadedTexture = false;
			return true;
		}

		if (isVectorZero(this.linVel) && isVectorZero(this.angVel))
		{
			// nothing will change
			return false;
		}
		
		if (!isVectorZero(this.linVel))
		{
			// Add a velocity to the position
			var velVec = new Array();
			velVec = this.linVel;
			multiplyVector(velVec, timeStep);
			addVectors(this.pos, velVec, this.pos);
		}
		
		if (!isVectorZero(this.angVel))
		{
			// Apply some rotations to the orientation from the angular velocity
			this.pitch(this.angVel[0] * timeStep);
			this.yaw(this.angVel[1] * timeStep);
			this.roll(this.angVel[2] * timeStep);
		}
		
		// force update.
		return true;
	}

	/**
		Render the model.

		@param {context} glCanvas3D
		@param {Scene} scene

	*/
	this.render = function(glCanvas3D, scene)
	{
		if (glCanvas3D == null)
		{
			logWarning('Model::render() called with a NULL glCanvas3D');	
			return false;
		}
		
		// render() is passed a reference to the scene, which gives us a chance
		// to setup somethings we could not eariler since we don't have the scene 
		// in some methods.
		if( this.firstTimeRender )
		{
			if( this.getTextureName())
			{
				scene.getTextureManager().addTexture(this.getTextureName());
			}

			// if we are using the 1.1 context, we have to setup the buffers
			if( scene.getRenderer() instanceof OpenGLES11)
			{
				this.createBuffers(glCanvas3D);
			}
			// make sure this code in this block isn't run again.
			this.firstTimeRender = false;
		}
		else
		{
			// if the user has changed the texture after we have already 
			// rendered once, we have to add the new texture to the 
			// TextureManager
			
			// don't bother to check if the image is already in the 
			// textureManager, the textureManager does that check already.
			if( this.getTextureName() )
			{
				scene.getTextureManager().addTexture(this.getTextureName());
			}
		}

		
		// only draw the primitive if it is visible 
		if( this.isVisible() )
		{
			if (scene.getRenderer() instanceof OpenGLES20)
			{	
				// world transform of the model						
				var wtMat = new Array(	this.getLeft()[0],	this.getLeft()[1],			this.getLeft()[2],			0,
									this.getUp()[0],			this.getUp()[1],			this.getUp()[2],			0,
									this.getDirection()[0],	this.getDirection()[1],	this.getDirection()[2],	0,
									this.getPosition()[0],		this.getPosition()[1],		this.getPosition()[2],		1);

				// scaling is done seperately for now					
				var wtScale = new Array( this.getScale()[0],0,0,0,
										0,this.getScale()[1],0,0,
										0,0,this.getScale()[2],0,
										0,0,0,1);
				
				// now add the saling components.							
				wtMat = multiplyMatrixByMatrix(wtScale,wtMat);
				
				var modelMatrix = glCanvas3D.getUniformLocation(scene.getRenderer().sp, "modelMatrix");
				glCanvas3D.uniformMatrix( modelMatrix, wtMat);
				

				// ambient lighting
				var ambientLight = scene.getAmbientLight();		

				var lightMatrix = new Array( ambientLight[0],0,0,0,
										0,ambientLight[1],0,0,
										0,0,ambientLight[2],0,
										0,0,0,ambientLight[3]);												

				var ambientLightUniform = glCanvas3D.getUniformLocation(scene.getRenderer().sp, "ambientLight");
				glCanvas3D.uniformMatrix(ambientLightUniform, lightMatrix);
				
				// Texture
				
				//var tex = glCanvas3D.getUniformLocation(scene.getRenderer().sp, "myTex");				
				//glCanvas3D.uniformi(tex, TextureManager.getID(this.getTextureName()));
	
				var ta = glCanvas3D.getAttribLocation(scene.getRenderer().sp, "Texture");
				// Only allow textures if the model has a texture and it also has UVs.
				if(this.getTextureName() && this.expandedUVs && ta != -1 )				
				{
					glCanvas3D.activeTexture(glCanvas3D.TEXTURE0);
					glCanvas3D.enable(glCanvas3D.TEXTURE_2D);
					glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D, scene.getTextureManager().getID(this.getTextureName()));

					glCanvas3D.vertexAttribPointer(ta, 2, glCanvas3D.FLOAT, this.expandedUVs);
					glCanvas3D.enableVertexAttribArray(ta);	
				}
				else
				{
					glCanvas3D.disableVertexAttribArray(ta);
					glCanvas3D.disable(glCanvas3D.TEXTURE_2D);
					glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D,-1);
				}			


				// NORMALS	
				var na = glCanvas3D.getAttribLocation(scene.getRenderer().sp, "Normal");
				if(this.expandedNormals && na != -1)
				{
					var N = makeZeroMatrix();				
					
					N = addMatrices(N, wtMat);
					N = transposeMatrix(N);
					N = inverseMatrix(N);
					
					var normalMatrix = glCanvas3D.getUniformLocation(scene.getRenderer().sp, "normalMatrix");
					glCanvas3D.uniformMatrix(normalMatrix, N);

					glCanvas3D.vertexAttribPointer(na, 3, glCanvas3D.FLOAT, this.expandedNormals);
					glCanvas3D.enableVertexAttribArray(na);
				}
				else
				{
					glCanvas3D.disableVertexAttribArray(na);					
				}

				// Vertices
				var va = glCanvas3D.getAttribLocation(scene.getRenderer().sp, "Vertex");
				glCanvas3D.vertexAttribPointer(va, 3, glCanvas3D.FLOAT, this.expandedVertices);
				glCanvas3D.enableVertexAttribArray(va);				
				
				// still trying to get this to work,
				// for now, I had to resort to using drawArrays
				//glCanvas3D.drawElements(glCanvas3D.TRIANGLES, ind.length, ind);
				glCanvas3D.drawArrays(glCanvas3D.TRIANGLES, 0, (this.expandedVertices.length/3));			
			}
			else if (scene.getRenderer() instanceof OpenGLES11)
			{
				// TEXTURES 
				// only bind the texture if this object was actually assigned one
				if(this.getTextureName() && this.buffers.tex)
				{
					glCanvas3D.enable(glCanvas3D.TEXTURE_2D);
					glCanvas3D.bindTexture(glCanvas3D.TEXTURE_2D, scene.getTextureManager().getID(this.getTextureName()));
					glCanvas3D.texCoordPointer(this.buffers.tex);
					glCanvas3D.enableClientState(glCanvas3D.TEXTURE_COORD_ARRAY);
				}
				else
				{
					glCanvas3D.disable(glCanvas3D.TEXTURE_2D);
				}

				// NORMALS
				// only enable the normals if the object actually has them
				if( this.buffers.normal)
				{
					glCanvas3D.normalPointer(this.buffers.normal);
					glCanvas3D.enableClientState(glCanvas3D.NORMAL_ARRAY);
				}

				// VERTICES
				glCanvas3D.vertexPointer(this.buffers.vertex);
				glCanvas3D.enableClientState(glCanvas3D.VERTEX_ARRAY);

				var scale = new Array( this.getScale()[0],0,0,0,
										0,this.getScale()[1],0,0,
										0,0,this.getScale()[2],0,
										0,0,0,1);									
			
				var m = new Array(	this.getLeft()[0],			this.getLeft()[1],			this.getLeft()[2],			0,
									this.getUp()[0],			this.getUp()[1],			this.getUp()[2],			0,
									this.getDirection()[0],	this.getDirection()[1],	this.getDirection()[2],	0,
									this.getPosition()[0],		this.getPosition()[1],		this.getPosition()[2],		1);

				// Draw
				glCanvas3D.pushMatrix();			
					glCanvas3D.multMatrix(m);
					glCanvas3D.multMatrix(scale);
					glCanvas3D.drawArrays(glCanvas3D.TRIANGLES, 0, (this.expandedVertices.length/3));
				glCanvas3D.popMatrix();					
				
				// Turn off Buffers
				glCanvas3D.disableClientState(glCanvas3D.VERTEX_ARRAY);
				glCanvas3D.disableClientState(glCanvas3D.NORMAL_ARRAY);
				glCanvas3D.disableClientState(glCanvas3D.TEXTURE_COORD_ARRAY);	
			}// close draw with 1.1
		}// if visible		
	}// render
} 

立方體 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]
	];
屬性與方法

// when this object is created, make a cube model inside it. this.m = new Model(); this.m.init(cube_transition_Vertices, cube_transition_Normals, cube_transition_UVs, cube_transition_Faces);

this.getPosition = function() { return this.m.getPosition();} this.getUp = function() { return this.m.getUp();} this.getDirection = function() { return this.m.getDirection();} this.getLeft = function() { return this.m.getLeft();} this.getLinearVel = function() { return this.m.getLinearVel();} this.getAngularVel = function() { return this.m.getAngularVel();} this.isVisible = function() { return this.m.isVisible();} this.getScale = function() {return this.m.getScale(); }

this.setTexture = function(imageFilename){ this.m.setTexture(imageFilename);} this.setTextureFromCanvas2D = function(sourceCanvas){this.m.setTextureFromCanvas2D(sourceCanvas);} this.getTextureName = function() {this.m.getTextureName();} this.unsetTexture = function(){this.m.unsetTexture();} this.setVisible = function(show){this.m.setVisible(show);}

// scale the Cube, if only one parameter is specified, consider // it to be a vector|array, otherwise consider it to be 3 scalars. this.scale = function(scaleVec, scaleY, scaleZ) { if( scaleY && scaleZ) { var triplet = new Array(scaleVec, scaleY, scaleZ); this.m.scale(triplet); } else { this.m.scale(scaleVec); } }

this.setPosition = function(vecPos){ this.m.setPosition(vecPos);} this.translate = function(translation){this.m.translate(translation);} this.setForward = function(newVec){this.m.setForward(newVec)}; this.setUpVector = function(newVec){this.m.setUpVector(newVec);} this.setLinearVel = function(newVec){this.m.setLinearVel(newVec);} this.setAngularVel = function(newVec){this.m.setAngularVel(newVec);} this.rotateOnAxis = function(axisVec, angle){this.m.rotateOnAxis(axisVec, angle);} this.yaw = function(angle){this.m.yaw(angle);} this.roll = function(angle){this.m.roll(angle);} this.pitch = function(angle){this.m.pitch(angle);} this.update = function(timeStep){this.m.update(timeStep);} this.render = function(glCanvas3D, scene){this.m.render(glCanvas3D, scene);} }

Primitive Class

Model Class

個人工具