搜尋
首頁web前端js教程Three.js原始碼閱讀筆記(物件是如何組織的)_基礎知識

這是Three.js原始碼閱讀筆記第三篇。之前兩篇主要是關於核心物件的,這些物件主要圍繞著向量vector3物件和矩陣matrix4物件展開的,關注的是空間中的單一頂點的位置和變化。這篇將主要討論Three.js中的物體是如何組織的:即如何將頂點、表面、材質組合成為一個具體的物件。
Object::Mesh
這個建構子建構了一個空間中的物體。之所以叫「網格」是因為,實際上具有體積的物體基本上都是建模成為「網格」的。

複製代碼 代碼如下:

THREE.Mesh = function ( geometry, material ) {
THREE.Object3D.call( this );
this.geometry = geometry;
this.material = ( material !== undefined ) ? material : new THREE.MeshBasicMaterial( {omrand: Mathaterial(om) * 0xffffff, wireframe: true } );
/* 一些其他的與本節無關的內容*/
}

實際上,Mesh類別只有兩個屬性,表示幾何形體的geometry物件和表示材質的material物件。 geometry物件在上一篇文章中已經介紹過,還有部分派生類別會在這篇部落格文章中介紹(透過這些衍生類別的建構過程,能更清楚地了解到Mesh物件的工作原理);matrial物件及其衍生類別也將在這篇筆記中介紹。 Mesh對象的這兩個屬性相互緊密關聯,geometry對像中的face數組中,每個face對象的materialIndex用來匹配material屬性對象,face對象的vertexUVs數組用以依次匹配每個頂點在數組上的取值。值得注意的是,Mesh只能有一個material物件(不知這樣設計的意圖何在),如果需要用到多個材質,應將材質依照materialIndex順序初始化在geometry本身的materials屬性中。
Geometry::CubeGeometry
這個建構子建立了一個立方體物件。
複製程式碼 程式碼如下:

THREE.. widthSegments, heightSegments, depthSegments ) {
THREE.Geometry.call( this );
var scope = this;
this.width = width;
this.height;
this.width = width;
this.height = height. depth = depth;
var width_half = this.width / 2;
var height_half = this.height / 2;
var depth_half = this.depth / 2;
var depth_half = this.depth / 2;
/* 略去* 🎜>buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px
/* 略去*/
function buildPlane( u , v, udir, vdir, width, height, depth, materialIndex ) {
/* 略去*/
}
this.computeCentroids();
this.mergefVertices(); };

建構子做的最重要的事在buildPlane。這個函數最重要的事情就是對scope的操作(上面的程式碼區塊中,scope就是this),包括:呼叫scope.vertices.push(vector)將頂點加入geometry物件;呼叫scope.faces.push(face)將表面加入到geometry對象,呼叫scope.faceVertexUvs[i].push(uv)方法將對應於頂點的材質座標加入geometry物件。程式碼的大部分都是關於產生立方體的邏輯,這些邏輯很容易理解,也很容易擴展到其他類型的geometry物件。

建構子的參數包括長、寬、高和三個方向的分段數。所謂分段,就是說如果將widthSeqments等三個參數都設定為2的話,那麼每個面將被表現成2×2=4個面,整個立方體由24個表面組成,正如同網格一樣。
複製程式碼 程式碼如下:

