Selaa lähdekoodia

Modified scene picking to handle pick location

marco.bellan 9 vuotta sitten
vanhempi
sitoutus
29c5b495fd

+ 14 - 5
Source/BansheeEditor/Include/BsScenePicking.h

@@ -13,13 +13,20 @@ namespace BansheeEngine
 	 *  @{
 	 */
 
-	 /** Contains the results of a scene picking. */
-	struct PickResults
+	 /** Contains the data of a scene picking action. */
+	struct PickData
 	{
-		Vector<UINT32> results;
+		Vector3 normal;
 		Vector3 pickPosition;
 	};
 
+	/** Contains the results of a scene picking action. */
+	struct PickResults
+	{
+		Vector<UINT32> objects;
+		PickData data;
+	};
+
 	class ScenePickingCore;
 
 	/**	Handles picking of scene objects with a pointer in scene view. */
@@ -47,9 +54,10 @@ namespace BansheeEngine
 		 * @param[in]	position	Pointer position relative to the camera viewport, in pixels.
 		 * @param[in]	area		Width/height of the checked area in pixels. Use (1, 1) if you want the exact position
 		 *							under the pointer.
+		 * @param[out]	data		Picking data regarding position and normal.
 		 * @return					Nearest SceneObject under the provided area, or an empty handle if no object is found.
 		 */
-		HSceneObject pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area);
+		HSceneObject pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, PickData& data);
 
 		/**
 		 * Attempts to find all scene objects under the provided position and area. This does not mean objects occluded by
@@ -59,9 +67,10 @@ namespace BansheeEngine
 		 * @param[in]	position	Pointer position relative to the camera viewport, in pixels.
 		 * @param[in]	area		Width/height of the checked area in pixels. Use (1, 1) if you want the exact position
 		 *							under the pointer.
+		 * @param[out]	data		Picking data regarding position and normal.
 		 * @return					A list of SceneObject%s under the provided area.
 		 */
-		Vector<HSceneObject> pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area);
+		Vector<HSceneObject> pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, PickData& data);
 
 	private:
 		friend class ScenePickingCore;

+ 28 - 9
Source/BansheeEditor/Source/BsScenePicking.cpp

@@ -54,16 +54,16 @@ namespace BansheeEngine
 		gCoreAccessor().queueCommand(std::bind(&ScenePickingCore::destroy, mCore));
 	}
 
-	HSceneObject ScenePicking::pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area)
+	HSceneObject ScenePicking::pickClosestObject(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, PickData& data)
 	{
-		Vector<HSceneObject> selectedObjects = pickObjects(cam, position, area);
+		Vector<HSceneObject> selectedObjects = pickObjects(cam, position, area, data);
 		if (selectedObjects.size() == 0)
 			return HSceneObject();
 
 		return selectedObjects[0];
 	}
 
-	Vector<HSceneObject> ScenePicking::pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area)
+	Vector<HSceneObject> ScenePicking::pickObjects(const SPtr<Camera>& cam, const Vector2I& position, const Vector2I& area, PickData& data)
 	{
 		auto comparePickElement = [&] (const ScenePicking::RenderablePickData& a, const ScenePicking::RenderablePickData& b)
 		{
@@ -170,10 +170,25 @@ namespace BansheeEngine
 		assert(op.hasCompleted());
 
 		PickResults returnValue = op.getReturnValue<PickResults>();
-		Vector3 pos = returnValue.pickPosition;
-		pos = cam->screenToWorldPoint(Vector2I(pos.x, pos.y), 
-			(1.0f / (pos.z + cam->getDeviceZTransform().y)) * cam->getDeviceZTransform().x);
-		Vector<UINT32> selectedObjects = returnValue.results;
+		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.pickPosition = pos;
+
+		Vector<UINT32> selectedObjects = returnValue.objects;
 		Vector<HSceneObject> results;
 
 		for (auto& selectedObjectIdx : selectedObjects)
@@ -423,8 +438,12 @@ namespace BansheeEngine
 			depth = depthPixelData->getDepthAt(position.x, position.y);
 
 		PickResults result;
-		result.results = objects;
-		result.pickPosition = Vector3(position.x, position.y, depth);
+		PickData data;
+		result.objects = objects;
+		const RenderAPIInfo& rapiInfo = rs.getAPIInfo();
+		depth = depth * Math::abs(rapiInfo.getMinimumDepthInputValue() - rapiInfo.getMinimumDepthInputValue()) + rapiInfo.getMinimumDepthInputValue();
+		data.pickPosition = Vector3(position.x, position.y, depth);
+		result.data = data;
 		asyncOp._completeOperation(result);
 	}
 }

+ 2 - 1
Source/SBansheeEditor/Source/BsScriptSceneSelection.cpp

@@ -39,7 +39,8 @@ namespace BansheeEngine
 	void ScriptSceneSelection::internal_PickObject(ScriptSceneSelection* thisPtr, Vector2I* inputPos, bool additive)
 	{
 		// TODO - Handle multi-selection (i.e. selection rectangle when dragging)
-		HSceneObject pickedObject = ScenePicking::instance().pickClosestObject(thisPtr->mCamera, *inputPos, Vector2I(1, 1));
+		PickData data;
+		HSceneObject pickedObject = ScenePicking::instance().pickClosestObject(thisPtr->mCamera, *inputPos, Vector2I(1, 1), data);
 
 		if (pickedObject)
 		{