Sfoglia il codice sorgente

Auto scale SSR.hx thickness with distance to camera and angle with surface normal. (deprecate previous thickness values).

clementlandrin 7 mesi fa
parent
commit
abdc404080
1 ha cambiato i file con 36 aggiunte e 9 eliminazioni
  1. 36 9
      hrt/prefab/rfx/SSR.hx

+ 36 - 9
hrt/prefab/rfx/SSR.hx

@@ -3,7 +3,12 @@ package hrt.prefab.rfx;
 class SSRShader extends h3d.shader.ScreenShader {
 	static var SRC = {
 
-		@global var depthMap : Channel;
+		@param var depthBuffer : Sampler2D;
+		@global var camera : {
+			var position : Vec3;
+			var zNear : Float;
+			var zFar : Float;
+		}
 
 		@const var USE_MASK : Bool;
 		@const var USE_ROUGHNESS : Bool;
@@ -36,6 +41,8 @@ class SSRShader extends h3d.shader.ScreenShader {
 		@param var vignettingRadius : Float;
 		@param var vignettingSoftness : Float;
 
+		@param var depthBufferPrecision : Float;
+
 		var screenDepth : Float;
 
 		function reflectedRay(ray : Vec3, normal : Vec3) : Vec3 {
@@ -43,11 +50,11 @@ class SSRShader extends h3d.shader.ScreenShader {
 		}
 
 		function getViewPos(uv:Vec2):Vec4 {
-			screenDepth = depthMap.getLod(uv, 0).r;
+			screenDepth = depthBuffer.getLod(uv, 0).r;
 			var ruv = vec4(uvToScreen(uv), screenDepth, 1);
 			var vpos = ruv * cameraInverseProj;
 			return vpos / vpos.w;
-		};
+		}
 
 		function intersectViewRayWithFrustum( start : Vec3, dir : Vec3 ) : Vec3 {
 			var wStart = vec4(start, 1.0) * cameraInverseView;
@@ -69,6 +76,13 @@ class SSRShader extends h3d.shader.ScreenShader {
 			return vEnd.xyz / vEnd.w;
 		}
 
+		// scale thickness by an approximation of minimum difference between to depth step.
+		// https://www.sjbaker.org/steve/omniv/love_your_z_buffer.html
+		function scaledThickness(z : Float) : Float {
+			var t = thickness * camera.zNear * depthBufferPrecision;
+			return t * z * z / (depthBufferPrecision * camera.zNear - z);
+		}
+
 		function fragment() {
 
 			var intensityFactor = 0.0;
@@ -115,13 +129,15 @@ class SSRShader extends h3d.shader.ScreenShader {
 			var frag = startFrag.xy + increment;
 			var uv = frag / texSize;
 
+			var angleCorrection = 1.0 / abs(dot(camDir, viewNormal));
 			if (!batchSample) {
 				var iStepCount = int( stepCount );
 				for ( curStep in 0...iStepCount ) {
 					var curPos = getViewPos(uv);
 					var viewDistance = (positionFrom.z * positionTo.z) / mix(positionTo.z, positionFrom.z, float( curStep + 1 ) / stepCount );
 					var depth = viewDistance - curPos.z;
-					if ( depth >= 0.0 && depth < thickness && screenDepth < 1 ) {
+					var t = scaledThickness(curPos.z) * angleCorrection;
+					if ( depth >= 0.0 && depth < t && screenDepth < 1 ) {
 						hit = 1;
 						break;
 					}
@@ -139,7 +155,8 @@ class SSRShader extends h3d.shader.ScreenShader {
 						var curPos = getViewPos(uv);
 						var viewDistance = (positionFrom.z * positionTo.z) / mix(positionTo.z, positionFrom.z, float( curStep * 4 + i + 1 ) / stepCount );
 						var depth = viewDistance - curPos.z;
-						results[i] = depth >= 0.0 && depth < thickness && screenDepth < 1;
+						var t = scaledThickness(curPos.z) * angleCorrection;
+						results[i] = depth >= 0.0 && depth < t && screenDepth < 1;
 						frag += increment;
 						uv = frag / texSize;
 					}
@@ -186,7 +203,7 @@ class SSR extends RendererFX {
 
 	@:s public var intensity : Float = 1.;
 	@:s public var colorMul : Float = 1.;
-	@:s public var thickness : Float = 1.0;
+	@:s public var thicknessValue : Float = 0.0001;
 	@:s public var blurRadius : Float = 1.0;
 	@:s public var textureSize : Float = 0.5;
 	@:s public var useMask : Bool = false;
@@ -216,7 +233,8 @@ class SSR extends RendererFX {
 
 		var hdrMap = r.ctx.getGlobal("hdrMap");
 		ssrShader.hdrMap = hdrMap;
-		@:privateAccess ssrShader.roughnessMap = cast(r, h3d.scene.pbr.Renderer).textures.pbr;
+		var pbrRenderer = cast(r, h3d.scene.pbr.Renderer);
+		@:privateAccess ssrShader.roughnessMap = pbrRenderer.textures.pbr;
 
 		var normalMap = r.ctx.getGlobal("normalMap").texture;
 		ssrShader.normalMap = normalMap;
@@ -224,7 +242,7 @@ class SSR extends RendererFX {
 		ssrShader.texSize = new h3d.Vector((t == null ? r.ctx.engine.width : t.width), (t == null ? r.ctx.engine.height : t.height));
 		ssrShader.colorMul = colorMul;
 		ssrShader.intensity = intensity;
-		ssrShader.thickness = thickness;
+		ssrShader.thickness = thicknessValue;
 		ssrShader.maxRoughness = maxRoughness;
 		ssrShader.USE_ROUGHNESS = useRoughness;
 		if ( minAngle == 0 )
@@ -245,6 +263,15 @@ class SSR extends RendererFX {
 		ssrShader.vignettingRadius = vignettingRadius;
 		ssrShader.vignettingSoftness = vignettingSmoothness;
 
+		ssrShader.depthBuffer = @:privateAccess pbrRenderer.textures.albedo.depthBuffer;
+		var depthBufferBits = switch(ssrShader.depthBuffer.format) {
+		case Depth16: 16;
+		case Depth24, Depth24Stencil8: 24;
+		case Depth32: 32;
+		default: throw "not a depthBuffer";
+		}
+		ssrShader.depthBufferPrecision = 1 << depthBufferBits;
+
 		ssrShader.frustum = r.ctx.getCameraFrustumBuffer();
 
 		ssrShader.USE_MASK = useMask;
@@ -289,7 +316,7 @@ class SSR extends RendererFX {
 				<dt>Color Mul</dt><dd><input type="range" min="0" max="1" field="colorMul"/></dd>
 				<dt>Max Roughness</dt><dd><input type="range" min="0" max="1" field="maxRoughness"/></dd>
 				<dt>Min Angle</dt><dd><input type="range" min="0" max="90" field="minAngle"/></dd>
-				<dt>Thickness</dt><dd><input type="range" min="0" max="1" field="thickness"/></dd>
+				<dt>Thickness</dt><dd><input type="range" min="0" max="1" field="thicknessValue"/></dd>
 				<dt>Ray marching resolution</dt><dd><input type="range" min="0" max="1" field="rayMarchingResolution"/></dd>
 				<dt>Blur radius</dt><dd><input type="range" min="0" max="5" field="blurRadius"/></dd>
 				<dt>Texture size</dt><dd><input type="range" min="0" max="1" field="textureSize"/></dd>