midas+son의 크리에이티브(creative) 이야기


유나이트 2017 초급 트레이닝 바이킹 게임 만들기


유니티 코리아 직원 - 프랑스인 줄리안 - 님의 강의와 

옆의 한국분 통역으로 진행되었다.


유니티를 다시 빠르게 되집어 보기 위해

중급이 아닌 초급을 신청하고 들었는데

4시간동안 계속 흥미진진하게 빠르게 지나갔다.


처음 부분만 너무 초급이라 좀 지루했지만

초반지나고부터 끝까지 흥미롭게 진행되었다.

대부분 다 아는 내용이지만 다시한번 핵심 내용만 빠르게 훑고 간단한 게임 하나가 완성 되었다.

스크립트 작업 없이 준비된 간단한 스크립트와 prefab으로 진행되었다.


진짜 유니티를 처음 해보는 사람이라도 

그렇게 어렵지 않게 게임을 만드는 경험과 

유니티의 기능에 대해 숙지 할수 있는 수준의 내용으로 준비되었는데

강의한 줄리안(?줄리앙??)의 노력이 돋보였다.

매 주마다 이 사람에게 새로운 강의를 듣고 싶을 정도다.


유니티로 게임을 하나라도 만들어본 사람이라면 너무 쉬운 내용이었는지 중간중간 나간 사람도 있었다는 듯하다.


유니티의 모든 기능에 대해서 4시간만에 알려줄수는 없으니 아쉬움이 남긴 했지만

다음에 이와 같은 방식의 트레이닝 행사가 있다면 또 듣고 싶다.(다른 주제와 난이도로...)

오랜만에 유니티 글이네요.


오브젝트 비교하는 구문을 예로 들자면

if (player.gameobject == other.gameobject)
{

//코드...

}

위와 같이 == 로 비교 하는게 편했고 잘 사용해 왔다.


근데 이 간편한 구문보다 약 2배 빠른 비교 방법이 있다는걸 이제 알았다.

원래는 C#의 문법인데 아래 MSDN 참조해보자.

https://msdn.microsoft.com/ko-kr/library/system.object.referenceequals(v=vs.110).aspx


//이건 C# - if(Object.ReferenceEquals(player.gameobject, other.gameobject))

//유니티에선 아래

if(System.Object.ReferenceEquals(player.gameobject, other.gameobject))

{

//코드...

}

주의 할 점은 Reference에 대한 비교이다 보니 

값이 같아도 Reference위치가 다르거나 Value Type이면 False가 떨어진다는 점이다.

null 비교에도 좋다.//System.Object.ReferenceEquals(gameobject, null)

http://uniteseoul.com/2017/

유나이트 2017 서울 공식 사이트


언리얼과 마찬가지로 코엑스에서 개최 합니다.

정확한 트랙 스케쥴은 아직 안나왔지만 

미리 등록 가능하네요.


얼리버드는 아쉽게 오늘(3/28) 까지 입니다.

원래 가격은 10만 이고 얼리버드는 5만 입니다.

사전등록으로 5월 1일까지는 또 8만원 입니다.


2일 분량의 입장권이라 비싼 건 아닙니다.(학생이시면 더 쌈)

5월 16~17일 화, 수요일 이틀간 개최됩니다.


==================================

https://event.eventservice.co.kr/unite17/trainingday.asp

트레이닝 데이라고 5월 15일 월요일

초급레벨 유니티 수업과 

중급레벨 VR수업도 들을 수 있습니다.

요청이 있어서 올려봅니다.


올해 6월 달에 올렸던 포트폴리오 마리오 런 게임을 보고 

타이틀 화면에서 배경이 무한으로 반복되는 것을 어떻게 했는지

궁금 하다고 하셔서 설명 드리겠습니다.


일단 이해를 돕기 위해 막 찍은 아래의 영상을 한번 봐주세요.


1. Image를 하나 Canvas에 만들어 둔다.(uGui 기준)

2. 스크립트로 게임이 실행되면 위의 Image를 복사한다.(그냥 2개 만들어서 써도 되지만 조금이라도 메모리 고려)

