꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 알 수 없는 사용자

* 이 글은 필자가 생각해낸 이론에 따라 쓰여진 것이 아니라 Doug Zongker's "Chicken chicken chicken". Presented at the AAAS humor session, February 16, 2007 의 이론에 바탕을 둔 것 입니다.

논문의 전문은:  http://isotropic.org/papers/chicken.pdf 

을 참조하시기 바랍니다. 

0. Chicken Chicken Chicken 

Chicken Chicken Chicken 은 Chicken Chicken Chicken 에서 Chicken Chicken Chicken 한 Chicken Chicken 의 Chicken 으로, Chicken Chicken Chicken 한 것으로 Chicken Chicken 합니다. Chicken Chicken Chicken 은 Chicken Chicken 으로 Chicken Chicken Chicken 하여  Chicken Chicken 함으로서 Chicken Chicken Chicken Chicken 하고 Chicken Chicken Chicken 하게 하여 Chicken Chicken Chicken Chicken 함을 Chicken Chicken Chicken Chicken Chicken Chicken 합니다. Chicken Chicken 함에 있어 Chicken Chicken Chicken 함을 Chicken Chicken 입니다.

1. Chicken Chicken Chicken 

Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken
Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 그러므로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 입니다.


둘째로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이며 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 으로 Chicken Chicken Chicken Chicken Chicken Chicken 함으로서 Chicken Chicken Chicken Chicken Chicken 하여 Chicken Chicken Chicken Chicken Chicken Chicken 하기도 합니다.


마지막으로 Chicken Chicken Chicken Chicken 은 Chicken Chicken Chicken Chicken Chicken Chicken 이며 Chicken Chicken 할 수 있으므로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 으로 평가하는 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이라고 주장하는 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 의 이론에 따라 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 입니다.

2. Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 

Chicken Chicken Chicken Chicken Chicken 은 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 으로 알려져 있으나 Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하다는 것을 Chicken Chicken Chicken Chicken Chicken 함으로서 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하겠습니다.

Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 함을 전제로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하여 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하게 되면 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하며, Chicken Chicken Chicken Chicken Chicken 라 가정하면 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이므로 Chicken Chicken Chicken는 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 함을 알 수 있습니다. 그러므로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 은 Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이며 Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이기 때문에 Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이기도 합니다.



3. Chicken Chicken Chicken Chicken !

Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 을 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 로 보는 관점이 있을 지라도 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이므로, Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하면 Chicken Chicken Chicken 을 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이라는 것을 Chicken Chicken Chicken Chicken으로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 하게 되므로 Chicken Chicken Chicken Chicken Chicken 라는 것을 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 로써 Chicken Chicken 합니다.

결론적으로 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이기 때문에 Chicken Chicken Chicken Chicken Chicken Chicken Chicken 은 Chicken Chicken Chicken Chicken Chicken Chicken 이고, Chicken Chicken Chicken Chicken Chicken Chicken 하며, Chicken Chicken Chicken Chicken Chicken  하는 Chicken Chicken 이 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 합니다.


*     *     *

    몇가지 아이디어를  더 넣는다고 시도를 해 보았지만, 결국 원문을 간추려서 번역한 꼴 밖에 안되네요. 어찌 되었든 Chicken Chicken하고 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 한 Chicken Chicken 은 게임을 개발하는 개발자의 입장에서 볼 때 Chicken Chicken Chicken 하고, Chicken Chicken Chicken Chicken 하기 때문에 게임 기획자와 프로그래머 모두에게 반드시 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 해야 하는 Chicken Chicken Chicken Chicken 라고 생각해서 소개해 봤습니다.

    사실, 디자인 쪽이나 렌더링에 관한건 잘 몰라서 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 이 그 분야에 적용될 수 있는지는 잘 모르겠습니다만, 그래도 Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken Chicken 정도는 적용해 볼 수 있지 않을까 라는 생각을 해봤습니다.

    아직 5년정도 밖에 안된 따끈따끈한 이론이라서 함께 연구해 보면 좋을 듯 합니다. 댓글로 의견좀 많이 달아 주세요

 
반응형
,
Posted by 친절한티스

늦장 연재 죄송합니다. 처음에는 별생각없이 쓰려고 했던 주제인데, 이게 파면 팔수록 어렵네요. 대략 연재할 내용을 구상해놓긴 했었는데, 머릿속에서 정리도 잘 안되고, 쩌렙인증 제대로 하고 있습니다. 고렙분들의 도움이 절실합니다. 혹시 글 내용 보시다가 보완해야 할게 보이시면 덧글 팍팍 달아주세요.


왠지 구조를 바꿔야 할것 같아...
보통 많은 게임들에서 상속 구조를 씁니다. OOP( Object-Oriented Programming ) 디자인을 지향합니다. 하나의 객체를 클래스로 정의하고 상속을 통해 객체를 확장해 나갑니다. 다음은 전형적인 상속 구조를 보여주는 이미지입니다.

끼로님의 이미지를 무단 도용했습니다.
감사합니다. 끼로님. 
 
플레이어를 예를 들면 게임 오브젝트 클래스를 기반으로 하여, 화면에 그려지는 객체이니 RenderableObject 클래스를 구현하고, 움직일수 있어야 하니 MovableObject 클래스를 구현하여 상속 받습니다. 그다지 문제될게 없어보입니다. 그러나 끼로님 포스트도 보시면 아시겠지만 이 방식이 항상 좋은 것만은 아닙니다.
 상속으로 인한 유연성의 부재라든가 여러 이유도 있지만 여기서 이야기 할것은 좀 다른 주제 입니다. 

상속을 통한 오브젝트들을 병렬로 처리 할 때 생기는 문제점들을 한번 알아 보겠습니다. 먼저 싱글 스레드로 각각의 오브젝트들을 업데이트 한다고 가정하겠습니다. 사용자 입력을 받고, 그에 맞게 플레이어를 움직이고, 그 상황에 맞게 적 몬스터라든가 환경들이 업데이트 됩니다. 그리고 업데이트 된 최종 결과물을 화면에 그려내는 것 입니다.

여기서 각각의 오브젝트들이 업데이트되는 과정을 좀더 자세히 들여다 보겠습니다. 사용자가 몬스터를 공격한다고 예를 들겠습니다. 플레이어가 공격 버튼을 입력함으로서, 플레이어 캐릭터는 공격 상태에 들어가게 됩니다. 그리고 상대 몬스터의 AI도 업데이트 됩니다. 플레이어의 공격을 막을 것인지, 피할 것인지, 같이 공격할 것인지 판단을 하게 됩니다. 이 때, 몬스터 오브젝트와 플레이어 오브젝트는 상호작용을 하게 됩니다. 서로를 참조 하며, 서로의 데이터를 검사하고, 공격의 성공, 회피의 성공들을 계산하게 됩니다. 그리고 나온 결과에 맞춰 후액션들이 결정 됩니다. 공격이 성공했으면 몬스터의 피격 액션이, 또는 회피에 성공했으면 회피 모션이 나오 듯이 말입니다.


이 모든 동작은 순차적으로 진행되었습니다. 아무런 문제도 없어 보이고, 상당히 논리적입니다. 그러나 이 과정이 병렬 처리로 들어가게 되면 예상치 못한 결과를 초래하게 됩니다. 가장 큰 문제는 오브젝트들이 서로를 직접적으로 참조 하고 있다는 겁니다. 다시 위의 과정을 살펴봐주세요. 플레이어의 캐릭터가 몬스터를 공격하면서 몬스터 객체를 직접 참조하고 있습니다. 몬스터의 방어력, 회피력을 참조 하고, 또 몬스터도 공격하는 플레이어를 참조하면서 회피할지, 맞대응을 할지 판단하게 됩니다.

병렬 처리에 있어 최대 문제점 중 하나가 데이터 의존성 입니다. 각각의 오브젝트들을 병렬로 처리하다 보면 서로 참조 하는 데이터가 어느 순간에 어떻게 바뀔지 알수가 없게 됩니다. 참조 하려는 데이터가 다른 스레드에 의해서 변질 될수 있기 때문입니다.

이런 문제점(?)이 생깁니다.

좀더 유리한 구조로...
그렇다면 위의 문제점을 해결하면서 병렬 처리에 유리한 방법이 어떤게 있을까요? 찾아보다 보면 여러 가지 방법 중에 눈에 띄는 것이 한가지 나옵니다. 바로 구성 요소 기반 객체 ( Component Based Object ) 입니다. 이것 역시 끼로님께서 연재 중이신 바로 그 것 입니다. (끼로님 사... 사... 좋아해요) 

왜 구성 요소(이하 컴포넌트) 기반 객체 방식이 병렬 처리에 유리한지 알아보겠습니다.  첫 째로 각 객체들을 직접적으로 참조하지 않습니다. 각 객체들은 컴포넌트로 구성 되어있고, 객체들은 직접적으로 동작하지 않고, 컴포넌트를 통해 모든 동작을 수행하게 됩니다. 컴포넌트들은 메시지를 통해 간접적으로 데이터를 주고 받으며, 동작을 수행하게 됩니다. 이를 통해 데이터 의존성 문제를 어느 정도 우회할 수 있게 됩니다.

 이렇게 우회해서 데이터를 전달

