three.js初探,立體幾何入手(一)


 

前言:首先先推薦一篇博客,關於webgl原理,講的非常之通俗易懂了 圖解WebGL&Three.js工作原理  webGL可以理解為openGL ES2.0

(webGL2.0 - openGL ES3.0)的javascript綁定。所以實現的語言是javascript和opengl(最常用的跨平台圖形庫)着色語言,webgl是

HTML5中提出的新技術,是一種3D繪圖標准。

three.js是以webgl為基礎的庫,封裝了一些3D渲染需求中重要的工具方法與渲染循環。WebGL門檻相對較高,Three.js對WebGL提供的接

口進行了非常好的封裝,簡化了很多細節,大大降低了學習成本

我們可能還聽說過一個D3.js(Data-Driven Documents),是一個數據可視化的庫,技術基礎是SVG。兼容性是IE9+,官網(http://d3js.org),

從官網的example中可以看出,它跟3d視圖還是不同的。

我們只需要從官網上下載一個three.js,然后用script標簽引入即可。

首先注意的一點是,我們在頁面上並不需要一個canvas標簽,只需要一個盛放canvas的容器就行,canvas是three.js動態生成的。

<!DOCTYPE html>
<html>
<head>
    <title>01.01 - WebGLRenderer - Skeleton</title>
    <script src="../libs/three.js"></script>
    <style>

        #canvas3d{
            width:800px;
            height:450px;
            margin:100px auto;
        }
    </style>
</head>
<body>
    <div id="canvas3d"></div>
</body>
</html>

  threejs里最重要的幾個元素,如下:

<script>
    var renderer;   //渲染器
    var scene;   //場景
    var camera;    //相機
    var light;    //光源
    var cube;      //物體
</script>

 1,生成3d渲染器,設置渲染器的寬高和背景色,(通常我們可以直接獲取頁面上畫布的寬高,便於嵌入改動)

renderer = new THREE.WebGLRenderer({antialias:true}); //生成渲染器對象(antialias屬性:抗鋸齒效果為設置有效)
renderer.setClearColor(0x333333, 1.0); 
//renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize('800', '450');

2,設置一個場景,也就是一個三維空間,用 [Scene] 類聲明一個叫 [scene] 的對象。

scene = new THREE.Scene();

3,設置一個攝像機camera,

OpenGL(WebGL)中、三維空間中的物體投影到二維空間的方式中,存在透視投影和正投影兩種相機。 透視投影就是、從視點開始越近的物體越大、遠處的物體繪制的較小的一種方式、和日常生活中我們看物體的方式是一致的。 正投影就是不管物體和視點距離,都按照統一的大小進行繪制、在建築和設計等領域需要從各個角度來繪制物體,因此這種投影被廣泛應用。在 Three.js 也能夠指定透視投影和正投影兩種方式的相機。

正交投影與透視投影的區別如上圖所示,左圖是正交投影,物體發出的光平行地投射到屏幕上,遠近的方塊都是一樣大的;右圖是透視投影,近大遠小,符合我們平時看東西的感覺。 

camera坐標系

Three中使用采用常見的右手坐標系定位。

// 四個參數分別代表了攝像機的視角、寬高比、近和遠兩個視截面。
//設置透視投影的相機,默認情況下相機的上方向為Y軸,右方向為X軸,沿着Z軸朝里(視野角:fov 縱橫比:aspect 相機離視體積最近的距離:near 相機離視體積最遠的距離:far)
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000);
// position and point the camera to the center of the scene
camera.position.x = 20;
camera.position.y = 18;
camera.position.z = 35;
camera.lookAt(scene.position); //設置視野的中心坐標

4,設置光源light

OpenGL(WebGL)的三維空間中,存在點光源和聚光燈兩種類型。 而且,作為點光源的一種特例還存在平行光源(無線遠光源)。另外,作為光源的參數還可以進行 [環境光] 等設置。 作為對應, Three.js中可以設置 [點光源(Point Light)] [聚光燈(Spot Light)] [平行光源(Direction Light)],和 [環境光(Ambient Light)]。 和OpenGL一樣、在一個場景中可以設置多個光源。 基本上,都是環境光和其他幾種光源進行組合。 如果不設置環境光,那么光線照射不到的面會變得過於黑暗.

