2
0
Эх сурвалжийг харах

Code quality and UX tweaks

marco.bellan 9 жил өмнө
parent
commit
aed8ff2d1c

+ 8 - 3
Source/BansheeCore/Include/BsPixelData.h

@@ -326,11 +326,16 @@ namespace BansheeEngine
 		 */
 		 */
 		void setColors(Color* colors, UINT32 numElements);
 		void setColors(Color* colors, UINT32 numElements);
 
 
-		/** Returns depth at the specified coordinates. */
+		/** 
+		 * Decodes data stored in a depth texture at the specified pixel coordinates, and outputs a floating point depth
+		 * value in range [0, 1]. 
+		 */
 		float getDepthAt(UINT32 x, UINT32 y, UINT32 z = 0) const;
 		float getDepthAt(UINT32 x, UINT32 y, UINT32 z = 0) const;
 
 
-		/** Sets the depth at the specified coordinates. */
-		void setDepthAt(float const &cv, UINT32 x, UINT32 y, UINT32 z = 0);
+		/** 
+		 * Sets a depth value in range [0, 1] at the specified pixel coordinates.
+		 */
+		void setDepthAt(const float& depth, UINT32 x, UINT32 y, UINT32 z = 0);
 
 
 		/**
 		/**
 		* Converts all the internal data into an array of float. Array is mapped as such:
 		* Converts all the internal data into an array of float. Array is mapped as such:

+ 3 - 3
Source/BansheeCore/Include/BsPixelUtil.h

@@ -190,11 +190,11 @@ namespace BansheeEngine
 		 */
 		 */
         static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src); 
         static void unpackColor(float* r, float* g, float* b, float* a, PixelFormat format, const void* src); 
 
 
-		/** Writes depth to the provided memory location. */
+		/** Writes a depth value to the provided memory location. */
 		static void packDepth(float depth, const PixelFormat format, void* dest);
 		static void packDepth(float depth, const PixelFormat format, void* dest);
 
 
-		/** Reads the depth from the provided memory location. */
-		static void unpackDepth(float& depth, PixelFormat format, void* src);
+		/** Reads the depth from the provided memory location. Value ranges in [0, 1]. */
+		static float unpackDepth(PixelFormat format, void* src);
         
         
 		/**
 		/**
 		 * Converts pixels from one format to another. Provided pixel data objects must have previously allocated buffers
 		 * Converts pixels from one format to another. Provided pixel data objects must have previously allocated buffers

+ 4 - 8
Source/BansheeCore/Source/BsPixelData.cpp

@@ -178,20 +178,16 @@ namespace BansheeEngine
 
 
 	float PixelData::getDepthAt(UINT32 x, UINT32 y, UINT32 z) const
 	float PixelData::getDepthAt(UINT32 x, UINT32 y, UINT32 z) const
 	{
 	{
-		float depth;
-
 		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
 		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
 		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
 		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
-		PixelUtil::unpackDepth(depth, mFormat, (unsigned char *)getData() + pixelOffset);
-
-		return depth;
+		return PixelUtil::unpackDepth(mFormat, (unsigned char *)getData() + pixelOffset);;
 	}
 	}
 
 
-	void PixelData::setDepthAt(float const& cv, UINT32 x, UINT32 y, UINT32 z)
+	void PixelData::setDepthAt(const float& depth, UINT32 x, UINT32 y, UINT32 z)
 	{
 	{
 		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
 		UINT32 pixelSize = PixelUtil::getNumElemBytes(mFormat);
 		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
 		UINT32 pixelOffset = pixelSize * (z * mSlicePitch + y * mRowPitch + x);
-		PixelUtil::packDepth(cv, mFormat, (unsigned char *)getData() + pixelOffset);
+		PixelUtil::packDepth(depth, mFormat, (unsigned char *)getData() + pixelOffset);
 	}
 	}
 
 
 	Vector<float> PixelData::getDepths() const
 	Vector<float> PixelData::getDepths() const
@@ -220,7 +216,7 @@ namespace BansheeEngine
 					UINT32 dataIdx = x * pixelSize + yDataIdx + zDataIdx;
 					UINT32 dataIdx = x * pixelSize + yDataIdx + zDataIdx;
 
 
 					UINT8* dest = data + dataIdx;
 					UINT8* dest = data + dataIdx;
-					PixelUtil::unpackDepth(depths[arrayIdx], mFormat, dest);
+					depths[arrayIdx] = PixelUtil::unpackDepth(mFormat, dest);
 				}
 				}
 			}
 			}
 		}
 		}

+ 7 - 6
Source/BansheeCore/Source/BsPixelUtil.cpp

@@ -1370,30 +1370,31 @@ namespace BansheeEngine
 
 
 	}
 	}
 
 
-	void PixelUtil::unpackDepth(float& depth, PixelFormat format, void* src)
+	float PixelUtil::unpackDepth(PixelFormat format, void* src)
 	{
 	{
 		const PixelFormatDescription &des = getDescriptionFor(format);
 		const PixelFormatDescription &des = getDescriptionFor(format);
 		if (!isDepth(format))
 		if (!isDepth(format))
 		{
 		{
 			LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
 			LOGERR("Cannot unpack from " + getFormatName(format) + ": it is not a depth format");
-			return;
+			return 0;
 		}
 		}
 		UINT32* color = (UINT32 *)src;
 		UINT32* color = (UINT32 *)src;
 		switch (format) {
 		switch (format) {
 		case PF_D24S8:
 		case PF_D24S8:
-			depth = static_cast<float>(*color & 0x00FFFFFF) / (float)16777216;
+			return  static_cast<float>(*color & 0x00FFFFFF) / (float)16777216;
 			break;
 			break;
 		case PF_D16:
 		case PF_D16:
-			depth = static_cast<float>(*color & 0xFFFF) / (float)65536;
+			return static_cast<float>(*color & 0xFFFF) / (float)65536;
 			break;
 			break;
 		case PF_D32:
 		case PF_D32:
-			depth = static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
+			return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
 			break;
 			break;
 		case PF_D32_S8X24:
 		case PF_D32_S8X24:
-			depth = static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
+			return static_cast<float>(*color & 0xFFFFFFFF) / (float)4294967296;
 			break;
 			break;
 		default:
 		default:
 			LOGERR("Cannot unpack from " + getFormatName(format));
 			LOGERR("Cannot unpack from " + getFormatName(format));
+			return 0;
 			break;
 			break;
 		}
 		}
 	}
 	}

+ 1 - 16
Source/BansheeEditor/Source/BsScenePicking.cpp

@@ -191,23 +191,8 @@ namespace BansheeEngine
 		if (data != nullptr)
 		if (data != nullptr)
 		{
 		{
 			Vector3 pos = returnValue.data.pickPosition;
 			Vector3 pos = returnValue.data.pickPosition;
-			Vector2 ndcPoint = cam->screenToNdcPoint(Vector2I(pos.x, pos.y));
-			Vector4 worldPoint(ndcPoint.x, ndcPoint.y, pos.z, 1.0f);
-			worldPoint = cam->getProjectionMatrixRS().inverse().multiply(worldPoint);
-			Vector3 worldPoint3D;
-
-			if (Math::abs(worldPoint.w) > 1e-7f)
-			{
-				float invW = 1.0f / worldPoint.w;
-
-				worldPoint3D.x = worldPoint.x * invW;
-				worldPoint3D.y = worldPoint.y * invW;
-				worldPoint3D.z = worldPoint.z * invW;
-			}
-			pos = cam->viewToWorldPoint(worldPoint3D);
 			*data = returnValue.data;
 			*data = returnValue.data;
-			data->pickPosition = pos;
-			//Todo: camera to world ray if object is too far
+			data->pickPosition = cam->screenToWorldPointDeviceDepth(Vector2I(pos.x, pos.y), pos.z);
 		}
 		}
 
 
 		Vector<UINT32> selectedObjects = returnValue.objects;
 		Vector<UINT32> selectedObjects = returnValue.objects;

+ 10 - 9
Source/BansheeEngine/Include/BsCamera.h

@@ -353,6 +353,16 @@ namespace BansheeEngine
 		 */
 		 */
 		Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
 		Vector3 screenToWorldPoint(const Vector2I& screenPoint, float depth = 0.5f) const;
 
 
+		/**
+		* Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point in
+		* world space.
+		*
+		* @param[in]	screenPoint	Point to transform.
+		* @param[in]	deviceDepth	Device depth to place the world point at. The depth is applied to the vector going from camera
+		*							origin to the point on the near plane.
+		*/
+		Vector3 screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth = 0.5f) const;
+
 		/**
 		/**
 		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point
 		 * Converts a point in screen space (pixels corresponding to render target attached to the camera) to a point
 		 * relative to camera's coordinate system (view space).
 		 * relative to camera's coordinate system (view space).
@@ -415,15 +425,6 @@ namespace BansheeEngine
 		 */
 		 */
 		Ray screenPointToRay(const Vector2I& screenPoint) const;
 		Ray screenPointToRay(const Vector2I& screenPoint) const;
 
 
-		/**
-		* Extracts the necessary values from the projection matrix that allow you to transform device Z value into
-		* world Z value.
-		*
-		* @return					Returns two values that can be used to transform device z to world z using this formula:
-		* 							z = (deviceZ + y) * x.
-		*/
-		Vector2 getDeviceZTransform() const;
-
 		/**	Projects a point from view to normalized device space. */
 		/**	Projects a point from view to normalized device space. */
 		Vector3 projectPoint(const Vector3& point) const;
 		Vector3 projectPoint(const Vector3& point) const;
 
 

+ 18 - 39
Source/BansheeEngine/Source/BsCamera.cpp

@@ -556,6 +556,24 @@ namespace BansheeEngine
 		return ndcToWorldPoint(ndcPoint, depth);
 		return ndcToWorldPoint(ndcPoint, depth);
 	}
 	}
 
 
+	Vector3 CameraBase::screenToWorldPointDeviceDepth(const Vector2I& screenPoint, float deviceDepth) const
+	{
+		Vector2 ndcPoint = screenToNdcPoint(screenPoint);
+		Vector4 worldPoint(ndcPoint.x, ndcPoint.y, deviceDepth, 1.0f);
+		worldPoint = getProjectionMatrixRS().inverse().multiply(worldPoint);
+		Vector3 worldPoint3D;
+
+		if (Math::abs(worldPoint.w) > 1e-7f)
+		{
+			float invW = 1.0f / worldPoint.w;
+
+			worldPoint3D.x = worldPoint.x * invW;
+			worldPoint3D.y = worldPoint.y * invW;
+			worldPoint3D.z = worldPoint.z * invW;
+		}
+		return viewToWorldPoint(worldPoint3D);
+	}
+
 	Vector3 CameraBase::screenToViewPoint(const Vector2I& screenPoint, float depth) const
 	Vector3 CameraBase::screenToViewPoint(const Vector2I& screenPoint, float depth) const
 	{
 	{
 		Vector2 ndcPoint = screenToNdcPoint(screenPoint);
 		Vector2 ndcPoint = screenToNdcPoint(screenPoint);
@@ -704,45 +722,6 @@ namespace BansheeEngine
 		return Vector3(0.0f, 0.0f, 0.0f);
 		return Vector3(0.0f, 0.0f, 0.0f);
 	}
 	}
 
 
-	Vector2 CameraBase::getDeviceZTransform() const
-	{
-		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
-		// in world space. This involes applying the inverse projection transform to the depth value. When you multiply
-		// a vector with the projection matrix you get [clipX, clipY, Az + B, C * z], where we don't care about clipX/clipY.
-		// A is [2, 2], B is [2, 3] and C is [3, 2] elements of the projection matrix (only ones that matter for our depth 
-		// value). The hardware will also automatically divide the z value with w to get the depth, therefore the final 
-		// formula is:
-		// depth = (Az + B) / (C * z)
-
-		// To get the z coordinate back we simply do the opposite: 
-		// z = B / (depth * C - A)
-
-		// However some APIs will also do a transformation on the depth values before storing them to the texture 
-		// (e.g. OpenGL will transform from [-1, 1] to [0, 1]). And we need to reverse that as well. Therefore the final 
-		// formula is:
-		// z = B / ((depth * (maxDepth - minDepth) + minDepth) * C - A)
-
-		// Are we reorganize it because it needs to fit the "(1.0f / (depth + y)) * x" format used in the shader:
-		// z = 1.0f / (depth + minDepth/(maxDepth - minDepth) - A/((maxDepth - minDepth) * C)) * B/((maxDepth - minDepth) * C)
-
-		RenderAPICore& rapi = RenderAPICore::instance();
-		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
-		Matrix4 projMatrix = mProjMatrix;
-
-		float depthRange = rapiInfo.getMaximumDepthInputValue() - rapiInfo.getMinimumDepthInputValue();
-		float minDepth = rapiInfo.getMinimumDepthInputValue();
-
-		float a = projMatrix[2][2];
-		float b = projMatrix[2][3];
-		float c = projMatrix[3][2];
-
-		Vector2 output;
-		output.x = b / (depthRange * c);
-		output.y = minDepth / depthRange - a / (depthRange * c);
-
-		return output;
-	}
-
 	CameraCore::~CameraCore()
 	CameraCore::~CameraCore()
 	{
 	{
 		RendererManager::instance().getActive()->notifyCameraRemoved(this);
 		RendererManager::instance().getActive()->notifyCameraRemoved(this);

+ 13 - 4
Source/MBansheeEditor/Windows/Scene/SceneWindow.cs

@@ -588,10 +588,19 @@ namespace BansheeEditor
                         if (Input.IsButtonHeld(ButtonCode.Space))
                         if (Input.IsButtonHeld(ButtonCode.Space))
                         {
                         {
                             SnapData snapData;
                             SnapData snapData;
-                            sceneSelection.Snap(scenePos, out snapData, new SceneObject[] {draggedSO});
-                            Quaternion q = Quaternion.FromToRotation(Vector3.YAxis, snapData.normal);
-                            draggedSO.Position = snapData.position;
-                            draggedSO.Rotation = q;
+                            var snappedTo = sceneSelection.Snap(scenePos, out snapData, new SceneObject[] {draggedSO});
+                            if (snappedTo != null)
+                            {
+                                Quaternion q = Quaternion.FromToRotation(Vector3.YAxis, snapData.normal);
+                                draggedSO.Position = snapData.position;
+                                draggedSO.Rotation = q;
+                            }
+                            else
+                            {
+                                Ray worldRay = camera.ViewportToWorldRay(scenePos);
+                                draggedSO.Position = worldRay * DefaultPlacementDepth - draggedSOOffset;
+                                draggedSO.Rotation = Quaternion.LookRotation(Vector3.YAxis);
+                            }
                         }
                         }
                         else
                         else
                         {
                         {

+ 10 - 0
Source/RenderBeast/Include/BsRendererCamera.h

@@ -57,6 +57,16 @@ namespace BansheeEngine
 		/** Populates camera render queues by determining visible renderable objects. */
 		/** Populates camera render queues by determining visible renderable objects. */
 		void determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds);
 		void determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds);
 
 
+		/**
+		* Extracts the necessary values from the projection matrix that allow you to transform device Z value into
+		* world Z value.
+		* 
+		* @param[in]	projMatrix	Projection matrix that was used to create the device Z value to transform.
+		* @return					Returns two values that can be used to transform device z to world z using this formula:
+		* 							z = (deviceZ + y) * x.
+		*/
+		Vector2 getDeviceZTransform(const Matrix4& projMatrix) const;
+
 		/** 
 		/** 
 		 * Returns a structure containing information about post-processing effects. This structure will be modified and
 		 * Returns a structure containing information about post-processing effects. This structure will be modified and
 		 * maintained by the post-processing system.
 		 * maintained by the post-processing system.

+ 39 - 1
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -70,6 +70,44 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	Vector2 RendererCamera::getDeviceZTransform(const Matrix4& projMatrix) const
+	{
+		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
+		// in world space. This involes applying the inverse projection transform to the depth value. When you multiply
+		// a vector with the projection matrix you get [clipX, clipY, Az + B, C * z], where we don't care about clipX/clipY.
+		// A is [2, 2], B is [2, 3] and C is [3, 2] elements of the projection matrix (only ones that matter for our depth 
+		// value). The hardware will also automatically divide the z value with w to get the depth, therefore the final 
+		// formula is:
+		// depth = (Az + B) / (C * z)
+
+		// To get the z coordinate back we simply do the opposite: 
+		// z = B / (depth * C - A)
+
+		// However some APIs will also do a transformation on the depth values before storing them to the texture 
+		// (e.g. OpenGL will transform from [-1, 1] to [0, 1]). And we need to reverse that as well. Therefore the final 
+		// formula is:
+		// z = B / ((depth * (maxDepth - minDepth) + minDepth) * C - A)
+
+		// Are we reorganize it because it needs to fit the "(1.0f / (depth + y)) * x" format used in the shader:
+		// z = 1.0f / (depth + minDepth/(maxDepth - minDepth) - A/((maxDepth - minDepth) * C)) * B/((maxDepth - minDepth) * C)
+
+		RenderAPICore& rapi = RenderAPICore::instance();
+		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
+
+		float depthRange = rapiInfo.getMaximumDepthInputValue() - rapiInfo.getMinimumDepthInputValue();
+		float minDepth = rapiInfo.getMinimumDepthInputValue();
+
+		float a = projMatrix[2][2];
+		float b = projMatrix[2][3];
+		float c = projMatrix[3][2];
+
+		Vector2 output;
+		output.x = b / (depthRange * c);
+		output.y = minDepth / depthRange - a / (depthRange * c);
+
+		return output;
+	}
+
 	void RendererCamera::determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds)
 	void RendererCamera::determineVisible(Vector<RendererObject>& renderables, const Vector<Bounds>& renderableBounds)
 	{
 	{
 		bool isOverlayCamera = mCamera->getFlags().isSet(CameraFlag::Overlay);
 		bool isOverlayCamera = mCamera->getFlags().isSet(CameraFlag::Overlay);
@@ -142,7 +180,7 @@ namespace BansheeEngine
 		data.screenToWorld = data.invViewProj * projZ;
 		data.screenToWorld = data.invViewProj * projZ;
 		data.viewDir = mCamera->getForward();
 		data.viewDir = mCamera->getForward();
 		data.viewOrigin = mCamera->getPosition();
 		data.viewOrigin = mCamera->getPosition();
-		data.deviceZToWorldZ = mCamera->getDeviceZTransform();
+		data.deviceZToWorldZ = getDeviceZTransform(data.proj);
 
 
 		SPtr<ViewportCore> viewport = mCamera->getViewport();
 		SPtr<ViewportCore> viewport = mCamera->getViewport();
 		SPtr<RenderTargetCore> rt = viewport->getTarget();
 		SPtr<RenderTargetCore> rt = viewport->getTarget();