Browse Source

Refactoring renderer so renderable parameter buffers are populated on renderable change, instead of every frame

BearishSun 9 years ago
parent
commit
7832d7d165

+ 12 - 3
Data/Raw/Engine/Includes/PerObjectData.bslinc

@@ -11,6 +11,7 @@ Parameters =
 Blocks =
 Blocks =
 {
 {
 	Block PerObject : auto("PerObject");
 	Block PerObject : auto("PerObject");
+	Block PerCall : auto("PerCall");
 };
 };
 
 
 Technique : base("PerObjectData") =
 Technique : base("PerObjectData") =
@@ -23,12 +24,16 @@ Technique : base("PerObjectData") =
 		{
 		{
 			cbuffer PerObject
 			cbuffer PerObject
 			{
 			{
-				float4x4 gMatWorldViewProj;
 				float4x4 gMatWorld;
 				float4x4 gMatWorld;
 				float4x4 gMatInvWorld;
 				float4x4 gMatInvWorld;
 				float4x4 gMatWorldNoScale;
 				float4x4 gMatWorldNoScale;
 				float4x4 gMatInvWorldNoScale;
 				float4x4 gMatInvWorldNoScale;
 				float gWorldDeterminantSign;
 				float gWorldDeterminantSign;
+			}	
+
+			cbuffer PerCall
+			{
+				float4x4 gMatWorldViewProj;
 			}			
 			}			
 		};
 		};
 	};
 	};
@@ -44,13 +49,17 @@ Technique : base("PerObjectData") =
 		{
 		{
 			layout(binding = 2, std140) uniform PerObject
 			layout(binding = 2, std140) uniform PerObject
 			{
 			{
-				mat4 gMatWorldViewProj;
 				mat4 gMatWorld;
 				mat4 gMatWorld;
 				mat4 gMatInvWorld;
 				mat4 gMatInvWorld;
 				mat4 gMatWorldNoScale;
 				mat4 gMatWorldNoScale;
 				mat4 gMatInvWorldNoScale;
 				mat4 gMatInvWorldNoScale;
 				float gWorldDeterminantSign;
 				float gWorldDeterminantSign;
-			};			
+			};
+			
+			layout(binding = 3, std140) uniform PerCall
+			{
+				mat4 gMatWorldViewProj;
+			};	
 		};
 		};
 	};
 	};
 };
 };

+ 1 - 0
Source/BansheeCore/Include/BsCoreRenderer.h

@@ -22,6 +22,7 @@ namespace bs
 	static StringID RBS_PerCamera = "PerCamera";
 	static StringID RBS_PerCamera = "PerCamera";
 	static StringID RBS_PerFrame = "PerFrame";
 	static StringID RBS_PerFrame = "PerFrame";
 	static StringID RBS_PerObject = "PerObject";
 	static StringID RBS_PerObject = "PerObject";