函數buildPlane( u, v, udir, vdir, 寬度, 高度, 深度, MaterialIndex ) {
var w, ix, iy,
gridX =scope.widthSegments,
gridY scope.heightSegments,
width_half = 寬度/ 2,
height_half = 高度/ 2,
offset =scope.vertices.length;
if ( (( u === 'x' & v == = 'y' ) || ( u === 'y' && v === 'x' ) ) {w = 'z';}
else if ( ( u === 'x' && v = == 'z' ) || ( u === 'z' && v === 'x' ) ) {w = 'y'; gridY = range.depthSegments;} else if ( ( u === 'z ' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {w = 'x';gridX = range.depthSegments;}
var gridX1 = gridX 1,
gridY1 = gridY 1,
segment_width = 寬度/ gridX,
segment_height = 高度/ gridY,
正常= 新三.Vector3();
> 0 ? 1 : - 1;
for ( iy = 0; iy for ( ix = 0; ix var vector = new THREE.Vector33 ();
向量[u]=(ix*segment_width-width_half)*udir;
向量[v]=(iy*segment_height-height_half)*vdir;
向量[ w ] = 深度;
scope.vertices.push(向量);
}
}
for ( iy = 0; iy for ( ix = 0; ix var a = ix gridX1 * 我;
var b = ix gridX1 * ( iy 1 );
var c = ( ix 1 ) gridX1 * ( iy 1 );
var d = ( ix 1 ) gridX1 * iy;
var face = new THREE.Face4(a 偏移量, b 偏移量, c 偏移量, d 偏移量);
face.normal.copy(正常) ;
face.vertexNormals.push( 正常. 克隆(), 正常. 克隆(), 正常. 克隆(), 正常. 克隆() );
face.materialIndex =materialIndex;
scope.facesface>face.materialIndex =materialIndex;
scope.facesfaces .push( 臉);
scope.faceVertexUvs[ 0 ].push( [
new THREE.UV( ix / gridX, 1 - iy / gridY ),
new THREE.UV( ix / gridX, ix / gridX, 1 - ( iy 1 ) / gridY ),
new THREE.UV( ( ix 1 ) / gridX, 1- ( iy 1 ) / gridY ),
new THREE.UV( ( ix 1 ) / gridX, 1 - iy / gridY )
]);
}
}
}


除了一個大部分物件都有clone()方法,CubeGeometry沒有其他的方法,其他的XXXGeometry物件也大抵如此。沒有方法說明該物件負責組織和資料存儲,以及如何利用這些資料產生三維場景和動畫,封裝在另外的物件中定義的。 Geometry::CylinderGeometry

顧名思義,該建構子建立一個圓柱體(或圓台)物件。 代碼如下:


THREE .CylinderGeomeius = fightius, Botius radiusSegments, heightSegments, openEnded ) {
/* 略*/
}


有了CubeGeometry建構函式的基礎,自己也應該能夠實作CylinderGeometry,我們只需要注意一下建構子各參數的意義。 radiusTop和radiusBottom表示頂部和底部的半徑,height表示高度。 radiusSegments定義了將圓週橫斷面多少份(該數字越大,圓柱更圓), heightSegments定義了需要將整個身高高度縮短多少份,openEnded指定是否產生頂面和底面。

源碼中還有兩點註解的:該模型的本地原點是中關節炎的中點,而不是重心之類的,遇到上圓面的高度(y軸值)是height/ 2,下圓面是-height/2,這一點對圓柱體來說沒有差異,但對於上下半徑不同的圓台體存在差異了;還有該模型的頂面和採用Groundface3 類型表面,而第三種Face4 類型表面。 Geometry::SphereGeometry

這個建構子建立一個球體。 程式碼如下:


THREE.SphereGeometry = f腳>

THREE.SphereGeometry = function (Seg.S)w. phiStart, phiLength, thetaStart, thetaLength ){
/* 略*/
}


各參數的意義:radius指定半徑,widthSegments表示「經度」分帶數量,heightSegments “緯度”分帶數目。後面四個參數是任選的,表示經度的初始值和緯度的初始值。熟悉極座標的都了解,通常用希臘文φ(phi)表示緯度圈角度(經度) ),而用θ(theta)表示經圈角度(緯度)。這四個數的預設值分別為0,2π,0,π,藉由改變它們的值,可以創造出殘缺的球面(但是邊緣必須平行) )。 源碼中,除了北極和南極的極圈內的區域是用face3類型表面,其他位置都是用face4類型表面。本地原點為球心。

幾何::PlaneGeometry
這個建構函式建立一個平面。 複製程式碼
程式碼如下:

THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ){
/* 略*/
}

各參數意義:依次為寬度>高度、寬度分段數、高度分段數。想必讀者對這種構造「格網」的方式應該很熟悉了吧。
原始碼中得到一些其他資訊:平面被構造在x-y平面上,原點即矩形中心點。
Geometry::ExtrudeGeometry
該物件現在是構造一般幾何形體的方法,但是通常我們是將建模好的物件儲存在某種格式的檔案中,並透過loader加載進來,所以似乎鮮有直接用到該函數的機會。而且這個函數看起來還是半成品,很多設定一股腦地堆在options物件裡,我也沒有仔細研究。
Material::Material
Material物件是所有其他種類Material的原型物件。
複製程式碼 程式碼如下:

