LensFlarePlugin.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * @author mikael emtinger / http://gomo.se/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. THREE.LensFlarePlugin = function ( ) {
  6. var _gl, _renderer, _precision, _lensFlare = {};
  7. this.init = function ( renderer ) {
  8. _gl = renderer.context;
  9. _renderer = renderer;
  10. _precision = renderer.getPrecision();
  11. _lensFlare.vertices = new Float32Array( 8 + 8 );
  12. _lensFlare.faces = new Uint16Array( 6 );
  13. var i = 0;
  14. _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex
  15. _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc.
  16. _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1;
  17. _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0;
  18. _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1;
  19. _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1;
  20. _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1;
  21. _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1;
  22. i = 0;
  23. _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2;
  24. _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3;
  25. // buffers
  26. _lensFlare.vertexBuffer = _gl.createBuffer();
  27. _lensFlare.elementBuffer = _gl.createBuffer();
  28. _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
  29. _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW );
  30. _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
  31. _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW );
  32. // textures
  33. _lensFlare.tempTexture = _gl.createTexture();
  34. _lensFlare.occlusionTexture = _gl.createTexture();
  35. _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
  36. _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null );
  37. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
  38. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
  39. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
  40. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
  41. _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
  42. _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null );
  43. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
  44. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
  45. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST );
  46. _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST );
  47. if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) {
  48. _lensFlare.hasVertexTexture = false;
  49. _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision );
  50. } else {
  51. _lensFlare.hasVertexTexture = true;
  52. _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision );
  53. }
  54. _lensFlare.attributes = {};
  55. _lensFlare.uniforms = {};
  56. _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" );
  57. _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" );
  58. _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" );
  59. _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" );
  60. _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" );
  61. _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" );
  62. _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" );
  63. _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" );
  64. _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" );
  65. _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" );
  66. };
  67. /*
  68. * Render lens flares
  69. * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
  70. * reads these back and calculates occlusion.
  71. * Then _lensFlare.update_lensFlares() is called to re-position and
  72. * update transparency of flares. Then they are rendered.
  73. *
  74. */
  75. this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
  76. var flares = scene.__webglFlares,
  77. nFlares = flares.length;
  78. if ( ! nFlares ) return;
  79. var tempPosition = new THREE.Vector3();
  80. var invAspect = viewportHeight / viewportWidth,
  81. halfViewportWidth = viewportWidth * 0.5,
  82. halfViewportHeight = viewportHeight * 0.5;
  83. var size = 16 / viewportHeight,
  84. scale = new THREE.Vector2( size * invAspect, size );
  85. var screenPosition = new THREE.Vector3( 1, 1, 0 ),
  86. screenPositionPixels = new THREE.Vector2( 1, 1 );
  87. var uniforms = _lensFlare.uniforms,
  88. attributes = _lensFlare.attributes;
  89. // set _lensFlare program and reset blending
  90. _gl.useProgram( _lensFlare.program );
  91. _gl.enableVertexAttribArray( _lensFlare.attributes.vertex );
  92. _gl.enableVertexAttribArray( _lensFlare.attributes.uv );
  93. // loop through all lens flares to update their occlusion and positions
  94. // setup gl and common used attribs/unforms
  95. _gl.uniform1i( uniforms.occlusionMap, 0 );
  96. _gl.uniform1i( uniforms.map, 1 );
  97. _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer );
  98. _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 );
  99. _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 );
  100. _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer );
  101. _gl.disable( _gl.CULL_FACE );
  102. _gl.depthMask( false );
  103. var i, j, jl, flare, sprite;
  104. for ( i = 0; i < nFlares; i ++ ) {
  105. size = 16 / viewportHeight;
  106. scale.set( size * invAspect, size );
  107. // calc object screen position
  108. flare = flares[ i ];
  109. tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );
  110. tempPosition.multiplyMatrix4( camera.matrixWorldInverse );
  111. tempPosition.multiplyMatrix4( camera.projectionMatrix );
  112. // setup arrays for gl programs
  113. screenPosition.copy( tempPosition )
  114. screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;
  115. screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;
  116. // screen cull
  117. if ( _lensFlare.hasVertexTexture || (
  118. screenPositionPixels.x > 0 &&
  119. screenPositionPixels.x < viewportWidth &&
  120. screenPositionPixels.y > 0 &&
  121. screenPositionPixels.y < viewportHeight ) ) {
  122. // save current RGB to temp texture
  123. _gl.activeTexture( _gl.TEXTURE1 );
  124. _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
  125. _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
  126. // render pink quad
  127. _gl.uniform1i( uniforms.renderType, 0 );
  128. _gl.uniform2f( uniforms.scale, scale.x, scale.y );
  129. _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
  130. _gl.disable( _gl.BLEND );
  131. _gl.enable( _gl.DEPTH_TEST );
  132. _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
  133. // copy result to occlusionMap
  134. _gl.activeTexture( _gl.TEXTURE0 );
  135. _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture );
  136. _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
  137. // restore graphics
  138. _gl.uniform1i( uniforms.renderType, 1 );
  139. _gl.disable( _gl.DEPTH_TEST );
  140. _gl.activeTexture( _gl.TEXTURE1 );
  141. _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture );
  142. _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
  143. // update object positions
  144. flare.positionScreen.copy( screenPosition )
  145. if ( flare.customUpdateCallback ) {
  146. flare.customUpdateCallback( flare );
  147. } else {
  148. flare.updateLensFlares();
  149. }
  150. // render flares
  151. _gl.uniform1i( uniforms.renderType, 2 );
  152. _gl.enable( _gl.BLEND );
  153. for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
  154. sprite = flare.lensFlares[ j ];
  155. if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
  156. screenPosition.x = sprite.x;
  157. screenPosition.y = sprite.y;
  158. screenPosition.z = sprite.z;
  159. size = sprite.size * sprite.scale / viewportHeight;
  160. scale.x = size * invAspect;
  161. scale.y = size;
  162. _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
  163. _gl.uniform2f( uniforms.scale, scale.x, scale.y );
  164. _gl.uniform1f( uniforms.rotation, sprite.rotation );
  165. _gl.uniform1f( uniforms.opacity, sprite.opacity );
  166. _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
  167. _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
  168. _renderer.setTexture( sprite.texture, 1 );
  169. _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 );
  170. }
  171. }
  172. }
  173. }
  174. // restore gl
  175. _gl.enable( _gl.CULL_FACE );
  176. _gl.enable( _gl.DEPTH_TEST );
  177. _gl.depthMask( true );
  178. };
  179. function createProgram ( shader, precision ) {
  180. var program = _gl.createProgram();
  181. var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER );
  182. var vertexShader = _gl.createShader( _gl.VERTEX_SHADER );
  183. var prefix = "precision " + precision + " float;\n";
  184. _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
  185. _gl.shaderSource( vertexShader, prefix + shader.vertexShader );
  186. _gl.compileShader( fragmentShader );
  187. _gl.compileShader( vertexShader );
  188. _gl.attachShader( program, fragmentShader );
  189. _gl.attachShader( program, vertexShader );
  190. _gl.linkProgram( program );
  191. return program;
  192. };
  193. };