Browse Source

When sycing core changes sync dependencies before dependants (WIP - Broke rendering)
Started work on deferred rendering path - cameras now reference and create gbuffers

BearishSun 10 years ago
parent
commit
0a188aad0b

+ 3 - 1
BansheeCore/Source/BsCoreObject.cpp

@@ -124,8 +124,10 @@ namespace BansheeEngine
 		std::function<void(const Vector<IndividualCoreSyncData>&)> callback =
 			[](const Vector<IndividualCoreSyncData>& data)
 		{
-			for (auto& entry : data)
+			// Traverse in reverse to sync dependencies before dependants
+			for (auto& riter = data.rbegin(); riter != data.rend(); ++riter)
 			{
+				const IndividualCoreSyncData& entry = *riter;
 				entry.destination->syncToCore(entry.syncData);
 
 				UINT8* dataPtr = entry.syncData.getBuffer();

+ 35 - 7
BansheeCore/Source/BsCoreObjectManager.cpp

@@ -80,17 +80,44 @@ namespace BansheeEngine
 		CoreStoredSyncData& syncData = mCoreSyncData.back();
 
 		syncData.alloc = allocator;
+
+		Vector<SPtr<CoreObject>> dependencies;
+		Vector<CoreObject*> todo;
+		UINT32 stackPos = 0;
+
 		for (auto& objectData : mObjects)
 		{
 			CoreObject* object = objectData.second;
-			SPtr<CoreObjectCore> objectCore = object->getCore();
-			if (objectCore != nullptr && object->isCoreDirty())
+			
+			todo.push_back(object);
+			while (stackPos < todo.size())
 			{
-				CoreSyncData objSyncData = object->syncToCore(allocator);
-				object->markCoreClean();
+				CoreObject* curObj = todo[stackPos];
+				stackPos++;
+
+				if (curObj->isCoreDirty())
+				{
+					SPtr<CoreObjectCore> objectCore = curObj->getCore();
+					if (objectCore == nullptr)
+						continue;
+
+					CoreSyncData objSyncData = curObj->syncToCore(allocator);
+					curObj->markCoreClean();
 
-				syncData.entries[object->getInternalID()] = CoreStoredSyncObjData(objectCore.get(), objSyncData);
+					syncData.entries[curObj->getInternalID()] = CoreStoredSyncObjData(objectCore.get(), objSyncData);
+				}
+
+				// Note: I don't check for recursion. Possible infinite loop if two objects
+				// are dependent on one another.
+				curObj->getCoreDependencies(dependencies);
+				for (auto& dependency : dependencies)
+					todo.push_back(dependency.get());
+
+				dependencies.clear();
 			}
+
+			todo.clear();
+			stackPos = 0;
 		}
 	}
 
@@ -103,9 +130,10 @@ namespace BansheeEngine
 
 		CoreStoredSyncData& syncData = mCoreSyncData.front();
 
-		for (auto& objectData : syncData.entries)
+		// Traverse in reverse to sync dependencies before dependants
+		for (auto& riter = syncData.entries.rbegin(); riter != syncData.entries.rend(); ++riter)
 		{
-			const CoreStoredSyncObjData& objSyncData = objectData.second;
+			const CoreStoredSyncObjData& objSyncData = riter->second;
 			objSyncData.destinationObj->syncToCore(objSyncData.syncData);
 
 			UINT8* data = objSyncData.syncData.getBuffer();

+ 4 - 0
BansheeEngine/Source/BsCamera.cpp

@@ -705,6 +705,8 @@ namespace BansheeEngine
 
 	void CameraCore::syncToCore(const CoreSyncData& data)
 	{
+		RendererManager::instance().getActive()->_notifyCameraRemoved(this);
+
 		char* dataPtr = (char*)data.getBuffer();
 
 		dataPtr = rttiReadElem(mLayers, dataPtr);
@@ -724,6 +726,8 @@ namespace BansheeEngine
 		mRecalcFrustum = true;
 		mRecalcFrustumPlanes = true;
 		mRecalcView = true;
+
+		RendererManager::instance().getActive()->_notifyCameraAdded(this);
 	}
 
 	Camera::Camera(RenderTargetPtr target, float left, float top, float width, float height)

+ 13 - 1
RenderBeast/Include/BsRenderBeast.h

@@ -73,6 +73,8 @@ namespace BansheeEngine
 		{
 			RenderQueuePtr opaqueQueue;
 			RenderQueuePtr transparentQueue;
+
+			SPtr<RenderTargets> gbuffer;
 		};
 
 		/**
@@ -181,6 +183,16 @@ namespace BansheeEngine
 		 */
 		void determineVisible(const CameraCore& camera);
 
+		/**
+		 * @brief	Renders all objects visible by the provided camera.
+		 *
+		 * @param	rtData	Render target data containing the camera to render.
+		 * @param	camIdx	Index of the camera to render.
+		 * 					
+		 * @note	Core thread only.
+		 */
+		void render(RenderTargetData& rtData, UINT32 camIdx);
+
 		/**
 		 * @brief	Renders all objects visible by the provided camera.
 		 *
@@ -188,7 +200,7 @@ namespace BansheeEngine
 		 *
 		 * @note	Core thread only.
 		 */
-		virtual void render(const CameraCore& camera);
+		void renderOLD(const CameraCore& camera);
 
 		/**
 		 * @brief	Creates data used by the renderer on the core thread.

+ 11 - 0
RenderBeast/Include/BsRenderTargets.h

@@ -39,6 +39,16 @@ namespace BansheeEngine
 		 */
 		void unbind();
 
+		/**
+		 * @brief	Checks if the targets support HDR rendering.
+		 */
+		bool getHDR() const { return mHDR; }
+
+		/**
+		 * @brief	Returns the number of samples per pixel supported by the targets.
+		 */
+		UINT32 getNumSamples() const { return mNumSamples; }
+
 	private:
 		RenderTargets(const ViewportCore& viewport, bool hdr, UINT32 numSamples);
 
@@ -53,5 +63,6 @@ namespace BansheeEngine
 		PixelFormat mDiffuseFormat;
 		PixelFormat mNormalFormat;
 		UINT32 mNumSamples;
+		bool mHDR;
 	};
 }

+ 266 - 82
RenderBeast/Source/BsRenderBeast.cpp

@@ -32,6 +32,7 @@
 #include "BsSamplerOverrides.h"
 #include "BsLight.h"
 #include "BsRenderTexturePool.h"
+#include "BsRenderTargets.h"
 
 using namespace std::placeholders;
 
@@ -251,11 +252,65 @@ namespace BansheeEngine
 			transparentStateReduction = StateReduction::Distance; // Transparent object MUST be sorted by distance
 
 		camData.transparentQueue = bs_shared_ptr_new<RenderQueue>(transparentStateReduction);
+
+		// Register in render target list
+		SPtr<RenderTargetCore> renderTarget = camera->getViewport()->getTarget();
+		if (renderTarget == nullptr)
+			return;
+
+		auto findIter = std::find_if(mRenderTargets.begin(), mRenderTargets.end(), 
+			[&](const RenderTargetData& x) { return x.target == renderTarget; });
+
+		if (findIter != mRenderTargets.end())
+		{
+			findIter->cameras.push_back(camera);
+		}
+		else
+		{
+			mRenderTargets.push_back(RenderTargetData());
+			RenderTargetData& renderTargetData = mRenderTargets.back();
+
+			renderTargetData.target = renderTarget;
+			renderTargetData.cameras.push_back(camera);
+		}
+
+		// Sort render targets based on priority
+		auto cameraComparer = [&](const CameraCore* a, const CameraCore* b) { return a->getPriority() > b->getPriority(); };
+		auto renderTargetInfoComparer = [&](const RenderTargetData& a, const RenderTargetData& b)
+		{ return a.target->getProperties().getPriority() > b.target->getProperties().getPriority(); };
+		std::sort(begin(mRenderTargets), end(mRenderTargets), renderTargetInfoComparer);
+
+		for (auto& camerasPerTarget : mRenderTargets)
+		{
+			Vector<const CameraCore*>& cameras = camerasPerTarget.cameras;
+
+			std::sort(begin(cameras), end(cameras), cameraComparer);
+		}
 	}
 
 	void RenderBeast::_notifyCameraRemoved(const CameraCore* camera)
 	{
 		mCameraData.erase(camera);
+
+		// Remove from render target list
+		for (auto iterTarget = mRenderTargets.begin(); iterTarget != mRenderTargets.end(); ++iterTarget)
+		{
+			RenderTargetData& target = *iterTarget;
+			for (auto iterCam = target.cameras.begin(); iterCam != target.cameras.end(); ++iterCam)
+			{
+				if (camera == *iterCam)
+				{
+					target.cameras.erase(iterCam);
+					break;
+				}
+			}
+
+			if (target.cameras.empty())
+			{
+				mRenderTargets.erase(iterTarget);
+				break;
+			}
+		}
 	}
 
 	void RenderBeast::setOptions(const SPtr<CoreRendererOptions>& options)
@@ -318,43 +373,6 @@ namespace BansheeEngine
 		// Update global per-frame hardware buffers
 		mStaticHandler->updatePerFrameBuffers(time);
 
-		// Sort cameras by render target
-		for (auto& cameraData : mCameraData)
-		{
-			const CameraCore* camera = cameraData.first;
-			SPtr<RenderTargetCore> renderTarget = camera->getViewport()->getTarget();
-
-			if (renderTarget == nullptr)
-				continue;
-
-			auto findIter = std::find_if(mRenderTargets.begin(), mRenderTargets.end(), [&](const RenderTargetData& x) { return x.target == renderTarget; });
-			if (findIter != mRenderTargets.end())
-			{
-				findIter->cameras.push_back(camera);
-			}
-			else
-			{
-				mRenderTargets.push_back(RenderTargetData());
-				RenderTargetData& renderTargetData = mRenderTargets.back();
-
-				renderTargetData.target = renderTarget;
-				renderTargetData.cameras.push_back(camera);
-			}
-		}
-
-		// Sort everything based on priority
-		auto cameraComparer = [&](const CameraCore* a, const CameraCore* b) { return a->getPriority() > b->getPriority(); };
-		auto renderTargetInfoComparer = [&](const RenderTargetData& a, const RenderTargetData& b)
-		{ return a.target->getProperties().getPriority() > b.target->getProperties().getPriority(); };
-		std::sort(begin(mRenderTargets), end(mRenderTargets), renderTargetInfoComparer);
-
-		for (auto& camerasPerTarget : mRenderTargets)
-		{
-			Vector<const CameraCore*>& cameras = camerasPerTarget.cameras;
-
-			std::sort(begin(cameras), end(cameras), cameraComparer);
-		}
-
 		// Generate render queues per camera
 		for (auto& cameraData : mCameraData)
 		{
@@ -369,8 +387,13 @@ namespace BansheeEngine
 			Vector<const CameraCore*>& cameras = renderTargetData.cameras;
 
 			RenderAPICore::instance().beginFrame();
-			RenderAPICore::instance().setRenderTarget(target);
 
+			//UINT32 numCameras = (UINT32)cameras.size();
+			//for (UINT32 i = 0; i < numCameras; i++)
+			//	render(renderTargetData, i);
+
+			// BEGIN OLD STUFF
+			RenderAPICore::instance().setRenderTarget(target);
 			for(auto& camera : cameras)
 			{
 				SPtr<ViewportCore> viewport = camera->getViewport();
@@ -389,66 +412,179 @@ namespace BansheeEngine
 				if(clearBuffers != 0)
 					RenderAPICore::instance().clearViewport(clearBuffers, viewport->getClearColor(), viewport->getClearDepthValue(), viewport->getClearStencilValue());
 
-				render(*camera);
+				renderOLD(*camera);
 			}
+			// END OLD STUFF
 
 			RenderAPICore::instance().endFrame();
 			RenderAPICore::instance().swapBuffers(target);
 		}
-
-		mRenderTargets.clear();
 	}
 
