|
@@ -0,0 +1,240 @@
|
|
|
+/**
|
|
|
+ * @author mikael emtinger / http://gomo.se/
|
|
|
+ * @author alteredq / http://alteredqualia.com/
|
|
|
+ */
|
|
|
+
|
|
|
+THREE.SpritePlugin = function ( ) {
|
|
|
+
|
|
|
+ var _gl, _renderer, _sprite = {};
|
|
|
+
|
|
|
+ this.init = function ( renderer ) {
|
|
|
+
|
|
|
+ _gl = renderer.context;
|
|
|
+ _renderer = renderer;
|
|
|
+
|
|
|
+ _sprite.vertices = new Float32Array( 8 + 8 );
|
|
|
+ _sprite.faces = new Uint16Array( 6 );
|
|
|
+
|
|
|
+ var i = 0;
|
|
|
+
|
|
|
+ _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = -1; // vertex 0
|
|
|
+ _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 1; // uv 0
|
|
|
+
|
|
|
+ _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = -1; // vertex 1
|
|
|
+ _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // uv 1
|
|
|
+
|
|
|
+ _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 1; // vertex 2
|
|
|
+ _sprite.vertices[ i++ ] = 1; _sprite.vertices[ i++ ] = 0; // uv 2
|
|
|
+
|
|
|
+ _sprite.vertices[ i++ ] = -1; _sprite.vertices[ i++ ] = 1; // vertex 3
|
|
|
+ _sprite.vertices[ i++ ] = 0; _sprite.vertices[ i++ ] = 0; // uv 3
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+
|
|
|
+ _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 1; _sprite.faces[ i++ ] = 2;
|
|
|
+ _sprite.faces[ i++ ] = 0; _sprite.faces[ i++ ] = 2; _sprite.faces[ i++ ] = 3;
|
|
|
+
|
|
|
+ _sprite.vertexBuffer = _gl.createBuffer();
|
|
|
+ _sprite.elementBuffer = _gl.createBuffer();
|
|
|
+
|
|
|
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
|
|
|
+ _gl.bufferData( _gl.ARRAY_BUFFER, _sprite.vertices, _gl.STATIC_DRAW );
|
|
|
+
|
|
|
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
|
|
|
+ _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _sprite.faces, _gl.STATIC_DRAW );
|
|
|
+
|
|
|
+ _sprite.program = createProgram( THREE.ShaderSprite[ "sprite" ] );
|
|
|
+
|
|
|
+ _sprite.attributes = {};
|
|
|
+ _sprite.uniforms = {};
|
|
|
+
|
|
|
+ _sprite.attributes.position = _gl.getAttribLocation ( _sprite.program, "position" );
|
|
|
+ _sprite.attributes.uv = _gl.getAttribLocation ( _sprite.program, "uv" );
|
|
|
+
|
|
|
+ _sprite.uniforms.uvOffset = _gl.getUniformLocation( _sprite.program, "uvOffset" );
|
|
|
+ _sprite.uniforms.uvScale = _gl.getUniformLocation( _sprite.program, "uvScale" );
|
|
|
+
|
|
|
+ _sprite.uniforms.rotation = _gl.getUniformLocation( _sprite.program, "rotation" );
|
|
|
+ _sprite.uniforms.scale = _gl.getUniformLocation( _sprite.program, "scale" );
|
|
|
+ _sprite.uniforms.alignment = _gl.getUniformLocation( _sprite.program, "alignment" );
|
|
|
+
|
|
|
+ _sprite.uniforms.color = _gl.getUniformLocation( _sprite.program, "color" );
|
|
|
+ _sprite.uniforms.map = _gl.getUniformLocation( _sprite.program, "map" );
|
|
|
+ _sprite.uniforms.opacity = _gl.getUniformLocation( _sprite.program, "opacity" );
|
|
|
+
|
|
|
+ _sprite.uniforms.useScreenCoordinates = _gl.getUniformLocation( _sprite.program, "useScreenCoordinates" );
|
|
|
+ _sprite.uniforms.affectedByDistance = _gl.getUniformLocation( _sprite.program, "affectedByDistance" );
|
|
|
+ _sprite.uniforms.screenPosition = _gl.getUniformLocation( _sprite.program, "screenPosition" );
|
|
|
+ _sprite.uniforms.modelViewMatrix = _gl.getUniformLocation( _sprite.program, "modelViewMatrix" );
|
|
|
+ _sprite.uniforms.projectionMatrix = _gl.getUniformLocation( _sprite.program, "projectionMatrix" );
|
|
|
+
|
|
|
+ _sprite.attributesEnabled = false;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ this.render = function ( scene, camera, viewportWidth, viewportHeight, projectionMatrixArray ) {
|
|
|
+
|
|
|
+ var o, ol, object;
|
|
|
+
|
|
|
+ var attributes = _sprite.attributes;
|
|
|
+ var uniforms = _sprite.uniforms;
|
|
|
+
|
|
|
+ var invAspect = viewportHeight / viewportWidth;
|
|
|
+
|
|
|
+ var size, scale = [];
|
|
|
+ var screenPosition;
|
|
|
+ var halfViewportWidth = viewportWidth * 0.5;
|
|
|
+ var halfViewportHeight = viewportHeight * 0.5;
|
|
|
+
|
|
|
+ var mergeWith3D = true;
|
|
|
+
|
|
|
+ // setup gl
|
|
|
+
|
|
|
+ _gl.useProgram( _sprite.program );
|
|
|
+ _currentProgram = _sprite.program;
|
|
|
+
|
|
|
+ if ( ! _sprite.attributesEnabled ) {
|
|
|
+
|
|
|
+ _gl.enableVertexAttribArray( attributes.position );
|
|
|
+ _gl.enableVertexAttribArray( attributes.uv );
|
|
|
+
|
|
|
+ _sprite.attributesEnabled = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _gl.disable( _gl.CULL_FACE );
|
|
|
+ _gl.enable( _gl.BLEND );
|
|
|
+ _gl.depthMask( true );
|
|
|
+
|
|
|
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, _sprite.vertexBuffer );
|
|
|
+ _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
|
|
|
+ _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
|
|
|
+
|
|
|
+ _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _sprite.elementBuffer );
|
|
|
+
|
|
|
+ _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, projectionMatrixArray );
|
|
|
+
|
|
|
+ _gl.activeTexture( _gl.TEXTURE0 );
|
|
|
+ _gl.uniform1i( uniforms.map, 0 );
|
|
|
+
|
|
|
+ // update positions and sort
|
|
|
+
|
|
|
+ for( o = 0, ol = scene.__webglSprites.length; o < ol; o ++ ) {
|
|
|
+
|
|
|
+ object = scene.__webglSprites[ o ];
|
|
|
+
|
|
|
+ if ( !object.visible || object.opacity === 0 ) continue;
|
|
|
+
|
|
|
+ if( !object.useScreenCoordinates ) {
|
|
|
+
|
|
|
+ object._modelViewMatrix.multiplyToArray( camera.matrixWorldInverse, object.matrixWorld, object._modelViewMatrixArray );
|
|
|
+ object.z = -object._modelViewMatrix.n34;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ object.z = -object.position.z;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ scene.__webglSprites.sort( painterSort );
|
|
|
+
|
|
|
+ // render all sprites
|
|
|
+
|
|
|
+ for ( o = 0, ol = scene.__webglSprites.length; o < ol; o ++ ) {
|
|
|
+
|
|
|
+ object = scene.__webglSprites[ o ];
|
|
|
+
|
|
|
+ if ( !object.visible || object.opacity === 0 ) continue;
|
|
|
+
|
|
|
+ if ( object.map && object.map.image && object.map.image.width ) {
|
|
|
+
|
|
|
+ if ( object.useScreenCoordinates ) {
|
|
|
+
|
|
|
+ _gl.uniform1i( uniforms.useScreenCoordinates, 1 );
|
|
|
+ _gl.uniform3f( uniforms.screenPosition, ( object.position.x - halfViewportWidth ) / halfViewportWidth,
|
|
|
+ ( halfViewportHeight - object.position.y ) / halfViewportHeight,
|
|
|
+ Math.max( 0, Math.min( 1, object.position.z )));
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ _gl.uniform1i( uniforms.useScreenCoordinates, 0 );
|
|
|
+ _gl.uniform1i( uniforms.affectedByDistance, object.affectedByDistance ? 1 : 0 );
|
|
|
+ _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrixArray );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ size = object.map.image.width / ( object.scaleByViewport ? viewportHeight : 1 );
|
|
|
+
|
|
|
+ scale[ 0 ] = size * invAspect * object.scale.x;
|
|
|
+ scale[ 1 ] = size * object.scale.y;
|
|
|
+
|
|
|
+ _gl.uniform2f( uniforms.uvScale, object.uvScale.x, object.uvScale.y );
|
|
|
+ _gl.uniform2f( uniforms.uvOffset, object.uvOffset.x, object.uvOffset.y );
|
|
|
+ _gl.uniform2f( uniforms.alignment, object.alignment.x, object.alignment.y );
|
|
|
+
|
|
|
+ _gl.uniform1f( uniforms.opacity, object.opacity );
|
|
|
+ _gl.uniform3f( uniforms.color, object.color.r, object.color.g, object.color.b );
|
|
|
+
|
|
|
+ _gl.uniform1f( uniforms.rotation, object.rotation );
|
|
|
+ _gl.uniform2fv( uniforms.scale, scale );
|
|
|
+
|
|
|
+ if ( object.mergeWith3D && !mergeWith3D ) {
|
|
|
+
|
|
|
+ _gl.enable( _gl.DEPTH_TEST );
|
|
|
+ mergeWith3D = true;
|
|
|
+
|
|
|
+ } else if ( !object.mergeWith3D && mergeWith3D ) {
|
|
|
+
|
|
|
+ _gl.disable( _gl.DEPTH_TEST );
|
|
|
+ mergeWith3D = false;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ _renderer.setBlending( object.blending );
|
|
|
+ _renderer.setTexture( object.map, 0 );
|
|
|
+
|
|
|
+ _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // restore gl
|
|
|
+
|
|
|
+ _gl.enable( _gl.CULL_FACE );
|
|
|
+ _gl.enable( _gl.DEPTH_TEST );
|
|
|
+ _gl.depthMask( true );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ function createProgram ( shader ) {
|
|
|
+
|
|
|
+ var program = _gl.createProgram();
|
|
|
+
|
|
|
+ var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
|
|
|
+ var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
|
|
|
+
|
|
|
+ _gl.shaderSource( fragmentShader, shader.fragmentShader );
|
|
|
+ _gl.shaderSource( vertexShader, shader.vertexShader );
|
|
|
+
|
|
|
+ _gl.compileShader( fragmentShader );
|
|
|
+ _gl.compileShader( vertexShader );
|
|
|
+
|
|
|
+ _gl.attachShader( program, fragmentShader );
|
|
|
+ _gl.attachShader( program, vertexShader );
|
|
|
+
|
|
|
+ _gl.linkProgram( program );
|
|
|
+
|
|
|
+ return program;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ function painterSort ( a, b ) {
|
|
|
+
|
|
|
+ return b.z - a.z;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+};
|