Get it on Google Play


Wm뮤 :: 유니티 좌표계산 모음

블로그 이미지
가끔 그림그리거나 3D모델링하거나
취미로 로봇만드는
퇴직한 전자과 게임프로그래머
2020.3.48f1 , 2022.3.6f1 주로 사용
모카쨩
@Ahzkwid

Recent Comment

Archive


2021. 7. 1. 01:41 Unity/C#

 

각도계산

https://wmmu.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EB%B0%A9%ED%96%A5%EA%B4%80%EB%A0%A8-%ED%95%A8%EC%88%98-%EC%A0%95%EB%A6%AC

 

결과값이 각도일 경우에는 위 링크로

결과값이 좌표일 경우에는 이 글을 이용

 

 

 

 

 

LenPos

각도를 좌표로

Quaternion direction;
Vecter3 distance;
LenPos = direction * Vector3.forward * distance

 

 

유니티판 PointDirection

2D 계산용

Debug.Log(Quaternion.Euler(0, 0, 0) * Vector2.right); //(1, 0, 0)
Debug.Log(Quaternion.Euler(0, 0, 90) * Vector2.right); //(0, 1, 0)
Debug.Log(Quaternion.Euler(0, 0, 180) * Vector2.right); //(-1, 0, 0)
Debug.Log(Quaternion.Euler(0, 0, 270) * Vector2.right); //(0, -1, 0)

 

 

 

ScreenToRectPosition

var canvas = GetComponentInParent<Canvas>();
Camera cam = null;
switch (canvas.renderMode)
{
    case RenderMode.ScreenSpaceOverlay:
        break;
    case RenderMode.ScreenSpaceCamera:
    case RenderMode.WorldSpace:
        cam = canvas.worldCamera;
        break;
    default:
        break;
}
if (cam == null)
{
    cam = Camera.main;
}



switch (canvas.renderMode)
{
    case RenderMode.ScreenSpaceOverlay:
        handle.transform.position = eventData.position;
        break;
    case RenderMode.ScreenSpaceCamera:
    case RenderMode.WorldSpace:
        Vector3 rectPos;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(GetComponent<RectTransform>(), eventData.position, cam, out rectPos);
        handle.transform.position = rectPos;
        break;
    default:
        break;
}

 

위에서 카메라만 가져올땐 약식으로 이거 써도 된다

public (Canvas, Camera) GetCanvasCamera()
{
    var canvas = GetComponentInParent<Canvas>();
    var camera = canvas.worldCamera;
    if (camera == null)
    {
        camera = Camera.main;
    }
    return (canvas,camera);

}

 

 

 

 

 

 

 

 

 

특정 각도를 upVector삼아서 회전

(노란색 : 회전시킨 벡터)

(빨간색 : 기준각도)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;




public class VectorRotationTest : MonoBehaviour
{
    void OnDrawGizmos()
    {
        //입력값
        var axis = new Vector3(-2.85f, 1.4f, 3.4f);
        var a = transform.rotation;
        var b = Quaternion.Euler( 0,  0, (Time.time * 30) % 360);



        //노란색원의 좌표계
        var radius = Vector2.Distance(Vector2.zero, new Vector2(axis.x, axis.y));
        var center = transform.position + a * Vector3.forward * axis.z;
        UnityEngine.Debug.DrawLine(center, center + a * Vector3.up * radius, Color.blue);
        UnityEngine.Debug.DrawLine(center, center + a * Vector3.right * radius, Color.green);

        //노란색원
        UnityEditor.Handles.color = Color.yellow;
        UnityEditor.Handles.DrawWireDisc(center, a * Vector3.forward, radius);
        UnityEditor.Handles.color = Color.white;


        //흰색원과 좌표계
        UnityEngine.Debug.DrawLine(transform.position, center, Color.red);
        UnityEngine.Debug.DrawLine(transform.position, transform.position + a * Vector3.up, Color.blue);
        UnityEngine.Debug.DrawLine(transform.position, transform.position + a * Vector3.right, Color.green);
        UnityEditor.Handles.DrawWireDisc(transform.position, a * Vector3.forward, 1f);

        var upRotation = a;

        //핵심
        UnityEngine.Debug.DrawLine(transform.position, transform.position + upRotation * b * axis, Color.yellow);

        //검은색 선
        UnityEngine.Debug.DrawLine(transform.position, transform.position + upRotation * b * Quaternion.Euler(0, 0, 90) * axis, Color.black);
        UnityEngine.Debug.DrawLine(transform.position, transform.position + upRotation * b * Quaternion.Euler(0, 0, 180) * axis, Color.black);
        UnityEngine.Debug.DrawLine(transform.position, transform.position + upRotation * b * Quaternion.Euler(0, 0, 270) * axis, Color.black);





    }
}

 

 

 

 

 

