国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

three.js 入門詳解(一)

Jacendfeng / 1709人閱讀

摘要:一般說來,對于制圖建模軟通常使正交投影,這樣不會因為投影而改變物體比例而對于其他大多數應用,通常使用透視投影,因為這更接近人眼的觀察效果。

1. 概述 1.1 什么是WebGL?
WebGL是在瀏覽器中實現三維效果的一套規范

想要使用WebGL原生的API來寫3D效果的話,很吃力。three.js是WebGL的一個開源框架,它省去了很多麻煩的細節。

1.2 初識three.js
什么是threejs,很簡單,你將它理解成three+js就可以了。three表示3D的意思js表示javascript的意思。那么合起來,three.js就是使用javascript 來寫3D程序的意思。

Javascript是運行在網頁端的腳本語言,那么毫無疑問Three.js也是運行在瀏覽器上的。

1.3 前期準備 1.3.1 下載地址

three.js 下載地址

1.3.2 目錄結構

Build目錄: 包含兩個文件,three.js 和three.min.js 。這是three.js最終被引用的文件。一個已經壓縮,一個沒有壓縮的js文件。

Docs目錄: 這里是three.js的幫助文檔,里面是各個函數的api,可惜并沒有詳細的解釋。試圖用這些文檔來學會three.js是不可能的。

Editor目錄: 一個類似3D-max的簡單編輯程序,它能創建一些三維物體。

Examples目錄: 一些很有趣的例子demo,可惜沒有文檔介紹。對圖像學理解不深入的同學,學習成本非常高。

Src目錄: 源代碼目錄,里面是所有源代碼。

Test目錄: 一些測試代碼,基本沒用。

Utils目錄: 存放一些腳本,python文件的工具目錄。例如將3D-Max格式的模型轉換為three.js特有的json模型。

.gitignore文件: git工具的過濾規則文件,沒有用。

CONTRIBUTING.md文件: 一個怎么報bug,怎么獲得幫助的說明文檔。

LICENSE文件: 版權信息。

README.md文件: 介紹three.js的一個文件,里面還包含了各個版本的更新內容列表。

1.3.3 配置開發環境

瀏覽器: 推薦使用高版本的瀏覽器,谷歌、火狐、360等,對于前端開發者來說,chrome是不二的選擇

js 開發工具: VS-code、Webstorm 都可以,為了方便下面的學習,這里使用Webstorm

Three.js 調試: 利用谷歌瀏覽器的調試窗口,使用斷點調試的方法

2. 開始使用Three.js
使用Three.js之前,首先在部分,需要引入外部文件Three.js

    
WebGL 的渲染是需要HTML5 中的Canvas元素的,你可以手動在HTML的部分中使用canvas標簽,或者讓Three.js幫你生成。這兩種選擇,一般沒有多大差別。我們先手動定義一個canvas標簽:

    
在js里面定義一個函數,將所有執行的代碼放在函數里,在html加載完成后,執行該函數
function init{
    // 所有需要執行的代碼
}

一個典型的Three.js程序,至少應該包括四個部分:渲染器(renderer)場景(scene)相機(camera)以及場景中創建的物體

2.1 渲染器(renderer)
渲染器決定了渲染的結果應該畫在頁面的什么元素上面,并且以怎樣的方式來繪制

渲染器將會和canvas元素進行綁定,如果之前標簽中,定義了id為canvasId的canvas標簽,那么renderer可以這樣寫:

var renderer = new THREE.WebGLRenderer({
    canvas : document.getElementById("canvasId");
});
如果想要Three.js生成Canvas元素的時候,在html中就不需要在定義一個canvas標簽了,直接在javascript代碼中寫道:
var renderer = new THREE.WebGLRenderer();
renderer.setSize = (800,600);
document.body.appendChild(renderer.domElement);

上面的代碼setSize是為canvas元素設置寬高,document.body.appendChild(renderer.domElement)是將渲染器對應的Canvas元素添加到body中。

我們可以使用下面的代碼(用于清除畫面的顏色)將背景色設置為黑色:
renderer.setClearColor(0x000000);
2.2 場景(scene)
在Three.js中添加物體都是添加到場景中的,因此它相當于一個大容器。一般說,場景里沒有很復雜的操作,只要new一個對象就可以了,然后將物體添加到場景中即可。
var scene = new THREE.Scene();
2.3 照相機(camera)
在介紹照相機之前,我們先來介紹一下坐標系。

three.js中使用的是右手坐標系,X軸水平向右,y軸垂直向上,Z軸的方向就是屏幕由里往外的方向

這里我們定義一個透視相機(相機也需要添加到場景中):
var camera = new THREE.PerspectiveCamera(45, 4 / 3, 1, 1000);
// 設置相機的位置
camera.position.set(0,0,5);
// 將相機添加到場景中
scene.add(camera);
2.4 創建一個物體
這里我們先介紹一個長方體,創建一個x、y、z方向長度分別為1、2、3的長方體,并設置為紅色。
var geometry = new THREE.CubeGeometry(1,2,3);
var material = new THREE.MeshBasicMaterial({
    color: 0xff0000;
});
var cube = new THREE.Mesh(geometry,material);
scene.add(cube);

new THREE.CubeGeometry(); 表示調用一個幾何體

Cube : 立方體 Geometry : 幾何;

CubeGeometry是一個正方體或者長方體,究竟是什么,由它的3個參數所決定

