Explorar el Código

Using off-peak specular direction for image based specular evaluation

BearishSun hace 8 años
padre
commit
de17828399

+ 22 - 6
Data/Raw/Engine/Includes/LightingCommon.bslinc

@@ -16,11 +16,12 @@ Technique
 			struct LightData
 			{
 				float3 position;
-				float radius;
+				float attRadius;
+				float srcRadius;
 				float3 direction;
 				float luminance;
 				float3 spotAngles;
-				float radiusSqrdInv;
+				float attRadiusSqrdInv;
 				float3 color;
 			};
 			
@@ -94,7 +95,8 @@ Technique
 				float distanceSqrd = dot(toLight, toLight);
 				float distanceAttenuation = 1.0f / max(distanceSqrd, 0.01f*0.01f);
 				
-				float radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
+				// Window function to ensure the light contribution fades out to 0 at attenuation radius
+				float radiusAttenuation = distanceSqrd * lightData.attRadiusSqrdInv;
 				radiusAttenuation *= radiusAttenuation;
 				radiusAttenuation = saturate(1.0f - radiusAttenuation);
 				radiusAttenuation *= radiusAttenuation;
@@ -111,6 +113,19 @@ Technique
 				return pointLightContribution * spotFalloff;
 			}
 			
+			// With microfacet BRDF the BRDF lobe is not centered around the reflected (mirror) direction.
+			// Because of NoL and shadow-masking terms the lobe gets shifted toward the normal as roughness
+			// increases. This is called the "off-specular peak". We approximate it using this function.
+			float3 getSpecularDominantDir(float3 N, float3 R, float roughness)
+			{
+				// Note: Try this formula as well:
+				//  float smoothness = 1 - roughness;
+				//  return lerp(N, R, smoothness * (sqrt(smoothness) + roughness));
+			
+				float r2 = roughness * roughness;
+				return lerp(N, R, (1 - r2) * (sqrt(1 - r2) + r2)); // Not normalized
+			}
+			
 			float3 getSurfaceShading(float3 V, float3 L, SurfaceData surfaceData)
 			{
 				float3 N = surfaceData.worldNormal.xyz;
@@ -214,11 +229,12 @@ Technique
 			struct LightData
 			{
 				vec3 position;
-				float radius;
+				float attRadius;
+				float srcRadius;
 				vec3 direction;
 				float luminance;
 				vec3 spotAngles;
-				float radiusSqrdInv;
+				float attRadiusSqrdInv;
 				vec3 color;
 			};
 									
@@ -281,7 +297,7 @@ Technique
 				L = normalize(L);
 				float NoL = clamp(dot(N, L), 0.0, 1.0); // TODO - Add bias here?
 
-				float radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
+				float radiusAttenuation = distanceSqrd * lightData.attRadiusSqrdInv;
 				radiusAttenuation *= radiusAttenuation;
 				radiusAttenuation = clamp(1.0f - radiusAttenuation, 0.0, 1.0);
 				radiusAttenuation *= radiusAttenuation;

+ 5 - 7
Data/Raw/Engine/Includes/ReflectionCubemapSampling.bslinc

@@ -135,10 +135,10 @@ Technique : base("ReflectionCubemapSampling") =
 				return lookupDir;
 			}
 			
-			float3 gatherReflectionRadiance(float3 worldPos, float3 dir, float roughness, uint probeOffset, uint numProbes)
+			float3 gatherReflectionRadiance(float3 worldPos, float3 dir, float roughness, float3 specularColor, uint probeOffset, uint numProbes)
 			{
-				#if FIXED_REFLECTION_COLOR
-					return float3(1.0f, 1.0f, 1.0f);
+				#if CAPTURING_REFLECTIONS
+					return specularColor;
 				#else
 				
 				float mipLevel = mapRoughnessToMipLevel(roughness, gReflCubemapNumMips);
@@ -192,7 +192,7 @@ Technique : base("ReflectionCubemapSampling") =
 				#endif
 			}
 			
