Przeglądaj źródła

Added better handle/gizmo shaders
Fixed an issue with cone shape mesh generation

Marko Pintera 10 lat temu
rodzic
commit
246f5b3acb

+ 1 - 0
BansheeCore/Include/BsCoreRenderer.h

@@ -27,6 +27,7 @@ namespace BansheeEngine
 	static StringID RPS_ViewProjTfrm = "VP";
 	static StringID RPS_WorldTfrm = "World";
 	static StringID RPS_Diffuse = "Diffuse";
+	static StringID RPS_ViewDir = "ViewDir";
 
 	/**
 	 * @brief	Primarily rendering class that allows you to specify how to render objects that exist

+ 40 - 1
BansheeCore/Include/BsGpuParam.h

@@ -114,6 +114,14 @@ namespace BansheeEngine
 		 */
 		T get(UINT32 arrayIdx = 0);
 
+		/**
+		 * @brief	Checks if param is initialized.
+		 */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
 	protected:
 		GpuParamsType mParent;
 		GpuParamDataDesc* mParamDesc;
@@ -146,12 +154,19 @@ namespace BansheeEngine
 		 */
 		void get(void* value, UINT32 sizeBytes, UINT32 arrayIdx = 0);
 
-
 		/**
 		 * @brief	Returns the size of the struct in bytes.
 		 */
 		UINT32 getElementSize() const;
 
+		/**
+		 * @brief	Checks if param is initialized.
+		 */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
 	protected:
 		GpuParamsType mParent;
 		GpuParamDataDesc* mParamDesc;
@@ -184,6 +199,14 @@ namespace BansheeEngine
 		 */
 		TextureType get();
 
+		/**
+		 * @brief	Checks if param is initialized.
+		 */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
 	protected:
 		GpuParamsType mParent;
 		GpuParamObjectDesc* mParamDesc;
@@ -216,6 +239,14 @@ namespace BansheeEngine
 		 */
 		TextureType get();
 
+		/**
+		 * @brief	Checks if param is initialized.
+		 */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
 	protected:
 		GpuParamsType mParent;
 		GpuParamObjectDesc* mParamDesc;
@@ -248,6 +279,14 @@ namespace BansheeEngine
 		 */
 		SamplerStateType get();
 
+		/**
+		 * @brief	Checks if param is initialized.
+		 */
+		bool operator==(const nullptr_t &nullval) const
+		{
+			return mParamDesc == nullptr;
+		}
+
 	protected:
 		GpuParamsType mParent;
 		GpuParamObjectDesc* mParamDesc;

+ 2 - 1
BansheeEditor/Include/BsGizmoManager.h

@@ -176,6 +176,7 @@ namespace BansheeEngine
 		{
 			SPtr<MaterialCore> mat;
 			GpuParamMat4Core mViewProj;
+			GpuParamVec4Core mViewDir;
 		};
 
 		struct WireMaterialData
@@ -215,7 +216,7 @@ namespace BansheeEngine
 		void initialize(const GizmoManager::CoreInitData& initData);
 
 		void render();
-		void renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material);
+		void renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, Vector3 viewDir, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material);
 		void renderIconGizmos(Rect2I screenArea, SPtr<MeshCoreBase> mesh, GizmoManager::IconRenderDataVecPtr renderData, bool usePickingMaterial);
 
 		void updateData(const SPtr<CameraHandlerCore>& camera, const SPtr<MeshCoreBase>& solidMesh, const SPtr<MeshCoreBase>& wireMesh,

+ 1 - 0
BansheeEditor/Include/BsHandleDrawManager.h

@@ -51,6 +51,7 @@ namespace BansheeEngine
 		{
 			SPtr<MaterialCore> mat;
 			GpuParamMat4Core mViewProj;
+			GpuParamVec4Core mViewDir;
 		};
 
 		struct WireMaterialData

+ 3 - 3
BansheeEditor/Source/BsEditorApplication.cpp

@@ -138,9 +138,9 @@ namespace BansheeEngine
 		MainEditorWindow* mainWindow = MainEditorWindow::create(getPrimaryWindow());
 		loadPlugin("SBansheeEditor", &mSBansheeEditorPlugin); // Managed part of the editor
 
-		EditorWidgetLayoutPtr layout = loadWidgetLayout();
-		if (layout != nullptr)
-			EditorWidgetManager::instance().setLayout(layout);
+		//EditorWidgetLayoutPtr layout = loadWidgetLayout();
+		//if (layout != nullptr)
+		//	EditorWidgetManager::instance().setLayout(layout);
 
 		BuildManager::instance().load(BUILD_DATA_PATH);
 

+ 8 - 5
BansheeEditor/Source/BsGizmoManager.cpp

@@ -365,12 +365,12 @@ namespace BansheeEngine
 			if (meshData.type == DrawHelper::MeshType::Solid)
 			{
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					mCore, viewMat, projMat, meshData.mesh->getCore(), GizmoMaterial::Picking));
+					mCore, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
 			}
 			else // Wire
 			{
 				gCoreAccessor().queueCommand(std::bind(&GizmoManagerCore::renderGizmos,
-					mCore, viewMat, projMat, meshData.mesh->getCore(), GizmoMaterial::Picking));
+					mCore, viewMat, projMat, camera->getForward(), meshData.mesh->getCore(), GizmoMaterial::Picking));
 			}
 		}
 