CubeGeometry(width, height, depth, segmentsWidth, segmentsHeight, segmentsDepth, materials, sides)
width:立方體x軸的長度

height:立方體y軸的長度

depth:立方體z軸的深度,也就是長度

想一想大家就明白,以上3個參數就能夠確定一個立方體。

剩下的幾個參數就要費解和復雜一些了,不過后面我們會自己來寫一個立方體,到時候,你會更明白這些參數的意義,這里你可以將這些參數省略。

new THREE.MeshBasicMaterial(); 表示的是物體的材質

你可以在里面設置物體的顏色

var material = new THREE.MeshBasicMaterial({
    color: 0xff0000;
});

一定不要忘了,將物體添加到場景

2.5 渲染
在定義了場景中的物體,設置好的照相機之后,渲染器就知道如何渲染出二維的結果了。這時候,我們只需要調用渲染器的渲染函數,就能使其渲染一次了。
renderer.render(scene, camera);
2.6 完整代碼


    
    長方體
    



    


效果圖


canvas元素的默認寬高為300/150

3. Three.js功能概覽
下面介紹下Three.js官網文檔中的一些重要的對象,在你需要尋求幫助時,就能夠知道關鍵詞是什么。

Cameras(照相機,控制投影方式)

Camera

OrthographicCamera

PerspectiveCamera

Core(核心對象)

BufferGeometry

Clock(用來記錄時間)

EventDispatcher

Face3

Face4

Geometry

Object3D

Projector

Raycaster(計算鼠標拾取物體時很有用的對象)

Lights(光照)

Light

AmbientLight

AreaLight

DirectionalLight

HemisphereLight

PointLight

SpotLight

Loaders(加載器,用來加載特定文件)

Loader

BinaryLoader

GeometryLoader

ImageLoader

JSONLoader

LoadingMonitor

SceneLoader

TextureLoader

Materials(材質,控制物體的顏色、紋理等)

Material

LineBasicMaterial

LineDashedMaterial

MeshBasicMaterial

MeshDepthMaterial

MeshFaceMaterial

MeshLambertMaterial

MeshNormalMaterial

MeshPhongMaterial

ParticleBasicMaterial

ParticleCanvasMaterial

ParticleDOMMaterial

ShaderMaterial

SpriteMaterial

Math(和數學相關的對象)

Box2

Box3

Color

Frustum

Math

Matrix3

Matrix4

Plane

Quaternion

Ray

Sphere

Spline

Triangle

Vector2

Vector3

Vector4

Objects(物體)

Bone

Line

LOD

Mesh(網格,最常用的物體)

MorphAnimMesh

Particle

ParticleSystem

Ribbon

SkinnedMesh

Sprite

Renderers(渲染器,可以渲染到不同對象上)

CanvasRenderer

WebGLRenderer(使用WebGL渲染,這是本書中最常用的方式)

WebGLRenderTarget

WebGLRenderTargetCube

WebGLShaders(著色器,在最后一章作介紹)

Renderers / Renderables

RenderableFace3

RenderableFace4

RenderableLine

RenderableObject

RenderableParticle

RenderableVertex

Scenes(場景)

Fog

FogExp2

Scene

Textures(紋理)

CompressedTexture

DataTexture

Texture

Extras

FontUtils

GeometryUtils

ImageUtils

SceneUtils

Extras / Animation

Animation

AnimationHandler

AnimationMorphTarget

KeyFrameAnimation

Extras / Cameras

CombinedCamera

CubeCamera

Extras / Core

Curve

CurvePath

Gyroscope

Path

Shape

Extras / Geometries(幾何形狀)

CircleGeometry

ConvexGeometry

CubeGeometry

CylinderGeometry

ExtrudeGeometry

IcosahedronGeometry

LatheGeometry

OctahedronGeometry

ParametricGeometry

PlaneGeometry

PolyhedronGeometry

ShapeGeometry

SphereGeometry

TetrahedronGeometry

TextGeometry

TorusGeometry

TorusKnotGeometry

TubeGeometry

Extras / Helpers

ArrowHelper

AxisHelper

CameraHelper

DirectionalLightHelper

HemisphereLightHelper

PointLightHelper

SpotLightHelper

Extras / Objects

ImmediateRenderObject

LensFlare

MorphBlendMesh

Extras / Renderers / Plugins

DepthPassPlugin

LensFlarePlugin

ShadowMapPlugin

SpritePlugin

Extras / Shaders

ShaderFlares

ShaderSprite

我們看到,Three.js功能是十分豐富的,一時間想全部掌握有些困難。在接下來的章節中,我們將會先詳細介紹照相機、幾何形狀、材質、物體等入門級知識;然后介紹使用動畫、模型導入、加入光照等功能;最后,對于學有余力的讀者,我們將介紹著色器,用于更高級的圖形渲染。

4. 照相機
本章將介紹照相機的概念,以及如何使用Three.js設置相應的參數。
4.1 什么是照相機?
在圖形學中,照相機可沒有生活中的照相機那么簡單

我們使用的Three.js創建的場景是三維的,而通常情況下顯示器是二維的,那么三維的場景怎么在二維的顯示器上顯示呢?照相機就是一個抽象,它定義了三維空間到二維屏幕投影的方式,用“照相機”這樣一個類比,可以使我們直觀地理解這一投影方式。

而針對投影方式的不同,照相機又分為正交投影照相機透視投影照相機。我們需要為自己的程序選擇合適的照相機。這兩者分別是什么,以及兩者有何差異,我們將在下節中作介紹。