두 번째로 객체를 구성하는 각각의 컴포넌트를 하나의 과제(Task)로서 처리할 수 있습니다. 많은 병렬 처리 라이브러리들은 과제 스케쥴링( Task Scheduler )을 지원합니다. 처리해야 할 100개의 과제가 있다고 가정해보겠습니다. 이 과제들은 서로 다른 처리량을 가지고 있으므로, 2개의 스레드에 똑같이 50개씩 분배 했다고 하더라도 동시에 과제 처리를 끝내지는 못합니다. 보통 먼저 과제를 처리 한 스레드가 나머지 스레드를 기다리게 됩니다. 하지만 스케쥴러를 통해 아직 과제를 처리 못한 스레드의 남은 과제를 가져와 보다 효율 적으로 과제를 처리할수 있게 됩니다. 이 스케쥴러를 이용하게 되면 객체 단위로 상태를 업데이트 하는 것보다 기능을 잘게 쪼갠 컴포넌트 방식이 훨씬 유리합니다.

스케쥴링을 통해 효율적으로 과제를 분배

그렇다고 이게 만능은 아니지... 
구성 요소 기반 객체를 쓴다고 해서 데이터 의존성에 완전히 벗어나는 것은 아닙니다. 어떻게든 데이터를 필요로 하는 컴포넌트에 데이터는 넘겨주어야 합니다. 그리고 이 데이터가 업데이트 된 올바른 데이터인지 보장도 필요합니다. 이를 위해 많은 방법들이 나와있습니다. 참조 카운트를 이용해 상위 컴포넌트 부터 처리를 한다거나 필요한 데이터를 가지고 있는 컴포넌트가 아직 업데이트 된 상태가 아니면 처리 중인 컴포넌트를 다시 대기열 뒤로 옮겨 나중에 업데이트 시키는 방식 등이 있습니다.


.... 이렇게 끼로님에게 묻어가기 성공

참고
Evolve Your Hierarchy : Refactoring Game Entities With Components
Game Programming Gems 6
게임 오브젝트 설계.. 나도 잘하고 싶다! by 끼로
Multithreaded Game Engine Architectures
반응형
,
Posted by 김포프

이젠 피할 수 없는 진실이 되고 말았습니다. 사실 실력도 좋은데... 워낙 꽃미남이 되어놓으니... 비주얼로 자꾸 기억해주시는군요.... 뭐 사실은 사실 겸허하게 받아들이겠습니다... -_-

거부할 수 없는 진실은 힘들다.. 어쩌지 이제 잡지 표지모델 제의도 들어오는데...



왠만한 게임 회사에는 프로그래머가 준수해야하는 코딩스탠다드(코딩 스타일이라고도 하죠)가 있는 것 같습니다. 제가 여태까지 프로그래밍을 해오면서도 상당히 많은 코딩 스탠다드들을 봤는데요  (수백만장씩 팔린 패키지 게임에 사용한 엔진만도 5~6개 만져봤으니 뭐 온갖 꼴은 다 봤죠) 요즘들어 코딩스탠다드가 정말 이렇게 빡셀 필요가 있나 하는 의문이 들고 있답니다. (잡생각이 많죠.. 때로...)

우선, 대충 배경지식..... 코딩스타일에서 정의하는 것은 대충 다음과 같습니다.
  • 인덴테이션/줄바꿈
  • 빈칸의 사용
  • 변수이름 짓는 법
  • 함수이름 짓는 법
  • 주석다는 규칙
  • 등등...

코딩스타일의 존재이유?
결국 코딩스타일을 강제함으로 인해 회사에서 얻으려고 하는 건 가독성입니다. 코드 스타일을 통일시키면 다른 프로그래머의 코드를 읽을 때 쉽게 이해할 수 있고, 따라서 생산성을 높일 수 있다는 미신적인 믿음이 존재하죠.

이렇게 하면 프로그래머의 생산성이 높아진다는 부두교의 미신이 있다..... (믿거나 말거나)



코딩 스타일에서 정의하는 것들의 예
우선 코딩 스타일의 예부터.....

인덴테이션/줄바꿈
다음 형태 중에 어떤 놈을 이용할까? 하는 고민...

a)

for ( int i = 0; i < 10; ++i ) {
  sum += i;
}


b)

for ( int i = 0; i < 10; ++i )
{
    sum += i;
}


c)

for ( int i = 0; i < 10; ++i )    sum += i;



등등

빈칸(white space)의 사용
대충 이런 것들 중에 어떤 놈을 써야하는지...

a)

int a = c * ( d + e );


b)

int a=c*(d+e);


등등

변수이름 짓는 법
단어별 대소문자, 멤버변수앞에 m 접두어를 붙이는지 등등...

a)

mMemberVariable = temp_variable * 2.0f;


b)

MemberVariable = tempVariable * 2.0f;


등등

함수이름 짓는 법
단어별 대소문자, private, public 대소문자 등등

a)

int MyClass::getNumPrivate();
int MyClass:GetNumPublic();
int do_something();


b)

int MyClass::_getNumPrivate();
int MyClass:getNumPublic();
int doSomething();


등등

주석다는 규칙
  • 클래스 선언 마다 주석을 달아야 하는가?
  • 함수 선언마다 주석을 달아야 하는가? 변수명 설명? 반환값 설명?
  • 그 외 어떤 코드에 주석을 달아야하는가?
  • 주석 달때 스타일은 어떤걸로? /* ... */,  //, ///, /**...**/ 등등
  • 기타 잡다한 것들...

하지만 의문이 들다
저도 좀 뭔가 깔끔하게 정리되어 있는 걸 좋아하는 놈이라 한동안 이런 미신에 푹 빠져살았습니다. 그런데 최근 몇 년 동안에 '정말정형화된 코딩스타일이 생산성을 향상시키나?'하는 의문이 들더군요. (물론 게임업계에 한정된 이야기입니다. 의료업계에서는 계속 빡세게 해주세요... 수술대 올라갔다가 버그 때문에 뻗은 기계 대문에 죽긴 싫습니다... -_-)

사실 코딩 스타일이란게 종교와도 같은 것이어서 이렇다 할 정답이 없습니다. 프로그래머 10명 잡고 물어보면 다들 선호하는 코딩 스타일이 다릅니다. 일례로 함수이름만 들어도 어떤 프로그래머는 private함수는 getNum() 이란식으로 작성하고 public 함수는 GetNum()이라고 작성하자고 하는 반면 다른 프로그래머는 get_num()과 GetNum()이라고 하자고도 할 겁니다.

어차피 회사란 집단체니까 그냥 일률적으로 정해놓고 프로그래머들을 다 강요하면 된다고 생각하는 건데... 정작 문제는 이 스타일로 개종해야하는 사람들에게는 이게 오히려 생산성 저하의 요소가 됩니다.

중요한건 프로그래머의 상식/배려/역량
그리고 참 웃겼던건.. 제가 지금까지 함께 작업했던 프로그래머만 해도 수백명인데... 그리고 이 엔진 저 엔진 옮겨다니면서 거친 코딩 스탠다드만도 대여섯은 될텐데..... 코딩 스탠다드하고 가독성은 정말 별 상관이 없었단 겁니다. 그보다는 오히려 어떤 코딩 스타일을 사용하던 간에 깨끗한 코드를 작성할 수 있는 프로그래머의 역량이 더 중요하더군요. 이런 분들이 대부분 이었습니다. 즉 굳이 코딩 스탠다드가 필요없는 인간들이 대부분...

회사에서 아무리 철저한 코딩 스탠다드를 만들어 놓아도 코드 드럽게 쓰는 애들(소수에 그칩니다)은 여전히 코드 이해 안되게 쓰더군요. 그래서 이런 애들을 좀 더 잘 관리하려고 코딩 스탠다드에 규칙을 더 추가합니다. 이러면 얘네들이 좀 나아질까요? 아닙니다. 얘네들이 코드가 드러운 이유가 있습니다. 남생각을 별로 안하거든요. 규칙이 얼마나 철저하던 간에 어떻게든 빠져나갑니다. 그 덕에 오히려 원래부터 깔끔한 코드 쓰던 사람들만 고생하죠. 이 사람들은 악법도 법이라고 존중하고, 다른 프로그래머들도 배려할 줄 아는 분들이므로 새로 생긴 규칙에 맞게 또 열심히 코드를 작성합니다. 이 규칙 없어도 원래부터 이해잘되는 깔끔한 코드를 작성하던 사람들인데 따라야 할 규칙만 늘어버렸죠. 

