本日はチュートリアルお試し枠です。
いつも通り、以下ブログの記事を参考に実施します。
azure-recipe.kc-cloud.jp
今回はSpatialMappingで面の判定を確認します。
記事の通りアプリを修正してプログラムを実行してみます。
一点、記事中に書いてあるPlaySpaceManager.csはおそらくPlaceable.csの誤りなので注意が必要です。
公式ページを確認しました。
・Holograms 230
https://developer.microsoft.com/en-us/windows/mixed-reality/holograms_230
アプリを起動します。逆向きではありますが壁面にポスターが表示されました。
ポスターをタップすると、ドラッグできます。
このとき、平面でないところにポスターを持ってくると、置けないことを意味する赤色の背景色が表示されます。
配置可能な平面だと、白色の背景色になります。
タップするとポスターを配置できました。
コードを確認します。
今回は、配置可能な平面かどうかを確認している関数を抽出しました。
・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以下かどうかを判定しているようです。