Просмотр исходного кода

Setting up light rendering parameters (WIP)

BearishSun 10 лет назад
Родитель
Сommit
8ebe56831a

+ 2 - 2
BansheeD3D11RenderAPI/Include/BsD3D11GpuProgram.h

@@ -16,7 +16,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	GpuProgramCore::hasColumnMajorMatrices
 		 */
-		bool hasColumnMajorMatrices() const { return mColumnMajorMatrices; }
+		bool hasColumnMajorMatrices() const override { return mColumnMajorMatrices; }
 
 		/**
 		 * @brief	Returns compiled shader microcode.
@@ -43,7 +43,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GpuProgramCore::initialize
 		 */
-		void initialize();
+		void initialize() override;
 
 		/**
 		 * @brief	Loads the shader from microcode.

+ 1 - 1
BansheeEditorExec/BsEditorExec.cpp

@@ -72,7 +72,7 @@ int CALLBACK WinMain(
 
 	__try
 	{
-		EditorApplication::startUp(RenderAPIPlugin::DX11);
+		EditorApplication::startUp(RenderAPIPlugin::OpenGL);
 		EditorApplication::instance().runMainLoop();
 		EditorApplication::shutDown();
 	}

+ 9 - 4
BansheeEngine/Include/BsRendererMaterial.h

@@ -2,7 +2,7 @@
 
 #include "BsPrerequisites.h"
 
-#define RMAT_DEF(path) virtual Path getShaderPath() override const { return path; }
+#define RMAT_DEF(path) virtual Path getShaderPath() const override { return path; }
 
 namespace BansheeEngine
 {
@@ -21,6 +21,11 @@ namespace BansheeEngine
 		 */
 		virtual Path getShaderPath() const { return Path::BLANK; }
 
+		/**
+		 * @brief	Returns the internal material.
+		 */
+		SPtr<MaterialCore> getMaterial() const { return mMaterial; }
+
 	private:
 		/**
 		 * @brief	Initializes the internal material. Should be called by the renderer material manager before
@@ -34,7 +39,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Allows derived classes to initialize their data.
 		 */
-		virtual void initialize() = 0;
+		virtual void initialize() { }
 
 		SPtr<MaterialCore> mMaterial;
 	};
@@ -44,7 +49,7 @@ namespace BansheeEngine
 	 * 			and set up materials used by the renderer.
 	 */
 	template<class T>
-	class BS_EXPORT RendererMaterial
+	class RendererMaterial : public RendererMaterialBase
 	{
 	private:
 		/**
@@ -64,10 +69,10 @@ namespace BansheeEngine
 	public:
 		virtual ~RendererMaterial() { }
 
+		static T* instance;
 	private:
 		friend class RendererMaterialManager;
 
-		static T* instance;
 		volatile InitOnStart mInit;
 	};
 

+ 45 - 0
RenderBeast/Include/BsLightRendering.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+#include "BsRendererMaterial.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * Shader that renders directional light sources during deferred rendering light pass. 
+	 */
+	class DirectionalLightMat : public RendererMaterial<DirectionalLightMat>
+	{
+		RMAT_DEF("DeferredDirectionalLightPass.bsl");
+
+	public:
+		/**
+		 * Updates the parameter buffers used by the material.
+		 */
+		void setParameters(const LightCore* light);
+	private:
+		/**
+		 * @copydoc RendererMaterial::initialize
+		 */
+		void initialize() override;
+	};
+
+	/**
+	 * Shader that renders point (radial & spot) light sources during deferred rendering light pass. 
+	 */
+	class PointLightMat : public RendererMaterial<PointLightMat>
+	{
+		RMAT_DEF("DeferredPointLightPass.bsl");
+
+	public:
+		/**
+		 * Updates the parameter buffers used by the material.
+		 */
+		void setParameters(const LightCore* light);
+	private:
+		/**
+		 * @copydoc RendererMaterial::initialize
+		 */
+		void initialize() override;
+	};
+}

+ 2 - 1
RenderBeast/Include/BsRenderBeast.h

@@ -276,7 +276,8 @@ namespace BansheeEngine
 		Vector<RenderableShaderData> mRenderableShaderData; // Core thread
 		Vector<Bounds> mWorldBounds; // Core thread
 
-		Vector<LightData> mLights; // Core thread
+		Vector<LightData> mDirectionalLights; // Core thread
+		Vector<LightData> mPointLights; // Core thread
 		Vector<Sphere> mLightWorldBounds; // Core thread
 
 		SPtr<RenderBeastOptions> mCoreOptions; // Core thread

+ 2 - 0
RenderBeast/RenderBeast.vcxproj

@@ -257,6 +257,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="Include\BsLightRendering.h" />
     <ClInclude Include="Include\BsStaticRenderableHandler.h" />
     <ClInclude Include="Include\BsRenderBeast.h" />
     <ClInclude Include="Include\BsRenderBeastFactory.h" />
@@ -267,6 +268,7 @@
     <ClInclude Include="Include\BsSamplerOverrides.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClCompile Include="Source\BsLightRendering.cpp" />
     <ClCompile Include="Source\BsStaticRenderableHandler.cpp" />
     <ClCompile Include="Source\BsRenderBeast.cpp" />
     <ClCompile Include="Source\BsRenderBeastFactory.cpp" />

+ 6 - 0
RenderBeast/RenderBeast.vcxproj.filters

@@ -39,6 +39,9 @@
     <ClInclude Include="Include\BsStaticRenderableHandler.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsLightRendering.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsRenderTexturePool.cpp">
@@ -62,5 +65,8 @@
     <ClCompile Include="Source\BsStaticRenderableHandler.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsLightRendering.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 115 - 0
RenderBeast/Source/BsLightRendering.cpp

@@ -0,0 +1,115 @@
+#include "BsLightRendering.h"
+#include "BsMaterial.h"
+#include "BsGpuParams.h"
+#include "BsLight.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * Manipulates PerLight parameter buffer used in various shaders.
+	 */
+	class PerLightParamBuffer
+	{
+	public:
+		// TODO - Doc
+		void initialize()
+		{
+			// TODO - This is never called
+			// TODO - Create the buffer (think of an automated way of doing it, creating the desc and retrieving the params.
+			
+			mParams->getParam("gLightPositionAndType", mParamLightPositionAndType);
+			mParams->getParam("gLightColorAndIntensity", mParamLightColorAndIntensity);
+			mParams->getParam("gLightSpotAngles", mParamLightSpotAngles);
+			mParams->getParam("gLightDirection", mParamLightDirection);
+			mParams->getParam("gLightGeometry", mParamLightGeometry);
+		}
+
+		// TODO - Doc
+		void 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;
+			}
+
+			mParamLightPositionAndType.set(positionAndType);
+			
+			Vector4 colorAndIntensity;
+			colorAndIntensity.x = light->getColor().r;
+			colorAndIntensity.y = light->getColor().g;
+			colorAndIntensity.z = light->getColor().b;
+			colorAndIntensity.w = light->getIntensity();
+
+			mParamLightColorAndIntensity.set(colorAndIntensity);
+
+			Vector2 spotAngles;
+			spotAngles.x = light->getSpotFalloffAngle().valueDegrees();
+			spotAngles.y = light->getSpotAngle().valueDegrees();
+
+			mParamLightSpotAngles.set(spotAngles);
+
+			mParamLightDirection.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();
+
+			mParamLightGeometry.set(lightGeometry);
+		}
+
+		// TODO - Doc
+		SPtr<GpuParamBlockBufferCore> getBuffer()
+		{
+			return mParams->getParamBlockBuffer(0);
+		}
+
+		static PerLightParamBuffer instance;
+
+	private:
+		SPtr<GpuParamsCore> mParams;
+
+		GpuParamVec4Core mParamLightPositionAndType;
+		GpuParamVec4Core mParamLightColorAndIntensity;
+		GpuParamVec2Core mParamLightSpotAngles;
+		GpuParamVec3Core mParamLightDirection;
+		GpuParamVec4Core mParamLightGeometry;
+	};
+
+	PerLightParamBuffer PerLightParamBuffer::instance;
+
+	void DirectionalLightMat::setParameters(const LightCore* light)
+	{
+		PerLightParamBuffer::instance.setParameters(light);
+	}
+
+	void DirectionalLightMat::initialize()
+	{
+		mMaterial->setParamBlockBuffer("PerLight", PerLightParamBuffer::instance.getBuffer());
+	}
+
+	void PointLightMat::setParameters(const LightCore* light)
+	{
+		PerLightParamBuffer::instance.setParameters(light);
+	}
+
+	void PointLightMat::initialize()
+	{
+		mMaterial->setParamBlockBuffer("PerLight", PerLightParamBuffer::instance.getBuffer());
+	}
+}