이게 배려라는 거다.... 밥그릇 까지도 깔끔하게... (이미지 출처: http://garul.tistory.com)



결국 제값주고 산 놈들만 손해란 건가?
이렇게 생각을 하다보니.... 꼭 게임에 DRM 입히는거와 마찬가지란 생각이 들더라구요. DRM을 아무리 빡세게 입혀도 해적질 할 애들은 다 해적질하고 쓰니 아무 상관없는데, 정가내고 산 사람들만 그 DRM에 얽매여서 온갖 귀찮은 일을 다 당해야 하는....

해석은 귀찮으니 생략..... 그림만 봐도 대충 뭔 귀찮은 일을 당하는 지 알거다...



차라리 개별적으로 갈구자. 짜르던가. 칼부림도 가끔?
결국 제가 내린 결론은 저희가 너무도 당연하게 여기며 쓰던 코딩 스탠다드가 생각보다 별로 효과적이지 않단 겁니다.

물론 코딩스탠다드를 싸그리 없애자는 건 아닙니다. 좀 최소한으로 줄이자는 거죠. 그리고 코드 드럽게 쓰는 애들을 개별적으로 갈궈서 좀 고치게 하던가... (인간이 직접 갈구는게 문서 던져주고 따라하라는 것보다 훨씬 효율적입니다... 칼부림이 가끔 날 뿐이지... -_-)...... 안되면 그냥 짜르던가....

이런 생각을 하게 된 또 다른 계기는 게임업계가 엄격한 코딩스타일이 필요한 분야가 아니란 겁니다. 어차피 코드작성한 건 다 내부적으로 쓰는거고, 문제 있으면 소스코드가 다 떡하니 있으니 아무나 가서 고칠 수 있으니까요. 게임업계가 아니라 미들웨어를 만들어서 판매하는 회사라던가 군사업체 및 의료장비에 들어가는 소프트웨어를 만드는 회사에서는 이게 좀 더 엄격해야겠죠. 미들웨어 회사는 라이브러리만 던져주는 경우가 많으니 그렇고, 군사업체 및 의료장비는 사람 생명이 걸린 일이라서 어쩌다 뭔 짓을 하더라도 버그를 아예 처음부터 만들지 않는게 중요하니까요. 어차피 게임이 엔터테인먼트 산업이고, 게임의 요구사항은 하루가 멀다하고 바뀌므로 차라리 유연하게 재빨리 코드를 작성할 수 있는게 게임 품질 향상에 더 기여한다고 봅니다. 게임의 품질이란건 사실 게이머가 느끼는 품질일 뿐이거든요. 인간의 목숨이 걸린 의료소프트웨어에서의 품질하고는 전혀 다르죠.

그냥 이정도면 하면 안될까요?
그래서 과연 '코딩스탠다드를 어디까지 줄일 수 있을까?' 하는 걸 좀 생각해봤죠. 이게 좀 간단해야 정작 남 배려할 줄 아는 프로그래머의 인생도 편해지지 않을까 해서....

나도 좀 단순히 편하게 살고 싶다... 물론 패리스 힐튼과 함께.... 근데 토토샵 질이 좀 심한데? -_-



위에서 들었던 목록을 한번씩 살펴보면서 이야기하죠.

인덴테이션
코드의 가독성을 위해서는 여전히 중요하다고 생각합니다. 특히나 코드의 scope를 보여주는데 도움이 되니까요. 근데 이제 Visual Studio 가 이런 인덴테이션을 직접 알아서 해주므로 크게 걱정할 필요가 없습니다. 20년 전에 이런 게 자동으로 안될때나 문제였지...

빈칸사용
뭐 이건 사실 int k = a * ( b + c );로 해주냐 int k=a*(b+c);로 해주냐 차인데... 어떻게 쓰던 코드 이해하는데 별 차이가 없습니다.... 굳이 목숨 걸 필요 없지 않나요? -_-

변수명/함수명
일단 멤버변수 이름앞에 m을 붙이니 public 함수는 대문자로 시작하니 마니 하는 건 이젠 별 의미가 없는거 같습니다. 어차피 IDE가 워낙 좋아져서 그냥 마우스만 올려도 나오는 경우가 많고 아니면 F12키 한번 누르면 곧바로 선언된데로 이동하니까요. 그리고 다시 돌아올땐 Ctrl + -키 누르면 끝이고... Visual Studio의 인텔리센스가 잘 작동안하면 Visual Assist 를 깔아도.....

단, 가독성을 위해 변수명이나 함수명을 잘 작성해주는 건 찬성입니다. 즉 int a = 1; 이라기보단 int numLoop = 1; 이란 식으로 변수명을 작성해주는거죠.. 딱 보면 이해가 되게... 함수명도 마찬가지고요.

주석다는 규칙
사실 주석달아야 할 곳에 안달아서 헷갈리는 경우도 많고, 달지 않아도 될 곳에 달아서 오히려 코드만 지저분해지는 경우 허다하죠... 이건 사실 어떻게 정의해도 코드 드러운 애들은 여전히 드럽고 코드 깔끔한 분들은 여전히 깔끔한.. 그런 부분...

저 개인적으로는
  1. 클래스 이름만 잘 정하면 굳이 클래스마다 주석을 달 필요가 없다. 이름보고 이해안될때만 기재.
  2. 함수/변수 이름만 잘 정하면 굳이 함수/변수마다 주석을 달 필요가 없다. 이름보고 이해 안되거나 변수의 반환값이 기묘할 때만 기재.
  3. 코드에서 곧바로 이해되면 주석은 필요없다.
  4. 옆에 앉은 놈이 코드만 보고 곧바로 이해가 안되면 코드블럭 별로 그 위에 주석으로 기재
정도가 젤 난거 같습니다.

대충 정리
이렇게 써보고 보니 결국 제가 괜찮다고 생각하는 법은 코딩 스타일의 통일성을 유지하려고 괜히 쓸데없는 규칙을 만드는 대신에 개발자들의 상식을 믿으란 쪽이 되어버린듯...

어쨌든 제가 좋다고 생각하는 코딩스타일은 이것 정도입니다.
  • 변수명/함수명에 의미를 담을 것
  • 코드의 스코프를 보여주기 위해 인덴테이션을 잘 할 것
  • 동료 프로그래머가 코드에서 곧바로 이해못할 만한 내용이면 코드 블럭 위해 간단히 주석을 달 것

개종 안하셔도 되요~
뭐, 다들 이러세요~ 라는 걸로 쓴 글은 아니고.... 그냥 한 번 생각해보시라고... 그리고 토론 좀 해보잔 의도로... (어차피 종교적인 토론이라... 난장판이 될 가능성이 높지만...-_-)






반응형
,
Posted by 알 수 없는 사용자

안녕하세요. 드디어 2번째 글을 쓰게 되는 돼지홍입니다. ^^

 

나이는 많지 않지만 기획자 경력이 10년 가까이 되다 보니 팀장도 하고 면접관 역할도 많이 하였습니다. 그러면서 기획 면접관으로 들어가 신입으로 기획자 면접을 보시는 분들을 보면 기획자라는 직업을 하고는 싶지만 어떻게 준비해야 하는지에 대해서 잘 모르시는 경우가 많은 것 같아 약간이나마 도움을 드리고자 글을 쓰게 되었습니다.

 

이 글은 주관적인 취향과 경험에 따라 이야기하는 것이기 때문에 다르게 생각하는 분들도 많을 것이라 생각됩니다. 하지만 기획을 시작하고자 하는 분들에게 작게 나마 도움이 될 수 있으면 좋을 것이라 생각해서 정리한 것이니 너그럽게 봐주시면 감사하겠습니다.^^ 저보다 고수이신 분들이 많이 계신데 제가 이런 글을 올려도 될지 ㅎㅎㅎ

 

그럼 시작해보겠습니다. 본격적인 내용은 편의상 경어를 사용하지 않았으니 양해 부탁 드립니다.

 

 

1.  기획자는 게임을 많이 하는 것도 중요

A.    게임을 많이 하면 추후 기획에 도움이 된다.

가장 쉽게 가장 기초가 될 수 있는 지식을 쌓을 수 있는 것이 바로 게임 플레이이다. 기획자는 게임 플레이를 통해 직접 재미를 체감할 수 있고 많은 지식도 쌓을 수 있어 추후 기획을 할 때 큰 도움이 될 수 있다.

제가 개인적으로 기획자란 직업을 아주 좋아하는 이유 중 하나이기는 하지만 너무 게임 플레이에만 집중하면 안 됩니다.;;;

1)     직접 재미를 체감하는 것이 가장 중요

왜 재미있는지도 모르는 게임을 기획자가 재미있게 만들 수 있을까?”에 대해서는 누구나 알고 있을 것이라 생각한다.

2)     커뮤니케이션에 도움

다양한 게임에 대한 경험과 지식은 게임 회사에 들어와 다른 팀원들과 작업에 대한 커뮤니케이션을 하는데 있어 의외로 큰 도움을 준다. 기획자는 다른 파트보다 커뮤니케이션이 아주 중요한 직업이기 때문에 더욱 중요할 수 있다.

3)     다양한 참고 자료 제공하기도 쉬움

기획자는 직접적으로 최종적인 결과물을 만드는 직업이 아니지만 기획서를 만드는 단계에서 상대에게 좀 더 쉽고 설득력있는 기획서를 제공하기 위해서는 참고 자료가 필요한 경우가 많다. 이럴 때 참고 자료로 사용되는 것들이 대부분 다른 게임이다.

 

