threejs 三面体_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動態生成的。
01.01 - WebGLRenderer - Skeleton#canvas3d{
width:800px;
height:450px;
margin:100px auto;
}
threejs里最重要的幾個元素,如下:
var renderer; //渲染器
var scene; //場景
var camera; //相機
var light; //光源
var cube; //物體
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:間隔的長度
總結
以上是生活随笔為你收集整理的threejs 三面体_three.js初探,立体几何入手(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英雄联盟LOL虚拟机 版本更新出现 游戏
- 下一篇: vue实现分页的两种方式