Skip to content

Instantly share code, notes, and snippets.

@sketchpunk
Last active January 25, 2019 15:37
Show Gist options
  • Save sketchpunk/40917bf1ebad58e23bda228c8c3de68a to your computer and use it in GitHub Desktop.
Save sketchpunk/40917bf1ebad58e23bda228c8c3de68a to your computer and use it in GitHub Desktop.
Draw Dynamic Points in Three.js
/**
* 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