您好我正在使用谷歌探戈和统一SDK!我正在制作一个应用程序,你应该在建筑物的3D模型中对齐自己。使用以下代码,您应该能够将探戈指向墙壁并在3D模型中单击该墙以通过PoinCloud.FindPlane和Physics.Raycast对齐它们。这非常有效!但。它只适用于app运行的开始。由于某种原因,PointCloud.FindPlane在应用运行时约30秒后总是失败。
我没有使用arealearning或区域描述,因为这应该是为了弥补学习本来应该解决的漂移。
我尝试过很多东西,比如使用arealearning等,但它无论如何都没有用。我怀疑PointCloud中的某些东西在需要多点时会被破坏,但我不知道如何修复它。我已经有了这个bug大约6个月了,并希望它会在以后的更新中修复,但它没有。
我认为这也发生在googles自己的一个例子中,我根据这个代码。
如果有人知道发生了什么并且导致了问题,或者你有一些方法可以偶尔刷新点云,因为它总是会工作几秒钟就会很棒!或者也许只使用最新的姿势使用FindPlane,因为我只在探戈面前使用FindPlane。谢谢!
值得一提的是,我不是"扫描"非常通过这个应用程序。只是穿过房间。(编辑)我还读到,使用FindPlane,探戈正在检查点云中的每个点,每帧只应使用一次。也许它会在一段时间后变慢?然后我需要暂时刷新PointCloud,但我似乎无法找到任何方法。
public class ModelPositionRefiner : MonoBehaviour, ITangoLifecycle, ITangoDepth
{
/// <summary>
/// The tango gameObject to ray cast from.
/// </summary>
public GameObject m_virtualTangoDevice;
/// <summary>
/// The HAX fixed distance between the tango and the bim floor.
/// </summary>
public float m_tangoToFloorDistance;
/// <summary>
/// Position in model to align with point cloud interception.
/// </summary>
private Ray m_selectedEnvironmentSurface;
/// <summary>
/// The point cloud object in the scene.
/// </summary>
public TangoPointCloud m_pointCloud;
/// <summary>
/// The canvas to place 2D game objects under.
/// </summary>
public Canvas m_canvas;
public Text m_errorField;
public TouchEffect m_touchEffect;
public TouchEffect m_errorTouchEffect;
public TouchEffect m_loadingTouchEffect;
/// <summary>
/// If set, then the depth camera is on and we are waiting for the next depth update.
/// </summary>
private bool m_findPlaneWaitingForDepth;
/// <summary>
/// A reference to TangoApplication instance.
/// </summary>
private TangoApplication m_tangoApplication;
/// <summary>
/// Unity Start function.
///
/// We find and assign pose controller and tango applicaiton, and register this class to callback events.
/// </summary>
public void Start()
{
m_tangoApplication = FindObjectOfType<TangoApplication>();
m_tangoApplication.Register(this);
}
/// <summary>
/// This is called when the permission granting process is finished.
/// </summary>
/// <param name="permissionsGranted"><c>true</c> if permissions were granted, otherwise <c>false</c>.</param>
public void OnTangoPermissions(bool permissionsGranted)
{
}
/// <summary>
/// This is called when succesfully connected to the Tango service.
/// </summary>
public void OnTangoServiceConnected()
{
m_tangoApplication.SetDepthCameraRate(1);
}
/// <summary>
/// This is called when disconnected from the Tango service.
/// </summary>
public void OnTangoServiceDisconnected()
{
}
/// <summary>
/// This is called each time new depth data is available.
///
/// On the Tango tablet, the depth callback occurs at 5 Hz.
/// </summary>
/// <param name="tangoDepth">Tango depth.</param>
public void OnTangoDepthAvailable(TangoUnityDepth tangoDepth)
{
// Don't handle depth here because the PointCloud may not have been updated yet. Just
// tell the coroutine it can continue.
m_findPlaneWaitingForDepth = false;
}
/// <summary>
/// Unity destroy function.
/// </summary>
public void OnDestroy()
{
m_tangoApplication.Unregister(this);
}
/// <summary>
/// Unity Update function.
/// </summary>
public void Update()
{
UpdateCheckForManualRefining();
}
/// <summary>
/// Checks for a manual click to align the bim surface clicked with the
/// </summary>
private void UpdateCheckForManualRefining()
{
// Check so that we don't click UI. The first is for computer and the 0 is required for which touch on touch device.
if (EventSystem.current.IsPointerOverGameObject() || EventSystem.current.IsPointerOverGameObject(0))
return;
Vector2 clickPosition;
if (Input.touchCount != 1)
return;
clickPosition = Input.GetTouch(0).position;
// Add a progress animation when pressing to refine position.
if (Utils.PressTimePassed(1f) && !Utils.PressDistancePassed(20))
{
m_loadingTouchEffect.Apply(m_canvas, clickPosition);
}
// When pressed enough time align clicked bim object with wath the tango is pointing toward!
if (Utils.PressTimePassed(2.5f) && !Utils.PressDistancePassed(20))
{
RaycastHit hitInfo;
// 10 is the environment model layer.
if (Physics.Raycast(Camera.main.ScreenPointToRay(clickPosition), out hitInfo, 1000, 1 << 10))
{
m_selectedEnvironmentSurface = new Ray(hitInfo.point, hitInfo.normal);
m_touchEffect.Apply(m_canvas, clickPosition);
StartCoroutine(_WaitForDepthAndCorrectModel(clickPosition));
}
else
{
m_errorTouchEffect.Apply(m_canvas, clickPosition);
}
}
}
private IEnumerator _WaitForDepthAndCorrectModel(Vector2 clickPosition)
{
m_findPlaneWaitingForDepth = true;
// Turn on the camera and wait for a single depth update.
m_tangoApplication.SetDepthCameraRate(TangoEnums.TangoDepthCameraRate.MAXIMUM);
while (m_findPlaneWaitingForDepth)
{
yield return null;
}
m_tangoApplication.SetDepthCameraRate(1);
// Find the plane.
Camera cam = Camera.main;
Vector3 cloudOrigin;
Plane plane;
if (!m_pointCloud.FindPlane(cam, new Vector3(Screen.width / 2, Screen.height / 2, 0), out cloudOrigin, out plane))
{
m_errorField.text = "Error: Tango has no depth. Valid distance: 0.5m - 4m. \nThe surface can't be too bright or too dark.";
m_errorTouchEffect.Apply(m_canvas, clickPosition);
yield break;
}
//cloudNormal is correctly oriented
Vector3 modelNormal = m_selectedEnvironmentSurface.direction;
Vector3 cloudNormal = plane.normal;
float floorLimit = 45;
float ceilingLimit = 180 - floorLimit;
float modelAngle = Vector3.Angle(modelNormal, Vector3.up);
float cloudAngle = Vector3.Angle(cloudNormal, Vector3.up);
// 0 is floor, 1 is ceilling, 2 is wall.
int modelNormalType = modelAngle < floorLimit ? 0 : (modelAngle > ceilingLimit ? 1 : 2);
int cloudNormalType = cloudAngle < floorLimit ? 0 : (cloudAngle > ceilingLimit ? 1 : 2);
if (modelNormalType != cloudNormalType)
{
m_errorField.text = "Error: If you click on a wall, floor or ceiling the Tango must be facing the same.";
m_errorTouchEffect.Apply(m_canvas, clickPosition);
yield break;
}
//Input is valid, reposition.
m_errorField.text = "";
//We can't click a floor or ceiling and rotate around the Y axis.
if (cloudNormalType == 2) // && modelNormalType == 2
{
//Ignore X and Z rotation since the floor is expected to be parallell with the worlds.
modelNormal.y = 0;
cloudNormal.y = 0;
float angle = Vector3.Angle(modelNormal, cloudNormal);
Vector3 cross = Vector3.Cross(modelNormal, cloudNormal);
angle = angle * Mathf.Sign(cross.y);
//We use cloudNormal since the new Model is now expected to be cloudNormal.
Location.ShowingLocation.Environment.transform.position += Vector3.Project(cloudOrigin - m_selectedEnvironmentSurface.origin, cloudNormal);
Location.ShowingLocation.Environment.transform.RotateAround(cam.transform.position, Vector3.up, angle);
}
else //Preferably a floor.
{
//Only move us to the right height from the floor.
Location.ShowingLocation.Environment.transform.position += Vector3.Project(modelNormal, cloudOrigin - m_selectedEnvironmentSurface.origin);
//Move us to the pointed direction.
//Location.ShowingLocation.Environment.transform.position += planeCenter - m_selectedEnvironmentSurface.origin;
}
}
}