+ 84 - 23
RenderBeast/Source/BsRenderBeast.cpp

@@ -33,6 +33,7 @@
 #include "BsLight.h"
 #include "BsRenderTexturePool.h"
 #include "BsRenderTargets.h"
+#include "BsLightRendering.h"
 
 using namespace std::placeholders;
 
@@ -217,42 +218,75 @@ namespace BansheeEngine
 
 	void RenderBeast::_notifyLightAdded(LightCore* light)
 	{
-		UINT32 lightId = (UINT32)mLights.size();
+		if (light->getType() == LightType::Directional)
+		{
+			UINT32 lightId = (UINT32)mDirectionalLights.size();
+
+			light->setRendererId(lightId);
 
-		light->setRendererId(lightId);
+			mDirectionalLights.push_back(LightData());
 
-		mLights.push_back(LightData());
-		mLightWorldBounds.push_back(light->getBounds());
+			LightData& lightData = mDirectionalLights.back();
+			lightData.internal = light;
+		}
+		else
+		{
+			UINT32 lightId = (UINT32)mPointLights.size();
 
-		LightData& lightData = mLights.back();
-		lightData.internal = light;
+			light->setRendererId(lightId);
+
+			mPointLights.push_back(LightData());
+			mLightWorldBounds.push_back(light->getBounds());
+
+			LightData& lightData = mPointLights.back();
+			lightData.internal = light;
+		}
 	}
 
 	void RenderBeast::_notifyLightUpdated(LightCore* light)
 	{
 		UINT32 lightId = light->getRendererId();
 
-		mLightWorldBounds[lightId] = light->getBounds();
+		if (light->getType() != LightType::Directional)
+			mLightWorldBounds[lightId] = light->getBounds();
 	}
 
 	void RenderBeast::_notifyLightRemoved(LightCore* light)
 	{
 		UINT32 lightId = light->getRendererId();
-		LightCore* lastLight = mLights.back().internal;
-		UINT32 lastLightId = lastLight->getRendererId();
-
-		if (lightId != lastLightId)
+		if (light->getType() == LightType::Directional)
 		{
-			// Swap current last element with the one we want to erase
-			std::swap(mLights[lightId], mLights[lastLightId]);
-			std::swap(mLightWorldBounds[lightId], mLightWorldBounds[lastLightId]);
+			LightCore* lastLight = mDirectionalLights.back().internal;
+			UINT32 lastLightId = lastLight->getRendererId();
 
-			lastLight->setRendererId(lightId);
+			if (lightId != lastLightId)
+			{
+				// Swap current last element with the one we want to erase
+				std::swap(mDirectionalLights[lightId], mDirectionalLights[lastLightId]);
+				lastLight->setRendererId(lightId);
+			}
+
+			// Last element is the one we want to erase
+			mDirectionalLights.erase(mDirectionalLights.end() - 1);
 		}
+		else
+		{
+			LightCore* lastLight = mPointLights.back().internal;
+			UINT32 lastLightId = lastLight->getRendererId();
 
-		// Last element is the one we want to erase
-		mLights.erase(mLights.end() - 1);
-		mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
+			if (lightId != lastLightId)
+			{
+				// Swap current last element with the one we want to erase
+				std::swap(mPointLights[lightId], mPointLights[lastLightId]);
+				std::swap(mLightWorldBounds[lightId], mLightWorldBounds[lastLightId]);
+
+				lastLight->setRendererId(lightId);
+			}
+
+			// Last element is the one we want to erase
+			mPointLights.erase(mPointLights.end() - 1);
+			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
+		}
 	}
 
 	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
