Przeglądaj źródła

Added shader code for parallax corrected reflection cubemap sampling

BearishSun 8 lat temu
rodzic
commit
befd1b159e

+ 4 - 0
Data/Raw/Engine/DataList.json

@@ -115,6 +115,10 @@
         {
         {
             "Path": "LightGridCommon.bslinc",
             "Path": "LightGridCommon.bslinc",
             "UUID": "26caf86e-433c-4ade-9bc5-55c136d82912"
             "UUID": "26caf86e-433c-4ade-9bc5-55c136d82912"
+        },
+        {
+            "Path": "ReflectionCubemapSampling.bslinc",
+            "UUID": "b65d98df-45db-4b03-a97c-bca6b07f1d22"
         }
         }
     ],
     ],
     "Shaders": [
     "Shaders": [

+ 54 - 27
Data/Raw/Engine/Includes/ReflectionCubemapCommon.bslinc

@@ -1,4 +1,4 @@
-Technique : base("ReflectionCubemap") =
+Technique : base("ReflectionCubemapCommon") =
 {
 {
 	Language = "HLSL11";
 	Language = "HLSL11";
 
 
@@ -6,28 +6,54 @@ Technique : base("ReflectionCubemap") =
 	{
 	{
 		Common = 
 		Common = 
 		{
 		{
-			#define REFLECTION_MIP_OFFSET 2
-		
+			float3 getDirFromCubeFace(uint cubeFace, float2 uv)
+			{
+				float3 dir;
+				if(cubeFace == 0)
+					dir = float3(1.0f, -uv.y, -uv.x);
+				else if(cubeFace == 1)
+					dir = float3(-1.0f, -uv.y, uv.x);
+				else if(cubeFace == 2)
+					dir = float3(uv.x, 1.0f, uv.y);
+				else if(cubeFace == 3)
+					dir = float3(uv.x, -1.0f, -uv.y);
+				else if(cubeFace == 4)
+					dir = float3(uv.x, -uv.y, 1.0f);
+				else
+					dir = float3(-uv.x, -uv.y, -1.0f);
+					
+				return dir;
+			}
+			
 			/**
 			/**
 			 * Calculates a mip level to sample from based on roughness value.
 			 * Calculates a mip level to sample from based on roughness value.
 			 *
 			 *
 			 * @param 	roughness	Roughness in range [0, 1]. Higher values yield more roughness.
 			 * @param 	roughness	Roughness in range [0, 1]. Higher values yield more roughness.
 			 * @param	numMips		Total number of mip-map levels in the texture we'll be sampling from.
 			 * @param	numMips		Total number of mip-map levels in the texture we'll be sampling from.
 			 * @return				Index of the mipmap level to sample.
 			 * @return				Index of the mipmap level to sample.
-			 */		
-			float getMipFromRoughness(float roughness, float numMips)
+			 */					
+			float mapRoughnessToMipLevel(float roughness, uint numMips)
 			{
 			{
-				// Note: This is just a heuristic as we don't calculate the exact size of the specular lobe,
-				// and neither do our filtered maps
-			
-				// We add an offset because we want to ignore the highest few mip levels
-				return numMips - 1 - REFLECTION_MIP_OFFSET - log2(roughness);
+				// We use the following equation:
+				//    mipLevel = log10(roughness) / log10(dropPercent)
+				//
+				// Where dropPercent represent by what % to drop the roughness with each mip level.
+				// We convert to log2 and a assume a drop percent value of 0.6. This gives us:
+				//    mipLevel = -1.35692 * log2(roughness);
+				
+				return max(0, numMips - 1 - (-1.35692 * log2(roughness)));
 			}
 			}
+			
+			float mapMipLevelToRoughness(uint mipLevel)
+			{
+				// mapRoughnessToMipLevel() solved for roughness
+				return 1.0f - exp2(-0.7369655941662063 * mipLevel);
+			}	
 		};
 		};
 	};
 	};
 };
 };
 
 
-Technique : base("ReflectionCubemap") =
+Technique : base("ReflectionCubemapCommon") =
 {
 {
 	Language = "GLSL";
 	Language = "GLSL";
 
 
@@ -35,23 +61,24 @@ Technique : base("ReflectionCubemap") =
 	{
 	{
 		Common = 
 		Common = 
 		{
 		{
-			#define REFLECTION_MIP_OFFSET 2
-		
-			/**
-			 * Calculates a mip level to sample from based on roughness value.
-			 *
-			 * @param 	roughness	Roughness in range [0, 1]. Higher values yield more roughness.
-			 * @param	numMips		Total number of mip-map levels in the texture we'll be sampling from.
-			 * @return				Index of the mipmap level to sample.
-			 */		
-			void getMipFromRoughness(float roughness, float numMips, out float mipLevel)
+			vec3 getDirFromCubeFace(uint cubeFace, vec2 uv)
 			{
 			{
-				// Note: This is just a heuristic as we don't calculate the exact size of the specular lobe,
-				// and neither do our filtered maps
-			
-				// We add an offset because we want to ignore the highest few mip levels
-				mipLevel = numMips - 1 - REFLECTION_MIP_OFFSET - log2(roughness);
-			}
+				vec3 dir;
+				if(cubeFace == 0)
+					dir = vec3(1.0f, -uv.y, -uv.x);
+				else if(cubeFace == 1)
+					dir = vec3(-1.0f, -uv.y, uv.x);
+				else if(cubeFace == 2)
+					dir = vec3(uv.x, 1.0f, uv.y);
+				else if(cubeFace == 3)
+					dir = vec3(uv.x, -1.0f, -uv.y);
+				else if(cubeFace == 4)
+					dir = vec3(uv.x, -uv.y, 1.0f);
+				else
+					dir = vec3(-uv.x, -uv.y, -1.0f);
+					
+				return dir;
+			}			
 		};
 		};
 	};
 	};
 };
 };

+ 121 - 0
Data/Raw/Engine/Includes/ReflectionCubemapSampling.bslinc

@@ -0,0 +1,121 @@
+Technique : base("ReflectionCubemapSampling") =
+{
+	Language = "HLSL11";
+
+	Pass =
+	{
+		Common = 
+		{
+			TextureCube gSkyCubemapTex;
+			SamplerState gSkyCubemapSamp;
+
+			cbuffer ReflectionParams
+			{
+				int gSkyNumMips;
+			}	
+			
+			float3 getSkyReflection(float3 dir, float roughness)
+			{
+				float mipLevel = mapRoughnessToMipLevel(roughness, gSkyNumMips);
+				float3 reflection = gSkyCubemapTex.SampleLevel(gSkyCubemapSamp, dir, mipLevel);
+
+				return reflection;
+			}
+			
+			float3 getSphereReflectionContribution(float normalizedDistance)
+			{			
+				// If closer than 60% to the probe radius, then full contribution is used.
+				// For the other 40% we smoothstep and return contribution lower than 1 so other
+				// reflection probes can be blended.			
+			
+				// smoothstep from 1 to 0.6:
+				//   float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+				//   return t * t * (3.0 - 2.0 * t);
+				float t = saturate(2.5 - 2.5 * normalizedDistance);
+				return t * t * (3.0 - 2.0 * t);
+			}
+			
+			float3 getLookupForSphereProxy(float3 originWS, float3 dirWS, float3 centerWS, float radius)
+			{
+				float radius2 = radius * radius;
+				float3 originLS = originWS - centerWS;
+				
+				float a = dot(originLS, dirWS);
+				float dist2 = a * a - dot(originLS, originLS) + radius2;
+
+				float3 lookupDir = dirWS;
+				
+				[flatten]
+				if(dist2 >= 0)
+				{
+					float farDist = sqrt(dist2) - a;
+					lookupDir = originLS + farDist * dirWS;
+				}
+				
+				return lookupDir;
+			}
+			
+			float3 getDistBoxToPoint(float3 point, float3 extents)
+			{
+				float3 d = max(max(-extents - point, 0), point - extents);
+				return length(d);
+			}
+			
+			float3 getLookupForBoxProxy(float3 originWS, float3 dirWS, float3 centerWS, float3 extents, float4x4 invBoxTransform, float transitionDistance, out float contribution)
+			{
+				// Transform origin and direction into box local space, where it is united sized and axis aligned
+				float3 originLS = mul(invBoxTransform, float4(originWS, 1)).xyz;
+				float3 dirLS = mul(invBoxTransform, float4(dirWS, 0)).xyz;
+				
+				// Get distance from 3 min planes and 3 max planes of the unit AABB
+				//  float3 unitVec = float3(1.0f, 1.0f, 1.0f);
+				//  float3 intersectsMax = (unitVec - originLS) / dirLS;
+				//  float3 intersectsMin = (-unitVec - originLS) / dirLS;
+				
+				float3 invDirLS = rcp(dirLS);
+				float3 intersectsMax = invDirLS - originLS * invDirLS;
+				float3 intersectsMin = -invDirLS - originLS * invDirLS;
+				
+				// Find nearest positive (along ray direction) intersection
+				float3 positiveIntersections = max(intersectsMax, intersectsMin);
+				float intersectDist = min(positiveIntersections.x, min(positiveIntersections.y, positiveIntersections.z));
+				
+				float3 intersectPositionWS = originWS + intersectDist * dirWS;
+				float3 lookupDir = intersectPositionWS - centerWS;
+				
+				// Calculate contribution
+				//// Shrink the box so fade out happens within box extents
+				float3 reducedExtents = extents - float3(transitionDistance, transitionDistance, transitionDistance);
+				float distToBox = getDistBoxToPoint(originLS * reducedExtents, reducedExtents);
+				
+				float normalizedDistance = distToBox / transitionDistance;
+				
+				// If closer than 70% to the probe radius, then full contribution is used.
+				// For the other 30% we smoothstep and return contribution lower than 1 so other
+				// reflection probes can be blended.			
+			
+				// smoothstep from 1 to 0.7:
+				//   float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
+				//   return t * t * (3.0 - 2.0 * t);
+				
+				float t = saturate(3.3333 - 3.3333 * normalizedDistance);
+				return t * t * (3.0 - 2.0 * t);
+				
+				return lookupDir;
+			}
+		};
+	};
+};
+
+Technique : base("ReflectionCubemapSampling") =
+{
+	Language = "GLSL";
+
+	Pass =
+	{
+		Common = 
+		{
+		
+		};
+	};
+};

+ 10 - 31
Data/Raw/Engine/Shaders/ReflectionCubeDownsample.bsl

@@ -1,4 +1,5 @@
 #include "$ENGINE$\PPBase.bslinc"
 #include "$ENGINE$\PPBase.bslinc"
+#include "$ENGINE$\ReflectionCubemapCommon.bslinc"
 
 
 Parameters =
 Parameters =
 {
 {
@@ -12,7 +13,9 @@ Blocks =
 	Block Input;
 	Block Input;
 };
 };
 
 
-Technique : inherits("PPBase") =
+Technique 
+ : inherits("PPBase")
+ : inherits("ReflectionCubemapCommon") =
 {
 {
 	Language = "HLSL11";
 	Language = "HLSL11";
 	
 	
@@ -31,20 +34,7 @@ Technique : inherits("PPBase") =
 			float4 main(VStoFS input) : SV_Target0
 			float4 main(VStoFS input) : SV_Target0
 			{
 			{
 				float2 scaledUV = input.uv0 * 2.0f - 1.0f;
 				float2 scaledUV = input.uv0 * 2.0f - 1.0f;
-				
-				float3 dir;
-				if(gCubeFace == 0)
-					dir = float3(1.0f, -scaledUV.y, -scaledUV.x);
-				else if(gCubeFace == 1)
-					dir = float3(-1.0f, -scaledUV.y, scaledUV.x);
-				else if(gCubeFace == 2)
-					dir = float3(scaledUV.x, 1.0f, scaledUV.y);
-				else if(gCubeFace == 3)
-					dir = float3(scaledUV.x, -1.0f, -scaledUV.y);
-				else if(gCubeFace == 4)
-					dir = float3(scaledUV.x, -scaledUV.y, 1.0f);
-				else
-					dir = float3(-scaledUV.x, -scaledUV.y, -1.0f);
+				float3 dir = getDirFromCubeFace(gCubeFace, scaledUV);
 				
 				
 				return gInputTex.Sample(gInputSamp, dir);
 				return gInputTex.Sample(gInputSamp, dir);
 			}	
 			}	
@@ -52,7 +42,9 @@ Technique : inherits("PPBase") =
 	};
 	};
 };
 };
 
 