//設置light
light = new THREE.DirectionalLight(0xff0000, 1.0, 0);  //設置平行光
light.position.set( 200, 200, 200 );    //設置光源向量
scene.add(light);  // 追加光源到場景

5,設置物體 object

在three.js中,我們使用Mesh模型,Mesh的構造函數是這樣的:Mesh( geometry, material ) geometry是它的形狀,material是它的材質。 三維模型通常用三角形的網格來描述

對於圖中的兔子,隨着三角形數量的增加,它的表面越來越平滑/准確

我們這里是一個立方體 cube

var cubeGeometry = new THREE.BoxGeometry(20, 10, 15,2,3,1); //設置長寬高 以及對應長寬高的分段,在使用線模式({wireframe:true})進行渲染的時候可以看到效果
var cubeMaterial = new THREE.MeshNormalMaterial({wireframe : true});  //材質
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
var border = new THREE.EdgesHelper( cube,0xffff00 );  //添加邊框
scene.add(cube);
scene.add(border);

6,最后一步,進行渲染

//將渲染器的元素添加到頁面中
document.getElementById('canvas3d').appendChild(renderer.domElement);
renderer.render(scene, camera);

完整的代碼已經上傳到github上: github(three-one)  如果你覺得我寫的對你有所幫助的話,請給我個star吧,謝謝

 最后的效果圖如下:


在上面的學習基礎上,我們繼續深入的探究一下,如何給3d視圖添加動畫,紋理等;

1,首先我們在上面的基礎上,添加多個立體幾何圖形

//立方體
var cubeGeometry = new THREE.BoxGeometry(15,15,15,1,1,1);
var cubeMaterial = new THREE.MeshNormalMaterial({wireframe : true});  //材質

cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
var border = new THREE.EdgesHelper( cube,0xffff00 );  //添加邊框
scene.add(cube);
scene.add(border);

//圓柱體
var cylinderGeometry = new THREE.CylinderGeometry(8, 8,10,30,30);
var cylinderMaterial = new THREE.MeshNormalMaterial();
var cylinder = new THREE.Mesh(cylinderGeometry,cylinderMaterial);
cylinder.position.x = -10;
cylinder.position.y = -5;
cylinder.position.z = 25;
cylinder.castShadow = true;
scene.add(cylinder);

//球體
var sphereGeometry = new THREE.SphereGeometry(7, 25, 25);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

// position the sphere
sphere.position.x = 0;
sphere.position.y = 0;
sphere.position.z = 0;
sphere.castShadow = true;

// add the sphere to the scene
scene.add(sphere);

//圓環
var torusGeometry = new THREE.TorusGeometry(10,3,20,20);
var torusMaterial = new THREE.MeshBasicMaterial();
var tours = new THREE.Mesh(torusGeometry,torusMaterial);
tours.position.x = 10;
tours.position.y = -10;
tours.position.z = -40;
tours.castShadow = true;

scene.add(tours);我們通過position屬性 

調整立體幾何在scene中的位置(x,y,z)

創建幾何體時有一點強調的是,對於參數的設置,例如創建圓環的時候,

THREE.TorusGeometry(10,3,20,20)
我們第三四個參數分割比的值越大,立體幾何中拼湊的平面圖形就越多,立體幾何就越圓滑,就是上一篇博客中兔子的那個原理。

2,添加動畫

我們要針對每個幾何體添加不同的動畫,所以就需要為每個幾何體添加一個name屬性來指定,比如:

cube.name = 'cube';

cylinder.name = 'cylinder';

然后在render函數中,用getObjectByName獲取到對應的幾何體,用setInterval的思想原理,通過requestAnimationFrame函數使得幾何體動起來

scene.getObjectByName('cube').rotation.x += control.rotationSpeed;
scene.getObjectByName('cube').scale.set(control.scale, control.scale, control.scale);

scene.getObjectByName('cylinder').rotation.z += control.rotationSpeed2;

scene.getObjectByName('tours').rotation.z += 0.05;
requestAnimationFrame(render);

  

3,stats性能插件

stats.js用於對JavaScript進行性能檢測。