@@ -655,8 +655,10 @@ namespace BansheeEngine
 		{
 			SPtr<MaterialCore> mat = mSolidMaterial.mat;
 			SPtr<GpuParamsCore> vertParams = mat->getPassParameters(0)->mVertParams;
+			SPtr<GpuParamsCore> fragParams = mat->getPassParameters(0)->mFragParams;
 
 			vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
+			fragParams->getParam("viewDir", mSolidMaterial.mViewDir);
 		}
 
 		{
@@ -739,16 +741,16 @@ namespace BansheeEngine
 		screenArea.height = (int)(normArea.height * height);
 
 		if (mSolidMesh != nullptr)
-			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mSolidMesh, GizmoManager::GizmoMaterial::Solid);
+			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mCamera->getForward(), mSolidMesh, GizmoManager::GizmoMaterial::Solid);
 
 		if (mWireMesh != nullptr)
-			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mWireMesh, GizmoManager::GizmoMaterial::Wire);
+			renderGizmos(mCamera->getViewMatrix(), mCamera->getProjectionMatrixRS(), mCamera->getForward(), mWireMesh, GizmoManager::GizmoMaterial::Wire);
 
 		if (mIconMesh != nullptr)
 			renderIconGizmos(screenArea, mIconMesh, mIconRenderData, false);
 	}
 
