Raycasting
[마지막 갱신일: 2020/01/30]
개요
Raycasting은 사용자가 지정한 Cubism의 메쉬와 임의의 좌표가 교차할지 어떨지를 판정하는 기능입니다.
클릭/탭된 좌표나, 씬 중의 임의의 오브젝트와 지정된 메쉬와의 충돌 판정을 취득하는 것이 가능합니다.
Raycasting 사용 방법은 여기를 참조하십시오.
Cubism SDK for Unity의 Raycasting은 크게 두 가지 요소로 구성됩니다.
- 판정할 아트 메쉬 지정용의 컴퍼넌트
- 입력된 좌표와 지정된 아트 메쉬의 충돌 판정을 실시하는 컴퍼넌트
1. 판정할 아트 메쉬 지정용 컴포넌트
충돌 판정에 사용할 메쉬를 지정하려면 CubismRaycastable을 사용합니다.
CubismRaycastable은 [Prefab의 루트]/Drawables/ 아래에 배치된 GameObject에 연결하여 사용합니다.
이것이 첨부된 GameObject와 같은 ID의 아트 메쉬를 명중 판정에 사용합니다.
CubismRaycastable에는 메쉬 당 판별의 정확도를 설정하는 매개 변수가 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
namespace Live2D.Cubism.Framework.Raycasting { /// <summary> /// Allows raycasting against <see cref="Core.CubismDrawable"/>s. /// </summary> public sealed class CubismRaycastable : MonoBehaviour { /// <summary> /// The precision. /// </summary> public CubismRaycastablePrecision Precision; } } |
CubismRaycastable.Precision에는 설정할 수 있는 값이 2개 있어 각각 아래와 같이 되어 있습니다.
- BoundingBox
그 메쉬를 둘러싸는, 네변이 수평 또는 수직의 구형을 충돌 판정으로서 사용합니다.
메쉬의 형상에 따라서는 메쉬 밖의 좌표에서도 충돌 판정을 취합니다만, Triangles에 비해 퍼포먼스가 뛰어납니다.
- Triangles
메쉬의 형상을 충돌 판정의 범위로서 사용합니다.
BoundingBox와 비교하면 성능이 떨어지지만 정확한 범위에서 판정을 할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
namespace Live2D.Cubism.Framework.Raycasting { /// <summary> /// Precision for casting rays against a <see cref="CubismRaycastable"/>. /// </summary> public enum CubismRaycastablePrecision { /// <summary> /// Cast against bounding box. /// </summary> BoundingBox, /// <summary> /// Cast against triangles. /// </summary> Triangles } } |
2. 입력된 좌표와 지정된 아트메쉬의 충돌 판정을 하는 컴퍼넌트
실제 충돌 판정의 취득은 CubismRaycaster를 사용합니다.
CubismRaycaster를 사용할 때는 Cubism의 Prefab 루트에 연결합니다.
CubismRaycaster를 초기화할 때 Prefab에 연결된 모든 CubismRaycastable에 대한 참조를 가져옵니다.
실행중에 충돌 판정용의 메쉬를 추가/삭제했을 때에는, CubismRaycaster.Refresh()를 호출해 참조를 다시 취득합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/// <summary> /// Refreshes the controller. Call this method after adding and/or removing <see cref="CubismRaycastable"/>. /// </summary> private void Refresh() { var candidates = this .FindCubismModel() .Drawables; // Find raycastable drawables. var raycastables = new List<CubismRenderer>(); var raycastablePrecisions = new List<CubismRaycastablePrecision>(); for (var i = 0; i < candidates.Length; i++) { // Skip non-raycastables. if (candidates[i].GetComponent<CubismRaycastable>() == null) { continue; } raycastables.Add(candidates[i].GetComponent<CubismRenderer>()); raycastablePrecisions.Add(candidates[i].GetComponent<CubismRaycastable>().Precision); } // Cache raycastables. Raycastables = raycastables.ToArray(); RaycastablePrecisions = raycastablePrecisions.ToArray(); } ... /// <summary> /// Called by Unity. Makes sure cache is initialized. /// </summary> private void Start() { // Initialize cache. Refresh(); } |
좌표로부터 충돌 판정을 취득하려면, CubismRaycaster.Raycast()를 이용합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
/// <summary> /// Casts a ray. /// </summary> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="result">The result of the cast.</param> /// <param name="maximumDistance">[Optional] The maximum distance of the ray.</param> /// <returns><see langword="true"/> in case of a hit; <see langword="false"/> otherwise.</returns> /// <returns>The numbers of drawables had hit</returns> public int Raycast(Vector3 origin, Vector3 direction, CubismRaycastHit[] result, float maximumDistance = Mathf.Infinity) { return Raycast(new Ray(origin, direction), result, maximumDistance); } /// <summary> /// Casts a ray. /// </summary> /// <param name="ray"></param> /// <param name="result">The result of the cast.</param> /// <param name="maximumDistance">[Optional] The maximum distance of the ray.</param> /// <returns><see langword="true"/> in case of a hit; <see langword="false"/> otherwise.</returns> /// <returns>The numbers of drawables had hit</returns> public int Raycast(Ray ray, CubismRaycastHit[] result, float maximumDistance = Mathf.Infinity) { // Cast ray against model plane. var intersectionInWorldSpace = ray.origin + ray.direction * (ray.direction.z / ray.origin.z); var intersectionInLocalSpace = transform.InverseTransformPoint(intersectionInWorldSpace); intersectionInLocalSpace.z = 0; var distance = intersectionInWorldSpace.magnitude; // Return non-hits. if (distance > maximumDistance) { return 0; } // Cast against each raycastable. var hitCount = 0; for (var i = 0; i < Raycastables.Length; i++) { var raycastable = Raycastables[i]; var raycastablePrecision = RaycastablePrecisions[i]; // Skip inactive raycastables. if (!raycastable.MeshRenderer.enabled) { continue; } if (raycastablePrecision == CubismRaycastablePrecision.BoundingBox) { var bounds = raycastable.Mesh.bounds; // Skip non hits if (!bounds.Contains(intersectionInLocalSpace)) { continue; } } else { // Skip non hits if (!ContainsInTriangles(raycastable.Mesh, intersectionInLocalSpace)) { continue; } } result[hitCount].Drawable = raycastable.GetComponent<CubismDrawable>(); result[hitCount].Distance = distance; result[hitCount].LocalPosition = intersectionInLocalSpace; result[hitCount].WorldPosition = intersectionInWorldSpace; ++hitCount; // Exit if result buffer is full. if (hitCount == result.Length) { break; } } return hitCount; } |
CubismRaycaster.Raycast() 는 반환값에 해충돌 판정을 취득한 메쉬의 수를 돌려줍니다.
또, 인수에 건네준 CubismRaycastHit[]형태의 인스턴스에 대해 판정을 취득한 메쉬의 정보가 설정됩니다.
1 2 |
var raycastResults = new CubismRaycastHit[4]; var hitCount = _raycaster.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), raycastResults); |
CubismRaycaster.Raycast() 는, 동 좌표상에 복수의 메쉬가 겹쳐져 있었을 경우, 최대로 CubismRaycastHit[] 형의 인스턴스의 요소의 수까지 취득합니다.
요소 수 이상의 메쉬가 겹치면 넘어서는 메쉬는 결과를 얻지 못합니다.
CubismRaycastHit은 충돌 판정을 취득한 메쉬의 정보를 가지는 구조체입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
using Live2D.Cubism.Core; using UnityEngine; namespace Live2D.Cubism.Framework.Raycasting { /// <summary> /// Contains raycast information. /// </summary> public struct CubismRaycastHit { /// <summary> /// The hit <see cref="CubismDrawable"/>. /// </summary> public CubismDrawable Drawable; /// <summary> /// The distance the ray traveled until it hit the <see cref="CubismDrawable"/>. /// </summary> public float Distance; /// <summary> /// The hit position local to the <see cref="CubismDrawable"/>. /// </summary> public Vector3 LocalPosition; /// <summary> /// The hit position in world coordinates. /// </summary> public Vector3 WorldPosition; } } |
- Drawable
충돌 판정을 취득한 아트 메쉬의 참조입니다.
- Distance
지정한 좌표로부터의 거리입니다.
CubismRaycaster.Raycast() 의 인수에 건네준 origin 또는 ray.origin 와 Drawable 의 Transform.position 의 직선 거리입니다.
- LocalPosition
충돌 판정을 취득한 아트 메쉬의 로컬 좌표입니다.
- WorldPosition
충돌 판정을 취득한 아트 메쉬의 월드 좌표입니다.