-Technique : inherits("PPBase") =
+Technique
+ : inherits("PPBase")
+ : inherits("ReflectionCubemapCommon") =
 {
 {
 	Language = "GLSL";
 	Language = "GLSL";
 	
 	
@@ -77,21 +69,8 @@ Technique : inherits("PPBase") =
 			void main()
 			void main()
 			{
 			{
 				vec2 scaledUV = FSInput.uv0 * 2.0f - 1.0f;
 				vec2 scaledUV = FSInput.uv0 * 2.0f - 1.0f;
-				
-				vec3 dir;
-				if(gCubeFace == 0)
-					dir = vec3(1.0f, -scaledUV.y, -scaledUV.x);
-				else if(gCubeFace == 1)
-					dir = vec3(-1.0f, -scaledUV.y, scaledUV.x);
-				else if(gCubeFace == 2)
-					dir = vec3(scaledUV.x, 1.0f, scaledUV.y);
-				else if(gCubeFace == 3)
-					dir = vec3(scaledUV.x, -1.0f, -scaledUV.y);
-				else if(gCubeFace == 4)
-					dir = vec3(scaledUV.x, -scaledUV.y, 1.0f);
-				else
-					dir = vec3(-scaledUV.x, -scaledUV.y, -1.0f);
-				
+				vec3 dir = getDirFromCubeFace(gCubeFace, scaledUV);
+
 				fragColor = texture(gInputTex, dir);
 				fragColor = texture(gInputTex, dir);
 			}	
 			}	
 		};
 		};