@@ -447,7 +481,7 @@ namespace BansheeEngine
 
 		mStaticHandler->updatePerCameraBuffers(viewProjMatrix, viewMatrix, projMatrix, camera->getForward());
 
-		// Render scene object to g-buffer if there are any
+		// Render scene objects to g-buffer if there are any
 		const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
 		bool hasGBuffer = opaqueElements.size() > 0;
 
@@ -542,16 +576,43 @@ namespace BansheeEngine
 			}
 		}
 
-		// Resolve gbuffer if there is one
+		// Render lights and resolve gbuffer if there is one
 		if (hasGBuffer)
 		{
-			// TODO - Render lights
-			// TODO - Resolve to render target
+			SPtr<MaterialCore> dirMaterial = DirectionalLightMat::instance->getMaterial();
+			SPtr<PassCore> dirPass = dirMaterial->getPass(0);
+
+			setPass(dirPass);
+
+			for (auto& light : mDirectionalLights)
+			{
+				if (!light.internal->getIsActive())
+					continue;
+
+				DirectionalLightMat::instance->setParameters(light.internal);
+
+				SPtr<MeshCore> mesh = nullptr; // TODO - Get full screen quad
+				draw(mesh, mesh->getProperties().getSubMesh(0));
+			}
+
+			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
+			for (auto& light : mPointLights)
+			{
+				if (!light.internal->getIsActive())
+					continue;
+
+				PointLightMat::instance->setParameters(light.internal);
+
+				SPtr<MeshCore> mesh = light.internal->getMesh();
+				draw(mesh, mesh->getProperties().getSubMesh(0));
+			}
+
+			// TODO - Resolve to render target (Later: Manual resolve during deferred light pass?)
 			
 			camData.gbuffer->unbind();
 		}
 
-		// Render transparent objects
+		// Render transparent objects (TODO - No lighting yet)
 		const Vector<RenderQueueElement>& transparentElements = camData.transparentQueue->getSortedElements();
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		{

+ 10 - 4
TODOExperimentation.txt

@@ -6,22 +6,28 @@ Determine how is light bleeding handled (if at all)
 
 ---------------------- IMPLEMENTATION ---------------------------
 
-When I update SceneObject transforms I must concatenate child/parent transforms by using position/rotation/scale separately,
-then assemble the world matrix from them. This ensures I can easily remove scaling factor from the matrix when needed,
-which is needed for transforming tangents in the shader. Currently Renderable::getTransformNoScale is not implemented.
-
 Assign ViewOrigin, PreViewTranslation, TransViewProj
  - Dont use pre-view translation for ortographic
  - Modify view and view projecion matrices so othey use translated 
  - Apply PreViewTranslation when generating world position in shader (multiply 3x3 rotation col by col, then add translation to last col and add that to rotated position)
  - Perhaps do all these modifcations outside of shader (i.e. have the world matrix be pre-transformed)
+ - Do this after I have basic rendering working, to avoid additional issues when I'm initially trying to get it to work
+
+Need an easy way to construct parameter buffers in C++
+ - PerFrame, PerCamera, PerObject, etc.
+ - Currently I need to create a dummy shader just to extract those buffers
+ - It would be better if I could manually specify the buffer in C++ and get its parameters
+  - In OpenGL it means I would probably need to use std140 or std430 layouts and modify my parsing code so it uses GL_UNIFORM_BLOCK_DATA_SIZE for retrieving block size
 
 Next week:
+ - Deferred base and light passes use different PerCamera buffers, unify them (both in shader and in code)
+ - Need to generate a full screen quad for directional light pass
  - Finish up DefferedPointLightPass by generating cone geometry in shader
  - Generate C++ code for populating cbuffers for deferred shaders (2+ days)
  - Modify Light so it generated adequate number of vertices required for cone geometry, without actually creating the cone
  - Think about how to handle post-processing shaders (HDR tone mapping)
  - Add cube and 3D support for render texture pool
+ - Lights aren't being culled
  - Load up and set up a test-bed with Ribek's scene
 
 Notes: