screen-space-reflections
Advanced tools
Comparing version 2.1.0 to 2.1.1
import { Pass, RenderPass, DepthPass, Effect, Selection } from 'postprocessing'; | ||
import { Vector2, WebGLRenderTarget, LinearFilter, HalfFloatType, ShaderMaterial, Uniform, FramebufferTexture, RGBAFormat, Matrix3, TangentSpaceNormalMap, GLSL3, Matrix4, ShaderChunk, UniformsUtils, FrontSide, VideoTexture, WebGLMultipleRenderTargets, Vector3, Quaternion } from 'three'; | ||
import { ShaderChunk, Matrix4, WebGLRenderTarget, NearestFilter, HalfFloatType, ShaderMaterial, UniformsUtils, FrontSide, VideoTexture, Vector2, LinearFilter, Uniform, FramebufferTexture, RGBAFormat, Matrix3, TangentSpaceNormalMap, GLSL3, WebGLMultipleRenderTargets, Vector3, Quaternion } from 'three'; | ||
@@ -37,16 +37,241 @@ function _extends() { | ||
var fragmentShader$2 = "#define GLSLIFY 1\n#define EULER 2.718281828459045\n#define FLOAT_EPSILON 0.00001\nuniform sampler2D inputTexture;uniform sampler2D accumulatedReflectionsTexture;uniform sampler2D velocityTexture;uniform float samples;uniform float maxSamples;uniform float temporalResolveMix;uniform float temporalResolveCorrectionMix;varying vec2 vUv;\n#include <packing>\n#define min3(a, b, c) min(a, min(b, c))\n#define min4(a, b, c, d) min(a, min3(b, c, d))\n#define min5(a, b, c, d, e) min(a, min4(b, c, d, e))\n#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f))\n#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g))\n#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h))\n#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i))\n#define max3(a, b, c) max(a, max(b, c))\n#define max4(a, b, c, d) max(a, max3(b, c, d))\n#define max5(a, b, c, d, e) max(a, max4(b, c, d, e))\n#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f))\n#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g))\n#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h))\n#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i))\nvoid main(){vec4 inputTexel=texture2D(inputTexture,vUv);float samplesValue=samples;bool wasDiscarded=false;\n#ifdef DITHERING\nivec2 size=textureSize(inputTexture,0);vec2 pxSize=vec2(float(size.x),float(size.y));int x=int(vUv.x*pxSize.x);int y=int(vUv.y*pxSize.y);int rest=int(samplesValue)% 2;wasDiscarded=x % 2==rest||y % 2==rest;samplesValue*=0.5;\n#endif\nvec4 lastFrameReflectionsTexel;vec3 newColor;\n#ifdef TEMPORAL_RESOLVE\nvec4 velocityTexel=texture2D(velocityTexture,vUv);vec2 velUv=velocityTexel.xy;float movement=length(velUv)*100.;if(movement>0.){vec2 reprojectedUv=vUv-velUv;if(reprojectedUv.x>=0.&&reprojectedUv.x<=1.&&reprojectedUv.y>=0.&&reprojectedUv.y<=1.){lastFrameReflectionsTexel=texture2D(accumulatedReflectionsTexture,reprojectedUv);if(!wasDiscarded){ivec2 size=textureSize(inputTexture,0);vec2 pxSize=vec2(float(size.x),float(size.y));vec2 px=1./pxSize;vec3 c02=texture2D(inputTexture,vUv+vec2(-px.x,px.y)).rgb;vec3 c12=texture2D(inputTexture,vUv+vec2(0.,px.y)).rgb;vec3 c22=texture2D(inputTexture,vUv+vec2(px.x,px.y)).rgb;vec3 c01=texture2D(inputTexture,vUv+vec2(-px.x,0.)).rgb;vec3 c11=inputTexel.rgb;vec3 c21=texture2D(inputTexture,vUv+vec2(px.x,0.)).rgb;vec3 c00=texture2D(inputTexture,vUv+vec2(-px.x,-px.y)).rgb;vec3 c10=texture2D(inputTexture,vUv+vec2(0.,-px.y)).rgb;vec3 c20=texture2D(inputTexture,vUv+vec2(px.x,-px.y)).rgb;vec3 minNeighborColor=min9(c02,c12,c22,c01,c11,c21,c00,c10,c20);vec3 maxNeighborColor=max9(c02,c12,c22,c01,c11,c21,c00,c10,c20);vec3 clampedColor=clamp(lastFrameReflectionsTexel.rgb,minNeighborColor,maxNeighborColor);float mixFactor=temporalResolveCorrectionMix*(1.+movement);mixFactor=min(mixFactor,1.);lastFrameReflectionsTexel.rgb=mix(lastFrameReflectionsTexel.rgb,clampedColor,mixFactor);}}else{lastFrameReflectionsTexel.rgb=inputTexel.rgb;}}else{lastFrameReflectionsTexel=texture2D(accumulatedReflectionsTexture,vUv);}\n#ifdef DITHERING\nif(wasDiscarded){inputTexel=lastFrameReflectionsTexel;}\n#endif\nfloat alpha=min(inputTexel.a,lastFrameReflectionsTexel.a);alpha=samplesValue<2.||movement<FLOAT_EPSILON ?(0.05+alpha): 0.;if(maxSamples!=0.&&samplesValue>maxSamples&&alpha>1.-FLOAT_EPSILON){gl_FragColor=lastFrameReflectionsTexel;return;}if(alpha<1.){newColor=mix(lastFrameReflectionsTexel.rgb,inputTexel.rgb,(1.-alpha)*temporalResolveCorrectionMix);}else if(samplesValue>4.&&movement<FLOAT_EPSILON&&length(lastFrameReflectionsTexel.rgb)<FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb;}else if(1./samplesValue>=1.-temporalResolveMix){newColor=lastFrameReflectionsTexel.rgb*(temporalResolveMix)+inputTexel.rgb*(1.-temporalResolveMix);}else{float mixVal=(1./samplesValue)/EULER;if(alpha<FLOAT_EPSILON&&samplesValue<15.)mixVal+=0.3;newColor=mix(lastFrameReflectionsTexel.rgb,inputTexel.rgb,mixVal);}\n#else\nlastFrameReflectionsTexel=texture2D(accumulatedReflectionsTexture,vUv);vec2 velUv=texture2D(velocityTexture,vUv).xy;float movement=length(velUv)*100.;float alpha=min(inputTexel.a,lastFrameReflectionsTexel.a);alpha=samplesValue<2.||movement<FLOAT_EPSILON ?(0.05+alpha): 0.;if(maxSamples!=0.&&samplesValue>maxSamples&&alpha>1.-FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb;}else{float samplesValueMultiplier=pow(samplesValue/32.,4.)+1.;if(samplesValue>1.&&alpha>1.-FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb*(1.-1./(samplesValue*samplesValueMultiplier))+inputTexel.rgb/(samplesValue*samplesValueMultiplier);}else{newColor=inputTexel.rgb;}}\n#endif\ngl_FragColor=vec4(newColor,alpha);}"; // eslint-disable-line | ||
var temporalResolve = "#define GLSLIFY 1\nuniform sampler2D inputTexture;uniform sampler2D accumulatedTexture;uniform sampler2D velocityTexture;uniform sampler2D lastVelocityTexture;uniform sampler2D depthTexture;uniform float temporalResolveCorrectionMix;varying vec2 vUv;\n#include <packing>\n#define min3(a, b, c) min(a, min(b, c))\n#define min4(a, b, c, d) min(a, min3(b, c, d))\n#define min5(a, b, c, d, e) min(a, min4(b, c, d, e))\n#define min6(a, b, c, d, e, f) min(a, min5(b, c, d, e, f))\n#define min7(a, b, c, d, e, f, g) min(a, min6(b, c, d, e, f, g))\n#define min8(a, b, c, d, e, f, g, h) min(a, min7(b, c, d, e, f, g, h))\n#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i))\n#define max3(a, b, c) max(a, max(b, c))\n#define max4(a, b, c, d) max(a, max3(b, c, d))\n#define max5(a, b, c, d, e) max(a, max4(b, c, d, e))\n#define max6(a, b, c, d, e, f) max(a, max5(b, c, d, e, f))\n#define max7(a, b, c, d, e, f, g) max(a, max6(b, c, d, e, f, g))\n#define max8(a, b, c, d, e, f, g, h) max(a, max7(b, c, d, e, f, g, h))\n#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i))\nvec2 getVelocity(sampler2D tex,vec2 uv,vec2 texSize){float closestDepth=100.0;vec2 closestUVOffset;for(int j=-1;j<=1;++j){for(int i=-1;i<=1;++i){vec2 uvOffset=vec2(i,j)/texSize;float neighborDepth=unpackRGBAToDepth(textureLod(depthTexture,vUv+uvOffset,0.));if(neighborDepth<closestDepth){closestUVOffset=uvOffset;closestDepth=neighborDepth;}}}return textureLod(velocityTexture,vUv+closestUVOffset,0.).xy;}void main(){vec4 inputTexel=texture2D(inputTexture,vUv);vec4 accumulatedTexel;vec3 outputColor;ivec2 size=textureSize(inputTexture,0);vec2 pxSize=vec2(float(size.x),float(size.y));vec2 velUv=texture2D(velocityTexture,vUv).xy;vec2 reprojectedUv=vUv-velUv;vec2 lastVelUv=texture2D(lastVelocityTexture,reprojectedUv).xy;float velocityLength=length(lastVelUv-velUv);float velocityDisocclusion=(velocityLength-0.000005)*10.;velocityDisocclusion*=velocityDisocclusion;\n#ifdef DILATION\nvelUv=getVelocity(velocityTexture,vUv,pxSize);reprojectedUv=vUv-velUv;\n#endif\nvec3 averageNeighborColor;bool didReproject=true;float movement=length(velUv)*100.;if(movement>0.){vec2 px=1./pxSize;vec3 c02=texture2D(inputTexture,vUv+vec2(-px.x,px.y)).rgb;vec3 c12=texture2D(inputTexture,vUv+vec2(0.,px.y)).rgb;vec3 c22=texture2D(inputTexture,vUv+vec2(px.x,px.y)).rgb;vec3 c01=texture2D(inputTexture,vUv+vec2(-px.x,0.)).rgb;vec3 c11=inputTexel.rgb;vec3 c21=texture2D(inputTexture,vUv+vec2(px.x,0.)).rgb;vec3 c00=texture2D(inputTexture,vUv+vec2(-px.x,-px.y)).rgb;vec3 c10=texture2D(inputTexture,vUv+vec2(0.,-px.y)).rgb;vec3 c20=texture2D(inputTexture,vUv+vec2(px.x,-px.y)).rgb;averageNeighborColor=c02+c12+c22+c01+c11+c21+c00+c10+c20;averageNeighborColor/=9.;if(reprojectedUv.x>=0.&&reprojectedUv.x<=1.&&reprojectedUv.y>=0.&&reprojectedUv.y<=1.){accumulatedTexel=texture2D(accumulatedTexture,reprojectedUv);vec3 minNeighborColor=min9(c02,c12,c22,c01,c11,c21,c00,c10,c20);vec3 maxNeighborColor=max9(c02,c12,c22,c01,c11,c21,c00,c10,c20);vec3 clampedColor=clamp(accumulatedTexel.rgb,minNeighborColor,maxNeighborColor);float mixFactor=temporalResolveCorrectionMix*(1.+movement);mixFactor=min(mixFactor,1.);accumulatedTexel.rgb=mix(accumulatedTexel.rgb,clampedColor,mixFactor);}else{accumulatedTexel.rgb=inputTexel.rgb;didReproject=false;}}else{accumulatedTexel=texture2D(accumulatedTexture,vUv);}\n#include <custom_compose_shader>\ngl_FragColor=vec4(vec3(outputColor),alpha);}"; // eslint-disable-line | ||
// this shader is from: https://github.com/gkjohnson/threejs-sandbox | ||
// a second set of bone information from the previou frame | ||
const prev_skinning_pars_vertex = | ||
/* glsl */ | ||
` | ||
#ifdef USE_SKINNING | ||
#ifdef BONE_TEXTURE | ||
uniform sampler2D prevBoneTexture; | ||
mat4 getPrevBoneMatrix( const in float i ) { | ||
float j = i * 4.0; | ||
float x = mod( j, float( boneTextureSize ) ); | ||
float y = floor( j / float( boneTextureSize ) ); | ||
float dx = 1.0 / float( boneTextureSize ); | ||
float dy = 1.0 / float( boneTextureSize ); | ||
y = dy * ( y + 0.5 ); | ||
vec4 v1 = texture2D( prevBoneTexture, vec2( dx * ( x + 0.5 ), y ) ); | ||
vec4 v2 = texture2D( prevBoneTexture, vec2( dx * ( x + 1.5 ), y ) ); | ||
vec4 v3 = texture2D( prevBoneTexture, vec2( dx * ( x + 2.5 ), y ) ); | ||
vec4 v4 = texture2D( prevBoneTexture, vec2( dx * ( x + 3.5 ), y ) ); | ||
mat4 bone = mat4( v1, v2, v3, v4 ); | ||
return bone; | ||
} | ||
#else | ||
uniform mat4 prevBoneMatrices[ MAX_BONES ]; | ||
mat4 getPrevBoneMatrix( const in float i ) { | ||
mat4 bone = prevBoneMatrices[ int(i) ]; | ||
return bone; | ||
} | ||
#endif | ||
#endif | ||
`; // Returns the body of the vertex shader for the velocity buffer and | ||
// outputs the position of the current and last frame positions | ||
const velocity_vertex = | ||
/* glsl */ | ||
` | ||
vec3 transformed; | ||
// Get the normal | ||
${ShaderChunk.skinbase_vertex} | ||
${ShaderChunk.beginnormal_vertex} | ||
${ShaderChunk.skinnormal_vertex} | ||
${ShaderChunk.defaultnormal_vertex} | ||
// Get the current vertex position | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinning_vertex} | ||
newPosition = velocityMatrix * vec4( transformed, 1.0 ); | ||
// Get the previous vertex position | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinbase_vertex.replace(/mat4 /g, "").replace(/getBoneMatrix/g, "getPrevBoneMatrix")} | ||
${ShaderChunk.skinning_vertex.replace(/vec4 /g, "")} | ||
prevPosition = prevVelocityMatrix * vec4( transformed, 1.0 ); | ||
gl_Position = newPosition; | ||
`; | ||
const VelocityShader = { | ||
uniforms: { | ||
prevVelocityMatrix: { | ||
value: new Matrix4() | ||
}, | ||
velocityMatrix: { | ||
value: new Matrix4() | ||
}, | ||
prevBoneTexture: { | ||
value: null | ||
}, | ||
interpolateGeometry: { | ||
value: 0 | ||
}, | ||
intensity: { | ||
value: 1 | ||
}, | ||
boneTexture: { | ||
value: null | ||
}, | ||
alphaTest: { | ||
value: 0.0 | ||
}, | ||
map: { | ||
value: null | ||
}, | ||
alphaMap: { | ||
value: null | ||
}, | ||
opacity: { | ||
value: 1.0 | ||
} | ||
}, | ||
vertexShader: | ||
/* glsl */ | ||
` | ||
${ShaderChunk.skinning_pars_vertex} | ||
${prev_skinning_pars_vertex} | ||
uniform mat4 velocityMatrix; | ||
uniform mat4 prevVelocityMatrix; | ||
uniform float interpolateGeometry; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
void main() { | ||
${velocity_vertex} | ||
} | ||
`, | ||
fragmentShader: | ||
/* glsl */ | ||
` | ||
uniform float intensity; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
void main() { | ||
#ifdef NEEDS_FULL_MOVEMENT | ||
gl_FragColor = vec4(1., 1., 1., 1. ); | ||
return; | ||
#endif | ||
vec2 pos0 = (prevPosition.xy / prevPosition.w) * 0.5 + 0.5; | ||
vec2 pos1 = (newPosition.xy / newPosition.w) * 0.5 + 0.5; | ||
vec2 vel = pos1 - pos0; | ||
gl_FragColor = vec4( vel, 0., 1. ); | ||
} | ||
`, | ||
defines: { | ||
MAX_BONES: 256 | ||
} | ||
}; | ||
var _cachedMaterials$1 = /*#__PURE__*/_classPrivateFieldLooseKey("cachedMaterials"); | ||
var _setVelocityMaterialInScene = /*#__PURE__*/_classPrivateFieldLooseKey("setVelocityMaterialInScene"); | ||
var _unsetVelocityMaterialInScene = /*#__PURE__*/_classPrivateFieldLooseKey("unsetVelocityMaterialInScene"); | ||
class VelocityPass extends Pass { | ||
constructor(scene, camera) { | ||
super("VelocityPass"); | ||
Object.defineProperty(this, _unsetVelocityMaterialInScene, { | ||
value: _unsetVelocityMaterialInScene2 | ||
}); | ||
Object.defineProperty(this, _setVelocityMaterialInScene, { | ||
value: _setVelocityMaterialInScene2 | ||
}); | ||
Object.defineProperty(this, _cachedMaterials$1, { | ||
writable: true, | ||
value: new WeakMap() | ||
}); | ||
this._scene = scene; | ||
this._camera = camera; | ||
this.renderTarget = new WebGLRenderTarget(typeof window !== "undefined" ? window.innerWidth : 2000, typeof window !== "undefined" ? window.innerHeight : 1000, { | ||
minFilter: NearestFilter, | ||
magFilter: NearestFilter, | ||
type: HalfFloatType | ||
}); | ||
} | ||
setSize(width, height) { | ||
this.renderTarget.setSize(width, height); | ||
} | ||
render(renderer) { | ||
_classPrivateFieldLooseBase(this, _setVelocityMaterialInScene)[_setVelocityMaterialInScene](); | ||
renderer.setRenderTarget(this.renderTarget); | ||
renderer.clear(); | ||
renderer.render(this._scene, this._camera); | ||
_classPrivateFieldLooseBase(this, _unsetVelocityMaterialInScene)[_unsetVelocityMaterialInScene](); | ||
} | ||
} | ||
function _setVelocityMaterialInScene2() { | ||
this._scene.traverse(c => { | ||
if (c.material) { | ||
const originalMaterial = c.material; | ||
let [cachedOriginalMaterial, velocityMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c) || []; | ||
if (!_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].has(c) || originalMaterial !== cachedOriginalMaterial) { | ||
velocityMaterial = new ShaderMaterial({ | ||
uniforms: UniformsUtils.clone(VelocityShader.uniforms), | ||
vertexShader: VelocityShader.vertexShader, | ||
fragmentShader: VelocityShader.fragmentShader, | ||
side: FrontSide | ||
}); | ||
_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].set(c, [originalMaterial, velocityMaterial]); | ||
} | ||
const needsUpdatedReflections = c.material.userData.needsUpdatedReflections || c.material.map instanceof VideoTexture; // mark the material as "ANIMATED" so that, when using temporal resolve, we get updated reflections | ||
if (needsUpdatedReflections && !Object.keys(velocityMaterial.defines).includes("NEEDS_FULL_MOVEMENT")) { | ||
velocityMaterial.defines.NEEDS_FULL_MOVEMENT = ""; | ||
velocityMaterial.needsUpdate = true; | ||
} else if (!needsUpdatedReflections && Object.keys(velocityMaterial.defines).includes("NEEDS_FULL_MOVEMENT")) { | ||
delete velocityMaterial.defines.NEEDS_FULL_MOVEMENT; | ||
velocityMaterial.needsUpdate = true; | ||
} | ||
velocityMaterial.uniforms.velocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
c.material = velocityMaterial; | ||
} | ||
}); | ||
} | ||
function _unsetVelocityMaterialInScene2() { | ||
this._scene.traverse(c => { | ||
if (c.material) { | ||
c.material.uniforms.prevVelocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
const [originalMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c); | ||
c.material = originalMaterial; | ||
} | ||
}); | ||
} | ||
const zeroVec2 = new Vector2(); | ||
var _ssrEffect$1 = /*#__PURE__*/_classPrivateFieldLooseKey("ssrEffect"); | ||
var _velocityPass = /*#__PURE__*/_classPrivateFieldLooseKey("velocityPass"); | ||
class ComposeReflectionsPass extends Pass { | ||
constructor(ssrEffect, options = {}) { | ||
super("ComposeReflectionsPass"); | ||
Object.defineProperty(this, _ssrEffect$1, { | ||
class TemporalResolvePass extends Pass { | ||
constructor(scene, camera, customComposeShader, options = {}) { | ||
super("TemporalResolvePass"); | ||
Object.defineProperty(this, _velocityPass, { | ||
writable: true, | ||
value: void 0 | ||
value: null | ||
}); | ||
_classPrivateFieldLooseBase(this, _ssrEffect$1)[_ssrEffect$1] = ssrEffect; | ||
const width = options.width || typeof window !== "undefined" ? window.innerWidth : 2000; | ||
@@ -60,10 +285,12 @@ const height = options.height || typeof window !== "undefined" ? window.innerHeight : 1000; | ||
}); | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass] = new VelocityPass(scene, camera); | ||
const fragmentShader = temporalResolve.replace("#include <custom_compose_shader>", customComposeShader); | ||
this.fullscreenMaterial = new ShaderMaterial({ | ||
type: "ComposeReflectionsMaterial", | ||
type: "TemporalResolveMaterial", | ||
uniforms: { | ||
inputTexture: new Uniform(null), | ||
accumulatedReflectionsTexture: new Uniform(null), | ||
velocityTexture: new Uniform(null), | ||
samples: new Uniform(0), | ||
maxSamples: new Uniform(0), | ||
accumulatedTexture: new Uniform(null), | ||
velocityTexture: new Uniform(_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].renderTarget.texture), | ||
lastVelocityTexture: new Uniform(null), | ||
depthTexture: new Uniform(null), | ||
temporalResolveMix: new Uniform(0), | ||
@@ -73,5 +300,6 @@ temporalResolveCorrectionMix: new Uniform(0) | ||
vertexShader, | ||
fragmentShader: fragmentShader$2 | ||
}); | ||
this.setupAccumulatedReflectionsTexture(width, height); | ||
fragmentShader | ||
}); // this.fullscreenMaterial.defines.DILATION = "" | ||
this.setupAccumulatedTexture(width, height); | ||
} | ||
@@ -81,4 +309,6 @@ | ||
this.renderTarget.dispose(); | ||
this.accumulatedReflectionsTexture.dispose(); | ||
this.accumulatedTexture.dispose(); | ||
this.fullscreenMaterial.dispose(); | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].dispose(); | ||
} | ||
@@ -88,21 +318,32 @@ | ||
this.renderTarget.setSize(width, height); | ||
this.accumulatedReflectionsTexture.dispose(); | ||
this.setupAccumulatedReflectionsTexture(width, height); | ||
this.fullscreenMaterial.uniforms.accumulatedReflectionsTexture.value = this.accumulatedReflectionsTexture; | ||
this.fullscreenMaterial.needsUpdate = true; | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].setSize(width, height); | ||
this.setupAccumulatedTexture(width, height); | ||
} | ||
setupAccumulatedReflectionsTexture(width, height) { | ||
this.accumulatedReflectionsTexture = new FramebufferTexture(width, height, RGBAFormat); | ||
this.accumulatedReflectionsTexture.minFilter = LinearFilter; | ||
this.accumulatedReflectionsTexture.magFilter = LinearFilter; | ||
this.accumulatedReflectionsTexture.type = HalfFloatType; | ||
setupAccumulatedTexture(width, height) { | ||
if (this.accumulatedTexture) this.accumulatedTexture.dispose(); | ||
this.accumulatedTexture = new FramebufferTexture(width, height, RGBAFormat); | ||
this.accumulatedTexture.minFilter = LinearFilter; | ||
this.accumulatedTexture.magFilter = LinearFilter; | ||
this.accumulatedTexture.type = HalfFloatType; | ||
this.lastVelocityTexture = new FramebufferTexture(width, height, RGBAFormat); | ||
this.lastVelocityTexture.minFilter = NearestFilter; | ||
this.lastVelocityTexture.magFilter = NearestFilter; | ||
this.lastVelocityTexture.type = HalfFloatType; | ||
this.fullscreenMaterial.uniforms.accumulatedTexture.value = this.accumulatedTexture; | ||
this.fullscreenMaterial.uniforms.lastVelocityTexture.value = this.lastVelocityTexture; | ||
this.fullscreenMaterial.needsUpdate = true; | ||
} | ||
render(renderer) { | ||
this.fullscreenMaterial.uniforms.samples.value = _classPrivateFieldLooseBase(this, _ssrEffect$1)[_ssrEffect$1].samples; | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].render(renderer); | ||
renderer.setRenderTarget(this.renderTarget); | ||
renderer.render(this.scene, this.camera); // save the render target's texture for use in next frame | ||
renderer.copyFramebufferToTexture(zeroVec2, this.accumulatedReflectionsTexture); | ||
renderer.copyFramebufferToTexture(zeroVec2, this.accumulatedTexture); | ||
renderer.setRenderTarget(_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].renderTarget); | ||
renderer.copyFramebufferToTexture(zeroVec2, this.lastVelocityTexture); | ||
} | ||
@@ -114,4 +355,8 @@ | ||
var fragmentShader$1 = "#define GLSLIFY 1\n#define MODE_DEFAULT 0\n#define MODE_REFLECTIONS 1\n#define MODE_RAW_REFLECTION 2\n#define MODE_BLURRED_REFLECTIONS 3\n#define MODE_INPUT 4\n#define MODE_BLUR_MIX 5\n#define FLOAT_EPSILON 0.00001\n#define SQRT_3 1.7320508075688772 + FLOAT_EPSILON\nuniform sampler2D inputTexture;uniform sampler2D reflectionsTexture;\n#ifdef ENABLE_BLUR\nuniform sampler2D depthTexture;\n#endif\nuniform float samples;uniform float blurMix;\n#include <bilateralBlur>\nvoid mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor){vec4 reflectionsTexel=texture2D(reflectionsTexture,vUv);vec3 reflectionClr=reflectionsTexel.xyz;\n#ifdef ENABLE_BLUR\nvec4 blurredReflectionsTexel=blur(reflectionsTexture,depthTexture);reflectionClr=mix(reflectionClr,blurredReflectionsTexel.xyz,blurMix);\n#endif\n#if RENDER_MODE == MODE_DEFAULT\noutputColor=vec4(inputColor.rgb+reflectionClr,1.);\n#endif\n#if RENDER_MODE == MODE_REFLECTIONS\noutputColor=vec4(reflectionClr,1.);\n#endif\n#if RENDER_MODE == MODE_RAW_REFLECTION\noutputColor=vec4(reflectionsTexel.xyz,1.);\n#endif\n#if RENDER_MODE == MODE_BLURRED_REFLECTIONS\n#ifdef ENABLE_BLUR\noutputColor=vec4(blurredReflectionsTexel.xyz,1.);\n#endif\n#endif\n#if RENDER_MODE == MODE_INPUT\noutputColor=vec4(inputColor.xyz,1.);\n#endif\n#if RENDER_MODE == MODE_BLUR_MIX\n#ifdef ENABLE_BLUR\noutputColor=vec4(vec3(blurMix),1.);\n#endif\n#endif\n}"; // eslint-disable-line | ||
var finalSSRShader = "#define GLSLIFY 1\n#define MODE_DEFAULT 0\n#define MODE_REFLECTIONS 1\n#define MODE_RAW_REFLECTION 2\n#define MODE_BLURRED_REFLECTIONS 3\n#define MODE_INPUT 4\n#define MODE_BLUR_MIX 5\n#define FLOAT_EPSILON 0.00001\n#define SQRT_3 1.7320508075688772 + FLOAT_EPSILON\nuniform sampler2D inputTexture;uniform sampler2D reflectionsTexture;\n#ifdef ENABLE_BLUR\nuniform sampler2D depthTexture;\n#endif\nuniform float samples;uniform float blurMix;\n#include <bilateralBlur>\nvoid mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor){vec4 reflectionsTexel=texture2D(reflectionsTexture,vUv);vec3 reflectionClr=reflectionsTexel.xyz;\n#ifdef ENABLE_BLUR\nvec4 blurredReflectionsTexel=blur(reflectionsTexture,depthTexture);reflectionClr=mix(reflectionClr,blurredReflectionsTexel.xyz,blurMix);\n#endif\n#if RENDER_MODE == MODE_DEFAULT\noutputColor=vec4(inputColor.rgb+reflectionClr,1.);\n#endif\n#if RENDER_MODE == MODE_REFLECTIONS\noutputColor=vec4(reflectionClr,1.);\n#endif\n#if RENDER_MODE == MODE_RAW_REFLECTION\noutputColor=vec4(reflectionsTexel.xyz,1.);\n#endif\n#if RENDER_MODE == MODE_BLURRED_REFLECTIONS\n#ifdef ENABLE_BLUR\noutputColor=vec4(blurredReflectionsTexel.xyz,1.);\n#endif\n#endif\n#if RENDER_MODE == MODE_INPUT\noutputColor=vec4(inputColor.xyz,1.);\n#endif\n#if RENDER_MODE == MODE_BLUR_MIX\n#ifdef ENABLE_BLUR\noutputColor=vec4(vec3(blurMix),1.);\n#endif\n#endif\n}"; // eslint-disable-line | ||
var customTRComposeShader = "#define GLSLIFY 1\nfloat alpha=min(inputTexel.a,accumulatedTexel.a);alpha=didReproject&&(samples<4.||velocityDisocclusion<FLOAT_EPSILON)?(0.05+alpha): 0.;if(maxSamples!=0.&&samples>maxSamples&&alpha>1.-FLOAT_EPSILON){gl_FragColor=accumulatedTexel;return;}if(!didReproject){gl_FragColor=vec4(averageNeighborColor,alpha);return;}if(length(accumulatedTexel.rgb)>FLOAT_EPSILON&&length(inputTexel.rgb)==0.){gl_FragColor=accumulatedTexel;return;}if(alpha<1.){outputColor=mix(accumulatedTexel.rgb,inputTexel.rgb,(1.-alpha*alpha)*temporalResolveCorrectionMix);}else if(samples>4.&&movement<FLOAT_EPSILON&&length(accumulatedTexel.rgb)<FLOAT_EPSILON){outputColor=accumulatedTexel.rgb;}else if(1./samples>=1.-temporalResolveMix){outputColor=accumulatedTexel.rgb*temporalResolveMix+inputTexel.rgb*(1.-temporalResolveMix);}else{float mixVal=(1./samples)/EULER;if(alpha<FLOAT_EPSILON&&samples<15.)mixVal+=0.3;outputColor=mix(accumulatedTexel.rgb,inputTexel.rgb,mixVal);}"; // eslint-disable-line | ||
var customBasicComposeShader = "#define GLSLIFY 1\naccumulatedTexel=textureLod(accumulatedTexture,vUv,0.);float alpha=min(inputTexel.a,accumulatedTexel.a);alpha=samples<2.||movement<FLOAT_EPSILON ?(0.05+alpha): 0.;if(maxSamples!=0.&&samples>maxSamples&&alpha>1.-FLOAT_EPSILON){outputColor=accumulatedTexel.rgb;}else{float samplesMultiplier=pow(samples/32.,4.)+1.;if(samples>1.&&alpha>1.-FLOAT_EPSILON){outputColor=accumulatedTexel.rgb*(1.-1./(samples*samplesMultiplier))+inputTexel.rgb/(samples*samplesMultiplier);}else{outputColor=inputTexel.rgb;}}"; // eslint-disable-line | ||
var helperFunctions = "#define GLSLIFY 1\nvec3 getViewPosition(const float depth){float clipW=_projectionMatrix[2][3]*depth+_projectionMatrix[3][3];vec4 clipPosition=vec4((vec3(vUv,depth)-0.5)*2.0,1.0);clipPosition*=clipW;return(_inverseProjectionMatrix*clipPosition).xyz;}float getViewZ(const in float depth){\n#ifdef PERSPECTIVE_CAMERA\nreturn perspectiveDepthToViewZ(depth,cameraNear,cameraFar);\n#else\nreturn orthographicDepthToViewZ(depth,cameraNear,cameraFar);\n#endif\n}vec3 screenSpaceToWorldSpace(const vec2 uv,const float depth){vec4 ndc=vec4((uv.x-0.5)*2.0,(uv.y-0.5)*2.0,(depth-0.5)*2.0,1.0);vec4 clip=_inverseProjectionMatrix*ndc;vec4 view=cameraMatrixWorld*(clip/clip.w);return view.xyz;}\n#define Scale (vec3(0.8, 0.8, 0.8))\n#define K (19.19)\nvec3 hash(vec3 a){a=fract(a*Scale);a+=dot(a,a.yxz+K);return fract((a.xxy+a.yxx)*a.zyx);}float fresnel_dielectric_cos(float cosi,float eta){float c=abs(cosi);float g=eta*eta-1.0+c*c;float result;if(g>0.0){g=sqrt(g);float A=(g-c)/(g+c);float B=(c*(g+c)-1.0)/(c*(g-c)+1.0);result=0.5*A*A*(1.0+B*B);}else{result=1.0;}return result;}float fresnel_dielectric(vec3 Incoming,vec3 Normal,float eta){float cosine=dot(Incoming,Normal);return min(1.0,5.0*fresnel_dielectric_cos(cosine,eta));}float czm_luminance(vec3 rgb){const vec3 W=vec3(0.2125,0.7154,0.0721);return dot(rgb,W);}"; // eslint-disable-line | ||
@@ -250,3 +495,3 @@ | ||
var fragmentShader = "#define GLSLIFY 1\nvarying vec2 vUv;uniform sampler2D inputTexture;uniform sampler2D accumulatedReflectionsTexture;uniform sampler2D normalTexture;uniform sampler2D depthTexture;uniform mat4 _projectionMatrix;uniform mat4 _inverseProjectionMatrix;uniform mat4 cameraMatrixWorld;uniform float cameraNear;uniform float cameraFar;uniform float rayStep;uniform float intensity;uniform float maxDepthDifference;uniform float roughnessFadeOut;uniform float maxRoughness;uniform float maxDepth;uniform float rayFadeOut;uniform float thickness;uniform float ior;uniform float samples;\n#ifdef ENABLE_JITTERING\nuniform float jitter;uniform float jitterRough;uniform float jitterSpread;\n#endif\n#define FLOAT_EPSILON 0.00001\n#define EARLY_OUT_COLOR vec4(0., 0., 0., 1.)\nconst vec2 INVALID_RAY_COORDS=vec2(-1.);float _maxDepthDifference;\n#include <packing>\n#include <helperFunctions>\nvec2 BinarySearch(inout vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference);vec2 RayMarch(vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference);void main(){\n#ifdef DITHERING\nivec2 size=textureSize(inputTexture,0);vec2 pxSize=vec2(float(size.x),float(size.y));int x=int(vUv.x*pxSize.x);int y=int(vUv.y*pxSize.y);int rest=int(samples)% 2;if(x % 2==rest||y % 2==rest){gl_FragColor=EARLY_OUT_COLOR;return;}\n#endif\nvec4 depthTexel=textureLod(depthTexture,vUv,0.);if(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON){gl_FragColor=EARLY_OUT_COLOR;return;}float unpackedDepth=unpackRGBAToDepth(depthTexel);if(unpackedDepth>maxDepth){gl_FragColor=EARLY_OUT_COLOR;return;}vec4 normalTexel=textureLod(normalTexture,vUv,0.);float roughness=normalTexel.a;if(roughness>maxRoughness||(roughness>1.-FLOAT_EPSILON&&roughnessFadeOut>1.-FLOAT_EPSILON)){gl_FragColor=EARLY_OUT_COLOR;return;}float specular=1.-roughness;specular*=specular;normalTexel.rgb=unpackRGBToNormal(normalTexel.rgb);float depth=getViewZ(unpackedDepth);vec3 viewNormal=normalTexel.xyz;vec3 viewPos=getViewPosition(depth);vec3 worldPos=screenSpaceToWorldSpace(vUv,unpackedDepth);vec3 jitt=vec3(0.);\n#ifdef ENABLE_JITTERING\nvec3 randomJitter=hash(5.*(samples*worldPos))-0.5;float spread=((2.-specular)+roughness*jitterRough)*jitterSpread;float jitterMix=jitter+jitterRough*roughness;if(jitterMix>1.)jitterMix=1.;jitt=mix(vec3(0.),randomJitter*spread,jitterMix);\n#endif\njitt=mix(jitt,vec3(0.),0.5);viewNormal+=jitt;vec3 reflected=normalize(reflect(normalize(viewPos),normalize(viewNormal)));_maxDepthDifference=maxDepthDifference*0.01;vec3 rayDir=reflected*-viewPos.z;vec3 hitPos=viewPos;float rayHitDepthDifference;vec2 coords=RayMarch(rayDir,hitPos,rayHitDepthDifference);if(coords.x==-1.){gl_FragColor=EARLY_OUT_COLOR;return;}vec2 coordsNDC=(coords*2.0-1.0);float screenFade=0.1;float maxDimension=min(1.0,max(abs(coordsNDC.x),abs(coordsNDC.y)));float screenEdgefactor=1.0-(max(0.0,maxDimension-screenFade)/(1.0-screenFade));screenEdgefactor=max(0.,screenEdgefactor);vec4 SSRTexel=textureLod(inputTexture,coords.xy,0.);vec4 SSRTexelReflected=textureLod(accumulatedReflectionsTexture,coords.xy,0.);vec3 SSR=SSRTexel.rgb+SSRTexelReflected.rgb;float roughnessFactor=mix(specular,1.,max(0.,1.-roughnessFadeOut));vec3 finalSSR=SSR*screenEdgefactor*roughnessFactor;vec3 hitWorldPos=screenSpaceToWorldSpace(coords,rayHitDepthDifference);float reflectionDistance=distance(hitWorldPos,worldPos);reflectionDistance+=1.;if(rayFadeOut!=0.){float opacity=1./(reflectionDistance*rayFadeOut*0.1);if(opacity>1.)opacity=1.;finalSSR*=opacity;}float fresnelFactor=fresnel_dielectric(normalize(viewPos),viewNormal,ior);finalSSR=finalSSR*fresnelFactor*intensity;\n#ifdef DITHERING\nfinalSSR*=2.;\n#endif\nfinalSSR=min(vec3(1.),finalSSR);float alpha=hitPos.z==1. ? SSRTexel.a : SSRTexelReflected.a;gl_FragColor=vec4(finalSSR,alpha);}vec2 RayMarch(vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference){dir=normalize(dir);dir*=rayStep;float depth;vec4 projectedCoord;vec4 lastProjectedCoord;float unpackedDepth;float stepMultiplier=1.;vec4 depthTexel;for(int i=0;i<MAX_STEPS;i++){hitPos+=dir*stepMultiplier;projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;if(projectedCoord.x>1.||projectedCoord.y>1.){hitPos-=dir*stepMultiplier;stepMultiplier*=0.5;continue;}depthTexel=textureLod(depthTexture,projectedCoord.xy,0.);unpackedDepth=unpackRGBAToDepth(depthTexel);depth=getViewZ(unpackedDepth);rayHitDepthDifference=depth-hitPos.z;if(rayHitDepthDifference>=0.&&rayHitDepthDifference<thickness){\n#if NUM_BINARY_SEARCH_STEPS == 0\nif(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON)return INVALID_RAY_COORDS;\n#else\nreturn BinarySearch(dir,hitPos,rayHitDepthDifference);\n#endif\n}lastProjectedCoord=projectedCoord;}\n#ifndef STRETCH_MISSED_RAYS\nreturn INVALID_RAY_COORDS;\n#endif\nrayHitDepthDifference=unpackedDepth;hitPos.z=1.;return projectedCoord.xy;}vec2 BinarySearch(inout vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference){float depth;vec4 projectedCoord;vec2 lastMinProjectedCoordXY;float unpackedDepth;vec4 depthTexel;for(int i=0;i<NUM_BINARY_SEARCH_STEPS;i++){projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;if((lastMinProjectedCoordXY.x>1.||lastMinProjectedCoordXY.y>1.)&&(projectedCoord.x>1.||projectedCoord.y>1.))return INVALID_RAY_COORDS;depthTexel=textureLod(depthTexture,projectedCoord.xy,0.);unpackedDepth=unpackRGBAToDepth(depthTexel);depth=getViewZ(unpackedDepth);rayHitDepthDifference=depth-hitPos.z;dir*=0.5;if(rayHitDepthDifference>0.0){hitPos-=dir;}else{hitPos+=dir;lastMinProjectedCoordXY=projectedCoord.xy;}}if(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON)return INVALID_RAY_COORDS;if(abs(rayHitDepthDifference)>_maxDepthDifference)return INVALID_RAY_COORDS;projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;rayHitDepthDifference=unpackedDepth;return projectedCoord.xy;}"; // eslint-disable-line | ||
var fragmentShader = "#define GLSLIFY 1\nvarying vec2 vUv;uniform sampler2D inputTexture;uniform sampler2D accumulatedTexture;uniform sampler2D normalTexture;uniform sampler2D depthTexture;uniform mat4 _projectionMatrix;uniform mat4 _inverseProjectionMatrix;uniform mat4 cameraMatrixWorld;uniform float cameraNear;uniform float cameraFar;uniform float rayStep;uniform float intensity;uniform float maxDepthDifference;uniform float roughnessFadeOut;uniform float maxRoughness;uniform float maxDepth;uniform float rayFadeOut;uniform float thickness;uniform float ior;uniform float samples;\n#ifdef ENABLE_JITTERING\nuniform float jitter;uniform float jitterRough;uniform float jitterSpread;\n#endif\n#define FLOAT_EPSILON 0.00001\n#define EARLY_OUT_COLOR vec4(0., 0., 0., 1.)\nconst vec2 INVALID_RAY_COORDS=vec2(-1.);float _maxDepthDifference;float nearMinusFar;float nearMulFar;float farMinusNear;\n#include <packing>\n#include <helperFunctions>\nvec2 BinarySearch(inout vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference);vec2 RayMarch(vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference);float fastGetViewZ(const in float depth);void main(){vec4 depthTexel=textureLod(depthTexture,vUv,0.);if(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON){gl_FragColor=EARLY_OUT_COLOR;return;}float unpackedDepth=unpackRGBAToDepth(depthTexel);if(unpackedDepth>maxDepth){gl_FragColor=EARLY_OUT_COLOR;return;}vec4 normalTexel=textureLod(normalTexture,vUv,0.);float roughness=normalTexel.a;if(roughness>maxRoughness||(roughness>1.-FLOAT_EPSILON&&roughnessFadeOut>1.-FLOAT_EPSILON)){gl_FragColor=EARLY_OUT_COLOR;return;}_maxDepthDifference=maxDepthDifference*0.01;nearMinusFar=cameraNear-cameraFar;nearMulFar=cameraNear*cameraFar;farMinusNear=cameraFar-cameraNear;float specular=1.-roughness;specular*=specular;normalTexel.rgb=unpackRGBToNormal(normalTexel.rgb);float depth=fastGetViewZ(unpackedDepth);vec3 viewNormal=normalTexel.xyz;vec3 viewPos=getViewPosition(depth);vec3 worldPos=screenSpaceToWorldSpace(vUv,unpackedDepth);vec3 jitt=vec3(0.);\n#ifdef ENABLE_JITTERING\nvec3 randomJitter=hash(5.*(samples*worldPos))-0.5;float spread=((2.-specular)+roughness*jitterRough)*jitterSpread;float jitterMix=jitter+jitterRough*roughness;if(jitterMix>1.)jitterMix=1.;jitt=mix(vec3(0.),randomJitter*spread,jitterMix);\n#endif\njitt=mix(jitt,vec3(0.),0.5);viewNormal+=jitt;vec3 reflected=normalize(reflect(normalize(viewPos),normalize(viewNormal)));vec3 rayDir=reflected*-viewPos.z;vec3 hitPos=viewPos;float rayHitDepthDifference;vec2 coords=RayMarch(rayDir,hitPos,rayHitDepthDifference);if(coords.x==-1.){gl_FragColor=EARLY_OUT_COLOR;return;}vec2 coordsNDC=(coords*2.0-1.0);float screenFade=0.1;float maxDimension=min(1.0,max(abs(coordsNDC.x),abs(coordsNDC.y)));float screenEdgefactor=1.0-(max(0.0,maxDimension-screenFade)/(1.0-screenFade));screenEdgefactor=max(0.,screenEdgefactor);vec4 SSRTexel=textureLod(inputTexture,coords.xy,0.);vec4 SSRTexelReflected=textureLod(accumulatedTexture,coords.xy,0.);vec3 SSR=SSRTexel.rgb+SSRTexelReflected.rgb;float roughnessFactor=mix(specular,1.,max(0.,1.-roughnessFadeOut));vec3 finalSSR=SSR*screenEdgefactor*roughnessFactor;if(rayFadeOut!=0.){vec3 hitWorldPos=screenSpaceToWorldSpace(coords,rayHitDepthDifference);float reflectionDistance=distance(hitWorldPos,worldPos);reflectionDistance+=1.;float opacity=1./(reflectionDistance*rayFadeOut*0.1);if(opacity>1.)opacity=1.;finalSSR*=opacity;}float fresnelFactor=fresnel_dielectric(normalize(viewPos),viewNormal,ior);finalSSR=finalSSR*fresnelFactor*intensity;finalSSR=min(vec3(1.),finalSSR);float alpha=hitPos.z==1. ? SSRTexel.a : SSRTexelReflected.a;gl_FragColor=vec4(finalSSR,alpha);}vec2 RayMarch(vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference){dir=normalize(dir);dir*=rayStep;float depth;vec4 projectedCoord;vec4 lastProjectedCoord;float unpackedDepth;float stepMultiplier=1.;vec4 depthTexel;for(int i=0;i<MAX_STEPS;i++){hitPos+=dir*stepMultiplier;projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;if(projectedCoord.x>1.||projectedCoord.y>1.){hitPos-=dir*stepMultiplier;stepMultiplier*=0.5;continue;}depthTexel=textureLod(depthTexture,projectedCoord.xy,0.);unpackedDepth=unpackRGBAToDepth(depthTexel);depth=fastGetViewZ(unpackedDepth);rayHitDepthDifference=depth-hitPos.z;if(rayHitDepthDifference>=0.&&rayHitDepthDifference<thickness){\n#if NUM_BINARY_SEARCH_STEPS == 0\nif(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON)return INVALID_RAY_COORDS;\n#else\nreturn BinarySearch(dir,hitPos,rayHitDepthDifference);\n#endif\n}lastProjectedCoord=projectedCoord;}\n#ifndef STRETCH_MISSED_RAYS\nreturn INVALID_RAY_COORDS;\n#endif\nrayHitDepthDifference=unpackedDepth;hitPos.z=1.;return projectedCoord.xy;}vec2 BinarySearch(inout vec3 dir,inout vec3 hitPos,inout float rayHitDepthDifference){float depth;vec4 projectedCoord;vec2 lastMinProjectedCoordXY;float unpackedDepth;vec4 depthTexel;for(int i=0;i<NUM_BINARY_SEARCH_STEPS;i++){projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;if((lastMinProjectedCoordXY.x>1.||lastMinProjectedCoordXY.y>1.)&&(projectedCoord.x>1.||projectedCoord.y>1.))return INVALID_RAY_COORDS;depthTexel=textureLod(depthTexture,projectedCoord.xy,0.);unpackedDepth=unpackRGBAToDepth(depthTexel);depth=fastGetViewZ(unpackedDepth);rayHitDepthDifference=depth-hitPos.z;dir*=0.5;if(rayHitDepthDifference>0.0){hitPos-=dir;}else{hitPos+=dir;lastMinProjectedCoordXY=projectedCoord.xy;}}if(dot(depthTexel.rgb,depthTexel.rgb)<FLOAT_EPSILON)return INVALID_RAY_COORDS;if(abs(rayHitDepthDifference)>_maxDepthDifference)return INVALID_RAY_COORDS;projectedCoord=_projectionMatrix*vec4(hitPos,1.0);projectedCoord.xy/=projectedCoord.w;projectedCoord.xy=projectedCoord.xy*0.5+0.5;rayHitDepthDifference=unpackedDepth;return projectedCoord.xy;}float fastGetViewZ(const in float depth){\n#ifdef PERSPECTIVE_CAMERA\nreturn nearMulFar/(farMinusNear*depth-cameraFar);\n#else\nreturn depth*nearMinusFar-cameraNear;\n#endif\n}"; // eslint-disable-line | ||
@@ -259,3 +504,3 @@ class ReflectionsMaterial extends ShaderMaterial { | ||
inputTexture: new Uniform(null), | ||
accumulatedReflectionsTexture: new Uniform(null), | ||
accumulatedTexture: new Uniform(null), | ||
normalTexture: new Uniform(null), | ||
@@ -296,227 +541,2 @@ depthTexture: new Uniform(null), | ||
// a second set of bone information from the previou frame | ||
const prev_skinning_pars_vertex = | ||
/* glsl */ | ||
` | ||
#ifdef USE_SKINNING | ||
#ifdef BONE_TEXTURE | ||
uniform sampler2D prevBoneTexture; | ||
mat4 getPrevBoneMatrix( const in float i ) { | ||
float j = i * 4.0; | ||
float x = mod( j, float( boneTextureSize ) ); | ||
float y = floor( j / float( boneTextureSize ) ); | ||
float dx = 1.0 / float( boneTextureSize ); | ||
float dy = 1.0 / float( boneTextureSize ); | ||
y = dy * ( y + 0.5 ); | ||
vec4 v1 = texture2D( prevBoneTexture, vec2( dx * ( x + 0.5 ), y ) ); | ||
vec4 v2 = texture2D( prevBoneTexture, vec2( dx * ( x + 1.5 ), y ) ); | ||
vec4 v3 = texture2D( prevBoneTexture, vec2( dx * ( x + 2.5 ), y ) ); | ||
vec4 v4 = texture2D( prevBoneTexture, vec2( dx * ( x + 3.5 ), y ) ); | ||
mat4 bone = mat4( v1, v2, v3, v4 ); | ||
return bone; | ||
} | ||
#else | ||
uniform mat4 prevBoneMatrices[ MAX_BONES ]; | ||
mat4 getPrevBoneMatrix( const in float i ) { | ||
mat4 bone = prevBoneMatrices[ int(i) ]; | ||
return bone; | ||
} | ||
#endif | ||
#endif | ||
`; // Returns the body of the vertex shader for the velocity buffer and | ||
// outputs the position of the current and last frame positions | ||
const velocity_vertex = | ||
/* glsl */ | ||
` | ||
vec3 transformed; | ||
// Get the normal | ||
${ShaderChunk.skinbase_vertex} | ||
${ShaderChunk.beginnormal_vertex} | ||
${ShaderChunk.skinnormal_vertex} | ||
${ShaderChunk.defaultnormal_vertex} | ||
// Get the current vertex position | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinning_vertex} | ||
newPosition = velocityMatrix * vec4( transformed, 1.0 ); | ||
// Get the previous vertex position | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinbase_vertex.replace(/mat4 /g, "").replace(/getBoneMatrix/g, "getPrevBoneMatrix")} | ||
${ShaderChunk.skinning_vertex.replace(/vec4 /g, "")} | ||
prevPosition = prevVelocityMatrix * vec4( transformed, 1.0 ); | ||
gl_Position = newPosition; | ||
`; | ||
const VelocityShader = { | ||
uniforms: { | ||
prevVelocityMatrix: { | ||
value: new Matrix4() | ||
}, | ||
velocityMatrix: { | ||
value: new Matrix4() | ||
}, | ||
prevBoneTexture: { | ||
value: null | ||
}, | ||
interpolateGeometry: { | ||
value: 0 | ||
}, | ||
intensity: { | ||
value: 1 | ||
}, | ||
boneTexture: { | ||
value: null | ||
}, | ||
alphaTest: { | ||
value: 0.0 | ||
}, | ||
map: { | ||
value: null | ||
}, | ||
alphaMap: { | ||
value: null | ||
}, | ||
opacity: { | ||
value: 1.0 | ||
} | ||
}, | ||
vertexShader: | ||
/* glsl */ | ||
` | ||
${ShaderChunk.skinning_pars_vertex} | ||
${prev_skinning_pars_vertex} | ||
uniform mat4 velocityMatrix; | ||
uniform mat4 prevVelocityMatrix; | ||
uniform float interpolateGeometry; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
void main() { | ||
${velocity_vertex} | ||
} | ||
`, | ||
fragmentShader: | ||
/* glsl */ | ||
` | ||
uniform float intensity; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
void main() { | ||
#ifdef NEEDS_UPDATED_REFLECTIONS | ||
gl_FragColor = vec4(1., 1., 1., 1. ); | ||
return; | ||
#endif | ||
vec2 pos0 = (prevPosition.xy / prevPosition.w) * 0.5 + 0.5; | ||
vec2 pos1 = (newPosition.xy / newPosition.w) * 0.5 + 0.5; | ||
vec2 vel = pos1 - pos0; | ||
gl_FragColor = vec4( vel, 0., 1. ); | ||
} | ||
`, | ||
defines: { | ||
MAX_BONES: 256 | ||
} | ||
}; | ||
var _cachedMaterials$1 = /*#__PURE__*/_classPrivateFieldLooseKey("cachedMaterials"); | ||
var _setVelocityMaterialInScene = /*#__PURE__*/_classPrivateFieldLooseKey("setVelocityMaterialInScene"); | ||
var _unsetVelocityMaterialInScene = /*#__PURE__*/_classPrivateFieldLooseKey("unsetVelocityMaterialInScene"); | ||
class VelocityPass extends Pass { | ||
constructor(scene, camera) { | ||
super("VelocityPass"); | ||
Object.defineProperty(this, _unsetVelocityMaterialInScene, { | ||
value: _unsetVelocityMaterialInScene2 | ||
}); | ||
Object.defineProperty(this, _setVelocityMaterialInScene, { | ||
value: _setVelocityMaterialInScene2 | ||
}); | ||
Object.defineProperty(this, _cachedMaterials$1, { | ||
writable: true, | ||
value: new WeakMap() | ||
}); | ||
this._scene = scene; | ||
this._camera = camera; | ||
this.renderTarget = new WebGLRenderTarget(typeof window !== "undefined" ? window.innerWidth : 2000, typeof window !== "undefined" ? window.innerHeight : 1000, { | ||
minFilter: LinearFilter, | ||
magFilter: LinearFilter, | ||
type: HalfFloatType | ||
}); | ||
} | ||
setSize(width, height) { | ||
this.renderTarget.setSize(width, height); | ||
} | ||
render(renderer) { | ||
_classPrivateFieldLooseBase(this, _setVelocityMaterialInScene)[_setVelocityMaterialInScene](); | ||
renderer.setRenderTarget(this.renderTarget); | ||
renderer.clear(); | ||
renderer.render(this._scene, this._camera); | ||
_classPrivateFieldLooseBase(this, _unsetVelocityMaterialInScene)[_unsetVelocityMaterialInScene](); | ||
} | ||
} | ||
function _setVelocityMaterialInScene2() { | ||
this._scene.traverse(c => { | ||
if (c.material) { | ||
const originalMaterial = c.material; | ||
let [cachedOriginalMaterial, velocityMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c) || []; | ||
if (!_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].has(c) || originalMaterial !== cachedOriginalMaterial) { | ||
velocityMaterial = new ShaderMaterial({ | ||
uniforms: UniformsUtils.clone(VelocityShader.uniforms), | ||
vertexShader: VelocityShader.vertexShader, | ||
fragmentShader: VelocityShader.fragmentShader, | ||
side: FrontSide | ||
}); | ||
_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].set(c, [originalMaterial, velocityMaterial]); | ||
} | ||
const needsUpdatedReflections = c.material.userData.needsUpdatedReflections || c.material.map instanceof VideoTexture; // mark the material as "ANIMATED" so that, when using temporal resolve, we get updated reflections | ||
if (needsUpdatedReflections && !Object.keys(velocityMaterial.defines).includes("NEEDS_UPDATED_REFLECTIONS")) { | ||
velocityMaterial.defines.NEEDS_UPDATED_REFLECTIONS = ""; | ||
velocityMaterial.needsUpdate = true; | ||
} else if (!needsUpdatedReflections && Object.keys(velocityMaterial.defines).includes("NEEDS_UPDATED_REFLECTIONS")) { | ||
delete velocityMaterial.defines.NEEDS_UPDATED_REFLECTIONS; | ||
velocityMaterial.needsUpdate = true; | ||
} | ||
velocityMaterial.uniforms.velocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
c.material = velocityMaterial; | ||
} | ||
}); | ||
} | ||
function _unsetVelocityMaterialInScene2() { | ||
this._scene.traverse(c => { | ||
if (c.material) { | ||
c.material.uniforms.prevVelocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
const [originalMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c); | ||
c.material = originalMaterial; | ||
} | ||
}); | ||
} | ||
const isWebGL2Available = () => { | ||
@@ -539,4 +559,2 @@ try { | ||
var _velocityPass = /*#__PURE__*/_classPrivateFieldLooseKey("velocityPass"); | ||
var _keepMaterialMapUpdated = /*#__PURE__*/_classPrivateFieldLooseKey("keepMaterialMapUpdated"); | ||
@@ -576,6 +594,2 @@ | ||
}); | ||
Object.defineProperty(this, _velocityPass, { | ||
writable: true, | ||
value: null | ||
}); | ||
_classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect] = ssrEffect; | ||
@@ -621,10 +635,8 @@ this._scene = ssrEffect._scene; | ||
this.depthTexture = _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].texture; | ||
} | ||
} // set up uniforms | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass] = new VelocityPass(this._scene, this._camera); | ||
this.velocityTexture = _classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].renderTarget.texture; // set up uniforms | ||
this.fullscreenMaterial.uniforms.normalTexture.value = this.normalTexture; | ||
this.fullscreenMaterial.uniforms.depthTexture.value = this.depthTexture; | ||
this.fullscreenMaterial.uniforms.accumulatedReflectionsTexture.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].composeReflectionsPass.accumulatedReflectionsTexture; | ||
this.fullscreenMaterial.uniforms.accumulatedTexture.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].temporalResolvePass.accumulatedTexture; | ||
this.fullscreenMaterial.uniforms.cameraMatrixWorld.value = this._camera.matrixWorld; | ||
@@ -638,6 +650,3 @@ this.fullscreenMaterial.uniforms._projectionMatrix.value = this._camera.projectionMatrix; | ||
this.gBuffersRenderTarget.setSize(width * _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].resolutionScale, height * _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].resolutionScale); | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].setSize(width, height); | ||
this.fullscreenMaterial.uniforms.accumulatedReflectionsTexture.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].composeReflectionsPass.accumulatedReflectionsTexture; | ||
this.fullscreenMaterial.uniforms.accumulatedTexture.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].temporalResolvePass.accumulatedTexture; | ||
this.fullscreenMaterial.needsUpdate = true; | ||
@@ -650,5 +659,2 @@ } | ||
this.renderPass.dispose(); | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].dispose(); | ||
if (!_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].dispose(); | ||
@@ -671,3 +677,2 @@ this.fullscreenMaterial.dispose(); | ||
if (!_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderPass.render(renderer, _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget); | ||
if (_classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].temporalResolve) _classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].render(renderer); | ||
this.fullscreenMaterial.uniforms.inputTexture.value = inputBuffer.texture; | ||
@@ -745,3 +750,3 @@ this.fullscreenMaterial.uniforms.samples.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].samples; | ||
const finalFragmentShader = fragmentShader$1.replace("#include <helperFunctions>", helperFunctions).replace("#include <bilateralBlur>", bilateralBlur); | ||
const finalFragmentShader = finalSSRShader.replace("#include <helperFunctions>", helperFunctions).replace("#include <bilateralBlur>", bilateralBlur); | ||
const defaultSSROptions = { | ||
@@ -770,7 +775,6 @@ temporalResolve: true, | ||
NUM_BINARY_SEARCH_STEPS: 5, | ||
maxDepthDifference: 3, | ||
maxDepthDifference: 10, | ||
maxDepth: 1, | ||
thickness: 10, | ||
ior: 1.45, | ||
DITHERING: false, | ||
STRETCH_MISSED_RAYS: true, | ||
@@ -816,12 +820,14 @@ USE_MRT: true, | ||
_options = _extends({}, defaultSSROptions, _options); // set up passes | ||
// temporal resolve pass | ||
this.composeReflectionsPass = new ComposeReflectionsPass(this, _options); | ||
this.temporalResolvePass = new TemporalResolvePass(scene, camera, "", _options); | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.samples = new Uniform(0); | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.maxSamples = new Uniform(0); | ||
this.temporalResolvePass.fullscreenMaterial.defines.EULER = 2.718281828459045; | ||
this.temporalResolvePass.fullscreenMaterial.defines.FLOAT_EPSILON = 0.00001; | ||
this.uniforms.get("reflectionsTexture").value = this.temporalResolvePass.renderTarget.texture; // reflections pass | ||
this.reflectionsPass = new ReflectionsPass(this, _options); | ||
const { | ||
uniforms | ||
} = this.composeReflectionsPass.fullscreenMaterial; | ||
uniforms.inputTexture.value = this.reflectionsPass.renderTarget.texture; | ||
uniforms.accumulatedReflectionsTexture.value = this.reflectionsPass.accumulatedReflectionsTexture; | ||
uniforms.velocityTexture.value = this.reflectionsPass.velocityTexture; | ||
this.uniforms.get("reflectionsTexture").value = this.composeReflectionsPass.renderTarget.texture; | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.inputTexture.value = this.reflectionsPass.renderTarget.texture; | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.depthTexture.value = this.reflectionsPass.depthTexture; | ||
_classPrivateFieldLooseBase(this, _lastSize)[_lastSize] = { | ||
@@ -844,3 +850,3 @@ width: _options.width, | ||
if (width === _classPrivateFieldLooseBase(this, _lastSize)[_lastSize].width && height === _classPrivateFieldLooseBase(this, _lastSize)[_lastSize].height && this.resolutionScale === _classPrivateFieldLooseBase(this, _lastSize)[_lastSize].resolutionScale) return; | ||
this.composeReflectionsPass.setSize(width, height); | ||
this.temporalResolvePass.setSize(width, height); | ||
this.reflectionsPass.setSize(width, height); | ||
@@ -871,3 +877,3 @@ _classPrivateFieldLooseBase(this, _lastSize)[_lastSize] = { | ||
this.reflectionsPass.dispose(); | ||
this.composeReflectionsPass.dispose(); | ||
this.temporalResolvePass.dispose(); | ||
} | ||
@@ -883,3 +889,4 @@ | ||
this.composeReflectionsPass.render(renderer); | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.samples.value = this.samples; | ||
this.temporalResolvePass.render(renderer); | ||
} | ||
@@ -931,3 +938,3 @@ | ||
case "maxSamples": | ||
this.composeReflectionsPass.fullscreenMaterial.uniforms.maxSamples.value = this.maxSamples; | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.maxSamples.value = this.maxSamples; | ||
break; | ||
@@ -978,15 +985,2 @@ | ||
case "DITHERING": | ||
if (value) { | ||
this.reflectionsPass.fullscreenMaterial.defines.DITHERING = ""; | ||
this.composeReflectionsPass.fullscreenMaterial.defines.DITHERING = ""; | ||
} else { | ||
delete this.reflectionsPass.fullscreenMaterial.defines.DITHERING; | ||
delete this.composeReflectionsPass.fullscreenMaterial.defines.DITHERING; | ||
} | ||
this.reflectionsPass.fullscreenMaterial.needsUpdate = needsUpdate; | ||
this.composeReflectionsPass.fullscreenMaterial.needsUpdate = needsUpdate; | ||
break; | ||
case "USE_NORMALMAP": | ||
@@ -997,17 +991,28 @@ case "USE_ROUGHNESSMAP": | ||
case "temporalResolve": | ||
if (value) { | ||
this.composeReflectionsPass.fullscreenMaterial.defines.TEMPORAL_RESOLVE = ""; | ||
} else { | ||
delete this.composeReflectionsPass.fullscreenMaterial.defines.TEMPORAL_RESOLVE; | ||
const composeShader = value ? customTRComposeShader : customBasicComposeShader; | ||
let fragmentShader = temporalResolve; // if we are not using temporal reprojection, then cut out the part that's doing the reprojection | ||
if (!value) { | ||
const removePart = fragmentShader.slice(fragmentShader.indexOf("// REPROJECT_START"), fragmentShader.indexOf("// REPROJECT_END") + "// REPROJECT_END".length); | ||
fragmentShader = temporalResolve.replace(removePart, ""); | ||
} | ||
this.composeReflectionsPass.fullscreenMaterial.needsUpdate = true; | ||
fragmentShader = fragmentShader.replace("#include <custom_compose_shader>", composeShader); | ||
fragmentShader = | ||
/* glsl */ | ||
` | ||
uniform float samples; | ||
uniform float maxSamples; | ||
uniform float temporalResolveMix; | ||
` + fragmentShader; | ||
this.temporalResolvePass.fullscreenMaterial.fragmentShader = fragmentShader; | ||
this.temporalResolvePass.fullscreenMaterial.needsUpdate = true; | ||
break; | ||
case "temporalResolveMix": | ||
this.composeReflectionsPass.fullscreenMaterial.uniforms.temporalResolveMix.value = value; | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.temporalResolveMix.value = value; | ||
break; | ||
case "temporalResolveCorrectionMix": | ||
this.composeReflectionsPass.fullscreenMaterial.uniforms.temporalResolveCorrectionMix.value = value; | ||
this.temporalResolvePass.fullscreenMaterial.uniforms.temporalResolveCorrectionMix.value = value; | ||
break; | ||
@@ -1014,0 +1019,0 @@ // must be a uniform |
@@ -68,3 +68,3 @@ { | ||
}, | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"lint-staged": { | ||
@@ -71,0 +71,0 @@ "*.{js,css,md}": "prettier --write" |
@@ -82,3 +82,2 @@ # three.js Screen Space Reflections | ||
ior: 1.45, | ||
DITHERING: false, | ||
STRETCH_MISSED_RAYS: true, | ||
@@ -142,4 +141,2 @@ USE_MRT: true, | ||
- `DITHERING`: Improves performance but reduces quality by only alternately calculating reflections for every second pixel each frame; only works well if resolutionScale is 1 | ||
- `STRETCH_MISSED_RAYS`: if there should still be reflections for rays for which a reflecting point couldn't be found; enabling this will result in stretched looking reflections which can look good or bad depending on the angle | ||
@@ -211,5 +208,7 @@ | ||
<summary>Expand to view tips</summary> | ||
### Getting rid of artifacts | ||
If you are getting artifacts, for example: | ||
<br> | ||
@@ -314,1 +313,3 @@ <img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots//artifacts.jpg" width="50%"> | ||
- [Temporal Anti Aliasing – Step by Step](https://ziyadbarakat.wordpress.com/2020/07/28/temporal-anti-aliasing-step-by-step/) | ||
- [Filmic SMAA: Sharp Morphological and Temporal Antialiasing](https://research.activision.com/publications/archives/filmic-smaasharp-morphological-and-temporal-antialiasing) |
Sorry, the diff of this file is not supported yet
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
124086
1814
312