Forráskód Böngészése

Added rendering for spot light geometry in the light pass shader
Added generating of a dummy mesh for spot light geometry

BearishSun 10 éve
szülő
commit
0fa957c38c

+ 335 - 333
BansheeEngine/Include/BsLight.h

@@ -1,334 +1,336 @@
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsIReflectable.h"
-#include "BsVector3.h"
-#include "BsQuaternion.h"
-#include "BsColor.h"
-#include "BsSphere.h"
-#include "BsCoreObject.h"
-
-namespace BansheeEngine
-{
-	/**
-	 * @brief	Light type that determines how is light information parsed
-	 *			by the renderer and other systems.
-	 */
-	enum class LightType
-	{
-		Directional, 
-		Point, 
-		Spot
-	};
-
-	/**
-	 * @brief	Signals which portion of a LightInternal is dirty.
-	 */
-	enum class LightDirtyFlag
-	{
-		Transform = 0x01,
-		Everything = 0x02
-	};
-
-	/**
-	 * @brief	Illuminates a portion of the scene covered by a light. Base class for both sim and core 
-	 *			thread Light implementations.
-	 */
-	class BS_EXPORT LightBase
-	{
-	public:
-		LightBase();
-		LightBase(LightType type, Color color, float intensity, float range, 
-			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
-
-		virtual ~LightBase() { }
-
-		/**
-		 * @brief	Returns the position of the light, in world space.
-		 */
-		Vector3 getPosition() const { return mPosition; }
-
-		/**
-		 * @brief	Sets the position of the light, in world space.
-		 */
-		void setPosition(const Vector3& position) { mPosition = position; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Returns the rotation of the light, in world space.
-		 */
-		Quaternion getRotation() const { return mRotation; }
-
-		/**
-		 * @brief	Sets the rotation of the light, in world space.
-		 */
-		void setRotation(const Quaternion& rotation) { mRotation = rotation; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Returns the type of the light.
-		 */
-		LightType getType() const { return mType; }
-
-		/**
-		 * @brief	Changes the type of the light.
-		 */
-		void setType(LightType type) { mType = type; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Checks does this light cast shadows when rendered.
-		 */
-		bool getCastsShadow() const { return mCastsShadows; }
-
-		/**
-		 * @brief	Sets whether this light will cast shadows when rendered.
-		 */
-		void setCastsShadow(bool castsShadow) { mCastsShadows = castsShadow; _markCoreDirty(); }
-
-		/**
-		 * @brief	Returns the color emitted from the light.
-		 */
-		Color getColor() const { return mColor; }
-
-		/**
-		 * @brief	Sets the color emitted from the light.
-		 */
-		void setColor(const Color& color) { mColor = color; _markCoreDirty(); }
-
-		/**
-		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
-		 */
-		float getRange() const { return mRange; }
-
-		/**
-		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
-		 *
-		 * @note	Normally you want to set this at a point where light intensity is too low due to attenuation.
-		 */
-		void setRange(float range) { mRange = range; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Gets the power of the light source. This is luminous flux for point & spot lights, 
-		 *			and radiance for directional lights.
-		 */
-		float getIntensity() const { return mIntensity; }
-
-		/**
-		 * @brief	Sets the power of the light source. This will be luminous flux for point & spot lights, 
-		 *			and radiance for directional lights.
-		 */
-		void setIntensity(float intensity) { mIntensity = intensity; _markCoreDirty(); }
-
-		/**
-		 * @brief	Gets the total angle covered by a spot light.
-		 */
-		Degree getSpotAngle() const { return mSpotAngle; }
-
-		/**
-		 * @brief	Sets the total angle covered by a spot light.
-		 */
-		void setSpotAngle(const Degree& spotAngle) { mSpotAngle = spotAngle; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Gets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
-		 *			starts linearly falling off as the angle approaches the total spot angle.
-		 */
-		Degree getSpotFalloffAngle() const { return mSpotFalloffAngle; }
-
-		/**
-		 * @brief	Sets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
-		 *			starts linearly falling off as the angle approaches the total spot angle.
-		 */
-		void setSpotFalloffAngle(const Degree& spotFallofAngle) { mSpotFalloffAngle = spotFallofAngle; _markCoreDirty(); updateBounds(); }
-
-		/**
-		 * @brief	Returns world space bounds that completely encompass the light's area of influence.
-		 */
-		Sphere getBounds() const { return mBounds; }
-
-		/**
-		 * @brief	Returns the radiance of the light source. This is the value that should be used in lighting equations.
-		 *
-		 * @note	Ignores the light direction, therefore caller must ensure to properly handle non-uniform emitters like spot lights
-		 */
-		float getRadiance() const;
-
-		/**
-		 * @brief	Checks whether the light should be rendered or not.
-		 */
-		bool getIsActive() const { return mIsActive; }
-
-		/**
-		 * @brief	Sets whether the light should be rendered or not.
-		 */
-		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
-
-		/**
-		 * @copydoc	CoreObject::markCoreDirty
-		 */
-		virtual void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) { }
-
-	protected:
-		/**
-		 * @brief	Updates the internal bounds for the light. Call this whenever a property affecting
-		 *			the bounds changes.
-		 */
-		virtual void updateBounds();
-
-		Vector3 mPosition; /**< World space position. */
-		Quaternion mRotation; /**< World space rotation. */
-
-		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
-		bool mCastsShadows; /**< Determines whether the light casts shadows. */
-		Color mColor; /**< Color of the light. */
-		float mRange; /**< Cut off range for the light when rendering. */
-		float mIntensity; /**< Power of the light source. This will be luminous flux for point & spot lights, and radiance for directional lights. */
-		Degree mSpotAngle; /**< Total angle covered by a spot light. */
-		Degree mSpotFalloffAngle; /**< Spot light angle at which falloff starts. Must be smaller than total angle. */
-		bool mIsActive; /**< Whether the light should be rendered or not. */
-		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
-	};
-
-	/**
-	 * @brief	Core thread usable version of a light.
-	 *
-	 * @see		LightBase
-	 */
-	class BS_EXPORT LightCore : public CoreObjectCore, public LightBase
-	{
-	public:
-		~LightCore();
-
-		/**
-		 * @brief	Sets an ID that can be used for uniquely identifying this object by the renderer.
-		 */
-		void setRendererId(UINT32 id) { mRendererId = id; }
-
-		/**
-		 * @brief	Retrieves an ID that can be used for uniquely identifying this object by the renderer.
-		 */
-		UINT32 getRendererId() const { return mRendererId; }
-
-		/**
-		 * @brief	Returns a mesh that represents the light's bounds.
-		 */
-		SPtr<MeshCore> getMesh() const { return mMesh; }
-
-	protected:
-		friend class Light;
-
-		LightCore(LightType type, Color color, float intensity, 
-			float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
-
-		/**
-		 * @copydoc	CoreObjectCore::initialize
-		 */
-		void initialize() override;
-
-		/**
-		 * @copydoc	CoreObject::syncToCore
-		 */
-		void syncToCore(const CoreSyncData& data) override;
-
-		/**
-		 * @copydoc	CoreObject::updateBounds
-		 */
-		void updateBounds() override;
-
-		/**
-		 * @brief	Generates a mesh that represents the light's bounds. Uses current light properties
-		 * 			for determining the mesh type and size.
-		 */
-		void generateMesh();
-
-		UINT32 mRendererId;
-		SPtr<MeshCore> mMesh;
-	};
-
-	/**
-	 * @brief	Sim thread usable version of a light.
-	 *
-	 * @see		LightBase
-	 */
-	class BS_EXPORT Light : public IReflectable, public CoreObject, public LightBase
-	{
-	public:
-		/**
-		 * @brief	Retrieves an implementation of a light usable only from the core thread.
-		 */
-		SPtr<LightCore> getCore() const;
-
-		/**
-	     * @brief	Returns the hash value that can be used to identify if the internal data needs an update.
-		 *
-		 * @note	Internal method.
-		 */
-		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
-
-		/**
-	     * @brief	Sets the hash value that can be used to identify if the internal data needs an update.
-		 *
-		 * @note	Internal method.
-		 */
-		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
-
-		/**
-		 * @brief	Updates internal transform values from the specified scene object, in case that scene
-		 *			object's transform changed since the last call.
-		 *
-		 * @note	Assumes the same scene object will be provided every time.
-		 */
-		void _updateTransform(const HSceneObject& parent);
-
-		/**
-		 * @brief	Creates a new light with provided settings.
-		 *
-		 * @param	type				Type of light that determines how are the rest of the parameters interpreted.
-		 * @param	color				Color of the light.
-		 * @param	intensity			Power of the light source. This will be luminous flux for point & spot lights, 
-		 *								and radiance for directional lights.
-		 * @param	range				Cut off range for the light when rendering.
-		 * @param	castsShadows		Determines whether the light casts shadows.
-		 * @param	spotAngle			Total angle covered by a spot light.
-		 * @param	spotFalloffAngle	Spot light angle at which falloff starts. Must be smaller than total angle.
-		 */
-		static SPtr<Light> create(LightType type = LightType::Point, Color color = Color::White,
-			float intensity = 100.0f, float range = 10.0f, bool castsShadows = false,
-			Degree spotAngle = Degree(45), Degree spotFalloffAngle = Degree(40));
-
-	protected:
-		Light(LightType type, Color color, float intensity, float range, 
-			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
-
-		/**
-		 * @copydoc	CoreObject::createCore
-		 */
-		SPtr<CoreObjectCore> createCore() const override;
-
-		/**
-		 * @copydoc	CoreObject::markCoreDirty
-		 */
-		void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) override;
-
-		/**
-		 * @copydoc	CoreObject::syncToCore
-		 */
-		CoreSyncData syncToCore(FrameAlloc* allocator) override;
-
-		/**
-		 * @brief	Creates a light with without initializing it. Used for serialization.
-		 */
-		static SPtr<Light> createEmpty();
-
-		UINT32 mLastUpdateHash;
-
-		/************************************************************************/
-		/* 								RTTI		                     		*/
-		/************************************************************************/
-	public:
-		friend class LightRTTI;
-		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
-
-	protected:
-		Light(); // Serialization only
-	};
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsIReflectable.h"
+#include "BsVector3.h"
+#include "BsQuaternion.h"
+#include "BsColor.h"
+#include "BsSphere.h"
+#include "BsCoreObject.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Light type that determines how is light information parsed
+	 *			by the renderer and other systems.
+	 */
+	enum class LightType
+	{
+		Directional, 
+		Point, 
+		Spot
+	};
+
+	/**
+	 * @brief	Signals which portion of a LightInternal is dirty.
+	 */
+	enum class LightDirtyFlag
+	{
+		Transform = 0x01,
+		Everything = 0x02
+	};
+
+	/**
+	 * @brief	Illuminates a portion of the scene covered by a light. Base class for both sim and core 
+	 *			thread Light implementations.
+	 */
+	class BS_EXPORT LightBase
+	{
+	public:
+		LightBase();
+		LightBase(LightType type, Color color, float intensity, float range, 
+			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
+
+		virtual ~LightBase() { }
+
+		/**
+		 * @brief	Returns the position of the light, in world space.
+		 */
+		Vector3 getPosition() const { return mPosition; }
+
+		/**
+		 * @brief	Sets the position of the light, in world space.
+		 */
+		void setPosition(const Vector3& position) { mPosition = position; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns the rotation of the light, in world space.
+		 */
+		Quaternion getRotation() const { return mRotation; }
+
+		/**
+		 * @brief	Sets the rotation of the light, in world space.
+		 */
+		void setRotation(const Quaternion& rotation) { mRotation = rotation; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns the type of the light.
+		 */
+		LightType getType() const { return mType; }
+
+		/**
+		 * @brief	Changes the type of the light.
+		 */
+		void setType(LightType type) { mType = type; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Checks does this light cast shadows when rendered.
+		 */
+		bool getCastsShadow() const { return mCastsShadows; }
+
+		/**
+		 * @brief	Sets whether this light will cast shadows when rendered.
+		 */
+		void setCastsShadow(bool castsShadow) { mCastsShadows = castsShadow; _markCoreDirty(); }
+
+		/**
+		 * @brief	Returns the color emitted from the light.
+		 */
+		Color getColor() const { return mColor; }
+
+		/**
+		 * @brief	Sets the color emitted from the light.
+		 */
+		void setColor(const Color& color) { mColor = color; _markCoreDirty(); }
+
+		/**
+		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
+		 */
+		float getRange() const { return mRange; }
+
+		/**
+		 * @brief	Returns the maximum range of the light. Light will not affect any geometry past that point.
+		 *
+		 * @note	Normally you want to set this at a point where light intensity is too low due to attenuation.
+		 */
+		void setRange(float range) { mRange = range; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Gets the power of the light source. This is luminous flux for point & spot lights, 
+		 *			and radiance for directional lights.
+		 */
+		float getIntensity() const { return mIntensity; }
+
+		/**
+		 * @brief	Sets the power of the light source. This will be luminous flux for point & spot lights, 
+		 *			and radiance for directional lights.
+		 */
+		void setIntensity(float intensity) { mIntensity = intensity; _markCoreDirty(); }
+
+		/**
+		 * @brief	Gets the total angle covered by a spot light.
+		 */
+		Degree getSpotAngle() const { return mSpotAngle; }
+
+		/**
+		 * @brief	Sets the total angle covered by a spot light.
+		 */
+		void setSpotAngle(const Degree& spotAngle) { mSpotAngle = spotAngle; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Gets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
+		 *			starts linearly falling off as the angle approaches the total spot angle.
+		 */
+		Degree getSpotFalloffAngle() const { return mSpotFalloffAngle; }
+
+		/**
+		 * @brief	Sets the falloff angle covered by a spot light. Falloff angle determines at what point does light intensity
+		 *			starts linearly falling off as the angle approaches the total spot angle.
+		 */
+		void setSpotFalloffAngle(const Degree& spotFallofAngle) { mSpotFalloffAngle = spotFallofAngle; _markCoreDirty(); updateBounds(); }
+
+		/**
+		 * @brief	Returns world space bounds that completely encompass the light's area of influence.
+		 */
+		Sphere getBounds() const { return mBounds; }
+
+		/**
+		 * @brief	Returns the radiance of the light source. This is the value that should be used in lighting equations.
+		 *
+		 * @note	Ignores the light direction, therefore caller must ensure to properly handle non-uniform emitters like spot lights
+		 */
+		float getRadiance() const;
+
+		/**
+		 * @brief	Checks whether the light should be rendered or not.
+		 */
+		bool getIsActive() const { return mIsActive; }
+
+		/**
+		 * @brief	Sets whether the light should be rendered or not.
+		 */
+		void setIsActive(bool active) { mIsActive = active; _markCoreDirty(); }
+
+		/**
+		 * @copydoc	CoreObject::markCoreDirty
+		 */
+		virtual void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) { }
+
+	protected:
+		/**
+		 * @brief	Updates the internal bounds for the light. Call this whenever a property affecting
+		 *			the bounds changes.
+		 */
+		virtual void updateBounds();
+
+		Vector3 mPosition; /**< World space position. */
+		Quaternion mRotation; /**< World space rotation. */
+
+		LightType mType; /**< Type of light that determines how are the rest of the parameters interpreted. */
+		bool mCastsShadows; /**< Determines whether the light casts shadows. */
+		Color mColor; /**< Color of the light. */
+		float mRange; /**< Cut off range for the light when rendering. */
+		float mIntensity; /**< Power of the light source. This will be luminous flux for point & spot lights, and radiance for directional lights. */
+		Degree mSpotAngle; /**< Total angle covered by a spot light. */
+		Degree mSpotFalloffAngle; /**< Spot light angle at which falloff starts. Must be smaller than total angle. */
+		bool mIsActive; /**< Whether the light should be rendered or not. */
+		Sphere mBounds; /**< Sphere that bounds the light area of influence. */
+	};
+
+	/**
+	 * @brief	Core thread usable version of a light.
+	 *
+	 * @see		LightBase
+	 */
+	class BS_EXPORT LightCore : public CoreObjectCore, public LightBase
+	{
+	public:
+		~LightCore();
+
+		/**
+		 * @brief	Sets an ID that can be used for uniquely identifying this object by the renderer.
+		 */
+		void setRendererId(UINT32 id) { mRendererId = id; }
+
+		/**
+		 * @brief	Retrieves an ID that can be used for uniquely identifying this object by the renderer.
+		 */
+		UINT32 getRendererId() const { return mRendererId; }
+
+		/**
+		 * @brief	Returns a mesh that represents the light's bounds.
+		 */
+		SPtr<MeshCore> getMesh() const { return mMesh; }
+
+		static const UINT32 LIGHT_CONE_NUM_SIDES;
+		static const UINT32 LIGHT_CONE_NUM_SLICES;
+	protected:
+		friend class Light;
+
+		LightCore(LightType type, Color color, float intensity, 
+			float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
+
+		/**
+		 * @copydoc	CoreObjectCore::initialize
+		 */
+		void initialize() override;
+
+		/**
+		 * @copydoc	CoreObject::syncToCore
+		 */
+		void syncToCore(const CoreSyncData& data) override;
+
+		/**
+		 * @copydoc	CoreObject::updateBounds
+		 */
+		void updateBounds() override;
+
+		/**
+		 * @brief	Generates a mesh that represents the light's bounds. Uses current light properties
+		 * 			for determining the mesh type and size.
+		 */
+		void generateMesh();
+
+		UINT32 mRendererId;
+		SPtr<MeshCore> mMesh;
+	};
+
+	/**
+	 * @brief	Sim thread usable version of a light.
+	 *
+	 * @see		LightBase
+	 */
+	class BS_EXPORT Light : public IReflectable, public CoreObject, public LightBase
+	{
+	public:
+		/**
+		 * @brief	Retrieves an implementation of a light usable only from the core thread.
+		 */
+		SPtr<LightCore> getCore() const;
+
+		/**
+	     * @brief	Returns the hash value that can be used to identify if the internal data needs an update.
+		 *
+		 * @note	Internal method.
+		 */
+		UINT32 _getLastModifiedHash() const { return mLastUpdateHash; }
+
+		/**
+	     * @brief	Sets the hash value that can be used to identify if the internal data needs an update.
+		 *
+		 * @note	Internal method.
+		 */
+		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
+
+		/**
+		 * @brief	Updates internal transform values from the specified scene object, in case that scene
+		 *			object's transform changed since the last call.
+		 *
+		 * @note	Assumes the same scene object will be provided every time.
+		 */
+		void _updateTransform(const HSceneObject& parent);
+
+		/**
+		 * @brief	Creates a new light with provided settings.
+		 *
+		 * @param	type				Type of light that determines how are the rest of the parameters interpreted.
+		 * @param	color				Color of the light.
+		 * @param	intensity			Power of the light source. This will be luminous flux for point & spot lights, 
+		 *								and radiance for directional lights.
+		 * @param	range				Cut off range for the light when rendering.
+		 * @param	castsShadows		Determines whether the light casts shadows.
+		 * @param	spotAngle			Total angle covered by a spot light.
+		 * @param	spotFalloffAngle	Spot light angle at which falloff starts. Must be smaller than total angle.
+		 */
+		static SPtr<Light> create(LightType type = LightType::Point, Color color = Color::White,
+			float intensity = 100.0f, float range = 10.0f, bool castsShadows = false,
+			Degree spotAngle = Degree(45), Degree spotFalloffAngle = Degree(40));
+
+	protected:
+		Light(LightType type, Color color, float intensity, float range, 
+			bool castsShadows, Degree spotAngle, Degree spotFalloffAngle);
+
+		/**
+		 * @copydoc	CoreObject::createCore
+		 */
+		SPtr<CoreObjectCore> createCore() const override;
+
+		/**
+		 * @copydoc	CoreObject::markCoreDirty
+		 */
+		void _markCoreDirty(LightDirtyFlag flag = LightDirtyFlag::Everything) override;
+
+		/**
+		 * @copydoc	CoreObject::syncToCore
+		 */
+		CoreSyncData syncToCore(FrameAlloc* allocator) override;
+
+		/**
+		 * @brief	Creates a light with without initializing it. Used for serialization.
+		 */
+		static SPtr<Light> createEmpty();
+
+		UINT32 mLastUpdateHash;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class LightRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+
+	protected:
+		Light(); // Serialization only
+	};
 }

+ 358 - 323
BansheeEngine/Source/BsLight.cpp

@@ -1,325 +1,360 @@
-#include "BsLight.h"
-#include "BsLightRTTI.h"
-#include "BsRendererManager.h"
-#include "BsRenderer.h"
-#include "BsFrameAlloc.h"
-#include "BsSceneObject.h"
-#include "BsVertexDataDesc.h"
-#include "BsMesh.h"
-#include "BsShapeMeshes3D.h"
-
-namespace BansheeEngine
-{
-	LightBase::LightBase()
-		:mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
-		mIntensity(100.0f), mSpotAngle(45), mColor(Color::White), mIsActive(true)
-	{
-		mBounds = Sphere(mPosition, mRange);
-	}
-
-	LightBase::LightBase(LightType type, Color color,
-		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
-		:mType(type), mCastsShadows(castsShadows), mRange(range), mSpotFalloffAngle(spotFalloffAngle),
-		mIntensity(intensity), mSpotAngle(spotAngle), mColor(color), mIsActive(true)
-	{
-		mBounds = Sphere(mPosition, mRange);
-	}
-
-	float LightBase::getRadiance() const
-	{
-		switch (mType)
-		{
-		case LightType::Point:
-			return mIntensity / (4 * Math::PI);
-		case LightType::Spot:
-		{
-			float cosTotalAngle = Math::cos(mSpotAngle);
-			float cosFalloffAngle = Math::cos(mSpotFalloffAngle);
-
-			return mIntensity / (Math::TWO_PI * (1.0f - (cosFalloffAngle + cosTotalAngle) * 0.5f));
-		}
-		}
-
-		return mIntensity;
-	}
-
-	void LightBase::updateBounds()
-	{
-		switch (mType)
-		{
-		case LightType::Directional:
-			mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
-			break;
-		case LightType::Point:
-			mBounds = Sphere(mPosition, mRange);
-			break;
-		case LightType::Spot:
-		{
-			Degree angle = Math::clamp(mSpotAngle, Degree(-90), Degree(90));
-			float coneRadius = Math::tan(angle) * mRange;
-
-			float radius;
-			Vector3 offset;
-			if (coneRadius < mRange)
-			{
-				radius = (mRange * mRange + coneRadius * coneRadius) / (0.5f * mRange);
-				offset = Vector3(0, 0, -(mRange - coneRadius));
-			}
-			else
-				radius = coneRadius;
-
-			Vector3 center = mPosition + mRotation.rotate(offset);
-			mBounds = Sphere(center, radius);
-		}
-			break;
-		}
-	}
-
-	LightCore::LightCore(LightType type, Color color,
-		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
-		:LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle), mRendererId(0)
-	{
-
-	}
-
-	LightCore::~LightCore()
-	{
-		gRenderer()->_notifyLightRemoved(this);
-	}
-
-	void LightCore::initialize()
-	{
-		updateBounds();
-		gRenderer()->_notifyLightAdded(this);
-
-		CoreObjectCore::initialize();
-	}
-
-	void LightCore::syncToCore(const CoreSyncData& data)
-	{
-		char* dataPtr = (char*)data.getBuffer();
-
-		UINT32 dirtyFlags = 0;
-		bool oldIsActive = mIsActive;
-		LightType oldType = mType;
-
-		dataPtr = rttiReadElem(mPosition, dataPtr);
-		dataPtr = rttiReadElem(mRotation, dataPtr);
-		dataPtr = rttiReadElem(mType, dataPtr);
-		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
-		dataPtr = rttiReadElem(mColor, dataPtr);
-		dataPtr = rttiReadElem(mRange, dataPtr);
-		dataPtr = rttiReadElem(mIntensity, dataPtr);
-		dataPtr = rttiReadElem(mSpotAngle, dataPtr);
-		dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
-		dataPtr = rttiReadElem(mIsActive, dataPtr);
-		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
-		dataPtr = rttiReadElem(mBounds, dataPtr);
-
-		updateBounds();
-
-		if (dirtyFlags == (UINT32)LightDirtyFlag::Transform)
-		{
-			if (mIsActive)
-				gRenderer()->_notifyLightUpdated(this);
-		}
-		else
-		{
-			if (oldIsActive != mIsActive)
-			{
-				if (mIsActive)
-					gRenderer()->_notifyLightAdded(this);
-				else
+#include "BsLight.h"
+#include "BsLightRTTI.h"
+#include "BsRendererManager.h"
+#include "BsRenderer.h"
+#include "BsFrameAlloc.h"
+#include "BsSceneObject.h"
+#include "BsVertexDataDesc.h"
+#include "BsMesh.h"
+#include "BsShapeMeshes3D.h"
+
+namespace BansheeEngine
+{
+	LightBase::LightBase()
+		:mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
+		mIntensity(100.0f), mSpotAngle(45), mColor(Color::White), mIsActive(true)
+	{
+		mBounds = Sphere(mPosition, mRange);
+	}
+
+	LightBase::LightBase(LightType type, Color color,
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		:mType(type), mCastsShadows(castsShadows), mRange(range), mSpotFalloffAngle(spotFalloffAngle),
+		mIntensity(intensity), mSpotAngle(spotAngle), mColor(color), mIsActive(true)
+	{
+		mBounds = Sphere(mPosition, mRange);
+	}
+
+	float LightBase::getRadiance() const
+	{
+		switch (mType)
+		{
+		case LightType::Point:
+			return mIntensity / (4 * Math::PI);
+		case LightType::Spot:
+		{
+			float cosTotalAngle = Math::cos(mSpotAngle);
+			float cosFalloffAngle = Math::cos(mSpotFalloffAngle);
+
+			return mIntensity / (Math::TWO_PI * (1.0f - (cosFalloffAngle + cosTotalAngle) * 0.5f));
+		}
+		}
+
+		return mIntensity;
+	}
+
+	void LightBase::updateBounds()
+	{
+		switch (mType)
+		{
+		case LightType::Directional:
+			mBounds = Sphere(mPosition, std::numeric_limits<float>::infinity());
+			break;
+		case LightType::Point:
+			mBounds = Sphere(mPosition, mRange);
+			break;
+		case LightType::Spot:
+		{
+			Degree angle = Math::clamp(mSpotAngle, Degree(-90), Degree(90));
+			float coneRadius = Math::tan(angle) * mRange;
+
+			float radius;
+			Vector3 offset;
+			if (coneRadius < mRange)
+			{
+				radius = (mRange * mRange + coneRadius * coneRadius) / (0.5f * mRange);
+				offset = Vector3(0, 0, -(mRange - coneRadius));
+			}
+			else
+				radius = coneRadius;
+
+			Vector3 center = mPosition + mRotation.rotate(offset);
+			mBounds = Sphere(center, radius);
+		}
+			break;
+		}
+	}
+
+	const UINT32 LightCore::LIGHT_CONE_NUM_SIDES = 20;
+	const UINT32 LightCore::LIGHT_CONE_NUM_SLICES = 10;
+
+	LightCore::LightCore(LightType type, Color color,
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		:LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle), mRendererId(0)
+	{
+
+	}
+
+	LightCore::~LightCore()
+	{
+		gRenderer()->_notifyLightRemoved(this);
+	}
+
+	void LightCore::initialize()
+	{
+		updateBounds();
+		gRenderer()->_notifyLightAdded(this);
+
+		CoreObjectCore::initialize();
+	}
+
+	void LightCore::syncToCore(const CoreSyncData& data)
+	{
+		char* dataPtr = (char*)data.getBuffer();
+
+		UINT32 dirtyFlags = 0;
+		bool oldIsActive = mIsActive;
+		LightType oldType = mType;
+
+		dataPtr = rttiReadElem(mPosition, dataPtr);
+		dataPtr = rttiReadElem(mRotation, dataPtr);
+		dataPtr = rttiReadElem(mType, dataPtr);
+		dataPtr = rttiReadElem(mCastsShadows, dataPtr);
+		dataPtr = rttiReadElem(mColor, dataPtr);
+		dataPtr = rttiReadElem(mRange, dataPtr);
+		dataPtr = rttiReadElem(mIntensity, dataPtr);
+		dataPtr = rttiReadElem(mSpotAngle, dataPtr);
+		dataPtr = rttiReadElem(mSpotFalloffAngle, dataPtr);
+		dataPtr = rttiReadElem(mIsActive, dataPtr);
+		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
+		dataPtr = rttiReadElem(mBounds, dataPtr);
+
+		updateBounds();
+
+		if (dirtyFlags == (UINT32)LightDirtyFlag::Transform)
+		{
+			if (mIsActive)
+				gRenderer()->_notifyLightUpdated(this);
+		}
+		else
+		{
+			if (oldIsActive != mIsActive)
+			{
+				if (mIsActive)
+					gRenderer()->_notifyLightAdded(this);
+				else
+				{
+					LightType newType = mType;
+					mType = oldType;
+					gRenderer()->_notifyLightRemoved(this);
+					mType = newType;
+				}
+			}
+			else
+			{
+				LightType newType = mType;
+				mType = oldType;
+				gRenderer()->_notifyLightRemoved(this);
+				mType = newType;
+
+				gRenderer()->_notifyLightAdded(this);
+			}
+		}
+	}
+
+	void LightCore::updateBounds()
+	{
+		LightBase::updateBounds();
+
+		generateMesh();
+	}
+
+	void LightCore::generateMesh()
+	{
+		switch (mType)
+		{
+		case LightType::Directional:
+			mMesh = nullptr;
+			return;
+		case LightType::Point:
+		{
+			SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
+			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+
+			UINT32 numVertices = 0;
+			UINT32 numIndices = 0;
+
+			ShapeMeshes3D::getNumElementsSphere(1, numVertices, numIndices);
+			MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
+
+			UINT32* indexData = meshData->getIndices32();
+			UINT8* positionData = meshData->getElementData(VES_POSITION);
+
+			ShapeMeshes3D::solidSphere(mBounds, positionData, nullptr, 0,
+				vertexDesc->getVertexStride(), indexData, 0, 1);
+
+			mMesh = MeshCore::create(meshData);
+		}
+			return;
+		case LightType::Spot:
+		{
+			SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
+			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+
+			UINT32 numVertices = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES * 2;
+			UINT32 numIndices = ((LIGHT_CONE_NUM_SIDES * 2) * LIGHT_CONE_NUM_SLICES * 2) * 3;
+
+			ShapeMeshes3D::getNumElementsCone(1, numVertices, numIndices);
+			MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
+
+			UINT32* indexData = meshData->getIndices32();
+			UINT8* positionData = meshData->getElementData(VES_POSITION);
+			UINT32 stride = vertexDesc->getVertexStride();
+
+			// Dummy vertex positions, actual ones generated in shader
+			for (UINT32 i = 0; i < numVertices; i++)
+			{
+				memcpy(positionData, &Vector3::ZERO, sizeof(Vector3));
+				positionData += stride;
+			}
+
+			// Cone indices
+			UINT32 curIdx = 0;
+			for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
+			{
+				for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
 				{
-					LightType newType = mType;
-					mType = oldType;
-					gRenderer()->_notifyLightRemoved(this);
-					mType = newType;
-				}
-			}
-			else
-			{
-				LightType newType = mType;
-				mType = oldType;
-				gRenderer()->_notifyLightRemoved(this);
-				mType = newType;
-
-				gRenderer()->_notifyLightAdded(this);
-			}
-		}
-	}
-
-	void LightCore::updateBounds()
-	{
-		LightBase::updateBounds();
-
-		generateMesh();
-	}
-
-	void LightCore::generateMesh()
-	{
-		switch (mType)
-		{
-		case LightType::Directional:
-			mMesh = nullptr;
-			return;
-		case LightType::Point:
-		{
-			SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
-			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
-
-			UINT32 numVertices = 0;
-			UINT32 numIndices = 0;
-
-			ShapeMeshes3D::getNumElementsSphere(1, numVertices, numIndices);
-			MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
-
-			UINT32* indexData = meshData->getIndices32();
-			UINT8* positionData = meshData->getElementData(VES_POSITION);
-
-			ShapeMeshes3D::solidSphere(mBounds, positionData, nullptr, 0,
-				vertexDesc->getVertexStride(), indexData, 0, 1);
-
-			mMesh = MeshCore::create(meshData);
-		}
-			return;
-		case LightType::Spot:
-		{
-			SPtr<VertexDataDesc> vertexDesc = bs_shared_ptr_new<VertexDataDesc>();
-			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
-
-			UINT32 numVertices = 0;
-			UINT32 numIndices = 0;
-
-			ShapeMeshes3D::getNumElementsCone(1, numVertices, numIndices);
-			MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
-
-			UINT32* indexData = meshData->getIndices32();
-			UINT8* positionData = meshData->getElementData(VES_POSITION);
-
-			Vector3 normal = -Vector3::UNIT_X;
-			Vector3 base = -normal * mRange;
-			
-			float radius = Math::sin(mSpotFalloffAngle) * mRange;
-
-			ShapeMeshes3D::solidCone(base, normal, mRange, radius, positionData, nullptr, 0,
-				vertexDesc->getVertexStride(), indexData, 0, 1);
-
-			mMesh = MeshCore::create(meshData);
-		}
-			return;
-		}
-	}
-
-	Light::Light()
-		:mLastUpdateHash(0)
-	{
-		
-	}
-
-	Light::Light(LightType type, Color color,
-		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
-		: LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle),
-		mLastUpdateHash(0)
-	{
-		// Calling virtual method is okay here because this is the most derived type
-		updateBounds();
-	}
-
-	SPtr<LightCore> Light::getCore() const
-	{
-		return std::static_pointer_cast<LightCore>(mCoreSpecific);
-	}
-
-	SPtr<Light> Light::create(LightType type, Color color,
-		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
-	{
-		Light* handler = new (bs_alloc<Light>()) 
-			Light(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle);
-		SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
-		handlerPtr->_setThisPtr(handlerPtr);
-		handlerPtr->initialize();
-
-		return handlerPtr;
-	}
-
-	SPtr<Light> Light::createEmpty()
-	{
-		Light* handler = new (bs_alloc<Light>()) Light();
-		SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
-		handlerPtr->_setThisPtr(handlerPtr);
-
-		return handlerPtr;
-	}
-
-	SPtr<CoreObjectCore> Light::createCore() const
-	{
-		LightCore* handler = new (bs_alloc<LightCore>()) 
-			LightCore(mType, mColor, mIntensity, mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
-		SPtr<LightCore> handlerPtr = bs_shared_ptr<LightCore>(handler);
-		handlerPtr->_setThisPtr(handlerPtr);
-
-		return handlerPtr;
-	}
-
-	CoreSyncData Light::syncToCore(FrameAlloc* allocator)
-	{
-		UINT32 size = 0;
-		size += rttiGetElemSize(mPosition);
-		size += rttiGetElemSize(mRotation);
-		size += rttiGetElemSize(mType);
-		size += rttiGetElemSize(mCastsShadows);
-		size += rttiGetElemSize(mColor);
-		size += rttiGetElemSize(mRange);
-		size += rttiGetElemSize(mIntensity);
-		size += rttiGetElemSize(mSpotAngle);
-		size += rttiGetElemSize(mIsActive);
-		size += rttiGetElemSize(mSpotFalloffAngle);
-		size += rttiGetElemSize(getCoreDirtyFlags());
-		size += rttiGetElemSize(mBounds);
-
-		UINT8* buffer = allocator->alloc(size);
-
-		char* dataPtr = (char*)buffer;
-		dataPtr = rttiWriteElem(mPosition, dataPtr);
-		dataPtr = rttiWriteElem(mRotation, dataPtr);
-		dataPtr = rttiWriteElem(mType, dataPtr);
-		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
-		dataPtr = rttiWriteElem(mColor, dataPtr);
-		dataPtr = rttiWriteElem(mRange, dataPtr);
-		dataPtr = rttiWriteElem(mIntensity, dataPtr);
-		dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
-		dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
-		dataPtr = rttiWriteElem(mIsActive, dataPtr);
-		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
-		dataPtr = rttiWriteElem(mBounds, dataPtr);
-
-		return CoreSyncData(buffer, size);
-	}
-
-	void Light::_updateTransform(const HSceneObject& parent)
-	{
-		UINT32 curHash = parent->getTransformHash();
-		if (curHash != _getLastModifiedHash())
-		{
-			setPosition(parent->getWorldPosition());
-			setRotation(parent->getWorldRotation());
-			_setLastModifiedHash(curHash);
-		}
-	}
-
-	void Light::_markCoreDirty(LightDirtyFlag flag)
-	{
-		markCoreDirty((UINT32)flag);
-	}
-
-	RTTITypeBase* Light::getRTTIStatic()
-	{
-		return LightRTTI::instance();
-	}
-
-	RTTITypeBase* Light::getRTTI() const
-	{
-		return Light::getRTTIStatic();
-	}
+					indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
+					indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
+
+					indexData[curIdx++] = sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
+				}
+			}
+
+			// Sphere cap indices
+			UINT32 coneOffset = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES;
+			for (UINT32 sliceIdx = 0; sliceIdx < (LIGHT_CONE_NUM_SLICES - 1); sliceIdx++)
+			{
+				for (UINT32 sideIdx = 0; sideIdx < LIGHT_CONE_NUM_SIDES; sideIdx++)
+				{
+					indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + sideIdx;
+					indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
+
+					indexData[curIdx++] = coneOffset + sliceIdx * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + (sideIdx + 1) % LIGHT_CONE_NUM_SIDES;
+					indexData[curIdx++] = coneOffset + (sliceIdx + 1) * LIGHT_CONE_NUM_SIDES + sideIdx;
+				}
+			}
+
+			mMesh = MeshCore::create(meshData);
+		}
+			return;
+		}
+	}
+
+	Light::Light()
+		:mLastUpdateHash(0)
+	{
+		
+	}
+
+	Light::Light(LightType type, Color color,
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+		: LightBase(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle),
+		mLastUpdateHash(0)
+	{
+		// Calling virtual method is okay here because this is the most derived type
+		updateBounds();
+	}
+
+	SPtr<LightCore> Light::getCore() const
+	{
+		return std::static_pointer_cast<LightCore>(mCoreSpecific);
+	}
+
+	SPtr<Light> Light::create(LightType type, Color color,
+		float intensity, float range, bool castsShadows, Degree spotAngle, Degree spotFalloffAngle)
+	{
+		Light* handler = new (bs_alloc<Light>()) 
+			Light(type, color, intensity, range, castsShadows, spotAngle, spotFalloffAngle);
+		SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
+		handlerPtr->_setThisPtr(handlerPtr);
+		handlerPtr->initialize();
+
+		return handlerPtr;
+	}
+
+	SPtr<Light> Light::createEmpty()
+	{
+		Light* handler = new (bs_alloc<Light>()) Light();
+		SPtr<Light> handlerPtr = bs_core_ptr<Light>(handler);
+		handlerPtr->_setThisPtr(handlerPtr);
+
+		return handlerPtr;
+	}
+
+	SPtr<CoreObjectCore> Light::createCore() const
+	{
+		LightCore* handler = new (bs_alloc<LightCore>()) 
+			LightCore(mType, mColor, mIntensity, mRange, mCastsShadows, mSpotAngle, mSpotFalloffAngle);
+		SPtr<LightCore> handlerPtr = bs_shared_ptr<LightCore>(handler);
+		handlerPtr->_setThisPtr(handlerPtr);
+
+		return handlerPtr;
+	}
+
+	CoreSyncData Light::syncToCore(FrameAlloc* allocator)
+	{
+		UINT32 size = 0;
+		size += rttiGetElemSize(mPosition);
+		size += rttiGetElemSize(mRotation);
+		size += rttiGetElemSize(mType);
+		size += rttiGetElemSize(mCastsShadows);
+		size += rttiGetElemSize(mColor);
+		size += rttiGetElemSize(mRange);
+		size += rttiGetElemSize(mIntensity);
+		size += rttiGetElemSize(mSpotAngle);
+		size += rttiGetElemSize(mIsActive);
+		size += rttiGetElemSize(mSpotFalloffAngle);
+		size += rttiGetElemSize(getCoreDirtyFlags());
+		size += rttiGetElemSize(mBounds);
+
+		UINT8* buffer = allocator->alloc(size);
+
+		char* dataPtr = (char*)buffer;
+		dataPtr = rttiWriteElem(mPosition, dataPtr);
+		dataPtr = rttiWriteElem(mRotation, dataPtr);
+		dataPtr = rttiWriteElem(mType, dataPtr);
+		dataPtr = rttiWriteElem(mCastsShadows, dataPtr);
+		dataPtr = rttiWriteElem(mColor, dataPtr);
+		dataPtr = rttiWriteElem(mRange, dataPtr);
+		dataPtr = rttiWriteElem(mIntensity, dataPtr);
+		dataPtr = rttiWriteElem(mSpotAngle, dataPtr);
+		dataPtr = rttiWriteElem(mSpotFalloffAngle, dataPtr);
+		dataPtr = rttiWriteElem(mIsActive, dataPtr);
+		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
+		dataPtr = rttiWriteElem(mBounds, dataPtr);
+
+		return CoreSyncData(buffer, size);
+	}
+
+	void Light::_updateTransform(const HSceneObject& parent)
+	{
+		UINT32 curHash = parent->getTransformHash();
+		if (curHash != _getLastModifiedHash())
+		{
+			setPosition(parent->getWorldPosition());
+			setRotation(parent->getWorldRotation());
+			_setLastModifiedHash(curHash);
+		}
+	}
+
+	void Light::_markCoreDirty(LightDirtyFlag flag)
+	{
+		markCoreDirty((UINT32)flag);
+	}
+
+	RTTITypeBase* Light::getRTTIStatic()
+	{
+		return LightRTTI::instance();
+	}
+
+	RTTITypeBase* Light::getRTTI() const
+	{
+		return Light::getRTTIStatic();
+	}
 }

+ 87 - 86
RenderBeast/Include/BsLightRendering.h

@@ -1,87 +1,88 @@
-#pragma once
-
-#include "BsRenderBeastPrerequisites.h"
-#include "BsRendererMaterial.h"
-#include "BsParamBlocks.h"
-
-namespace BansheeEngine
-{
-	BS_PARAM_BLOCK_BEGIN(PerLightParamBuffer)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPositionAndType)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightColorAndIntensity)
-		BS_PARAM_BLOCK_ENTRY(Vector2, gLightSpotAngles)
-		BS_PARAM_BLOCK_ENTRY(Vector3, gLightDirection)
-		BS_PARAM_BLOCK_ENTRY(Vector4, gLightGeometry)
-	BS_PARAM_BLOCK_END
-
-	/**
-	 * Manipulates PerLight parameter buffer used in various shaders.
-	 */
-	class PerLightParams
-	{
-	public:
-		/**
-		 * Updates data in the parameter buffer from the data in the provided light.
-		 */
-		void setParameters(const LightCore* light);
-
-		/**
-		 * Returns the internal parameter buffer that can be bound to the pipeline.
-		 */
-		const SPtr<GpuParamBlockBufferCore>& getBuffer() const;
-	private:
-		PerLightParamBuffer mBuffer;
-	};
-
-	/**
-	 * Shader that renders directional light sources during deferred rendering light pass. 
-	 */
-	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat>
-	{
-		RMAT_DEF("DeferredDirectionalLightPass.bsl");
-
-	public:
-		DirectionalLightMat();
-
-		/**
-		 * Binds the gbuffer used for rendering the light.
-		 */
-		void setGBuffer(const SPtr<RenderTargets>& gbuffer);
-
-		/**
-		 * Updates the parameter buffers used by the material.
-		 */
-		void setParameters(const LightCore* light);
-	private:
-		PerLightParams mParams; // Note: Should this buffer be shared between both point and directional lights?
-		MaterialParamTextureCore mGBufferA;
-		MaterialParamTextureCore mGBufferB;
-		MaterialParamTextureCore mGBufferDepth;
-	};
-
-	/**
-	 * Shader that renders point (radial & spot) light sources during deferred rendering light pass. 
-	 */
-	class PointLightMat : public RendererMaterial<PointLightMat>
-	{
-		RMAT_DEF("DeferredPointLightPass.bsl");
-
-	public:
-		PointLightMat();
-
-		/**
-		 * Binds the gbuffer used for rendering the light.
-		 */
-		void setGBuffer(const SPtr<RenderTargets>& gbuffer);
-
-		/**
-		 * Updates the parameter buffers used by the material.
-		 */
-		void setParameters(const LightCore* light);
-	private:
-		PerLightParams mParams; // Note: Should this buffer be shared between both point and directional lights?
-		MaterialParamTextureCore mGBufferA;
-		MaterialParamTextureCore mGBufferB;
-		MaterialParamTextureCore mGBufferDepth;
-	};
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+#include "BsRendererMaterial.h"
+#include "BsParamBlocks.h"
+
+namespace BansheeEngine
+{
+	BS_PARAM_BLOCK_BEGIN(PerLightParamBuffer)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightPositionAndType)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightColorAndIntensity)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gLightSpotAngles)
+		BS_PARAM_BLOCK_ENTRY(Vector3, gLightDirection)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gLightGeometry)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatConeTransform)
+	BS_PARAM_BLOCK_END
+
+	/**
+	 * Manipulates PerLight parameter buffer used in various shaders.
+	 */
+	class PerLightParams
+	{
+	public:
+		/**
+		 * Updates data in the parameter buffer from the data in the provided light.
+		 */
+		void setParameters(const LightCore* light);
+
+		/**
+		 * Returns the internal parameter buffer that can be bound to the pipeline.
+		 */
+		const SPtr<GpuParamBlockBufferCore>& getBuffer() const;
+	private:
+		PerLightParamBuffer mBuffer;
+	};
+
+	/**
+	 * Shader that renders directional light sources during deferred rendering light pass. 
+	 */
+	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat>
+	{
+		RMAT_DEF("DeferredDirectionalLightPass.bsl");
+
+	public:
+		DirectionalLightMat();
+
+		/**
+		 * Binds the gbuffer used for rendering the light.
+		 */
+		void setGBuffer(const SPtr<RenderTargets>& gbuffer);
+
+		/**
+		 * Updates the parameter buffers used by the material.
+		 */
+		void setParameters(const LightCore* light);
+	private:
+		PerLightParams mParams; // Note: Should this buffer be shared between both point and directional lights?
+		MaterialParamTextureCore mGBufferA;
+		MaterialParamTextureCore mGBufferB;
+		MaterialParamTextureCore mGBufferDepth;
+	};
+
+	/**
+	 * Shader that renders point (radial & spot) light sources during deferred rendering light pass. 
+	 */
+	class PointLightMat : public RendererMaterial<PointLightMat>
+	{
+		RMAT_DEF("DeferredPointLightPass.bsl");
+
+	public:
+		PointLightMat();
+
+		/**
+		 * Binds the gbuffer used for rendering the light.
+		 */
+		void setGBuffer(const SPtr<RenderTargets>& gbuffer);
+
+		/**
+		 * Updates the parameter buffers used by the material.
+		 */
+		void setParameters(const LightCore* light);
+	private:
+		PerLightParams mParams; // Note: Should this buffer be shared between both point and directional lights?
+		MaterialParamTextureCore mGBufferA;
+		MaterialParamTextureCore mGBufferB;
+		MaterialParamTextureCore mGBufferDepth;
+	};
 }

+ 122 - 118
RenderBeast/Source/BsLightRendering.cpp

@@ -1,119 +1,123 @@
-#include "BsLightRendering.h"
-#include "BsMaterial.h"
-#include "BsShader.h"
-#include "BsRenderBeast.h"
-#include "BsRenderTargets.h"
-#include "BsGpuParams.h"
-#include "BsLight.h"
-
-namespace BansheeEngine
-{
-	void PerLightParams::setParameters(const LightCore* light)
-	{
-		// Note: I could just copy the data directly to the parameter buffer if I ensured the parameter
-		// layout matches
-
-		Vector4 positionAndType = (Vector4)light->getPosition();
-
-		switch (light->getType())
-		{
-		case LightType::Directional:
-			positionAndType.w = 0;
-			break;
-		case LightType::Point:
-			positionAndType.w = 0.3f;
-			break;
-		case LightType::Spot:
-			positionAndType.w = 0.8f;
-			break;
-		}
-
-		mBuffer.gLightPositionAndType.set(positionAndType);
-			
-		Vector4 colorAndIntensity;
-		colorAndIntensity.x = light->getColor().r;
-		colorAndIntensity.y = light->getColor().g;
-		colorAndIntensity.z = light->getColor().b;
-		colorAndIntensity.w = light->getIntensity();
-
-		mBuffer.gLightColorAndIntensity.set(colorAndIntensity);
-
-		Vector2 spotAngles;
-		spotAngles.x = light->getSpotFalloffAngle().valueDegrees();
-		spotAngles.y = light->getSpotAngle().valueDegrees();
-
-		mBuffer.gLightSpotAngles.set(spotAngles);
-
-		mBuffer.gLightDirection.set(light->getRotation().zAxis());
-
-		Vector4 lightGeometry;
-		lightGeometry.x = 20; // Cone geometry sides
-		lightGeometry.y = 10; // Cone geometry slices
-		lightGeometry.z = light->getBounds().getRadius();
-
-		lightGeometry.w = light->getSpotAngle().valueDegrees();
-
-		mBuffer.gLightGeometry.set(lightGeometry);
-	}
-
-	const SPtr<GpuParamBlockBufferCore>& PerLightParams::getBuffer() const
-	{
-		return mBuffer.getBuffer();
-	}
-	
-	DirectionalLightMat::DirectionalLightMat()
-	{
-		mMaterial->setParamBlockBuffer("PerLight", mParams.getBuffer());
-
-		auto& texParams = mMaterial->getShader()->getTextureParams();
-		for (auto& entry : texParams)
-		{
-			if (entry.second.rendererSemantic == RPS_GBufferA)
-				mGBufferA = mMaterial->getParamTexture(entry.second.name);
-			else if (entry.second.rendererSemantic == RPS_GBufferB)
-				mGBufferB = mMaterial->getParamTexture(entry.second.name);
-			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
-				mGBufferDepth = mMaterial->getParamTexture(entry.second.name);
-		}
-	}
-
-	void DirectionalLightMat::setGBuffer(const SPtr<RenderTargets>& gbuffer)
-	{
-		mGBufferA.set(gbuffer->getTextureA());
-		mGBufferB.set(gbuffer->getTextureB());
-		mGBufferDepth.set(gbuffer->getTextureDepth());
-	}
-
-	void DirectionalLightMat::setParameters(const LightCore* light)
-	{
-		mParams.setParameters(light);
-	}
-
-	PointLightMat::PointLightMat()
-	{
-		mMaterial->setParamBlockBuffer("PerLight", mParams.getBuffer());
-
-		auto& texParams = mMaterial->getShader()->getTextureParams();
-		for (auto& entry : texParams)
-		{
-			if (entry.second.rendererSemantic == RPS_GBufferA)
-				mGBufferA = mMaterial->getParamTexture(entry.second.name);
-			else if (entry.second.rendererSemantic == RPS_GBufferB)
-				mGBufferB = mMaterial->getParamTexture(entry.second.name);
-			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
-				mGBufferDepth = mMaterial->getParamTexture(entry.second.name);
-		}
-	}
-
-	void PointLightMat::setGBuffer(const SPtr<RenderTargets>& gbuffer)
-	{
-		mGBufferA.set(gbuffer->getTextureA());
-		mGBufferB.set(gbuffer->getTextureB());
-		mGBufferDepth.set(gbuffer->getTextureDepth());
-	}
-
-	void PointLightMat::setParameters(const LightCore* light)
-	{
-		mParams.setParameters(light);
-	}
+#include "BsLightRendering.h"
+#include "BsMaterial.h"
+#include "BsShader.h"
+#include "BsRenderBeast.h"
+#include "BsRenderTargets.h"
+#include "BsGpuParams.h"
+#include "BsLight.h"
+
+namespace BansheeEngine
+{
+	void PerLightParams::setParameters(const LightCore* light)
+	{
+		// Note: I could just copy the data directly to the parameter buffer if I ensured the parameter
+		// layout matches
+
+		Vector4 positionAndType = (Vector4)light->getPosition();
+
+		switch (light->getType())
+		{
+		case LightType::Directional:
+			positionAndType.w = 0;
+			break;
+		case LightType::Point:
+			positionAndType.w = 0.3f;
+			break;
+		case LightType::Spot:
+			positionAndType.w = 0.8f;
+			break;
+		}
+
+		mBuffer.gLightPositionAndType.set(positionAndType);
+			
+		Vector4 colorAndIntensity;
+		colorAndIntensity.x = light->getColor().r;
+		colorAndIntensity.y = light->getColor().g;
+		colorAndIntensity.z = light->getColor().b;
+		colorAndIntensity.w = light->getIntensity();
+
+		mBuffer.gLightColorAndIntensity.set(colorAndIntensity);
+
+		Vector2 spotAngles;
+		spotAngles.x = light->getSpotFalloffAngle().valueDegrees();
+		spotAngles.y = light->getSpotAngle().valueDegrees();
+
+		mBuffer.gLightSpotAngles.set(spotAngles);
+
+		mBuffer.gLightDirection.set(light->getRotation().zAxis());
+
+		Vector4 lightGeometry;
+		lightGeometry.x = LightCore::LIGHT_CONE_NUM_SIDES;
+		lightGeometry.y = LightCore::LIGHT_CONE_NUM_SLICES;
+		lightGeometry.z = light->getBounds().getRadius();
+
+		float coneRadius = Math::sin(light->getSpotFalloffAngle()) * light->getRange();
+		lightGeometry.w = coneRadius;
+
+		mBuffer.gLightGeometry.set(lightGeometry);
+
+		Matrix4 transform = Matrix4::TRS(light->getPosition(), light->getRotation(), Vector3::ONE);
+		mBuffer.gMatConeTransform.set(transform);
+	}
+
+	const SPtr<GpuParamBlockBufferCore>& PerLightParams::getBuffer() const
+	{
+		return mBuffer.getBuffer();
+	}
+	
+	DirectionalLightMat::DirectionalLightMat()
+	{
+		mMaterial->setParamBlockBuffer("PerLight", mParams.getBuffer());
+
+		auto& texParams = mMaterial->getShader()->getTextureParams();
+		for (auto& entry : texParams)
+		{
+			if (entry.second.rendererSemantic == RPS_GBufferA)
+				mGBufferA = mMaterial->getParamTexture(entry.second.name);
+			else if (entry.second.rendererSemantic == RPS_GBufferB)
+				mGBufferB = mMaterial->getParamTexture(entry.second.name);
+			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
+				mGBufferDepth = mMaterial->getParamTexture(entry.second.name);
+		}
+	}
+
+	void DirectionalLightMat::setGBuffer(const SPtr<RenderTargets>& gbuffer)
+	{
+		mGBufferA.set(gbuffer->getTextureA());
+		mGBufferB.set(gbuffer->getTextureB());
+		mGBufferDepth.set(gbuffer->getTextureDepth());
+	}
+
+	void DirectionalLightMat::setParameters(const LightCore* light)
+	{
+		mParams.setParameters(light);
+	}
+
+	PointLightMat::PointLightMat()
+	{
+		mMaterial->setParamBlockBuffer("PerLight", mParams.getBuffer());
+
+		auto& texParams = mMaterial->getShader()->getTextureParams();
+		for (auto& entry : texParams)
+		{
+			if (entry.second.rendererSemantic == RPS_GBufferA)
+				mGBufferA = mMaterial->getParamTexture(entry.second.name);
+			else if (entry.second.rendererSemantic == RPS_GBufferB)
+				mGBufferB = mMaterial->getParamTexture(entry.second.name);
+			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
+				mGBufferDepth = mMaterial->getParamTexture(entry.second.name);
+		}
+	}
+
+	void PointLightMat::setGBuffer(const SPtr<RenderTargets>& gbuffer)
+	{
+		mGBufferA.set(gbuffer->getTextureA());
+		mGBufferB.set(gbuffer->getTextureB());
+		mGBufferDepth.set(gbuffer->getTextureDepth());
+	}
+
+	void PointLightMat::setParameters(const LightCore* light)
+	{
+		mParams.setParameters(light);
+	}
 }