WebGLDeferredRenderer.js 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. /**
  2. * @author alteredq / http://alteredqualia.com/
  3. * @author MPanknin / http://www.redplant.de/
  4. */
  5. THREE.WebGLDeferredRenderer = function ( parameters ) {
  6. var _this = this;
  7. var pixelWidth = parameters.width !== undefined ? parameters.width : 800;
  8. var pixelHeight = parameters.height !== undefined ? parameters.height : 600;
  9. var currentScale = parameters.scale !== undefined ? parameters.scale : 1;
  10. var devicePixelRatio = self.devicePixelRatio !== undefined ? self.devicePixelRatio : 1;
  11. var fullWidth = pixelWidth * devicePixelRatio;
  12. var fullHeight = pixelHeight * devicePixelRatio;
  13. var scaledWidth = Math.floor( currentScale * fullWidth );
  14. var scaledHeight = Math.floor( currentScale * fullHeight );
  15. var brightness = parameters.brightness !== undefined ? parameters.brightness : 1;
  16. var tonemapping = parameters.tonemapping !== undefined ? parameters.tonemapping : THREE.SimpleOperator;
  17. var antialias = parameters.antialias !== undefined ? parameters.antialias : false;
  18. this.renderer = parameters.renderer;
  19. if ( this.renderer === undefined ) {
  20. this.renderer = new THREE.WebGLRenderer( { antialias: false } );
  21. this.renderer.setSize( fullWidth, fullHeight );
  22. this.renderer.setClearColor( 0x000000, 0 );
  23. this.renderer.autoClear = false;
  24. }
  25. this.domElement = this.renderer.domElement;
  26. //
  27. var gl = this.renderer.context;
  28. //
  29. var currentCamera = null;
  30. var projectionMatrixInverse = new THREE.Matrix4();
  31. var positionVS = new THREE.Vector3();
  32. var directionVS = new THREE.Vector3();
  33. var tempVS = new THREE.Vector3();
  34. var rightVS = new THREE.Vector3();
  35. var normalVS = new THREE.Vector3();
  36. var upVS = new THREE.Vector3();
  37. //
  38. var geometryLightSphere = new THREE.SphereGeometry( 1, 16, 8 );
  39. var geometryLightPlane = new THREE.PlaneBufferGeometry( 2, 2 );
  40. var black = new THREE.Color( 0x000000 );
  41. var colorShader = THREE.ShaderDeferred[ "color" ];
  42. var normalDepthShader = THREE.ShaderDeferred[ "normalDepth" ];
  43. //
  44. var emissiveLightShader = THREE.ShaderDeferred[ "emissiveLight" ];
  45. var pointLightShader = THREE.ShaderDeferred[ "pointLight" ];
  46. var spotLightShader = THREE.ShaderDeferred[ "spotLight" ];
  47. var directionalLightShader = THREE.ShaderDeferred[ "directionalLight" ];
  48. var hemisphereLightShader = THREE.ShaderDeferred[ "hemisphereLight" ];
  49. var areaLightShader = THREE.ShaderDeferred[ "areaLight" ];
  50. var compositeShader = THREE.ShaderDeferred[ "composite" ];
  51. //
  52. var compColor, compNormal, compDepth, compLight, compFinal;
  53. var passColor, passNormal, passDepth, passLightFullscreen, passLightProxy, compositePass;
  54. var effectFXAA;
  55. //
  56. var lightSceneFullscreen, lightSceneProxy;
  57. //
  58. var resizableMaterials = [];
  59. //
  60. var invisibleMaterial = new THREE.ShaderMaterial();
  61. invisibleMaterial.visible = false;
  62. var defaultNormalDepthMaterial = new THREE.ShaderMaterial( {
  63. uniforms: THREE.UniformsUtils.clone( normalDepthShader.uniforms ),
  64. vertexShader: normalDepthShader.vertexShader,
  65. fragmentShader: normalDepthShader.fragmentShader,
  66. blending: THREE.NoBlending
  67. } );
  68. //
  69. var initDeferredMaterials = function ( object ) {
  70. if ( object.material instanceof THREE.MeshFaceMaterial ) {
  71. var colorMaterials = [];
  72. var normalDepthMaterials = [];
  73. var materials = object.material.materials;
  74. for ( var i = 0, il = materials.length; i < il; i ++ ) {
  75. var deferredMaterials = createDeferredMaterials( materials[ i ] );
  76. if ( deferredMaterials.transparent ) {
  77. colorMaterials.push( invisibleMaterial );
  78. normalDepthMaterials.push( invisibleMaterial );
  79. } else {
  80. colorMaterials.push( deferredMaterials.colorMaterial );
  81. normalDepthMaterials.push( deferredMaterials.normalDepthMaterial );
  82. }
  83. }
  84. object.userData.colorMaterial = new THREE.MeshFaceMaterial( colorMaterials );
  85. object.userData.normalDepthMaterial = new THREE.MeshFaceMaterial( normalDepthMaterials );
  86. } else {
  87. var deferredMaterials = createDeferredMaterials( object.material );
  88. object.userData.colorMaterial = deferredMaterials.colorMaterial;
  89. object.userData.normalDepthMaterial = deferredMaterials.normalDepthMaterial;
  90. object.userData.transparent = deferredMaterials.transparent;
  91. }
  92. };
  93. var createDeferredMaterials = function ( originalMaterial ) {
  94. var deferredMaterials = {};
  95. // color material
  96. // -----------------
  97. // diffuse color
  98. // specular color
  99. // shininess
  100. // diffuse map
  101. // vertex colors
  102. // alphaTest
  103. // morphs
  104. var uniforms = THREE.UniformsUtils.clone( colorShader.uniforms );
  105. var defines = { "USE_MAP": !! originalMaterial.map, "USE_ENVMAP": !! originalMaterial.envMap, "GAMMA_INPUT": true };
  106. var material = new THREE.ShaderMaterial( {
  107. fragmentShader: colorShader.fragmentShader,
  108. vertexShader: colorShader.vertexShader,
  109. uniforms: uniforms,
  110. defines: defines,
  111. shading: originalMaterial.shading
  112. } );
  113. if ( originalMaterial instanceof THREE.MeshBasicMaterial ) {
  114. var diffuse = black;
  115. var emissive = originalMaterial.color;
  116. } else {
  117. var diffuse = originalMaterial.color;
  118. var emissive = originalMaterial.emissive !== undefined ? originalMaterial.emissive : black;
  119. }
  120. var specular = originalMaterial.specular !== undefined ? originalMaterial.specular : black;
  121. var shininess = originalMaterial.shininess !== undefined ? originalMaterial.shininess : 1;
  122. var wrapAround = originalMaterial.wrapAround !== undefined ? ( originalMaterial.wrapAround ? -1 : 1 ) : 1;
  123. var additiveSpecular = originalMaterial.metal !== undefined ? ( originalMaterial.metal ? 1 : -1 ) : -1;
  124. uniforms.emissive.value.copyGammaToLinear( emissive );
  125. uniforms.diffuse.value.copyGammaToLinear( diffuse );
  126. uniforms.specular.value.copyGammaToLinear( specular );
  127. uniforms.shininess.value = shininess;
  128. uniforms.wrapAround.value = wrapAround;
  129. uniforms.additiveSpecular.value = additiveSpecular;
  130. uniforms.map.value = originalMaterial.map;
  131. if ( originalMaterial.envMap ) {
  132. uniforms.envMap.value = originalMaterial.envMap;
  133. uniforms.useRefract.value = originalMaterial.envMap.mapping instanceof THREE.CubeRefractionMapping;
  134. uniforms.refractionRatio.value = originalMaterial.refractionRatio;
  135. uniforms.combine.value = originalMaterial.combine;
  136. uniforms.reflectivity.value = originalMaterial.reflectivity;
  137. uniforms.flipEnvMap.value = ( originalMaterial.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1;
  138. uniforms.samplerNormalDepth.value = compNormalDepth.renderTarget2;
  139. uniforms.viewWidth.value = scaledWidth;
  140. uniforms.viewHeight.value = scaledHeight;
  141. resizableMaterials.push( { "material": material } );
  142. }
  143. material.vertexColors = originalMaterial.vertexColors;
  144. material.morphTargets = originalMaterial.morphTargets;
  145. material.morphNormals = originalMaterial.morphNormals;
  146. material.skinning = originalMaterial.skinning;
  147. material.alphaTest = originalMaterial.alphaTest;
  148. material.wireframe = originalMaterial.wireframe;
  149. // uv repeat and offset setting priorities
  150. // 1. color map
  151. // 2. specular map
  152. // 3. normal map
  153. // 4. bump map
  154. var uvScaleMap;
  155. if ( originalMaterial.map ) {
  156. uvScaleMap = originalMaterial.map;
  157. } else if ( originalMaterial.specularMap ) {
  158. uvScaleMap = originalMaterial.specularMap;
  159. } else if ( originalMaterial.normalMap ) {
  160. uvScaleMap = originalMaterial.normalMap;
  161. } else if ( originalMaterial.bumpMap ) {
  162. uvScaleMap = originalMaterial.bumpMap;
  163. }
  164. if ( uvScaleMap !== undefined ) {
  165. var offset = uvScaleMap.offset;
  166. var repeat = uvScaleMap.repeat;
  167. uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
  168. }
  169. deferredMaterials.colorMaterial = material;
  170. // normal + depth material
  171. // -----------------
  172. // vertex normals
  173. // morph normals
  174. // bump map
  175. // bump scale
  176. // clip depth
  177. if ( originalMaterial.morphTargets || originalMaterial.skinning || originalMaterial.bumpMap ) {
  178. var uniforms = THREE.UniformsUtils.clone( normalDepthShader.uniforms );
  179. var defines = { "USE_BUMPMAP": !!originalMaterial.bumpMap };
  180. var normalDepthMaterial = new THREE.ShaderMaterial( {
  181. uniforms: uniforms,
  182. vertexShader: normalDepthShader.vertexShader,
  183. fragmentShader: normalDepthShader.fragmentShader,
  184. shading: originalMaterial.shading,
  185. defines: defines,
  186. blending: THREE.NoBlending
  187. } );
  188. normalDepthMaterial.morphTargets = originalMaterial.morphTargets;
  189. normalDepthMaterial.morphNormals = originalMaterial.morphNormals;
  190. normalDepthMaterial.skinning = originalMaterial.skinning;
  191. if ( originalMaterial.bumpMap ) {
  192. uniforms.bumpMap.value = originalMaterial.bumpMap;
  193. uniforms.bumpScale.value = originalMaterial.bumpScale;
  194. var offset = originalMaterial.bumpMap.offset;
  195. var repeat = originalMaterial.bumpMap.repeat;
  196. uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y );
  197. }
  198. } else {
  199. var normalDepthMaterial = defaultNormalDepthMaterial.clone();
  200. }
  201. normalDepthMaterial.wireframe = originalMaterial.wireframe;
  202. normalDepthMaterial.vertexColors = originalMaterial.vertexColors;
  203. deferredMaterials.normalDepthMaterial = normalDepthMaterial;
  204. //
  205. deferredMaterials.transparent = originalMaterial.transparent;
  206. return deferredMaterials;
  207. };
  208. var updatePointLightProxy = function ( lightProxy ) {
  209. var light = lightProxy.userData.originalLight;
  210. var uniforms = lightProxy.material.uniforms;
  211. // skip infinite pointlights
  212. // right now you can't switch between infinite and finite pointlights
  213. // it's just too messy as they use different proxies
  214. var distance = light.distance;
  215. if ( distance > 0 ) {
  216. lightProxy.scale.set( 1, 1, 1 ).multiplyScalar( distance );
  217. uniforms[ "lightRadius" ].value = distance;
  218. positionVS.setFromMatrixPosition( light.matrixWorld );
  219. positionVS.applyMatrix4( currentCamera.matrixWorldInverse );
  220. uniforms[ "lightPositionVS" ].value.copy( positionVS );
  221. lightProxy.position.setFromMatrixPosition( light.matrixWorld );
  222. } else {
  223. uniforms[ "lightRadius" ].value = Infinity;
  224. }
  225. // linear space colors
  226. var intensity = light.intensity * light.intensity;
  227. uniforms[ "lightIntensity" ].value = intensity;
  228. uniforms[ "lightColor" ].value.copyGammaToLinear( light.color );
  229. };
  230. var createDeferredPointLight = function ( light ) {
  231. // setup light material
  232. var materialLight = new THREE.ShaderMaterial( {
  233. uniforms: THREE.UniformsUtils.clone( pointLightShader.uniforms ),
  234. vertexShader: pointLightShader.vertexShader,
  235. fragmentShader: pointLightShader.fragmentShader,
  236. blending: THREE.AdditiveBlending,
  237. depthWrite: false,
  238. transparent: true,
  239. side: THREE.BackSide
  240. } );
  241. // infinite pointlights use full-screen quad proxy
  242. // regular pointlights use sphere proxy
  243. var geometry;
  244. if ( light.distance > 0 ) {
  245. geometry = geometryLightSphere;
  246. } else {
  247. geometry = geometryLightPlane;
  248. materialLight.depthTest = false;
  249. materialLight.side = THREE.FrontSide;
  250. }
  251. materialLight.uniforms[ "viewWidth" ].value = scaledWidth;
  252. materialLight.uniforms[ "viewHeight" ].value = scaledHeight;
  253. materialLight.uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  254. materialLight.uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
  255. // create light proxy mesh
  256. var meshLight = new THREE.Mesh( geometry, materialLight );
  257. // keep reference for color and intensity updates
  258. meshLight.userData.originalLight = light;
  259. // keep reference for size reset
  260. resizableMaterials.push( { "material": materialLight } );
  261. // sync proxy uniforms to the original light
  262. updatePointLightProxy( meshLight );
  263. return meshLight;
  264. };
  265. var updateSpotLightProxy = function ( lightProxy ) {
  266. var light = lightProxy.userData.originalLight;
  267. var uniforms = lightProxy.material.uniforms;
  268. var viewMatrix = currentCamera.matrixWorldInverse;
  269. var modelMatrix = light.matrixWorld;
  270. positionVS.setFromMatrixPosition( modelMatrix );
  271. positionVS.applyMatrix4( viewMatrix );
  272. directionVS.setFromMatrixPosition( modelMatrix );
  273. tempVS.setFromMatrixPosition( light.target.matrixWorld );
  274. directionVS.sub( tempVS );
  275. directionVS.normalize();
  276. directionVS.transformDirection( viewMatrix );
  277. uniforms[ "lightPositionVS" ].value.copy( positionVS );
  278. uniforms[ "lightDirectionVS" ].value.copy( directionVS );
  279. uniforms[ "lightAngle" ].value = light.angle;
  280. uniforms[ "lightDistance" ].value = light.distance;
  281. // linear space colors
  282. var intensity = light.intensity * light.intensity;
  283. uniforms[ "lightIntensity" ].value = intensity;
  284. uniforms[ "lightColor" ].value.copyGammaToLinear( light.color );
  285. };
  286. var createDeferredSpotLight = function ( light ) {
  287. // setup light material
  288. var uniforms = THREE.UniformsUtils.clone( spotLightShader.uniforms );
  289. var materialLight = new THREE.ShaderMaterial( {
  290. uniforms: uniforms,
  291. vertexShader: spotLightShader.vertexShader,
  292. fragmentShader: spotLightShader.fragmentShader,
  293. blending: THREE.AdditiveBlending,
  294. depthWrite: false,
  295. depthTest: false,
  296. transparent: true
  297. } );
  298. uniforms[ "viewWidth" ].value = scaledWidth;
  299. uniforms[ "viewHeight" ].value = scaledHeight;
  300. uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  301. uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
  302. // create light proxy mesh
  303. var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
  304. // keep reference for color and intensity updates
  305. meshLight.userData.originalLight = light;
  306. // keep reference for size reset
  307. resizableMaterials.push( { "material": materialLight } );
  308. // sync proxy uniforms to the original light
  309. updateSpotLightProxy( meshLight );
  310. return meshLight;
  311. };
  312. var updateDirectionalLightProxy = function ( lightProxy ) {
  313. var light = lightProxy.userData.originalLight;
  314. var uniforms = lightProxy.material.uniforms;
  315. directionVS.setFromMatrixPosition( light.matrixWorld );
  316. tempVS.setFromMatrixPosition( light.target.matrixWorld );
  317. directionVS.sub( tempVS );
  318. directionVS.normalize();
  319. directionVS.transformDirection( currentCamera.matrixWorldInverse );
  320. uniforms[ "lightDirectionVS" ].value.copy( directionVS );
  321. // linear space colors
  322. var intensity = light.intensity * light.intensity;
  323. uniforms[ "lightIntensity" ].value = intensity;
  324. uniforms[ "lightColor" ].value.copyGammaToLinear( light.color );
  325. };
  326. var createDeferredDirectionalLight = function ( light ) {
  327. // setup light material
  328. var uniforms = THREE.UniformsUtils.clone( directionalLightShader.uniforms );
  329. var materialLight = new THREE.ShaderMaterial( {
  330. uniforms: uniforms,
  331. vertexShader: directionalLightShader.vertexShader,
  332. fragmentShader: directionalLightShader.fragmentShader,
  333. blending: THREE.AdditiveBlending,
  334. depthWrite: false,
  335. depthTest: false,
  336. transparent: true
  337. } );
  338. uniforms[ "viewWidth" ].value = scaledWidth;
  339. uniforms[ "viewHeight" ].value = scaledHeight;
  340. uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  341. uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
  342. // create light proxy mesh
  343. var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
  344. // keep reference for color and intensity updates
  345. meshLight.userData.originalLight = light;
  346. // keep reference for size reset
  347. resizableMaterials.push( { "material": materialLight } );
  348. // sync proxy uniforms to the original light
  349. updateDirectionalLightProxy( meshLight );
  350. return meshLight;
  351. };
  352. var updateHemisphereLightProxy = function ( lightProxy ) {
  353. var light = lightProxy.userData.originalLight;
  354. var uniforms = lightProxy.material.uniforms;
  355. directionVS.setFromMatrixPosition( light.matrixWorld );
  356. directionVS.normalize();
  357. directionVS.transformDirection( currentCamera.matrixWorldInverse );
  358. uniforms[ "lightDirectionVS" ].value.copy( directionVS );
  359. // linear space colors
  360. var intensity = light.intensity * light.intensity;
  361. uniforms[ "lightIntensity" ].value = intensity;
  362. uniforms[ "lightColorSky" ].value.copyGammaToLinear( light.color );
  363. uniforms[ "lightColorGround" ].value.copyGammaToLinear( light.groundColor );
  364. };
  365. var createDeferredHemisphereLight = function ( light ) {
  366. // setup light material
  367. var uniforms = THREE.UniformsUtils.clone( hemisphereLightShader.uniforms );
  368. var materialLight = new THREE.ShaderMaterial( {
  369. uniforms: uniforms,
  370. vertexShader: hemisphereLightShader.vertexShader,
  371. fragmentShader: hemisphereLightShader.fragmentShader,
  372. blending: THREE.AdditiveBlending,
  373. depthWrite: false,
  374. depthTest: false,
  375. transparent: true
  376. } );
  377. uniforms[ "viewWidth" ].value = scaledWidth;
  378. uniforms[ "viewHeight" ].value = scaledHeight;
  379. uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  380. uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
  381. // create light proxy mesh
  382. var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
  383. // keep reference for color and intensity updates
  384. meshLight.userData.originalLight = light;
  385. // keep reference for size reset
  386. resizableMaterials.push( { "material": materialLight } );
  387. // sync proxy uniforms to the original light
  388. updateHemisphereLightProxy( meshLight );
  389. return meshLight;
  390. };
  391. var updateAreaLightProxy = function ( lightProxy ) {
  392. var light = lightProxy.userData.originalLight;
  393. var uniforms = lightProxy.material.uniforms;
  394. var modelMatrix = light.matrixWorld;
  395. var viewMatrix = currentCamera.matrixWorldInverse;
  396. positionVS.setFromMatrixPosition( modelMatrix );
  397. positionVS.applyMatrix4( viewMatrix );
  398. uniforms[ "lightPositionVS" ].value.copy( positionVS );
  399. rightVS.copy( light.right );
  400. rightVS.transformDirection( modelMatrix );
  401. rightVS.transformDirection( viewMatrix );
  402. normalVS.copy( light.normal );
  403. normalVS.transformDirection( modelMatrix );
  404. normalVS.transformDirection( viewMatrix );
  405. upVS.crossVectors( rightVS, normalVS );
  406. upVS.normalize();
  407. uniforms[ "lightRightVS" ].value.copy( rightVS );
  408. uniforms[ "lightNormalVS" ].value.copy( normalVS );
  409. uniforms[ "lightUpVS" ].value.copy( upVS );
  410. uniforms[ "lightWidth" ].value = light.width;
  411. uniforms[ "lightHeight" ].value = light.height;
  412. uniforms[ "constantAttenuation" ].value = light.constantAttenuation;
  413. uniforms[ "linearAttenuation" ].value = light.linearAttenuation;
  414. uniforms[ "quadraticAttenuation" ].value = light.quadraticAttenuation;
  415. // linear space colors
  416. var intensity = light.intensity * light.intensity;
  417. uniforms[ "lightIntensity" ].value = intensity;
  418. uniforms[ "lightColor" ].value.copyGammaToLinear( light.color );
  419. };
  420. var createDeferredAreaLight = function ( light ) {
  421. // setup light material
  422. var uniforms = THREE.UniformsUtils.clone( areaLightShader.uniforms );
  423. var materialLight = new THREE.ShaderMaterial( {
  424. uniforms: uniforms,
  425. vertexShader: areaLightShader.vertexShader,
  426. fragmentShader: areaLightShader.fragmentShader,
  427. blending: THREE.AdditiveBlending,
  428. depthWrite: false,
  429. depthTest: false,
  430. transparent: true
  431. } );
  432. uniforms[ "viewWidth" ].value = scaledWidth;
  433. uniforms[ "viewHeight" ].value = scaledHeight;
  434. uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  435. uniforms[ 'samplerNormalDepth' ].value = compNormalDepth.renderTarget2;
  436. // create light proxy mesh
  437. var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
  438. // keep reference for color and intensity updates
  439. meshLight.userData.originalLight = light;
  440. // keep reference for size reset
  441. resizableMaterials.push( { "material": materialLight } );
  442. // sync proxy uniforms to the original light
  443. updateAreaLightProxy( meshLight );
  444. return meshLight;
  445. };
  446. var createDeferredEmissiveLight = function () {
  447. // setup light material
  448. var materialLight = new THREE.ShaderMaterial( {
  449. uniforms: THREE.UniformsUtils.clone( emissiveLightShader.uniforms ),
  450. vertexShader: emissiveLightShader.vertexShader,
  451. fragmentShader: emissiveLightShader.fragmentShader,
  452. depthTest: false,
  453. depthWrite: false,
  454. blending: THREE.NoBlending
  455. } );
  456. materialLight.uniforms[ "viewWidth" ].value = scaledWidth;
  457. materialLight.uniforms[ "viewHeight" ].value = scaledHeight;
  458. materialLight.uniforms[ 'samplerColor' ].value = compColor.renderTarget2;
  459. // create light proxy mesh
  460. var meshLight = new THREE.Mesh( geometryLightPlane, materialLight );
  461. // keep reference for size reset
  462. resizableMaterials.push( { "material": materialLight } );
  463. return meshLight;
  464. };
  465. var initDeferredProperties = function ( object ) {
  466. if ( object.userData.deferredInitialized ) return;
  467. if ( object.material ) initDeferredMaterials( object );
  468. if ( object instanceof THREE.PointLight ) {
  469. var proxy = createDeferredPointLight( object );
  470. if ( object.distance > 0 ) {
  471. lightSceneProxy.add( proxy );
  472. } else {
  473. lightSceneFullscreen.add( proxy );
  474. }
  475. } else if ( object instanceof THREE.SpotLight ) {
  476. var proxy = createDeferredSpotLight( object );
  477. lightSceneFullscreen.add( proxy );
  478. } else if ( object instanceof THREE.DirectionalLight ) {
  479. var proxy = createDeferredDirectionalLight( object );
  480. lightSceneFullscreen.add( proxy );
  481. } else if ( object instanceof THREE.HemisphereLight ) {
  482. var proxy = createDeferredHemisphereLight( object );
  483. lightSceneFullscreen.add( proxy );
  484. } else if ( object instanceof THREE.AreaLight ) {
  485. var proxy = createDeferredAreaLight( object );
  486. lightSceneFullscreen.add( proxy );
  487. }
  488. object.userData.deferredInitialized = true;
  489. };
  490. //
  491. var setMaterialColor = function ( object ) {
  492. if ( object.material ) {
  493. if ( object.userData.transparent ) {
  494. object.material = invisibleMaterial;
  495. } else {
  496. object.material = object.userData.colorMaterial;
  497. }
  498. }
  499. };
  500. var setMaterialNormalDepth = function ( object ) {
  501. if ( object.material ) {
  502. if ( object.userData.transparent ) {
  503. object.material = invisibleMaterial;
  504. } else {
  505. object.material = object.userData.normalDepthMaterial;
  506. }
  507. }
  508. };
  509. // external API
  510. this.setAntialias = function ( enabled ) {
  511. antialias = enabled;
  512. if ( antialias ) {
  513. effectFXAA.enabled = true;
  514. compositePass.renderToScreen = false;
  515. } else {
  516. effectFXAA.enabled = false;
  517. compositePass.renderToScreen = true;
  518. }
  519. };
  520. this.getAntialias = function () {
  521. return antialias;
  522. };
  523. this.addEffect = function ( effect, normalDepthUniform, colorUniform ) {
  524. if ( effect.material && effect.uniforms ) {
  525. if ( normalDepthUniform ) effect.uniforms[ normalDepthUniform ].value = compNormalDepth.renderTarget2;
  526. if ( colorUniform ) effect.uniforms[ colorUniform ].value = compColor.renderTarget2;
  527. if ( normalDepthUniform || colorUniform ) {
  528. resizableMaterials.push( { "material": effect.material, "normalDepth": normalDepthUniform, "color": colorUniform } );
  529. }
  530. }
  531. compFinal.insertPass( effect, -1 );
  532. };
  533. this.setScale = function ( scale ) {
  534. currentScale = scale;
  535. scaledWidth = Math.floor( currentScale * fullWidth );
  536. scaledHeight = Math.floor( currentScale * fullHeight );
  537. compNormalDepth.setSize( scaledWidth, scaledHeight );
  538. compColor.setSize( scaledWidth, scaledHeight );
  539. compLight.setSize( scaledWidth, scaledHeight );
  540. compFinal.setSize( scaledWidth, scaledHeight );
  541. compColor.renderTarget2.shareDepthFrom = compNormalDepth.renderTarget2;
  542. compLight.renderTarget2.shareDepthFrom = compNormalDepth.renderTarget2;
  543. for ( var i = 0, il = resizableMaterials.length; i < il; i ++ ) {
  544. var materialEntry = resizableMaterials[ i ];
  545. var material = materialEntry.material;
  546. var uniforms = material.uniforms;
  547. var colorLabel = materialEntry.color !== undefined ? materialEntry.color : 'samplerColor';
  548. var normalDepthLabel = materialEntry.normalDepth !== undefined ? materialEntry.normalDepth : 'samplerNormalDepth';
  549. if ( uniforms[ colorLabel ] ) uniforms[ colorLabel ].value = compColor.renderTarget2;
  550. if ( uniforms[ normalDepthLabel ] ) uniforms[ normalDepthLabel ].value = compNormalDepth.renderTarget2;
  551. if ( uniforms[ 'viewWidth' ] ) uniforms[ "viewWidth" ].value = scaledWidth;
  552. if ( uniforms[ 'viewHeight' ] ) uniforms[ "viewHeight" ].value = scaledHeight;
  553. }
  554. compositePass.uniforms[ 'samplerLight' ].value = compLight.renderTarget2;
  555. effectFXAA.uniforms[ 'resolution' ].value.set( 1 / fullWidth, 1 / fullHeight );
  556. };
  557. this.setSize = function ( width, height ) {
  558. fullWidth = width;
  559. fullHeight = height;
  560. this.renderer.setSize( fullWidth, fullHeight );
  561. this.setScale( currentScale );
  562. };
  563. //
  564. function updateLightProxy ( proxy ) {
  565. var uniforms = proxy.material.uniforms;
  566. if ( uniforms[ "matProjInverse" ] ) uniforms[ "matProjInverse" ].value = projectionMatrixInverse;
  567. if ( uniforms[ "matView" ] ) uniforms[ "matView" ].value = currentCamera.matrixWorldInverse;
  568. var originalLight = proxy.userData.originalLight;
  569. if ( originalLight ) {
  570. proxy.visible = originalLight.visible;
  571. if ( originalLight instanceof THREE.PointLight ) {
  572. updatePointLightProxy( proxy );
  573. } else if ( originalLight instanceof THREE.SpotLight ) {
  574. updateSpotLightProxy( proxy );
  575. } else if ( originalLight instanceof THREE.DirectionalLight ) {
  576. updateDirectionalLightProxy( proxy );
  577. } else if ( originalLight instanceof THREE.HemisphereLight ) {
  578. updateHemisphereLightProxy( proxy );
  579. } else if ( originalLight instanceof THREE.AreaLight ) {
  580. updateAreaLightProxy( proxy );
  581. }
  582. }
  583. };
  584. this.render = function ( scene, camera ) {
  585. // setup deferred properties
  586. if ( ! scene.userData.lightSceneProxy ) {
  587. scene.userData.lightSceneProxy = new THREE.Scene();
  588. scene.userData.lightSceneFullscreen = new THREE.Scene();
  589. var meshLight = createDeferredEmissiveLight();
  590. scene.userData.lightSceneFullscreen.add( meshLight );
  591. }
  592. currentCamera = camera;
  593. lightSceneProxy = scene.userData.lightSceneProxy;
  594. lightSceneFullscreen = scene.userData.lightSceneFullscreen;
  595. passColor.camera = currentCamera;
  596. passNormalDepth.camera = currentCamera;
  597. passLightProxy.camera = currentCamera;
  598. passLightFullscreen.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );
  599. passColor.scene = scene;
  600. passNormalDepth.scene = scene;
  601. passLightFullscreen.scene = lightSceneFullscreen;
  602. passLightProxy.scene = lightSceneProxy;
  603. scene.traverse( initDeferredProperties );
  604. // update scene graph only once per frame
  605. // (both color and normalDepth passes use exactly the same scene state)
  606. scene.autoUpdate = false;
  607. scene.updateMatrixWorld();
  608. // 1) g-buffer normals + depth pass
  609. scene.traverse( setMaterialNormalDepth );
  610. // clear shared depth buffer
  611. this.renderer.autoClearDepth = true;
  612. this.renderer.autoClearStencil = true;
  613. // write 1 to shared stencil buffer
  614. // for non-background pixels
  615. //gl.enable( gl.STENCIL_TEST );
  616. gl.stencilOp( gl.REPLACE, gl.REPLACE, gl.REPLACE );
  617. gl.stencilFunc( gl.ALWAYS, 1, 0xffffffff );
  618. gl.clearStencil( 0 );
  619. compNormalDepth.render();
  620. // just touch foreground pixels (stencil == 1)
  621. // both in color and light passes
  622. gl.stencilFunc( gl.EQUAL, 1, 0xffffffff );
  623. gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
  624. // 2) g-buffer color pass
  625. scene.traverse( setMaterialColor );
  626. // must use clean slate depth buffer
  627. // otherwise there are z-fighting glitches
  628. // not enough precision between two geometry passes
  629. // just to use EQUAL depth test
  630. this.renderer.autoClearDepth = true;
  631. this.renderer.autoClearStencil = false;
  632. compColor.render();
  633. // 3) light pass
  634. // do not clear depth buffer in this pass
  635. // depth from geometry pass is used for light culling
  636. // (write light proxy color pixel if behind scene pixel)
  637. this.renderer.autoClearDepth = false;
  638. scene.autoUpdate = true;
  639. gl.depthFunc( gl.GEQUAL );
  640. projectionMatrixInverse.getInverse( currentCamera.projectionMatrix );
  641. for ( var i = 0, il = lightSceneProxy.children.length; i < il; i ++ ) {
  642. var proxy = lightSceneProxy.children[ i ];
  643. updateLightProxy( proxy );
  644. }
  645. for ( var i = 0, il = lightSceneFullscreen.children.length; i < il; i ++ ) {
  646. var proxy = lightSceneFullscreen.children[ i ];
  647. updateLightProxy( proxy );
  648. }
  649. compLight.render();
  650. // 4) composite pass
  651. // return back to usual depth and stencil handling state
  652. this.renderer.autoClearDepth = true;
  653. this.renderer.autoClearStencil = true;
  654. gl.depthFunc( gl.LEQUAL );
  655. gl.disable( gl.STENCIL_TEST );
  656. compFinal.render( 0.1 );
  657. };
  658. //
  659. var createRenderTargets = function ( ) {
  660. var rtParamsFloatLinear = { minFilter: THREE.NearestFilter, magFilter: THREE.LinearFilter, stencilBuffer: true,
  661. format: THREE.RGBAFormat, type: THREE.FloatType };
  662. var rtParamsFloatNearest = { minFilter: THREE.NearestFilter, magFilter: THREE.NearestFilter, stencilBuffer: true,
  663. format: THREE.RGBAFormat, type: THREE.FloatType };
  664. var rtParamsUByte = { minFilter: THREE.NearestFilter, magFilter: THREE.LinearFilter, stencilBuffer: false,
  665. format: THREE.RGBFormat, type: THREE.UnsignedByteType };
  666. // g-buffers
  667. var rtColor = new THREE.WebGLRenderTarget( scaledWidth, scaledHeight, rtParamsFloatNearest );
  668. var rtNormalDepth = new THREE.WebGLRenderTarget( scaledWidth, scaledHeight, rtParamsFloatNearest );
  669. var rtLight = new THREE.WebGLRenderTarget( scaledWidth, scaledHeight, rtParamsFloatLinear );
  670. var rtFinal = new THREE.WebGLRenderTarget( scaledWidth, scaledHeight, rtParamsUByte );
  671. rtColor.generateMipmaps = false;
  672. rtNormalDepth.generateMipmaps = false;
  673. rtLight.generateMipmaps = false;
  674. rtFinal.generateMipmaps = false;
  675. // normal + depth composer
  676. passNormalDepth = new THREE.RenderPass();
  677. passNormalDepth.clear = true;
  678. compNormalDepth = new THREE.EffectComposer( _this.renderer, rtNormalDepth );
  679. compNormalDepth.addPass( passNormalDepth );
  680. // color composer
  681. passColor = new THREE.RenderPass();
  682. passColor.clear = true;
  683. compColor = new THREE.EffectComposer( _this.renderer, rtColor );
  684. compColor.addPass( passColor );
  685. compColor.renderTarget2.shareDepthFrom = compNormalDepth.renderTarget2;
  686. // light composer
  687. passLightFullscreen = new THREE.RenderPass();
  688. passLightFullscreen.clear = true;
  689. passLightProxy = new THREE.RenderPass();
  690. passLightProxy.clear = false;
  691. compLight = new THREE.EffectComposer( _this.renderer, rtLight );
  692. compLight.addPass( passLightFullscreen );
  693. compLight.addPass( passLightProxy );
  694. compLight.renderTarget2.shareDepthFrom = compNormalDepth.renderTarget2;
  695. // final composer
  696. compositePass = new THREE.ShaderPass( compositeShader );
  697. compositePass.uniforms[ 'samplerLight' ].value = compLight.renderTarget2;
  698. compositePass.uniforms[ 'brightness' ].value = brightness;
  699. compositePass.material.blending = THREE.NoBlending;
  700. compositePass.clear = true;
  701. var defines;
  702. switch ( tonemapping ) {
  703. case THREE.SimpleOperator: defines = { "TONEMAP_SIMPLE": true }; break;
  704. case THREE.LinearOperator: defines = { "TONEMAP_LINEAR": true }; break;
  705. case THREE.ReinhardOperator: defines = { "TONEMAP_REINHARD": true }; break;
  706. case THREE.FilmicOperator: defines = { "TONEMAP_FILMIC": true }; break;
  707. case THREE.UnchartedOperator: defines = { "TONEMAP_UNCHARTED": true }; break;
  708. }
  709. compositePass.material.defines = defines;
  710. // FXAA
  711. effectFXAA = new THREE.ShaderPass( THREE.FXAAShader );
  712. effectFXAA.uniforms[ 'resolution' ].value.set( 1 / fullWidth, 1 / fullHeight );
  713. effectFXAA.renderToScreen = true;
  714. //
  715. compFinal = new THREE.EffectComposer( _this.renderer, rtFinal );
  716. compFinal.addPass( compositePass );
  717. compFinal.addPass( effectFXAA );
  718. if ( antialias ) {
  719. effectFXAA.enabled = true;
  720. compositePass.renderToScreen = false;
  721. } else {
  722. effectFXAA.enabled = false;
  723. compositePass.renderToScreen = true;
  724. }
  725. };
  726. // init
  727. createRenderTargets();
  728. };
  729. // tonemapping operator types
  730. THREE.NoOperator = 0;
  731. THREE.SimpleOperator = 1;
  732. THREE.LinearOperator = 2;
  733. THREE.ReinhardOperator = 3;
  734. THREE.FilmicOperator = 4;
  735. THREE.UnchartedOperator = 5;