使用粒子能夠很容易的建立不少細小的物體,例如雨滴雪花等javascript
本章主要內容:html
1 使用ParticleBasicMaterial(基礎粒子材質)來建立和設計粒子java
2 使用ParticleSystem來建立一個粒子集合web
3 使用已有的幾何體來建立一個粒子系統canvas
4 讓粒子和粒子系統動起來數組
5 用紋理給粒子造型緩存
6 使用ParticleCanvasMaterial在畫布上爲粒子造型併發
名稱 | 描述 |
Sprite粒子 | 參數是material,生成的sprite能夠設置position和scale等屬性直接添加到場景中app var sprite = new THREE.Sprite(material); sprite.position.set(x * 10, y * 10, 0); scene.add(sprite); |
SpriteMaterial粒子的基本材質 | 粒子的基本材質,將在本章第7部分重點講解其參數dom var material = new THREE.SpriteMaterial(); |
PointCloud粒子系統 | 參數幾何體和材質 var cloud = new THREE.PointCloud(geom, material); scene.add(cloud); |
PointCloudMaterial粒子系統的材質 | 設置全部粒子的大小,顏色,頂點顏色,透明度,是否根據相機距離的遠近改變大小等屬性 var material = new THREE.PointCloudMaterial({size: 4, vertexColors: true, color: 0xffffff}); |
SpriteCanvasMaterial | 專門爲CanvasRenderer渲染器建立的材質,該材質的program屬性輸出的是粒子的紋理 |
1 粒子-----THREE.Particle
注意:新的THREE.js已經定義了Sprite對象,即THREE.Sprite,向後兼容THREE.Particle = THREE.Sprite;粒子Particle已經改名爲精靈Sprite
THREE.js源碼中有這樣一行代碼
THREE.Sprite跟THREE.Mesh同樣,都是THREE.Object3D對象的擴展,Sprite的參數是材質material,
另外CanvasRenderer對象已經不存在了,只有WebGLRenderer(已經找到緣由,three.js中只有WebGLRenderer,要引入CanvasRenderer.js才能夠)
<!DOCTYPE html> <html> <head> <title>Example 07.01 - Particles - Only works in CanvasRenderer</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size //THREE.CanvasRenderer雖然書中介紹的CanvasRenderer,可是THREE.CanvasRenderer的值是undefined,尚未找到緣由 //var canvasRenderer = new THREE.CanvasRenderer(); var canvasRenderer = new THREE.WebGLRenderer(); canvasRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); canvasRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 0; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(canvasRenderer.domElement); createSprites(); render(); function createSprites() { var material = new THREE.SpriteMaterial(); //var material = new THREE.ParticleBasicMaterial(); for (var x = -5; x < 5; x++) { for (var y = -5; y < 5; y++) { //var sprite = new THREE.Particle(material); var sprite = new THREE.Sprite(material); sprite.position.set(x * 10, y * 10, 0); scene.add(sprite); } } } function render() { stats.update(); requestAnimationFrame(render); canvasRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); //ParticleBasicMaterial已經改名爲PointCloudMaterial
console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' );//THREE.ParticleSystemMaterial已經改名爲THREE.PointCloudMaterial
console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' );
<!DOCTYPE html> <html> <head> <title>Example 07.02 - Particles - Only works in WebGLRenderer</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 0; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); createParticles(); render(); function createParticles() { var geom = new THREE.Geometry(); console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' ); console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' ); //建立一個點雲材質 //PointCloudMaterial==ParticleBasicMaterial var material = new THREE.PointCloudMaterial({size: 4, vertexColors: true, color: 0xffffff}); for (var x = -5; x < 5; x++) { for (var y = -5; y < 5; y++) { var particle = new THREE.Vector3(x * 10, y * 10, 0); geom.vertices.push(particle); geom.colors.push(new THREE.Color(Math.random() * 0x00ffff)); } } //console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' ); //PointCloud==ParticleSystem var cloud = new THREE.PointCloud(geom, material); scene.add(cloud); } function render() { stats.update(); requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
2 粒子材質PointCloudMaterial和粒子系統PointCloud
PointCloudMaterial的屬性 | 描述 |
color | PointCloud中全部的粒子的顏色都相同, 除非設置了vertexColors且該幾何體的colors屬性不爲空,纔會使用colors顏色,不然都使用該屬性 |
map | 在粒子上應用某種材質 |
size | 粒子的大小 |
sizeAnnutation | false:不管相機的位置,全部的粒子大小一致; true:離相機近的粒子更大一些,離相機越遠越小 |
vetexColors | true:且該幾何體的colors屬性有值,則該粒子會捨棄第一個屬性--color,而應用該幾何體的colors屬性的顏色 |
opacity | 透明度 |
transparent | 是否透明 |
blending | 渲染粒子時的融合模式 |
fog | 是否受場景的霧化影響 |
<!DOCTYPE html> <html> <head> <title>Example 07.03 - Particle Basic Material</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); var cloud; var controls = new function () { this.size = 4; this.transparent = true; this.opacity = 0.6; this.vertexColors = true; this.color = 0xffffff; this.sizeAttenuation = true; this.rotateSystem = true; this.redraw = function () { if (scene.getObjectByName("particles")) { scene.remove(scene.getObjectByName("particles")); } createParticles(controls.size, controls.transparent, controls.opacity, controls.vertexColors, controls.sizeAttenuation, controls.color); }; }; var gui = new dat.GUI(); gui.add(controls, 'size', 0, 10).onChange(controls.redraw); gui.add(controls, 'transparent').onChange(controls.redraw); gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw); gui.add(controls, 'vertexColors').onChange(controls.redraw); gui.addColor(controls, 'color').onChange(controls.redraw); gui.add(controls, 'sizeAttenuation').onChange(controls.redraw); gui.add(controls, 'rotateSystem'); controls.redraw(); render(); function createParticles(size, transparent, opacity, vertexColors, sizeAttenuation, color) { var geom = new THREE.Geometry(); //設置粒子材質的屬性 var material = new THREE.PointCloudMaterial({ size: size,//粒子的大小 transparent: transparent,//是否透明 opacity: opacity,//透明度是多少 vertexColors: vertexColors, /*一般狀況下,全部的粒子應用同一種顏色,可是若該值設置爲true, 且幾何體的colors數組也有值,則會使用colors數組的顏色*/ sizeAttenuation: sizeAttenuation, /*false:無論粒子距離相機的遠近,它們都擁有相同的尺寸 true:粒子的大小取決於它們距離相機的遠近 */ color: color//粒子系統中全部粒子的顏色 }); var range = 500; for (var i = 0; i < 15000; i++) { var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2); geom.vertices.push(particle); var color = new THREE.Color(0x00ff00); color.setHSL(color.getHSL().h, color.getHSL().s, Math.random() * color.getHSL().l); geom.colors.push(color); } //粒子系統PointCloud與網格Mesh相同,只接受幾何體和材質兩個參數 cloud = new THREE.PointCloud(geom, material); cloud.name = "particles"; scene.add(cloud); } var step = 0; function render() { stats.update(); if (controls.rotateSystem) { step += 0.01; cloud.rotation.x = step; cloud.rotation.z = step; } requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
3 使用畫布格式化粒子---針對CanvasRenderer渲染器所建立的材質SpriteCanvasMaterial
<!DOCTYPE html> <html> <head> <title>Example 07.04 - Particles - Canvas based texture</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <script type="text/javascript" src="../libs/CanvasRenderer.js"></script> <script type="text/javascript" src="../libs/Projector.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var canvasRenderer = new THREE.CanvasRenderer(); // var canvasRenderer = new THREE.WebGLRenderer(); canvasRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); canvasRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(canvasRenderer.domElement); var getTexture = function (ctx) { // the body,繪製吃豆人中幽靈的身體 ctx.translate(-81, -84); ctx.fillStyle = "orange"; ctx.beginPath(); ctx.moveTo(83, 116); ctx.lineTo(83, 102); ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); ctx.lineTo(111, 116); ctx.lineTo(106.333, 111.333); ctx.lineTo(101.666, 116); ctx.lineTo(97, 111.333); ctx.lineTo(92.333, 116); ctx.lineTo(87.666, 111.333); ctx.lineTo(83, 116); ctx.fill(); // the eyes //繪製其眼睛 ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(91, 96); ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); ctx.moveTo(103, 96); ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); ctx.fill(); // the pupils //繪製其眼珠 ctx.fillStyle = "blue"; ctx.beginPath(); ctx.arc(101, 102, 2, 0, Math.PI * 2, true); ctx.fill(); ctx.beginPath(); ctx.arc(89, 102, 2, 0, Math.PI * 2, true); ctx.fill(); }; createSprites(); render(); function createSprites() { var material = new THREE.SpriteCanvasMaterial({ program: getTexture, color: 0xffffff } ); material.rotation = Math.PI; var range = 500; for (var i = 0; i < 1500; i++) { //Sprite是Object3D的擴展 var sprite = new THREE.Sprite(material); sprite.position.set(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2); sprite.scale.set(0.1, 0.1, 0.1); scene.add(sprite); } } var step = 0; function render() { stats.update(); requestAnimationFrame(render); canvasRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
4 基於WebGLRenderer渲染器使用的粒子材質----PointCloudMaterial
PointCloudMaterial材質的map屬性使用的是THREE.Texture紋理,該紋理是畫布canvas做爲參數傳遞給紋理構造函數獲得的
var texture = new THREE.Texture(canvas);
<!DOCTYPE html> <html> <head> <title>Example 07.05 - Particles - Canvas based texture - WebGL</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); var getTexture = function () { var canvas = document.createElement('canvas'); canvas.width = 32; canvas.height = 32; var ctx = canvas.getContext('2d'); // the body ctx.translate(-81, -84); ctx.fillStyle = "orange"; ctx.beginPath(); ctx.moveTo(83, 116); ctx.lineTo(83, 102); ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); ctx.lineTo(111, 116); ctx.lineTo(106.333, 111.333); ctx.lineTo(101.666, 116); ctx.lineTo(97, 111.333); ctx.lineTo(92.333, 116); ctx.lineTo(87.666, 111.333); ctx.lineTo(83, 116); ctx.fill(); // the eyes ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(91, 96); ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); ctx.moveTo(103, 96); ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); ctx.fill(); // the pupils ctx.fillStyle = "blue"; ctx.beginPath(); ctx.arc(101, 102, 2, 0, Math.PI * 2, true); ctx.fill(); ctx.beginPath(); ctx.arc(89, 102, 2, 0, Math.PI * 2, true); ctx.fill(); var texture = new THREE.Texture(canvas); texture.needsUpdate = true; return texture; }; var cloud; var controls = new function () { this.size = 15; this.transparent = true; this.opacity = 0.6; this.color = 0xffffff; this.rotateSystem = true; this.sizeAttenuation = true; this.redraw = function () { if (scene.getObjectByName("pointcloud")) { scene.remove(scene.getObjectByName("pointcloud")); } createPointCloud(controls.size, controls.transparent, controls.opacity, controls.sizeAttenuation, controls.color); }; }; var gui = new dat.GUI(); gui.add(controls, 'size', 0, 20).onChange(controls.redraw); gui.add(controls, 'transparent').onChange(controls.redraw); gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw); gui.addColor(controls, 'color').onChange(controls.redraw); gui.add(controls, 'sizeAttenuation').onChange(controls.redraw); gui.add(controls, 'rotateSystem'); controls.redraw(); render(); function createPointCloud(size, transparent, opacity, sizeAttenuation, color) { var geom = new THREE.Geometry(); var material = new THREE.PointCloudMaterial({ size: size, transparent: transparent, opacity: opacity, map: getTexture(), sizeAttenuation: sizeAttenuation, color: color }); var range = 500; for (var i = 0; i < 5000; i++) { var particle = new THREE.Vector3(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2); geom.vertices.push(particle); } cloud = new THREE.PointCloud(geom, material); cloud.name = 'pointcloud'; cloud.sortParticles = true; scene.add(cloud); } var step = 0; function render() { stats.update(); if (controls.rotateSystem) { step += 0.01; cloud.rotation.x = step; cloud.rotation.z = step; } requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
5 引入外部圖片造成紋理,而後利用該紋理格式化粒子
引入外部圖片造成紋理var texture=new THREE.ImageUtils.loadTexture("../img/rain.jpg");
格式化粒子的材質var material = new THREE.PiontCloudMaterial({map:texture});
利用該材質生成粒子系統 var cloud = new THREE.PointCloud(geom, material);
<!DOCTYPE html> <html> <head> <title>Example 07.06 - Particles - Rainy scene</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 40; camera.position.z = 110; camera.lookAt(new THREE.Vector3(20, 30, 0)); // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); var system1; var cloud; var controls = new function () { this.size = 3; this.transparent = true; this.opacity = 0.6; this.color = 0xffffff; this.sizeAttenuation = true; this.redraw = function () { //有兩個粒子系統 scene.remove(scene.getObjectByName("particles1")); scene.remove(scene.getObjectByName("particles2")); createPointCloud(controls.size, controls.transparent, controls.opacity, controls.sizeAttenuation, controls.color); }; }; var gui = new dat.GUI(); gui.add(controls, 'size', 0, 20).onChange(controls.redraw); gui.add(controls, 'transparent').onChange(controls.redraw); gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw); gui.addColor(controls, 'color').onChange(controls.redraw); gui.add(controls, 'sizeAttenuation').onChange(controls.redraw); controls.redraw(); render(); function createPointCloud(size, transparent, opacity, sizeAttenuation, color) { //引入外部圖片生成紋理 var texture = THREE.ImageUtils.loadTexture("../assets/textures/particles/raindrop-3.png"); var geom = new THREE.Geometry(); var material = new THREE.PointCloudMaterial({ size: size, transparent: transparent, opacity: opacity, map: texture, blending: THREE.AdditiveBlending, /*這種融合方式:在畫新的像素時,背景像素的顏色會被添加到新像素上*/ sizeAttenuation: sizeAttenuation, color: color }); var range = 40; for (var i = 0; i < 1500; i++) { var particle = new THREE.Vector3( Math.random() * range - range / 2, Math.random() * range * 1.5, Math.random() * range - range / 2); particle.velocityY = 0.1 + Math.random() / 5; particle.velocityX = (Math.random() - 0.5) / 3; geom.vertices.push(particle); } cloud = new THREE.PointCloud(geom, material); cloud.sortParticles = true; scene.add(cloud); } function render() { stats.update(); var vertices = cloud.geometry.vertices; vertices.forEach(function (v) { v.y = v.y - (v.velocityY); v.x = v.x - (v.velocityX); if (v.y <= 0) v.y = 60; if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1; }); requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
6 經過模擬下雪,學習多個粒子系統併發進行
<!DOCTYPE html> <html> <head> <title>Example 07.07 - Particles - Snowy scene</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 200); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 40; camera.position.z = 110; camera.lookAt(new THREE.Vector3(20, 30, 0)); // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); var system1; var system2; var controls = new function () { this.size = 10; this.transparent = true; this.opacity = 0.6; this.color = 0xffffff; this.sizeAttenuation = true; this.redraw = function () { var toRemove = []; scene.children.forEach(function (child) { if (child instanceof THREE.PointCloud) { toRemove.push(child); } }); toRemove.forEach(function (child) { scene.remove(child) }); createPointClouds(controls.size, controls.transparent, controls.opacity, controls.sizeAttenuation, controls.color); }; }; var gui = new dat.GUI(); gui.add(controls, 'size', 0, 20).onChange(controls.redraw); gui.add(controls, 'transparent').onChange(controls.redraw); gui.add(controls, 'opacity', 0, 1).onChange(controls.redraw); gui.addColor(controls, 'color').onChange(controls.redraw); gui.add(controls, 'sizeAttenuation').onChange(controls.redraw); controls.redraw(); render(); function createPointCloud(name, texture, size, transparent, opacity, sizeAttenuation, color) { var geom = new THREE.Geometry(); var color = new THREE.Color(color); color.setHSL(color.getHSL().h, color.getHSL().s, (Math.random()) * color.getHSL().l); var material = new THREE.PointCloudMaterial({ size: size, transparent: transparent, opacity: opacity, map: texture, blending: THREE.AdditiveBlending, depthWrite: false,/*該屬性決定了這個對象是否影響WebGL的深度緩存,將其設置爲false,則各個粒子系統之間互不干涉*/ sizeAttenuation: sizeAttenuation, color: color }); var range = 40; for (var i = 0; i < 50; i++) { var particle = new THREE.Vector3( Math.random() * range - range / 2, Math.random() * range * 1.5, Math.random() * range - range / 2); particle.velocityY = 0.1 + Math.random() / 5; particle.velocityX = (Math.random() - 0.5) / 3; particle.velocityZ = (Math.random() - 0.5) / 3; geom.vertices.push(particle); } var system = new THREE.PointCloud(geom, material); system.name = name; system.sortParticles = true; return system; } function createPointClouds(size, transparent, opacity, sizeAttenuation, color) { var texture1 = THREE.ImageUtils.loadTexture("../assets/textures/particles/snowflake1.png"); var texture2 = THREE.ImageUtils.loadTexture("../assets/textures/particles/snowflake2.png"); var texture3 = THREE.ImageUtils.loadTexture("../assets/textures/particles/snowflake3.png"); var texture4 = THREE.ImageUtils.loadTexture("../assets/textures/particles/snowflake5.png"); scene.add(createPointCloud("system1", texture1, size, transparent, opacity, sizeAttenuation, color)); scene.add(createPointCloud("system2", texture2, size, transparent, opacity, sizeAttenuation, color)); scene.add(createPointCloud("system3", texture3, size, transparent, opacity, sizeAttenuation, color)); scene.add(createPointCloud("system4", texture4, size, transparent, opacity, sizeAttenuation, color)); } function render() { stats.update(); scene.children.forEach(function (child) { if (child instanceof THREE.PointCloud) { var vertices = child.geometry.vertices; vertices.forEach(function (v) { v.y = v.y - (v.velocityY); v.x = v.x - (v.velocityX); v.z = v.z - (v.velocityZ); if (v.y <= 0) v.y = 60; if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -1; if (v.z <= -20 || v.z >= 20) v.velocityZ = v.velocityZ * -1; }); } }); requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
7 Sprite粒子和SpriteMaterial粒子的基本材質
SpriteMaterial屬性 | 描述 |
color | 粒子的顏色 |
map | 粒子的紋理 |
sizeAnnutation | 相機的遠近是否影響粒子的大小 |
opacity | 透明度 |
transparent | 是否透明 |
blending | 融合方式 |
fog | 是否受場景霧化的影響 |
useScreenCoordinates | true:粒子的位置是絕對位置,原點是屏幕的左上角 |
scaleByViewport | true:粒子的大小取決於視窗的尺寸,粒子的寬=圖片的寬/窗口的高 false:粒子的寬=圖片的寬/1.0 |
alignment | 當粒子被縮放的時候,指定從哪裏開始縮放, THREE.SpriteAlignment.topLeft左上角保持不動,進行縮放 |
uvOffset | 當載入的圖片是一個精靈圖片,即不少小圖組成一張大圖,取大圖上具體某個小圖時,使用該屬性,進行偏移獲得具體的小圖 |
uvScale | 對根據uvOffset獲取到的小圖進行縮放 |
<!DOCTYPE html> <html> <head> <title>Example 07.09 - Sprites in 3D</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; background-color: #000000; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); // position and point the camera to the center of the scene camera.position.x = 20; camera.position.y = 0; camera.position.z = 150; // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); createSprites(); render(); var group; function createSprites() { group = new THREE.Object3D(); var range = 200; for (var i = 0; i < 400; i++) { group.add(createSprite(10, false, 0.6, 0xffffff, i % 5, range)); } scene.add(group); } function getTexture() { //只須要載入一張大圖,該大圖由5個小圖組成 var texture = new THREE.ImageUtils.loadTexture("../assets/textures/particles/sprite-sheet.png"); return texture; } function createSprite(size, transparent, opacity, color, spriteNumber, range) { var spriteMaterial = new THREE.SpriteMaterial({ opacity: opacity, color: color, transparent: transparent, map: getTexture() } ); // we have 1 row, with five sprites spriteMaterial.map.offset = new THREE.Vector2(0.2 * spriteNumber, 0); spriteMaterial.map.repeat = new THREE.Vector2(1 / 5, 1); spriteMaterial.depthTest = false; spriteMaterial.blending = THREE.AdditiveBlending; var sprite = new THREE.Sprite(spriteMaterial); sprite.scale.set(size, size, size); sprite.position.set(Math.random() * range - range / 2, Math.random() * range - range / 2, Math.random() * range - range / 2); sprite.velocityX = 5; return sprite; } var step = 0; function render() { stats.update(); step += 0.01; group.rotation.x = step; requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>
8 將canvas做爲紋理,其中canvas上繪製了一條放射顏色漸變,扭結環幾何體的各個頂點和canvas紋理做爲參數傳遞粒子系統的構造函數,生成一個粒子系統
var gradient = context.createRadialGradient()//canvas上繪製一條放射顏色漸變
var texture = new THREE.Texture(canvas);//canvas做爲參數傳遞給紋理構造函數,生成一個紋理
var material = new THREE.PointCloudMaterial({map: generateSprite()});// 利用粒子基本材質的map屬性應用該紋理,生成材質
var geom = new THREE.TorusKnotGeometry()//扭結環構造函數,生成一個幾何體
var cloud = new THREE.PointCloud(geom, material);//利用上面獲得的幾何體和材質獲得一個粒子系統
<!DOCTYPE html> <html> <head> <title>Example 07.10 - 3D Torusknot</title> <script type="text/javascript" src="../libs/three.js"></script> <script type="text/javascript" src="../libs/stats.js"></script> <script type="text/javascript" src="../libs/dat.gui.js"></script> <style> body { /* set margin to 0 and overflow to hidden, to go fullscreen */ margin: 0; overflow: hidden; } </style> </head> <body> <div id="Stats-output"> </div> <!-- Div which will hold the Output --> <div id="WebGL-output"> </div> <!-- Javascript code that runs our Three.js examples --> <script type="text/javascript"> // once everything is loaded, we run our Three.js stuff. function init() { var stats = initStats(); // create a scene, that will hold all our elements such as objects, cameras and lights. var scene = new THREE.Scene(); // create a camera, which defines where we're looking at. var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); // create a render and set the size var webGLRenderer = new THREE.WebGLRenderer(); webGLRenderer.setClearColor(new THREE.Color(0x000000, 1.0)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); webGLRenderer.shadowMapEnabled = true; // position and point the camera to the center of the scene camera.position.x = -30; camera.position.y = 40; camera.position.z = 50; camera.lookAt(new THREE.Vector3(10, 0, 0)); // add the output of the renderer to the html element document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); // call the render function var step = 0; var knot; // setup the control gui var controls = new function () { // we need the first child, since it's a multimaterial this.radius = 13; this.tube = 1.7; this.radialSegments = 156; this.tubularSegments = 12; this.p = 5; this.q = 4; this.heightScale = 3.5; this.asParticles = false; this.rotate = false; this.redraw = function () { // remove the old plane if (knot) scene.remove(knot); // create a new one var geom = new THREE.TorusKnotGeometry(controls.radius, controls.tube, Math.round(controls.radialSegments), Math.round(controls.tubularSegments), Math.round(controls.p), Math.round(controls.q), controls.heightScale); if (controls.asParticles) { knot = createPointCloud(geom); } else { knot = createMesh(geom); } // add it to the scene. scene.add(knot); }; }; var gui = new dat.GUI(); gui.add(controls, 'radius', 0, 40).onChange(controls.redraw); gui.add(controls, 'tube', 0, 40).onChange(controls.redraw); gui.add(controls, 'radialSegments', 0, 400).step(1).onChange(controls.redraw); gui.add(controls, 'tubularSegments', 1, 20).step(1).onChange(controls.redraw); gui.add(controls, 'p', 1, 10).step(1).onChange(controls.redraw); gui.add(controls, 'q', 1, 15).step(1).onChange(controls.redraw); gui.add(controls, 'heightScale', 0, 5).onChange(controls.redraw); gui.add(controls, 'asParticles').onChange(controls.redraw); gui.add(controls, 'rotate').onChange(controls.redraw); controls.redraw(); render(); // from THREE.js examples function generateSprite() { var canvas = document.createElement('canvas'); canvas.width = 16; canvas.height = 16; var context = canvas.getContext('2d'); var gradient = context.createRadialGradient(canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2); gradient.addColorStop(0, 'rgba(255,255,255,1)'); gradient.addColorStop(0.2, 'rgba(0,255,255,1)'); gradient.addColorStop(0.4, 'rgba(0,0,64,1)'); gradient.addColorStop(1, 'rgba(0,0,0,1)'); context.fillStyle = gradient; context.fillRect(0, 0, canvas.width, canvas.height); var texture = new THREE.Texture(canvas); texture.needsUpdate = true; return texture; } function createPointCloud(geom) { var material = new THREE.PointCloudMaterial({ color: 0xffffff, size: 3, transparent: true, blending: THREE.AdditiveBlending, map: generateSprite() }); var cloud = new THREE.PointCloud(geom, material); cloud.sortParticles = true; return cloud; } function createMesh(geom) { // assign two materials var meshMaterial = new THREE.MeshNormalMaterial({}); meshMaterial.side = THREE.DoubleSide; // create a multimaterial var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [meshMaterial]); return mesh; } function render() { stats.update(); if (controls.rotate) { knot.rotation.y = step += 0.01; } // render using requestAnimationFrame requestAnimationFrame(render); webGLRenderer.render(scene, camera); } function initStats() { var stats = new Stats(); stats.setMode(0); // 0: fps, 1: ms // Align top-left stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.getElementById("Stats-output").appendChild(stats.domElement); return stats; } } window.onload = init; </script> </body> </html>