SSRShader.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. ( function () {
  2. /**
  3. * References:
  4. * https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-reflection.html
  5. */
  6. var SSRShader = {
  7. defines: {
  8. MAX_STEP: 0,
  9. PERSPECTIVE_CAMERA: true,
  10. DISTANCE_ATTENUATION: true,
  11. FRESNEL: true,
  12. INFINITE_THICK: false,
  13. SELECTIVE: false
  14. },
  15. uniforms: {
  16. 'tDiffuse': {
  17. value: null
  18. },
  19. 'tNormal': {
  20. value: null
  21. },
  22. 'tMetalness': {
  23. value: null
  24. },
  25. 'tDepth': {
  26. value: null
  27. },
  28. 'cameraNear': {
  29. value: null
  30. },
  31. 'cameraFar': {
  32. value: null
  33. },
  34. 'resolution': {
  35. value: new THREE.Vector2()
  36. },
  37. 'cameraProjectionMatrix': {
  38. value: new THREE.Matrix4()
  39. },
  40. 'cameraInverseProjectionMatrix': {
  41. value: new THREE.Matrix4()
  42. },
  43. 'opacity': {
  44. value: .5
  45. },
  46. 'maxDistance': {
  47. value: 180
  48. },
  49. 'cameraRange': {
  50. value: 0
  51. },
  52. 'surfDist': {
  53. value: .007
  54. },
  55. 'thickTolerance': {
  56. value: .03
  57. }
  58. },
  59. vertexShader:
  60. /* glsl */
  61. `
  62. varying vec2 vUv;
  63. void main() {
  64. vUv = uv;
  65. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  66. }
  67. `,
  68. fragmentShader:
  69. /* glsl */
  70. `
  71. // precision highp float;
  72. precision highp sampler2D;
  73. varying vec2 vUv;
  74. uniform sampler2D tDepth;
  75. uniform sampler2D tNormal;
  76. uniform sampler2D tMetalness;
  77. uniform sampler2D tDiffuse;
  78. uniform float cameraRange;
  79. uniform vec2 resolution;
  80. uniform float opacity;
  81. uniform float cameraNear;
  82. uniform float cameraFar;
  83. uniform float maxDistance;
  84. uniform float surfDist;
  85. uniform mat4 cameraProjectionMatrix;
  86. uniform mat4 cameraInverseProjectionMatrix;
  87. uniform float thickTolerance;
  88. #include <packing>
  89. float pointToLineDistance(vec3 x0, vec3 x1, vec3 x2) {
  90. //x0: point, x1: linePointA, x2: linePointB
  91. //https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
  92. return length(cross(x0-x1,x0-x2))/length(x2-x1);
  93. }
  94. float pointPlaneDistance(vec3 point,vec3 planePoint,vec3 planeNormal){
  95. // https://mathworld.wolfram.com/Point-PlaneDistance.html
  96. //// https://en.wikipedia.org/wiki/Plane_(geometry)
  97. //// http://paulbourke.net/geometry/pointlineplane/
  98. float a=planeNormal.x,b=planeNormal.y,c=planeNormal.z;
  99. float x0=point.x,y0=point.y,z0=point.z;
  100. float x=planePoint.x,y=planePoint.y,z=planePoint.z;
  101. float d=-(a*x+b*y+c*z);
  102. float distance=(a*x0+b*y0+c*z0+d)/sqrt(a*a+b*b+c*c);
  103. return distance;
  104. }
  105. float getDepth( const in vec2 uv ) {
  106. return texture2D( tDepth, uv ).x;
  107. }
  108. float getViewZ( const in float depth ) {
  109. #ifdef PERSPECTIVE_CAMERA
  110. return perspectiveDepthToViewZ( depth, cameraNear, cameraFar );
  111. #else
  112. return orthographicDepthToViewZ( depth, cameraNear, cameraFar );
  113. #endif
  114. }
  115. vec3 getViewPosition( const in vec2 uv, const in float depth/*clip space*/, const in float clipW ) {
  116. vec4 clipPosition = vec4( ( vec3( uv, depth ) - 0.5 ) * 2.0, 1.0 );//ndc
  117. clipPosition *= clipW; //clip
  118. return ( cameraInverseProjectionMatrix * clipPosition ).xyz;//view
  119. }
  120. vec3 getViewNormal( const in vec2 uv ) {
  121. return unpackRGBToNormal( texture2D( tNormal, uv ).xyz );
  122. }
  123. vec2 viewPositionToXY(vec3 viewPosition){
  124. vec2 xy;
  125. vec4 clip=cameraProjectionMatrix*vec4(viewPosition,1);
  126. xy=clip.xy;//clip
  127. float clipW=clip.w;
  128. xy/=clipW;//NDC
  129. xy=(xy+1.)/2.;//uv
  130. xy*=resolution;//screen
  131. return xy;
  132. }
  133. void main(){
  134. #ifdef SELECTIVE
  135. float metalness=texture2D(tMetalness,vUv).r;
  136. if(metalness==0.) return;
  137. #endif
  138. float depth = getDepth( vUv );
  139. float viewZ = getViewZ( depth );
  140. if(-viewZ>=cameraFar) return;
  141. float clipW = cameraProjectionMatrix[2][3] * viewZ+cameraProjectionMatrix[3][3];
  142. vec3 viewPosition=getViewPosition( vUv, depth, clipW );
  143. vec2 d0=gl_FragCoord.xy;
  144. vec2 d1;
  145. vec3 viewNormal=getViewNormal( vUv );
  146. #ifdef PERSPECTIVE_CAMERA
  147. vec3 viewIncidentDir=normalize(viewPosition);
  148. vec3 viewReflectDir=reflect(viewIncidentDir,viewNormal);
  149. #else
  150. vec3 viewIncidentDir=vec3(0,0,-1);
  151. vec3 viewReflectDir=reflect(viewIncidentDir,viewNormal);
  152. #endif
  153. float maxReflectRayLen=maxDistance/dot(-viewIncidentDir,viewNormal);
  154. // dot(a,b)==length(a)*length(b)*cos(theta) // https://www.mathsisfun.com/algebra/vectors-dot-product.html
  155. // if(a.isNormalized&&b.isNormalized) dot(a,b)==cos(theta)
  156. // maxDistance/maxReflectRayLen=cos(theta)
  157. // maxDistance/maxReflectRayLen==dot(a,b)
  158. // maxReflectRayLen==maxDistance/dot(a,b)
  159. vec3 d1viewPosition=viewPosition+viewReflectDir*maxReflectRayLen;
  160. #ifdef PERSPECTIVE_CAMERA
  161. if(d1viewPosition.z>-cameraNear){
  162. //https://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfLines.aspx
  163. float t=(-cameraNear-viewPosition.z)/viewReflectDir.z;
  164. d1viewPosition=viewPosition+viewReflectDir*t;
  165. }
  166. #endif
  167. d1=viewPositionToXY(d1viewPosition);
  168. float totalLen=length(d1-d0);
  169. float xLen=d1.x-d0.x;
  170. float yLen=d1.y-d0.y;
  171. float totalStep=max(abs(xLen),abs(yLen));
  172. float xSpan=xLen/totalStep;
  173. float ySpan=yLen/totalStep;
  174. for(float i=0.;i<float(MAX_STEP);i++){
  175. if(i>=totalStep) break;
  176. vec2 xy=vec2(d0.x+i*xSpan,d0.y+i*ySpan);
  177. if(xy.x<0.||xy.x>resolution.x||xy.y<0.||xy.y>resolution.y) break;
  178. float s=length(xy-d0)/totalLen;
  179. vec2 uv=xy/resolution;
  180. float d = getDepth(uv);
  181. float vZ = getViewZ( d );
  182. if(-vZ>=cameraFar) continue;
  183. float cW = cameraProjectionMatrix[2][3] * vZ+cameraProjectionMatrix[3][3];
  184. vec3 vP=getViewPosition( uv, d, cW );
  185. #ifdef PERSPECTIVE_CAMERA
  186. // https://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf
  187. float recipVPZ=1./viewPosition.z;
  188. float viewReflectRayZ=1./(recipVPZ+s*(1./d1viewPosition.z-recipVPZ));
  189. float sD=surfDist*cW;
  190. #else
  191. float viewReflectRayZ=viewPosition.z+s*(d1viewPosition.z-viewPosition.z);
  192. float sD=surfDist;
  193. #endif
  194. if(viewReflectRayZ-sD>vZ) continue;
  195. #ifdef INFINITE_THICK
  196. if(viewReflectRayZ+thickTolerance*clipW<vP.z) break;
  197. #endif
  198. float away=pointToLineDistance(vP,viewPosition,d1viewPosition);
  199. float op=opacity;
  200. if(away<sD){
  201. vec3 vN=getViewNormal( uv );
  202. if(dot(viewReflectDir,vN)>=0.) continue;
  203. float distance=pointPlaneDistance(vP,viewPosition,viewNormal);
  204. if(distance>maxDistance) break;
  205. #ifdef DISTANCE_ATTENUATION
  206. float ratio=1.-(distance/maxDistance);
  207. float attenuation=ratio*ratio;
  208. op=opacity*attenuation;
  209. #endif
  210. #ifdef FRESNEL
  211. float fresnelCoe=(dot(viewIncidentDir,viewReflectDir)+1.)/2.;
  212. op*=fresnelCoe;
  213. #endif
  214. vec4 reflectColor=texture2D(tDiffuse,uv);
  215. gl_FragColor.xyz=reflectColor.xyz;
  216. gl_FragColor.a=op;
  217. break;
  218. }
  219. }
  220. }
  221. `
  222. };
  223. var SSRDepthShader = {
  224. defines: {
  225. 'PERSPECTIVE_CAMERA': 1
  226. },
  227. uniforms: {
  228. 'tDepth': {
  229. value: null
  230. },
  231. 'cameraNear': {
  232. value: null
  233. },
  234. 'cameraFar': {
  235. value: null
  236. }
  237. },
  238. vertexShader:
  239. /* glsl */
  240. `
  241. varying vec2 vUv;
  242. void main() {
  243. vUv = uv;
  244. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  245. }
  246. `,
  247. fragmentShader:
  248. /* glsl */
  249. `
  250. uniform sampler2D tDepth;
  251. uniform float cameraNear;
  252. uniform float cameraFar;
  253. varying vec2 vUv;
  254. #include <packing>
  255. float getLinearDepth( const in vec2 uv ) {
  256. #if PERSPECTIVE_CAMERA == 1
  257. float fragCoordZ = texture2D( tDepth, uv ).x;
  258. float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );
  259. return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );
  260. #else
  261. return texture2D( tDepth, uv ).x;
  262. #endif
  263. }
  264. void main() {
  265. float depth = getLinearDepth( vUv );
  266. float d = 1.0 - depth;
  267. // d=(d-.999)*1000.;
  268. gl_FragColor = vec4( vec3( d ), 1.0 );
  269. }
  270. `
  271. };
  272. var SSRBlurShader = {
  273. uniforms: {
  274. 'tDiffuse': {
  275. value: null
  276. },
  277. 'resolution': {
  278. value: new THREE.Vector2()
  279. },
  280. 'opacity': {
  281. value: .5
  282. }
  283. },
  284. vertexShader:
  285. /* glsl */
  286. `
  287. varying vec2 vUv;
  288. void main() {
  289. vUv = uv;
  290. gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  291. }
  292. `,
  293. fragmentShader:
  294. /* glsl */
  295. `
  296. uniform sampler2D tDiffuse;
  297. uniform vec2 resolution;
  298. varying vec2 vUv;
  299. void main() {
  300. //reverse engineering from PhotoShop blur filter, then change coefficient
  301. vec2 texelSize = ( 1.0 / resolution );
  302. vec4 c=texture2D(tDiffuse,vUv);
  303. vec2 offset;
  304. offset=(vec2(-1,0))*texelSize;
  305. vec4 cl=texture2D(tDiffuse,vUv+offset);
  306. offset=(vec2(1,0))*texelSize;
  307. vec4 cr=texture2D(tDiffuse,vUv+offset);
  308. offset=(vec2(0,-1))*texelSize;
  309. vec4 cb=texture2D(tDiffuse,vUv+offset);
  310. offset=(vec2(0,1))*texelSize;
  311. vec4 ct=texture2D(tDiffuse,vUv+offset);
  312. // float coeCenter=.5;
  313. // float coeSide=.125;
  314. float coeCenter=.2;
  315. float coeSide=.2;
  316. float a=c.a*coeCenter+cl.a*coeSide+cr.a*coeSide+cb.a*coeSide+ct.a*coeSide;
  317. vec3 rgb=(c.rgb*c.a*coeCenter+cl.rgb*cl.a*coeSide+cr.rgb*cr.a*coeSide+cb.rgb*cb.a*coeSide+ct.rgb*ct.a*coeSide)/a;
  318. gl_FragColor=vec4(rgb,a);
  319. }
  320. `
  321. };
  322. THREE.SSRBlurShader = SSRBlurShader;
  323. THREE.SSRDepthShader = SSRDepthShader;
  324. THREE.SSRShader = SSRShader;
  325. } )();