벡터를 6방향으로 정규화

var axisNormal=vector;
if (Mathf.Abs(axisNormal.x) > Mathf.Abs(axisNormal.y))
{
    axisNormal.y = 0;
}
if (Mathf.Abs(axisNormal.x) > Mathf.Abs(axisNormal.z))
{
    axisNormal.z = 0;
}
else
{
    axisNormal.x = 0;
}
axisNormal = axisNormal.normalized;

 

 

 

GPT가 짜준 패스에서 최단지점 구하는 함수

Vector3 ClosestPoint(Vector3 a, Vector3 b, Vector3 position)
{
    Vector3 ab = b - a;
    Vector3 ap = position - a;
    float t = Vector3.Dot(ap, ab) / Vector3.Dot(ab, ab);
    t = Mathf.Clamp01(t); // a와 b 사이의 지점만을 고려하려면 이 줄을 추가합니다.
    return a + ab * t;
}
Vector3 ClosestPoint(Vector3 position)
{
    var path = GetPath();
    float minDistance = float.MaxValue;
    Vector3 closestPoint = Vector3.zero;

    for (int i = 0; i < path.Count - 1; i++)
    {
        Vector3 point = ClosestPoint(path[i], path[i + 1], position);
        float distance = Vector3.Distance(point, position);

        if (distance < minDistance)
        {
            minDistance = distance;
            closestPoint = point;
        }
    }

    return closestPoint;
}

List<Vector3> GetPath()
{
    var childs = new List<Transform>();
    for (int i = 0; i < tracksParent.childCount; i++)
    {
        childs.Add(tracksParent.GetChild(i));
    }
    var path = childs.ConvertAll(x => x.position);

    return path;
}

 

 

상대좌표

그러니까 글로벌 좌표를 로컬 좌표로 바꿔준다

스케일값은 계산되어있지 않다

var localPosition = Quaternion.Inverse(transform.rotation) * (globalPosition - transform.position);

 

 

 

벡터를 특정 각도로 랜덤하게 회전

FPS 게임에서 총알 각도등을 계산할때 쓴다

기존에 내가 계산하던 방식

var vector = Camera.main.transform.forward;
var angle = 5f;
var randomAngle = Random.Range(0, angle);
var rotatedVector = Quaternion.LookRotation(vector, Vector3.up) * Quaternion.Euler(0, 0, Random.Range(0f, 360f)) * Quaternion.Euler(randomAngle, 0, 0) * Vector3.forward * Vector3.Distance(Vector3.zero, vector);

Debug.DrawRay(Camera.main.transform.position, rotatedVector, Color.black);

 

AI가 짜준 방식

이쪽이 더 효율적이다. 위에건 사람이 작동원리를 알기 쉬우니 그냥 둠. 다른 게임엔진에서 쓸수도 있고

var vector = Camera.main.transform.forward;
var angle = 5f;
var randomAngle = Random.Range(0, angle);
var rotatedVector = Quaternion.AngleAxis(randomAngle, Random.onUnitSphere) * vector;

Debug.DrawRay(Camera.main.transform.position, rotatedVector, Color.black);

 

 

WorldPosition을 ScreenPosition으로

var cam = Camera.main;
var screenPoint = RectTransformUtility.WorldToScreenPoint(cam, worldPosition);

 

 

그리고 하기는 예제이다

 

https://wmmu.tistory.com/search/WorldToScreenPoint

 

Wm뮤

자료정리용 개인공간

wmmu.tistory.com

 

 

WorldPosition, ScreenPosition, localRectPosion 종합세트

 

v1