4.2 正交投影和透視投影
舉個簡單的例子來說明正交投影與透視投影照相機的區別。使用透視投影照相機獲得的結果是類似人眼在真實世界中看到的有“近大遠小”的效果(如下圖中的(a));而使用正交投影照相機獲得的結果就像我們在數學幾何學課上老師教我們畫的效果,對于三維空間內平行的線,投影到二維空間中也一定是平行的(如下圖中的(b))。

一般說來,對于制圖、建模軟通常使正交投影,這樣不會因為投影而改變物體比例;而對于其他大多數應用,通常使用 透視投影,因為這更接近人眼的觀察效果。當然,照相機的選擇并沒有對錯之分,你可以更具應用的特性,選擇一個效果更佳的照相機。

4.3 正交投影照相機 4.3.1 參數介紹
正交投影照相機(Orthographic Camera)
THREE.OrthographicCamera(left, right, top, bottom, near, far)
這六個參數分別代表正交投影照相機拍攝到的空間的六個面的位置,這六個面圍成一個長方體,我們稱其視景體(Frustum)。只有在視景體內部(下圖中的灰色部分)的物體才可能顯示在屏幕上,而視景體外的物體會在顯示之前被裁減掉。

為了保持照相機的橫豎比例,需要保證(right - left)與(top - bottom)的比例與Canvas寬度與高度的比例(800/600)一致。
// [2-(-2)] / [1.5-(-1.5)] = canvas.width/canvas.height
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10) // left right top bottom near far

near與far都是指到照相機位置在深度平面的位置,而照相機不應該拍攝到其后方的物體,因此這兩個值應該均為正值。為了保證場景中的物體不會因為太近或太遠而被照相機忽略,一般near的值設置得較小far的值設置得較大,具體值視場景中物體的位置等決定。

4.3.2 示例代碼
下面我們通過一個具體的例子來了解正交投影照相機的設置

基本設置

設置照相機:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.poaition.set(0,0,5);
scene.add(camera);

在原點處創建一個邊長為1的正方體,為了和透視效果做對比,這里我們使用wireframe而不是實心的材質,以便看到正方體后方的邊:

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), 
    new THREE.MeshBasicMaterial({
        color: 0xff0000,
        wireframe: true
    })
);
scene.add(cube);

效果圖:

我們看到正交投影的結果是一個正方形,后面的邊與前面完全重合了,這也就是正交投影與透視投影的區別所在。

長寬比例

這里,我們的Canvas寬度是800px,高度是600px,照相機水平方向距離4,垂直方向距離3,因此長寬比例保持不變。為了試驗長寬比例變化時的效果,我們將照相機水平方向的距離減小為2(right-left = 2):
var camera = new THREE.OrthographicCamera(-1, 1, 1.5, -1.5, 1, 10);

效果圖(此時水平方向的距離就被拉長了):

照相機位置

接下來,我們來看看照相機位置對渲染結果的影響。在之前的例子中,我們將照相機設置在(0, 0, 5)位置,而由于照相機默認是面向z軸負方向放置的,所以能看到在原點處的正方體。現在,如果我們將照相機向右移動1個單位:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
// 向右移動一個單位的位置
camera.position.set(1, 0, 5);

效果圖(物體看上去向左移動了)

其實照相機就好比人的眼睛,當我們身體往右移動的時候,看到的物體就好像向左移了。

正交投影攝像機在設置時,是否需要保證left 和 right 互為相反數呢?

下面,我們將原本的參數(-2, 2, 1.5, -1.5, 1, 10)改為(-1, 1, 1.5, -1.5, 1, 10),即,將視景體設置得更靠右:

var camera = new THREE.OrthographicCamera(-1, 3, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);

效果圖(與之前相機向右的效果是一樣的)

換個角度

到目前為止,我們使用照相機,都是沿著Z軸負方向觀察的,因此看到的都是一個正方形,現在我們嘗試一下仰望這個正方體,改變照相機的位置:
// x軸:4;  y軸:-3;  z軸:5
camera.position.set(4, -3, 5);
照相機默認是沿著z軸的負方向觀察的,因此觀察不到正方體,只看到一片黑。我們可以通過lookAt函數指定它看著原點方向

camera.lookAt(new THREE.Vector3(0, 0, 0));

效果圖:

注意:lookAt函數接收的是一個THREE.Vector3的實例千萬不能寫成camera.lookAt(0,0,0)

4.4 透視投影照相機 4.4.1 參數介紹
透視投影照相機(Perspective Camera)
THREE.PerspectiveCamera(fov, aspect, near, far)
讓我們通過一張透視照相機投影的圖來了解這些參數。

透視圖中,灰色的部分是視景體,是可能被渲染的物體所在的區域。fov是視景體豎直方向上張角(是角度制而非弧度制),如側視圖所示。

aspect等于width / height,是照相機水平方向和豎直方向長度的比值,通常設為Canvas的橫縱比例

near和far分別是照相機到視景體 最近、最遠的距離,均為正值,且far應大于near

4.4.2 示例代碼
下面我們通過一個例子來學習透視投影照相機

基本設置

設置透視投影照相機,這里Canvas長800px,寬600px,所以aspect設為800 / 600

var camera = new THREE.PerspectiveCamera(45, 800 / 600, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

設置一個在原點處的邊長為1的正方體:

var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1),
        new THREE.MeshBasicMaterial({
            color: 0xff0000,
            wireframe: true
        })
);
scene.add(cube);

