RenderPixelatedPass.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. ( function () {
  2. class RenderPixelatedPass extends THREE.Pass {
  3. constructor( pixelSize, scene, camera, options = {} ) {
  4. super();
  5. this.pixelSize = pixelSize;
  6. this.resolution = new THREE.Vector2();
  7. this.renderResolution = new THREE.Vector2();
  8. this.pixelatedMaterial = this.createPixelatedMaterial();
  9. this.normalMaterial = new THREE.MeshNormalMaterial();
  10. this.fsQuad = new THREE.FullScreenQuad( this.pixelatedMaterial );
  11. this.scene = scene;
  12. this.camera = camera;
  13. this.normalEdgeStrength = options.normalEdgeStrength || 0.3;
  14. this.depthEdgeStrength = options.depthEdgeStrength || 0.4;
  15. this.beautyRenderTarget = new THREE.WebGLRenderTarget();
  16. this.beautyRenderTarget.texture.minFilter = THREE.NearestFilter;
  17. this.beautyRenderTarget.texture.magFilter = THREE.NearestFilter;
  18. this.beautyRenderTarget.depthTexture = new THREE.DepthTexture();
  19. this.normalRenderTarget = new THREE.WebGLRenderTarget();
  20. this.normalRenderTarget.texture.minFilter = THREE.NearestFilter;
  21. this.normalRenderTarget.texture.magFilter = THREE.NearestFilter;
  22. }
  23. dispose() {
  24. this.beautyRenderTarget.dispose();
  25. this.normalRenderTarget.dispose();
  26. this.pixelatedMaterial.dispose();
  27. this.normalMaterial.dispose();
  28. this.fsQuad.dispose();
  29. }
  30. setSize( width, height ) {
  31. this.resolution.set( width, height );
  32. this.renderResolution.set( width / this.pixelSize | 0, height / this.pixelSize | 0 );
  33. const {
  34. x,
  35. y
  36. } = this.renderResolution;
  37. this.beautyRenderTarget.setSize( x, y );
  38. this.normalRenderTarget.setSize( x, y );
  39. this.fsQuad.material.uniforms.resolution.value.set( x, y, 1 / x, 1 / y );
  40. }
  41. setPixelSize( pixelSize ) {
  42. this.pixelSize = pixelSize;
  43. this.setSize( this.resolution.x, this.resolution.y );
  44. }
  45. render( renderer, writeBuffer ) {
  46. const uniforms = this.fsQuad.material.uniforms;
  47. uniforms.normalEdgeStrength.value = this.normalEdgeStrength;
  48. uniforms.depthEdgeStrength.value = this.depthEdgeStrength;
  49. renderer.setRenderTarget( this.beautyRenderTarget );
  50. renderer.render( this.scene, this.camera );
  51. const overrideMaterial_old = this.scene.overrideMaterial;
  52. renderer.setRenderTarget( this.normalRenderTarget );
  53. this.scene.overrideMaterial = this.normalMaterial;
  54. renderer.render( this.scene, this.camera );
  55. this.scene.overrideMaterial = overrideMaterial_old;
  56. uniforms.tDiffuse.value = this.beautyRenderTarget.texture;
  57. uniforms.tDepth.value = this.beautyRenderTarget.depthTexture;
  58. uniforms.tNormal.value = this.normalRenderTarget.texture;
  59. if ( this.renderToScreen ) {
  60. renderer.setRenderTarget( null );
  61. } else {
  62. renderer.setRenderTarget( writeBuffer );
  63. if ( this.clear ) renderer.clear();
  64. }
  65. this.fsQuad.render( renderer );
  66. }
  67. createPixelatedMaterial() {
  68. return new THREE.ShaderMaterial( {
  69. uniforms: {
  70. tDiffuse: {
  71. value: null
  72. },
  73. tDepth: {
  74. value: null
  75. },
  76. tNormal: {
  77. value: null
  78. },
  79. resolution: {
  80. value: new THREE.Vector4( this.renderResolution.x, this.renderResolution.y, 1 / this.renderResolution.x, 1 / this.renderResolution.y )
  81. },
  82. normalEdgeStrength: {
  83. value: 0
  84. },
  85. depthEdgeStrength: {
  86. value: 0
  87. }
  88. },
  89. vertexShader: /* glsl */`
  90. varying vec2 vUv;
  91. void main() {
  92. vUv = uv;
  93. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  94. }
  95. `,
  96. fragmentShader: /* glsl */`
  97. uniform sampler2D tDiffuse;
  98. uniform sampler2D tDepth;
  99. uniform sampler2D tNormal;
  100. uniform vec4 resolution;
  101. uniform float normalEdgeStrength;
  102. uniform float depthEdgeStrength;
  103. varying vec2 vUv;
  104. float getDepth(int x, int y) {
  105. return texture2D( tDepth, vUv + vec2(x, y) * resolution.zw ).r;
  106. }
  107. vec3 getNormal(int x, int y) {
  108. return texture2D( tNormal, vUv + vec2(x, y) * resolution.zw ).rgb * 2.0 - 1.0;
  109. }
  110. float depthEdgeIndicator(float depth, vec3 normal) {
  111. float diff = 0.0;
  112. diff += clamp(getDepth(1, 0) - depth, 0.0, 1.0);
  113. diff += clamp(getDepth(-1, 0) - depth, 0.0, 1.0);
  114. diff += clamp(getDepth(0, 1) - depth, 0.0, 1.0);
  115. diff += clamp(getDepth(0, -1) - depth, 0.0, 1.0);
  116. return floor(smoothstep(0.01, 0.02, diff) * 2.) / 2.;
  117. }
  118. float neighborNormalEdgeIndicator(int x, int y, float depth, vec3 normal) {
  119. float depthDiff = getDepth(x, y) - depth;
  120. vec3 neighborNormal = getNormal(x, y);
  121. // Edge pixels should yield to faces who's normals are closer to the bias normal.
  122. vec3 normalEdgeBias = vec3(1., 1., 1.); // This should probably be a parameter.
  123. float normalDiff = dot(normal - neighborNormal, normalEdgeBias);
  124. float normalIndicator = clamp(smoothstep(-.01, .01, normalDiff), 0.0, 1.0);
  125. // Only the shallower pixel should detect the normal edge.
  126. float depthIndicator = clamp(sign(depthDiff * .25 + .0025), 0.0, 1.0);
  127. return (1.0 - dot(normal, neighborNormal)) * depthIndicator * normalIndicator;
  128. }
  129. float normalEdgeIndicator(float depth, vec3 normal) {
  130. float indicator = 0.0;
  131. indicator += neighborNormalEdgeIndicator(0, -1, depth, normal);
  132. indicator += neighborNormalEdgeIndicator(0, 1, depth, normal);
  133. indicator += neighborNormalEdgeIndicator(-1, 0, depth, normal);
  134. indicator += neighborNormalEdgeIndicator(1, 0, depth, normal);
  135. return step(0.1, indicator);
  136. }
  137. void main() {
  138. vec4 texel = texture2D( tDiffuse, vUv );
  139. float depth = 0.0;
  140. vec3 normal = vec3(0.0);
  141. if (depthEdgeStrength > 0.0 || normalEdgeStrength > 0.0) {
  142. depth = getDepth(0, 0);
  143. normal = getNormal(0, 0);
  144. }
  145. float dei = 0.0;
  146. if (depthEdgeStrength > 0.0)
  147. dei = depthEdgeIndicator(depth, normal);
  148. float nei = 0.0;
  149. if (normalEdgeStrength > 0.0)
  150. nei = normalEdgeIndicator(depth, normal);
  151. float Strength = dei > 0.0 ? (1.0 - depthEdgeStrength * dei) : (1.0 + normalEdgeStrength * nei);
  152. gl_FragColor = texel * Strength;
  153. }
  154. `
  155. } );
  156. }
  157. }
  158. THREE.RenderPixelatedPass = RenderPixelatedPass;
  159. } )();