B.     게임을 너무 쉽게 판단하지 마라

가끔 면접을 보다 보면 각 게임을 1시간만 플레이해보고도 모든 것을 판단해버리는 천재?들이 존재한다. ~~~!!!!! 이런 사람은 개인적으로 뽑지 않는다.;;;

1)     온라인 게임은 각 플레이 타임별로 제공하는 것이 다르다.

물론 처음 1시간이 유저 입장에서 바라보는 가장 중요한 포인트일지도 모른다. 하지만 기획자를 지망하는 사람이라면 게임의 전체를 이해할 수 있을 정도로 플레이하고 각 플레이 타임별로 제공하는 재미나 기획 의도 그리고 효과 등을 파악하고 게임을 판단하는 것이 좋다.

-       MMORPG 2~3개 게임 만렙 키워보는 것을 추천

각 게임별로 추구하는 재미가 다르기 때문에 한 가지 게임만 키워보는 것 보다는 2개 이상의 게임을 경험해보는 것이 좋다.

2)     다른 기획자가 바보라고 생각하지 말아라!!

모든 게임이 기획자가 있고 그 기획자들이 정말 고민하고 기획하여 결과물이 나온 것이 그 게임들이다. 절대 무시하시는 발언이나 자신은 그런 실수를 결코 하지 않을 것이란 생각은 하지 말길 바란다. 기획은 쉬워 보일 수는 있지만 결코 쉽지 않다. 어렵게 생각하고 주의하여 기획하는 사람은 좀 더 나은 결과물에 접근할 가능성이 크지만 쉽게 생각하는 사람은 좀 더 실수나 나쁜 결과물을 만들 가능성이 크다.

한국 게임만 유독 무시하는 발언하는 기획자도 개인적으로는 좋아하진 않습니다.

 

C.     다양한 게임을 하는 것을 추천

누구나 게임을 플레이하는 취향이 존재하기 마련이다. 하지만 기획자를 직업을 택했다면 다양한 게임을 플레이해보는 것을 추천한다.

1)     콘솔 게임도 뛰어나지만 온라인 게임도 뛰어나다.

가끔 보면 콘솔 게임만 뛰어나다고 생각하고 콘솔 게임만 플레이하는 사람들이 있다. 분명 콘솔 게임이 뛰어나고 배워야 할 부분이 많은 것도 사실이다. 하지만 콘솔 게임에 온라인적인 요소가 있진 않다. 아마 대부분 우리나라 기획자는 온라인 게임을 만들 것이다. 온라인 게임이기 때문에 생기는 제약도 있지만 재미도 아주 많다. 그 것을 아는 것이 아주 중요하다. 물론 가끔 반대로 온라인 게임만 하는 사람에게는 콘솔 게임 플레이를 추천한다.

2)     다른 장르의 게임에서 배우는 것도 많다.

자신은 RPG만 좋아하고 RPG만 개발한다고 RPG만 플레이하는 사람들이 있다. 하지만 생각의 전환이나 다양한 아이디어 그리고 좀 더 특정 요소의 집중적인 퀄리티 향상을 노린다면 다양한 장르의 게임을 플레이해보는 것을 추천한다.

 

D.    게임을 즐기는 것도 중요하지만 분석하고 고찰하라

게임을 유저 입장에서 즐겨서 재미를 느끼는 것도 아주 중요하다. 하지만 기획자라면 자신이 플레이해본 게임에 대해서 분석하고 고찰하여 자신의 것으로 만드는 것도 중요하다. 기획자는 항상 생각이 많아야 한다. 항상 생각하여 좀 더 나은 것을 기획할 수 있도록 준비하자.

1)     분명 면접에서 물어볼 것이다.

플레이 해본 게임에 대해서 단순히 아 이게임은 전투의 타격감이 죽이고 재미있어요이렇게만 이야기한 사람을 나라면 뽑지 않을 것 같다. 왜 타격감이 좋았고 왜 재미있었는지에 대해서 끓임 없이 고민하고 더 나은 것을 찾아보려고 한 사람을 뽑을 것이다. 면접을 볼 때 정답을 이야기하면 최고이겠지만 대부분 신입을 뽑을 때 정답을 원해서 질문하진 않을 것이다. 이 사람이 평소에도 얼마나 깊이 있는 생각을 많이 하고 있는지를 보기 위해서 질문하는 것이다.

 

E.     지나치게 게임 플레이에 치중되는 것도 좋지 않음

게임 플레이가 아주 중요하긴 하지만 전부는 아니다. 기획자 준비한다고 집에서 게임만 항상 하고 있지 말길 바란다.

 

F.     소설, 만화책, 애니, 영화도 모두 도움이 된다.

다양한 경험과 지식은 언제나 기획자에게 도움이 된다. 모든 매체의 문화를 섭렵하는 것은 무리가 있겠지만 트렌트가 되는 것들 정도는 보는 것이 좋다.

 

 

2.  문서 작성 능력을 키워라!

A.    보기 좋은 문서는 첫 인상을 좋게 만든다.

기획자 지망생 입장에서 의외로 가장 통과하기 힘든 것이 서류 전형일 것이다. 그런데 이 서류 전형에서 가장 필수적인 것이 기획서이다. 기획자는 얼굴 보고 뽑는 것이 아니다. 기획서가 얼굴인 것이다. 보기 좋고 이쁘게 정리된 기획서는 좋은 첫 인상을 남기기 가장 쉽고 확실한 방법이다.

포트폴리오(기획서)가 없는 사람은 성의 없다고 보통 판단하기 때문에 서류 정형을 통과할 확률이 거의 없습니다.

 

B.     워드, 엑셀, 오피스는 기본

거의 100%의 게임 회사 기획자는 실무에서 워드, 엑셀, 오피스를 각 상황에 맞춰 사용한다. 근데 이미 숙달되어 있다고 판단되는 신입 기획자라면 뽑는 사람 입장에서 좀 더 매력적일 것이다. 포트폴리오에 자신의 문서 작성 능력을 보여주기 위해 용도에 맞게 워드, 엑셀, 오피스를 사용한 문서를 포함시키는 것이 좋다.

1)     상황에 맞춰 사용할수록 좋음

워드는 일반적인 기획서에 오피스는 PT용도의 문서에 엑셀은 밸런스나 수치가 필요한 문서에 사용하면 더욱 좋은 인상을 줄 수 있을 것이다.

 

C.     기획서에는 반드시 기획 의도가 존재해야 한다.

이미 기획 의도에 대한 글을 작성했기 때문에 여기에서는 설명하지 않겠습니다. 못 보신 분들은 링크를 따라가서 글을 읽어주시길 바랍니다.

http://gamedevforever.com/90

 

D.    맞춤법 실수와 오타 정도는 수정한 문서를 포트폴리오로 제공

위에도 이야기를 했지만 기획서는 자신의 얼굴이 되는 것이다. 첫 인상이다. 그런데 맞춤법 실수와 오타는 이런 첫 인상을 망칠 수 있는 원인이 될 수 있다. 아주 사소한 것이라면 모르겠지만 많은 맞춤법 실수와 오타는 분명 감점 요인이 될 수 있다.

물론 그런 사소한 것만 보지 말고 기획 내용을 보라구!~라고 할 수도 있겠지만 한 회사에 입사하기 위해 공들여 준비한 문서에 그렇게 실수가 많다면.. 면접관의 입장에서 생각해보길 바랍니다.

 

 

3.  프로그래밍을 배우면 좋다.

A.    요즘은 기획자도 프로그래밍을 하는 경우가 많다.

스크립트 사용이 보편화되면서 퀘스트, 몬스터 AI 등을 만들 때 기획자가 직접 스크립트를 사용하는 회사가 아주 많아졌다. 그리고 퀘스트, 몬스터 AI를 담당하는 기획자의 숫자도 아주!~ 많다. 그렇다면 이런 프로그래밍에 대한 지식이 이미 있는 기획자라면 뽑는 사람 입장에서 얼마나 매력적일 것인가!

물론 프로그래머분들 입장에서는 프로그래밍이라고 할 것까지야 없을 정도로 간단한 부분이기는 합니다. ㅎㅎㅎ 노여워 하지 말아주세요.^^

 

B.     프로그래밍 공부는 논리적인 사고에 도움이 된다.

프로그래밍을 공부하면서 간단하더라도 구체적으로 구현해야 되는 방법을 고민하고 구현을 해봄으로써 기획자는 기획 내용을 좀 더 논리적인 구조로 이해하고 표현하는 방법도 배울 수 있게 된다. 한 마디로 일석이조이다. 논리적인 구조 이해와 표현을 습득한다면 프로그래머뿐 아니라 다른 팀원에게도 좀 더 쉽고 구체적으로 기획 내용을 전달할 수 있게 된다.

 

C.     프로그래머만큼 배우란 의미는 아니다.

기초적인 지식을 배우고 실습해보라는 의미이지 기획자가 프로그래머는 아니다. 프로그래머를 약간이나마 이해하고 스크립트를 다룰 수 있는 수준이면 된다.

 

 