+	static StringID RBS_PerCall = "PerCall";
 
 
 	/**
 	/**
 	 * Available parameter semantics that allow the renderer to identify the use of a GPU parameter specified in a shader.
 	 * Available parameter semantics that allow the renderer to identify the use of a GPU parameter specified in a shader.

+ 1 - 0
Source/RenderBeast/CMakeSources.cmake

@@ -24,6 +24,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsLightRendering.cpp"
 	"Source/BsLightRendering.cpp"
 	"Source/BsPostProcessing.cpp"
 	"Source/BsPostProcessing.cpp"
 	"Source/BsRendererCamera.cpp"
 	"Source/BsRendererCamera.cpp"
+	"Source/BsRendererObject.cpp"
 )
 )
 
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 1 - 27
Source/RenderBeast/Include/BsObjectRendering.h

@@ -22,25 +22,6 @@ namespace bs
 		BS_PARAM_BLOCK_ENTRY(float, gTime)
 		BS_PARAM_BLOCK_ENTRY(float, gTime)
 	BS_PARAM_BLOCK_END
 	BS_PARAM_BLOCK_END
 
 
-	BS_PARAM_BLOCK_BEGIN(PerObjectParamBuffer)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorldViewProj)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorld)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvWorld)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorldNoScale)
-		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvWorldNoScale)
-		BS_PARAM_BLOCK_ENTRY(float, gWorldDeterminantSign)
-	BS_PARAM_BLOCK_END
-
-	/**	Data bound to the shader when rendering a specific renderable object. */
-	struct RenderableShaderData
-	{
-		Matrix4 worldTransform;
-		Matrix4 invWorldTransform;
-		Matrix4 worldNoScaleTransform;
-		Matrix4 invWorldNoScaleTransform;
-		float worldDeterminantSign;
-	};
-
 	/** Manages initialization and rendering of individual renderable object, represented as RenderableElement%s. */
 	/** Manages initialization and rendering of individual renderable object, represented as RenderableElement%s. */
 	class BS_BSRND_EXPORT ObjectRenderer
 	class BS_BSRND_EXPORT ObjectRenderer
 	{
 	{
@@ -48,20 +29,13 @@ namespace bs
 		ObjectRenderer();
 		ObjectRenderer();
 
 
 		/** Initializes the specified renderable element, making it ready to be used. */
 		/** Initializes the specified renderable element, making it ready to be used. */
-		void initElement(BeastRenderableElement& element);
+		void initElement(RendererObject& owner, BeastRenderableElement& element);
 
 
 		/** Updates global per frame parameter buffers with new values. To be called at the start of every frame. */
 		/** Updates global per frame parameter buffers with new values. To be called at the start of every frame. */
 		void setParamFrameParams(float time);
 		void setParamFrameParams(float time);
 
 
-		/**
-		 * Updates object specific parameter buffers with new values. To be called whenever object specific values change.
-		 */
-		void setPerObjectParams(const BeastRenderableElement& element, const RenderableShaderData& data,
-			const Matrix4& wvpMatrix, const SPtr<GpuBufferCore>& boneMatrices = nullptr);
-
 	protected:
 	protected:
 		PerFrameParamBuffer mPerFrameParams;
 		PerFrameParamBuffer mPerFrameParams;
-		PerObjectParamBuffer mPerObjectParams;
 	};
 	};
 
 
 	/** Basic shader that is used when no other is available. */
 	/** Basic shader that is used when no other is available. */

+ 1 - 2
Source/RenderBeast/Include/BsRenderBeast.h

@@ -198,8 +198,7 @@ namespace bs
 		UnorderedMap<const CameraCore*, RendererCamera*> mCameras;
 		UnorderedMap<const CameraCore*, RendererCamera*> mCameras;
 		UnorderedMap<SamplerOverrideKey, MaterialSamplerOverrides*> mSamplerOverrides;
 		UnorderedMap<SamplerOverrideKey, MaterialSamplerOverrides*> mSamplerOverrides;
 
 
-		Vector<RendererObject> mRenderables;
-		Vector<RenderableShaderData> mRenderableShaderData;
+		Vector<RendererObject*> mRenderables;
 		Vector<Bounds> mWorldBounds;
 		Vector<Bounds> mWorldBounds;
 		Vector<bool> mVisibility; // Transient
 		Vector<bool> mVisibility; // Transient
 
 

+ 1 - 1
Source/RenderBeast/Include/BsRendererCamera.h

@@ -81,7 +81,7 @@ namespace bs
 		 *									As a side-effect, per-camera visibility data is also calculated and can be
 		 *									As a side-effect, per-camera visibility data is also calculated and can be
 		 *									retrieved by calling getVisibilityMask().
 		 *									retrieved by calling getVisibilityMask().
 		 */
 		 */
-		void determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds, 
+		void determineVisible(const Vector<RendererObject*>& renderables, const Vector<Bounds>& renderableBounds, 
 			Vector<bool>& visibility);
 			Vector<bool>& visibility);
 
 
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */

+ 29 - 6
Source/RenderBeast/Include/BsRendererObject.h

@@ -5,6 +5,8 @@
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderBeastPrerequisites.h"
 #include "BsRenderableElement.h"
 #include "BsRenderableElement.h"
 #include "BsRenderable.h"
 #include "BsRenderable.h"
+#include "BsParamBlocks.h"
+#include "BsMaterialParam.h"
 
 
 namespace bs
 namespace bs
 {
 {
@@ -12,6 +14,18 @@ namespace bs
 	 *  @{
 	 *  @{
 	 */
 	 */
 
 
+	BS_PARAM_BLOCK_BEGIN(PerObjectParamBuffer)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorld)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvWorld)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorldNoScale)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvWorldNoScale)
+		BS_PARAM_BLOCK_ENTRY(float, gWorldDeterminantSign)
+	BS_PARAM_BLOCK_END
+
+	BS_PARAM_BLOCK_BEGIN(PerCallParamBuffer)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatWorldViewProj)
+	BS_PARAM_BLOCK_END
+
 	struct MaterialSamplerOverrides;
 	struct MaterialSamplerOverrides;
 
 
 	/**
 	/**
@@ -46,11 +60,6 @@ namespace bs
 		/** Index to which should the per-camera param block buffer be bound to. */
 		/** Index to which should the per-camera param block buffer be bound to. */
 		UINT32 perCameraBindingIdx;
 		UINT32 perCameraBindingIdx;
 
 
