Ver Fonte

Fix for area spot light shadows, as the stencil geometry didn't account for the extra radius

BearishSun há 8 anos atrás
pai
commit
418150005f

+ 7 - 0
Source/RenderBeast/Include/BsLightRendering.h

@@ -46,6 +46,13 @@ namespace bs { namespace ct
 		 */
 		void getParameters(SPtr<GpuParamBlockBuffer>& buffer) const;
 		
+		/** 
+		 * Calculates the light position that is shifted in order to account for area spot lights. For non-spot lights
+		 * this method will return normal light position. The position will be shifted back from the light direction, 
+		 * magnitude of the shift depending on the source radius.
+		 */
+		Vector3 getShiftedLightPosition() const;
+
 		Light* internal;
 	};
 

+ 15 - 7
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -43,11 +43,7 @@ namespace bs { namespace ct
 		if (internal->getType() == LightType::Directional)
 			output.srcRadius *= Math::DEG2RAD;
 
-		// Create position for fake attenuation for area spot lights (with disc center)
-		if (internal->getType() == LightType::Spot)
-			output.shiftedLightPosition = output.position - output.direction * (output.srcRadius / Math::tan(spotAngle * 0.5f));
-		else
-			output.shiftedLightPosition = output.position;
+		output.shiftedLightPosition = getShiftedLightPosition();
 	}
 
 	void RendererLight::getParameters(SPtr<GpuParamBlockBuffer>& buffer) const
@@ -80,7 +76,8 @@ namespace bs { namespace ct
 		lightGeometry.y = (float)Light::LIGHT_CONE_NUM_SLICES;
 		lightGeometry.z = internal->getBounds().getRadius();
 
-		float coneRadius = Math::sin(lightData.spotAngles.x) * internal->getAttenuationRadius();
+		float extraRadius = lightData.srcRadius / Math::tan(lightData.spotAngles.x * 0.5f);
+		float coneRadius = Math::sin(lightData.spotAngles.x) * (internal->getAttenuationRadius() + extraRadius);
 		lightGeometry.w = coneRadius;
 
 		gPerLightParamDef.gLightGeometry.set(buffer, lightGeometry);
@@ -88,10 +85,21 @@ namespace bs { namespace ct
 		Quaternion lightRotation(BsIdentity);
 		lightRotation.lookRotation(internal->getRotation().zAxis());
 
-		Matrix4 transform = Matrix4::TRS(internal->getPosition(), lightRotation, Vector3::ONE);
+		Matrix4 transform = Matrix4::TRS(lightData.shiftedLightPosition, lightRotation, Vector3::ONE);
 		gPerLightParamDef.gMatConeTransform.set(buffer, transform);
 	}
 
+	Vector3 RendererLight::getShiftedLightPosition() const
+	{
+		Vector3 direction = internal->getRotation().zAxis();
+
+		// Create position for fake attenuation for area spot lights (with disc center)
+		if (internal->getType() == LightType::Spot)
+			return internal->getPosition() - direction * (internal->getSourceRadius() / Math::tan(internal->getSpotAngle() * 0.5f));
+		else
+			return internal->getPosition();
+	}
+
 	GBufferParams::GBufferParams(const SPtr<Material>& material, const SPtr<GpuParamsSet>& paramsSet)
 		: mMaterial(material), mParamsSet(paramsSet)
 	{

+ 1 - 1
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -1075,7 +1075,7 @@ namespace bs { namespace ct
 		Quaternion lightRotation(BsIdentity);
 		lightRotation.lookRotation(light->getRotation().zAxis());
 
-		Matrix4 view = Matrix4::view(light->getPosition(), lightRotation);
+		Matrix4 view = Matrix4::view(rendererLight.getShiftedLightPosition(), lightRotation);
 		Matrix4 proj = Matrix4::projectionPerspective(light->getSpotAngle(), 1.0f, 0.05f, light->getAttenuationRadius());
 
 		ConvexVolume localFrustum = ConvexVolume(proj);