THREE.Material = function (>

THREE.Material = function (>

THREE.Material = function (>
. .MaterialLibrary.push( this );
this.id = THREE.MaterialIdCount ;
this.name = '';
this.side = THREE.FrontSide;
this.opacity = 1;
this.transparent = false;
this.blending = THREE.NormalBlending;
this.blendSrc = THREE.SrcAlphaFactor;
this.blendDst = THREE.OneMinusMinus.SrcAlphaFactor;
this.blendDst = THREE.OneMinusMinus.SrcAlphaFactor;
this.blendDst = THREE.OneMinusMinus.Srcphathisation.SrcLquetDst = THREE。 AddEquation;
this.depthTest = true;
this.depthWrite = true;
this.polygonOffset = false;
this.polygonOffsetFactor = 0;
this.polygonOfmm>Units = 0; this.alphaTest = 0;
this.overdraw = false; // Boolean for fixing antialiasing gaps in CanvasRenderer
this.visible = true;
this.needsUpdate = true;
};

先看一些較為重要的屬性:
屬性opacity為一個0-1區間的值,表示透明度。屬性transparent指定是否使用透明,只有在該值為真的時候,才會將其與混合(透明是渲染像素時,待渲染值與已存在值共同作用計算出渲染後像素值,達到混合的效果) 。

屬性blending,blendSrc,blendDst,blendEquation指定了混合方式和混合源Src和混合像素已有的像元值Dst的權重指定方式。預設(如建構函式中賦的預設值),新的像元值等於:新值×alpha 舊值×(1-alpha)。

我曾經困惑為何Material類別中沒有最重要的對象,表示紋理圖片的屬性。後來我理解了,其實材質和紋理還是有差別的,只能說某種材質有紋理的,但也有材質是沒有紋理的。材質影響的是整個形體的渲染效果,例如:「對一條線渲染為5px寬,兩端點為方塊,不透明的紅色」這段描述就可以認為是材質,而沒有涉及任何紋理。 和眾多Geometry物件一樣,Material物件除了通用的clone(),dellocate()和setValues()方法,沒有其他方法。以下是兩種最基本的材質物件。

Material::LineBasicMaterial
此建構函式會建立用於渲染線狀形體的材質。 複製程式碼

程式碼如下:


THREE.LineBasicMaterial = function (Material = function (Naterial = function (Material = function) THREE.Material.call( this );
this.color = new THREE.Color( 0xffffff );
this.linewidth = 1;
this.linecap = 'round';
thisline. = 'round';
this.vertexColors = false;
this.fog = true;
this.setValues( parameters );
};


屬性和linewidth顧名思義,指線的顏色和線的寬度(線沒有寬度,這裡的寬度是用來渲染的)。
屬性linecap和linejoin指定線條端點和連接點的樣式。 屬性fog指定該種材質是否收到霧的影響。
Material::MeshBasicMaterial
此建構函式建立用於渲染Mesh表面的材質。 複製程式碼
程式碼如下:

THREE.MeshBasicMaterial = function ( parameters ) {
THREE.Material.call( this );
this.color = new THREE.Color( 0xffffff ); // emissive . map = null;
this.lightMap = null;
this.specularMap = null;
this.envMap = null;
this.combine = THREE.MultiplyOperation;
this.reflectivity = 1.reflectivity = 1.reflectivity = 1.reflectivity = 1.reflectivity = 1.reflectivity = 1.reflectivity。 ;
this.refractionRatio = 0.98;
this.fog = true;
this.shading = THREE.SmoothShading;
this.wireframe = false;
this.wireframeLiidth = 1; >this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.vertexColors = THREE.NoColors;
this.skinning = false;
this.morphTargets = fsese; 🎜>this.setValues( parameters );
};


這裡出現了最重要的紋理屬性,包括map,lightMap和specularMap,他們都是texture類型的物件。
屬性wireframe指定表面的邊界線是否渲染,如果渲染,後面的若干以wireframe開頭的屬性表示如果渲染邊界線,將如何渲染。

Texture::Texture

這個建構函式用來建立紋理物件。

複製程式碼 程式碼如下: THREE.Texture = function ( >
THREE.Texture = function ( imageS, . wrapT, magFilter, minFilter, format, type, anisotropy ) {
THREE.TextureLibrary.push( this );
this.id = THREE.TextureIdCount ;
this.name = ''; this.name = '';
this; .image = image;
this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping();
this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrap; .wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;
this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
this.minter = min .LinearMipMapLinearFilter;
this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
this.format = format !== undefined ? format : THREE.RGBAFormat; undefined ? type : THREE.UnsignedByteType;
this.offset = new THREE.Vector2( 0, 0 );
this.repeat = new THREE.Vector2( 1, 1 );
this.generateMipmaps = true ;
this.premultiplyAlpha = false;
this.flipY = true;
this.needsUpdate = false;
this.onUpdate = null;
};


>最重要的屬性是image,這是一個JavaScript Image類型物件。傳入的第一個參數就是該對象,如何創建該對像在後面說。

後面的物件都是可選的,如果預設會填入預設值,而且往往都是填入預設值。
屬性magFileter和minFileter指定紋理在放大縮小時的過濾方式:最接近點、雙線性內插等。
從url產生一個texture,需要呼叫Three.ImageUtils.loadTexture(paras),函數傳回一個texture類型物件。在函數內部又呼叫了THREE.ImageLoader.load(paras)函數,這個函數內部又呼叫了THREE.Texture()建構函數,產生紋理。
陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Python vs. JavaScript:開發人員的比較分析Python vs. JavaScript:開發人員的比較分析May 09, 2025 am 12:22 AM

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

Python vs. JavaScript:選擇合適的工具Python vs. JavaScript:選擇合適的工具May 08, 2025 am 12:10 AM

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript:了解每個的優勢Python和JavaScript:了解每個的優勢May 06, 2025 am 12:15 AM

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

JavaScript的核心:它是在C還是C上構建的?JavaScript的核心:它是在C還是C上構建的?May 05, 2025 am 12:07 AM

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript應用程序:從前端到後端JavaScript應用程序:從前端到後端May 04, 2025 am 12:12 AM

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

Python vs. JavaScript:您應該學到哪種語言?Python vs. JavaScript:您應該學到哪種語言?May 03, 2025 am 12:10 AM

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架:為現代網絡開發提供動力JavaScript框架:為現代網絡開發提供動力May 02, 2025 am 12:04 AM

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

JavaScript,C和瀏覽器之間的關係JavaScript,C和瀏覽器之間的關係May 01, 2025 am 12:06 AM

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!