Explorar o código

Scene color added to deferred renderer and removed dummy light since we now have an ambient term
Depth buffer is now shared between base and other passes during rendering

BearishSun %!s(int64=10) %!d(string=hai) anos
pai
achega
76cef38e81

+ 1 - 0
BansheeEditor/Source/BsEditorWindowBase.cpp

@@ -70,6 +70,7 @@ namespace BansheeEngine
 		mCamera->setNearClipDistance(5);
 		mCamera->setNearClipDistance(5);
 		mCamera->setAspectRatio(1.0f);
 		mCamera->setAspectRatio(1.0f);
 		mCamera->setLayers(0);
 		mCamera->setLayers(0);
+		mCamera->setFlags(CameraFlags::Overlay);
 
 
 		mGUI = mSceneObject->addComponent<CGUIWidget>(mCamera);
 		mGUI = mSceneObject->addComponent<CGUIWidget>(mCamera);
 		mGUI->setDepth(128);
 		mGUI->setDepth(128);

+ 1 - 1
BansheeEditor/Source/BsScenePicking.cpp

@@ -92,7 +92,7 @@ namespace BansheeEngine
 				continue;
 				continue;
 
 
 			HMesh mesh = renderable->getMesh();
 			HMesh mesh = renderable->getMesh();
-			if (!mesh)
+			if (!mesh.isLoaded())
 				continue;
 				continue;
 
 
 			Bounds worldBounds = mesh->getProperties().getBounds();
 			Bounds worldBounds = mesh->getProperties().getBounds();

+ 2 - 2
BansheeEngine/Include/BsCamera.h

@@ -42,8 +42,8 @@ namespace BansheeEngine
 	enum class CameraFlags
 	enum class CameraFlags
 	{
 	{
 		/** This flag is a signal to the renderer that his camera will only render overlays and doesn't require depth   
 		/** This flag is a signal to the renderer that his camera will only render overlays and doesn't require depth   
-		 * buffer or multi-sampled render targets. */
-		Overlay 
+		 * buffer or multi-sampled render targets. This can improve performance and memory usage. */
+		Overlay = 1
 	};
 	};
 
 
 	/**
 	/**

+ 3 - 0
ExampleProject/Main/Main.cpp

@@ -315,6 +315,9 @@ namespace BansheeEngine
 		// First we want another camera that is responsible for rendering GUI
 		// First we want another camera that is responsible for rendering GUI
 		HCamera guiCamera = guiSO->addComponent<CCamera>(window);
 		HCamera guiCamera = guiSO->addComponent<CCamera>(window);
 
 
+		// Notify the renderer that the camera will only be used for overlays (e.g. GUI) so it can optimize its usage
+		guiCamera->setFlags(CameraFlags::Overlay);
+
 		// Set up GUI camera properties. 
 		// Set up GUI camera properties. 
 		// We don't care about aspect ratio for GUI camera.
 		// We don't care about aspect ratio for GUI camera.
 		guiCamera->setAspectRatio(1.0f);
 		guiCamera->setAspectRatio(1.0f);

+ 1 - 0
MBansheeEditor/ConsoleWindow.cs

@@ -393,6 +393,7 @@ namespace BansheeEditor
                 messageLayout.AddElement(messageLabel);
                 messageLayout.AddElement(messageLabel);
                 messageLayout.AddElement(functionLabel);
                 messageLayout.AddElement(functionLabel);
                 messageLayout.AddSpace(PADDING);
                 messageLayout.AddSpace(PADDING);
+                mainLayout.AddFlexibleSpace();
                 mainLayout.AddSpace(PADDING);
                 mainLayout.AddSpace(PADDING);
 
 
                 background = new GUITexture(Builtin.WhiteTexture, GUIOption.FixedHeight(ENTRY_HEIGHT));
                 background = new GUITexture(Builtin.WhiteTexture, GUIOption.FixedHeight(ENTRY_HEIGHT));

+ 2 - 3
RenderBeast/Include/BsRenderBeast.h

@@ -106,7 +106,7 @@ namespace BansheeEngine
 			RenderQueuePtr opaqueQueue;
 			RenderQueuePtr opaqueQueue;
 			RenderQueuePtr transparentQueue;
 			RenderQueuePtr transparentQueue;
 
 
-			SPtr<RenderTargets> gbuffer;
+			SPtr<RenderTargets> target;
 		};
 		};
 
 
 		/**
 		/**
@@ -228,7 +228,7 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Creates data used by the renderer on the core thread.
 		 * @brief	Creates data used by the renderer on the core thread.
 		 */
 		 */
-		void initializeCore(const SPtr<LightCore>& dummyLight);
+		void initializeCore();
 
 
 		/**
 		/**
 		 * @brief	Destroys data used by the renderer on the core thread.
 		 * @brief	Destroys data used by the renderer on the core thread.
@@ -293,7 +293,6 @@ namespace BansheeEngine
 		Vector<LightData> mDirectionalLights; // Core thread
 		Vector<LightData> mDirectionalLights; // Core thread
 		Vector<LightData> mPointLights; // Core thread
 		Vector<LightData> mPointLights; // Core thread
 		Vector<Sphere> mLightWorldBounds; // Core thread
 		Vector<Sphere> mLightWorldBounds; // Core thread
-		SPtr<LightCore> mDummyDirLight; // Core thread
 
 
 		SPtr<RenderBeastOptions> mCoreOptions; // Core thread
 		SPtr<RenderBeastOptions> mCoreOptions; // Core thread
 
 

+ 12 - 1
RenderBeast/Include/BsRenderTargets.h

@@ -43,7 +43,17 @@ namespace BansheeEngine
 		/**
 		/**
 		 * @brief	Binds the GBuffer render target for rendering.
 		 * @brief	Binds the GBuffer render target for rendering.
 		 */
 		 */
-		void bind();
+		void bindGBuffer();
+
+		/**
+		 * @brief	Binds the scene color render target for rendering.
+		 */
+		void bindSceneColor();
+
+		/**
+		 * @brief	Resolves the GBuffer scene color into the output scene color buffer.
+		 */
+		void resolve();
 
 
 		/**
 		/**
 		 * @brief	Returns the first color texture of the gbuffer as a bindable texture.
 		 * @brief	Returns the first color texture of the gbuffer as a bindable texture.
@@ -91,6 +101,7 @@ namespace BansheeEngine
 		SPtr<PooledRenderTexture> mDepthTex;
 		SPtr<PooledRenderTexture> mDepthTex;
 
 
 		SPtr<MultiRenderTextureCore> mGBufferRT;
 		SPtr<MultiRenderTextureCore> mGBufferRT;
+		SPtr<RenderTextureCore> mSceneColorRT;
 
 
 		PixelFormat mDiffuseFormat;
 		PixelFormat mDiffuseFormat;
 		PixelFormat mNormalFormat;
 		PixelFormat mNormalFormat;

+ 70 - 76
RenderBeast/Source/BsRenderBeast.cpp

@@ -56,9 +56,7 @@ namespace BansheeEngine
 	{
 	{
 		CoreRenderer::initialize();
 		CoreRenderer::initialize();
 
 
-		SPtr<Light> dummyDirLight = Light::create(LightType::Directional);
-
-		CoreThread::instance().queueCommand(std::bind(&RenderBeast::initializeCore, this, dummyDirLight->getCore()));
+		CoreThread::instance().queueCommand(std::bind(&RenderBeast::initializeCore, this));
 	}
 	}
 
 
 	void RenderBeast::destroy()
 	void RenderBeast::destroy()
@@ -69,7 +67,7 @@ namespace BansheeEngine
 		gCoreAccessor().submitToCoreThread(true);
 		gCoreAccessor().submitToCoreThread(true);
 	}
 	}
 
 
-	void RenderBeast::initializeCore(const SPtr<LightCore>& dummyLight)
+	void RenderBeast::initializeCore()
 	{
 	{
 		RendererUtility::startUp();
 		RendererUtility::startUp();
 
 
@@ -80,8 +78,6 @@ namespace BansheeEngine
 		mPointLightMat = bs_new<PointLightMat>();
 		mPointLightMat = bs_new<PointLightMat>();
 		mDirLightMat = bs_new<DirectionalLightMat>();
 		mDirLightMat = bs_new<DirectionalLightMat>();
 
 
-		mDummyDirLight = dummyLight;
-
 		RenderTexturePool::startUp();
 		RenderTexturePool::startUp();
 	}
 	}
 
 
@@ -93,7 +89,6 @@ namespace BansheeEngine
 		mRenderTargets.clear();
 		mRenderTargets.clear();
 		mCameraData.clear();
 		mCameraData.clear();
 		mRenderables.clear();
 		mRenderables.clear();
-		mDummyDirLight = nullptr;
 
 
 		RenderTexturePool::shutDown();
 		RenderTexturePool::shutDown();
 
 
@@ -264,11 +259,7 @@ namespace BansheeEngine
 	{
 	{
 		if (light->getType() == LightType::Directional)
 		if (light->getType() == LightType::Directional)
 		{
 		{
-			if (mDummyDirLight != nullptr && mDummyDirLight.get() != light)
-				mDummyDirLight->setIsActive(false);
-
 			UINT32 lightId = (UINT32)mDirectionalLights.size();
 			UINT32 lightId = (UINT32)mDirectionalLights.size();
-
 			light->setRendererId(lightId);
 			light->setRendererId(lightId);
 
 
 			mDirectionalLights.push_back(LightData());
 			mDirectionalLights.push_back(LightData());
@@ -334,10 +325,6 @@ namespace BansheeEngine
 			mPointLights.erase(mPointLights.end() - 1);
 			mPointLights.erase(mPointLights.end() - 1);
 			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
 			mLightWorldBounds.erase(mLightWorldBounds.end() - 1);
 		}
 		}
-
-		UINT32 numDirLights = (UINT32)mDirectionalLights.size();
-		if (numDirLights == 0 && mDummyDirLight != nullptr) // Enable dummy light because otherwise nothing will get rendered in unlit areas
-			mDummyDirLight->setIsActive(true);
 	}
 	}
 
 
 	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
 	void RenderBeast::_notifyCameraAdded(const CameraCore* camera)
@@ -516,19 +503,37 @@ namespace BansheeEngine
 
 
 		if (hasGBuffer)
 		if (hasGBuffer)
 		{
 		{
-			bool createGBuffer = camData.gbuffer == nullptr ||
-				camData.gbuffer->getHDR() != mCoreOptions->hdr ||
-				camData.gbuffer->getNumSamples() != mCoreOptions->msaa;
+			bool createGBuffer = camData.target == nullptr ||
+				camData.target->getHDR() != mCoreOptions->hdr ||
+				camData.target->getNumSamples() != mCoreOptions->msaa;
 
 
 			if (createGBuffer)
 			if (createGBuffer)
-				camData.gbuffer = RenderTargets::create(viewport, mCoreOptions->hdr, mCoreOptions->msaa);
+				camData.target = RenderTargets::create(viewport, mCoreOptions->hdr, mCoreOptions->msaa);
 
 
-			camData.gbuffer->allocate();
-			camData.gbuffer->bind();
+			camData.target->allocate();
+			camData.target->bindGBuffer();
+		}
+		else
+			camData.target = nullptr;
+
+		// Trigger pre-scene callbacks
+		auto iterCameraCallbacks = mRenderCallbacks.find(camera);
+		if (iterCameraCallbacks != mRenderCallbacks.end())
+		{
+			for (auto& callbackPair : iterCameraCallbacks->second)
+			{
+				const RenderCallbackData& callbackData = callbackPair.second;
 
 
-			UINT32 clearBuffers = FBT_COLOR | FBT_DEPTH | FBT_STENCIL;
-			RenderAPICore::instance().clearViewport(clearBuffers, Color::ZERO, 1.0f, 0);
+				if (callbackData.overlay || callbackPair.first >= 0)
+					break;
 
 
+				callbackData.callback();
+			}
+		}
+		
+		if (hasGBuffer)
+		{
+			// Render base pass
 			const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
 			const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
 			for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 			for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 			{
 			{
@@ -558,61 +563,14 @@ namespace BansheeEngine
 				gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 				gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 			}
 			}
 
 
-			camData.gbuffer->release();
-		}
-		else
-			camData.gbuffer = nullptr;
-
-		// Prepare final render target
-		SPtr<RenderTargetCore> target = rtData.target;
-
-		RenderAPICore::instance().setRenderTarget(target);
-		RenderAPICore::instance().setViewport(viewport->getNormArea());
-
-		// If first camera in render target, prepare the render target
-		if (camIdx == 0)
-		{
-			UINT32 clearBuffers = 0;
-			if (viewport->getRequiresColorClear())
-				clearBuffers |= FBT_COLOR;
-
-			if (viewport->getRequiresDepthClear())
-				clearBuffers |= FBT_DEPTH;
-
-			if (viewport->getRequiresStencilClear())
-				clearBuffers |= FBT_STENCIL;
-
-			if (clearBuffers != 0)
-				RenderAPICore::instance().clearViewport(clearBuffers, viewport->getClearColor(), viewport->getClearDepthValue(), viewport->getClearStencilValue());
-		}
-
-		// Trigger pre-scene callbacks
-		auto iterCameraCallbacks = mRenderCallbacks.find(camera);
-		if (iterCameraCallbacks != mRenderCallbacks.end())
-		{
-			for (auto& callbackPair : iterCameraCallbacks->second)
-			{
-				const RenderCallbackData& callbackData = callbackPair.second;
-
-				if (callbackData.overlay || callbackPair.first >= 0)
-					break;
-
-				callbackData.callback();
-			}
-		}
-
-		// Render lights and resolve gbuffer if there is one
-		if (hasGBuffer)
-		{
-			// TODO - Need to handle a case when GBuffer has MSAA but scene target has not
-
-			UINT32 numLights = (UINT32)(mDirectionalLights.size() + mPointLights.size());
+			camData.target->bindSceneColor();
 
 
+			// Render light pass
 			SPtr<MaterialCore> dirMaterial = mDirLightMat->getMaterial();
 			SPtr<MaterialCore> dirMaterial = mDirLightMat->getMaterial();
 			SPtr<PassCore> dirPass = dirMaterial->getPass(0);
 			SPtr<PassCore> dirPass = dirMaterial->getPass(0);
 
 
 			setPass(dirPass);
 			setPass(dirPass);
-			mDirLightMat->setGBuffer(camData.gbuffer);
+			mDirLightMat->setGBuffer(camData.target);
 
 
 			for (auto& light : mDirectionalLights)
 			for (auto& light : mDirectionalLights)
 			{
 			{
@@ -630,7 +588,7 @@ namespace BansheeEngine
 			SPtr<PassCore> pointPass = pointMaterial->getPass(0);
 			SPtr<PassCore> pointPass = pointMaterial->getPass(0);
 
 
 			setPass(pointPass);
 			setPass(pointPass);
-			mPointLightMat->setGBuffer(camData.gbuffer);
+			mPointLightMat->setGBuffer(camData.target);
 
 
 			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
 			// TODO - Cull lights based on visibility, right now I just iterate over all of them. 
 			for (auto& light : mPointLights)
 			for (auto& light : mPointLights)
@@ -645,8 +603,6 @@ namespace BansheeEngine
 				SPtr<MeshCore> mesh = light.internal->getMesh();
 				SPtr<MeshCore> mesh = light.internal->getMesh();
 				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
 				gRendererUtility().draw(mesh, mesh->getProperties().getSubMesh(0));
 			}
 			}
-
-			// TODO - Resolve to render target if it was MSAA (Later: Manual resolve during deferred light pass?)
 		}
 		}
 
 
 		// Render transparent objects (TODO - No lighting yet)
 		// Render transparent objects (TODO - No lighting yet)
@@ -696,6 +652,41 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
+		if (hasGBuffer)
+		{
+			// TODO - Instead of doing a separate resolve here I could potentially perform a resolve directly in the
+			// light pass.
+			camData.target->resolve();
+		}
+		else
+		{
+			// Prepare final render target
+			SPtr<RenderTargetCore> target = rtData.target;
+
+			RenderAPICore::instance().setRenderTarget(target);
+			RenderAPICore::instance().setViewport(viewport->getNormArea());
+
+			// If first camera in render target, prepare the render target
+			if (camIdx == 0)
+			{
+				UINT32 clearBuffers = 0;
+				if (viewport->getRequiresColorClear())
+					clearBuffers |= FBT_COLOR;
+
+				if (viewport->getRequiresDepthClear())
+					clearBuffers |= FBT_DEPTH;
+
+				if (viewport->getRequiresStencilClear())
+					clearBuffers |= FBT_STENCIL;
+
+				if (clearBuffers != 0)
+				{
+					RenderAPICore::instance().clearViewport(clearBuffers, viewport->getClearColor(),
+						viewport->getClearDepthValue(), viewport->getClearStencilValue());
+				}
+			}
+		}
+
 		// Render overlay post-scene callbacks
 		// Render overlay post-scene callbacks
 		if (iterCameraCallbacks != mRenderCallbacks.end())
 		if (iterCameraCallbacks != mRenderCallbacks.end())
 		{
 		{
@@ -710,6 +701,9 @@ namespace BansheeEngine
 			}
 			}
 		}
 		}
 
 
+		if (hasGBuffer)
+			camData.target->release();
+
 		gProfilerCPU().endSample("Render");
 		gProfilerCPU().endSample("Render");
 	}
 	}
 	
 	

+ 63 - 2
RenderBeast/Source/BsRenderTargets.cpp

@@ -55,7 +55,7 @@ namespace BansheeEngine
 		mNormalTex = newNormalRT;
 		mNormalTex = newNormalRT;
 		mDepthTex = newDepthRT;
 		mDepthTex = newDepthRT;
 
 
-		if (mGBufferRT == nullptr || rebuildTargets)
+		if (mGBufferRT == nullptr || mSceneColorRT == nullptr || rebuildTargets)
 		{
 		{
 			MULTI_RENDER_TEXTURE_CORE_DESC gbufferDesc;
 			MULTI_RENDER_TEXTURE_CORE_DESC gbufferDesc;
 			gbufferDesc.colorSurfaces.resize(3);
 			gbufferDesc.colorSurfaces.resize(3);
@@ -87,6 +87,17 @@ namespace BansheeEngine
 			gbufferDesc.depthStencilSurface.mipLevel = 0;
 			gbufferDesc.depthStencilSurface.mipLevel = 0;
 
 
 			mGBufferRT = TextureCoreManager::instance().createMultiRenderTexture(gbufferDesc);
 			mGBufferRT = TextureCoreManager::instance().createMultiRenderTexture(gbufferDesc);
+
+			RENDER_TEXTURE_CORE_DESC sceneColorDesc;
+			sceneColorDesc.colorSurface.texture = sceneColorTex;
+			sceneColorDesc.colorSurface.face = 0;
+			sceneColorDesc.colorSurface.mipLevel = 0;
+
+			sceneColorDesc.depthStencilSurface.texture = mDepthTex->texture;
+			sceneColorDesc.depthStencilSurface.face = 0;
+			sceneColorDesc.depthStencilSurface.mipLevel = 0;
+
+			mSceneColorRT = TextureCoreManager::instance().createRenderTexture(sceneColorDesc);
 		}
 		}
 	}
 	}
 
 
@@ -97,18 +108,68 @@ namespace BansheeEngine
 
 
 		RenderTexturePool& texPool = RenderTexturePool::instance();
 		RenderTexturePool& texPool = RenderTexturePool::instance();
 
 
+		if (mSceneColorTex != nullptr)
+			texPool.release(mSceneColorTex);
+
 		texPool.release(mAlbedoTex);
 		texPool.release(mAlbedoTex);
 		texPool.release(mNormalTex);
 		texPool.release(mNormalTex);
 		texPool.release(mDepthTex);
 		texPool.release(mDepthTex);
 	}
 	}
 
 
-	void RenderTargets::bind()
+	void RenderTargets::bindGBuffer()
 	{
 	{
 		RenderAPICore& rapi = RenderAPICore::instance();
 		RenderAPICore& rapi = RenderAPICore::instance();
 		rapi.setRenderTarget(mGBufferRT);
 		rapi.setRenderTarget(mGBufferRT);
 
 
 		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
 		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
 		rapi.setViewport(area);
 		rapi.setViewport(area);
+
+		UINT32 clearBuffers = FBT_COLOR | FBT_DEPTH | FBT_STENCIL;
+		RenderAPICore::instance().clearViewport(clearBuffers, Color::ZERO, 1.0f, 0);
+	}
+
+	void RenderTargets::bindSceneColor()
+	{
+		RenderAPICore& rapi = RenderAPICore::instance();
+		rapi.setRenderTarget(mSceneColorRT);
+
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
+	}
+
+	void RenderTargets::resolve()
+	{
+		// Prepare final render target
+		SPtr<RenderTargetCore> target = mViewport->getTarget();
+
+		RenderAPICore::instance().setRenderTarget(target);
+		RenderAPICore::instance().setViewport(mViewport->getNormArea());
+
+		// If using a separate scene color texture clear the final render target
+		if (mSceneColorTex == nullptr)
+		{
+			// Do nothing as final render target is already our scene color target
+		}
+		else
+		{
+			UINT32 clearBuffers = 0;
+			if (mViewport->getRequiresColorClear())
+				clearBuffers |= FBT_COLOR;
+
+			if (mViewport->getRequiresDepthClear())
+				clearBuffers |= FBT_DEPTH;
+
+			if (mViewport->getRequiresStencilClear())
+				clearBuffers |= FBT_STENCIL;
+
+			if (clearBuffers != 0)
+			{
+				RenderAPICore::instance().clearViewport(clearBuffers, mViewport->getClearColor(),
+					mViewport->getClearDepthValue(), mViewport->getClearStencilValue());
+			}
+
+			// TODO - Copy from internal scene color to final scene color
+		}
 	}
 	}
 
 
 	SPtr<TextureCore> RenderTargets::getTextureA() const
 	SPtr<TextureCore> RenderTargets::getTextureA() const

+ 5 - 7
TODOExperimentation.txt

@@ -14,15 +14,13 @@ Assign ViewOrigin, PreViewTranslation, TransViewProj
  - Do this after I have basic rendering working, to avoid additional issues when I'm initially trying to get it to work
  - Do this after I have basic rendering working, to avoid additional issues when I'm initially trying to get it to work
  
  
 Later:
 Later:
- - Output skylight color in base pass (hook up color buffer as well as gbuffer as render target so I can output scene color)
-  - For now just use a constant color, later add a SH environment map lookup
+ - Resolving scene color to final scene color in RenderTargets::resolve is not implemented
+  - Need to be able to copy portions of an MSAA texture to a non-MSAA texture 
+ - Add warnings for depth buffers or MSAA on output target
+ - Remove depth buffers from Scene and Game window RT's, as well as the primary window  
  - I changed how unsupported texture formats work, I should test if I didn't break OpenGL
  - I changed how unsupported texture formats work, I should test if I didn't break OpenGL
  - When rendering lights right now I need to bind Gbuffer and light parameters to material, and then bind the material parameters to the pipeline
  - When rendering lights right now I need to bind Gbuffer and light parameters to material, and then bind the material parameters to the pipeline
   - Either unify these two processes by finding a better way, or hide the binding in light material class
   - Either unify these two processes by finding a better way, or hide the binding in light material class
- - Too many depth buffers. Main render surface has one, game viewport has one and gbuffer has one
-  - Disable main depth buffer by default, disable depth buffer in SceneWindow and GameWindow RT's
-  - When rendering to scene target use the gbuffers depth buffer (what if their sizes don't match due to quantization?)
-  - Although having an extra depth buffer won't be the worst thing as even at full HD it's only 8MB
  - Finish up DefferedPointLightPass by generating cone geometry in shader
  - Finish up DefferedPointLightPass by generating cone geometry in shader
  - Modify Light so it generated adequate number of vertices required for cone geometry, without actually creating the cone
  - 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)
  - Think about how to handle post-processing shaders (HDR tone mapping)
@@ -38,7 +36,7 @@ Notes:
    this as later it will be hard to debug when the pipeline is more complex.
    this as later it will be hard to debug when the pipeline is more complex.
  - Consider having a debug toggle that makes the gbuffer use floating point storage, to compare quality quickly
  - Consider having a debug toggle that makes the gbuffer use floating point storage, to compare quality quickly
  - I'll need to add sky-lighting and perhaps other form of pre-computed lighting. Base pass should output colors resulting
  - I'll need to add sky-lighting and perhaps other form of pre-computed lighting. Base pass should output colors resulting
-   from those operations during its base pass.
+   from those operations during its base pass. Right now I just output constant ambient.
  - Don't forget to make everything gamma correct
  - Don't forget to make everything gamma correct
 
 
 Generate different RenderableController for each set of elements
 Generate different RenderableController for each set of elements