-		/** 
-		 * Parameter for setting global bone pose transforms used for an element with skeletal animation, null otherwise. 
-		 */
-		MaterialParamBufferCore boneMatricesParam;
-
 		/** GPU buffer containing element's bone matrices, if it requires any. */
 		/** GPU buffer containing element's bone matrices, if it requires any. */
 		SPtr<GpuBufferCore> boneMatrixBuffer;
 		SPtr<GpuBufferCore> boneMatrixBuffer;
 
 
@@ -67,9 +76,23 @@ namespace bs
 	 /** Contains information about a Renderable, used by the Renderer. */
 	 /** Contains information about a Renderable, used by the Renderer. */
 	struct RendererObject
 	struct RendererObject
 	{
 	{
+		/** Updates the per-object GPU buffer according to the currently set properties. */
+		void updatePerObjectBuffer();
+
+		/** 
+		 * Updates the per-call GPU buffer according to the provided parameters. 
+		 * 
+		 * @param[in]	viewProj	Combined view-projection matrix of the current camera.
+		 * @param[in]	flush		True if the buffer contents should be immediately flushed to the GPU.
+		 */
+		void updatePerCallBuffer(const Matrix4& viewProj, bool flush = true);
+
 		RenderableCore* renderable;
 		RenderableCore* renderable;
 		Vector<BeastRenderableElement> elements;
 		Vector<BeastRenderableElement> elements;
+
+		PerObjectParamBuffer perObjectParams;
+		PerCallParamBuffer perCallParams;
 	};
 	};
 
 
 	/** @} */
 	/** @} */
-}
+}

+ 14 - 20
Source/RenderBeast/Source/BsObjectRendering.cpp

@@ -17,11 +17,13 @@ namespace bs
 	ObjectRenderer::ObjectRenderer()
 	ObjectRenderer::ObjectRenderer()
 	{ }
 	{ }
 
 
-	void ObjectRenderer::initElement(BeastRenderableElement& element)
+	void ObjectRenderer::initElement(RendererObject& owner, BeastRenderableElement& element)
 	{
 	{
 		SPtr<ShaderCore> shader = element.material->getShader();
 		SPtr<ShaderCore> shader = element.material->getShader();
 		if (shader == nullptr)
 		if (shader == nullptr)
 		{
 		{
+			element.perCameraBindingIdx = -1;
+
 			LOGWRN("Missing shader on material.");
 			LOGWRN("Missing shader on material.");
 			return;
 			return;
 		}
 		}
@@ -35,7 +37,15 @@ namespace bs
 			if (paramBlockDesc.second.rendererSemantic == RBS_PerFrame)
 			if (paramBlockDesc.second.rendererSemantic == RBS_PerFrame)
 				element.params->setParamBlockBuffer(paramBlockDesc.second.name, mPerFrameParams.getBuffer(), true);
 				element.params->setParamBlockBuffer(paramBlockDesc.second.name, mPerFrameParams.getBuffer(), true);
 			else if (paramBlockDesc.second.rendererSemantic == RBS_PerObject)
 			else if (paramBlockDesc.second.rendererSemantic == RBS_PerObject)
-				element.params->setParamBlockBuffer(paramBlockDesc.second.name, mPerObjectParams.getBuffer(), true);
+			{
+				element.params->setParamBlockBuffer(paramBlockDesc.second.name,
+													owner.perObjectParams.getBuffer(), true);
+			}
+			else if (paramBlockDesc.second.rendererSemantic == RBS_PerCall)
+			{
+				element.params->setParamBlockBuffer(paramBlockDesc.second.name,
+													owner.perCallParams.getBuffer(), true);
+			}
 		}
 		}
 
 
 		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferDescs = shader->getBufferParams();
 		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferDescs = shader->getBufferParams();
