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

Adding scene color to deferred renderer, and sharing gbuffer depth for forward rendering (WIP part 1)

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

+ 10 - 1
BansheeEngine/Source/BsRenderable.cpp

@@ -12,6 +12,15 @@
 
 namespace BansheeEngine
 {
+	template<class T>
+	bool isMeshValid(const T& mesh) { return false; }
+
+	template<>
+	bool isMeshValid(const HMesh& mesh) { return mesh.isLoaded(); }
+
+	template<>
+	bool isMeshValid(const SPtr<MeshCore>& mesh) { return mesh != nullptr; }
+
 	template<bool Core>
 	TRenderable<Core>::TRenderable()
 		:mLayer(1), mTransform(Matrix4::IDENTITY), mTransformNoScale(Matrix4::IDENTITY), mIsActive(true)
@@ -31,7 +40,7 @@ namespace BansheeEngine
 		mMesh = mesh;
 
 		int numSubMeshes = 0;
-		if (mesh != nullptr)
+		if (isMeshValid(mesh))
 			numSubMeshes = mesh->getProperties().getNumSubMeshes();
 
 		mMaterials.resize(numSubMeshes);

+ 33 - 16
RenderBeast/Include/BsRenderTargets.h

@@ -19,25 +19,31 @@ namespace BansheeEngine
 		 *			the internal render targets - this happens the first time you call ::bind.
 		 *
 		 * @param	viewport		Viewport that the render targets will be used for. Determines size of the
-		 *							render targets.
+		 *							render targets, and the output color render target.
 		 * @param	hdr				Should the render targets support high dynamic range rendering.
 		 * @param	numSamples		Number of samples to use if multisampling is active. Provide 0 or 1 if
 		 *							multisampled targets are not needed.
 		 */
-		static SPtr<RenderTargets> create(const ViewportCore& viewport, bool hdr, UINT32 numSamples);
+		static SPtr<RenderTargets> create(const SPtr<ViewportCore>& viewport, bool hdr, UINT32 numSamples);
 
 		/**
-		 * @brief	Binds the render targets for rendering. This will also allocate the render
-		 *			targets if they aren't already allocated.
+		 * @brief	Allocates the textures required for rendering. Allocations are pooled so this is generally a fast 
+		 * 			operation unless the size or other render target options changed. This must be called before binding
+		 * 			render targets.
 		 */
-		void bind();
+		void allocate();
+
+		/**
+		 * @brief	Deallocates textures by returning them to the pool. This should be done when the caller is done using 
+		 * 			the render targets, so that other systems might re-use them. This will not release any memory unless
+		 * 			all render targets pointing to those textures go out of scope.
+		 */
+		void release();
 
 		/**
-		 * @brief	Frees the render targets so they may be used by another set of render targets. This
-		 *			will not release the render target memory. Memory will only released once all
-		 *			RenderTarget instances pointing to the render target go out of scope.
+		 * @brief	Binds the GBuffer render target for rendering.
 		 */
-		void unbind();
+		void bind();
 
 		/**
 		 * @brief	Returns the first color texture of the gbuffer as a bindable texture.
@@ -65,16 +71,27 @@ namespace BansheeEngine
 		UINT32 getNumSamples() const { return mNumSamples; }
 
 	private:
-		RenderTargets(const ViewportCore& viewport, bool hdr, UINT32 numSamples);
+		RenderTargets(const SPtr<ViewportCore>& viewport, bool hdr, UINT32 numSamples);
+
+		/**
+		 * @brief	Returns the width of gbuffer textures, in pixels.
+		 */
+		UINT32 getWidth() const;
+
+		/**
+		 * @brief	Returns the height of gbuffer textures, in pixels.
+		 */
+		UINT32 getHeight() const;
+
+		SPtr<ViewportCore> mViewport;
 
-		SPtr<PooledRenderTexture> mDiffuseRT;
-		SPtr<PooledRenderTexture> mNormalRT;
-		SPtr<PooledRenderTexture> mDepthRT;
+		SPtr<PooledRenderTexture> mSceneColorTex;
+		SPtr<PooledRenderTexture> mAlbedoTex;
+		SPtr<PooledRenderTexture> mNormalTex;
+		SPtr<PooledRenderTexture> mDepthTex;
 
-		SPtr<MultiRenderTextureCore> mGBuffer;
+		SPtr<MultiRenderTextureCore> mGBufferRT;
 
-		UINT32 mWidth;
-		UINT32 mHeight;
 		PixelFormat mDiffuseFormat;
 		PixelFormat mNormalFormat;
 		UINT32 mNumSamples;

+ 3 - 2
RenderBeast/Source/BsRenderBeast.cpp

@@ -522,8 +522,9 @@ namespace BansheeEngine
 				camData.gbuffer->getNumSamples() != mCoreOptions->msaa;
 
 			if (createGBuffer)
-				camData.gbuffer = RenderTargets::create(*viewport, mCoreOptions->hdr, mCoreOptions->msaa);
+				camData.gbuffer = RenderTargets::create(viewport, mCoreOptions->hdr, mCoreOptions->msaa);
 
+			camData.gbuffer->allocate();
 			camData.gbuffer->bind();
 
 			UINT32 clearBuffers = FBT_COLOR | FBT_DEPTH | FBT_STENCIL;
@@ -557,7 +558,7 @@ namespace BansheeEngine
 				gRendererUtility().draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 			}
 