+ 10 - 49
Data/Raw/Engine/Shaders/ReflectionCubeImportanceSample.bsl

@@ -1,4 +1,5 @@
 #include "$ENGINE$\PPBase.bslinc"
 #include "$ENGINE$\PPBase.bslinc"
+#include "$ENGINE$\ReflectionCubemapCommon.bslinc"
 
 
 Parameters =
 Parameters =
 {
 {
@@ -12,7 +13,9 @@ Blocks =
 	Block Input;
 	Block Input;
 };
 };
 
 
-Technique : inherits("PPBase") =
+Technique
+ : inherits("PPBase")
+ : inherits("ReflectionCubemapCommon") =
 {
 {
 	Language = "HLSL11";
 	Language = "HLSL11";
 	
 	
@@ -71,24 +74,6 @@ Technique : inherits("PPBase") =
 				return roughness4 * cosTheta * sinTheta / (d*d*PI);
 				return roughness4 * cosTheta * sinTheta / (d*d*PI);
 			}
 			}
 			
 			
-			float mapRoughnessToMipLevel(float roughness, uint maxMipLevel)
-			{
-				// We use the following equation:
-				//    mipLevel = log10(roughness) / log10(dropPercent)
-				//
-				// Where dropPercent represent by what % to drop the roughness with each mip level.
-				// We convert to log2 and a assume a drop percent value of 0.6. This gives us:
-				//    mipLevel = -1.35692 * log2(roughness);
-				
-				return max(0, maxMipLevel - (-1.35692 * log2(roughness)));
-			}
-			
-			float mapMipLevelToRoughness(uint mipLevel)
-			{
-				// Inverse of mapRoughnessToMipLevel()
-				return 1.0f - exp2(-0.7369655941662063 * mipLevel);
-			}
-			
 			cbuffer Input
 			cbuffer Input
 			{
 			{
 				int gCubeFace;
 				int gCubeFace;
@@ -102,21 +87,8 @@ Technique : inherits("PPBase") =
 			float4 main(VStoFS input) : SV_Target0
 			float4 main(VStoFS input) : SV_Target0
 			{
 			{
 				float2 scaledUV = input.uv0 * 2.0f - 1.0f;
 				float2 scaledUV = input.uv0 * 2.0f - 1.0f;
-														
-				float3 N;
-				if(gCubeFace == 0)
-					N = float3(1.0f, -scaledUV.y, -scaledUV.x);
-				else if(gCubeFace == 1)
-					N = float3(-1.0f, -scaledUV.y, scaledUV.x);
-				else if(gCubeFace == 2)
-					N = float3(scaledUV.x, 1.0f, scaledUV.y);
-				else if(gCubeFace == 3)
-					N = float3(scaledUV.x, -1.0f, -scaledUV.y);
-				else if(gCubeFace == 4)
-					N = float3(scaledUV.x, -scaledUV.y, 1.0f);
-				else
-					N = float3(-scaledUV.x, -scaledUV.y, -1.0f);
-				
+										
+				float3 N = getDirFromCubeFace(gCubeFace, scaledUV);
 				N = normalize(N);
 				N = normalize(N);
 				
 				
 				// Determine which mip level to sample from depending on PDF and cube -> sphere mapping distortion
 				// Determine which mip level to sample from depending on PDF and cube -> sphere mapping distortion
@@ -163,7 +135,9 @@ Technique : inherits("PPBase") =
 	};
 	};
 };
 };
 
 