4.  무엇이든지 직접 만들어 보면 더욱 도움이 된다.

A.    이론과 실전은 다르다.

우리는 학자가 되려고 기획자를 하는 것은 아니다. 실제 게임을 만들려고 기획자를 하는 것이다. 이론만 고민해서는 한계가 있다. 실전을 통해 얻은 경험은 아주 큰 자산이 될 것이다.

물론 게임 학원이나 학교를 다니시는 분들은 이미 경험해보셨겠지만 혼자 독학 하시는 분들은 특히 이런 과정이 더 필요합니다.

1)     워크래프트나 스타크래프트 유즈맵

요즘은 게임들이 유즈맵을 많이 지원하고 있다. 기획자 혼자의 힘으로 게임을 간단하게 나마 만들기 아주 좋은 환경이다. 한 번 만들어서 다른 사람과 플레이를 통해 피드백도 받을 수 있고 정말 잘된다면 나도 LOL??? ㅎㅎㅎ

2)     웹 게임

웹 프로그래밍을 공부한다면 간단한 웹 게임을 만드는 것도 가능하다. 웹 게임은 온라인 환경에서 혼자 프로그래밍이나 그래픽을 전부 담당해야 하기 때문에 좀 더 어렵겠지만 더 큰 경험을 얻을 수는 있다.

저는 홈페이지 만드는 것에 관심이 많아 회사에 다니기 전에 웹 게임을 만들었습니다. 물론 별로 해본 사람은 없지만;;; 느낀 것이 아주 아주 많았습니다.

 

B.     적극적인 활동은 좋은 인상을 준다.

간단하더라도 게임을 직접 제작해 보는 것은 경험으로 도움이 되는 것뿐만 아니라 대부분 면접관에게 좋은 인상도 줄 수 있을 것이다. 적극적으로 자신이 원하는 바를 위해 실천하는 사람을 나쁘게 볼 사람은 거의 없을 것이라 생각한다.

 

 

5.  기획자로써 갖추었으면 하는 자세

아주 많이 주관적인 내용입니다. .ㅠ 개인적으로 생각하는 방향이기 때문에 이런 생각을 하는 사람도 있구나 정도로 봐주시면 감사하겠습니다.

 

A.    남들보다 똑똑해서 기획자가 아니다.

기획자가 남들보다 똑똑해서 기획서를 만들고 다른 팀이 실행하는 것이 아니다. 기획자는 항상 다른 사람보다 더 많이 생각하고 모두가 알아보기 쉽게 정리하여 납득할 수 있는 방향과 기획서를 만드는 것이다. 내가 남들보다 더 똑똑하니 기획자를 해야겠다고 생각했다면 그냥 사장을 해라.

 

B.     먼저 남들에게 인정받기 위해 노력하자.

기획자는 항상 남들에게 자신의 주장을 펼쳐야 하는 경우가 많다. 하지만 인간적으로나 업무적으로 인정받기 이전에 강한 주장은 분명 옳은 부분이어도 잘 받아들여지지 않는 경우가 많다. 우선은 회사에 입사했다면 자신의 주장을 펼치기에 앞서 인간적으로나 업무적으로 팀원들에게 인정을 받는 것이 좋다.

 

C.     항상 겸손하고 남을 무시하지 말아라

가끔 보면 기획팀이 아니 팀 사람을 게임에 대해 아무것도 모른다고 무시하는 사람이 있다. 기획자는 커뮤니티의 핵심이고 그 커뮤니티 능력이 기획자의 핵심 능력 중 하나이다. 자신이 아무리 뛰어나도 기획자가 게임을 만들 수 있는 것은 아니다. 다른 사람에게 항상 겸손하고 남을 납득시킬 수 있어야 한다.

 

 

마지막으로 잡담

저도 그렇지만 제 주위 분들에게 물어봐도 기획자가 지원하는 사람은 다른 팀에 비해 아주 많지만 의외로 뽑을 만한 사람은 아주 적다고 이야기를 많이 합니다. 저도 그렇지만 주위 분들도 뽑고 싶습니다. 정말 사람 충원 너무 힘들어요 ㅠ.ㅠ 신입도 많이 뽑고 싶지만 정말 저희 입장되시면 뽑을 만한 기본을 갖추고 있는 분들이 별로 없습니다.

 

제가 지금 작성한 글이 자세한 설명이 있는 것이 아니기 때문에 기획 지망자 분들에게 직접적인 도움이 되긴 힘들겠지만 면접관들 중 이런 생각을 가지고 있는 사람이 있구나 이런 부분을 더 공부하면 좋겠구나라고 생각해주시면 좋을 것 같습니다.

 

좀 어떻게 보면 건방진 글이 된 것 같네요 ㅠ.ㅠ 저도 많이 부족하지만 작게 나마 도움이 될 수 있을 것 같아 적은 글이니 좋게 봐주시면 감사하겠습니다. 긴 글 읽어주셔서 감사합니다.

 

ps> 의외로 어떤 주제로 글을 써야 할지 고민이 많이 되네요 ㅠ.ㅠ 다음은 모를 쓸까나? .

 


반응형
,
Posted by 알 수 없는 사용자

안녕하세요. 알콜코더 민군입니다.

 

현재 제작 중인 게임에서, 랜덤 시드 값을 일치 시켜서, 랜덤 결과를 서로 다른 클라이언트끼리 동기화 시키는 작업을 진행 하였습니다. 랜덤 시드값만 서로 일치시키면, 이후에 생성되는 랜덤 함수의 결과값들은 모두 일치가 되기 때문에, 예전에 스타크래프트와 같은 패키지 게임에서 자주 사용했던 테크닉입니다. ^^; 서로 다른 클라이언트끼리 처음 시드값만 일치 시키면, 이후의 랜덤값은 정해져 있기 때문에, 그 랜덤값을 사용한 이벤트등의 동기화에 사용하는 것이죠.

 

이런 테크닉은 패키지 게임 시절에는 리플레이 저장이나 네트워크 동기화등에서 상당히 많이 사용하였습니다. 하지만 온라인 게임으로 넘어오면서, 대부분 서버에서 랜덤값을 직접 생성하여 넘겨주기 때문에, 이 테크닉 쓸일이 거의 없었는데… 이번 상황은 랜덤값이 게임의 결과에 전혀 영향을 끼치 않고, 단지 연출에만 영향을 끼치기 때문에 이 테크닉을 사용하기로 하였습니다. (서버 부담을 줄여달라는 서버쪽의 간절한 요청 때문에.. 아흑..OTL)

 

일반적으로 랜덤 함수라면 C++ 표준 rand() 함수를 사용하게 됩니다. 뭐.. 일반적인 랜덤값을 사용하는 경우에는 사실 이 표준 함수를 사용해도, 별 문제는 없습니다. ^^; 하지만 위와 같은 테크닉을 사용할 때는 rand() 함수를 사용하면 안됩니다!

왜냐하면, C++의 표준 rand() 함수는 아래와 같은 약간의 문제점을 가지고 있습니다.

  1. rand() 함수의 분포는 그리 고르지 않다. 특히 작은 표본을 사용할때는 더욱 그렇다. 
    즉, 이말은 1~10까지 랜덤을 1억번쯤 돌리면, 확률이 다들 비슷하게 나오긴 하지만, 10번 정도만 돌릴때에는 1 하나만 10번이 나온다거나 하는 가능성이 있다는 것입니다.

     

  2. rand() 함수는 전역 함수이다. 어디서든 사용이 가능하다
    이 함수는 표준 함수이기 때문에, 코드의 어디에서도 호출이 가능합니다. 그래서 호출 되는 경우를 제어할 수 가 없습니다.

 

< 즉 이런 기적의 확률이 나올수도 있는거임.. ㅠ.ㅠ >

 

저의 경우에 문제가 되는 것은 1번이 아니라, 2번입니다. 같은 랜덤 시드값으로 서로 다른 클라이언트에서, 싱크를 맞추기 위해서는 랜덤 호출 횟수가 정확히(!) 일치하여야 합니다! 내가 랜덤함수를 5번 호출했으면, 상대방도 5번 호출해야 같은 결과 값이 나와서 싱크가 일치하게 됩니다.

그런데 만약? 내가 작성한 코드가 아니라 어딘가 다른 코드에서 그것도 한쪽 클라이언트에서만 그 사이에 rand()를 호출하게 되면 어떻게 될까요? 넵. 당연히 그 다음부터는 모든 싱크가 아작이 나게됩니다…(그리고 이 경우에는 어디서부터 문제가 발생 했는지 찾는 것도 거의 불가능)

전역 함수라는 특징 때문에, 어디서 어떻게 불리울지 모르기 때문에, 언제 호출 횟수가 어긋날지 모른다는 문제가 발생하기 때문에, 랜덤 시드로 씽크를 맞추는 이 테크닉에서는 rand() 함수를 사용하는 것은 불가능 합니다. (내 코드에서는 절대 그럴리가 없어! 라고 해도… 다른 사람이 작성한 코드에서 과연 부르지 않는다는 보장이 있을까요…)

 