-			float3 getImageBasedSpecular(float3 worldPos, float3 V, SurfaceData surfaceData)
+			float3 getImageBasedSpecular(float3 worldPos, float3 V, float3 R, SurfaceData surfaceData)
 			{
 				// See C++ code for generation of gPreintegratedEnvBRDF to see why this code works as is
 				float3 N = surfaceData.worldNormal.xyz;
@@ -201,9 +201,7 @@ Technique : base("ReflectionCubemapSampling") =
 				// Note: Using a fixed F0 value of 0.04 (plastic) for dielectrics, and using albedo as specular for conductors.
 				// For more customizability allow the user to provide separate albedo/specular colors for both types.
 				float3 specularColor = lerp(float3(0.04f, 0.04f, 0.04f), surfaceData.albedo.rgb, surfaceData.metalness);
-				
-				float3 R = 2 * dot(V, N) * N - V;
-				float3 radiance = gatherReflectionRadiance(worldPos, R, surfaceData.roughness, 0, 0);
+				float3 radiance = gatherReflectionRadiance(worldPos, R, surfaceData.roughness, specularColor, 0, 0);
 				
 				float2 envBRDF = gPreintegratedEnvBRDF.SampleLevel(gPreintegratedEnvBRDFSamp, float2(NoV, surfaceData.roughness), 0).rg;
 				

+ 2 - 2
Data/Raw/Engine/Shaders/LightGridLLCreation.bsl

@@ -107,7 +107,7 @@ Technique
 					for(uint i = lightOffset; i < lightEnd; ++i)
 					{
 						float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
-						float lightRadius = gLights[i].radius;
+						float lightRadius = gLights[i].attRadius;
 						
 						// Calculate distance from box to light
 						float3 distances = max(abs(lightPosition - cellCenter) - cellExtent, 0);
@@ -229,7 +229,7 @@ Technique
 					for(uint i = lightOffset; i < lightEnd; ++i)
 					{
 						vec4 lightPosition = gMatView * vec4(gLightsData[i].position, 1.0f);
-						float lightRadius = gLightsData[i].radius;
+						float lightRadius = gLightsData[i].attRadius;
 						
 						// Calculate distance from box to light
 						vec3 distances = max(abs(lightPosition.xyz - cellCenter) - cellExtent, 0);

+ 6 - 3
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -161,10 +161,13 @@ Technique
 				lightOffsets.w = sTotalNumLights;
 				
 				float3 V = normalize(gViewOrigin - worldPosition);
+				float3 N = surfaceData.worldNormal.xyz;
+				float3 R = 2 * dot(V, N) * N - V;
+				float3 specR = getSpecularDominantDir(N, R, surfaceData.roughness);
 				
 				float4 directLighting = getDirectLighting(worldPosition, surfaceData, lightOffsets);
 				float3 indirectDiffuse = getSkyIndirectDiffuse(surfaceData.worldNormal) * surfaceData.albedo;
-				float3 imageBasedSpecular = getImageBasedSpecular(worldPosition, V, surfaceData);
+				float3 imageBasedSpecular = getImageBasedSpecular(worldPosition, V, specR, surfaceData);
 
 				float4 totalLighting = directLighting;
 				totalLighting.rgb += indirectDiffuse;
@@ -286,7 +289,7 @@ Technique
 					for (uint i = lightOffset; i < lightsEnd && i < MAX_LIGHTS; i += TILE_SIZE)
 					{
 						float4 lightPosition = mul(gMatView, float4(gLights[i].position, 1.0f));
-						float lightRadius = gLights[i].radius;
+						float lightRadius = gLights[i].attRadius;
 						
 						// Note: The cull method can have false positives. In case of large light bounds and small tiles, it
 						// can end up being quite a lot. Consider adding an extra heuristic to check a separating plane.
@@ -607,7 +610,7 @@ Technique
 					{
 						LightData lightData = gLightsData[i];
 						vec4 lightPosition = gMatView * vec4(lightData.position, 1.0f);
-						float lightRadius = lightData.radius;
+						float lightRadius = lightData.attRadius;
 						
 						bool lightInTile = true;
 					

+ 10 - 8
Source/RenderBeast/Include/BsLightRendering.h

@@ -17,11 +17,12 @@ namespace bs { namespace ct
 	struct LightData
 	{
 		Vector3 position;
-		float radius;
+		float attRadius;
+		float srcRadius;
 		Vector3 direction;
 		float luminance;
 		Vector3 spotAngles;
-		float radiusSqrdInv;
+		float attRadiusSqrdInv;
 		Vector3 color;
 	};
 
@@ -154,8 +155,8 @@ namespace bs { namespace ct
 	};
 
 	/** Shader that performs a lighting pass over data stored in the Gbuffer. */
-	template<int MSAA_COUNT, bool FixedReflColor>
-	class TTiledDeferredLightingMat : public ITiledDeferredLightingMat, public RendererMaterial<TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>>
+	template<int MSAA_COUNT, bool CapturingReflections>
+	class TTiledDeferredLightingMat : public ITiledDeferredLightingMat, public RendererMaterial<TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>>
 	{
 		RMAT_DEF("TiledDeferredLighting.bsl");
 
@@ -188,11 +189,12 @@ namespace bs { namespace ct
 		/**
 		 * Returns a version of the tile-deferred lighting material that matches the parameters.
 		 * 
-		 * @param[in]   msaa				Number of samples per pixel.
-		 * @param[in]   fixedReflColor		If true reflection probes will not be evaluated and instead a fixed color will
-		 *									be returned instead. Useful when rendering reflection probes.
+		 * @param[in]   msaa					Number of samples per pixel.
+		 * @param[in]   capturingReflections	If true reflection probes will not be evaluated and instead the material's
+		 *										specular color will be returned instead. Useful when rendering reflection
+		 *										probes.
 		 */
-		ITiledDeferredLightingMat* get(UINT32 msaa, bool fixedReflColor);
+		ITiledDeferredLightingMat* get(UINT32 msaa, bool capturingReflections);
 
 	private:
 		ITiledDeferredLightingMat* mInstances[8];

+ 18 - 17
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -29,13 +29,14 @@ namespace bs { namespace ct
 		Color color = mInternal->getColor();
 
 		output.position = mInternal->getPosition();
-		output.radius = mInternal->getBounds().getRadius();
+		output.attRadius = mInternal->getBounds().getRadius();
+		output.srcRadius = mInternal->getSourceRadius();
 		output.direction = mInternal->getRotation().zAxis();
 		output.luminance = mInternal->getLuminance();
 		output.spotAngles.x = spotAngle.valueRadians();
 		output.spotAngles.y = Math::cos(output.spotAngles.x);
 		output.spotAngles.z = 1.0f / (Math::cos(spotFalloffAngle) - output.spotAngles.y);
-		output.radiusSqrdInv = 1.0f / (output.radius * output.radius);
+		output.attRadiusSqrdInv = 1.0f / (output.attRadius * output.attRadius);
 		output.color = Vector3(color.r, color.g, color.b);
 	}
 
@@ -373,43 +374,43 @@ namespace bs { namespace ct
 		return texture;
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::TTiledDeferredLightingMat()
+	template<int MSAA_COUNT, bool CapturingReflections>
+	TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::TTiledDeferredLightingMat()
 		:mInternal(mMaterial, mParamsSet, MSAA_COUNT)
 	{
 
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	void TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::_initDefines(ShaderDefines& defines)
+	template<int MSAA_COUNT, bool CapturingReflections>
+	void TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::_initDefines(ShaderDefines& defines)
 	{
 		defines.set("TILE_SIZE", TiledDeferredLighting::TILE_SIZE);
 		defines.set("MSAA_COUNT", MSAA_COUNT);
-		defines.set("FIXED_REFLECTION_COLOR", FixedReflColor);
+		defines.set("CAPTURING_REFLECTIONS", CapturingReflections);
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	void TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::execute(const SPtr<RenderTargets>& gbuffer,
+	template<int MSAA_COUNT, bool CapturingReflections>
+	void TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::execute(const SPtr<RenderTargets>& gbuffer,
 		const SPtr<GpuParamBlockBuffer>& perCamera, const SPtr<Texture>& preintegratedGF, bool noLighting)
 	{
 		mInternal.execute(gbuffer, perCamera, preintegratedGF, noLighting);
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	void TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::setLights(const GPULightData& lightData)
+	template<int MSAA_COUNT, bool CapturingReflections>
+	void TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::setLights(const GPULightData& lightData)
 	{
 		mInternal.setLights(lightData);
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	void TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::setReflectionProbes(const GPUReflProbeData& probeData, 
+	template<int MSAA_COUNT, bool CapturingReflections>
+	void TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::setReflectionProbes(const GPUReflProbeData& probeData,
 		const SPtr<Texture>& reflectionCubemaps)
 	{
 		mInternal.setReflectionProbes(probeData, reflectionCubemaps);
 	}
 
-	template<int MSAA_COUNT, bool FixedReflColor>
-	void TTiledDeferredLightingMat<MSAA_COUNT, FixedReflColor>::setSky(const SPtr<Texture>& skyReflections, 
+	template<int MSAA_COUNT, bool CapturingReflections>
+	void TTiledDeferredLightingMat<MSAA_COUNT, CapturingReflections>::setSky(const SPtr<Texture>& skyReflections,
 		const SPtr<Texture>& skyIrradiance)
 	{
 		mInternal.setSky(skyReflections, skyIrradiance);
@@ -434,9 +435,9 @@ namespace bs { namespace ct
 			bs_delete(mInstances[i]);
 	}
 
-	ITiledDeferredLightingMat* TiledDeferredLightingMaterials::get(UINT32 msaa, bool fixedReflColor)
+	ITiledDeferredLightingMat* TiledDeferredLightingMaterials::get(UINT32 msaa, bool capturingReflections)
 	{
-		if (!fixedReflColor)
+		if (!capturingReflections)
 		{
 			if (msaa == 1)
 				return mInstances[0];