카테고리 없음

면접 질문 답 Unity

1vdlrwnsv1 2025. 5. 12. 21:17

벡터의 내적과 외적

 

내적(Dot Product)

두 벡터간 각도 또는 방향의 유사도을 알고 싶을 때 사용함

 벡터의 방향이 완전히 동일한 경우에는 1 값을 가지고, 90도의 각을 이루면 0 값, 180도로 반대의 방향을 가지면 -1 값을 가지게 된다. 즉, -1 이상 1이하 값을 가지며 값이 1에 가까울수록 유사도가 높다고 판단할 수 있다

결과는 스칼라(숫자) 이며

1: 같은 방향

0: 수직

-1: 반대 방향

 

사용 예시:

시야 판별: 플레이어가 적을 바라보고 있는지 확인할 때.

Vector.Dot(player.forward, directionToEnemy) > cos(시야각/2))

 

외적(Cross Product)

두 벡터로부터 수직인 벡터를 만들 때 사용함

결과는 벡터

벡터는 두 벡터가 이루는 평면에 수직

방향은 오른손 법칙 따름

 

사용예시:

캐릭터 회전 방향계산: 왼쪽인지 오른쪽인지 판단

법선 벡터 계산: 3D 모델에서 삼각형의 법선 구할 때

트랜스폼 보정: LookAt 방향을 기준으로 회전 축 만들기

 

예 플레이어 이동 

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    public Transform cameraTransform;

    private void Update()
    {
        // WASD 입력값을 받아 방향 벡터로 변환
        Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;

        if (moveInput.sqrMagnitude > 0.01f)
        {
            // 카메라 기준으로 방향 변환
            Vector3 camForward = cameraTransform.forward;
            Vector3 camRight = cameraTransform.right;

            // 수평 이동만 하도록 Y축 제거
            camForward.y = 0;
            camRight.y = 0;
            camForward.Normalize();
            camRight.Normalize();

            // 이동 방향 계산 (카메라 기준)
            Vector3 moveDir = camForward * moveInput.z + camRight * moveInput.x;
            transform.position += moveDir * moveSpeed * Time.deltaTime;

            // ✅ 내적(Dot): 내 캐릭터의 정면 방향과 이동 방향이 얼마나 비슷한지 판단
            // 1 → 같은 방향, -1 → 완전히 반대, 0 → 수직
            float forwardDot = Vector3.Dot(transform.forward, moveDir);
            Debug.Log("전방 내적 (1이면 정면, -1이면 후면): " + forwardDot.ToString("F2"));

            // ✅ 외적(Cross): 현재 바라보는 방향과 이동 방향으로 회전 방향(왼/오)을 알 수 있음
            // y > 0 → 왼쪽으로 회전해야 함
            // y < 0 → 오른쪽으로 회전해야 함
            Vector3 cross = Vector3.Cross(transform.forward, moveDir);
            float rotationDir = cross.y > 0 ? 1 : -1;
            float angle = Vector3.Angle(transform.forward, moveDir);

            if (angle > 1f)
            {
                // 바라보는 방향을 이동 방향으로 부드럽게 회전
                transform.rotation = Quaternion.Slerp(transform.rotation,
                    Quaternion.LookRotation(moveDir), Time.deltaTime * 10f);
            }
        }
    }
}

 

쿼터니언을 사용하는 이유

https://nbcamp.spartacodingclub.kr/blog/%EA%B0%9C%EB%85%90-%EC%BD%95-%EC%BF%BC%ED%84%B0%EB%8B%88%EC%96%B8quaternion-21484

 

쿼터니언은: 3d 회전을 표현하는 수학적 구조

유니티에서 3D 공간의 회전을 나타내는 데이터 형식입니다

 

왜 필요한가? : 오일러 회전의 한계 때문

 

오일러 회전 문제점:

 

회전 보간이 부자연 스럽다: 회전 애니메이션이나 Lerp사용시 끊김

 

짐벌락: 회전축이 겹쳐 자유도가 줄어드는 현상

 

대충 어떤순서로 회전을 시키든 어떻게든 회전축이 겹쳐서 더 이상 회전할 수 없는 상태 혹은 원하는 회전을 줄 수 없는 상태를 말하는 것 같다(아님 말고)

 

 

  • 짐벌락은 회전 축 두 개가 정렬되거나 겹쳐서회전의 자유도가 줄어드는 현상.
  • 회전 순서에 따라 생기기도 하고, 특정 각도에서 발생함 (특히 pitch가 ±90도일 때 자주 발생).
  • 유니티에서도 eulerAngle로만 회전 처리하면 이슈가 생길 수 있음.

 

 

https://m.blog.naver.com/jsjhahi/205951840(짐벌락 현상 정리 블로그)

 

DirectX 짐벌락 현상 ( Gimbal Lock )

짐벌락 현상 ( Gimbal Lock )     짐벌( Gimbal )   - 짐벌이란 물체가 회전하도록 중심...

blog.naver.com

 

쿼터니언의 장점:

짐벌락 방지

부드러운 회전 보간(Slerp) 사용 가능

연속적인 회전누적이 안정적이다

 

유니티 내부 회전 시스템은 기본적으로 쿼터니안 기반임:

transform.rotation, Quaternion.Lerp, Quaternion.Slerp 등을 통해 회전 연산

 

네트워크 프로토콜(IP, TCP, UDP)이 뭔가?

 

IP 장치 간의 주소 체계로, 클라이언트가 포톤 서버와 통신할  사용됩니다.

포톤 서버는 오브젝트 회전이나 위치정보, 음성채팅 등 실시간 게임 데이터는 UDP 기반의 Photon Realtime 서버를 사용하는데, 이는 실시간 게임에서 빠른 통신이 중요하기 때문입니다.

다만 UDP 신뢰성이 없기 때문에, 포톤은 Photon Chat SDK 통해 TCP 기반으로 통신하며, 메시지 유실이 없어야 하므로 신뢰성이 높은 TCP 프로토콜을 사용

 

IP(Internet Protocol)

모든 컴퓨터에 주소(IP주소) 를 부여하고 데이터를 전달

택배 시스템의 주소 개념

 

TCP(Transmission Cotrol Protocol)

연결기반, 신뢰성 있는 통신

순서 보장, 손실 시 재전송, 흐름 제어, 혼잡 제어 포함

예시: 웹 브라우징, 파일 전송, 채팅 시스템 등

 

UDP(User Datagram Protocol)

비연결 기반 빠르지만 신뢰성 없음

순서, 재전송 없음. 지연이 적음

예시: 온라인 게임, 실시간 스트리밍, 음성채팅 등

 

 

TCP 와 UDP 차이

 

TCP는 신뢰성 있는 연결 지향 프로토콜ㅇ임

특징: 연결지향, 데이터 순서 보장, 데이터 손실 복구, 흐름 제어(수신자가 감당 되는 속도로 전송), 혼잡 제어(네트워크 혼잡시 속도를 낮춰 안정을 유지함)

 

사용예시: 웹 브라우징, 이메일, 파일 전송, 채팅기능 등

 

UDP는 빠르지만 신뢰성 없는 비연결 프로토콜

특징: 연결 없음, 순서와 재전송 없음(오면 받고 아니면 말고), 오버헤드(어떤 기능을 하기 위해 추가로 드는 시간) 적용 빠름(실시간 성능 우선)

사용 예시: 온라인 게임, 스트리밍, 음성 통신

 

항목                          TCP                                                                                   UDP 

연결 방식 연결 지향 (3-way handshake) 비연결
속도 느림 (신뢰성 확보) 빠름 (신뢰성 없음)
용도 웹, 메일, 채팅 게임위치정보, 음성 통신, 영상 스트리밍

 

3-way handshake? : TCP통신에서 연결을 맺을 때 사용하는 3단계 과정

절차: 클라이언트가 서버에 신호 보냄 -> 서버가 응답 -> 클라이언트가 연결 신호 보냄

이 과정이 끝나여 데이터 전송 가능

연결 확실히 맺었기 때문에 신뢰성 확보

 

렌더링 파이프라인

 

렌더링 파이프라인은 3D 씬을 화면에 출력되는 픽셀 이미지로 바꾸는 일련의 과정

 

3차원으로 만들어진 모델을 2차원으로 투영하는 렌더링 과정의 프로세스를 자세하게 표현한 것

 

 

  • Scene 구성
    • 오브젝트, 조명, 카메라 배치
  • 카메라에서 프러스텀 안 오브젝트 수집 (Culling)
  • 셰이더 실행
    • Vertex Shader: 정점 → 화면 좌표로 변환
    • Fragment Shader: 픽셀당 색상/조명 계산
  • 라스터화 (Rasterization)
    • 삼각형 → 픽셀 단위로 쪼갬
  • Z-Buffer / Depth Test
    • 가장 가까운 픽셀만 남기고 나머지 버림
  • 최종 색상 버퍼 출력
    • 화면에 렌더링

 

3D 공간에 있는 오브젝트들이 화면에 표현되는 픽셀로 표시되기까지의 과정

  1. World Space → View Space (모델뷰 변환)
    • 오브젝트의 위치를 카메라 기준으로 변환
  2. View Space → Clip Space (투영 변환)
    • 원근감을 위한 투영행렬 적용 (Perspective/Orthographic)
  3. Clip Space → NDC (정규 장치 좌표)
    • 좌표를 -1~1 범위로 정규화
  4. NDC → Screen Space
    • 화면 해상도 기준으로 픽셀 위치 결정
  5. 라스터화(Rasterization)
    • 삼각형을 픽셀 단위로 나눠서 채움
  6. Fragment Shader 실행
    • 각 픽셀의 색상 계산 (조명, 텍스처 등)
  7. Depth Test 및 Blend
    • 깊이 확인 및 반투명 처리
  8. 프레임버퍼에 그리기
    • 최종 이미지 출력

 

셰이더를 활용해본 경험이 있을까요? 어떻게 활용했는지 설명해주세요.

 

커스텀 셰이더를 작성해서 홀로그램 조준경을 구현했었음

Shader "Custom/Holographic"
{
    Properties
    {
        _MainTex ("Dot Texture", 2D) = "white" {}
        _DotColor ("Dot Color", Color) = (1, 0, 0, 1)
        _GlowStrength ("Glow Strength", Range(0, 10)) = 1
        _Thickness ("Dot Thickness", Range(0.5, 3)) = 1
    }

    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent+10" }
        LOD 100

        Pass
        {
            ZTest Always
            ZWrite Off
            Blend One One
            Cull Off

            Stencil
            {
                Ref 1
                Comp Equal
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed4 _DotColor;
            float _GlowStrength;
            float _Thickness;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 texCol = tex2D(_MainTex, i.uv);

                // 텍스처 알파를 두께 비율로 제곱 조절 (중심 확장 느낌)
                float alpha = pow(texCol.a, 1.0 / _Thickness);

                // 알파 컷팅
                clip(alpha - 0.1);

                // 최종 색상 = 도트 색상 * 조정된 알파 * 글로우 세기
                float glow = alpha * _GlowStrength;
                return fixed4(_DotColor.rgb * glow, glow);
            }
            ENDCG
        }
    }
}

기능 

알파 텍스쳐 기반 도트효과

중심부 밝기 강조

glow효과

Stencil 버퍼 활용 (특정 영역에서만 표시 되게)

 

"Queue"="Transparent+10" 으로 렌더링 순서 조정 Blend One One을 사용해 Additive Blending으로 발광 느낌을 줬음
ZWrite Off와 ZTest Always를 써서 깊이 버퍼에 영향을 주지 않도록 함
 
  • tex2D로 불러온 알파값을 _Thickness로 보정하여 도트 중심부가 더 강하게 보이도록 했음
  • pow(texCol.a, 1.0 / _Thickness)를 통해 두께감 제어가 가능

clip(alpha - 0.1) 일정 알파 이하값은 버려서 또렷한 경겨를 유지 블러없이 깔끔한 패턴 연출

 

_GlowStrength를 곱해서 발광효과 강도 조절 가능

스텐실 조건: Stencil {Ref 1 Comp Equal}을 통해 미리 설정된 스텐실 마스크 영역에서만 보이게 제한

 

Lens셰이더를 갖고 있는 오브젝트를 통해서 봤을때만 보이게 만듦