物管理前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
13 KiB

  1. (function () {
  2. /**
  3. * UnrealBloomPass is inspired by the bloom pass of Unreal Engine. It creates a
  4. * mip map chain of bloom textures and blurs them with different radii. Because
  5. * of the weighted combination of mips, and because larger blurs are done on
  6. * higher mips, this effect provides good quality and performance.
  7. *
  8. * Reference:
  9. * - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
  10. */
  11. class UnrealBloomPass extends THREE.Pass {
  12. constructor(resolution, strength, radius, threshold) {
  13. super();
  14. this.strength = strength !== undefined ? strength : 1;
  15. this.radius = radius;
  16. this.threshold = threshold;
  17. this.resolution =
  18. resolution !== undefined
  19. ? new THREE.Vector2(resolution.x, resolution.y)
  20. : new THREE.Vector2(256, 256); // create color only once here, reuse it later inside the render function
  21. this.clearColor = new THREE.Color(0, 0, 0); // render targets
  22. this.renderTargetsHorizontal = [];
  23. this.renderTargetsVertical = [];
  24. this.nMips = 5;
  25. let resx = Math.round(this.resolution.x / 2);
  26. let resy = Math.round(this.resolution.y / 2);
  27. this.renderTargetBright = new THREE.WebGLRenderTarget(resx, resy);
  28. this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
  29. this.renderTargetBright.texture.generateMipmaps = false;
  30. for (let i = 0; i < this.nMips; i++) {
  31. const renderTargetHorizonal = new THREE.WebGLRenderTarget(resx, resy);
  32. renderTargetHorizonal.texture.name = "UnrealBloomPass.h" + i;
  33. renderTargetHorizonal.texture.generateMipmaps = false;
  34. this.renderTargetsHorizontal.push(renderTargetHorizonal);
  35. const renderTargetVertical = new THREE.WebGLRenderTarget(resx, resy);
  36. renderTargetVertical.texture.name = "UnrealBloomPass.v" + i;
  37. renderTargetVertical.texture.generateMipmaps = false;
  38. this.renderTargetsVertical.push(renderTargetVertical);
  39. resx = Math.round(resx / 2);
  40. resy = Math.round(resy / 2);
  41. } // luminosity high pass material
  42. if (THREE.LuminosityHighPassShader === undefined)
  43. console.error("THREE.UnrealBloomPass relies on THREE.LuminosityHighPassShader");
  44. const highPassShader = THREE.LuminosityHighPassShader;
  45. this.highPassUniforms = THREE.UniformsUtils.clone(highPassShader.uniforms);
  46. this.highPassUniforms["luminosityThreshold"].value = threshold;
  47. this.highPassUniforms["smoothWidth"].value = 0.01;
  48. this.materialHighPassFilter = new THREE.ShaderMaterial({
  49. uniforms: this.highPassUniforms,
  50. vertexShader: highPassShader.vertexShader,
  51. fragmentShader: highPassShader.fragmentShader,
  52. defines: {}
  53. }); // Gaussian Blur Materials
  54. this.separableBlurMaterials = [];
  55. const kernelSizeArray = [3, 5, 7, 9, 11];
  56. resx = Math.round(this.resolution.x / 2);
  57. resy = Math.round(this.resolution.y / 2);
  58. for (let i = 0; i < this.nMips; i++) {
  59. this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i]));
  60. this.separableBlurMaterials[i].uniforms["texSize"].value = new THREE.Vector2(resx, resy);
  61. resx = Math.round(resx / 2);
  62. resy = Math.round(resy / 2);
  63. } // Composite material
  64. this.compositeMaterial = this.getCompositeMaterial(this.nMips);
  65. this.compositeMaterial.uniforms["blurTexture1"].value = this.renderTargetsVertical[0].texture;
  66. this.compositeMaterial.uniforms["blurTexture2"].value = this.renderTargetsVertical[1].texture;
  67. this.compositeMaterial.uniforms["blurTexture3"].value = this.renderTargetsVertical[2].texture;
  68. this.compositeMaterial.uniforms["blurTexture4"].value = this.renderTargetsVertical[3].texture;
  69. this.compositeMaterial.uniforms["blurTexture5"].value = this.renderTargetsVertical[4].texture;
  70. this.compositeMaterial.uniforms["bloomStrength"].value = strength;
  71. this.compositeMaterial.uniforms["bloomRadius"].value = 0.1;
  72. this.compositeMaterial.needsUpdate = true;
  73. const bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2];
  74. this.compositeMaterial.uniforms["bloomFactors"].value = bloomFactors;
  75. this.bloomTintColors = [
  76. new THREE.Vector3(1, 1, 1),
  77. new THREE.Vector3(1, 1, 1),
  78. new THREE.Vector3(1, 1, 1),
  79. new THREE.Vector3(1, 1, 1),
  80. new THREE.Vector3(1, 1, 1)
  81. ];
  82. this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors; // copy material
  83. if (THREE.CopyShader === undefined) {
  84. console.error("THREE.UnrealBloomPass relies on THREE.CopyShader");
  85. }
  86. const copyShader = THREE.CopyShader;
  87. this.copyUniforms = THREE.UniformsUtils.clone(copyShader.uniforms);
  88. this.copyUniforms["opacity"].value = 1.0;
  89. this.materialCopy = new THREE.ShaderMaterial({
  90. uniforms: this.copyUniforms,
  91. vertexShader: copyShader.vertexShader,
  92. fragmentShader: copyShader.fragmentShader,
  93. blending: THREE.AdditiveBlending,
  94. depthTest: false,
  95. depthWrite: false,
  96. transparent: true
  97. });
  98. this.enabled = true;
  99. this.needsSwap = false;
  100. this._oldClearColor = new THREE.Color();
  101. this.oldClearAlpha = 1;
  102. this.basic = new THREE.MeshBasicMaterial();
  103. this.fsQuad = new THREE.FullScreenQuad(null);
  104. }
  105. dispose() {
  106. for (let i = 0; i < this.renderTargetsHorizontal.length; i++) {
  107. this.renderTargetsHorizontal[i].dispose();
  108. }
  109. for (let i = 0; i < this.renderTargetsVertical.length; i++) {
  110. this.renderTargetsVertical[i].dispose();
  111. }
  112. this.renderTargetBright.dispose();
  113. }
  114. setSize(width, height) {
  115. let resx = Math.round(width / 2);
  116. let resy = Math.round(height / 2);
  117. this.renderTargetBright.setSize(resx, resy);
  118. for (let i = 0; i < this.nMips; i++) {
  119. this.renderTargetsHorizontal[i].setSize(resx, resy);
  120. this.renderTargetsVertical[i].setSize(resx, resy);
  121. this.separableBlurMaterials[i].uniforms["texSize"].value = new THREE.Vector2(resx, resy);
  122. resx = Math.round(resx / 2);
  123. resy = Math.round(resy / 2);
  124. }
  125. }
  126. render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
  127. renderer.getClearColor(this._oldClearColor);
  128. this.oldClearAlpha = renderer.getClearAlpha();
  129. const oldAutoClear = renderer.autoClear;
  130. renderer.autoClear = false;
  131. renderer.setClearColor(this.clearColor, 0);
  132. if (maskActive) renderer.state.buffers.stencil.setTest(false); // Render input to screen
  133. if (this.renderToScreen) {
  134. this.fsQuad.material = this.basic;
  135. this.basic.map = readBuffer.texture;
  136. renderer.setRenderTarget(null);
  137. renderer.clear();
  138. this.fsQuad.render(renderer);
  139. } // 1. Extract Bright Areas
  140. this.highPassUniforms["tDiffuse"].value = readBuffer.texture;
  141. this.highPassUniforms["luminosityThreshold"].value = this.threshold;
  142. this.fsQuad.material = this.materialHighPassFilter;
  143. renderer.setRenderTarget(this.renderTargetBright);
  144. renderer.clear();
  145. this.fsQuad.render(renderer); // 2. Blur All the mips progressively
  146. let inputRenderTarget = this.renderTargetBright;
  147. for (let i = 0; i < this.nMips; i++) {
  148. this.fsQuad.material = this.separableBlurMaterials[i];
  149. this.separableBlurMaterials[i].uniforms["colorTexture"].value = inputRenderTarget.texture;
  150. this.separableBlurMaterials[i].uniforms["direction"].value = UnrealBloomPass.BlurDirectionX;
  151. renderer.setRenderTarget(this.renderTargetsHorizontal[i]);
  152. renderer.clear();
  153. this.fsQuad.render(renderer);
  154. this.separableBlurMaterials[i].uniforms["colorTexture"].value =
  155. this.renderTargetsHorizontal[i].texture;
  156. this.separableBlurMaterials[i].uniforms["direction"].value = UnrealBloomPass.BlurDirectionY;
  157. renderer.setRenderTarget(this.renderTargetsVertical[i]);
  158. renderer.clear();
  159. this.fsQuad.render(renderer);
  160. inputRenderTarget = this.renderTargetsVertical[i];
  161. } // Composite All the mips
  162. this.fsQuad.material = this.compositeMaterial;
  163. this.compositeMaterial.uniforms["bloomStrength"].value = this.strength;
  164. this.compositeMaterial.uniforms["bloomRadius"].value = this.radius;
  165. this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
  166. renderer.setRenderTarget(this.renderTargetsHorizontal[0]);
  167. renderer.clear();
  168. this.fsQuad.render(renderer); // Blend it additively over the input texture
  169. this.fsQuad.material = this.materialCopy;
  170. this.copyUniforms["tDiffuse"].value = this.renderTargetsHorizontal[0].texture;
  171. if (maskActive) renderer.state.buffers.stencil.setTest(true);
  172. if (this.renderToScreen) {
  173. renderer.setRenderTarget(null);
  174. this.fsQuad.render(renderer);
  175. } else {
  176. renderer.setRenderTarget(readBuffer);
  177. this.fsQuad.render(renderer);
  178. } // Restore renderer settings
  179. renderer.setClearColor(this._oldClearColor, this.oldClearAlpha);
  180. renderer.autoClear = oldAutoClear;
  181. }
  182. getSeperableBlurMaterial(kernelRadius) {
  183. return new THREE.ShaderMaterial({
  184. defines: {
  185. KERNEL_RADIUS: kernelRadius,
  186. SIGMA: kernelRadius
  187. },
  188. uniforms: {
  189. colorTexture: {
  190. value: null
  191. },
  192. texSize: {
  193. value: new THREE.Vector2(0.5, 0.5)
  194. },
  195. direction: {
  196. value: new THREE.Vector2(0.5, 0.5)
  197. }
  198. },
  199. vertexShader: `varying vec2 vUv;
  200. void main() {
  201. vUv = uv;
  202. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  203. }`,
  204. fragmentShader: `#include <common>
  205. varying vec2 vUv;
  206. uniform sampler2D colorTexture;
  207. uniform vec2 texSize;
  208. uniform vec2 direction;
  209. float gaussianPdf(in float x, in float sigma) {
  210. return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;
  211. }
  212. void main() {
  213. vec2 invSize = 1.0 / texSize;
  214. float fSigma = float(SIGMA);
  215. float weightSum = gaussianPdf(0.0, fSigma);
  216. vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;
  217. for( int i = 1; i < KERNEL_RADIUS; i ++ ) {
  218. float x = float(i);
  219. float w = gaussianPdf(x, fSigma);
  220. vec2 uvOffset = direction * invSize * x;
  221. vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;
  222. vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;
  223. diffuseSum += (sample1 + sample2) * w;
  224. weightSum += 2.0 * w;
  225. }
  226. gl_FragColor = vec4(diffuseSum/weightSum, 1.0);
  227. }`
  228. });
  229. }
  230. getCompositeMaterial(nMips) {
  231. return new THREE.ShaderMaterial({
  232. defines: {
  233. NUM_MIPS: nMips
  234. },
  235. uniforms: {
  236. blurTexture1: {
  237. value: null
  238. },
  239. blurTexture2: {
  240. value: null
  241. },
  242. blurTexture3: {
  243. value: null
  244. },
  245. blurTexture4: {
  246. value: null
  247. },
  248. blurTexture5: {
  249. value: null
  250. },
  251. bloomStrength: {
  252. value: 1.0
  253. },
  254. bloomFactors: {
  255. value: null
  256. },
  257. bloomTintColors: {
  258. value: null
  259. },
  260. bloomRadius: {
  261. value: 0.0
  262. }
  263. },
  264. vertexShader: `varying vec2 vUv;
  265. void main() {
  266. vUv = uv;
  267. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  268. }`,
  269. fragmentShader: `varying vec2 vUv;
  270. uniform sampler2D blurTexture1;
  271. uniform sampler2D blurTexture2;
  272. uniform sampler2D blurTexture3;
  273. uniform sampler2D blurTexture4;
  274. uniform sampler2D blurTexture5;
  275. uniform float bloomStrength;
  276. uniform float bloomRadius;
  277. uniform float bloomFactors[NUM_MIPS];
  278. uniform vec3 bloomTintColors[NUM_MIPS];
  279. float lerpBloomFactor(const in float factor) {
  280. float mirrorFactor = 1.2 - factor;
  281. return mix(factor, mirrorFactor, bloomRadius);
  282. }
  283. void main() {
  284. gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) +
  285. lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) +
  286. lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) +
  287. lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) +
  288. lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );
  289. }`
  290. });
  291. }
  292. }
  293. UnrealBloomPass.BlurDirectionX = new THREE.Vector2(1.0, 0.0);
  294. UnrealBloomPass.BlurDirectionY = new THREE.Vector2(0.0, 1.0);
  295. THREE.UnrealBloomPass = UnrealBloomPass;
  296. })();