three.js是JavaScript編寫(xiě)的WebGL第三方庫(kù)誊辉。提供了非常多的3D顯示功能。Three.js 是一款運(yùn)行在瀏覽器中的 3D 引擎邀跃,你可以用它創(chuàng)建各種三維場(chǎng)景蛙紫,包括了攝影機(jī)坑傅、光影、材質(zhì)等各種對(duì)象蒜茴。
下載地址 : http://threejs.org/
首先創(chuàng)建一個(gè) HTML 文件 , 引入 three.js 引擎包
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Three.js實(shí)現(xiàn)3D空間粒子效果</title>
<style type="text/css">
body {
background-color: #000000;
margin: 0px;
overflow: hidden;
}
</style>
<script src="scripts/three.js"></script>
</head>
<body>
</body>
</html>
變量
定義全局變量:
// the main three.js components
var camera, scene, renderer,
// to keep track of the mouse position
mouseX = 0, mouseY = 0,
// an array to store our particles in
particles = [];
// let's get going!
init();
初始化three.js
為了使用three.js粉私,我們需要在init()函數(shù)中設(shè)置三個(gè)主要的對(duì)象:
1.scene(場(chǎng)景): 場(chǎng)景中包含了所有的3D對(duì)象數(shù)據(jù)
2.camera(相機(jī)): 相機(jī)有位置(position),旋轉(zhuǎn)(rotation)和視野屬性(field of view)
3.renderer(渲染器): 決定場(chǎng)景中的一個(gè)物體在照相機(jī)的視角看來(lái)是什么樣子
function init() {
// 照相機(jī)參數(shù)
camera = new THREE.PerspectiveCamera(80, window.innerWidth/window.innerHeight, 1, 4000);
// 將相機(jī)向后(即屏幕外)移
camera.position.z = 1000;
Camera構(gòu)造器的第一個(gè)參數(shù)是視野(field of view)毡鉴。這是一個(gè)角度,越大憎瘸,則表示虛擬的相機(jī)鏡片越寬幌甘。
第二個(gè)參數(shù)是輸出的寬和高之比痊项。這個(gè)值必須與CanvasRenderer相一致鞍泉。
相機(jī)只能看見(jiàn)一定范圍之內(nèi)的物體,這個(gè)范圍是由near和far來(lái)確定的边器,在這里分別為1和4000托修。因而任何比1近的物體或者比4000遠(yuǎn)的物體是不會(huì)被渲染的睦刃。
在默認(rèn)情況下相機(jī)位于3D世界的起始位置(origin)0,0,0(我的上一篇博客用CSS3繪制一個(gè)旋轉(zhuǎn)的立方體中有關(guān)于origin的介紹)。但是你創(chuàng)建的3D物體也會(huì)放置在這一點(diǎn)际长,因而默認(rèn)值用處并不大工育。我們需要將相機(jī)向后移動(dòng)一點(diǎn)郁轻,即給其一個(gè)正的z值(由屏幕內(nèi)指向外側(cè))好唯。在這里將其移動(dòng)1000。
場(chǎng)景(Scene)
// the scene contains all the 3D object data
scene = new THREE.Scene();
scene.add(camera);
注意必須將相機(jī)加入到場(chǎng)景中蜕提。
渲染器(Renderer)
// 加入CanvasRenderer靶端,由渲染器決定場(chǎng)景中的物體看起來(lái)如何凛膏,并將其畫(huà)出
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
// 將渲染器的canvas domElement加入到body中
document.body.appendChild(renderer.domElement);
這里的CanvasRenderer創(chuàng)建了它自己的DOM元素猖毫,這是一個(gè)普通的2D canvas對(duì)象须喂,我們需要把它加入到文件的body部分才能看見(jiàn)它坞生。我們想讓它充滿(mǎn)整個(gè)瀏覽器窗口,所以將它的大小設(shè)置為window.innerWidth和window.innerHeight又兵。
渲染循環(huán)
接下來(lái)我們需要做的是產(chǎn)生粒子沛厨,加入鼠標(biāo)移動(dòng)監(jiān)聽(tīng)器(mousemove listener)來(lái)追蹤鼠標(biāo)位置升熊,最后設(shè)定間隔每秒調(diào)用update
函數(shù)30次级野。
makeParticles();
// add the mouse move listener
document.addEventListener('mousemove', onMouseMove, false);
// 每秒渲染30次
setInterval(update, 1000/30);
創(chuàng)建材質(zhì)和粒子
在for循環(huán)中zpos以20為步長(zhǎng)從-1000增加至1000蓖柔。
在循環(huán)中风纠,我們創(chuàng)建一個(gè)新的材質(zhì)(material)然后新建一個(gè)粒子。粒子有一個(gè)position屬性镐捧,它有x, y, z三個(gè)值懂酱。
我們給每一個(gè)粒子一個(gè)隨機(jī)的x和y位置誊抛,將它的z位置設(shè)置為zpos拗窃。
接著將粒子加入到particles數(shù)組中,保證能夠跟蹤所有的粒子并在update循環(huán)中對(duì)它們進(jìn)行操作九默。
function makeParticles() {
var particle, material;
// 將z坐標(biāo)從-1000(最遠(yuǎn)處)逐步增加至1000(相機(jī)所在處)
// 每一個(gè)位置加入一個(gè)隨機(jī)的粒子
for (var zpos = -1000; zpos < 1000; zpos += 20) {
// 創(chuàng)建一個(gè)粒子材質(zhì)驼修,向其傳入顏色及我們定義的粒子渲染函數(shù)
material = new THREE.ParticleCanvasMaterial( {
// color: 0xffffff,
color: getRandomColor(),
program: particleRender
});
// 創(chuàng)建粒子
particle = new THREE.Particle(material);
// 賦給它一個(gè)位于-500至500之間的隨機(jī)x和y值
particle.position.x = Math.random() * 1000 - 500;
particle.position.y = Math.random() * 1000 - 500;
particle.position.z = zpos;
// 將其放大一點(diǎn)
particle.scale.x = particle.scale.y = 10;
// 把它加入到場(chǎng)景中
scene.add(particle);
// 將粒子加入到我們的particles數(shù)組中
particles.push(particle);
}
}
update函數(shù)
function update() {
updateParticles();
renderer.render( scene, camera );
}
onMouseMouse函數(shù)
//鼠標(biāo)移動(dòng)時(shí)調(diào)用
function onMouseMove(event){
mouseX = event.clientX;
mouseY = event.clientY;
}
畫(huà)圓
three.js并沒(méi)有內(nèi)置圓形粒子材質(zhì)勉躺,所以需要告訴它如何去畫(huà)一個(gè)圓觅丰。我們是通過(guò)給particleRender
傳遞必要的canvas繪圖API來(lái)做到這一點(diǎn)的妇萄。
function particleRender(context) {
context.beginPath();
context.arc(0, 0, 1, 0, 2*Math.PI, true);
context.fill();
}
把一個(gè)函數(shù)傳遞給材質(zhì)(material)似乎有點(diǎn)奇怪,但這實(shí)際上是一個(gè)非常靈活的系統(tǒng)轻掩。它獲得了canvas上下文的引用唇牧,所以我們可以畫(huà)出任何想要的形狀聚唐。同時(shí)canvas的坐標(biāo)系統(tǒng)將會(huì)根據(jù)粒子進(jìn)行縮放和平移,因此我們只需要以起點(diǎn)(origin)為中心畫(huà)圖即可扮惦。
移動(dòng)粒子
現(xiàn)在來(lái)看一下updateParticles
函數(shù)崖蜜,它將會(huì)在我們每個(gè)的更新周期中調(diào)用客峭,就在我們進(jìn)行渲染之前桃笙。
// 根據(jù)鼠標(biāo)位置移動(dòng)所有的粒子
function updateParticles() {
// 對(duì)每個(gè)粒子進(jìn)行迭代處理
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
// 根據(jù)mouseY值進(jìn)行移動(dòng)
particle.position.z += mouseY * 0.1;
// 如果粒子過(guò)近,將其移至后面
if (particle.position.z > 1000)
particle.position.z -= 2000;
}
}
鼠標(biāo)越低闪檬,mouseY值越大购笆,粒子移動(dòng)速度越快同欠。
整合代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>drawStar</title>
<style type="text/css">
body{background-color: #000;margin: 0;overflow: hidden;}
</style>
</head>
<body>
<script src="three.min.js"></script>
<script type="text/javascript">
//全局變量
//three的三要素
var camera,scene,renderer,
//跟蹤鼠標(biāo)位置
mouseX = 0, mouseY = 0 ,
//一個(gè)數(shù)組样傍,用于存儲(chǔ)我們的粒子
particles = [];
// 初始化
init();
function init() {
//照相機(jī)的參數(shù)
camera = new THREE.PerspectiveCamera(80, window.innerWidth/window.innerHeight, 1,4000);
//將相機(jī)屏幕外移動(dòng)
camera.position.z = 1000;
//場(chǎng)景
scene = new THREE.Scene();
scene.add(camera);
//渲染器
renderer = new THREE.CanvasRenderer();
//設(shè)置2Dcanvas的大小
renderer.setSize(window.innerWidth,window.innerHeight);
//將渲染器的canvas domElement加入到body中
document.body.appendChild(renderer.domElement);
makeParticles();
//設(shè)置鼠標(biāo)移動(dòng)監(jiān)聽(tīng)
document.addEventListener( 'mousemove', onMouseMove, false );
//每秒渲染30次
setInterval(update,1000/30);
}
function update(){
//作用是將粒子向前移動(dòng)
updateParticles();
//從相機(jī)的視角渲染場(chǎng)景
renderer.render(scene,camera);
}
function makeParticles() {
var particle, material; //創(chuàng)建粒子和材質(zhì)
for (var zpos = -1000; zpos < 1000; zpos += 20) {
//創(chuàng)建材質(zhì)
material = new THREE.ParticleCanvasMaterial( {
color: getRandomColor(),
// color: 0xffffff,
program: particleRender,
});
//創(chuàng)建粒子
particle = new THREE.Particle(material);
particle.position.x = Math.random() * 1000 - 500;
particle.position.y = Math.random() * 1000 - 500;
particle.position.z = zpos;
//將其放大一點(diǎn)
particle.scale.x = particle.scale.y = 10;
//放入到場(chǎng)景中
scene.add(particle)
//將粒子加入到particles數(shù)組中
particles.push(particle)
}
}
function particleRender( context ) {
context.beginPath();
context.arc( 0, 0, 1, 0, Math.PI * 2,true );
context.fill();
};
function getRandomColor() {
var r = 255*Math.random()|0,
g = 255*Math.random()|0,
b = 255*Math.random()|0,
// console.log( parseInt(r, 16) );
return '0x' + parseInt(r, 16) + parseInt(g, 16) + parseInt( b, 16);
}
function updateParticles() {
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
particle.position.z += mouseY * 0.1;
if (particle.position.z>1000)
particle.position.z -=2000;
}
}
function onMouseMove( event ) {
mouseX = event.cilentX;
mouseY = event.clientY;
}
</script>
</body>
</html>