3. 원본을 먼저 움직이고자 하는 방향으로 무브. 이때는 하나만 움직인다.

4. 원본이 움직이다가 하나가지고 화면을 커버를 못하면 복사본을 그 뒤에 이어 붙인다.

5. 원본이 더이상 움직일 필요가 없어지면 원본과 복사본을 스왑한다.

6. 3~5가 반복 된다.


위 글로 이해가 잘 안되면 아래의 소스를 봐보세요. (C# 으로 짠 스크립트)

   //배경 루프 함수

   void LoopBackGroundImage()   

    {

        //배경 이미지가 움직여야 될 위치

        float x = backImage.rectTransform.position.x + backMoveSpeed * Time.deltaTime;


        //x위치 검사

        if (x >= backImage.rectTransform.sizeDelta.x)

        {

            //원본 이동 - 남는 부분이 있음

            backImage.rectTransform.position = new Vector3(x, backImage.rectTransform.position.y, 0);

            //남는 부분은 복사본이 영역을 차지하여 이동

            backImageClone.rectTransform.position = new Vector3(x - backImage.rectTransform.sizeDelta.x, backImage.rectTransform.position.y, 0);

        }

        else

        {

            //첫장만 이동

            backImage.rectTransform.position = new Vector3(x, backImage.rectTransform.position.y, 0);

        }


        //원본이 모두 이동하고 더이상 비쳐지지 않을때

        //복사본과 원본을 서로 교체

        if (x - Screen.width >= backImage.rectTransform.sizeDelta.x)

        {

            tempBackImage = backImage;

            backImage = backImageClone;

            backImageClone = tempBackImage;

            backImage.rectTransform.position = new Vector2(Screen.width, backImage.rectTransform.position.y);

        }

    }


그렇게 어려운 건 아닙니다.

어렵다 느낀다면 이제 막 Unity를 배워서 익숙해 지지 않은거지요.


그리고 위에 벡터 쓸 때 Vector3쓰다가 Vector2 쓴거도 있는데 오류 아니라 되는 겁니다.

특별한 의미 없습니다. z를 안바꾸면 저렇게도 써도 돼요.


또 다른 거 얘기 해보자면

new를 안하고 미리 만들어둔거 하나 가지고 쓰는게 좋습니다. 

이건 나중에 자세히 알아보겠습니다.

드로우 콜(Draw call) 이란 렌더링을 위한 그리기 요청으로 CPU의 성능을 많이 잡아 먹는다.

드로우 콜에 대해서 많은 최적화 방법이 있는데

이 글에서는 간단하고 중요도가 큰 4가지만 알아 보겠다.


1. 정적(Static) 배칭

Inspector의 오브젝트 이름 우측 부근에 Static 버튼이 있는데

이 버튼을 적용하면 이 오브젝트는 정적으로 선언된 것이 된다.

하지만 이것만 가지고 드로우 콜을 줄였구나 생가하면 안되고 조건을 맞게 써야한다.

그 조건은 정적이라는 말과 같이 움직이면 안된다.

position, rotate, scale 모두 변화가 없어야 한다.

그리고 메테리얼이 바뀌면 안된다. 동일한 오브젝트는 같은 메테리얼을 사용하여야 한다.

이 조건이 맞춰지고 설정을 해주어야지 드로우 콜이 늘어 나지 않는다.

하지만 이 방법에는 단점이 있다.

그것은 정적 배칭된 객체들은 메모리 사용이 계속 유지되므로 자원 낭비가 심하다는 것이다.

작은 메모리를 가진 모바일에선 그 양에 따라 튕기는 위험성도 가지고 있다.

즉 메모리와 렌더링 성능의 저울질을 잘 할 줄 알아야 한다.


2. 라이트맵 처리

조명에 따라서 렌더링할 때마다 매번 계산을 해준다.

다이렉트x를 할 때에도 주의사항에 있었지만

조명이 많으면 그만큼 있어보이지만 FPS가 급격히 낮아진다.

게임이 잘돌아가지 않는 다는 것이다.

그래서 해당 빛에 대한 값을 게임중에 계산하는 것이 아니라 

게임 빌드 단계에서 정해버리는 것이다.

그러면 게임중에 따로 연산을 하지 않으므로 있어보인다.

하지만 좀 어색해지는 감도 없지않아 생겨버리게 된다.


3.메테리얼 통합

아틀라스(atlras)라고 전문 용어가 있는 듯하다.

여러개의 텍스쳐 였던 것을 하나의 텍스쳐로 통합을 하는 것이라고 생각하면 된다.

통합된 텍스쳐에서 uv좌표값으로 짤라 사용하는 것이다.

여러개의 텍스쳐를 불러 처리하는 것보다 

하나의 텍스쳐를 불러 처리하는 게

드로우 콜에는 좋은 듯 하다.

기본적으로 유니티에서 Sprite packer로 여러개의 텍스쳐를 스프라이트화 시킬 수 있고

NGUI를 사용하면 Atlras Maker로 아틀라스를 만들어 사용할 수 있다.


4.오클루전 컬링(Occlusion Culling)

벽이 있고 벽 뒤에 오브젝트가 있는데 카메라는 벽을 정면으로 바라보고 있다.

게임 씬 에서는 뒤에 있는 오브젝트가 안그려지지만

내부적으로는 그려지고 있다.

안보이는데 처리를 한다.

그것이 비효율적이기에 생긴 기법이 오클루전 컬링이다.

유니티에서는 옵션으로 처리할 수 있다.

프러스텀컬링(Frustum Culling)이랑 헷살리면 안되는데 

프러스텀 컬링은 카메라 영역 외부에 있는 오브젝트들을 그리지 않는 것이다.

오클루전 컬링(Occlusion Culling)은 카메라 영역 내부에 있는 오브젝트 중에 

다른 오브젝트가 덮어씌워 안보이게 되는 것을 미리 렌더링 처리를 안한다는 것이다.

테스트 해보니 살짝 보일 부분도 처리를 안한다거나 하는 부족한 부분이 

조금씩 눈에 띄기는 하지만 잘 사용해보자.

크게 2가지만 생각을 하면 된다고 한다.


1. 게임같이 만들기

시작->인게임->끝


위의 요소가 분명 해야 한다. 

인게임만 있으면 없어 보인다.


2. 중점적으로 보여주고자 하는 내용 정하기

i.   ui

ii.  ai(waypoint, BossPattern)

iii. system(puzzle, Run)


하나의 포폴에서 전부 잘하기는 쉽지 않다.

위의 3가지 외에도 부각 시킬 수 있는 장점을 찾아서 보여주자.

UI를 이쁘게 잘 만들거나, 

AI를 잘 짜거나, 

시스템 요소가 좋다거나 

해당 포폴에 대한 방향성을 정하고 시작하는 것이 좋다.

NGUI를 처음 접해보면 이미지를 하나 가져다가 쓰고 싶은데

이미지에 해당 하는 항목이 여럿 보여서 심란할 것이다.


그래서 간단하게 구분을 해보도록 하겠다.


1. Sprite 

NGUI에서 만들어낸 Atlas를 이용해서 이미지를 가져오는 것이다.

유니티로 스프라이트 만든 것을 가져오는 것은 안되고 시도해봤자 나뉘기 전의 통짜 원본이 들어간다.


2. Texture

그냥 단일 이미지를 띄우는 것이라고 생각하면 된다.


3.Unity 2D Sprite

유니티에서 만들어낸 스프라이트를 사용하는 것이다.

1번에서 안됐던 유니티용 스프라이트를 쓰고자 하면 이 항목을 선택해야 한다.



카메라를 별도로 달아서 

백미러, 사이드 미러 같은 별도의 뷰 영역을 만들어 보자.


별도의 Camera Object와 Renderer Texture와 teuxture Material을 사용하여

하나의 display에서 여러 카메라를 보일수는 있지만

거울이라는 것은 좌우가 반전이 되어있어야 한다.


별도의 옵션을 찾지 못해 위와 같이 스크립트로 처리를 했다.


렌더 관련 이벤트 함수 호출 순서는 

OnPreCull() -> OnPreRender() -> 오브젝트들 렌더 -> OnPostRender()

순이다.


camera.ResetProjectionMatrix(); 는 가이드를 보면 

"projection이 노멀 카메라 파라미터들을 반사하도록 만들 때 사용한다."라고

되어있는데 함수 명대로 ProjectionMatrix를 Reset해주는 것이 아닐까 생각한다.

그 후 projectionMatrix의 scale을 x축으로 반전하도록 처리하고 

GL.invertCulling = true; 를 하여 백페이스 컬링을 반전 시킨 것이다.

그리고 오브젝터 렌더가 끝나면 

백페이스 컬링을 다시 원래 값으로 돌린다.


위처럼 카메라에 스크립트를 넣으면 거울 처럼 좌우가 반전된 영역을 얻을 수 있다.



'공부 > Unity' 카테고리의 다른 글

포트폴리오 잘하는 법  (0) 2016.08.25
NGUI 이미지 분류법  (0) 2016.08.07
There are 2 audio listeners in the scene 해결 방법  (0) 2016.07.01
MipMap(밉맵) - 이론  (0) 2016.06.29
Resources.Load<TextAsset> 가 null 일 때  (0) 2016.06.22

There are 2 audio listeners in the scene. Please ensure there is always exactly one audio listener in the scene.



위의 메세지가 Console에 계속 출력될 때에는

카메라를 뒤져보자.

씬 하나에는 Audio Listener가 하나 있어야 되는데

Camera Object를 추가하면

Audio Listener가 기본적으로 달려 있어서

Main Camera에 달린 Audio Listener와 겹치기 때문이다.


뒤에 추가한 Camera에서 Audio Listener를 찾아서

비활성화 하거나 Remove Component를 해주자

'공부 > Unity' 카테고리의 다른 글

NGUI 이미지 분류법  (0) 2016.08.07
Camera Mirror(Reflect) - 거울(반사)  (0) 2016.07.04
MipMap(밉맵) - 이론  (0) 2016.06.29
Resources.Load<TextAsset> 가 null 일 때  (0) 2016.06.22
NGUI 한글 입력 문제 - ime 버그  (0) 2016.06.19

밉맵(MipMap)이라고 불리는 맵핑(Mapping) 기법을 알게되었다.


DirectX를 할 땐 신경 쓰지 않았는데

유니티에서는 기본으로 되어있는 옵션이 있어서 알아보았다.


멀리 있는 사물이나 땅에 Texture를 씌운다고 생각을 해보자.

한 영역이 화면에서는 멀리 있어서 8 pixel 이내에 찍어야 하는데

그 영역에 들어갈 Texture가 256x256 짜리라면 이 것을 줄여

연산을 통해서 그 적은 pixel만큼 들어갈수 있게 평균을 낸 RGB값을 넣게 된다.

멀리 떨어져 있다면 그 영역의 수도 많아지게되고

연산이 많아 지는 것은 3D 에서의 큰 문제일 수 밖에 없다.


그래서 나온 방법이 미리 미리 작은 해상도의 Texture를 준비하는 것이다.(논리적이든 물리적이든)

Texture의 크기는 2의 배수로 하는 것이 최적이고

256x256이라면 128x128, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2....와 같이 

미리 적은 pixel의 Texture를 메모리에 넣어 놓고

나중에 연산을 할때 적절한 크기의 Texture를 꺼내 사용하는 것이다.


장점은 말그대로 런타임 시의 연산을 줄여 프레임이 떨어지는 것을 미리 방지 할 수 있다는 것이고

단점은 미리 Texture를 만들어넣기 때문에 메모리를 많이 사용한다는 것이다.


옛날에는 하드웨어 성능이 좋지 않아 메모리 문제도 생각을 많이 했지만

요즘은 모바일도 렘이 크기 때문에 MipMap을 사용하는 것이 3D게임에서는 기본이라 생각하면 된다.

2D는 오히려 버짐 현상이 나올 수 있으므로 MipMap을 사용 하지 않는 것이 좋다.