效果圖:

對比正交透視照相機下正方形的效果,透視投影可以看到全部的12條邊,而且有近大遠小的效果,這也就是與正交投影的區別。

豎直張角

接下來,我們來看下fov的改變對渲染效果的影響。我們將原來的45改為60

var camera = new THREE.PerspectiveCamera(60, 800 / 600, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

效果圖:

為什么正方體顯得更小了呢?我們從下面的側視圖來看,雖然正方體的實際大小并未改變,但是將照相機的豎直張角設置得更大時,視景體變大了,因而正方體相對于整個視景體的大小就變小了,看起來正方形就顯得變小了。

注意,改變fov不會起畫面橫豎比例的變化,而改變aspect改變橫豎比例。

5. 點、線、面 5.1 3D世界的組成
在計算機世界里,3D世界由點組成,兩個點能組成一條直線,三個不在一條直線上的點,就能組成一個三角面,無數的三角面就能組成各種各樣的物體,如下圖:

我們通常把這種網絡模型叫做Mesh模型。給物體貼上皮膚,或者專業點就叫做紋理,那么這個物體就活靈活現了。最后無數的物體就組成了我們的3D世界。

5.2 在Three.js中定義一個點
在三維空間中的某一個點可以用一個坐標點來表示。一個坐標點由x,y,z三個分量構成。在three.js中,點可以在右手坐標系中表示: 

空間幾何中,點可以用一個向量來表示,在Three.js中也是用一個向量來表示的

THREE.Vector3 = function ( x, y, z ) {

this.x = x || 0;
this.y = y || 0;
this.z = z || 0;

};

我們來分析這段代碼:前面我們已經知道了THREE是Three.js引擎的一個全局變量。只要你想用它,就可以在任何地方用它。

那么THREE.Vector3呢,就是表示Vector3是定義在THREE下面的一個。以后要用Vector3,就必須要加THREE前綴。當然Three.js的設計者,也可以不加THREE這個前綴,但是他們預見到,Three.js引擎中會有很多類型,最好給這些類型加一個前綴,以免與開發者的代碼產生沖突。

THREE.Vector3被賦值為一個函數。這個函數有3個參數,分別代表x坐標y坐標z坐標的分量。函數體內的代碼將他們分別賦值給成員變量x,y,z。看看上面的代碼,中間使用了一個“||”(或)運算符,就是當x=null或者undefine時,this.x的值應該取0

5.3 點的操作
在3D世界中可以用THREE.Vector3D來表示。

現在來看看怎么定義個點,假設有一個點x=4,y=8,z=9。你可以這樣定義它:

var point1 = new THREE.Vecotr3(4,8,9);

另外你也可以使用set方法,代碼如下:

var point1 = new THREE.Vector3();

point1.set(4,8,9);
5.4 繪制一條線段
兩個不重合的點能夠決定一條直線。在three.js中,也可以通過定義兩個點,來畫一條直線。

1、首先,聲明一個幾何體geometry

幾何體里面有個vertices變量,可以用來存放點

var geometry = new THREE.Geometry();
// 幾何體里面有個vertices變量,可以用來存放點

2、定義一種線條的材質,使用THREE.LineBasicMaterial類型來定義,它接受一個集合作為參數,其原型如下:

THREE.LineBasicMaterial(parameters);

parameters 是定義材質外觀的對象,它包含多個屬性來定義材質,這些屬性是:

Color 線條的顏色,用16進制表示,默認都是白色

Linewidth 線條的寬度,默認是1個單位寬度

Linecap 線條兩端的外觀,默認是圓角端點,當線條較粗的時候才能看到效果

Linejoin 兩個線條的連接點處的外觀,默認是“round”,表示圓角。

VertexColors 定義線條材質是否使用頂點顏色,這是一個boolean值。意思是,線條各部分的顏色會根據頂點的顏色來進行插值。

Fog 定義材質的顏色是否受全局霧效的影響。

我們這里使用了頂點顏色 vertexColors: THREE.VertexColors,就是線條的顏色會根據頂點來計算。

var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );

注意: 關于線寬的坑,WebGLRender渲染方式是不之持繪制線寬的,要想支持,需要將渲染方式設置為CanvasRenderer

3、接下來,定義兩種顏色,分別表示線條兩個端點的顏色,

var color1 = new THREE.Color( 0x444444 ),
    color2 = new THREE.Color( 0xFF0000 );

4、定義2個頂點的位置,并放到geometry中,代碼如下:

var p1 = new THREE.Vector3(-100,0,100);
var p2 = new THREE.Vector3(100,0,-100);

geometry.vertices.push(p1);
geometry.vertices.push(p2);

5、為4中定義的2個頂點,設置不同的顏色,代碼如下所示:

geometry.colors.push( color1, color2 );

geometry中colors表示頂點的顏色,必須材質中vertexColors等于THREE.VertexColors時,顏色才有效,如果vertexColors等于THREE.NoColors時,顏色就沒有效果了。那么就會去取材質中color的值,這個很重要。

6、定義一條線。

定義線條,使用THREE.Line類,代碼如下所示:

var line = new THREE.Line( geometry, material, THREE.LinePieces );

第一個參數是幾何體geometry,里面包含了2個頂點和頂點的顏色

第二個參數是線條的材質,或者是線條的屬性,表示線條以哪種方式取色。

第三個參數是一組點的連接方式。

7、然后,將這條線加入到場景中,代碼如下:

scene.add(line);

8、整體代碼:





    

    