我們創建一個createStats的函數,然后在init初始化中調用它

function createStats() {
    var stats = new Stats();
    stats.setMode(0);

    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '5px';

    return stats;
}

需要特別注意的一點是,我們需要在render函數中不斷的更新stats顯示

stats.update(); 

dat.gui.js用於創建菜單欄,可以用來控制場景中的各個參數來調試場景。

function addControls(controlObject){
        var gui = new dat.GUI();
        gui.add(controlObject,'rotationSpeed',-0.1,0.1);
        gui.add(controlObject, 'scale', 0.01, 2);

        gui.add(controlObject, 'rotationSpeed2', -0.1, 0.1);
} 

創建addControls函數,然后在init初始化函數中設置默認值,並調用這個函數

control = new function (){
    this.rotationSpeed = 0.005;
    this.scale = 1;

    this.rotationSpeed2 = 0.05;
}
addControls(control);

4,添加紋理

這個首先注意的就是圖片應該是異步獲取的,所以你可以放在本地的apache中,也可以自己用nodejs非常方便的搭建一個服務器,不然的話,他就會報錯,跨域了。

var texture = new THREE.ImageUtils.loadTexture("http://10.1.26.29:84/Brick-2399.jpg");
torusMaterial.map = texture;

最后的效果圖如下:

 

完整的代碼:github(threejs-two)  如果你覺得我寫的對你有幫助的話,請給我個star吧,謝謝,我會繼續更新下去的

 


 

5,最后,從完整的代碼中,我們可以看出,關於材質,我們也是調用了不同的函數,這里總結一下材質

材質種類: 
MeshBasicMaterial:為幾何體賦予一種簡單的顏色,或者顯示幾何體的線框 
MeshDepthMaterial:根據網格到相機的距離,該材質決定如何給網格染色 
MeshNormalMaterial:根據物體表面的法向量計算顏色 
MeshFaceMaterial:這是一種容器,可以在該容器中為物體的各個表面上設置不同的顏色 
MeshLambertMaterial:考慮光照的影響,可以創建顏色暗淡,不光亮的物體 
MeshPhongMaterial:考慮光照的影響,可以創建光亮的物體 
ShaderMaterial:使用自定義的着色器程序,直接控制頂點的放置方式,以及像素的着色方式。 
LineBasicMaterial:可以用於THREE.Line幾何體,從而創建着色的直線 
LineDashedMaterial:類似與基礎材質,但可以創建虛線效果

(1)MeshBasicMaterial:不考慮光照的影響。

屬性:

color 
wireframe 
wireframeLinewidth 
wireframeLinecap:線段端點如何顯示。可選值有:butt(平)、round、square。默認是round。WebGLRenderer對象不支持該屬性。 
wireframeLinejoin:線段連接點如何顯示。可選值有:round、bevel(斜角)、miter(尖角)。默認是round。WebGLRenderer對象不支持屬性。 
shading:着色模式。可選值:THREE.SmoothShading、THREE.FlatShading。 
vertexColors:為每個頂點定義不同的顏色。在CanvasRenderer對象中不起作用。 
fog:指示當前是否會受全局霧化效果設置的影響。

兩種設置屬性的方式: 

//1.構造函數
var meshMaterial = new THREE.MeshBasicMaterial({color:0xffccff});
//2屬性
meshMaterial.visible = false;

(2)MeshDepthMaterial

使用這種材質的物體,其外觀不是由光照或某個材質屬性決定的;而是由物體到相機的距離決定的。可以將這種材質與其他材質相結合,從而很容易創建逐漸消失的效果。

只有兩個控制線框的屬性: 
wireframe 
wireframeLinewidth

可以通過設置相機的near和far的值,來控制創建中使用這種材質的物體的消失速度。如果near和fat之間的差值越大,那么物體遠離相機時,只會稍微消失一點;反之,物體消失的效果非常明顯。

var cubeMaterial = new THREE.MeshDepthMaterial();
var colorMaterial = new THREE.MeshBasicMaterial({color:0x00ff00,transparent:true,blending:THREE.MultiplyBlending});

var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry,[colorMaterial,cubeMaterial]);