-	void RenderBeast::determineVisible(const CameraCore& camera)
+	void RenderBeast::render(RenderTargetData& rtData, UINT32 camIdx)
 	{
-		CameraData& cameraData = mCameraData[&camera];
+		const CameraCore* camera = rtData.cameras[camIdx];
+		CameraData& camData = mCameraData[camera];
+		SPtr<ViewportCore> viewport = camera->getViewport();
 
-		UINT64 cameraLayers = camera.getLayers();
-		ConvexVolume worldFrustum = camera.getWorldFrustum();
+		Matrix4 projMatrixCstm = camera->getProjectionMatrixRS();
+		Matrix4 viewMatrixCstm = camera->getViewMatrix();
 
-		// Update per-object param buffers and queue render elements
-		for (auto& renderableData : mRenderables)
+		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
+
+		mStaticHandler->updatePerCameraBuffers(camera->getForward());
+
+		// Render scene object to g-buffer if there are any
+		const Vector<RenderQueueElement>& opaqueElements = camData.opaqueQueue->getSortedElements();
+		bool hasGBuffer = opaqueElements.size() > 0;
+
+		if (hasGBuffer)
 		{
-			RenderableCore* renderable = renderableData.renderable;
-			RenderableHandler* controller = renderableData.controller;
-			UINT32 renderableType = renderable->getRenderableType();
-			UINT32 rendererId = renderable->getRendererId();
+			bool createGBuffer = camData.gbuffer == nullptr ||
+				camData.gbuffer->getHDR() != mCoreOptions->hdr ||
+				camData.gbuffer->getNumSamples() != mCoreOptions->msaa;
 
-			if ((renderable->getLayer() & cameraLayers) == 0)
-				continue;
+			if (createGBuffer)
+				camData.gbuffer = RenderTargets::create(*viewport, mCoreOptions->hdr, mCoreOptions->msaa);
 
-			// Do frustum culling
-			// TODO - This is bound to be a bottleneck at some point. When it is ensure that intersect
-			// methods use vector operations, as it is trivial to update them.
-			const Sphere& boundingSphere = mWorldBounds[rendererId].getSphere();
-			if (worldFrustum.intersects(boundingSphere))
+			camData.gbuffer->bind();
+
+			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());
+
+			for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 			{
-				// More precise with the box
-				const AABox& boundingBox = mWorldBounds[rendererId].getBox();
+				BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+				SPtr<MaterialCore> material = renderElem->material;
 
-				if (worldFrustum.intersects(boundingBox))
-				{
-					float distanceToCamera = (camera.getPosition() - boundingBox.getCenter()).length();
+				UINT32 rendererId = renderElem->renderableId;
+				Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
 
-					for (auto& renderElem : renderableData.elements)
-					{
-						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
+				mStaticHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+				mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
+				mStaticHandler->bindPerObjectBuffers(*renderElem);
 
-						if (isTransparent)
-							cameraData.transparentQueue->add(&renderElem, distanceToCamera);
-						else
-							cameraData.opaqueQueue->add(&renderElem, distanceToCamera);
-					}
-						
+				if (iter->applyPass)
+				{
+					SPtr<PassCore> pass = material->getPass(iter->passIdx);
+					setPass(pass);
 				}
+
+				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+
+				if (renderElem->samplerOverrides != nullptr)
+					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
+				else
+					setPassParams(passParams, nullptr);
+
+				draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 			}
 		}
+		else
+			camData.gbuffer = nullptr;
 
-		cameraData.opaqueQueue->sort();
-		cameraData.transparentQueue->sort();
+		// Prepare final render target
+		SPtr<RenderTargetCore> target = rtData.target;
+
+		// If first camera in render target, prepare the RT
+		if (camIdx == 0)
+		{
+			RenderAPICore::instance().setRenderTarget(target);
+			RenderAPICore::instance().setViewport(viewport->getNormArea());
+
+			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)
+			{
+				if (callbackPair.first >= 0)
+					break;
+
+				callbackPair.second();
+			}
+		}
+
+		// Resolve gbuffer if there is one
+		if (hasGBuffer)
+		{
+			// TODO - Render lights
+			// TODO - Resolve to render target
+			
+			camData.gbuffer->unbind();
+		}
+
+		// Render transparent objects
+		const Vector<RenderQueueElement>& transparentElements = camData.transparentQueue->getSortedElements();
+		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
+		{
+			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
+			SPtr<MaterialCore> material = renderElem->material;
+
+			UINT32 rendererId = renderElem->renderableId;
+			Matrix4 worldViewProjMatrix = viewProjMatrix * mWorldTransforms[rendererId];
+
+			mStaticHandler->updatePerObjectBuffers(*renderElem, worldViewProjMatrix);
+			mStaticHandler->bindGlobalBuffers(*renderElem); // Note: If I can keep global buffer slot indexes the same between shaders I could only bind these once
+			mStaticHandler->bindPerObjectBuffers(*renderElem);
+
+			if (iter->applyPass)
+			{
+				SPtr<PassCore> pass = material->getPass(iter->passIdx);
+				setPass(pass);
+			}
+
+			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+
+			if (renderElem->samplerOverrides != nullptr)
+				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
+			else
+				setPassParams(passParams, nullptr);
+
+			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
+		}
+
+		camData.opaqueQueue->clear();
+		camData.transparentQueue->clear();
+
+		// Render post-scene callbacks
+		if (iterCameraCallbacks != mRenderCallbacks.end())
+		{
+			for (auto& callbackPair : iterCameraCallbacks->second)
+			{
+				if (callbackPair.first < 0)
+					continue;
+
+				callbackPair.second();
+			}
+		}
 	}
 
-	void RenderBeast::render(const CameraCore& camera)
+	void RenderBeast::renderOLD(const CameraCore& camera)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -478,6 +614,7 @@ namespace BansheeEngine
 		//// Update global per-frame hardware buffers
 		mStaticHandler->updatePerCameraBuffers(camera.getForward());
 