-Technique : inherits("PPBase") =
+Technique
+ : inherits("PPBase")
+ : inherits("ReflectionCubemapCommon") =
 {
 {
 	Language = "GLSL";
 	Language = "GLSL";
 	
 	
@@ -188,20 +162,7 @@ Technique : inherits("PPBase") =
 			void main()
 			void main()
 			{
 			{
 				vec2 scaledUV = FSInput.uv0 * 2.0f - 1.0f;
 				vec2 scaledUV = FSInput.uv0 * 2.0f - 1.0f;
-				
-				vec3 dir;
-				if(gCubeFace == 0)
-					dir = vec3(1.0f, -scaledUV.y, -scaledUV.x);
-				else if(gCubeFace == 1)
-					dir = vec3(-1.0f, -scaledUV.y, scaledUV.x);
-				else if(gCubeFace == 2)
-					dir = vec3(scaledUV.x, 1.0f, scaledUV.y);
-				else if(gCubeFace == 3)
-					dir = vec3(scaledUV.x, -1.0f, -scaledUV.y);
-				else if(gCubeFace == 4)
-					dir = vec3(scaledUV.x, -scaledUV.y, 1.0f);
-				else
-					dir = vec3(-scaledUV.x, -scaledUV.y, -1.0f);
+				vec3 N = getDirFromCubeFace(gCubeFace, scaledUV);
 				
 				
 				fragColor = texture(gInputTex, dir);
 				fragColor = texture(gInputTex, dir);
 			}	
 			}	

+ 20 - 2
Source/BansheeCore/Include/BsReflectionProbe.h

@@ -70,6 +70,13 @@ namespace bs
 		void setRotation(const Quaternion& rotation) 
 		void setRotation(const Quaternion& rotation) 
 			{ mRotation = rotation; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
 			{ mRotation = rotation; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
 
 
+		/**	Returns the scale of the probe. */
+		Vector3 getScale() const { return mScale; }
+
+		/**	Sets the scale of the probe. */
+		void setScale(const Vector3& scale)
+			{ mScale = scale; _markCoreDirty(ReflectionProbeDirtyFlag::Transform); updateBounds(); }
+
 		/**	Returns the type of the probe. */
 		/**	Returns the type of the probe. */
 		ReflectionProbeType getType() const { return mType; }
 		ReflectionProbeType getType() const { return mType; }
 
 
@@ -77,13 +84,13 @@ namespace bs
 		void setType(ReflectionProbeType type) { mType = type; _markCoreDirty(); updateBounds(); }
 		void setType(ReflectionProbeType type) { mType = type; _markCoreDirty(); updateBounds(); }
 
 
 		/** Returns the radius of a sphere reflection probe. Determines range of influence. */
 		/** Returns the radius of a sphere reflection probe. Determines range of influence. */
-		float getRadius() const { return mRadius; }
+		float getRadius() const { return mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z); }
 
 
 		/** Sets the radius of a sphere reflection probe. */
 		/** Sets the radius of a sphere reflection probe. */
 		void setRadius(float radius) { mRadius = radius; _markCoreDirty(); updateBounds(); }
 		void setRadius(float radius) { mRadius = radius; _markCoreDirty(); updateBounds(); }
 
 
 		/** Returns the extents of a box or plane reflection probe. */
 		/** Returns the extents of a box or plane reflection probe. */
-		Vector3 getExtents() const { return mExtents; }
+		Vector3 getExtents() const { return mExtents * mScale; }
 
 
 		/** Sets the extents of a box or a plane reflection probe. Determines range of influence. */
 		/** Sets the extents of a box or a plane reflection probe. Determines range of influence. */
 		void setExtents(const Vector3& extents) { mExtents = extents; _markCoreDirty(); updateBounds(); }
 		void setExtents(const Vector3& extents) { mExtents = extents; _markCoreDirty(); updateBounds(); }
@@ -91,6 +98,15 @@ namespace bs
 		/**	Returns world space bounds that completely encompass the probe's area of influence. */
 		/**	Returns world space bounds that completely encompass the probe's area of influence. */
 		Sphere getBounds() const { return mBounds; }
 		Sphere getBounds() const { return mBounds; }
 		
 		
+		/** 
+		 * Sets a distance that will be used for fading out the box reflection probe with distance. By default it
+		 * is equal to one, and can never be less than one. Only relevant for box probes.
+		 */
+		void setTransitionDistance(float distance) { mTransitionDistance = std::max(1.0f, distance); }
+
+		/** Retrieves transition distance set by setTransitionDistance(). */
+		float getTransitionDistance() const { return mTransitionDistance; }
+
 		/**	Checks whether the probe should be used or not. */
 		/**	Checks whether the probe should be used or not. */
 		bool getIsActive() const { return mIsActive; }
 		bool getIsActive() const { return mIsActive; }
 
 
@@ -112,10 +128,12 @@ namespace bs
 
 
 		Vector3 mPosition; /**< World space position. */
 		Vector3 mPosition; /**< World space position. */
 		Quaternion mRotation; /**< World space rotation. */
 		Quaternion mRotation; /**< World space rotation. */
+		Vector3 mScale; /** Scale applied to radius/extents. */
 
 
 		ReflectionProbeType mType; /**< Type of probe that determines how are the rest of the parameters interpreted. */
 		ReflectionProbeType mType; /**< Type of probe that determines how are the rest of the parameters interpreted. */
 		float mRadius; /**< Radius used for sphere reflection probes. */
 		float mRadius; /**< Radius used for sphere reflection probes. */
 		Vector3 mExtents; /**< Extents used by box & plane reflection probes. */
 		Vector3 mExtents; /**< Extents used by box & plane reflection probes. */
+		float mTransitionDistance; /**< Extra distance to used for fading out box probes. */
 		String mUUID; /**< Identifier that uniquely identifies the probe. */
 		String mUUID; /**< Identifier that uniquely identifies the probe. */
 
 
 		bool mIsActive; /**< Whether the light should be rendered or not. */
 		bool mIsActive; /**< Whether the light should be rendered or not. */

+ 7 - 5
Source/BansheeCore/Include/BsReflectionProbeRTTI.h

@@ -19,11 +19,13 @@ namespace bs
 		BS_BEGIN_RTTI_MEMBERS
 		BS_BEGIN_RTTI_MEMBERS
 			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
 			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
 			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
 			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
-			BS_RTTI_MEMBER_PLAIN(mType, 2)
-			BS_RTTI_MEMBER_PLAIN(mRadius, 3)
-			BS_RTTI_MEMBER_PLAIN(mExtents, 4)
-			BS_RTTI_MEMBER_REFL(mCustomTexture, 5)
-			BS_RTTI_MEMBER_PLAIN(mUUID, 6)
+			BS_RTTI_MEMBER_PLAIN(mScale, 2)
+			BS_RTTI_MEMBER_PLAIN(mType, 3)
+			BS_RTTI_MEMBER_PLAIN(mRadius, 4)
+			BS_RTTI_MEMBER_PLAIN(mExtents, 5)
+			BS_RTTI_MEMBER_PLAIN(mTransitionDistance, 6)
+			BS_RTTI_MEMBER_REFL(mCustomTexture, 7)
+			BS_RTTI_MEMBER_PLAIN(mUUID, 8)
 		BS_END_RTTI_MEMBERS
 		BS_END_RTTI_MEMBERS
 	public:
 	public:
 		ReflectionProbeRTTI()
 		ReflectionProbeRTTI()

+ 14 - 6
Source/BansheeCore/Source/BsReflectionProbe.cpp

@@ -11,13 +11,13 @@
 namespace bs
 namespace bs
 {
 {
 	ReflectionProbeBase::ReflectionProbeBase()
 	ReflectionProbeBase::ReflectionProbeBase()
-		: mPosition(BsZero), mRotation(BsIdentity), mType(ReflectionProbeType::Box), mRadius(1.0f)
-		, mExtents(1.0f, 1.0f, 1.0f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
+		: mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(ReflectionProbeType::Box), mRadius(1.0f)
+		, mExtents(1.0f, 1.0f, 1.0f), mTransitionDistance(1.0f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
 	{ }
 	{ }
 
 
 	ReflectionProbeBase::ReflectionProbeBase(ReflectionProbeType type, float radius, const Vector3& extents)
 	ReflectionProbeBase::ReflectionProbeBase(ReflectionProbeType type, float radius, const Vector3& extents)
-		: mPosition(BsZero), mRotation(BsIdentity), mType(type), mRadius(radius)
-		, mExtents(extents), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
+		: mPosition(BsZero), mRotation(BsIdentity), mScale(1.0f, 1.0f, 1.0f), mType(type), mRadius(radius)
+		, mExtents(extents), mTransitionDistance(1.0f), mIsActive(true), mBounds(Vector3::ZERO, 1.0f)
 	{ }
 	{ }
 
 
 	void ReflectionProbeBase::updateBounds()
 	void ReflectionProbeBase::updateBounds()
@@ -25,11 +25,11 @@ namespace bs
 		switch (mType)
 		switch (mType)
 		{
 		{
 		case ReflectionProbeType::Sphere:
 		case ReflectionProbeType::Sphere:
-			mBounds = Sphere(mPosition, mRadius);
+			mBounds = Sphere(mPosition, mRadius * std::max(std::max(mScale.x, mScale.y), mScale.z));
 			break;
 			break;
 		case ReflectionProbeType::Box:
 		case ReflectionProbeType::Box:
 		case ReflectionProbeType::Plane:
 		case ReflectionProbeType::Plane:
-			mBounds = Sphere(mPosition, mExtents.length());
+			mBounds = Sphere(mPosition, (mExtents * mScale).length());
 			break;
 			break;
 		}
 		}
 	}
 	}
@@ -129,9 +129,11 @@ namespace bs
 		UINT32 size = 0;
 		UINT32 size = 0;
 		size += rttiGetElemSize(mPosition);
 		size += rttiGetElemSize(mPosition);
 		size += rttiGetElemSize(mRotation);
 		size += rttiGetElemSize(mRotation);
+		size += rttiGetElemSize(mScale);
 		size += rttiGetElemSize(mType);
 		size += rttiGetElemSize(mType);
 		size += rttiGetElemSize(mRadius);
 		size += rttiGetElemSize(mRadius);
 		size += rttiGetElemSize(mExtents);
 		size += rttiGetElemSize(mExtents);
+		size += rttiGetElemSize(mTransitionDistance);
 		size += rttiGetElemSize(mIsActive);
 		size += rttiGetElemSize(mIsActive);
 		size += rttiGetElemSize(getCoreDirtyFlags());
 		size += rttiGetElemSize(getCoreDirtyFlags());
 		size += rttiGetElemSize(mBounds);
 		size += rttiGetElemSize(mBounds);
@@ -143,9 +145,11 @@ namespace bs
 		char* dataPtr = (char*)buffer;
 		char* dataPtr = (char*)buffer;
 		dataPtr = rttiWriteElem(mPosition, dataPtr);
 		dataPtr = rttiWriteElem(mPosition, dataPtr);
 		dataPtr = rttiWriteElem(mRotation, dataPtr);
 		dataPtr = rttiWriteElem(mRotation, dataPtr);
+		dataPtr = rttiWriteElem(mScale, dataPtr);
 		dataPtr = rttiWriteElem(mType, dataPtr);
 		dataPtr = rttiWriteElem(mType, dataPtr);
 		dataPtr = rttiWriteElem(mRadius, dataPtr);
 		dataPtr = rttiWriteElem(mRadius, dataPtr);
 		dataPtr = rttiWriteElem(mExtents, dataPtr);
 		dataPtr = rttiWriteElem(mExtents, dataPtr);
+		dataPtr = rttiWriteElem(mTransitionDistance, dataPtr);
 		dataPtr = rttiWriteElem(mIsActive, dataPtr);
 		dataPtr = rttiWriteElem(mIsActive, dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 		dataPtr = rttiWriteElem(mBounds, dataPtr);
 		dataPtr = rttiWriteElem(mBounds, dataPtr);
@@ -169,6 +173,8 @@ namespace bs
 		{
 		{
 			setPosition(parent->getWorldPosition());
 			setPosition(parent->getWorldPosition());
 			setRotation(parent->getWorldRotation());
 			setRotation(parent->getWorldRotation());
+			setScale(parent->getWorldScale());
+
 			_setLastModifiedHash(curHash);
 			_setLastModifiedHash(curHash);
 		}
 		}
 	}
 	}
@@ -219,9 +225,11 @@ namespace bs
 
 
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mRotation, dataPtr);
 		dataPtr = rttiReadElem(mRotation, dataPtr);
+		dataPtr = rttiReadElem(mScale, dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mType, dataPtr);
 		dataPtr = rttiReadElem(mRadius, dataPtr);
 		dataPtr = rttiReadElem(mRadius, dataPtr);
 		dataPtr = rttiReadElem(mExtents, dataPtr);
 		dataPtr = rttiReadElem(mExtents, dataPtr);
+		dataPtr = rttiReadElem(mTransitionDistance, dataPtr);
 		dataPtr = rttiReadElem(mIsActive, dataPtr);
 		dataPtr = rttiReadElem(mIsActive, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 		dataPtr = rttiReadElem(mBounds, dataPtr);
 		dataPtr = rttiReadElem(mBounds, dataPtr);