cube.children[1].scale.set(0.99,0.99,0.99);//避免渲染遮擋而造成的閃爍

(3)MeshNormalMaterial

法向量的作用: 決定光的發射方向、在計算光照、陰影時提供信息、為物體表面上色。法向量所指的方向決定每個面從MeshNormalMaterial材質獲取的顏色。

屬性: 
wireframe 
wireframeLinewidth 
shading

for(var f = 0 , f1 = sphere.geometry.faces.length; f < f1 ; f++){
    var face = spere.geometry.faces[f];
    var arrow = new THREE.ArrowHelper(face.normal,face.centroid,2,0x3333ff);
    spere.add(arrow);
}

  在球體的每個面上添加了一個長度為2,顏色為0x3333ff的箭頭

(4)MeshFaceMaterial

可以為幾何體的每一個面指定不同的材質。

假設有一個正方體,可以為每個面指定不同的顏色。

var matArray = [];
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));

var faceMaterial = new THREE.MeshFaceMaterial(matArray);

var cubeGeometry = new THREE.CubeGeometry(3,3,3);
var cube = new THREE.Mesh(cubeGeometry,faceMaterial);

(5)MeshLambertMaterial

對光源有反應。

基本屬性: 
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。

獨特屬性:

ambient:和AmbientLight光源一起使用。該顏色會與AmbientLight光源的顏色相乘。默認是白色。 
emissive:該材質發射的屬性。不像是光源,只是一種純粹的、不受其他光照影響的顏色。默認是黑色。

(6)MeshPhongMaterial

基本屬性: 
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。

獨特屬性:

ambient 
emissive 
specular:指定該材質的光亮程度及其高光部分的顏色。如果將他設置成跟color屬性相同的顏色,將會得到一種更加類似金屬的材質。如果設置為灰色,材質將變得更像塑料。 
shininess:指定高光部分的亮度。默認是30.

(7)ShaderMaterial 

屬性: 
wireframe 
wireframeLinewidth 
shading 
vertexColor 
fog:指示當前是否會受全局霧化效果設置的影響。

獨特屬性:

fragmentShader:定義每個傳入的像素的顏色。 
vertexShader:允許你修改每一個傳入的頂點的位置 
uniforms:該屬性可以向你的着色器發送消息。將同樣的信息發送到每一個頂點和片段。 
defines:該屬性可以轉換為vertexShader和fragmentShader里的#define代碼。該屬性可以用來設置着色器程序里的一些全局變量。 
attributes:該屬性可以修改每個頂點和片段。常用來傳遞位置數據和法向量相關的數據。如果要用這個屬性,辣么你要為幾何體中的所有頂點提供信息。 
lights:定義光照數據是否傳遞給着色器。默認是false。

獨特屬性:

fragmentShader:定義每個傳入的像素的顏色。 
vertexShader:允許你修改每一個傳入的頂點的位置 
uniforms:該屬性可以向你的着色器發送消息。將同樣的信息發送到每一個頂點和片段。 
defines:該屬性可以轉換為vertexShader和fragmentShader里的#define代碼。該屬性可以用來設置着色器程序里的一些全局變量。 
attributes:該屬性可以修改每個頂點和片段。常用來傳遞位置數據和法向量相關的數據。如果要用這個屬性,辣么你要為幾何體中的所有頂點提供信息。 
lights:定義光照數據是否傳遞給着色器。默認是false。

(8)LineBasicMaterial

基本屬性:

color 
lineWidth 
LineCap:butt、round、square。默認是round。WebGLRenderer不支持該屬性。 
LineJoin:round、bevel(斜切)、miter(尖角)。默認是round。WebGLRenderer不支持該屬性。 
vertexColors:該屬性值設置為 THREE.VertexColors值時,就可以為每個頂點指定一種顏色。 
fog:指定當前物體是否受全局霧化效果的影響。

(9)LineDashedMaterial

和LineBasicMaterial有着一樣的屬性,但是有幾個額外的屬性,可以用來定義短划線長度和短划線中間空格長度的屬性。

獨特屬性: 
scale:縮放dashSize和gapSize。如果scale<1,則dashSize和gapSize就會增大。 
dashSize:短線划的長度 
gapSize:間隔的長度

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM