screen-space-reflections
Advanced tools
Comparing version 2.0.7 to 2.0.8
import { Pass, RenderPass, DepthPass, Effect, Selection } from 'postprocessing'; | ||
import { Vector2, WebGLRenderTarget, NearestFilter, HalfFloatType, ShaderMaterial, Uniform, FramebufferTexture, RGBAFormat, ShaderChunk, Matrix4, Matrix3, UniformsUtils, TangentSpaceNormalMap, GLSL3, FrontSide, VideoTexture, WebGLMultipleRenderTargets, DataTexture, FloatType, Vector3, Quaternion } from 'three'; | ||
import { Vector2, WebGLRenderTarget, LinearFilter, HalfFloatType, ShaderMaterial, Uniform, FramebufferTexture, RGBAFormat, Matrix3, TangentSpaceNormalMap, GLSL3, Matrix4, ShaderChunk, NearestFilter, UniformsUtils, FrontSide, VideoTexture, WebGLMultipleRenderTargets, Vector3, Quaternion } from 'three'; | ||
@@ -37,3 +37,3 @@ 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);vec4 lastFrameReflectionsTexel;vec3 newColor;\n#ifdef TEMPORAL_RESOLVE\nvec4 velocityTexel=texture2D(velocityTexture,vUv);if(velocityTexel.a>1.-FLOAT_EPSILON){return;}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);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);}float alpha=min(inputTexel.a,lastFrameReflectionsTexel.a);alpha=samples<2.||movement<FLOAT_EPSILON ?(0.05+alpha): 0.;if(maxSamples!=0.&&samples>maxSamples&&alpha>1.-FLOAT_EPSILON){gl_FragColor=lastFrameReflectionsTexel;return;}if(alpha<1.){newColor=mix(lastFrameReflectionsTexel.rgb,inputTexel.rgb,(1.-alpha)*temporalResolveCorrectionMix);}else if(samples>4.&&movement<FLOAT_EPSILON&&length(lastFrameReflectionsTexel.rgb)<FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb;}else if(1./samples>=1.-temporalResolveMix){newColor=lastFrameReflectionsTexel.rgb*(temporalResolveMix)+inputTexel.rgb*(1.-temporalResolveMix);}else{float mixVal=(1./samples)/EULER;if(alpha<FLOAT_EPSILON&&samples<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=samples<2.||movement<FLOAT_EPSILON ?(0.05+alpha): 0.;if(maxSamples!=0.&&samples>maxSamples&&alpha>1.-FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb;}else{float samplesMultiplier=pow(samples/32.,4.)+1.;if(samples>1.&&alpha>1.-FLOAT_EPSILON){newColor=lastFrameReflectionsTexel.rgb*(1.-1./(samples*samplesMultiplier))+inputTexel.rgb/(samples*samplesMultiplier);}else{newColor=inputTexel.rgb;}}\n#endif\ngl_FragColor=vec4(newColor,alpha);}"; // eslint-disable-line | ||
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 | ||
@@ -55,5 +55,6 @@ const zeroVec2 = new Vector2(); | ||
this.renderTarget = new WebGLRenderTarget(width, height, { | ||
minFilter: NearestFilter, | ||
magFilter: NearestFilter, | ||
type: HalfFloatType | ||
minFilter: LinearFilter, | ||
magFilter: LinearFilter, | ||
type: HalfFloatType, | ||
depthBuffer: false | ||
}); | ||
@@ -93,4 +94,4 @@ this.fullscreenMaterial = new ShaderMaterial({ | ||
this.accumulatedReflectionsTexture = new FramebufferTexture(width, height, RGBAFormat); | ||
this.accumulatedReflectionsTexture.minFilter = NearestFilter; | ||
this.accumulatedReflectionsTexture.magFilter = NearestFilter; | ||
this.accumulatedReflectionsTexture.minFilter = LinearFilter; | ||
this.accumulatedReflectionsTexture.magFilter = LinearFilter; | ||
this.accumulatedReflectionsTexture.type = HalfFloatType; | ||
@@ -113,144 +114,4 @@ } | ||
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 float depth){return perspectiveDepthToViewZ(depth,cameraNear,cameraFar);}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 | ||
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 | ||
// 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 = modelViewMatrix * 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 = prevModelViewMatrix * vec4( transformed, 1.0 ); | ||
newPosition = projectionMatrix * newPosition; | ||
prevPosition = prevProjectionMatrix * prevPosition; | ||
gl_Position = mix( newPosition, prevPosition, interpolateGeometry ); | ||
`; | ||
const VelocityShader = { | ||
uniforms: { | ||
prevProjectionMatrix: { | ||
value: new Matrix4() | ||
}, | ||
prevModelViewMatrix: { | ||
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 prevProjectionMatrix; | ||
uniform mat4 prevModelViewMatrix; | ||
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 | ||
vec3 pos0 = prevPosition.xyz / prevPosition.w; | ||
pos0 += 1.0; | ||
pos0 /= 2.0; | ||
vec3 pos1 = newPosition.xyz / newPosition.w; | ||
pos1 += 1.0; | ||
pos1 /= 2.0; | ||
vec3 vel = pos1 - pos0; | ||
gl_FragColor = vec4( vel * intensity, 1.0 ); | ||
} | ||
` | ||
}; | ||
// WebGL2: will render normals to RGB channel of "gNormal" buffer, roughness to A channel of "gNormal" buffer, depth to RGBA channel of "gDepth" buffer | ||
@@ -265,6 +126,5 @@ // and velocity to "gVelocity" buffer | ||
USE_UV: "", | ||
TEMPORAL_RESOLVE: "", | ||
MAX_BONES: 256 | ||
TEMPORAL_RESOLVE: "" | ||
}, | ||
uniforms: _extends({ | ||
uniforms: { | ||
opacity: new Uniform(1), | ||
@@ -276,22 +136,9 @@ normalMap: new Uniform(null), | ||
roughnessMap: new Uniform(null) | ||
}, UniformsUtils.clone(VelocityShader.uniforms)), | ||
}, | ||
vertexShader: | ||
/* glsl */ | ||
` | ||
#ifdef USE_MRT | ||
#ifdef USE_MRT | ||
out vec2 vHighPrecisionZW; | ||
#endif | ||
#ifdef TEMPORAL_RESOLVE | ||
${ShaderChunk.skinning_pars_vertex} | ||
${prev_skinning_pars_vertex} | ||
uniform mat4 prevProjectionMatrix; | ||
uniform mat4 prevModelViewMatrix; | ||
uniform float interpolateGeometry; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
#endif | ||
#define NORMAL | ||
@@ -306,5 +153,5 @@ #if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP ) | ||
#include <morphtarget_pars_vertex> | ||
#include <skinning_pars_vertex> | ||
#include <logdepthbuf_pars_vertex> | ||
#include <clipping_planes_pars_vertex> | ||
void main() { | ||
@@ -320,2 +167,3 @@ #include <uv_vertex> | ||
#include <morphtarget_vertex> | ||
#include <skinning_vertex> | ||
#include <displacementmap_vertex> | ||
@@ -328,32 +176,8 @@ #include <project_vertex> | ||
#endif | ||
#ifdef USE_MRT | ||
vHighPrecisionZW = gl_Position.zw; | ||
#endif | ||
#ifdef USE_UV | ||
vUv = ( uvTransform * vec3( uv, 1 ) ).xy; | ||
#endif | ||
#ifdef TEMPORAL_RESOLVE | ||
// #ifndef NEEDS_UPDATED_REFLECTIONS | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinning_vertex} | ||
newPosition = modelViewMatrix * vec4( transformed, 1.0 ); | ||
transformed = vec3( position ); | ||
${ShaderChunk.skinbase_vertex.replace(/mat4 /g, "").replace(/getBoneMatrix/g, "getPrevBoneMatrix")} | ||
${ShaderChunk.skinning_vertex.replace(/vec4 /g, "")} | ||
prevPosition = prevModelViewMatrix * vec4( transformed, 1.0 ); | ||
newPosition = projectionMatrix * newPosition; | ||
prevPosition = prevProjectionMatrix * prevPosition; | ||
gl_Position = mix( newPosition, prevPosition, interpolateGeometry ); | ||
// #endif | ||
#endif | ||
} | ||
@@ -364,3 +188,3 @@ `, | ||
` | ||
#define NORMAL | ||
#define NORMAL | ||
#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP ) | ||
@@ -376,22 +200,11 @@ varying vec3 vViewPosition; | ||
#include <clipping_planes_pars_fragment> | ||
#include <roughnessmap_pars_fragment> | ||
#ifdef USE_MRT | ||
layout(location = 0) out vec4 gNormal; | ||
layout(location = 1) out vec4 gDepth; | ||
#ifdef TEMPORAL_RESOLVE | ||
layout(location = 2) out vec4 gVelocity; | ||
uniform float intensity; | ||
varying vec4 prevPosition; | ||
varying vec4 newPosition; | ||
#endif | ||
layout(location = 0) out vec4 gNormal; | ||
layout(location = 1) out vec4 gDepth; | ||
in vec2 vHighPrecisionZW; | ||
in vec2 vHighPrecisionZW; | ||
#endif | ||
uniform float roughness; | ||
void main() { | ||
@@ -402,3 +215,3 @@ #include <clipping_planes_fragment> | ||
#include <normal_fragment_maps> | ||
float roughnessFactor = roughness; | ||
@@ -417,34 +230,10 @@ | ||
vec3 normalColor = packNormalToRGB( normal ); | ||
#ifdef USE_MRT | ||
float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5; | ||
vec4 depthColor = packDepthToRGBA( fragCoordZ ); | ||
gNormal = vec4( normalColor, 1.0 ); | ||
gNormal.a = roughnessFactor; | ||
gNormal = vec4( normalColor, roughnessFactor ); | ||
gDepth = depthColor; | ||
#ifdef TEMPORAL_RESOLVE | ||
#ifdef NEEDS_UPDATED_REFLECTIONS | ||
gVelocity = vec4(1., 1., 1., 1.); | ||
#else | ||
vec3 pos0 = prevPosition.xyz / prevPosition.w; | ||
pos0 += 1.0; | ||
pos0 /= 2.0; | ||
vec3 pos1 = newPosition.xyz / newPosition.w; | ||
pos1 += 1.0; | ||
pos1 /= 2.0; | ||
vec3 vel = pos1 - pos0; | ||
float skyVal = fragCoordZ == 0. ? 1. : 0.; | ||
gVelocity = vec4( vel * intensity, skyVal); | ||
#endif | ||
#endif | ||
#else | ||
gl_FragColor = vec4(normalColor, roughnessFactor); | ||
#endif | ||
} | ||
@@ -468,3 +257,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(){vec4 depthTexel=texture2D(depthTexture,vUv);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=texture2D(normalTexture,vUv);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=texture2D(inputTexture,coords.xy);vec4 SSRTexelReflected=texture2D(accumulatedReflectionsTexture,coords.xy);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*reflectionDistance*rayFadeOut*0.01);if(opacity>1.)opacity=1.;finalSSR*=opacity;}float blurMix=0.;\n#ifdef ENABLE_BLUR\nblurMix=sqrt(reflectionDistance)*maxRoughness;if(blurMix>1.)blurMix=1.;\n#endif\nfloat 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;int steps;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}steps++;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 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;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 | ||
@@ -513,8 +302,140 @@ class ReflectionsMaterial extends ShaderMaterial { | ||
var _defaultMaterials = /*#__PURE__*/_classPrivateFieldLooseKey("defaultMaterials"); | ||
// a second set of bone information from the previou frame | ||
var _velocityMaterials = /*#__PURE__*/_classPrivateFieldLooseKey("velocityMaterials"); | ||
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 | ||
var _prevProjectionMatrix$1 = /*#__PURE__*/_classPrivateFieldLooseKey("prevProjectionMatrix"); | ||
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"); | ||
@@ -533,14 +454,6 @@ | ||
}); | ||
Object.defineProperty(this, _defaultMaterials, { | ||
Object.defineProperty(this, _cachedMaterials$1, { | ||
writable: true, | ||
value: {} | ||
value: new WeakMap() | ||
}); | ||
Object.defineProperty(this, _velocityMaterials, { | ||
writable: true, | ||
value: {} | ||
}); | ||
Object.defineProperty(this, _prevProjectionMatrix$1, { | ||
writable: true, | ||
value: new Matrix4() | ||
}); | ||
this._scene = scene; | ||
@@ -555,2 +468,6 @@ this._camera = camera; | ||
setSize(width, height) { | ||
this.renderTarget.setSize(width, height); | ||
} | ||
render(renderer) { | ||
@@ -564,4 +481,2 @@ _classPrivateFieldLooseBase(this, _setVelocityMaterialInScene)[_setVelocityMaterialInScene](); | ||
_classPrivateFieldLooseBase(this, _unsetVelocityMaterialInScene)[_unsetVelocityMaterialInScene](); | ||
_classPrivateFieldLooseBase(this, _prevProjectionMatrix$1)[_prevProjectionMatrix$1].copy(this._camera.projectionMatrix); | ||
} | ||
@@ -574,7 +489,7 @@ | ||
if (c.material) { | ||
const origMat = c.material; | ||
_classPrivateFieldLooseBase(this, _defaultMaterials)[_defaultMaterials][c.material.uuid] = origMat; | ||
const originalMaterial = c.material; | ||
let [cachedOriginalMaterial, velocityMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c) || []; | ||
if (_classPrivateFieldLooseBase(this, _velocityMaterials)[_velocityMaterials][origMat.uuid] === undefined) { | ||
_classPrivateFieldLooseBase(this, _velocityMaterials)[_velocityMaterials][origMat.uuid] = new ShaderMaterial({ | ||
if (!_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].has(c) || originalMaterial !== cachedOriginalMaterial) { | ||
velocityMaterial = new ShaderMaterial({ | ||
uniforms: UniformsUtils.clone(VelocityShader.uniforms), | ||
@@ -586,17 +501,5 @@ vertexShader: VelocityShader.vertexShader, | ||
const velocityMaterial = _classPrivateFieldLooseBase(this, _velocityMaterials)[_velocityMaterials][origMat.uuid]; | ||
velocityMaterial._originalUuid = c.material.uuid; | ||
velocityMaterial.extensions.derivatives = true; | ||
_classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].set(c, [originalMaterial, velocityMaterial]); | ||
} | ||
const velocityMaterial = _classPrivateFieldLooseBase(this, _velocityMaterials)[_velocityMaterials][c.material.uuid]; | ||
velocityMaterial.uniforms.prevModelViewMatrix.value.multiplyMatrices(this._camera.matrixWorldInverse, c.matrixWorld); | ||
velocityMaterial.uniforms.prevProjectionMatrix.value = _classPrivateFieldLooseBase(this, _prevProjectionMatrix$1)[_prevProjectionMatrix$1]; | ||
if (c.userData.prevModelViewMatrix) { | ||
velocityMaterial.uniforms.prevModelViewMatrix.value.copy(c.userData.prevModelViewMatrix); | ||
} | ||
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 | ||
@@ -612,2 +515,3 @@ | ||
velocityMaterial.uniforms.velocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
c.material = velocityMaterial; | ||
@@ -621,5 +525,7 @@ } | ||
if (c.material) { | ||
if (c.userData.prevModelViewMatrix === undefined) c.userData.prevModelViewMatrix = new Matrix4(); | ||
c.userData.prevModelViewMatrix.multiplyMatrices(this._camera.matrixWorldInverse, c.matrixWorld); | ||
c.material = _classPrivateFieldLooseBase(this, _defaultMaterials)[_defaultMaterials][c.material._originalUuid]; | ||
c.material.uniforms.prevVelocityMatrix.value.multiplyMatrices(this._camera.projectionMatrix, c.modelViewMatrix); | ||
const [originalMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials$1)[_cachedMaterials$1].get(c); | ||
c.material = originalMaterial; | ||
} | ||
@@ -642,4 +548,2 @@ }); | ||
var _prevProjectionMatrix = /*#__PURE__*/_classPrivateFieldLooseKey("prevProjectionMatrix"); | ||
var _USE_MRT = /*#__PURE__*/_classPrivateFieldLooseKey("USE_MRT"); | ||
@@ -649,3 +553,3 @@ | ||
var _webgl1VelocityPass = /*#__PURE__*/_classPrivateFieldLooseKey("webgl1VelocityPass"); | ||
var _velocityPass = /*#__PURE__*/_classPrivateFieldLooseKey("velocityPass"); | ||
@@ -656,4 +560,2 @@ var _keepMaterialMapUpdated = /*#__PURE__*/_classPrivateFieldLooseKey("keepMaterialMapUpdated"); | ||
var _updateBoneTexture = /*#__PURE__*/_classPrivateFieldLooseKey("updateBoneTexture"); | ||
var _unsetMRTMaterialInScene = /*#__PURE__*/_classPrivateFieldLooseKey("unsetMRTMaterialInScene"); | ||
@@ -667,5 +569,2 @@ | ||
}); | ||
Object.defineProperty(this, _updateBoneTexture, { | ||
value: _updateBoneTexture2 | ||
}); | ||
Object.defineProperty(this, _setMRTMaterialInScene, { | ||
@@ -685,6 +584,2 @@ value: _setMRTMaterialInScene2 | ||
}); | ||
Object.defineProperty(this, _prevProjectionMatrix, { | ||
writable: true, | ||
value: new Matrix4() | ||
}); | ||
Object.defineProperty(this, _USE_MRT, { | ||
@@ -698,3 +593,3 @@ writable: true, | ||
}); | ||
Object.defineProperty(this, _webgl1VelocityPass, { | ||
Object.defineProperty(this, _velocityPass, { | ||
writable: true, | ||
@@ -707,7 +602,9 @@ value: null | ||
this.fullscreenMaterial = new ReflectionsMaterial(); | ||
if (ssrEffect._camera.isPerspectiveCamera) this.fullscreenMaterial.defines.PERSPECTIVE_CAMERA = ""; | ||
const width = options.width || typeof window !== "undefined" ? window.innerWidth : 2000; | ||
const height = options.height || typeof window !== "undefined" ? window.innerHeight : 1000; | ||
this.renderTarget = new WebGLRenderTarget(width, height, { | ||
minFilter: NearestFilter, | ||
magFilter: NearestFilter | ||
minFilter: LinearFilter, | ||
magFilter: LinearFilter, | ||
depthBuffer: false | ||
}); | ||
@@ -719,10 +616,8 @@ this.renderPass = new RenderPass(this._scene, this._camera); | ||
// buffers: normal, depth, velocity (3), roughness will be written to the alpha channel of the normal buffer | ||
this.gBuffersRenderTarget = new WebGLMultipleRenderTargets(width, height, 3, { | ||
this.gBuffersRenderTarget = new WebGLMultipleRenderTargets(width, height, 2, { | ||
minFilter: NearestFilter, | ||
magFilter: NearestFilter, | ||
type: HalfFloatType | ||
magFilter: NearestFilter | ||
}); | ||
this.normalTexture = this.gBuffersRenderTarget.texture[0]; | ||
this.depthTexture = this.gBuffersRenderTarget.texture[1]; | ||
this.velocityTexture = this.gBuffersRenderTarget.texture[2]; | ||
} else { | ||
@@ -733,6 +628,4 @@ // depth pass | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget.magFilter = NearestFilter; | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget.generateMipmaps = true; | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget.texture.minFilter = NearestFilter; | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget.texture.magFilter = NearestFilter; | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].renderTarget.texture.generateMipmaps = true; | ||
@@ -748,6 +641,7 @@ _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].setSize(typeof window !== "undefined" ? window.innerWidth : 2000, typeof window !== "undefined" ? window.innerHeight : 1000); // render normals (in the rgb channel) and roughness (in the alpha channel) in gBuffersRenderTarget | ||
this.depthTexture = _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].texture; | ||
_classPrivateFieldLooseBase(this, _webgl1VelocityPass)[_webgl1VelocityPass] = new VelocityPass(this._scene, this._camera); | ||
this.velocityTexture = _classPrivateFieldLooseBase(this, _webgl1VelocityPass)[_webgl1VelocityPass].renderTarget.texture; | ||
} | ||
_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; | ||
@@ -764,10 +658,7 @@ this.fullscreenMaterial.uniforms.depthTexture.value = this.depthTexture; | ||
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.needsUpdate = true; | ||
if (!_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) { | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].setSize(width, height); | ||
_classPrivateFieldLooseBase(this, _webgl1VelocityPass)[_webgl1VelocityPass].setSize(width, height); | ||
} | ||
} | ||
@@ -779,10 +670,7 @@ | ||
this.renderPass.dispose(); | ||
this.fullscreenMaterial.dispose(); | ||
if (!_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) { | ||
_classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].dispose(); | ||
_classPrivateFieldLooseBase(this, _velocityPass)[_velocityPass].dispose(); | ||
_classPrivateFieldLooseBase(this, _webgl1VelocityPass)[_webgl1VelocityPass].dispose(); | ||
} | ||
if (!_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) _classPrivateFieldLooseBase(this, _webgl1DepthPass)[_webgl1DepthPass].dispose(); | ||
this.fullscreenMaterial.dispose(); | ||
this.normalTexture = null; | ||
@@ -797,3 +685,3 @@ this.depthTexture = null; | ||
renderer.setRenderTarget(this.gBuffersRenderTarget); | ||
this.renderPass.render(renderer, this.gBuffersRenderTarget, this.gBuffersRenderTarget); | ||
this.renderPass.render(renderer, this.gBuffersRenderTarget); | ||
@@ -803,8 +691,4 @@ _classPrivateFieldLooseBase(this, _unsetMRTMaterialInScene)[_unsetMRTMaterialInScene](); // render depth and velocity in seperate passes | ||
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, _webgl1VelocityPass)[_webgl1VelocityPass].render(renderer); | ||
} | ||
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; | ||
@@ -849,5 +733,5 @@ this.fullscreenMaterial.uniforms.samples.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].samples; | ||
if (!_classPrivateFieldLooseBase(this, _cachedMaterials)[_cachedMaterials].has(c) || originalMaterial !== cachedOriginalMaterial) { | ||
if (mrtMaterial) mrtMaterial.dispose(); | ||
mrtMaterial = new MRTMaterial(); | ||
if (_classPrivateFieldLooseBase(this, _USE_MRT)[_USE_MRT]) mrtMaterial.defines.USE_MRT = ""; | ||
mrtMaterial.uniforms.prevProjectionMatrix.value = _classPrivateFieldLooseBase(this, _prevProjectionMatrix)[_prevProjectionMatrix]; | ||
mrtMaterial.normalScale = originalMaterial.normalScale; | ||
@@ -866,19 +750,2 @@ mrtMaterial.uniforms.normalScale.value = originalMaterial.normalScale; | ||
const needsUpdatedReflections = c.material.userData.needsUpdatedReflections || c.material.map instanceof VideoTexture; // mark the material as "NEEDS_UPDATED_REFLECTIONS" so that, when using temporal resolve, we get updated reflections | ||
if (needsUpdatedReflections && !Object.keys(mrtMaterial.defines).includes("NEEDS_UPDATED_REFLECTIONS")) { | ||
mrtMaterial.defines.NEEDS_UPDATED_REFLECTIONS = ""; | ||
mrtMaterial.needsUpdate = true; | ||
} else if (!needsUpdatedReflections && Object.keys(mrtMaterial.defines).includes("NEEDS_UPDATED_REFLECTIONS")) { | ||
delete mrtMaterial.defines.NEEDS_UPDATED_REFLECTIONS; | ||
mrtMaterial.needsUpdate = true; | ||
} | ||
if (c.skeleton) { | ||
mrtMaterial.defines.USE_SKINNING = ""; | ||
mrtMaterial.defines.BONE_TEXTURE = ""; | ||
_classPrivateFieldLooseBase(this, _updateBoneTexture)[_updateBoneTexture](mrtMaterial, c.skeleton, "boneTexture", "boneMatrices"); | ||
} | ||
mrtMaterial.uniforms.roughness.value = _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].selection.size === 0 || _classPrivateFieldLooseBase(this, _ssrEffect)[_ssrEffect].selection.has(c) ? originalMaterial.roughness || 0 : 10e10; | ||
@@ -890,25 +757,6 @@ c.material = mrtMaterial; | ||
function _updateBoneTexture2(material, skeleton, uniformName, boneMatricesName) { | ||
let boneMatrices = material[boneMatricesName]; | ||
if (material[boneMatricesName]?.length !== skeleton.boneMatrices.length) { | ||
delete material[boneMatricesName]; | ||
boneMatrices = new Float32Array(skeleton.boneMatrices.length); | ||
material[boneMatricesName] = boneMatrices; | ||
} | ||
material[boneMatricesName].set(skeleton.boneMatrices); | ||
const size = Math.sqrt(skeleton.boneMatrices.length / 4); | ||
const boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType); | ||
boneTexture.needsUpdate = true; | ||
if (material.uniforms[uniformName].value) material.uniforms[uniformName].value.dispose(); | ||
material.uniforms[uniformName].value = boneTexture; | ||
} | ||
function _unsetMRTMaterialInScene2() { | ||
this._scene.traverse(c => { | ||
if (c.material?.type === "MRTMaterial") { | ||
c.material.uniforms.prevModelViewMatrix.value.copy(c.modelViewMatrix); | ||
if (c.skeleton) _classPrivateFieldLooseBase(this, _updateBoneTexture)[_updateBoneTexture](c.material, c.skeleton, "prevBoneTexture", "prevBoneMatrices"); // set material back to the original one | ||
// set material back to the original one | ||
const [originalMaterial] = _classPrivateFieldLooseBase(this, _cachedMaterials)[_cachedMaterials].get(c); | ||
@@ -919,4 +767,2 @@ | ||
}); | ||
_classPrivateFieldLooseBase(this, _prevProjectionMatrix)[_prevProjectionMatrix].copy(this._camera.projectionMatrix); | ||
} | ||
@@ -929,3 +775,3 @@ | ||
temporalResolveCorrectionMix: 1, | ||
maxSamples: 0, | ||
maxSamples: 256, | ||
resolutionScale: 1, | ||
@@ -953,2 +799,3 @@ width: typeof window !== "undefined" ? window.innerWidth : 2000, | ||
ior: 1.45, | ||
DITHERING: false, | ||
STRETCH_MISSED_RAYS: true, | ||
@@ -1151,2 +998,15 @@ USE_MRT: true, | ||
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": | ||
@@ -1153,0 +1013,0 @@ case "USE_ROUGHNESSMAP": |
@@ -68,3 +68,3 @@ { | ||
}, | ||
"version": "2.0.7", | ||
"version": "2.0.8", | ||
"lint-staged": { | ||
@@ -71,0 +71,0 @@ "*.{js,css,md}": "prettier --write" |
@@ -5,5 +5,5 @@ # three.js Screen Space Reflections | ||
<br></br> | ||
[<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots/1.png">](https://screen-space-reflections.vercel.app) | ||
[<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots/1.jpg">](https://screen-space-reflections.vercel.app) | ||
<br></br> | ||
<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots//2.png"> | ||
<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots//2.jpg"> | ||
<br></br> | ||
@@ -23,13 +23,2 @@ | ||
## Run Locally | ||
If you'd like to test this project and run it locally, run these commands: | ||
``` | ||
git clone https://github.com/0beqz/screen-space-reflections | ||
cd screen-space-reflections/example | ||
npm i --force | ||
npm run dev | ||
``` | ||
## Usage | ||
@@ -64,3 +53,4 @@ | ||
Default values of the optional `options` parameter: | ||
<details> | ||
<summary>Default values of the optional "options" parameter</summary> | ||
@@ -72,3 +62,3 @@ ```javascript | ||
temporalResolveCorrectionMix: 1, | ||
maxSamples: 0, | ||
maxSamples: 256, | ||
resolutionScale: 1, | ||
@@ -96,2 +86,3 @@ width: typeof window !== "undefined" ? window.innerWidth : 2000, | ||
ior: 1.45, | ||
DITHERING: false, | ||
STRETCH_MISSED_RAYS: true, | ||
@@ -104,4 +95,6 @@ USE_MRT: true, | ||
</details> | ||
<details> | ||
<summary>Description of the properties:</summary> | ||
<summary>Description of the properties</summary> | ||
@@ -154,2 +147,4 @@ - `width`: width of the SSREffect | ||
- `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 | ||
@@ -165,4 +160,36 @@ | ||
### ❗ Highly recommended: Use a GUI to tweak the options | ||
Since the right options for an SSR effect depend a lot on the scene, it can happen that you don't seem to have an effect at all in your scene when you use the SSR effect for the first time in it without any configuration. This can have multiple causes such as `rayStep` being way too low for your scene for example. So to find out which SSR options are right for your scene, you should use a GUI to find the right values easily. | ||
The [example](https://github.com/0beqz/screen-space-reflections/tree/main/example) already comes with a simple one-file GUI [`SSRDebugGUI.js`](https://github.com/0beqz/screen-space-reflections/blob/main/example/SSRDebugGUI.js) that you can use in your project like so: | ||
- First install the npm package of the module used for the GUI: | ||
``` | ||
npm i tweakpane | ||
``` | ||
- then just copy the `SSRDebugGUI.js` to your project and initialize it like so in your scene: | ||
```javascript | ||
import { SSRDebugGUI } from "./SSRDebugGUI" | ||
const gui = new SSRDebugGUI(ssrEffect, options) | ||
``` | ||
That's it, you should now have the GUI you can see in the [example scene](https://screen-space-reflections.vercel.app/). The `options` parameter is optional for the SSRDebugGUI and will default to the default options if no `options` parameter is given. | ||
<br> | ||
## Run Locally | ||
If you'd like to test this project and run it locally, run these commands: | ||
``` | ||
git clone https://github.com/0beqz/screen-space-reflections | ||
cd screen-space-reflections/example | ||
npm i --force | ||
npm run dev | ||
``` | ||
## Features | ||
@@ -190,9 +217,2 @@ | ||
<summary>Expand to view tips</summary> | ||
### Getting the right look | ||
SSR usually needs a lot of tweaking before it looks alright in a scene, so using a GUI where you can easily modify all values is highly recommended. | ||
The demo uses [tweakpane](https://cocopon.github.io/tweakpane/) as the GUI. If you want to use it, check out how it's initalized and used in the demo: https://github.com/0beqz/screen-space-reflections/blob/main/example/main.js. | ||
<br> | ||
### Getting rid of artifacts | ||
@@ -202,3 +222,3 @@ | ||
<br> | ||
<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots//artifacts.png" width="50%"> | ||
<img src="https://raw.githubusercontent.com/0beqz/screen-space-reflections/screenshots//artifacts.jpg" width="50%"> | ||
@@ -205,0 +225,0 @@ Then try the following: |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
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
311
121930
1806