-	void GizmoManagerCore::renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material)
+	void GizmoManagerCore::renderGizmos(Matrix4 viewMatrix, Matrix4 projMatrix, Vector3 viewDir, SPtr<MeshCoreBase> mesh, GizmoManager::GizmoMaterial material)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
@@ -758,6 +760,7 @@ namespace BansheeEngine
 		{
 		case GizmoManager::GizmoMaterial::Solid:
 			mSolidMaterial.mViewProj.set(viewProjMat);
+			mSolidMaterial.mViewDir.set((Vector4)viewDir);
 			CoreRenderer::setPass(mSolidMaterial.mat, 0);
 			break;
 		case GizmoManager::GizmoMaterial::Wire:

+ 3 - 1
BansheeEditor/Source/BsHandleDrawManager.cpp

@@ -183,7 +183,6 @@ namespace BansheeEngine
 
 	void HandleDrawManagerCore::initialize(const SPtr<MaterialCore>& wireMat, const SPtr<MaterialCore>& solidMat)
 	{
-		// TODO - Make a better interface when dealing with parameters through proxies?
 		{
 			mWireMaterial.mat = wireMat;
 			SPtr<GpuParamsCore> vertParams = wireMat->getPassParameters(0)->mVertParams;
@@ -194,8 +193,10 @@ namespace BansheeEngine
 		{
 			mSolidMaterial.mat = solidMat;
 			SPtr<GpuParamsCore> vertParams = solidMat->getPassParameters(0)->mVertParams;
+			SPtr<GpuParamsCore> fragParams = solidMat->getPassParameters(0)->mFragParams;
 
 			vertParams->getParam("matViewProj", mSolidMaterial.mViewProj);
+			fragParams->getParam("viewDir", mSolidMaterial.mViewDir);
 		}
 	}
 
@@ -237,6 +238,7 @@ namespace BansheeEngine
 
 		Matrix4 viewProjMat = mCamera->getProjectionMatrixRS() * mCamera->getViewMatrix();
 		mSolidMaterial.mViewProj.set(viewProjMat);
+		mSolidMaterial.mViewDir.set((Vector4)mCamera->getForward());
 		mWireMaterial.mViewProj.set(viewProjMat);
 
 		MeshType currentType = MeshType::Solid;

+ 7 - 0
BansheeEngine/Include/BsCameraHandler.h

@@ -106,6 +106,13 @@ namespace BansheeEngine
 		 */
 		virtual Vector3 getPosition() const { return mPosition; }
 
+		/**
+		 * @brief	Gets the Z (forward) axis of the object, in world space.
+		 *
+		 * @return	Forward axis of the object.
+		 */
+		Vector3 getForward() const { return getRotation().rotate(-Vector3::UNIT_Z); }
+
 		/**
 		 * @brief	Sets camera world space rotation.
 		 */

+ 38 - 25
BansheeEngine/Source/BsShapeMeshes3D.cpp

@@ -291,7 +291,7 @@ namespace BansheeEngine
 
 	void ShapeMeshes3D::getNumElementsCone(UINT32 quality, UINT32& numVertices, UINT32& numIndices)
 	{
-		numVertices = ((quality + 1) * 4 + 1) * 2;
+		numVertices = ((quality + 1) * 4) * 3 + 1;
 		numIndices = ((quality + 1) * 4) * 6;
 	}
 
@@ -619,59 +619,72 @@ namespace BansheeEngine
 		for (UINT32 i = 0; i < numTriangles - 1; i++)
 		{
 			outIndices[i * 3 + 0] = vertexOffset + baseIdx;
-			outIndices[i * 3 + 1] = vertexOffset + i;
-			outIndices[i * 3 + 2] = vertexOffset + i + 1;
+			outIndices[i * 3 + 1] = vertexOffset + i + 1;
+			outIndices[i * 3 + 2] = vertexOffset + i;
 		}
 
 		{
 			UINT32 i = numTriangles - 1;
 			outIndices[i * 3 + 0] = vertexOffset + baseIdx;
-			outIndices[i * 3 + 1] = vertexOffset + i;
-			outIndices[i * 3 + 2] = vertexOffset + 0;
+			outIndices[i * 3 + 1] = vertexOffset + 0;
+			outIndices[i * 3 + 2] = vertexOffset + i;
 		}
 
-		// Generate cone
+		//// Generate cone
+		// Base vertices
 		generateArcVertices(base, normal, radius, Degree(0), Degree(360),
 			numArcVertices + 1, outVertices, 0, vertexStride);
 
 		Vector3 topVertex = base + normal * height;
 
-		UINT32 totalNumConeVertices = numArcVertices;
-		for (UINT32 i = 0; i < totalNumConeVertices; i++)
+		// Normals
+		UINT8* outNormalsBase = outNormals;
+		UINT8* outNormalsTop = outNormals + numArcVertices * vertexStride;
+		for (INT32 i = 0; i < (INT32)numArcVertices; i++)
 		{
-			int offsetA = i;
-			int offsetB = (i + 1) % totalNumConeVertices;
+			int offsetA = i == 0 ? numArcVertices - 1 : i - 1;
+			int offsetB = i;
+			int offsetC = (i + 1) % numArcVertices;
 
 			Vector3* a = (Vector3*)(outVertices + (offsetA * vertexStride));
 			Vector3* b = (Vector3*)(outVertices + (offsetB * vertexStride));
+			Vector3* c = (Vector3*)(outVertices + (offsetC * vertexStride));
 
-			Vector3 triNormal = *a - topVertex;
-			triNormal = triNormal.cross(*b - topVertex);
-			triNormal.normalize();
+			Vector3 toTop = topVertex - *b;
 
-			outNormals = writeVector3(outNormals, vertexStride, triNormal); // TODO - Smooth normals?
-		}
+			Vector3 normalLeft = Vector3::cross(*a - *b, toTop);
+			normalLeft.normalize();
+
+			Vector3 normalRight = Vector3::cross(toTop, *c - *b);
+			normalRight.normalize();
 
-		*(Vector3*)outNormals = normal;
+			Vector3 triNormal = Vector3::normalize(normalLeft + normalRight);
 
+			outNormalsBase = writeVector3(outNormalsBase, vertexStride, triNormal);
+			outNormalsTop = writeVector3(outNormalsTop, vertexStride, triNormal);
+		}
+
+		// Top vertices (All same position, but need them separate because of different normals)
 		outVertices += numArcVertices * vertexStride;
-		outVertices = writeVector3(outVertices, vertexStride, topVertex); // Write top vertex
-		UINT32 topIdx = numArcVertices;
+
+		for (UINT32 i = 0; i < numArcVertices; i++)
+			outVertices = writeVector3(outVertices, vertexStride, topVertex);
 
 		outIndices += numTriangles * 3;
-		UINT32 curVertOffset = vertexOffset + numArcVertices + 1;
+		UINT32 curVertBaseOffset = vertexOffset + numArcVertices + 1;
+		UINT32 curVertTopOffset = curVertBaseOffset + numArcVertices;
 		for (UINT32 i = 0; i < numTriangles - 1; i++)
 		{
-			outIndices[i * 3 + 0] = curVertOffset + topIdx;
-			outIndices[i * 3 + 1] = curVertOffset + i + 1;
-			outIndices[i * 3 + 2] = curVertOffset + i;
+			outIndices[i * 3 + 0] = curVertTopOffset + i;
+			outIndices[i * 3 + 1] = curVertBaseOffset + i;
+			outIndices[i * 3 + 2] = curVertBaseOffset + i + 1;
 		}
 
 		{
 			UINT32 i = numTriangles - 1;
-			outIndices[i * 3 + 0] = curVertOffset + topIdx;
-			outIndices[i * 3 + 1] = curVertOffset + 0;
-			outIndices[i * 3 + 2] = curVertOffset + i;
+			outIndices[i * 3 + 0] = curVertTopOffset + i;
+			outIndices[i * 3 + 1] = curVertBaseOffset + i;
+			outIndices[i * 3 + 2] = curVertBaseOffset + 0;
 		}
 	}
 

