MRが楽しい

MRやVRについて学習したことを書き残す

公式チュートリアル「HOLOGRAMS 230 4章」を試してみる

本日はチュートリアルお試し枠です。
いつも通り、以下ブログの記事を参考に実施します。
azure-recipe.kc-cloud.jp

今回はSpatialMappingで面の判定を確認します。
記事の通りアプリを修正してプログラムを実行してみます。

一点、記事中に書いてあるPlaySpaceManager.csはおそらくPlaceable.csの誤りなので注意が必要です。
公式ページを確認しました。
・Holograms 230
 https://developer.microsoft.com/en-us/windows/mixed-reality/holograms_230

アプリを起動します。逆向きではありますが壁面にポスターが表示されました。
f:id:bluebirdofoz:20170719021554j:plain
ポスターをタップすると、ドラッグできます。
このとき、平面でないところにポスターを持ってくると、置けないことを意味する赤色の背景色が表示されます。
f:id:bluebirdofoz:20170719021602j:plain
配置可能な平面だと、白色の背景色になります。
f:id:bluebirdofoz:20170719021617j:plain
タップするとポスターを配置できました。
f:id:bluebirdofoz:20170719021627j:plain

コードを確認します。
今回は、配置可能な平面かどうかを確認している関数を抽出しました。
・Placeable.cs

    // Threshold (the closer to 0, the stricter the standard) used to determine if a surface is flat.
    private float distanceThreshold = 0.02f;
(略)
    /// <summary>
    /// Verify whether or not the object can be placed.
    /// </summary>
    /// <param name="position">
    /// The target position on the surface.
    /// </param>
    /// <param name="surfaceNormal">
    /// The normal of the surface on which the object is to be placed.
    /// </param>
    /// <returns>
    /// True if the target position is valid for placing the object, otherwise false.
    /// </returns>
    private bool ValidatePlacement(out Vector3 position, out Vector3 surfaceNormal)
    {
        Vector3 raycastDirection = gameObject.transform.forward;

        if (PlacementSurface == PlacementSurfaces.Horizontal)        
        {
            // Placing on horizontal surfaces.
            // Raycast from the bottom face of the box collider.
            raycastDirection = -(Vector3.up);
        }

        // Initialize out parameters.
        position = Vector3.zero;
        surfaceNormal = Vector3.zero;

        Vector3[] facePoints = GetColliderFacePoints();

        // The origin points we receive are in local space and we 
        // need to raycast in world space.
        for (int i = 0; i < facePoints.Length; i++)
        {
            facePoints[i] = gameObject.transform.TransformVector(facePoints[i]) + gameObject.transform.position;
        }

        // Cast a ray from the center of the box collider face to the surface.
        RaycastHit centerHit;
        if (!Physics.Raycast(facePoints[0],
                        raycastDirection,
                        out centerHit,
                        maximumPlacementDistance,
                        SpatialMappingManager.Instance.LayerMask))
        {
            // If the ray failed to hit the surface, we are done.
            return false;
        }

        // We have found a surface.  Set position and surfaceNormal.
        position = centerHit.point;
        surfaceNormal = centerHit.normal;

        // Cast a ray from the corners of the box collider face to the surface.
        for (int i = 1; i < facePoints.Length; i++)
        {
            RaycastHit hitInfo;
            if (Physics.Raycast(facePoints[i],
                                raycastDirection,
                                out hitInfo,
                                maximumPlacementDistance,
                                SpatialMappingManager.Instance.LayerMask))
            {
                // To be a valid placement location, each of the corners must have a similar
                // enough distance to the surface as the center point
                if (!IsEquivalentDistance(centerHit.distance, hitInfo.distance))
                {
                    return false;
                }
            }
            else
            {
                // The raycast failed to intersect with the target layer.
                return false;
            }
        }

        return true;
    }
(略)
    /// <summary>
    /// Determines if two distance values should be considered equivalent. 
    /// </summary>
    /// <param name="d1">
    /// Distance to compare.
    /// </param>
    /// <param name="d2">
    /// Distance to compare.
    /// </param>
    /// <returns>
    /// True if the distances are within the desired tolerance, otherwise false.
    /// </returns>
    private bool IsEquivalentDistance(float d1, float d2)
    {
        float dist = Mathf.Abs(d1 - d2);
        return (dist <= distanceThreshold);
    }

ボックスコライダーの各コーナーからレイキャストの衝突判定を実施し、その距離の差が0.02f以下かどうかを判定しているようです。