Last active
January 25, 2019 15:37
-
-
Save sketchpunk/40917bf1ebad58e23bda228c8c3de68a to your computer and use it in GitHub Desktop.
Draw Dynamic Points in Three.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Display Points on the scene, each with its own size and color. | |
* @example <caption>Simple How to use</caption> | |
* let dPnt = new DynamicPoints( 200 ); | |
* Scene.add( dPnt.mesh ); | |
*/ | |
class DynamicPoints{ | |
constructor( maxLen = 100 ){ | |
/** | |
* How many vertices to draw. | |
* @private @type {number} | |
*/ | |
this.vertCnt = 0; | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// SETUP BUFFERS | |
// Vertext Position AND Point size will be saved in the W component of the Vec4. | |
// This will save on creating another buffer to hold that information. Custom Shader is | |
// Needed to handle this setup. | |
this.aPos = new THREE.BufferAttribute( new Float32Array( maxLen * 4 ), 4 ); | |
this.aPos.setDynamic( true ); | |
// Containts a custom color for each vertex | |
this.aColor = new THREE.BufferAttribute( new Float32Array( maxLen * 3), 3 ); | |
this.aColor.setDynamic( true ); | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// GEOMETRY | |
this.geo = new THREE.BufferGeometry(); | |
this.geo.addAttribute( "position", this.aPos ); // Use standard three.js shader attrib names | |
this.geo.addAttribute( "color", this.aColor ); // to be compatible with some materials | |
this.geo.setDrawRange( 0, this.vertCnt ); | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
/** | |
* Mesh that can be added to the scene. | |
* @public @type {THREE.Points} | |
*/ | |
this.mesh = new THREE.Points( this.geo, DynamicPoints._getMaterial() ); | |
} | |
////////////////////////////////////////////////////////////////////// | |
// METHODS | |
////////////////////////////////////////////////////////////////////// | |
/** | |
* Add new points | |
* @param {number} x - X Position | |
* @param {number} y - Y Position | |
* @param {number} z - Z Position | |
* @param {number} [size=40] - Size of the point | |
* @param {number} [hex=0xff0000] - Color of the point in hex number form (0xffffff) | |
* @public @return {DynamicPoints} | |
*/ | |
add( x, y, z, size=40, hex=0xff0000 ){ | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// VERTEX POSITION | |
this.aPos.setXYZW( this.vertCnt, x, y, z, size ); | |
this.aPos.needsUpdate = true; | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// VERTEX COLOR | |
const NORMALIZE_RGB = 1 / 255; | |
this.aColor.setXYZ( | |
this.vertCnt, | |
( hex >> 16 & 255 ) * NORMALIZE_RGB, | |
( hex >> 8 & 255 ) * NORMALIZE_RGB, | |
( hex & 255 ) * NORMALIZE_RGB | |
); | |
this.aColor.needsUpdate = true; | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
// INCREMENT AND UPDATE DRAW RANGE | |
this.vertCnt++; | |
this.geo.setDrawRange( 0, this.vertCnt ); | |
return this; | |
} | |
/** | |
* Sets the Position attribute that the concepts needs to be updated to the gpu | |
* @param {number} i - Vertex Index | |
* @param {?number} x - X Position | |
* @param {?number} y - Y Position | |
* @param {?number} z - Z Position | |
* @public @return {DynamicPoints} | |
*/ | |
set( i, x=null, y=null, z=null ){ | |
let ii = i * 4; | |
if( x != null ) this.aPos.array[ ii ] = x; | |
if( y != null ) this.aPos.array[ ii+1 ] = y; | |
if( z != null ) this.aPos.array[ ii+2 ] = z; | |
return this; | |
} | |
/** | |
* Sets the Position attribute that the concepts needs to be updated to the gpu | |
* @public @return {DynamicPoints} | |
*/ | |
requestUpdate(){ this.aPos.needsUpdate = true; return this; } | |
/** | |
* Reset draw range to 0 | |
* @public @return {DynamicPoints} | |
*/ | |
reset(){ | |
this.vertCnt = 0; | |
this.geo.setDrawRange( 0, 0 ); | |
return this; | |
} | |
////////////////////////////////////////////////////////////////////// | |
// PRIVATE STATIC FUNCS | |
////////////////////////////////////////////////////////////////////// | |
/** | |
* Create a custom Shader Material that will render the dynamic points | |
* @private @return {THREE.RawShaderMaterial} | |
*/ | |
static _getMaterial(){ | |
const sVertex = `const float scale = 1.0; | |
attribute vec4 position; | |
attribute vec3 color; | |
uniform mat4 modelViewMatrix; | |
uniform mat4 projectionMatrix; | |
uniform float pnt_size; | |
varying vec3 v_color; | |
void main(){ | |
vec4 ws_position = modelViewMatrix * vec4( position.xyz, 1.0 ); | |
v_color = color; | |
gl_PointSize = position.w * ( scale / -ws_position.z ); | |
gl_Position = projectionMatrix * ws_position; | |
}`; | |
const sFragment = `precision mediump float; | |
const vec2 UV_CENTER = vec2( 0.5 ); | |
varying vec3 v_color; | |
void main(){ | |
vec2 coord = gl_PointCoord - UV_CENTER; | |
//if( length(coord) > 0.5 ) discard; | |
gl_FragColor = vec4( v_color, smoothstep( 0.5, 0.45, length(coord) ) ); | |
}`; | |
return new THREE.RawShaderMaterial( { fragmentShader:sFragment, vertexShader:sVertex, transparent:true } ); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment