블로그

  • KPT 시작하기

    – 준비물 : 화이트보드, 포스트잇(3개 컬러), 두꺼운 펜, 타임 타이머

    – 참가 인원 : 지금까지 진행자 포함 총 8명까지는 진행해보았다. 6명일 때는 여유가 있었고 8명이 되었을 때는 50분을 꽉 채우거나 5분 오버하는 경향이 있었으니 참고 바란다. 

    타임 타이머는 구글 스프린트에서 사용되는 마법의 시계를 추천한다. 현재 남은 시간을 시각적으로 표현하고 있어서 각자 정해진 시간 안에 마칠 수 있도록 해준다. 팀 내 스프린트에서도 잘 사용하였는데 짧은 시간 안에 Keep, Problem, Try를 작성하고 공유해야 하는 KPT에도 타임 타이머는 굉장히 활용도가 높았다. 물론 다양한 종류의 타이머를 사용해도 좋다. 대신, 현장에서 정해진 시간이 줄어드는 것이 보일 수 있게 하여 짧은 시간 안에 집중해서 작성 및 공유를 마칠 수 있도록 유도하는 게 중요하다.

    5ef522c7f4bc74ec2d1cf21fb6dcadf7.jpg

    작성 방법은 포스트잇이나 웹 서비스를 사용해도 괜찮지만, 모이는 건 오프라인으로 다 같이 모여서 하길 추천한다. 같은 장소에 모여서 얼굴을 보고 이야기를 나누는게 가장 좋았다.

    타임 스케줄

    시간은 50분 정도로 진행되며 만약의 상황에 대비해 10분 정도 여유를 가지자. 진행 순서는 아래와 같다.

    – KPT에 대해서 설명 : 5분

    – Keep, Problem 작성 : 5분

    – 각자 작성한 Keep, Problem 공유 : 10분

    – Try 작성 : 7분

    – 각자 작성한 Try 공유 : 8분

    – 팀 및 프로젝트에 활용할 Try & Action 선정 : 15분

    KPT에 대해서 설명 (5분)

    KPT를 팀에서 진행하자고 하면 다들 처음 듣는 키워드에 어렵게 느낄 수도 있다. 나는 PM(또는 팀 리더)이 먼저 KPT에 대해서 공부하고 간략하게 공유할 자료를 만들었으면 한다. 자료의 내용은 대략 이렇다.

    – 팀 및 프로젝트 회고의 목적

    – KPT Goal : KPT가 끝나는 조건을 한 문장으로 작성

    – KPT 설명 : 개요, Keep, Problem, Try에 대해서

    – 타임 스케줄

    나는 이 자료를 만들어서 매번 KPT를 할 때마다 짧게라도 어떤 내용인지 꼭 설명을 하고 KPT를 진행하고 있다. 새롭게 들어온 멤버가 있거나 시간이 어느 정도 지난 시점이라면 해당 방법론에 대해서 잊어버렸을 가능성이 있기에 KPT에 대해서 1분이라도 꼭 설명 후 시작한다. 그리고 같은 팀에서 첫 번째 KPT를 잘 마쳤다면 두 번째부터는 KPT에 대한 설명을 짧게하고 이전 KPT에서 결정된 Try & Action의 결과물을 간단하게 공유하는 시간으로 한다.

    Keep, Problem 작성 (5분)

    포스트잇 컬러는 Keep (옐로), Problem (핑크)로 나눠서 각 멤버에게 나눠준다. 멤버는 5분 동안 각자 생각하고 있는 Keep, Problem에 대해서 작성한다. 내용이 어느 한쪽에 치우쳐도 괜찮다. 5분 동안 본인의 생각을 작성하는게 중요하다.

    Keep은 현재 만족하고 있는 부분(Good), 계속해서 이어갔으면 하는 부분(Keep)을 자유롭게 작성한다. Problem은 불편(or 불만)하게 느끼는 부분, 개선이 필요하다고 생각되는 부분, 잠재적인 문제를 작성한다. 진행자 본인도 해당 시간 동안 똑같이 작성한다. (타임 타이머는 누구라도 고개를 들면 확인할 수 있도록 하는게 중요하다)

    Keep, Problem 공유 (10분)

    08944b620ac410d7fd56d101f6672312.jpg

    각자 자기 순서가 오면 작성한 Keep과 Problem를 읽고 진행자에게 넘겨준다. 진행자는 넘겨받은 포스트잇을 화이트보드의 Keep 영역과 Problem 영역에 붙인다. 타인의 순서에 나온 내용이 본인의 것과 같다 하더라도 그냥 듣는다. 각자 공유가 다 된 후에 이해가 안 되는 부분에 대해서는 작성자에게 의미를 물을 수 있다. 작성자는 해당 내용이 어떠한 것인지 간략하게 설명할 수 있으며 현재 KPT에 참여하고 있는 멤버들이 해당 건에 대해서 이해할 수 있도록 돕는다.

    다만, 여기서 주의할 점은 불필요한 논쟁과 토론은 금지한다. 각 멤버가 토론을 시작하면 진행자는 중재하고 Try 작성에서 해당 문제에 대한 해결책을 제안해달라고 언급 후 다음 순서로 넘어가자. 말 그대로 Keep과 Problem을 공유하는 자리임을 잊지 말자. 공유를 통해서 현재 팀 내에서 좋았던 점, 불편했던 점등이 가시화되어 구성원들에게 공유가 되는 것이 중요하다.

    Try 작성 (7분)

    참가자 전원이 각자 Try에 대해서 생각해본다. 마구잡이로 아이디어를 내는 것보다 조금 전에 각 멤버들로부터 나온 Problem의 해결책에 대해서 생각해보는 것이 좋다. 예를 들면, 결과물에 실수가 많다라는 Problem에 대해서 다음부터는 신경 써서 잘하자보다는 제출 전에 팀 멤버에게 리뷰 받는 구조를 만들기를 통해서 해당 문제에 대해서 다들 좋게 좋게 넘어가는게 아니라 간단하더라도 확실히 해결할 수 있는 솔루션을 제안하여 팀 내에서 일어나고 있는 불편한 부분을 해소할 수 있는 게 가능하다. 개인적으로는 아래와 같은 내용이 Try 작성에 도움이 되었다. 

    – Try는 다음 KPT(회고)에서 판별이 가능한 것으로 할 것. 

    – 자신의 행동으로 컨트롤 가능한 것으로 할 것. 

    – KPT가 끝나자마자 실행 가능한 것을 제안할 것.

    Try 공유 (8분)

    43f802dd24d0b9066250ffdcd990f0ff.jpg

    각자 자기 순서가 오면 작성한 Try를 읽고 진행자에게 넘겨준다. 진행자는 넘겨받은 포스트잇을 화이트보드의 Try 영역에 붙인다. (비슷한 솔루션은 그룹핑해서 붙여두는 것도 좋다)

    각자 공유가 다 된 후에 이해가 안 되는 부분에 대해서는 작성자에게 물어볼  수 있으며 작성자는 해당 내용이 어떠한 것인지 간략하게 설명할 수 있다. 물론, 이때도 토론 및 논쟁은 불필요하다. 정해진 시간 안에 공유를 마칠 수 있도록 진행자의 판단이 중요하다.

    Try & Action 선정 (15분)

    Try 공유가 끝났다면 이 안에서 다음 KPT 실시까지 Action을 취해서 개선할 수 있도록 Try(솔루션)를 정하는 게 필요하다. 나도 처음에는 이 부분에 시간 할당을 많이 해서 토론도 하고 솔루션에 대해서 깊게 나눠봤지만 시간만 쓰고 좋은 결과로 이어지지 않았다. 그 후 선택하고 있는 방법이 각자 마음에 드는 Try에 투표를 하는 것이다. 한 사람당 2-3개의 투표권이 있고 자신의 것에 투표해도 무방하다. 이렇게 하면 현재 팀 내에서 가장 문제시되고 있는 것에 대한 Try(솔루션)가 자연스럽게 상위에 올라오게 된다.

    한 번의 KPT에서 정할 수 있는 Try는 최대 3개로 한다. 그리고 중요한 것은 해당 Try에 대한 담당자를 선정하고 어떠한 결과물로 공유할 지 그 자리에서 이야기한다. (담당자는 거수형태로 했다. 아무도 없을 때는 팀 리더가 하는게 가장 좋았다)

    예를 들어, 결과물을 제출 전에 팀 멤버에게 리뷰 받기가 Try로 선정되었다면 담당자가 이 Try에 대해서 리뷰를 받는 플로우 및 룰을 문서로 정리해서 팀에 공유하면 된다. (대체적으로 문서화하여 솔루션으로서 공유하는 케이스가 가장 많다. 각 담당자의 재량에 따라 프로토타입이나 다양한 형태의 솔루션이 나오는 경우도 있다)

    여기서 중요한 건 솔루션은 각 담당자에게 맡기는 것이다. 그 자리에서 어떠한 솔루션으로 해야 한다는 디테일한 부분까지 이야기하면 끝이 없다. 다음 KPT 실시까지 각 담당자가 Task로 가지고 있으면서 본 업무 외에 시간이 남을 때 진행할 수 있도록 여유를 준다. KPT를 여는 주기는 1달 간격으로 하고 있다. (2주나 3주도 괜찮지만 1달도 은근 금방 오더라)

    단, 다음 KPT까지는 담당자가 Task를 완료할 수 있도록 팀 리더가 어느 정도 기간이 지나면 진행 상황에 대해서 체크할 필요가 있다. 경우에 따라서는 바로 해결하는 멤버가 있는가 하면 다음 KPT가 시작되기 직전에 완료해서 공유하는 경우도 있다. 정답은 없다. 팀 내에 언급된 문제에 대해서 솔루션이 제안되고 다들 그 내용에 맞춰서 움직여 보는 것이다. 그래도 부족하다면 다음 KPT에서 Problem으로 언급하여 Try로 연결하면 된다. 본인이 생각했던 Try가 선정되지 않았다고 실망할 필요도 없다. 정말 문제라면 또 언급될 것이고 그때 선정하면 된다.

    팀 리더의 세심한 관리가 필요하다.

    a79f33c85de7bc6877823c7187288e12.jpg

    의외로 언급되는 문제들을 보면 솔루션으로 연결하지 않아도 리더와 멤버들이 조금만 주의하면 해결할 수 있는 것들도 상당수이다. 이 부분은 리더가 먼저 캐치해서 평소 업무 중에 신경 써서 각 멤버들이 불편하게 생각했던 부분에 세심한 배려를 하면 좋을 것이다.

    팀 멤버에게 최대한 부담을 주지 않으면서 KPT를 주기적으로 열기 위해서는 팀 리더의 세심한 관리가 필요하다. KPT가 끝나고 각 Try 담당자에게 Task를 할당하거나 금일 언급된 내용을 회의록으로 남겨서 어떻게 바뀌어 왔는지 회고할 수 있도록 하는 게 중요하다. 그리고 KPT가 끝나면 다음 KPT 일정도 바로 캘린더에 넣어서 팀 멤버들에게 이 KPT는 계속 이어서한다는 것을 인지시킨다.

    의외로 매달 새로운 문제가 제기된다.

    KPT를 4번 정도 했을 시점이었다. 나름대로 문제라고 생각했던 부분이 어느 정도 팀 내 룰로 정해졌고 해결되었던 부분도 많이 봐왔던 터라 이번 KPT는 Problem이 별로 없지 않을까 생각했던 적이 있다. 근데 아니었다. 그때 회사 및 프로젝트 등 환경에 맞춰서 새로운 문제는 계속해서 나오는 것이었다.

    내 기준으로 봤을 때는 그 당시 팀에 큰 문제가 없어 보였지만 착각이었다. 오히려 평소보다 Problem이 더욱 많이 나오는 것이었다. 굉장히 많이 반성했던 기억이 있다. 내가 봤을 때 괜찮아 보여서 KPT를 쉬자고 하려고 했던 시점이었기 때문이다. 그 이후로는 KPT를 계속해서 하고 있다. 때때로 매우 간단한 Try가 선정되기도 하지만 그 또한 중요하다. 문제가 개선되고 있다는 뜻이기 때문이다.

    매달 KPT를 진행하면 성장한다.

    c5242e2a776a59a674b4a1226cb0274b.jpg

    매달 KPT를 진행하면 다들 진행 방식도 익숙해지고 운영적인 부분 등에서도 피드백을 주기에 각 회사 및 팀 상황에 맞춰서 KPT를 변형해가길 바란다. 그러면서 팀은 더욱 건강해지고 방치되어 있던 문제는 가시화되어 해결되는 솔루션으로 이어질 것이다. KPT는 스타트업뿐 만 아니라 조직이 있는 모든 곳에 적용될 수 있다고 생각된다.

    좀처럼 팀 내에서 서로의 생각을 공유하기 힘들거나, 리더와 멤버 간의 인식 차이가 있거나, 문제를 제안해도 솔루션으로 연결되지 않아 고민이라면 KPT로 해결할 수 있을 것으로 생각된다. 다들 건강하게 팀 동료과 피드백을 주고받으며 성장하길 희망한다.

  • Lerp를 프로처럼 사용하는 방법

    나는 이런 종류의 일을 너무 자주 본다:

    transform.position = Vector3.Lerp(startPos, endPos, Time.deltaTime);
    

    그것을 게시하는 사람은 일반적으로 그것이 Vector3.Lerp“깨졌다”고 확신하지만 실제 문제는 그들이 그것을 올바르게 사용하지 않는다는 것입니다.

    “선형 보간”의 약어인 Lerp는 매우 간단한 작업을 수행합니다. 두 값이 주어지면 두 값 x사이 의 백분율 y값을 반환합니다 . t출력이 변경될 것으로 예상되는 경우 전달하는 인수에 이를 반영해야 합니다!

    Time.deltaTime위의 예에서는 가장 최근 프레임 동안 경과한 시간만 전달하므로 를 전달하는 것은 의미가 없습니다 . 게임이 일정한 50fps로 실행되는 경우 항상0.02 .

    해당 타이머가 여러 프레임에 걸쳐 누적되도록 하면 더 나은 결과를 얻을 수 있습니다.

    이와 같은 내용이 요점을 전달해야 합니다.

    public class LerpExample : MonoBehaviour {
        float lerpTime = 1f;
        float currentLerpTime;
     
        float moveDistance = 10f;
     
        Vector3 startPos;
        Vector3 endPos;
     
        protected void Start() {
            startPos = transform.position;
            endPos = transform.position + transform.up * moveDistance;
        }
     
        protected void Update() {
            //reset when we press spacebar
            if (Input.GetKeyDown(KeyCode.Space)) {
                currentLerpTime = 0f;
            }
     
            //increment timer once per frame
            currentLerpTime += Time.deltaTime;
            if (currentLerpTime > lerpTime) {
                currentLerpTime = lerpTime;
            }
     
            //lerp!
            float perc = currentLerpTime / lerpTime;
            transform.position = Vector3.Lerp(startPos, endPos, perc);
        }
    }

    빈 장면을 만들고, 큐브에 놓고, 이 스크립트를 첨부하고, 실제로 작동하는 모습을 볼 수 있습니다.

    변수는 원래 있던 perc곳에 사용됩니다 . Time.deltaTime무엇입니까 perc? 이는 Lerp를 통한 진행 상황을 나타내는 0와 사이의 숫자입니다 .1

    궁금하신 분들은 lerpTime또는 변경하면 결과를 확인해보세요 moveDistance.

    모든 것을 Lerp

    Unity는 다양한 값을 보간하기 위한 도우미 함수를 제공합니다.

    • Mathf.Lerp
    • Vector3.Lerp
    • Color.Lerp

    하지만 결국에는 Mathf.Lerp 만 있으면 됩니다. 다른 것들은 단지 편의를 위한 방법일 뿐입니다. 보간해야 할 클래스나 데이터에 대해 자체 Lerp 함수를 작성하는 것은 충분히 쉽습니다.

    Unity가 회전을 표현하기 위해 사용하는 쿼터니언의 특정 경우에는 Slerp 또는 “Spherical Lerp”도 있습니다.

    두 개의 값이 있고 두 값 사이를 원활하게 전환하고 싶으십니까? 보간은 당신의 친구입니다!

    Lerp 너머

    만약 우리가 t단순한 백분율이 아닌 Lerp a를 통과한다면 어떻게 될까요? 두 점 사이에 그래프로 표시된 직선 대신 일종의 곡선을 원하면 어떻게 될까요? 0입력은 과 사이에 있어야 1하지만 이를 수행하는 기능이 많이 있습니다.

    예를 들어, sinerp를 사용하여 “완화”할 수 있습니다.

    float t = currentLerpTime / lerpTime;
    t = Mathf.Sin(t * Mathf.PI * 0.5f);
    
    interp-sinerp

    또는 coserp를 사용하여 “편안하게” 할 수도 있습니다.

    t = 1f - Mathf.Cos(t * Mathf.PI * 0.5f)
    
    interp-coserp

    기하급수적인 움직임을 만들 수도 있습니다.

    t = t*t
    
    인터프 쿼드

    그 자체를 곱하는 것에 는 흥미로운 특징이 있습니다. 과 사이에 있는 t한 , 그 자체를 여러 번 곱하면 항상 와 사이에 있는 숫자가 생성됩니다 .t01t01

    스무스스텝

    위에서 언급한 곱셈 속성은 유명한 “스무스 스텝” 공식 과 같이 이지 인(Ease In) 및 이지 아웃(Ease Out)하는 일부 보간 방법의 핵심 개념입니다 .

    t = t*t * (3f - 2f*t)
    
    매끄러운

    아니면 제가 개인적으로 좋아하는 “smootherstep”도 있습니다.

    t = t*t*t * (t * (6f*t - 15f) + 10f)
    
    상호 평활화

    정말 매끄러워요! (저항할 수 없었습니다.)

    제가 언급한 이러한 추가 공식 중 다수는 Unity에 포함되어 있지 않지만, 이를 통해 찾거나 생성할 수 있는 모든 함수를 자유롭게 사용할 수 있습니다.

    숨쉬게 해라

    끝나지 않는 Lerp는 어떻습니까?

    Robert Yang은 “가끔 사인파로 게임의 모든 것을 애니메이션화할 수 있었으면 좋겠다”고 말한 적이 있습니다 .

    일부 게임에서는 플레이어가 실행되는 동안 약간의 “머리 흔들림”이 발생합니다. 다른 게임에서는 메인 메뉴 카메라에 부드러운 밥이 필요합니다. 나는 “코를 고는” 불빛이 점점 희미해졌다가 사라지는 것을 본 적이 있습니다. 어떤 경우이든, 나는 파동 함수가 얼마나 환상적으로 유용할 수 있는지 지적하고 싶습니다. 입력 영역은 무한하므로 끝이 없으며 출력 범위는 좁고 일정하므로 제어하기 쉽습니다.

    예를 들어, 다음 스크립트는 사인파에 따라 객체를 천천히 위아래로 움직이게 만듭니다.

    public class BreatheSimple : MonoBehaviour {
        Vector3 startPos;
     
        protected void Start() {
            startPos = transform.position;
        }
     
        protected void Update() {
            float distance = Mathf.Sin(Time.timeSinceLevelLoad);
            transform.position = startPos + Vector3.up * distance;
        }
    }

    사인파를 조정하면 더 많은 제어가 가능해집니다.

    public class Breathe : MonoBehaviour {
        Vector3 startPos;
     
        public float amplitude = 10f;
        public float period = 5f;
     
        protected void Start() {
            startPos = transform.position;
        }
     
        protected void Update() {
            float theta = Time.timeSinceLevelLoad / period;
            float distance = amplitude * Mathf.Sin(theta);
            transform.position = startPos + Vector3.up * distance;
        }
    }

    진폭은 개체가 이동하는 거리를 제어합니다. period는 얼마나 빨리 수행되는지를 제어합니다.

    interp-sineparams

    플레이어의 머리 봅슬레이에는 작은 진폭과 짧은 기간이 필요할 수 있습니다. 메뉴 카메라의 느린 호흡으로 인해 매우 오랜 시간이 걸리거나 다양한 속도로 여러 축에서 움직임이 필요할 수 있습니다.

    수학을 정리할 수만 있다면 원하는 동작은 무엇이든 얻을 수 있습니다.

    사인파의 절대값만 취하면 어떻게 될까요? 상향 전용 수신 거부.

    사인파의 출력을 0과 사이에 고정하면 어떻게 됩니까 1? 바운스 사이에 일시 중지가 있는 위쪽으로만 바운싱합니다. 이유를 알 수 있나요? 고정된 곡선을 직접 그리면 명확해집니다.

    0.6해당 웨이브의 출력을 과 사이에 고정하면 어떻게 될까요 1? 일종의 “두근두근” 모션을 얻을 수 있나요? UI에서 경고를 확장하는 데 유용할 수 있습니까?

    정말 멋지게 만들고 싶다면 애니메이션 곡선을 사용하여 Lerp 매개변수를 관리할 수도 있습니다.

    나는 꽤 난해한 곡선과 파동 함수를 작성했습니다. 그것을 섞는 것을 두려워하지 마십시오.

    닫는 중

    Lerp는 다양한 응용 프로그램에서 쉽고 강력한 기능입니다.

    제가 작성한 첫 번째 플러그인 중 하나는 다양한 줌과 위치 사이를 보간하는 카메라 관리자였습니다. 또한 보간을 사용하여 재료 매개변수, UI 애니메이션, 물리적 힘, 오디오 볼륨, 간단한 컷씬 등을 관리했습니다.

    이것은 사용법을 알면 점점 더 자주 등장하는 망치 중 하나입니다.

    많은 코드를 작성하고 싶지 않거나 빠르게 시작하고 싶다면 iTween, GoKit 또는 Hotween과 같은 플러그인을 사용하여 Unity에 많은 추가 보간 지원을 추가할 수 있습니다.

  • Essential Mathematics

    내적을 이용한 투영

    두 벡트 v, w 가 있고 w가 0이 아닐때 w위에 v를 투영하는 식은 다음과 같이 정의 한다.
    [latex]proj_{w}v={v \cdot w \over {\vert\vert w \vert\vert}^{2}} w[/latex]

    이것은 w에 평행한 v의 성분을 제공하는데, 이것은 v의 끝에서 w의 위로 수직으로 떨어뜨린 것과 같다.

    v에서 투영백터를 빼서 w에 수직인 v의 성분을 얻을수 있는데 다음과 같다.
    [latex]perp_{w}v=v-{v \cdot w \over {\vert\vert w \vert\vert}^{2}} w[/latex]

    반사벡터

    [latex]P+2n(-P\cdot n)[/latex]

    그람 – 슈미트 직교화

    외적

    보통 두가지 경우에 외적을 사용하는데,

    첫번째는 두 벡터들에 직교화는 벡터를 구하는것.

    두번째는 내적과 마찬가지로 두벡터들이 평행한지를 판별가능.

    [latex]\vert\vert v \times w \vert\vert = \vert\vert v \vert\vert \ \vert\vert w \vert\vert \sin \theta [/latex]

    벡터삼중적

    [latex]u\cdot(v \times w) = \vert\vert u \vert\vert \ \vert\vert v\times w \vert\vert \cos \theta[/latex]

    사용예

    현재 속도가 v이고 d방향으로 이동하고자 하는 탱크가 있다고 하자. 현재 위쪽 방향을 u를 향하도록 탱크의 방위를 맞춘다. 외적 v X d 와 그 결과를 u와 내적해서 나온 결과가 양수 라면, 그때 d가 v의 왼쪽에 있다는것을 알수 있다.

    스칼라삼중적

    아핀공간