더보기
#if UNITY_EDITOR
    public GameObject handle;
    void OnDrawGizmos()
    {


        // Draw a semitransparent blue cube at the transforms position
        var rectTransform = GetComponent<RectTransform>();
        if (rectTransform == null)
        {
            return;
        }
        var lossyScale = rectTransform.lossyScale;
        float wid = rectTransform.rect.width;
        float hei = rectTransform.rect.height;
        var pivot = rectTransform.pivot;

        Vector3 downPos = transform.up * lossyScale.y * hei * (pivot.y - 1);
        Vector3 upPos = transform.up * lossyScale.y * hei * pivot.y;
        Vector3 leftPos = transform.right * lossyScale.x * wid * (pivot.x - 1);
        Vector3 rightPos = transform.right * lossyScale.x * wid * pivot.x;

        Gizmos.color = Color.white;

        //꼭지점 추출
        var worldPositions = new Vector3[4];
        worldPositions[0] = transform.position + upPos + leftPos;
        worldPositions[1] = transform.position + upPos + rightPos;
        worldPositions[2] = transform.position + downPos + leftPos;
        worldPositions[3] = transform.position + downPos + rightPos;

        var worldHandlePosition = handle.transform.position;
        Gizmos.DrawLine(worldPositions[0], worldPositions[1]);
        Gizmos.DrawLine(worldPositions[2], worldPositions[3]);
        Gizmos.DrawLine(worldPositions[0], worldPositions[2]);
        Gizmos.DrawLine(worldPositions[1], worldPositions[3]);



        //worldPosition 2 screenPosition
        Vector2[] screenPositions;
        Vector2 screenHandlePosition;
        {

            var canvas = GetComponentInParent<Canvas>();
            Camera cam = null;
            switch (canvas.renderMode)
            {
                case RenderMode.ScreenSpaceOverlay:
                    break;
                case RenderMode.ScreenSpaceCamera:
                case RenderMode.WorldSpace:
                    cam = canvas.worldCamera;
                    break;
                default:
                    break;
            }
            if (cam == null)
            {
                cam = Camera.main;
            }

            screenPositions = System.Array.ConvertAll(worldPositions, wp => RectTransformUtility.WorldToScreenPoint(cam, wp));
            screenHandlePosition = RectTransformUtility.WorldToScreenPoint(cam, worldHandlePosition);

            for (int i = 0; i < 4; i++)
            {
                var color = Color.white;
                if (i < 2)
                {
                    color = Color.black;
                }
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldPositions[i], $"wp[{i}] : {worldPositions[i].ToString("F2")}\nsp[{i}] : {screenPositions[i]}", guiStyle);
            }
        }




        //worldPosition 2 normalizedPosionLocal
        Vector2 localRectHandlePosion;
        {
            var l = (Quaternion.Inverse(transform.rotation) * (transform.position + leftPos)).x;
            var r = (Quaternion.Inverse(transform.rotation) * (transform.position + rightPos)).x;
            var t = (Quaternion.Inverse(transform.rotation) * (transform.position + upPos)).y;
            var d = (Quaternion.Inverse(transform.rotation) * (transform.position + downPos)).y;



            localRectHandlePosion = Quaternion.Inverse(transform.rotation) * worldHandlePosition;
            localRectHandlePosion.x = (localRectHandlePosion.x - l) / (r - l);
            localRectHandlePosion.y = (localRectHandlePosion.y - d) / (t - d);


            {
                var color = Color.green;
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldHandlePosition, $"whp : {worldHandlePosition.ToString("F2")}\nshp : {screenHandlePosition}\nlrhp : {localRectHandlePosion.ToString("F2")}", guiStyle);
            }
        }

        //localRectHandlePosion 2 worldPosition
        {
            var l = (Quaternion.Inverse(transform.rotation) * (transform.position + leftPos)).x;
            var r = (Quaternion.Inverse(transform.rotation) * (transform.position + rightPos)).x;
            var t = (Quaternion.Inverse(transform.rotation) * (transform.position + upPos)).y;
            var d = (Quaternion.Inverse(transform.rotation) * (transform.position + downPos)).y;


            var worldPos = transform.rotation * new Vector3(l + localRectHandlePosion.x * (r - l), d + localRectHandlePosion.y * (t - d), 0);


            {
                var color = Color.gray;
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldPos, "\n\n\nworldPos", guiStyle);
            }
        }

    }
#endif

 

 

v2


