tadashi000000

theme:

TypeScriptでthree.jsのパーティクルをテスト

summary:

長さ1000四方の立方体にサイズ80のパーティクルを5000個浮遊させる

points:

・パーティクルに画像を利用する

・黒背景のjpg画像を透過させるようblendingプロパティにTHREE.AdditiveBlendingを適用

・カメラは立方体から0距離の位置

・通常パーティクルは個別の処理は不得手だが、位置変更だけならそれほどパフォーマンスは落ちない

・透過画像を利用する方法は薄いグラデーションがキレイに表示され無かったので却下

・シーンにアンチエイリアスを設定するのは処理速度が目に見えて重くなったので却下

・テストはサーバを起動しlocalhost環境で行う

date:
reference:

PointsMaterial

https://threejs.org/docs/#api/materials/PointsMaterial
TypeScript:

//-----------------------------------------------------------------------------
// const
//-----------------------------------------------------------------------------
const CUBE_SIZE:number = 1000;
const PARTICLE_SIZE:number = 80;
const PARTICLE_NUM:number = 5000;
const PARTICLE_VELOCITY:number = 1;

//-----------------------------------------------------------------------------
// excute main
//-----------------------------------------------------------------------------
window.addEventListener("load", function(){new Main();});

//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
class Main
{
	constructor()
	{
		var scene:THREE.Scene = new THREE.Scene();
		var renderer:TjRenderer = new TjRenderer();
		var camera:TjCamera = new TjCamera();
		var cloud:TjCloud = new TjCloud();
		scene.add(cloud);
		renderLoop();
		function renderLoop()
		{
			cloud.calc();
			requestAnimationFrame(renderLoop);
			renderer.render(scene, camera);
		}
	}
}

//-----------------------------------------------------------------------------
// renderer
//-----------------------------------------------------------------------------
class TjRenderer extends THREE.WebGLRenderer
{
	constructor()
	{
		super();
		this.setClearColor(new THREE.Color(0x000000));
		this.setSize(window.innerWidth, window.innerHeight);
		document.getElementById("idTest001").appendChild(this.domElement);
	}
}

//-----------------------------------------------------------------------------
// camera
//-----------------------------------------------------------------------------
class TjCamera extends THREE.PerspectiveCamera
{
	constructor()
	{
		super(45, window.innerWidth / window.innerHeight, 0.1, CUBE_SIZE + 0);
		this.position.x = CUBE_SIZE / 2;
		this.position.y = CUBE_SIZE / 2;
		this.position.z = CUBE_SIZE * 1;
		this.lookAt(new THREE.Vector3(CUBE_SIZE / 2, CUBE_SIZE / 2, CUBE_SIZE / 2));
	}
}

//-----------------------------------------------------------------------------
// cloud
//-----------------------------------------------------------------------------
class TjCloud extends THREE.Points
{
	constructor()
	{
		var textureLoader:THREE.TextureLoader = new THREE.TextureLoader();
		var texture = textureLoader.load("dot003.jpg");
		var material:THREE.PointsMaterial = new THREE.PointsMaterial
		(
			{
				size: PARTICLE_SIZE,
				transparent: true,
				opacity: 0.8,
				depthWrite: false,
				map: texture,
				blending: THREE.AdditiveBlending,
				sizeAttenuation: true,
				color: 0xffffff
			}
		);
	
		var geom:THREE.Geometry = new THREE.Geometry();
		for(var i:number = 0; i < PARTICLE_NUM; i++)
		{
			var particle:TjParticle = new TjParticle
			(
				Math.random() * CUBE_SIZE,
				Math.random() * CUBE_SIZE,
				Math.random() * CUBE_SIZE,
				(Math.random() - 0.5) * PARTICLE_VELOCITY,
				(Math.random() - 0.5) * PARTICLE_VELOCITY,
				(Math.random() - 0.5) * PARTICLE_VELOCITY
			);
			geom.vertices.push(particle);
		}
	
		super(geom, material);
	}

	public calc():void
	{
		var geometry:THREE.Geometry = <THREE.Geometry>this.geometry;
		var vertices:TjParticle[] = <TjParticle[]>geometry.vertices;
		vertices.forEach
		(
			function(particle:TjParticle)
			{
				particle.x += particle.m_velocity.x;
				particle.y += particle.m_velocity.y;
				particle.z += particle.m_velocity.z;

				if(particle.x <= 0 || particle.x >= CUBE_SIZE)
				{
					particle.m_velocity.x *= (-1);
				};
				
				if(particle.y <= 0 || particle.y >= CUBE_SIZE)
				{
					particle.m_velocity.y *= (-1);
				};
				
				if(particle.z <= 0 || particle.z >= CUBE_SIZE)
				{
					particle.m_velocity.z *= (-1);
				};
			}
		);
		geometry.verticesNeedUpdate = true;
	}
}

//-----------------------------------------------------------------------------
// particle
//-----------------------------------------------------------------------------
class TjParticle extends THREE.Vector3
{
	public m_velocity:THREE.Vector3;
	constructor(
		x:number,
		y:number,
		z:number,
		vx:number,
		vy:number,
		vz:number
	)
	{
		super(x, y, z);
		this.m_velocity = new THREE.Vector3(vx, vy, vz);
	}
}
		
HTML:

<!DOCTYPE html>
<html>
<head>
<title>threejstest</title>
<script type="text/javascript" src="three.js"></script>
<style>
body
{
margin: 0;
overflow: hidden;
background-color: #000000;
}
</style>
</head>
<body>
<div id="idTest001"></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
		
output:

実行結果