그래서 따로 랜덤 생성 클래스를 만들어 사용하게 됩니다. 랜덤 클래스를 만들고 그 인스턴스만을 사용하게 되면, 호출 횟수가 어긋나는 문제를 해결할 수 있으니까요. ^^

저의 경우가 바로 이런 경우라서, 랜덤 생성 알고리즘을 한번 찾아 봤습니다. 랜덤 생성 알고리즘은 "난수 생성기(Random Number Generator)", 혹은 "의사 난수 생성기" 등으로 불리웁니다. (그냥 저는 편의를 위해.. 이후 '랜덤 생성기'라고 칭하겠습니다. 이게 걍 편해요…)

 

이렇게 따로 랜덤 생성기를 이용해서, 랜덤 생성 클래스를 만들어 사용하면, 위와 같이 코드의 다른곳에서 랜덤값이 불리우는 경우를 제어할 수 있습니다. 물론 그렇다고 랜덤 생성 알고리즘을 혼자 고급 수학책이나 물리책 펴놓고 만들어서 쓰라는 이야기는 아닙니다. 친절하게도 이런 알고리즘은 전문 수학자 분들이 편하게 갖다 쓸수 있도록 편하고도 멋지게 만들어 두었습니다. (아이구~ 이런 감사할때가….)

 

이런 랜덤 생성기중에서 가장 유명하고 널리 쓰이는 알고리즘이 바로 [메르센 트위스터(MT.Mersenne Twister)]와 [WELL]이라는 랜덤 생성기입니다.

그리고 이 랜덤 생성기들은 위와 같은 테크닉에 사용할 수 있는 용도 외에도 다음과 같은 뛰어난 장점들을 가지고 있습니다

  1. 표준 함수보다 랜덤 분포가 훨씬 고르다

    표준 함수의 경우 2^32승의 period를 가지는데 반해, MT의 경우는 2^19937-1를 가집니다. 그리고 623차원까지 동일분포 되어 있습니다. (자세한건 아래 링크 참조)

     

  2. 표준 함수보다 훨씬 속도가 빠르다.

    MT의 경우에 비트 연산만으로 구현되어 있어서, 표준 rand()보다 약 4배가 빠르다고 합니다. 그리고 WELL 같은 경우에는 MT보다 40%가 더 빠르다고 합니다.

 

 

메르센 트위스터

위키백과우리 모두의 백과사전.

메르센 트위스터(Mersenne Twister) 1997년에 마츠모토 마코토(松本 ) 니시무라 다쿠지(西村拓士) 개발한 유사난수 생성기이다.[1] 메르센 트위스터는 동일한 저자들이 개발한 TT800 생성기의 개선판으로기존 생성기들의 문제점들을 피하면서 매우 질이 좋은 난수를 빠르게 생성할  있도록 설계되었다.

메르센 트위스터의 이름은 난수의 반복 주기가 메르센 소수 데에서 유래했다메르센 트위스터는  속도와 난수의 품질 때문에 점점 많은 곳에서 채택되고 있으며흔히 주기가 219937 − 1 MT19937 사용한다. MT19937 같으나 생성해 내는 난수가 32비트가 아닌 64비트인MT19937-64 쓰이며2006년에 동일한 저자들이 발표한 SIMD 기반 메르센 트위스터는 MT19937 비해 대략  정도 빠른 것으로 알려져 있다.

난수의 품질에도 불구하고메르센 트위스터는 암호학적으로 안전한 유사난수 생성기 아니다 난수의 특성(주기난수 범위) 알고 있을  유한한 수의 난수( 경우 624)만으로 현재 생성기의 상태를 알아   있으며 뒤에 나올 난수를 예측해   있다암호학적으로안전한 유사난수 생성기를 얻기 위해서는 해시 함수 사용해야 하지만 난수의 생성 속도가 낮아진다또는 블룸 블룸 (BBS) 같이 암호학적으로 안전하게 설계된 생성기를  수도 있다.

 

< 출처 : 위키피디아 >

 

메르센 트위스터는 현재도 가장 널리 사용되고 있는 랜덤 생성기입니다. C++에서는 Boost에도 이 MT 랜덤 생성기가 구현 되어 있습니다. 또한 MATLAB, Ruby, Python등의 언어에서도 기본 난수 알고리즘으로 채택되어서 사용 되고 있습니다. 뭐 물론 단점이 없는 건 아니지만, 장점이 훨씬 더 크기 때문에 표준으로 채택이 되었겠죠. ^^

그리고 가장 큰 장점은 특별히 따로 구현하지 않아도, Boost에 포함되어 있기 때문에, Boost만 있다면 바로 사용이 가능하다는 장점이 있습니다. 사용 방법에 관해서는 하단의 참조 링크에서 확인하실 수 있습니다.

 

WELL

WELL은 위 MT의 디자이너가 10년후에 고안한 난수 발생 알고리즘 입니다. 그의 주장에 따르면 MT보다 40% 빠르고 코드도 더 간단합니다. WELL은 분포도에 따라서 WELL512, WELL1024, WELL19947, WELL44497의 종류가 있습니다. 숫자가 클수록 분포도가 높긴 하지만, 게임에서 사용하기엔 512나 1024만으로도 충분할 것 같습니다.

WELL의 구현 코드는 이곳에서 받을 수 있습니다. 실제로 보면 정말 구현은 간단합니다.

아래가 WELL512의 구현 코드입니다.

이게 다입니다. Period는 이름 그대로 2^512입니다. 그렇다 해도 일반 PC로 저걸 세는데 10^100년이 걸린다고 하는군요. 초나 분이 아니라 년 말입니다. (googol years라고 부른다고 하는군요)

사용법은 위의 state만 적절히 초기화 해주고, 함수를 호출하면 32비트 정수(난수)가 리턴됩니다.

 

간단한 시물레이터로 두 난수 발생기를 시뮬레이팅 해 보았을 때의 차이를 보여드리겠습니다.


C/C++의 rand함수


WELL512 알고리즘

 

<이미지 출처 : binsoo Blog >

 

일반적으로 게임 개발할때는 이런 랜덤 생성기까지 필요 하지 않을지도 모릅니다. 그러나 MMORPG와 같이 랜덤이 게임의 밸런스에 큰 영향을 끼치는 경우에는, 서버 측에서 이런 고성능의 랜덤 생성기가 필요한 경우가 많습니다. 유저나 해커가 랜덤값을 함부로 예측해서는 안되니까요. ^^; 그리고 저의 경우 처럼 랜덤 시드를 이용해서 이벤트 동기화를 맞추는 경우에는 전역 함수인 rand()를 사용할 수 없기 때문에 꼭 이런 랜덤 함수가 별도로 필요합니다. 그런 경우에 굳이 이런 좋은 난수 알고리즘들을 놔두고 새로 짜는 고생은 안하는게 낫겠죠.(그렇다고 내가 만든 알고리즘이 저것보다 좋을리는 택도 없을 테니…=ㅅ=;)

 

반응형
,
Posted by 알 수 없는 사용자
반갑습니다. cagetu 입니다. 

다른 분들 처럼 하나의 주제에 마음을 두고 연재를 하지 못하고, 그냥 이것 저것 닭~치는 대로 방황을 하고 있습니다. 오늘은 완전 또 이상한 곳으로 튀어서, OpenGL ES에 대해서 알아보려고 합니다.

제가 가지고 있는 아이폰 3GS가 얼마전 2년 약정이 끝난 것을 보면, 벌써 아이폰 개발 열풍이 꽤 많은 시간이 지났습니다.

2년 전으로 거슬러 올라가서 생각해보면, 개발자들이 너도 나도 아이폰으로 무엇인가를 만들어 보겠노라며, 모두들 아이폰을 장만하고, 맥북을 장만하고 OpenGL이나 Cocoa 등을 만지작 만지작 해봤을 거라 생각됩니다만, 아마도 오래 갔을리가 없겠죠?! ㅎ
맥북은 윈도우를 설치해서 워드질하고 있고, 아이폰은 그냥 카톡질이나 하고 있네요. ㅎㅎ

현재의 개발 모습은 어떨까요? 다들 아시다시피~ 대세는 요놈입니다.

아니면, 돈이 초큼 더 있다면, 언리얼 3 엔진을 하기도 합니다. 즉, 모바일도 엔진을 구매하는 시대입니다. 
물론, 엔진을 구매하지 않는다고 해도, cocos2D 라는 멋진 놈이 있기도 합니다. ㅎ

그런데, 왜 뒤늦게 OpenGL 렌더러 타령이냐? 그러게요?! 왜 그럴까요?

사실 이런 시대에 어쩌면 OpenGL ES 따위 몰라도 게임 만드는데 전혀 지장이 없을지도 모릅니다. 게임엔진들이 받쳐줄테니까요.
하지만, 모바일 디바이스들도 점점 발전하고, 게임 엔진 가격은 점점 비싸지고 있습니다. 거기에 경쟁은 점점 더 치열해지고 있지요. 이럴 때는 자체 엔진도 힘을 발휘 할 수 있는 충분한 기회가 있을수도 있을거라 생각이 드는군요.
아니면, 그냥 개발자들의 취미나 관심으로 한번 정도 관심을 가져봐도 좋을 듯 합니다. WebGL이 얼마나 주목을 받을지 모르지만, 좀 봐두는 것도 나쁘지는 않을테니까요. 

