SpritePlugin.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. THREE.SpritePlugin = function () {
  6. var _gl, _renderer, _texture;
  7. var vertices, faces, vertexBuffer, elementBuffer;
  8. var program, attributes, uniforms;
  9. this.init = function ( renderer ) {
  10. _gl = renderer.context;
  11. _renderer = renderer;
  12. vertices = new Float32Array( [
  13. - 0.5, - 0.5, 0, 0,
  14. 0.5, - 0.5, 1, 0,
  15. 0.5, 0.5, 1, 1,
  16. - 0.5, 0.5, 0, 1
  17. ] );
  18. faces = new Uint16Array( [
  19. 0, 1, 2,
  20. 0, 2, 3
  21. ] );
  22. vertexBuffer = _gl.createBuffer();
  23. elementBuffer = _gl.createBuffer();
  24. _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer );
  25. _gl.bufferData( _gl.ARRAY_BUFFER, vertices, _gl.STATIC_DRAW );
  26. _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  27. _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faces, _gl.STATIC_DRAW );
  28. program = createProgram();
  29. attributes = {
  30. position: _gl.getAttribLocation ( program, 'position' ),
  31. uv: _gl.getAttribLocation ( program, 'uv' )
  32. };
  33. uniforms = {
  34. uvOffset: _gl.getUniformLocation( program, 'uvOffset' ),
  35. uvScale: _gl.getUniformLocation( program, 'uvScale' ),
  36. rotation: _gl.getUniformLocation( program, 'rotation' ),
  37. scale: _gl.getUniformLocation( program, 'scale' ),
  38. color: _gl.getUniformLocation( program, 'color' ),
  39. map: _gl.getUniformLocation( program, 'map' ),
  40. opacity: _gl.getUniformLocation( program, 'opacity' ),
  41. modelViewMatrix: _gl.getUniformLocation( program, 'modelViewMatrix' ),
  42. projectionMatrix: _gl.getUniformLocation( program, 'projectionMatrix' ),
  43. fogType: _gl.getUniformLocation( program, 'fogType' ),
  44. fogDensity: _gl.getUniformLocation( program, 'fogDensity' ),
  45. fogNear: _gl.getUniformLocation( program, 'fogNear' ),
  46. fogFar: _gl.getUniformLocation( program, 'fogFar' ),
  47. fogColor: _gl.getUniformLocation( program, 'fogColor' ),
  48. alphaTest: _gl.getUniformLocation( program, 'alphaTest' )
  49. };
  50. var canvas = document.createElement( 'canvas' );
  51. canvas.width = 8;
  52. canvas.height = 8;
  53. var context = canvas.getContext( '2d' );
  54. context.fillStyle = '#ffffff';
  55. context.fillRect( 0, 0, canvas.width, canvas.height );
  56. _texture = new THREE.Texture( canvas );
  57. _texture.needsUpdate = true;
  58. };
  59. this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
  60. var sprites = scene.__webglSprites,
  61. nSprites = sprites.length;
  62. if ( ! nSprites ) return;
  63. // setup gl
  64. _gl.useProgram( program );
  65. _gl.enableVertexAttribArray( attributes.position );
  66. _gl.enableVertexAttribArray( attributes.uv );
  67. _gl.disable( _gl.CULL_FACE );
  68. _gl.enable( _gl.BLEND );
  69. _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer );
  70. _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 );
  71. _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
  72. _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
  73. _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
  74. _gl.activeTexture( _gl.TEXTURE0 );
  75. _gl.uniform1i( uniforms.map, 0 );
  76. var oldFogType = 0;
  77. var sceneFogType = 0;
  78. var fog = scene.fog;
  79. if ( fog ) {
  80. _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
  81. if ( fog instanceof THREE.Fog ) {
  82. _gl.uniform1f( uniforms.fogNear, fog.near );
  83. _gl.uniform1f( uniforms.fogFar, fog.far );
  84. _gl.uniform1i( uniforms.fogType, 1 );
  85. oldFogType = 1;
  86. sceneFogType = 1;
  87. } else if ( fog instanceof THREE.FogExp2 ) {
  88. _gl.uniform1f( uniforms.fogDensity, fog.density );
  89. _gl.uniform1i( uniforms.fogType, 2 );
  90. oldFogType = 2;
  91. sceneFogType = 2;
  92. }
  93. } else {
  94. _gl.uniform1i( uniforms.fogType, 0 );
  95. oldFogType = 0;
  96. sceneFogType = 0;
  97. }
  98. // update positions and sort
  99. var i, sprite, material, fogType, scale = [];
  100. for( i = 0; i < nSprites; i ++ ) {
  101. sprite = sprites[ i ];
  102. material = sprite.material;
  103. if ( sprite.visible === false ) continue;
  104. sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
  105. sprite.z = - sprite._modelViewMatrix.elements[ 14 ];
  106. }
  107. sprites.sort( painterSortStable );
  108. // render all sprites
  109. for( i = 0; i < nSprites; i ++ ) {
  110. sprite = sprites[ i ];
  111. if ( sprite.visible === false ) continue;
  112. material = sprite.material;
  113. _gl.uniform1f( uniforms.alphaTest, material.alphaTest );
  114. _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );
  115. scale[ 0 ] = sprite.scale.x;
  116. scale[ 1 ] = sprite.scale.y;
  117. if ( scene.fog && material.fog ) {
  118. fogType = sceneFogType;
  119. } else {
  120. fogType = 0;
  121. }
  122. if ( oldFogType !== fogType ) {
  123. _gl.uniform1i( uniforms.fogType, fogType );
  124. oldFogType = fogType;
  125. }
  126. if ( material.map !== null ) {
  127. _gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
  128. _gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
  129. } else {
  130. _gl.uniform2f( uniforms.uvOffset, 0, 0 );
  131. _gl.uniform2f( uniforms.uvScale, 1, 1 );
  132. }
  133. _gl.uniform1f( uniforms.opacity, material.opacity );
  134. _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
  135. _gl.uniform1f( uniforms.rotation, material.rotation );
  136. _gl.uniform2fv( uniforms.scale, scale );
  137. _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
  138. _renderer.setDepthTest( material.depthTest );
  139. _renderer.setDepthWrite( material.depthWrite );
  140. if ( material.map && material.map.image && material.map.image.width ) {
  141. _renderer.setTexture( material.map, 0 );
  142. } else {
  143. _renderer.setTexture( _texture, 0 );
  144. }
  145. _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
  146. }
  147. // restore gl
  148. _gl.enable( _gl.CULL_FACE );
  149. };
  150. function createProgram () {
  151. var program = _gl.createProgram();
  152. var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
  153. var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
  154. _gl.shaderSource( vertexShader, [
  155. 'precision ' + _renderer.getPrecision() + ' float;',
  156. 'uniform mat4 modelViewMatrix;',
  157. 'uniform mat4 projectionMatrix;',
  158. 'uniform float rotation;',
  159. 'uniform vec2 scale;',
  160. 'uniform vec2 uvOffset;',
  161. 'uniform vec2 uvScale;',
  162. 'attribute vec2 position;',
  163. 'attribute vec2 uv;',
  164. 'varying vec2 vUV;',
  165. 'void main() {',
  166. 'vUV = uvOffset + uv * uvScale;',
  167. 'vec2 alignedPosition = position * scale;',
  168. 'vec2 rotatedPosition;',
  169. 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
  170. 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
  171. 'vec4 finalPosition;',
  172. 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
  173. 'finalPosition.xy += rotatedPosition;',
  174. 'finalPosition = projectionMatrix * finalPosition;',
  175. 'gl_Position = finalPosition;',
  176. '}'
  177. ].join( '\n' ) );
  178. _gl.shaderSource( fragmentShader, [
  179. 'precision ' + _renderer.getPrecision() + ' float;',
  180. 'uniform vec3 color;',
  181. 'uniform sampler2D map;',
  182. 'uniform float opacity;',
  183. 'uniform int fogType;',
  184. 'uniform vec3 fogColor;',
  185. 'uniform float fogDensity;',
  186. 'uniform float fogNear;',
  187. 'uniform float fogFar;',
  188. 'uniform float alphaTest;',
  189. 'varying vec2 vUV;',
  190. 'void main() {',
  191. 'vec4 texture = texture2D( map, vUV );',
  192. 'if ( texture.a < alphaTest ) discard;',
  193. 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
  194. 'if ( fogType > 0 ) {',
  195. 'float depth = gl_FragCoord.z / gl_FragCoord.w;',
  196. 'float fogFactor = 0.0;',
  197. 'if ( fogType == 1 ) {',
  198. 'fogFactor = smoothstep( fogNear, fogFar, depth );',
  199. '} else {',
  200. 'const float LOG2 = 1.442695;',
  201. 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
  202. 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
  203. '}',
  204. 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',
  205. '}',
  206. '}'
  207. ].join( '\n' ) );
  208. _gl.compileShader( vertexShader );
  209. _gl.compileShader( fragmentShader );
  210. _gl.attachShader( program, vertexShader );
  211. _gl.attachShader( program, fragmentShader );
  212. _gl.linkProgram( program );
  213. return program;
  214. };
  215. function painterSortStable ( a, b ) {
  216. if ( a.z !== b.z ) {
  217. return b.z - a.z;
  218. } else {
  219. return b.id - a.id;
  220. }
  221. };
  222. };