#if UNITY_EDITOR
    public GameObject handle;
    void OnDrawGizmos()
    {


        // Draw a semitransparent blue cube at the transforms position
        var rectTransform = GetComponent<RectTransform>();
        if (rectTransform == null)
        {
            return;
        }
        var lossyScale = rectTransform.lossyScale;
        float wid = rectTransform.rect.width;
        float hei = rectTransform.rect.height;
        var pivot = rectTransform.pivot;

        Vector3 downPos = transform.up * lossyScale.y * hei * (pivot.y - 1);
        Vector3 upPos = transform.up * lossyScale.y * hei * pivot.y;
        Vector3 leftPos = transform.right * lossyScale.x * wid * (pivot.x - 1);
        Vector3 rightPos = transform.right * lossyScale.x * wid * pivot.x;

        Gizmos.color = Color.white;

        //꼭지점 추출
        var worldPositions = new Vector3[4];
        worldPositions[0] = transform.position + upPos + leftPos;
        worldPositions[1] = transform.position + upPos + rightPos;
        worldPositions[2] = transform.position + downPos + leftPos;
        worldPositions[3] = transform.position + downPos + rightPos;

        var worldHandlePosition= handle.transform.position;
        Gizmos.DrawLine(worldPositions[0], worldPositions[1]);
        Gizmos.DrawLine(worldPositions[2], worldPositions[3]);
        Gizmos.DrawLine(worldPositions[0], worldPositions[2]);
        Gizmos.DrawLine(worldPositions[1], worldPositions[3]);



        //worldPosition 2 screenPosition
        Vector2[] screenPositions;
        Vector2 screenHandlePosition;
        {

            var canvas = GetComponentInParent<Canvas>();
            Camera cam = null;
            switch (canvas.renderMode)
            {
                case RenderMode.ScreenSpaceOverlay:
                    break;
                case RenderMode.ScreenSpaceCamera:
                case RenderMode.WorldSpace:
                    cam = canvas.worldCamera;
                    break;
                default:
                    break;
            }
            if (cam == null)
            {
                cam = Camera.main;
            }

            screenPositions = System.Array.ConvertAll(worldPositions, wp => RectTransformUtility.WorldToScreenPoint(cam, wp));
            screenHandlePosition = RectTransformUtility.WorldToScreenPoint(cam, worldHandlePosition);

            for (int i = 0; i < 4; i++)
            {
                var color = Color.white;
                if (i < 2)
                {
                    color = Color.black;
                }
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldPositions[i], $"wp[{i}] : {worldPositions[i].ToString("F2")}\nsp[{i}] : {screenPositions[i]}", guiStyle);
            }
        }




        //worldPosition 2 normalizedPosionLocal
        Vector2 normalizedPositionLocal;
        {
            Vector2 localHandlePoint = rectTransform.InverseTransformPoint(worldHandlePosition);

            normalizedPositionLocal = (localHandlePoint- rectTransform.rect.min)/ rectTransform.rect.size;


            {
                var color = Color.green;
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldHandlePosition, $"whp : {worldHandlePosition.ToString("F2")}\nshp : {screenHandlePosition}\nlhp : {normalizedPositionLocal.ToString("F2")}", guiStyle);
            }
        }

        //normalizedPosionLocal 2 worldPosition
        {
            var rect = rectTransform.rect;
            var  worldPos = transform.TransformPoint(rect.min + normalizedPositionLocal * rect.size);


            {
                var color = Color.gray;
                var guiStyle = new GUIStyle();
                guiStyle.fontSize = 16;
                guiStyle.normal.textColor = color;
                UnityEditor.Handles.Label(worldPos, "\n\n\nworldPos", guiStyle);
            }
        }

    }
#endif

 

 

 

 

 

 

 

씬뷰상 오브젝트 거리

아바타툴 만들때 사용함

var screenPoint = HandleUtility.WorldToGUIPoint( transform.position);
targets = targets.OrderBy(target => Vector2.Distance(HandleUtility.WorldToGUIPoint(target.transform.position), screenPoint)).ToArray();

 

 

 

 

 

 

 

 

 

'Unity > C#' 카테고리의 다른 글

유니티 빌드 관련 코드  (0) 2021.08.09
유니티 커스텀 인터페이스  (0) 2021.06.24
유니티 기즈모 (Gizmo) 관련코드  (0) 2021.06.15
posted by 모카쨩

  • total
  • today
  • yesterday

Recent Post

저사양 유저용 블로그 진입