+ 16 - 6
BansheeRenderer/Include/BsBansheeLitTexRenderableController.h

@@ -25,7 +25,6 @@ namespace BansheeEngine
 		{
 			SPtr<GpuParamBlockBufferCore> perObjectParamBuffer;
 
-			bool hasWVPParam = false;
 			GpuParamMat4Core wvpParam;
 
 			Vector<RenderableElement::BufferBindInfo> perObjectBuffers;
@@ -36,18 +35,24 @@ namespace BansheeEngine
 		/**
 		 * @copydoc	RenderableHandler::initializeRenderElem
 		 */
-		void initializeRenderElem(RenderableElement& element);
+		void initializeRenderElem(RenderableElement& element) override;
 
 		/**
 		 * @copydoc	RenderableHandler::bindPerObjectBuffers
 		 */
-		void bindPerObjectBuffers(const RenderableElement& element);
+		void bindPerObjectBuffers(const RenderableElement& element) override;
 
 		/**
-		 * @brief	Updates global parameter buffers with new values. 
-		 *			To be called whenever global values change.
+		 * @brief	Updates global per frame parameter buffers with new values. 
+		 *			To be called at the start of every frame.
 		 */
-		void updateGlobalBuffers(float time);
+		void updatePerFrameBuffers(float time);
+
+		/**
+		 * @brief	Updates global per frame parameter buffers with new values. 
+		 *			To be called at the start of rendering for every camera.
+		 */
+		void updatePerCameraBuffers(const Vector3& viewDir);
 
 		/**
 		 * @brief	Updates object specific parameter buffers with new values.
@@ -67,19 +72,24 @@ namespace BansheeEngine
 
 		GpuParamBlockDesc staticParamBlockDesc;
 		GpuParamBlockDesc perFrameParamBlockDesc;
+		GpuParamBlockDesc perCameraParamBlockDesc;
 		GpuParamBlockDesc perObjectParamBlockDesc;
 
 		GpuParamDataDesc timeParamDesc;
 		GpuParamDataDesc lightDirParamDesc;
 		GpuParamDataDesc wvpParamDesc;
+		GpuParamDataDesc viewDirParamDesc;
 
 		SPtr<GpuParamBlockBufferCore> staticParamBuffer;
 		SPtr<GpuParamBlockBufferCore> perFrameParamBuffer;
+		SPtr<GpuParamBlockBufferCore> perCameraParamBuffer;
 
 		SPtr<GpuParamsCore> staticParams;
 		SPtr<GpuParamsCore> perFrameParams;
+		SPtr<GpuParamsCore> perCameraParams;
 
 		GpuParamVec4Core lightDirParam;
+		GpuParamVec3Core viewDirParam;
 		GpuParamFloatCore timeParam;
 	};
 }

+ 73 - 13
BansheeRenderer/Source/BsBansheeLitTexRenderableController.cpp

@@ -24,13 +24,16 @@ namespace BansheeEngine
 		GpuParamDescPtr staticParamsDesc = bs_shared_ptr<GpuParamDesc>();
 		GpuParamDescPtr perFrameParamsDesc = bs_shared_ptr<GpuParamDesc>();
 		GpuParamDescPtr perObjectParamsDesc = bs_shared_ptr<GpuParamDesc>();
+		GpuParamDescPtr perCameraParamsDesc = bs_shared_ptr<GpuParamDesc>();
 
 		bool foundLightDir = false;
 		bool foundTime = false;
 		bool foundWVP = false;
+		bool foundViewDir = false;
 		bool foundStatic = false;
 		bool foundPerFrame = false;
 		bool foundPerObject = false;
+		bool foundPerCamera = false;
 
 		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams = defaultShader->getDataParams();
 		for (auto& param : dataParams)
@@ -65,6 +68,16 @@ namespace BansheeEngine
 				perObjectParamsDesc->params[iterFind->first] = iterFind->second;
 				foundWVP = true;
 			}
+			else if (!foundViewDir && param.second.rendererSemantic == RPS_ViewDir)
+			{
+				auto iterFind = fragParamDesc->params.find(param.second.gpuVariableName);
+				if (iterFind == fragParamDesc->params.end())
+					continue;
+
+				viewDirParamDesc = iterFind->second;
+				perCameraParamsDesc->params[iterFind->first] = iterFind->second;
+				foundViewDir = true;
+			}
 		}
 
 		const Map<String, SHADER_PARAM_BLOCK_DESC>& paramBlocks = defaultShader->getParamBlocks();
@@ -90,6 +103,16 @@ namespace BansheeEngine
 				perFrameParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
 				foundPerFrame = true;
 			}
+			else if (!foundPerCamera && block.second.rendererSemantic == RBS_PerCamera)
+			{
+				auto iterFind = fragParamDesc->paramBlocks.find(block.second.name);
+				if (iterFind == fragParamDesc->paramBlocks.end())
+					continue;
+
+				perCameraParamBlockDesc = iterFind->second;
+				perCameraParamsDesc->paramBlocks[iterFind->first] = iterFind->second;
+				foundPerCamera = true;
+			}
 			else if (!foundPerObject && block.second.rendererSemantic == RBS_PerObject)
 			{
 				auto iterFind = vertParamDesc->paramBlocks.find(block.second.name);
@@ -102,23 +125,28 @@ namespace BansheeEngine
 			}
 		}
 
-		if (!foundLightDir || !foundTime || !foundWVP || !foundStatic || !foundPerFrame || !foundPerObject)
+		if (!foundLightDir || !foundTime || !foundWVP || !foundViewDir || !foundStatic || !foundPerFrame || !foundPerCamera || !foundPerObject)
 			BS_EXCEPT(InternalErrorException, "Invalid default shader.");
 
 		// Create global GPU param buffers and get parameter handles
 		staticParams = GpuParamsCore::create(staticParamsDesc, false);
 		perFrameParams = GpuParamsCore::create(perFrameParamsDesc, false);
+		perCameraParams = GpuParamsCore::create(perCameraParamsDesc, false);
 
 		staticParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(staticParamBlockDesc.blockSize * sizeof(UINT32));
 		perFrameParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perFrameParamBlockDesc.blockSize * sizeof(UINT32));
+		perCameraParamBuffer = HardwareBufferCoreManager::instance().createGpuParamBlockBuffer(perCameraParamBlockDesc.blockSize * sizeof(UINT32));
 
 		staticParams->setParamBlockBuffer(staticParamBlockDesc.slot, staticParamBuffer);
 		perFrameParams->setParamBlockBuffer(perFrameParamBlockDesc.slot, perFrameParamBuffer);
+		perCameraParams->setParamBlockBuffer(perCameraParamBlockDesc.slot, perCameraParamBuffer);
 
 		staticParams->getParam(lightDirParamDesc.name, lightDirParam);
 		perFrameParams->getParam(timeParamDesc.name, timeParam);
+		perCameraParams->getParam(viewDirParamDesc.name, viewDirParam);
 
 		lightDirParam.set(Vector4(0.707f, 0.707f, 0.707f, 0.0f));
+		staticParams->updateHardwareBuffers();
 	}
 
 	void LitTexRenderableController::initializeRenderElem(RenderableElement& element)
@@ -143,6 +171,7 @@ namespace BansheeEngine
 		const Map<String, SHADER_DATA_PARAM_DESC>& dataParamDescs = shader->getDataParams();
 		String staticBlockName;
 		String perFrameBlockName;
+		String perCameraBlockName;
 		String perObjectBlockName;
 
 		String wvpParamName;
@@ -151,8 +180,10 @@ namespace BansheeEngine
 		{
 			if (paramBlockDesc.second.rendererSemantic == RBS_Static)
 				staticBlockName = paramBlockDesc.second.name;
-			else if(paramBlockDesc.second.rendererSemantic == RBS_PerFrame)
+			else if (paramBlockDesc.second.rendererSemantic == RBS_PerFrame)
 				perFrameBlockName = paramBlockDesc.second.name;
+			else if (paramBlockDesc.second.rendererSemantic == RBS_PerCamera)
+				perCameraBlockName = paramBlockDesc.second.name;
 			else if (paramBlockDesc.second.rendererSemantic == RBS_PerObject)
 				perObjectBlockName = paramBlockDesc.second.name;
 		}
@@ -204,6 +235,19 @@ namespace BansheeEngine
 					}
 				}
 
+				if (perCameraBlockName != "")
+				{
+					auto findIter = paramsDesc.paramBlocks.find(perCameraBlockName);
+					if (findIter != paramsDesc.paramBlocks.end())
+					{
+						if (findIter->second.blockSize == perCameraParamBlockDesc.blockSize)
+						{
+							UINT32 slotIdx = findIter->second.slot;
+							element.rendererBuffers.push_back(RenderableElement::BufferBindInfo(i, j, slotIdx, perCameraParamBuffer));
+						}
+					}
+				}
+
 				if (perObjectBlockName != "")
 				{
 					auto findIter = paramsDesc.paramBlocks.find(perObjectBlockName);
@@ -216,16 +260,13 @@ namespace BansheeEngine
 
 							rendererData->perObjectBuffers.push_back(RenderableElement::BufferBindInfo(i, j, findIter->second.slot, rendererData->perObjectParamBuffer));
 
-							if (!rendererData->hasWVPParam && wvpParamName != "")
+							if (rendererData->wvpParam == nullptr && wvpParamName != "")
 							{
 								auto findIter2 = paramsDesc.params.find(wvpParamName);
 								if (findIter2 != paramsDesc.params.end())
 								{
 									if (paramsMatch(findIter2->second, wvpParamDesc))
-									{
 										gpuParams->getParam(wvpParamName, rendererData->wvpParam);
-										rendererData->hasWVPParam = true;
-									}
 								}
 							}
 						}
@@ -248,20 +289,25 @@ namespace BansheeEngine
 		}
 	}
 
-	void LitTexRenderableController::updateGlobalBuffers(float time)
+	void LitTexRenderableController::updatePerFrameBuffers(float time)
 	{
 		timeParam.set(time);
 
-		staticParams->updateHardwareBuffers();
 		perFrameParams->updateHardwareBuffers();
 	}
 
+	void LitTexRenderableController::updatePerCameraBuffers(const Vector3& viewDir)
+	{
+		viewDirParam.set(viewDir);
+
+		perCameraParams->updateHardwareBuffers();
+	}
+
 	void LitTexRenderableController::updatePerObjectBuffers(RenderableElement& element, const Matrix4& wvpMatrix)
 	{
 		PerObjectData* rendererData = any_cast_unsafe<PerObjectData>(&element.rendererData);
 
-		if (rendererData->hasWVPParam)
-			rendererData->wvpParam.set(wvpMatrix);
+		rendererData->wvpParam.set(wvpMatrix);
 
 		if (rendererData->perObjectParamBuffer != nullptr)
 			rendererData->perObjectParamBuffer->flushToGPU();
@@ -298,10 +344,15 @@ namespace BansheeEngine
 			{
 				float4 lightDir;
 			}
+
+			cbuffer PerCamera
+			{
+				float3 viewDir;
+			}
 			
 			float4 ps_main() : SV_Target
 			{
-				return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
+				return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f)) + dot(viewDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
 			})";	
 
 			vsProgram = GpuProgramCore::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
@@ -324,12 +375,14 @@ namespace BansheeEngine
 
 			String psCode = R"(
 			BS_PARAM_BLOCK Static { lightDir }
+			BS_PARAM_BLOCK PerCamera { viewDir }
 
 			float4 lightDir;
+			float3 viewDir;
 
 			float4 ps_main() : COLOR0
 			{
-				return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
+				return dot(lightDir, float4(0.5f, 0.5f, 0.5f, 0.5f)) + dot(viewDir, float4(0.5f, 0.5f, 0.5f, 0.5f));
 			})";
 
 			vsProgram = GpuProgramCore::create(vsCode, "vs_main", "hlsl9", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
@@ -366,11 +419,16 @@ namespace BansheeEngine
 				vec4 lightDir;
 			};
 
+			uniform PerCamera
+			{
+				vec3 viewDir;
+			}
+
 			out vec4 fragColor;
 
 			void main()
 			{
-				fragColor = lightDir * vec4(0.5f, 0.5f, 0.5f, 0.5f);
+				fragColor = lightDir * vec4(0.5f, 0.5f, 0.5f, 0.5f) + viewDir * vec4(0.5f, 0.5f 0.5f, 0.5f);
 			})";
 
 			vsProgram = GpuProgramCore::create(vsCode, "main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
@@ -387,10 +445,12 @@ namespace BansheeEngine
 		SHADER_DESC_CORE shaderDesc;
 		shaderDesc.setParamBlockAttribs("Static", true, GPBU_DYNAMIC, RBS_Static);
 		shaderDesc.setParamBlockAttribs("PerFrame", true, GPBU_DYNAMIC, RBS_PerFrame);
+		shaderDesc.setParamBlockAttribs("PerCamera", true, GPBU_DYNAMIC, RBS_PerCamera);
 		shaderDesc.setParamBlockAttribs("PerObject", true, GPBU_DYNAMIC, RBS_PerObject);
 
 		shaderDesc.addParameter("lightDir", "lightDir", GPDT_FLOAT4, RPS_LightDir);
 		shaderDesc.addParameter("time", "time", GPDT_FLOAT1, RPS_Time);
+		shaderDesc.addParameter("viewDir", "viewDir", GPDT_FLOAT4, RPS_ViewDir);
 		shaderDesc.addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4, RPS_WorldViewProjTfrm);
 
 		SPtr<ShaderCore> defaultShader = ShaderCore::create("LitTexDefault", shaderDesc, { newTechnique });

+ 5 - 2
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -212,8 +212,8 @@ namespace BansheeEngine
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		// Update global hardware buffers
-		mLitTexHandler->updateGlobalBuffers(time);
+		// Update global per-frame hardware buffers
+		mLitTexHandler->updatePerFrameBuffers(time);
 
 		// Sort cameras by render target
 		for (auto& cameraData : mCameraData)
@@ -295,6 +295,9 @@ namespace BansheeEngine
 
 		RenderAPICore& rs = RenderAPICore::instance();
 
+		// Update global per-frame hardware buffers
+		mLitTexHandler->updatePerCameraBuffers(camera.getForward());
+
 		Matrix4 projMatrixCstm = camera.getProjectionMatrixRS();
 		Matrix4 viewMatrixCstm = camera.getViewMatrix();
 

+ 5 - 0
TODO.txt

@@ -56,6 +56,11 @@ Code quality improvements:
 ----------------------------------------------------------------------
 Polish stage 1
 
+Handle cones are either inside out or have incorrect normals
+Re-enable widget layout loading
+Fix a crash when re-opening scene window
+Crash in DefaultHandleManager.PreInput when just flying around the scene while having a handle active and hovering over it a few times
+
 After undocking ProjectWindow the auto-scroll seems to be stuck in up position
 When selecting an gizmo icon the selection seems delayed and its gizmos flash for a frame before hiding (Can't reproduce atm but I saw it)
 Main window resize areas don't seem to be set up or work