效果圖:

5.5 線條的深度理解
在Threejs中,一條線由點,材質和顏色組成。

點由THREE.Vector3表示,Threejs中沒有提供多帶帶畫點的函數,它必須被放到一個THREE.Geometry形狀中,這個結構中包含一個數組vertices,這個vertices就是存放無數的點(THREE.Vector3)的數組

1、為了繪制一條直線,首先我們需要定義兩個點

var p1 = new THREE.Vector3( -1, 0, 1 );
var p2 = new THREE.Vector3( 1, 0, -1 );

2、聲明一個THREE.Geometry,并把點加進去

var geometry = new THREE.Geometry();
geometry.vertices.push(p1);
geometry.vertices.push(p2);

geometry.vertices的能夠使用push方法,是因為geometry.vertices是一個數組。這樣geometry中就有了2個點了。

3、然后我們需要給線加一種材質,THREE.LineBasicMaterial

var material = new THREE.LineBasicMaterial();

4、最終我們通過THREE.Line繪制了一條線:

var line = new THREE.Line( geometry, material, THREE.LinePieces );
5.6 繪制網格線
我們要畫一個網格的坐標,那么我們就應該找到線的點。把網格虛擬成正方形,在正方形邊界上找到幾個等分點,用這些點兩兩連接,就能夠畫出整個網格來。

1、定義兩個點

// 在x軸上定義兩個點p1(-500,0,0),p2(500,0,0)。
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ));
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ));

2、算法

這兩個點決定了x軸上的一條線段,將這條線段復制20次,分別平行移動到z軸的不同位置,就能夠形成一組平行的線段。

同理,將p1p2這條線先圍繞y軸旋轉90度,然后再復制20份,平行于z軸移動到不同的位置,也能形成一組平行線。

for ( var i = 0; i <-= 20; i ++ ) {
    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial({ color: 0x000000, opacity: 0.2 }));
    line.position.z = ( i * 50 ) - 500;
    scene.add( line );

    var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ));
    line.position.x = ( i * 50 ) - 500;
    line.rotation.y = 90 * Math.PI / 180;   //  旋轉90度
    scene.add( line );

}

3、完整代碼





    

    






效果圖:

6. 幾何形狀
在創建物體時,需要傳入兩個參數,一個是幾何形狀(Geometry),另一個是材質(Material),這一章將著重介紹幾何形狀的創建,第6章介紹材質,第7章介紹如何使用兩者創建網格。

幾何形狀(Geometry)最主要的功能是儲存了一個物體的頂點信息。WebGL需要程序員指定每個頂點的位置,而在Three.js中,可以通過指定一些特征來創建幾何形狀,例如使用半徑創建一個球體,從而省去程序員一個個指定頂點的工作量。

本章節將分別介紹立方體、平面、球體、圓柱體、四面體、八面體等幾何形狀,以及以三維文字作為幾何形狀的方法。本節還會介紹通過手動定義 頂點位置面片信息組成幾何形狀。

6.1 基本幾何形狀 6.1.1 立方體
雖然這形狀的名字叫做立方體(CubeGeometry),但其實是長方體,也就是長寬高可以設置不同的值:
new THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)

這里,widthx方向上的長度;heighty方向上的長度;depthz方向上的長度;后三個參數分別是在三個方向上的分段數,如widthSegments為3的話,代表x方向上水平分為三份。一般情況下不需要分段的話,可以不設置后三個參數,后三個參數的缺省值為1。其他幾何形狀中的分段也是類似的,下面不做說明。

長寬高

創建立方體直觀簡單,如:new THREE.CubeGeometry(1, 2, 3);可以創建一個x方向長度為1,y方向長度為2,z方向長度為3的立方體。

// 調用渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setSize(800, 600);
document.body.appendChild(renderer.domElement);
renderer.setClearColor(0x000000);

// 調用場景
var scene = new THREE.Scene();

// 調用相機
var camera = new THREE.OrthographicCamera(-5, 5, 3.75, -3.75, 0.1, 100);
camera.position.set(25, 25, 25);
camera.lookAt(new THREE.Vector3(0, 0, 0));
scene.add(camera);

// 新建一個幾何體(長方體)
var cube = new THREE.Mesh(new THREE.CubeGeometry(1, 2, 3), new THREE.MeshBasicMaterial({
    color: 0xffff00,
    wireframe: true
}));

scene.add(cube);

為了更好地表現參數效果,我們在場景中用長度為3紅、綠、藍線段分別表示x、y、z三個軸(這里不需要深究,后面會詳細介紹):

// 封裝一個坐標系函數
function drawAxes(scene) {
    // x-axis
    var xGeo = new THREE.Geometry();
    xGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    xGeo.vertices.push(new THREE.Vector3(3, 0, 0));
    var xMat = new THREE.LineBasicMaterial({
        color: 0xff0000
    });
    var xAxis = new THREE.Line(xGeo, xMat);
    scene.add(xAxis);

    // y-axis
    var yGeo = new THREE.Geometry();
    yGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    yGeo.vertices.push(new THREE.Vector3(0, 3, 0));
    var yMat = new THREE.LineBasicMaterial({
        color: 0x00ff00
    });
    var yAxis = new THREE.Line(yGeo, yMat);
    scene.add(yAxis);

    // z-axis
    var zGeo = new THREE.Geometry();
    zGeo.vertices.push(new THREE.Vector3(0, 0, 0));
    zGeo.vertices.push(new THREE.Vector3(0, 0, 3));
    var zMat = new THREE.LineBasicMaterial({
        color: 0x00ccff
    });
    var zAxis = new THREE.Line(zGeo, zMat);
    scene.add(zAxis);
}

