|
@@ -0,0 +1,284 @@
|
|
|
|
+<!DOCTYPE html>
|
|
|
|
+<html lang="en">
|
|
|
|
+<head>
|
|
|
|
+ <title>three.js webgl - instanced particles - billboards - colors</title>
|
|
|
|
+ <meta charset="utf-8">
|
|
|
|
+ <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
|
|
|
|
+ <style>
|
|
|
|
+ body {
|
|
|
|
+ color: #ffffff;
|
|
|
|
+ font-family: Monospace;
|
|
|
|
+ font-size: 13px;
|
|
|
|
+ text-align: center;
|
|
|
|
+ font-weight: bold;
|
|
|
|
+ background-color: #000000;
|
|
|
|
+ margin: 0px;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #info {
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 0px;
|
|
|
|
+ width: 100%;
|
|
|
|
+ padding: 5px;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ a {
|
|
|
|
+ color: #ffffff;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #oldie a {
|
|
|
|
+ color: #da0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ #notSupported {
|
|
|
|
+ width: 50%;
|
|
|
|
+ margin: auto;
|
|
|
|
+ border: 2px red solid;
|
|
|
|
+ margin-top: 20px;
|
|
|
|
+ padding: 10px;
|
|
|
|
+ }
|
|
|
|
+ </style>
|
|
|
|
+</head>
|
|
|
|
+<body>
|
|
|
|
+
|
|
|
|
+ <div id="info">
|
|
|
|
+ <a href="http://threejs.org" target="_blank">three.js</a> - instanced circle billboards - colors
|
|
|
|
+ <div id="notSupported" style="display:none">Sorry your graphics card + browser does not support hardware instancing</div>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <script src="../build/three.min.js"></script>
|
|
|
|
+ <script src="js/Detector.js"></script>
|
|
|
|
+ <script src="js/libs/stats.min.js"></script>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ <script id="vshader" type="x-shader/x-vertex">
|
|
|
|
+ precision highp float;
|
|
|
|
+ uniform mat4 modelViewMatrix;
|
|
|
|
+ uniform mat4 projectionMatrix;
|
|
|
|
+
|
|
|
|
+ attribute vec3 position;
|
|
|
|
+ attribute vec2 uv;
|
|
|
|
+ attribute vec3 normal;
|
|
|
|
+
|
|
|
|
+ attribute vec4 translateScale;
|
|
|
|
+ attribute vec3 color;
|
|
|
|
+
|
|
|
|
+ varying vec2 vUv;
|
|
|
|
+ varying vec3 vColor;
|
|
|
|
+
|
|
|
|
+ void main() {
|
|
|
|
+
|
|
|
|
+ vec4 positionAdj = vec4( translateScale.xyz, 1.0 );
|
|
|
|
+ vec4 mvPosition = modelViewMatrix * positionAdj;
|
|
|
|
+
|
|
|
|
+ mvPosition.xyz += position * translateScale.w;
|
|
|
|
+
|
|
|
|
+ vUv = uv;
|
|
|
|
+ vColor = color;
|
|
|
|
+
|
|
|
|
+ gl_Position = projectionMatrix * mvPosition;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ </script>
|
|
|
|
+ <script id="fshader" type="x-shader/x-fragment">
|
|
|
|
+ precision highp float;
|
|
|
|
+
|
|
|
|
+ uniform sampler2D map;
|
|
|
|
+
|
|
|
|
+ varying vec2 vUv;
|
|
|
|
+ varying vec3 vColor;
|
|
|
|
+
|
|
|
|
+ void main() {
|
|
|
|
+
|
|
|
|
+ vec4 diffuseColor = texture2D( map, vUv );
|
|
|
|
+ gl_FragColor = vec4( diffuseColor.xyz * vColor, diffuseColor.w );
|
|
|
|
+
|
|
|
|
+ if ( diffuseColor.w < 0.5 ) discard;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ </script>
|
|
|
|
+
|
|
|
|
+ <script>
|
|
|
|
+
|
|
|
|
+ var container, stats;
|
|
|
|
+
|
|
|
|
+ var camera, scene, renderer;
|
|
|
|
+ var particles, geometry, material, sprite;
|
|
|
|
+ var mouseX = 0, mouseY = 0;
|
|
|
|
+
|
|
|
|
+ var windowHalfX = window.innerWidth / 2;
|
|
|
|
+ var windowHalfY = window.innerHeight / 2;
|
|
|
|
+
|
|
|
|
+ function init() {
|
|
|
|
+
|
|
|
|
+ if ( !Detector.webgl ) {
|
|
|
|
+
|
|
|
|
+ Detector.addGetWebGLMessage();
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ renderer = new THREE.WebGLRenderer();
|
|
|
|
+
|
|
|
|
+ if ( !renderer.supportsInstancedArrays ) {
|
|
|
|
+ document.getElementById( "notSupported" ).style.display = "";
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ container = document.createElement( 'div' );
|
|
|
|
+ document.body.appendChild( container );
|
|
|
|
+
|
|
|
|
+ camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 3000 );
|
|
|
|
+ camera.position.z = 1400;
|
|
|
|
+
|
|
|
|
+ scene = new THREE.Scene();
|
|
|
|
+
|
|
|
|
+ geometry = new THREE.InstancedBufferGeometry().copy( new THREE.CircleBufferGeometry( 1, 16 ) );
|
|
|
|
+
|
|
|
|
+ sprite = THREE.ImageUtils.loadTexture( "textures/sprites/ball.png" );
|
|
|
|
+
|
|
|
|
+ var particleCount = 5000;
|
|
|
|
+
|
|
|
|
+ var translateScaleArray = new Float32Array( 4 * particleCount );
|
|
|
|
+ var colorsArray = new Float32Array( 3 * particleCount );
|
|
|
|
+
|
|
|
|
+ var color = new THREE.Color( 0xffffff );
|
|
|
|
+ for ( i = 0, ii = 0, ul = particleCount * 4; i < ul; i += 4, ii += 3 ) {
|
|
|
|
+
|
|
|
|
+ translateScaleArray[i] = 2000 * Math.random() - 1000;
|
|
|
|
+ translateScaleArray[i + 1] = 2000 * Math.random() - 1000;
|
|
|
|
+ translateScaleArray[i + 2] = 2000 * Math.random() - 1000;
|
|
|
|
+ translateScaleArray[i + 3] = 24;
|
|
|
|
+
|
|
|
|
+ color.setHSL(( translateScaleArray[i] + 1000 ) / 2000, 1, 0.5 );
|
|
|
|
+
|
|
|
|
+ colorsArray[ii] = color.r;
|
|
|
|
+ colorsArray[ii + 1] = color.g;
|
|
|
|
+ colorsArray[ii + 2] = color.b;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ geometry.addAttribute( "translateScale", new THREE.InstancedBufferAttribute( translateScaleArray, 4, 1 ) );
|
|
|
|
+ geometry.addAttribute( "color", new THREE.InstancedBufferAttribute( colorsArray, 3, 1 ) );
|
|
|
|
+
|
|
|
|
+ material = new THREE.RawShaderMaterial( {
|
|
|
|
+ uniforms: {
|
|
|
|
+ map: { type: "t", value: sprite }
|
|
|
|
+ },
|
|
|
|
+ vertexShader: document.getElementById( 'vshader' ).textContent,
|
|
|
|
+ fragmentShader: document.getElementById( 'fshader' ).textContent,
|
|
|
|
+ depthTest: true,
|
|
|
|
+ depthWrite: true,
|
|
|
|
+ attributes: { 'translateScale': 1, 'color': 2 }
|
|
|
|
+
|
|
|
|
+ } );
|
|
|
|
+
|
|
|
|
+ scene.add( new THREE.Mesh( geometry, material ) );
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ renderer.setPixelRatio( window.devicePixelRatio );
|
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
|
+ container.appendChild( renderer.domElement );
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ stats = new Stats();
|
|
|
|
+ stats.domElement.style.position = 'absolute';
|
|
|
|
+ stats.domElement.style.top = '0px';
|
|
|
|
+ container.appendChild( stats.domElement );
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ document.addEventListener( 'mousemove', onDocumentMouseMove, false );
|
|
|
|
+ document.addEventListener( 'touchstart', onDocumentTouchStart, false );
|
|
|
|
+ document.addEventListener( 'touchmove', onDocumentTouchMove, false );
|
|
|
|
+
|
|
|
|
+ window.addEventListener( 'resize', onWindowResize, false );
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onDocumentMouseMove( event ) {
|
|
|
|
+
|
|
|
|
+ mouseX = event.clientX - windowHalfX;
|
|
|
|
+ mouseY = event.clientY - windowHalfY;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onDocumentTouchStart( event ) {
|
|
|
|
+
|
|
|
|
+ if ( event.touches.length === 1 ) {
|
|
|
|
+
|
|
|
|
+ event.preventDefault();
|
|
|
|
+
|
|
|
|
+ mouseX = event.touches[0].pageX - windowHalfX;
|
|
|
|
+ mouseY = event.touches[0].pageY - windowHalfY;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onDocumentTouchMove( event ) {
|
|
|
|
+
|
|
|
|
+ if ( event.touches.length === 1 ) {
|
|
|
|
+
|
|
|
|
+ event.preventDefault();
|
|
|
|
+
|
|
|
|
+ mouseX = event.touches[0].pageX - windowHalfX;
|
|
|
|
+ mouseY = event.touches[0].pageY - windowHalfY;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function onWindowResize( event ) {
|
|
|
|
+
|
|
|
|
+ windowHalfX = window.innerWidth / 2;
|
|
|
|
+ windowHalfY = window.innerHeight / 2;
|
|
|
|
+
|
|
|
|
+ camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
|
+ camera.updateProjectionMatrix();
|
|
|
|
+
|
|
|
|
+ renderer.setSize( window.innerWidth, window.innerHeight );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //
|
|
|
|
+
|
|
|
|
+ function animate() {
|
|
|
|
+
|
|
|
|
+ requestAnimationFrame( animate );
|
|
|
|
+
|
|
|
|
+ render();
|
|
|
|
+ stats.update();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ var lastTime = 0;
|
|
|
|
+
|
|
|
|
+ function render() {
|
|
|
|
+
|
|
|
|
+ var time = Date.now() * 0.00005;
|
|
|
|
+
|
|
|
|
+ camera.position.x += ( mouseX - camera.position.x ) * 0.05;
|
|
|
|
+ camera.position.y += ( -mouseY - camera.position.y ) * 0.05;
|
|
|
|
+
|
|
|
|
+ camera.lookAt( scene.position );
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ renderer.render( scene, camera );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if ( init() ) {
|
|
|
|
+
|
|
|
|
+ animate();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ </script>
|
|
|
|
+
|
|
|
|
+</body>
|
|
|
|
+</html>
|