+		// TODO - This bit can be removed once I fully switch to deferred
 		const Vector<RenderQueueElement>& opaqueElements = cameraData.opaqueQueue->getSortedElements();
 		for(auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		{
@@ -529,14 +666,12 @@ namespace BansheeEngine
 				setPass(pass);
 			}
 
-			{
-				SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
+			SPtr<PassParametersCore> passParams = material->getPassParameters(iter->passIdx);
 
-				if (renderElem->samplerOverrides != nullptr)
-					setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
-				else
-					setPassParams(passParams, nullptr);
-			}
+			if (renderElem->samplerOverrides != nullptr)
+				setPassParams(passParams, &renderElem->samplerOverrides->passes[iter->passIdx]);
+			else
+				setPassParams(passParams, nullptr);
 
 			draw(iter->renderElem->mesh, iter->renderElem->subMesh);
 		}
@@ -557,6 +692,55 @@ namespace BansheeEngine
 		}
 	}
 
+	void RenderBeast::determineVisible(const CameraCore& camera)
+	{
+		CameraData& cameraData = mCameraData[&camera];
+
+		UINT64 cameraLayers = camera.getLayers();
+		ConvexVolume worldFrustum = camera.getWorldFrustum();
+
+		// Update per-object param buffers and queue render elements
+		for (auto& renderableData : mRenderables)
+		{
+			RenderableCore* renderable = renderableData.renderable;
+			RenderableHandler* controller = renderableData.controller;
+			UINT32 renderableType = renderable->getRenderableType();
+			UINT32 rendererId = renderable->getRendererId();
+
+			if ((renderable->getLayer() & cameraLayers) == 0)
+				continue;
+
+			// Do frustum culling
+			// TODO - This is bound to be a bottleneck at some point. When it is ensure that intersect
+			// methods use vector operations, as it is trivial to update them.
+			const Sphere& boundingSphere = mWorldBounds[rendererId].getSphere();
+			if (worldFrustum.intersects(boundingSphere))
+			{
+				// More precise with the box
+				const AABox& boundingBox = mWorldBounds[rendererId].getBox();
+
+				if (worldFrustum.intersects(boundingBox))
+				{
+					float distanceToCamera = (camera.getPosition() - boundingBox.getCenter()).length();
+
+					for (auto& renderElem : renderableData.elements)
+					{
+						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
+
+						if (isTransparent)
+							cameraData.transparentQueue->add(&renderElem, distanceToCamera);
+						else
+							cameraData.opaqueQueue->add(&renderElem, distanceToCamera);
+					}
+
+				}
+			}
+		}
+
+		cameraData.opaqueQueue->sort();
+		cameraData.transparentQueue->sort();
+	}
+
 	void RenderBeast::refreshSamplerOverrides(bool force)
 	{
 		for (auto& entry : mSamplerOverrides)

+ 3 - 2
RenderBeast/Source/BsRenderTargets.cpp

@@ -7,7 +7,7 @@
 namespace BansheeEngine
 {
 	RenderTargets::RenderTargets(const ViewportCore& viewport, bool hdr, UINT32 numSamples)
-		:mNumSamples(numSamples)
+		:mNumSamples(numSamples), mHDR(hdr)
 	{
 		// TODO - Round up width/height so it's divisible by 8?
 		mWidth = (UINT32)viewport.getWidth();
@@ -60,7 +60,8 @@ namespace BansheeEngine
 		RenderAPICore& rapi = RenderAPICore::instance();
 		rapi.setRenderTarget(mGBuffer);
 
-		// TODO - Clear gbuffer?
+		Rect2 area(0.0f, 0.0f, 1.0f, 1.0f);
+		rapi.setViewport(area);
 	}
 
 	void RenderTargets::unbind()

+ 2 - 0
TODO.txt

@@ -53,6 +53,8 @@ Code quality improvements:
 Polish
 
 Ribek use:
+ - When performing core sync it doesn't handle it in hierarchical order. E.g. if a camera depends on viewport, then it should
+   sync the viewport first, then camera
  - Opening complex array entries causes inspector to get screwed up
  - Hook up color picker to guicolor field
  - Camera, Renderable, Material, Texture inspector

+ 1 - 0
TODOExperimentation.txt

@@ -13,6 +13,7 @@ Next week:
  - Think about how to handle post-processing shaders (HDR tone mapping)
  - Add cube and 3D support for render texture pool
 
+When doing viewport clear in DX11 it will only clear the first render target
 RenderTexturePool needs support for cube and 3D textures
 Lights need getLightMesh() method
  - Need cone to use when rendering spot light, sphere otherwise