// 在init 函數里調用這個函數 即可在屏幕上顯示一個坐標系了
drawAxes(scene);

在設置材質,并添加到場景之后具體的效果是:

物體的默認位置原點,對于立方體而言,是其幾何中心在原點的位置。

分段

根據THREE.CubeGeometry(width, height, depth, widthSegments, heightSegments, depthSegments),的后三個參數,為這個長方體分段:

// x軸分兩段  y軸分兩段 z軸分三段
new THREE.CubeGeometry(1, 2, 3, 2, 2, 3)

效果圖:

注意這個分段是對六個面進行分段,而不是對立方體的體素分段,因此在立方體的中間是不分段的,只有六個側面被分段。

6.1.2 平面
這里的平面(PlaneGeometry)其實是一個長方形,而并非是數學意義上無限大的平面:
new THREE.PlaneGeometry(width, height, widthSegments, heightSegments)

其中,widthx方向上的長度;heighty方向上的長度;后兩個參數同樣表示分段

new THREE.PlaneGeometry(2, 4);創建的平面在x軸和y軸所在平面內:

var plane = new THREE.Mesh(
    new THREE.PlaneGeometry(2, 4), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(plane);

效果圖:

如果需要創建的平面在x軸和z軸所在的平面內,可以通過物體的旋轉來實現,具體的做法將在下面章節介紹到。

6.1.3 球體
球體(SphereGeometry)的構造函數是:
new THREE.SphereGeometry(radius, segmentsWidth, segmentsHeight, phiStart, phiLength, thetaStart, thetaLength)

其中,radius半徑segmentsWidth表示經度上的切片數segmentsHeight表示緯度上的切片數phiStart表示經度開始的弧度phiLength表示經度跨過的弧度thetaStart表示緯度開始的弧度thetaLength表示緯度跨過的弧度

分段

首先,我們來理解下segmentsWidthsegmentsHeight。使用var sphere = new THREE.SphereGeometry(2, 8, 6)可以創建一個半徑為2經度劃分成8份,緯度劃分成6份的球體

var sphere = new THREE.Mesh(
    new THREE.SphereGeometry(2, 8, 6), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(sphere);

效果圖:

new THREE.SphereGeometry(2, 8, 16)的效果如圖:

new THREE.SphereGeometry(3, 18, 12)的效果如圖:

segmentsWidth相當于經度被切成了幾瓣,而segmentsHeight相當于緯度被切成了幾層。因為在圖形底層的實現中,并沒有曲線的概念,曲線都是由多個折線近似構成的。對于球體而言,當這兩個值較大的時候,形成的多面體就可以近似看做是球體了。

經度弧度

new THREE.SphereGeometry(2, 8, 6, Math.PI / 2, Math.PI / 3)表示起始經度為Math.PI / 6,經度跨度為Math.PI / 3

var sphere = new THREE.Mesh(
    new THREE.SphereGeometry(2, 8, 6, Math.PI / 2, Math.PI / 3), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(sphere);

效果圖:

值得注意的是,這里的SegmentsWidth8意味著對于經度從Math.PI / 2跨過Math.PI / 3區域內劃分為8塊,而不是整個球體的經度劃分成8塊后再判斷在此經度范圍內的部分。

緯度弧度

理解了經度之后,緯度可以同理理解。new THREE.SphereGeometry(2, 8, 6, 0, Math.PI * 2, Math.PI / 6, Math.PI / 3)意味著緯度從Math.PI / 6跨過Math.PI / 3

var sphere = new THREE.Mesh(
    // 經度起始弧度為0度,經度跨度為 180*2
    new THREE.SphereGeometry(2, 8, 6, 0, Math.PI * 2, Math.PI / 6, Math.PI / 3), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(sphere);

效果圖:

我們再來看一個經度緯度都改變了起始位置和跨度的例子:new THREE.SphereGeometry(2, 8, 6, Math.PI / 2, Math.PI, Math.PI / 6, Math.PI / 2)

var sphere = new THREE.Mesh(
    new THREE.SphereGeometry(2, 8, 6, Math.PI / 2, Math.PI, Math.PI / 6, Math.PI / 2), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(sphere);

效果圖:

6.1.4 圓形
圓形(CircleGeometry)可以創建圓形或者扇形,其構造函數是:
new THREE.CircleGeometry(radius, segments, thetaStart, thetaLength)

這里的參數跟繪制圓是一樣的,我們再來熟悉一下。radius是半徑;segments表示切片數;thetaStart表示緯度開始的弧度thetaLength表示緯度跨過的弧度

看個例子: new THREE.CircleGeometry(3, 18, Math.PI / 3, Math.PI / 3 * 4)可以創建一個在x軸和y軸所在平面的三分之二圓的扇形:

var circle = new THREE.Mesh(
    new THREE.CircleGeometry(2, 18, Math.PI / 3, Math.PI / 3 * 4), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(circle);

效果圖:

6.1.5 圓柱體
圓柱體(CylinderGeometry)的構造函數是:
new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded)

其中,radiusTopradiusBottom分別是頂面和底面的半徑,由此可知,當這兩個參數設置為不同的值時,實際上創建的是一個圓臺;height是圓柱體的高度radiusSegmentsheightSegments可類比球體中的分段,一個表示底面、頂面的分段,另一個表示環面的分段;openEnded是一個布爾值,表示是否沒有頂面和底面,缺省值為false,表示有頂面和底面。

標準圓柱體

new THREE.CylinderGeometry(1.5, 1.5, 3, 18, 3)創建一個頂面與底面半徑都為2,高度為4的圓柱體:

var cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry(1.5, 1.5, 3, 18, 3), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(cylinder);

效果圖:

圓臺

頂面、底面半徑不一致的時候,即是一個圓臺。將底面半徑設為2創建一個圓臺:new THREE.CylinderGeometry(1.5, 2, 3, 18, 3)

var cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry(1.5, 2, 3, 18, 3), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(cylinder);

效果圖:

無底面、頂面

openEndedtrue的時候,將無底面、頂面。new THREE.CylinderGeometry(1.5, 1.5, 3, 18, 3, true)將創建一個沒有頂面與底面的圓柱:

var cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry(1.5, 1.5, 3, 18, 3, true), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(cylinder);

效果圖:

6.1.6 正四面體、正八面體、正二十面體
正四面體(TetrahedronGeometry)、正八面體(OctahedronGeometry)、正二十面體(IcosahedronGeometry)的構造函數較為類似,分別為:
// 正四面體
new THREE.TetrahedronGeometry(radius, detail)
// 正八面體
new THREE.OctahedronGeometry(radius, detail)
// 正二十面體
new THREE.IcosahedronGeometry(radius, detail)

其中,radius是半徑;detail是細節層次(Level of Detail)的層數,對于大面片數模型,可以控制在視角靠近物體時,顯示面片數多的精細模型,而在離物體較遠時,顯示面片數較少的粗略模型。這里我們不對detail多作展開,一般可以對這個值缺省。

正四面體

new THREE.TetrahedronGeometry(2.5)創建一個半徑2.5的正四面體:

var tetrahedron = new THREE.Mesh(
    new THREE.TetrahedronGeometry(2.5), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(tetrahedron);

效果圖:

正八面體

new THREE.OctahedronGeometry(2.5)創建一個半徑為2.5的正八面體:

var octahedron = new THREE.Mesh(
    new THREE.OctahedronGeometry(2.5), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(octahedron);

效果圖:

正二十面體

new THREE.IcosahedronGeometry(2.5)創建一個半徑為2.5的正二十面體:

var icosahedron = new THREE.Mesh(
    new THREE.IcosahedronGeometry(2.5), 
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(icosahedron);

效果圖:

6.1.7 圓環面
圓環面(TorusGeometry)就是甜甜圈的形狀,其構造函數是:
new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments, arc)

其中,radius是圓環半徑;tube是管道半徑;radialSegmentstubularSegments分別是兩個分段數,詳見上圖;arc是圓環面的弧度,缺省值為Math.PI * 2

粗糙圓環面

new THREE.TorusGeometry(2, 0.7, 4, 8)創建一個粗糙的圓環面:

var torus = new THREE.Mesh(
    new THREE.TorusGeometry(2, 0.7, 4, 8),
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(torus);

效果圖:

精細圓環面

new THREE.TorusGeometry(2, 0.7, 12, 18)創建一個較為精細的圓環面:

var torus = new THREE.Mesh(
    new THREE.TorusGeometry(2, 0.7, 12, 18),
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(torus);

效果圖:

部分圓環面

new THREE.TorusGeometry(2, 0.7, 4, 8, Math.PI / 3 * 2)創建部分圓環面:

var torus = new THREE.Mesh(
    new THREE.TorusGeometry(2, 0.7, 4, 8, Math.PI / 3 * 2),
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(torus);

效果圖:

6.1.8 圓環結
如果說圓環面是甜甜圈,那么圓環結(TorusKnotGeometry)就是打了結的甜甜圈,其構造參數為:
new THREE.TorusKnotGeometry(radius, tube, radialSegments, tubularSegments, p, q, heightScale)

前四個參數在圓環面中已經有所介紹,pq是控制其樣式的參數,一般可以缺省,如果需要詳細了解,請學習圓環結的相關知識;heightScale是在z軸方向上的縮放。

new THREE.TorusKnotGeometry(2, 0.5, 32, 8) 默認樣式的圓環結:

var torus = new THREE.Mesh(
    new THREE.TorusKnotGeometry(1.6, 0.4, 32, 8),
    new THREE.MeshBasicMaterial({
        color: 0xffff00,
        wireframe: true
    })
);
scene.add(torus);

效果圖:

6.2 文字形狀
文字形狀(TextGeometry)可以用來創建三維的文字形狀。
6.2.1 下載使用
使用文字前,需要下載和引用額外的字體庫。字體庫在three.js Github master/examples/fonts目錄下,下載里面的json文件,放在你的目錄下,然后加載。

這里,我們就以helvetiker字體為例。我們在剛剛的字體庫目錄下,下載helvetiker_regular.typeface.json文件放在你的目錄下,然后用以下方法加載:

// 調用一個字體加載函數
var loader = new THREE.FontLoader();
loader.load("helvetiker_regular.typeface.json", function(font) {
    var mesh = new THREE.Mesh(
        new THREE.TextGeometry("Hello", {
            font: font,
            size: 1,
            height: 1
        }), 
        new THREE.MeshBasicMaterial({
            color: 0xffff00,
            wireframe: true
        })
    );
    scene.add(mesh);
    // 寫在loader函數里面 否則不顯示
    renderer.render(scene,camera);
});

注意:

之前用的73dev版本的three.js,執行代碼的時候發現報錯,可能是還沒有添加這個功能,所以建議去下載最新版本的three.js。

json配置文件,需要在本地服務器打開,推薦使用webstorm編輯器,因為它打開html文件時,就是以本地服務器的方式打開的。或者在cmd命令行中輸入live-server,但需要配置,具體方法請點這里。

6.2.2 參數介紹
創建文字形狀的流程和之前介紹的基本幾何形狀是類似的,其構造函數是:
new THREE.TextGeometry(text, parameters)

其中,text是要顯示的文字字符串,parameters是以下參數組成的對象:

size:字號大小,一般為大寫字母的高度

height:文字的厚度

curveSegments:弧線分段數,使得文字的曲線更加光滑

font:字體,默認是"helvetiker",需對應引用的字體文件

weight:值為"normal""bold",表示是否加粗

style:值為"normal""italics",表示是否斜體

bevelEnabled:布爾值,是否使用倒角,意為在邊緣處斜切

bevelThickness:倒角厚度

bevelSize:倒角寬度

6.2.3 示例代碼
創建一個三維文字new THREE.TextGeometry("hello", {size: 1, height: 1})




    
    hello
    



    

效果圖:

我們可以改變材質和添加光照來改變顯示效果(燈光、材質不必深究,后面會細講)

// 將材質改為lambert材質
var material = new THREE.MeshLambertMaterial({
    color: 0xffff00
});

// 加上一束方向光
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 0, 0.5);
scene.add(light);

效果圖:

這里只是給大家看了一個效果,具體材質、燈光的原理不要去深究,直接跳過,看下面的知識點。

6.3 自定義形狀
對于Three.js沒有提供的形狀,可以通過自定義形狀來創建。

由于自定義形狀需要手動指定每個頂點位置,以及頂點連接情況,如果該形狀非常復雜,程序員計算量就會比較大。這種情況,建議使用建模工具,創建好之后,再通過three.js導入到場景中,這樣會十分高效、方便。

自定義形狀使用的是Geometry類,它是其他如CubeGeometry、SphereGeometry等幾何形狀的父類,其構造函數是:

new THREE.Geometry()

我們以創建一個梯臺為例,首先,初始化一個幾何形狀,然后設置頂點位置以及頂點連接情況。

頂面創建4個點,底面創建4個點,按照順時針的順序逐個創建

geometry創建點的時候都是push到數組vertices里面的

所以這8個點,按照順序都有一個對應的索引值

利用Face3的方法將3點連成一個三角面

看代碼

// 初始化幾何形狀
var geometry = new THREE.Geometry();

// 設置頂點的位置 
// 頂部4個點
geometry.vertices.push(new THREE.Vector3(-1, 2, -1));
geometry.vertices.push(new THREE.Vector3(1, 2, -1));
geometry.vertices.push(new THREE.Vector3(1, 2, 1));
geometry.vertices.push(new THREE.Vector3(-1, 2, 1));
// 底部4頂點
geometry.vertices.push(new THREE.Vector3(-2, 0, -2));
geometry.vertices.push(new THREE.Vector3(2, 0, -2));
geometry.vertices.push(new THREE.Vector3(2, 0, 2));
geometry.vertices.push(new THREE.Vector3(-2, 0, 2));

// 設置頂點連接情況
// 頂面
geometry.faces.push(new THREE.Face3(0, 1, 3));
geometry.faces.push(new THREE.Face3(1, 2, 3));
// 底面
geometry.faces.push(new THREE.Face3(4, 5, 6));
geometry.faces.push(new THREE.Face3(5, 6, 7));
// 四個側面
geometry.faces.push(new THREE.Face3(1, 5, 6));
geometry.faces.push(new THREE.Face3(6, 2, 1));
geometry.faces.push(new THREE.Face3(2, 6, 7));
geometry.faces.push(new THREE.Face3(7, 3, 2));
geometry.faces.push(new THREE.Face3(3, 7, 0));
geometry.faces.push(new THREE.Face3(7, 4, 0));
geometry.faces.push(new THREE.Face3(0, 4, 5));
geometry.faces.push(new THREE.Face3(0, 5, 1));

效果圖:

總結:

需要注意的是,new THREE.Vector3(-1, 2, -1)創建一個矢量,作為頂點位置追加到geometry.vertices數組中。

而由new THREE.Face3(0, 1, 3)創建一個三個頂點組成的面片,追加到geometry.faces數組中。三個參數分別是四個頂點在geometry.vertices中的序號。

7. 材質
材質(material),是獨立于物體頂點信息之外的與渲染效果相關的屬性。通過設置材質可以改變物體顏色、紋理貼圖、光照模式等。

下面將會為大家介紹基本材質兩種基于光照模型材質法向量作為材質圖像作為材質

7.1 基本材質
使用基本材質(BasicMaterial)的物體,渲染后物體的顏色,始終為該材質的顏色,不會由于光照產生明暗、陰影效果。如果沒有指定材質的顏色,則顏色是隨機的,構造函數如下:
new THREE.MeshBasicMaterial(opt)

其中參數opt可以缺省,或者為包含各屬性的值。如,為一個黃色正方體添加一個1不透明度 (opacity)

new THREE.MeshBasicMaterial({
    color: 0xffff00,
    opacity: 0.75
});

示例代碼:





    
    基本材質
    



                    
閱讀需要支付1元查看
<