잡설이 길었군요~ 암튼 그런 의미로, 이번에는 OpenGL ES 입니다.

"이것만 보면 OpenGL ES용 렌더러를 만들 수 있다!~ 뙇~" 뭐 이런 건 아니고요~ DirectX에 익숙한 프로그래머들이 OpenGL ES을 사용할 때, 겪을 수 있는 시행착오들을 줄여보고자 제가 한 캐삽질 경험을 이야기해보도록 하겠습니다. 

셰이더를 사용할 수 있는 ES 2.0을 기준으로 잡았으며, 기본적인 내용은 OpenGL ES에 대한 서적들이 꼼꼼하게 잘 설명을 하고 있기 때문에, 특별히 다루지 않겠습니다.


OpenGL ES 2.0

하드웨어적인 제약이 심한 임베디드 환경을 위해서 더 작고 가벼운 OpenGL의 표준을 재정했는데, 이것이 바로 OpenGL ES(OpenGL Embedded System)입니다.

OpenGL ES의 표준은 kronos group(
http://kr.khronos.org/)에서 관리를 하고 있습니다. OpenGL과 OpenGL ES와의 발전 관계를 보면 다음과 같습니다.

   - OpenGL 1.3 -> OpenGL ES 1.0
   - OpenGL 1.5 -> OpenGL ES 1.1
   - OpenGL 2.0 -> OpenGL ES 2.0 (2007년도)

가장 주목할 만한 것이 바로 최신 버전인 OpenGL ES 2.0 입니다. 1.x 버전은 그래픽 처리에 대해서 고정파이프라인(Fixed Pipeline)을 사용하는 반면에, 2.0 버전은 프로그래머블 셰이더(Programmable Shader)를 이용할 수 있습니다. 이를 통해서, 상위 버전인 OpenGL과 DirectX와 마찬가지로 강력하고 빠른 처리가 가능해졌습니다. 멋지죠?! ㅎㅎ
따라서, 1.x 버전과 2.0 버전은 서로 호환성을 가지지 않습니다. 즉, 플랫폼에 맞추어서 적절히 적용할 수 있도록 처리를 해주어야 한다는 의미가 되겠습니다.


아이폰의 경우에는 3GS 모델 이상 부터가 ES 2.0을 지원하고 있고, 최근 나오는 스마트폰의 경우에는 일반적으로 ES 2.0 을 거의 지원하고 있습니다.
 
OpenGL ES 셰이더

OpenGL ES 2.0 의 셰이더는 기본적으로 GLSL 문법을 사용하고 있습니다. GLSL에 대해서 간단히 소개하면, OpenGL Shader Language 의 약자로 DirectX에서 사용하는 HLSL과 유사한 상위 레벨 셰이더 언어입니다.

GLSL의 문법은 HLSL을 사용해보셨다면, 어렵지 않게 익히실 수 있을텐데요.
자세한 것은 참고자료(http://mew.cx/glsl_quickref.pdf )를 통해서 보시면 되겠습니다만, 간단하게 정리를 해보도록 하겠습니다.

GLSL 에서의 정식 명칭은 Vertex Shader와 Fragment Shader 입니다. 보통 DirectX에서는 Vertex Shader와 Pixel Shader라고 보통 많이 이야기를 하지요. (이후 부터는 그냥 Vertex Shader와 Pixel Shader로 통일해서 사용하겠습니다.)

DirectX의 경우, 보통 HLSL을 직접 사용하지 않고, Effect 파일(.fx)을 많이 사용하는데, Effect 파일의 경우, 하나의 파일에서 Vertex/Pixel Shader를 모두 작성하는 반면에, GLSL에서는 보통 Vertex Shader와 Pixel Shader 파일을 나누어서 작성합니다. (물론, Unity3D 등과 같이 GLSL을 감싸는 자신만의 셰이더 파일을 만들어 사용하기도 합니다.)

버텍스 셰이더의 경우, 크게 분류하면, "Vertex 입력 선업부, 셰이더 변수 선언부, Vertex 출력부, 본문"으로 나눌 수 있고요.
픽셀 셰이더의 경우에는 "Vertex 출력(입력)부, 셰이더 변수 선언부, 본문"으로 나눌 수 있습니다.  
이는 다음과 같은 키워드로 분류가 됩니다.

   - attribute : 버텍스 입력을 정의한다. (DirectX의 버텍스 입력 구조체와 동일)
   - uniform : 셰이더 변수를 정의한다. (DirectX의 셰이더 변수를 선언하는 것과 동일하다.) 
   - varying : 버텍스 셰이더에서 픽셀 셰이더로 전달할 변수들을 정의한다. (DirectX의 버텍스 출력 구조체와 동일)
   - void main : 본문 
       - gl_Position : 버텍스 셰이더에서 버텍스 연산 결과를 출력하기 위한 변수이다.
       - gl_FragColor : 픽셀 셰이더의 최종 결과를 출력하기 위한 변수이다.


그렇다면, 이렇게 셰이더에서 정의된 내용들과 네이티브 코드에서 어떻게 연결해줄까요?

GLSL은 HLSL에서 처럼 Sementic이라는 개념이 없습니다. 대부분 셰이더에서 선언된 순서를 인덱스로 하여 네이티브 코드에서 연결을 해주거나, 이름을 이용해서 셰이더와 연결을 해줍니다.

GLSL을 사용하면서 굉장히 당황스러웠던 부분은 바로, 최적화를 위해서 "셰이더에서 사용하지 않으면, 삭제해버린다"라는 것이 었는데요. GLSL을 이용해서 셰이더 코드를 작성했으나, 실제로 렌더링 결과에 영향을 주지 않는 셰이더 코드와 변수들을 모두 최적화를 위해서 컴파일 할 때 모두 삭제가 됩니다. 예를 들면, 아래와 같은 경우에는 DiffuseMap, DiffuseLight의 부분은 실제 코드에서 사용되고 있지 않기 때문에, 자동으로 삭제가 되므로 최종적으로는 "gl_FragColor = vec4(1.0);"이 되는 것입니다. 
void main()
{
//<@ 사용하지 않으니, 컴파일시 삭제되요~ vec4 DiffuseMap = texture2D(DiffuseTextexture, uv); vec4 DiffuseLight = max(0.0, dot(normal, lightdir) * normal;
//>@ gl_FragColor = vec4(1.0); }
이 내용을 잘 기억해두지 않으시면, 굉장히 까다로운 에러가 마구 튀어나오니 주의 하셔야 합니다...

[attribute]

attribute는 기본적으로 DirectX의 Vertex Declaration과 동일하게 생각하시면 됩니다.
struct Vertex
{   
   vec3 position;
   vec3 normal;
   vec2 texcoord;
};
라는 버텍스 구조체가 있다면, attribute는 다음과 같이 선언해주면 됩니다.
attribute vec3 position;
attribute vec3 normal;
attribute vec2 texcoord;
일반적으로 HLSL의 경우에는 버텍스 구조체를 정의하고, 버텍스 버퍼에 맞추어서 Vertex Declaration을 정의했다면, 셰이더에서 사용여부와 상관없이 Vertex Declaration을 SetVertexDeclaration으로 설정을 해주기만 하면 됩니다. 
하지만, GLSL의 경우에는 버텍스 정의를 했다고 하더라도, 실제 셰이더에서 사용하지 않는다면, Attribute가 삭제되어 버리기 때문에, 실제로 셰이더 "어떤 버텍스 요소들이 사용되고 있는가?"를 체크해서 바인딩을 해주어야 합니다. 

즉, glGetAttribLocation를 이용해서, 버텍스 요소가 사용되고 있는지 체크를 하고, 사용되는 버텍스 요소라면, "glVertexAttribPointer(index, size, type, normalized, stride, pointer)" 를 사용해서, attribute와 선언해주면 됩니다. GLSL은 Sementic이라는 개념이 없기 때문에, 이름 기반으로 처리를 해야합니다.

주의사항...
1. 쉽게 처리를 하기 위해서는 Sementic과 같이 내부에서 이름과 타입을 미리 정의해놓고 사용하면 좋습니다. 
2. 버텍스가 Pos, Normal, UV라고 설정했을 때, 셰이더에서 Pos, UV만 사용하다면, 
glVertexAttribPointer 를 설정할 때, 지워진 버텍스 요소를 고려하여, Offset을 잘 설정해주셔야 합니다.
3. 
normalized 인데요. true로 설정된다면, normalized된 value들이 하나의 integer format내로 저장되며, [-1, 1]이나 [0, 1]로 매핑됩니다. 따라서, COLOR 정보나, Skinning 처리 시 BoneWeight 정보들을 normalize를 true로 해주어야 합니다. 

[uniform]

uniform의 경우에는 일반적으로 변수의 이름을 기반으로 네이티브 코드와 연결을 해줍니다. 일반적으로 DirectX에서 셰이더를 처리할 때와 유사하게 사용하시면 됩니다. 
특이한 것 하나는 셰이더 변수에 배열을 사용할 때, "uniform mat4 BoneList[_MAXBONE];"이라고 선언되었을 때, 이 셰이더 변수의 이름은 "BoneList[0]"이 된다는 것입니다.

uniform 또한 사용하지 않을경우에는 자동으로 셰이더 내부에서 삭제가 되어 버립니다. 이 점을 참고하셔야 합니다.


보신 것과 같이 HLSL과 비교했을 때, 전체적인 흐름이 많이 다른지 않습니다. 단지 작업을 하실 때, OpenGL의 좌표계 특성과 문법의 차이 정도만 익숙해진다면, HLSL을 사용하는 것처럼 셰이더를 자유롭게 컨트롤 할 수 있을 것입니다.


[컨트롤 하고 싶은 욕구가 막 생기십니까?! ㅎㅎ]


버텍스 / 인덱스 버퍼 / Draw

특별히 내용상으로 다른 부분은 없습니다. 하지만, DirectX에 익숙한 개발자라면, 충분히 헷갈릴 수 있는 부분이 있기 때문에 한번 같이 보면 좋을 것 같아서 비교해보도록 하겠습니다.

DirectX
Vertex Buffer / Index Buffer를 만들고, SetSourceStream, SetIndices를 이용해서, 바인딩하고, DrawIndexedPrimitive를 이용하여 그려줍니다. 
OpenGLES
Vertex Buffer / Index Buffer를 만들고, glBindBuffer를 이용해서 바인딩해주고, glDrawElement를 이용해서 줍니다.


딱 봐도 다른 부분이 없습니다. 아직까지는... 훗~

여기서의 OpenGLES 2.0에서의 가장 큰 특징인 Lock/Unlock에 관련된 API를 지원하지 않는다는 것입니다. Lock / Unlock과 동일한 개념을 구현하려면, glBindData / glSubBindData를 이용하면 됩니다. 어떤 식으로 처리 되는지는 참고자료를 보시기 바랍니다(http://www.arcsynthesis.org/gltut/Positioning/Tutorial%2003.html ). 보시면 아시겠지만, DirectX에서의 Lock / Unlock하는 것과 크게 달라보이지 않습니다.
(좀 더 디테일하게 구현 사례를 보시고 싶으신 분들은 Orge3d 엔진의 "OgreGLESHardwareVertexBuffer.cpp"를 참고하시면 되겠습니다.) 


언뜻보면, 크게 달라보이지 않는데, 문제는 Vertex Offset에 있습니다.

DirectX에서 렌더링이 시작되는 Vertex의 시작 인덱스는 어떻게 구해지는지 보도록하지요.

DrawIndexedPrimitive(Type, BaseVertexIndex, MinIndex,  NumVertices, StartIndex, PrimitiveCount)
- BaseVertexIndex : IndexBuffer에 저장된 각 VertexBuffer의 인덱스에 추가되는 값
- StartIndex : IndexBuffer의 첫번째 Index를 사용
- MinIndex : 사용되는 가장 작은 VertexBuffer의 인덱스
- NumVertices : 버텍스개수. 첫 버텍스 인덱스는 BaseVertexIndex + MinIndex의 위치임
 
SetSourceStream(StreamNumber, pStreamData, OffsetInBytes, Stride)
- OffsetInBytes : 버텍스 Stream의 시작점에 대한 Offset (Offset된 위치부터 "버텍스 버퍼의 인덱스가 0이 됨") 

자~ 다들 기억 나시나요? 아마 많은 분들이 이 변수 설정에 따른 Index의 위치에 대해서 많이 헷갈리실 수 있을 것입니다.
즉, 현재 그리고자 삼각형(그냥 간단하게...)의 버텍스 버퍼에서의 시작 위치는 "OffsetInBytes + BaseVertexIndex + MinIndex + StartIndex"가 되겠네요. (맞나요???)

OpenGL의 경우에는 불행히도, SetSourceStream에 해당하는 OffsetInBytes의 기능이 없습니다.  

glDrawElements(type, count, type, indices) 
-  indices : 시작되는 indexbuffer의 포인터 (StartIndex만큼 포인터를 이동시켜서 설정해준다.)

즉, "StartIndex" 정도가 지정할 수 있는 전부가 되겠습니다. DirectX에서 사용하던 OffsetInBytes의 기능을 적용하려면, StartIndex에 OffsetInBytes를 추가해주던가, 아니면, 버텍스 버퍼에 값을 채울 때, 항상 0번부터 채워서 Offset 자체가 없도록 만들 수 있을 것입니다. 

특히, 배칭과 같은 처리를 하기 위해서는 Dynamic Buffer를 운영하여 하는데, Offset과 Lock에 대해서 그 차이점이 확실히 알고 있어야 조금 삽질을 줄일 수 있습니다.

결론적으로, DirectX에서 구현했던 내용을 OpenGLES로 포팅할 때, 그 차이에 대해서 주의하지 않으면, 아마 꽤 많은 시간을 삽질하셔야만 할 것입니다. (제가 그랬다구욧~ ㅜㅜ) 

깊이버퍼의 정밀도

DirectX에서 보통 설정하는 깊이버퍼 옵션은 D24S8입니다. 즉, 24비트 깊이버퍼와 8비트 스텐실 버퍼라는 말이겠지요.

OpenGL ES의 경우에는 16비트 깊이 버퍼를 이용하게 됩니다. 이는 렌더타겟에 깊이버퍼(Z버퍼)를 생성해서 붙여주어도 마찬가지로 16비트 깊이 버퍼를 사용합니다.

정밀도가 부족한  OpenGL의 경우, 상대적으로 먼 거리의 객체의 경우에는 z-fighting문제가 발생할 수 있습니다. 특히, 이유는 모르겠지만, FrameBuffer에서 깊이버퍼를 설정하고 렌더링했을 때보다, 렌더타겟에 장면을 그리기 위해서, 깊이버퍼를 생성해서 렌더타겟과 연결해주는 경우는 더욱 원거리 z-fighting이 심해집니다. (아이폰의 경우, 기본적으로 이렇게 버퍼를 생성해서 사용하기 때문에, z-fighting 문제를 해결해야 합니다.)
 
이 문제를 해결하기 위해서는 다음과 같이 처리를 해야 합니다.

   - near 평면을 너무 가깝게 설정하지 않는다.
   - far 평면을 너무 멀리 하지 않는다.
   - 오브젝트이 크기를 스케일해서 (축소) 사용한다.
   - 거리가 멀리 있는 오브젝트는 Z-Test를 끈다.
   - glDepthRangef를 이용하여, 렌더링 구간을 지정해주고, 근거리와 먼거리를 나누어서 두 패스로 렌더링 한다. 



여기서 재미있는 것은 glDepthRange를 이용해서, 깊이버퍼의 구간을 지정할 수 있다는 것인데요. 그래서, 원거리와 근거리를 나누어서 렌더링하기도 하네요.
glDepthRangef(0.0, 0.5);
draw_near_scene();
glDepthRange(0.5, 1.0);
draw_far_scene();
특별한 처리가 없이, 적당히 잘 나오게 하려면, near를 크게 하거나, 전체의 축척을 작게 설정하는 것이 가장 효율적으로 보입니다.

마무리

보신것과 같이 DirectX와 OpenGLES가 그렇게 많이 다른편은 아닙니다. 사실 API도 굉장히 단순하고, 직관적입니다. 따라서, DirectX에 익숙한 국내 개발자들도 충분히 쉽게 익히고 사용할 수 있습니다. 기본적은 3D 개념이 다른게 있을리도 없습니다. 단지, 만들면서, 두 API나 문법의 차이 때문에 막히는 부분이 힘들 뿐입니다. 

하지만, 이런 작업 상의 Tip 같은 내용을 많이 접하기가 어려워서, 나름 삽질을 꽤 많이 했습니다. 제가 삽질한 내용이 부디 다른 사람들의 삽질을 조금이나마 막아 주기를 바라는 마음에 이 글을 씁니다. 조금이나마 도움이 되었으면 좋겠군요. ㅎㅎ.

앞으로, OpenGL ES는 WebGL 뿐만 아니라, PSVita에도 사용하고 있기 때문에, 기회가 된다면, 휴대용 콘솔 게임도 한번 도전해 보고 싶네욤.. ㅎㅎ
 

그러니, 만들어 머겅... 두 번 머겅.... 끝!

참고자료

OpenGL ES로 모바일용 렌더러를 만들고 싶으시다구요?! 스펙을 참고하시려면 여기를...
- 유니티3D 문서창고 : 
http://unity3d.com/unity/ 
- 언리얼 모바일 개발문서 : http://udk.com

OpenGL ES 강좌
-  OpenGL ES 및 cocos2D 강좌

OpenGL ES Programming Guide
https://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Introduction/Introduction.html
반응형
,