@@ -49,9 +59,8 @@ namespace bs
 		
 		
 		if (!boneMatricesParamName.empty())
 		if (!boneMatricesParamName.empty())
 		{
 		{
-			// Note: Bone matrices should be shared between all sub-meshes, so maybe it's better to create this buffer
-			// on a per-Renderable basis, rather than per-element?
-			element.boneMatricesParam = element.material->getParamBuffer(boneMatricesParamName);
+			MaterialParamBufferCore boneMatricesParam = element.material->getParamBuffer(boneMatricesParamName);
+			boneMatricesParam.set(element.boneMatrixBuffer);
 		}
 		}
 	}
 	}
 
 
@@ -60,21 +69,6 @@ namespace bs
 		mPerFrameParams.gTime.set(time);
 		mPerFrameParams.gTime.set(time);
 	}
 	}
 
 
-	void ObjectRenderer::setPerObjectParams(const BeastRenderableElement& element, const RenderableShaderData& data,
-		const Matrix4& wvpMatrix, const SPtr<GpuBufferCore>& boneMatrices)
-	{
-		// Note: If I kept all the values in the same structure maybe a simple memcpy directly into the constant buffer
-		// would be better (i.e. faster)?
-		mPerObjectParams.gMatWorld.set(data.worldTransform);
-		mPerObjectParams.gMatInvWorld.set(data.invWorldTransform);
-		mPerObjectParams.gMatWorldNoScale.set(data.worldNoScaleTransform);
-		mPerObjectParams.gMatInvWorldNoScale.set(data.invWorldNoScaleTransform);
-		mPerObjectParams.gWorldDeterminantSign.set(data.worldDeterminantSign);
-		mPerObjectParams.gMatWorldViewProj.set(wvpMatrix);
-
-		element.boneMatricesParam.set(boneMatrices);
-	}
-
 	void DefaultMaterial::_initDefines(ShaderDefines& defines)
 	void DefaultMaterial::_initDefines(ShaderDefines& defines)
 	{
 	{
 		// Do nothing
 		// Do nothing

+ 35 - 67
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -86,6 +86,9 @@ namespace bs
 		if (mObjectRenderer != nullptr)
 		if (mObjectRenderer != nullptr)
 			bs_delete(mObjectRenderer);
 			bs_delete(mObjectRenderer);
 
 
+		for (auto& entry : mRenderables)
+			bs_delete(entry);
+
 		for (auto& entry : mCameras)
 		for (auto& entry : mCameras)
 			bs_delete(entry.second);
 			bs_delete(entry.second);
 
 
@@ -113,20 +116,13 @@ namespace bs
 
 
 		renderable->setRendererId(renderableId);
 		renderable->setRendererId(renderableId);
 
 
-		mRenderables.push_back(RendererObject());
-		mRenderableShaderData.push_back(RenderableShaderData());
+		mRenderables.push_back(bs_new<RendererObject>());
 		mWorldBounds.push_back(renderable->getBounds());
 		mWorldBounds.push_back(renderable->getBounds());
 		mVisibility.push_back(false);
 		mVisibility.push_back(false);
 
 
-		RendererObject& rendererObject = mRenderables.back();
-		rendererObject.renderable = renderable;
-
-		RenderableShaderData& shaderData = mRenderableShaderData.back();
-		shaderData.worldTransform = renderable->getTransform();
-		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
-		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
-		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
-		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
+		RendererObject* rendererObject = mRenderables.back();
+		rendererObject->renderable = renderable;
+		rendererObject->updatePerObjectBuffer();
 
 
 		SPtr<MeshCore> mesh = renderable->getMesh();
 		SPtr<MeshCore> mesh = renderable->getMesh();
 		if (mesh != nullptr)
 		if (mesh != nullptr)
@@ -136,8 +132,8 @@ namespace bs
 
 
 			for (UINT32 i = 0; i < meshProps.getNumSubMeshes(); i++)
 			for (UINT32 i = 0; i < meshProps.getNumSubMeshes(); i++)
 			{
 			{
-				rendererObject.elements.push_back(BeastRenderableElement());
-				BeastRenderableElement& renElement = rendererObject.elements.back();
+				rendererObject->elements.push_back(BeastRenderableElement());
+				BeastRenderableElement& renElement = rendererObject->elements.back();
 
 
 				renElement.mesh = mesh;
 				renElement.mesh = mesh;
 				renElement.subMesh = meshProps.getSubMesh(i);
 				renElement.subMesh = meshProps.getSubMesh(i);
@@ -264,26 +260,7 @@ namespace bs
 					samplerOverrides->refCount++;
 					samplerOverrides->refCount++;
 				}
 				}
 
 
-				mObjectRenderer->initElement(renElement);
-
-				// Set up or find bind spots for relevant GPU param buffers
-				SPtr<ShaderCore> shader = renElement.material->getShader();
-				if (shader != nullptr)
-				{
-					const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlockDescs = shader->getParamBlocks();
-
-					for (auto& paramBlockDesc : paramBlockDescs)
-					{
-						if (paramBlockDesc.second.rendererSemantic == RBS_PerCamera)
-						{
-							renElement.perCameraBindingIdx = renElement.params->getParamBlockBufferIndex(paramBlockDesc.second.name);
-
-							// TODO - Verify size
-						}
-					}
-				}
-				else
-					renElement.perCameraBindingIdx = -1;
+				mObjectRenderer->initElement(*rendererObject, renElement);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -291,10 +268,11 @@ namespace bs
 	void RenderBeast::notifyRenderableRemoved(RenderableCore* renderable)
 	void RenderBeast::notifyRenderableRemoved(RenderableCore* renderable)
 	{
 	{
 		UINT32 renderableId = renderable->getRendererId();
 		UINT32 renderableId = renderable->getRendererId();
-		RenderableCore* lastRenerable = mRenderables.back().renderable;
+		RenderableCore* lastRenerable = mRenderables.back()->renderable;
 		UINT32 lastRenderableId = lastRenerable->getRendererId();
 		UINT32 lastRenderableId = lastRenerable->getRendererId();
 
 
-		Vector<BeastRenderableElement>& elements = mRenderables[renderableId].elements;
+		RendererObject* rendererObject = mRenderables[renderableId];
+		Vector<BeastRenderableElement>& elements = rendererObject->elements;
 		for (auto& element : elements)
 		for (auto& element : elements)
 		{
 		{
 			SamplerOverrideKey samplerKey(element.material, element.techniqueIdx);
 			SamplerOverrideKey samplerKey(element.material, element.techniqueIdx);
@@ -318,7 +296,6 @@ namespace bs
 			// Swap current last element with the one we want to erase
 			// Swap current last element with the one we want to erase
 			std::swap(mRenderables[renderableId], mRenderables[lastRenderableId]);
 			std::swap(mRenderables[renderableId], mRenderables[lastRenderableId]);
 			std::swap(mWorldBounds[renderableId], mWorldBounds[lastRenderableId]);
 			std::swap(mWorldBounds[renderableId], mWorldBounds[lastRenderableId]);
-			std::swap(mRenderableShaderData[renderableId], mRenderableShaderData[lastRenderableId]);
 
 
 			lastRenerable->setRendererId(renderableId);
 			lastRenerable->setRendererId(renderableId);
 
 
@@ -329,21 +306,16 @@ namespace bs
 		// Last element is the one we want to erase
 		// Last element is the one we want to erase
 		mRenderables.erase(mRenderables.end() - 1);
 		mRenderables.erase(mRenderables.end() - 1);
 		mWorldBounds.erase(mWorldBounds.end() - 1);
 		mWorldBounds.erase(mWorldBounds.end() - 1);
-		mRenderableShaderData.erase(mRenderableShaderData.end() - 1);
 		mVisibility.erase(mVisibility.end() - 1);
 		mVisibility.erase(mVisibility.end() - 1);
+
+		bs_delete(rendererObject);
 	}
 	}
 
 
 	void RenderBeast::notifyRenderableUpdated(RenderableCore* renderable)
 	void RenderBeast::notifyRenderableUpdated(RenderableCore* renderable)
 	{
 	{
 		UINT32 renderableId = renderable->getRendererId();
 		UINT32 renderableId = renderable->getRendererId();
 
 
-		RenderableShaderData& shaderData = mRenderableShaderData[renderableId];
-		shaderData.worldTransform = renderable->getTransform();
-		shaderData.invWorldTransform = shaderData.worldTransform.inverseAffine();
-		shaderData.worldNoScaleTransform = renderable->getTransformNoScale();
-		shaderData.invWorldNoScaleTransform = shaderData.worldNoScaleTransform.inverseAffine();
-		shaderData.worldDeterminantSign = shaderData.worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f;
-
+		mRenderables[renderableId]->updatePerObjectBuffer();
 		mWorldBounds[renderableId] = renderable->getBounds();
 		mWorldBounds[renderableId] = renderable->getBounds();
 	}
 	}
 
 
@@ -609,21 +581,23 @@ namespace bs
 		const RendererAnimationData& animData = AnimationManager::instance().getRendererData();
 		const RendererAnimationData& animData = AnimationManager::instance().getRendererData();
 		RendererFrame frameInfo(delta, animData);
 		RendererFrame frameInfo(delta, animData);
 
 
-		// Update bone matrix and morph shape GPU buffers
+		// Update per-object, bone matrix and morph shape GPU buffers
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
 		{
 		{
 			if (!mVisibility[i])
 			if (!mVisibility[i])
 				continue;
 				continue;
 
 
-			mRenderables[i].renderable->updateAnimationBuffers(animData);
+			// Note: Before uploading bone matrices perhaps check if they has actually been changed since last frame
+			mRenderables[i]->renderable->updateAnimationBuffers(animData);
 
 
-			// TODO - Also move per-object buffer updates here (will require worldViewProj matrix to be moved to a separate buffer (or a push constant))
-			// TODO - Before uploading bone matrices and per-object data, check if it has actually been changed since last frame (most objects will be static)
-			// TODO - Also move per-camera buffer updates in a separate loop
-		}
+			// Note: Could this step be moved in notifyRenderableUpdated, so it only triggers when material actually gets
+			// changed? Although it shouldn't matter much because if the internal dirty flags.
+			for (auto& element : mRenderables[i]->elements)
+				element.material->updateParamsSet(element.params, element.techniqueIdx);
 
 
-		// TODO - When porting to Vulkan, start upload and issue barrier (but somehow avoid blocking too long here?)
+			mRenderables[i]->perObjectParams.flushToGPU();
+		}
 
 
 		// Render everything, target by target
 		// Render everything, target by target
 		for (auto& rtInfo : mRenderTargets)
 		for (auto& rtInfo : mRenderTargets)
@@ -661,7 +635,11 @@ namespace bs
 
 
 		assert(!camera->getFlags().isSet(CameraFlag::Overlay));
 		assert(!camera->getFlags().isSet(CameraFlag::Overlay));
 
 
-		// Assign camera data to all relevant renderables
+		Matrix4 proj = camera->getProjectionMatrixRS();
+		Matrix4 view = camera->getViewMatrix();
+		Matrix4 viewProj = proj * view;
+
+		// Assign camera and per-call data to all relevant renderables
 		const Vector<bool>& visibility = rendererCam->getVisibilityMask();
 		const Vector<bool>& visibility = rendererCam->getVisibilityMask();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
@@ -669,17 +647,16 @@ namespace bs
 			if (!visibility[i])
 			if (!visibility[i])
 				continue;
 				continue;
 
 
-			for (auto& element : mRenderables[i].elements)
+			RendererObject* rendererObject = mRenderables[i];
+			rendererObject->updatePerCallBuffer(viewProj);
+
+			for (auto& element : mRenderables[i]->elements)
 			{
 			{
 				if (element.perCameraBindingIdx != -1)
 				if (element.perCameraBindingIdx != -1)
 					element.params->setParamBlockBuffer(element.perCameraBindingIdx, parCameraBuffer.getBuffer(), true);
 					element.params->setParamBlockBuffer(element.perCameraBindingIdx, parCameraBuffer.getBuffer(), true);
 			}
 			}
 		}
 		}
 
 
-		Matrix4 proj = camera->getProjectionMatrixRS();
-		Matrix4 view = camera->getViewMatrix();
-		Matrix4 viewProj = proj * view;
-
 		rendererCam->beginRendering(true);
 		rendererCam->beginRendering(true);
 
 
 		SPtr<RenderTargets> renderTargets = rendererCam->getRenderTargets();
 		SPtr<RenderTargets> renderTargets = rendererCam->getRenderTargets();
@@ -703,8 +680,6 @@ namespace bs
 			}
 			}
 		}
 		}
 
 
-
-		
 		//// Render base pass
 		//// Render base pass
 		const Vector<RenderQueueElement>& opaqueElements = rendererCam->getOpaqueQueue()->getSortedElements();
 		const Vector<RenderQueueElement>& opaqueElements = rendererCam->getOpaqueQueue()->getSortedElements();
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
@@ -884,13 +859,6 @@ namespace bs
 	{
 	{
 		SPtr<MaterialCore> material = element.material;
 		SPtr<MaterialCore> material = element.material;
 
 
-		UINT32 rendererId = element.renderableId;
-		Matrix4 worldViewProjMatrix = viewProj * mRenderableShaderData[rendererId].worldTransform;
-		SPtr<GpuBufferCore> boneMatrices = element.boneMatrixBuffer;
-
-		mObjectRenderer->setPerObjectParams(element, mRenderableShaderData[rendererId], worldViewProjMatrix, boneMatrices);
-		material->updateParamsSet(element.params, element.techniqueIdx);
-
 		if (bindPass)
 		if (bindPass)
 			gRendererUtility().setPass(material, passIdx, element.techniqueIdx);
 			gRendererUtility().setPass(material, passIdx, element.techniqueIdx);
 
 
@@ -947,7 +915,7 @@ namespace bs
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
 		{
 		{
-			for(auto& element : mRenderables[i].elements)
+			for(auto& element : mRenderables[i]->elements)
 			{
 			{
 				MaterialSamplerOverrides* overrides = element.samplerOverrides;
 				MaterialSamplerOverrides* overrides = element.samplerOverrides;
 				if(overrides != nullptr && overrides->isDirty)
 				if(overrides != nullptr && overrides->isDirty)

+ 3 - 3
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -78,7 +78,7 @@ namespace bs
 		}
 		}
 	}
 	}
 
 
-	void RendererCamera::determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds, 
+	void RendererCamera::determineVisible(const Vector<RendererObject*>& renderables, const Vector<Bounds>& renderableBounds,
 		Vector<bool>& visibility)
 		Vector<bool>& visibility)
 	{
 	{
 		mVisibility.clear();
 		mVisibility.clear();
@@ -94,7 +94,7 @@ namespace bs
 		// Update per-object param buffers and queue render elements
 		// Update per-object param buffers and queue render elements
 		for(UINT32 i = 0; i < (UINT32)renderables.size(); i++)
 		for(UINT32 i = 0; i < (UINT32)renderables.size(); i++)
 		{
 		{
-			RenderableCore* renderable = renderables[i].renderable;
+			RenderableCore* renderable = renderables[i]->renderable;
 			UINT32 rendererId = renderable->getRendererId();
 			UINT32 rendererId = renderable->getRendererId();
 
 
 			if ((renderable->getLayer() & cameraLayers) == 0)
 			if ((renderable->getLayer() & cameraLayers) == 0)
@@ -116,7 +116,7 @@ namespace bs
 
 
 					float distanceToCamera = (mCamera->getPosition() - boundingBox.getCenter()).length();
 					float distanceToCamera = (mCamera->getPosition() - boundingBox.getCenter()).length();
 
 
-					for (auto& renderElem : renderables[i].elements)
+					for (auto& renderElem : renderables[i]->elements)
 					{
 					{
 						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
 						bool isTransparent = (renderElem.material->getShader()->getFlags() & (UINT32)ShaderFlags::Transparent) != 0;
 
 

+ 28 - 0
Source/RenderBeast/Source/BsRendererObject.cpp

@@ -0,0 +1,28 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsRendererObject.h"
+
+namespace bs
+{
+	void RendererObject::updatePerObjectBuffer()
+	{
+		Matrix4 worldTransform = renderable->getTransform();
+		Matrix4 worldNoScaleTransform = renderable->getTransformNoScale();
+
+		perObjectParams.gMatWorld.set(worldTransform);
+		perObjectParams.gMatInvWorld.set(worldTransform.inverseAffine());
+		perObjectParams.gMatWorldNoScale.set(worldNoScaleTransform);
+		perObjectParams.gMatInvWorldNoScale.set(worldNoScaleTransform.inverseAffine());
+		perObjectParams.gWorldDeterminantSign.set(worldTransform.determinant3x3() >= 0.0f ? 1.0f : -1.0f);
+	}
+
+	void RendererObject::updatePerCallBuffer(const Matrix4& viewProj, bool flush)
+	{
+		Matrix4 worldViewProjMatrix = viewProj * renderable->getTransform();
+
+		perCallParams.gMatWorldViewProj.set(worldViewProjMatrix);
+
+		if(flush)
+			perCallParams.flushToGPU();
+	}
+}