-			camData.gbuffer->unbind();
+			camData.gbuffer->release();
 		}
 		else
 			camData.gbuffer = nullptr;

+ 78 - 33
RenderBeast/Source/BsRenderTargets.cpp

@@ -6,13 +6,9 @@
 
 namespace BansheeEngine
 {
-	RenderTargets::RenderTargets(const ViewportCore& viewport, bool hdr, UINT32 numSamples)
-		:mNumSamples(numSamples), mHDR(hdr)
+	RenderTargets::RenderTargets(const SPtr<ViewportCore>& viewport, bool hdr, UINT32 numSamples)
+		:mNumSamples(numSamples), mHDR(hdr), mViewport(viewport)
 	{
-		// TODO - Round up width/height so it's divisible by 8?
-		mWidth = (UINT32)viewport.getWidth();
-		mHeight = (UINT32)viewport.getHeight();
-
 		if (hdr)
 			mDiffuseFormat = PF_FLOAT_R11G11B10;
 		else
@@ -21,73 +17,122 @@ namespace BansheeEngine
 		mNormalFormat = PF_UNORM_R10G10B10A2;
 	}
 
-	SPtr<RenderTargets> RenderTargets::create(const ViewportCore& viewport, bool hdr, UINT32 numSamples)
+	SPtr<RenderTargets> RenderTargets::create(const SPtr<ViewportCore>& viewport, bool hdr, UINT32 numSamples)
 	{
 		return bs_shared_ptr<RenderTargets>(new (bs_alloc<RenderTargets>()) RenderTargets(viewport, hdr, numSamples));
 	}
 
-	void RenderTargets::bind()
+	void RenderTargets::allocate()
 	{
 		RenderTexturePool& texPool = RenderTexturePool::instance();
 
-		mDiffuseRT = texPool.get(mDiffuseFormat, mWidth, mHeight, false, mNumSamples);
-		mNormalRT = texPool.get(mNormalFormat, mWidth, mHeight, false, mNumSamples);
-		mDepthRT = texPool.get(PF_D24S8, mWidth, mHeight, false, mNumSamples);
+		UINT32 width = getWidth();
+		UINT32 height = getHeight();
+
+		SPtr<PooledRenderTexture> newAlbedoRT = texPool.get(mDiffuseFormat, width, height, false, mNumSamples);
+		SPtr<PooledRenderTexture> newNormalRT = texPool.get(mNormalFormat, width, height, false, mNumSamples);
+		SPtr<PooledRenderTexture> newDepthRT = texPool.get(PF_D24S8, width, height, false, mNumSamples);
+
+		SPtr<PooledRenderTexture> newColorRT = nullptr;
+
+		// See if I can use the final output color target for gbuffer rendering, this saves a little memory
+		SPtr<RenderTargetCore> resolvedRT = mViewport->getTarget();
+		const RenderTargetProperties& resolvedRTProps = resolvedRT->getProperties();
+
+		bool useResolvedColor = !resolvedRTProps.isWindow() &&
+			mViewport->getWidth() == getWidth() &&
+			mViewport->getHeight() == getHeight() &&
+			((resolvedRTProps.getMultisampleCount() <= 1) == (mNumSamples <= 1) ||
+			resolvedRTProps.getMultisampleCount() == mNumSamples);
+
+		if (!useResolvedColor)
+			newColorRT = texPool.get(PF_B8G8R8X8, width, height, false, mNumSamples);
+
+		bool rebuildTargets = newColorRT != mSceneColorTex || newAlbedoRT != mAlbedoTex || newNormalRT != mNormalTex || newDepthRT != mDepthTex;
 
-		// Note: I'm making an assumption here that textures retrieved from render texture pool
-		// won't change, which should be true as long as I don't request these same sizes & formats
-		// somewhere else at the same time while binding the gbuffer (which shouldn't happen).
-		if (mGBuffer == nullptr)
+		mSceneColorTex = newColorRT;
+		mAlbedoTex = newAlbedoRT;
+		mNormalTex = newNormalRT;
+		mDepthTex = newDepthRT;
+
+		if (mGBufferRT == nullptr || rebuildTargets)
 		{
 			MULTI_RENDER_TEXTURE_CORE_DESC gbufferDesc;
-			gbufferDesc.colorSurfaces.resize(2);
+			gbufferDesc.colorSurfaces.resize(3);
+
+			SPtr<TextureCore> sceneColorTex = nullptr;
 
-			gbufferDesc.colorSurfaces[0].texture = mDiffuseRT->texture;
+			if (newColorRT != nullptr)
+				sceneColorTex = newColorRT->texture;
+			else // Re-using output scene color texture
+			{
+				SPtr<RenderTextureCore> resolvedRTex = std::static_pointer_cast<RenderTextureCore>(resolvedRT);
+				sceneColorTex = resolvedRTex->getBindableColorTexture();
+			}
+
+			gbufferDesc.colorSurfaces[0].texture = sceneColorTex;
 			gbufferDesc.colorSurfaces[0].face = 0;
 			gbufferDesc.colorSurfaces[0].mipLevel = 0;
 
-			gbufferDesc.colorSurfaces[1].texture = mNormalRT->texture;
+			gbufferDesc.colorSurfaces[1].texture = mAlbedoTex->texture;
 			gbufferDesc.colorSurfaces[1].face = 0;
 			gbufferDesc.colorSurfaces[1].mipLevel = 0;
 
-			gbufferDesc.depthStencilSurface.texture = mDepthRT->texture;
+			gbufferDesc.colorSurfaces[2].texture = mNormalTex->texture;
+			gbufferDesc.colorSurfaces[2].face = 0;
+			gbufferDesc.colorSurfaces[2].mipLevel = 0;
+
+			gbufferDesc.depthStencilSurface.texture = mDepthTex->texture;
 			gbufferDesc.depthStencilSurface.face = 0;
 			gbufferDesc.depthStencilSurface.mipLevel = 0;
 
-			mGBuffer = TextureCoreManager::instance().createMultiRenderTexture(gbufferDesc);
+			mGBufferRT = TextureCoreManager::instance().createMultiRenderTexture(gbufferDesc);
 		}
-
-		RenderAPICore& rapi = RenderAPICore::instance();
-		rapi.setRenderTarget(mGBuffer);
-
-		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
-		rapi.setViewport(area);
 	}
 
-	void RenderTargets::unbind()
+	void RenderTargets::release()
 	{
 		RenderAPICore& rapi = RenderAPICore::instance();
 		rapi.setRenderTarget(nullptr);
 
 		RenderTexturePool& texPool = RenderTexturePool::instance();
 
-		texPool.release(mDiffuseRT);
-		texPool.release(mNormalRT);
-		texPool.release(mDepthRT);
+		texPool.release(mAlbedoTex);
+		texPool.release(mNormalTex);
+		texPool.release(mDepthTex);
+	}
+
+	void RenderTargets::bind()
+	{
+		RenderAPICore& rapi = RenderAPICore::instance();
+		rapi.setRenderTarget(mGBufferRT);
+
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
 	}
 
 	SPtr<TextureCore> RenderTargets::getTextureA() const
 	{
-		return mDiffuseRT->texture;
+		return mAlbedoTex->texture;
 	}
 
 	SPtr<TextureCore> RenderTargets::getTextureB() const
 	{
-		return mNormalRT->texture;
+		return mNormalTex->texture;
 	}
 
 	SPtr<TextureCore> RenderTargets::getTextureDepth() const
 	{
-		return mDepthRT->texture;
+		return mDepthTex->texture;
+	}
+
+	UINT32 RenderTargets::getWidth() const
+	{
+		return (UINT32)mViewport->getWidth();
+	}
+
+	UINT32 RenderTargets::getHeight() const
+	{
+		return (UINT32)mViewport->getHeight();
 	}
 }

+ 1 - 1
TODOExperimentation.txt

@@ -16,7 +16,6 @@ Assign ViewOrigin, PreViewTranslation, TransViewProj
 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
- - Lights already existing in scene on load don't seem to render (seems they get converted to point lights for some reason)
  - 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
   - Either unify these two processes by finding a better way, or hide the binding in light material class
@@ -40,6 +39,7 @@ Notes:
  - 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
    from those operations during its base pass.
+ - Don't forget to make everything gamma correct
 
 Generate different RenderableController for each set of elements
  - Will likely want to rename current LitTexRenderableController to OpaqueSomething