꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 알 수 없는 사용자
이번에는 클라이언트를 공격하는 공격에 저항하기 위한 프로그래밍 꼼수(?!)들에 대해 다루어 보도록 하겠다. 두 세번에 걸쳐 앞서 이야기 했던 클라이언트를 공격하는 세 가지 방법중 첫번째 방법과 두번째 방법을 막기 위해서 프로그래머가 고려할 수 있는 방법에 대해 제안해 보도록 하겠다.

이전 글에서도 다루었지만, 클라이언트는 기본적으로 해커의 손에 있는 것 이기 때문에 해커는 굉장히 다양한 방법으로 - 조낸 똑똑한 방법으로도, 무식하기 짝이 없는 방식으로도 공격할 수 있다. 그렇기 때문에 그 어떤 방법을 사용해도 끈질긴 해커의 공격에서 클라이언트를 보호할 수 는 없다. 해커의 공격에 저항하는 프로그래밍의 목적은 단 하나, 해커가 지겨워서 혹은 투자한 시간에 비해 얻는게 없다고 느끼게 만들어 목표물을 바꾸게 만드는 것이다.


'내가 이짓을 해서 얻는게 대체 뭐냐...' 라는 표정을 짓고있는 어린 여성 해커 (믿거나 말거나)

해커를 지겹게 만들려면 기존에 잘 알려진 공격 방법을 막는 것 부터 시작해야 한다. 기존에 잘 알려진 공격 방법들은 이미 툴도 많이 나와있기 때문에, 찌질하고 생각없는 것들이 웹 페이지를 띄워 놓거나 책을 펴놓고 한줄한줄 따라하다가 성공하는 불상사가 생기기도 한다. 그런 찌질한 애들이 정말 될거라고 생각 못하고 생각없이 시키는대로 따라하다 실수로 성공해서 뉴스에 나오는 거다. 

그런 가장 간단한 것들 부터 다루고 시작해 보도록 하자. 이번에 다룰 내용은 주로 저장되어있는 파일 - 실행 파일이든 데이터 파일이든 공격자의 하드디스크에 저장되어 있는 파일들에게 공격자들로 부터 비누방울 정도의 얇은 보호막을 치는 방법들이다. 하!지!만! 아무리 얇디 얇은 보호막이지만 띨띨한 공격자들의 눈먼 공격 정도는 충분히 막을 수 있다. 잊지말라, 우리의 노력은 해커의 공격을 100% 완전히 차단할 수 있는 완전무결한 방어책을 만드는 것이 아니다. 해커로 하여금 분노하여 해커 자신의 컴퓨터와 모니터에 도끼질을 하고 후회하게 만드는 것이고, 시도하다 지겨워서 더 재미있어보이는 다른 일을 하게 되기까지 시간을 벌려고 하는 것이다.

0. 들어가기 전에 메모리 구조 이야길 잠시 하겠다.
뭐 모두모두 알고있는 내용일 것 이라 생각 되지만, 그래도 잠시 언급하고 넘어가는게 쬐끔은 도움이 되지 않을까 싶어 부랴부랴 추가 해 보았다. 다음은 일반적인 프로세스의 메모리 구조다.



경우에 따라서는 위 아래가 바뀌어 있을 수 도 있지만, 그림의 표현의 문제일 뿐 둘은 동일한 그림이다. 이 그림에서는 가장 윗쪽이 0번지 가장 아랫쪽이 FFFF....FFFF 번지에 해당된다.

우리가 열심히 프로그램 코드를 작성해서 컴파일을 시도하면, 어셈블리 언어를 거쳐서 기계어로 번역 된 다음에 프로그램 코드 영역에 예쁘게 보존된다. 그리고 프로그램 내에서 사용되는 수 많은 상수들과 스태틱 데이터 - C의 경우 static으로 선언된 변수와 전역변수는 스태틱 데이터 영역에 몰아서 저장된다. 프로그램내에서 선언되고 사용된 위치와 전혀 상관없이 모든 데이터들은 전부 이 영역에 몰아준다. 왜? 편리하니까!

컴파일된 결과물은 프로그램 코드 영역과 스태틱 데이터 영역을 합쳐 놓은 것에 해당되며, 하드디스크에 저장되어 있는 파일의 내용물이 바로 이것이다. 그러므로 프로그램 코드 안에 넣어둔 상수나 스태틱 변수의 값은 모두 해커/크래커의 것 이다.

프로그램이 실행되면, 운영체제는 프로그램 코드영역과 스태틱 데이터 영역의 내용을 하드디스크에서 읽어 들인다음 힙 영역과 스택 영역을 생성하고, 프로그램 코드 영역의 가장 첫 위치로 jump 한다. 보통 프로그램 코드 영역의 가장 첫 위치에 main 함수로 jump하는 기계어 코드가 들어있다. 그리고, main 함수가 실행되는 것이다[각주:1].

힙영역은 *alloc 계열의 메모리 할당 함수가 사용되는 영역이다. 보통 '아래쪽으로 자란다'는 표현이 사용되기는 하지만, 최근의 CPU와 운영체제의 개념에서는 그다지 맞는 표현은 아니다. 스택영역은 함수가 호출될 때 마다 돌아갈 위치가 기록되며, 로컬 변수들이 저장되는 영역이기도 하다. 함수가 호출 될 때 마다 점유 영역이 커지며, 보통 '위쪽으로 자란다'는 표현이 사용된다. 뭐, 아직은 그럭저럭 맞는 표현이기도 하다.

위의 그림에는 각 영역별로 선이 그어져 있지만, 실제로 저렇게 구분되어 있을 리는 없다. 코드가 커진다면 프로그램 A 에서는 스태틱 데이터 영역이지만 프로그램 B 에서는 프로그램 코드 영역일 수 도 있는 것 이다. 힙 영역과 스택 영역도 마찬가지다. 물리적으로 어찌 되었든 간에 논리적으로는 연속된 영역에 존재하는 메모리 이기 때문에 프로그램, 스태틱, 힙, 그리고 스택이 사실은 같은 메모리 이다. 결국, 힙이나 스택에 코드를 저장할 수 있다면, 해당 코드를 실행할 수 도 있다. 바로 여기에서 부터 수많은 해킹 기법이 시작되는 것이다.

그런데... 어쩌라고... 재미 없어 하품하시는 작은 하마 되시겠다. 


1. 파일을 액세스 할 때에는 환경변수를 참조하지 말라
 
경험있는 MMO 클라이언트 프로그래머들이라면 이미 알고 있는 당연한 내용이리라 본다. 환경변수를 참조해서 동적 라이브러리를 찾거나 혹은 파일을 찾는다면, 해커는 가짜 동적 라이브러리 혹은 데이터파일 하나 만들어서 아무데나 던져놓고 환경변수를 바꾸는 것 만으로도 소기의 목적을 달성할 확률이 아주 높아진다.

사실, 환경변수를 참조하지 말라고 하는 것은 '좋은 / 확장성 있는' 프로그램을 만드는 기법에 정면으로 대치되는 어이없는 조언이지만 해커의 공격 이라는 것은 그런 '좋은' 것을 삐딱하게 이용하는 데에서 시작되기 때문에, 어쩔 수 없는 노릇 이기도하다. 몇몇 상용 MMO 게임들은 이런 조건을 충족하기 위해 설치 디렉토리를 변경할 수 없게 고정 하기도 한다. (설마, 그냥 동적 패스 구성할 능력이 안돼서 고정 패스를 쓰는 건 아니겠지? 꿈보다 해몽이 좋은건가?)

2. 외부 프로그램을 실행시키지 말라, 어쩔 수 없다면 절대 패스를 이용하라

외부 프로그램을 실행 시키고 그 실행 결과에 따라 프로그램이 동작하게 만든다면, 그야말로 '나잡아 잡숴 주세요' 라고 해커에게 부탁하는 꼴이 된다. 그러므로 다른 프로그램의 기능을 이용해야 하는 경우 가능하면 그 기능을 내 코드에 어떤 형식으로든 포함 시켜야 한다. 정말 불가능 하다면, 절대패스를 이용하도록 해야 한다.

만약, 액세스 빈도가 잦지 않고 사용자를 기다리게 할 수 있는 상황이라면 보안목적으로 만들어진 해쉬함수들 (SHA, MD5) 등을 이용하여 대상 프로그램/파일이 변조되지 않았다는 것을 먼저 확인하는 것도 해커를 귀찮게 하는 방법이 될 수 있다.

3. 변조 되어서는 안되는 중요한 데이터 파일 이라면 암호화 하라

MMO의 경우 변조함으로서 어떤 이익을 얻을 수 있는 파일은 클라이언트측에 저장하지 않는 것이 당연하다. 그러나 어떤 이유에 의해 도저히 서버로 전달해서 저장할 수 없다면, 혹은 오프라인에서도 혼자 플레이 하다가 그 결과를 서버로 보낼 수 있도록 하는 등의 기능을 구현 하고자 하면 어쩔 수 없이 로컬에 저장해야 하는 경우엔 저장할 때 암호화 하여 저장하고, 로드하기 전에 검증을 해야 한다.

중요한 파일을 암호화 한 경우, 해당 파일을 복호화 하기 위한 키는 서버에서 보내준 것을 사용해야 한다. 키는 반드시 서버에 저장하고, 사용시 서버에서 전달받아 파일을 복호화 한 다음 바로 키를 삭제해야 한다. 암호화 했다고 해도 키와 암호화 된 파일 모두가 로컬에 저장되어 있는 경우에는 - 비록 키가 프로그램 안에 숨겨져 있다고 해도 찾아내어 복호화 하고 수정한 다음에 다시 암호화 할 수 있는 가능성이 있다고 보는게 맞다.

4. 중요한 파일을 로드해서 사용하기 전에는 반드시 검증하라

3에서 언급된 데이터 파일을 포함하여 인증용 라이브러리 같이 프로그램을 수행하는데 있어 중요한 역할을 하는 파일들은 실행 전에 반드시 검증해 주어야 한다. 검증은 SHA나 HAS같은 보안 목적으로 만들어진 해쉬 함수를 활용해야 한다. '파일의 검증'이라는 말을 들으면 바로 떠오르는 것이 아마도 'CRC'일텐데, CRC는 변조를 방지하려는 목적이 아니기 때문에 고의로 변조한 경우에는 찾아내지 못한다는 문제점이 있다. 그러므로 보안 목적으로 만들어진 해쉬 함수를 사용해야 한다.


보이는게 모두 진실은 아니다. 프로포즈 하기 전에도 검증은 해야 한다.
사진속 인물이 궁금하다면 '남태희'라고 구글 형님에게 물어보면 알려준다. 


ㄱ. 검증을 위해서는 보안목적으로 만들어진 해쉬 함수를 사용한다.[각주:2]

보안을 위해 만들어진 해쉬 함수들은 속도 보다는, 공격자가 위조를 막는 것이 첫번째 목표이다. 그렇기 때문에 해쉬 함수를 이용해서 파일을 검증하면, 검증을 회피할 수 있는 공격 프로그램이나 데이터를 만들어 내기가 아주 어렵다[각주:3]. 공격자를 귀찮게 하는, 보안을 위해 만들어진 해쉬 함수들은 다음과 같은 세가지 조건을 가지고 있다.

1. 해쉬 값을 가지고 원래 값을 찾아내기가 아주 어렵다[각주:4].
2. 어떤 데이터의 해쉬값과 동일한 해쉬값을 갖는 다른 데이터를 찾아내기가 아주 어렵다.
3. 같은 해쉬값을 갖는 두 데이터를 찾아내기가 아주 어렵다[각주:5].

추가적으로, 대부분의 블록암호나 보안을 위한 해쉬는 diffusion(확산) 이라는 특성을 가지고 있다. 렌더링에 사용되는 확산하고 별다를바 없는 개념이기야 하겠지만, 암호학에서는 한 비트라도 변경되면 결과물이 완전히 변경되는 효과를 말한다. SHA1을 가지고 예를 들어 보겠다.

SHA1("HELLO2") == 0xf55a1dfb23cb72689274c543ad201c388b52b149
SHA1("HELLO3") == 0x8c0a6d67117649466d1928145bdd4cabeab9ef28

2의 아스키 코드 값은 32 - 0010 0000b 이고 3의 아스키 코드 값은 33 - 0010 0001b 이므로, 그야말로 여섯바이트 중 한 비트가 변경 되었음에도 불구하고 결과값의 40바이트 전체가 완전히 변경 된 것을 볼 수 있다.

이렇듯 조금만 바꿔도 검증용 데이터는 완전히 바뀌는 데다가, 같은 해쉬값을 갖는 다른 - 변조된 파일을 만드는 것은 아주 어렵기 때문에, 해커는 파일 자체를 수정하는 것 외의 다른 방법을 찾으려고 시도하게 될 확률이 높아진다.

ㄴ. 검증에 사용되는 데이터는 항상 상수로 사용하라

한마디로 표현하자면, 그리고 가장 무식한 방법을 들자면, 다음과 같이 쓰라는 말이다.

if(data[0] != 0xf55a) return 0;
if(data[1] != 0x1dfb) return 0;
if(data[2] != 0x23cb) return 0;
...
if(data[18] != 0x8b52) return 0;
if(data[19] != 0xb149) return 0;
return 1; 


이때 data 배열은 파일을 보안을 위해 만들어진 해쉬함수를 이용해 얻어진 해쉬값이다.

매크로 함수를 만든다면 아래와 같은 방법도 나쁘지 않을 수 있다.

(data[0] != 0xf55a)? 0: (data[1] != 0x1dfb)? 0: ...

        (data[18] != 0x8b52)? 0: (data[19] != 0xb149)? 0: 1; 


무식하다는 점에 있어서는 위쪽의 소스와 별다를 바 없지만, 매크로 함수에는 조금 더 나을 수도 있지 않을 까 싶기도 하다라는 생각을 해볼 수 있지 않을까라는 입장이 될 수도 있을 법한 소스 이다(응?).

물론 위의 방법은 아주 무식하고, 아주 귀찮은 방법이다. 검증 데이터를 배열에 때려박아 넣고 for 루프 한번 휙 돌려주면 해결 될텐데, 그야말로 프로그램 완전 초짜나 쓸만한 닥질로 보일 것 이다. 더 나아가 편하게 검증 데이터를 변경하기 위해 - 검증되는 라이브러리를 재 컴파일 할 때 마다 검증데이터를 변경해야 하니, 전역으로 잡아주거나, 스태틱 멤버 상수로 잡아주면 편리하게 작업을 할 수 있을 것이다. 심지어는 빌드 스크립트에 검증 데이터를 자동으로 생성해서 헤더에 박아넣는 일을 할 수 도 있을 것이다.

그러나, 그렇게 하면 프로그래머가 편리한 만큼 해커도 편리하게 검증 키를 찾아낼 수 있다. 왜? 컴파일러가 식별자를 갖는 상수 값들은 전부 스태틱 영역에 예쁘게 모아주기 때문에, 해커는 문자열을 찾아낼 때와 동일한 방법으로 실행파일의 스태틱 영역만 뒤져보면 손쉽게 키를 찾아낼 수 있다. 게다가 검증에 사용되는 데이터의 길이는 고정되어 있으니 찾기도, 바꿔 넣기도 쉽다.

ㄷ. 검증용 함수는 가능하면 인라인 함수로 만들어라

인라인 함수의 장점중 하나는, '나는 하나만 만들지만 컴파일 된 결과물에는 같은 코드가 여러번 반복된다'이다. 이렇게 해주면 공격자는 리버스를 시도할 때 불필요하게 긴 코드가 여기저기 반복되어 존재하는 것으로 보게 된다. 그리고 정말 자기가 필요로하는 코드 영역이 어디인지 찾기 힘들어진다.

이중에 네가 수정해야 하는 코드가 어느거냥?


5. 중요한 파일이라 암호화 해야 한다면. 압축한 후 암호화 하라

아무리 강력한 블록암호 기법이고, 키를 아주 잘 숨겨서 공격자가 찾을 수 없다고 해도 블록암호 자체를 공격해서 키를 알아내는 공격법은 있다. 가장 잘 알려진 공격 방법은 '선형 공격; Linear Cryptanalysis'과 '차분 공격; Differential Cryptanalysis' 이다. 이 방법을 이용하면 충분한 양의 암호문과 시간만 있으면 암호문에서 키를 알아낼 수 도 있다.

그러나, 파일을 먼저 압축한 후에 암호화 하면 1) 암호화 해야 하는 데이터의 양이 줄어들고 (물론 데이터의 특성에 따라 커질 수 도 있다) 2) 설령 블록암호 공격기법을 통해 키를 알아냈다고 해도 암호가 풀린 데이터가 압축되어 있으면 정말 공격에 성공 했는지 여부도 확신하기 쉽지 않게 된다.

암호를 풀었는데 이상한 데이터가 나온다면


당연히 해커는 암호를 풀어내는데 어려움을 느끼게 될 것 이고, 띨띨한 초보자 라면 프로그램이 공격에 성공했다고 메시지를 출력했는데도 불구하고 만들어진 파일이 여전히 의미를 알 수 없는 바이너리 파일이기에 그냥 프로그램이 오동작 했다고 판단할 확률이 높아진다.

주의할 점 중 하나는, 파일의 첫 세바이트를 해당 파일이 어떤 형태의 파일인지 기록하는 표준이 있다는 사실이다. 그렇기 때문에 자신이 사용하는 압축 함수가 완성된 압축 데이터의 첫 세바이트에 그런 정보를 기록해서 주는지 아닌지를 확인해 보고, 만일 기록해 준다면 제거해 주어야 한다. 힘들게 압축해서 암호화 했는데 공격자가 그 세바이트를 보고 공격에 성공했고, 압축을 풀면 된다는 사실을 알게 된다면, OTL 좌절 인거다. 게다가 압축 방법 까지 알려주는 친절까지 베푼 셈이 되는 거다.

할거면 좀 제대로 하지그랬어
 
6. 암호화 할 때에는 암호화할 데이터의 처음에 랜덤 값을 추가 하라

블록암호는 확산 - diffusion 이라는 특성을 갖고 있다[각주:6]. 암호화 되는 데이터중 한 비트가 바뀌면 결과 전체에 그 영향이 확산되어 완전히 다른 결과를 얻게 된다. 그러므로 파일의 제일 앞에 랜덤 값이 들어간다면 같은 데이터를 암호화 해도 매번 다른 암호문을 얻게 되므로 공격자를 혼란에 빠뜨릴 수 있다.

단, 블록암호의 확산은 한 단위 - 블록암호의 종류에 따라 다르겠지만 가장 많이 쓰이는 AES의 경우 최대 256비트 까지, 보통 128비트에만 영향을 주게 된다. 이 크기를 넘는 경우에는 운용모드(Operation Mode)라는 개념이 사용되어 여러 블록을 암호화 하게 된다. 일반적으로 블록암호에 익숙하지 않은 사람이 암호화 하는데 쉽게 사용하는 운용모드는 ECB라는 방식인데 가장 쉽게 깨지는 방식이다. ECB를 사용하면, 처음에 랜덤 값을 넣어도 가장 첫 블록만 확산의 영향을 받게 되므로 암호화 하는 효과가 가장 약하다. 그러니 chaining이 되는 다른 방식을 사용해야만 한다. 다시 말하지만, 블록암호를 이용하여 암호화 할때엔 절대 ECB 모드를 사용해서는 안된다.

가장 단순하고 쓰기 쉽지만 그다지 쓸모 없는 ECB 방식의 암호화,
ECB가 나쁘지 않은 경우는 한 블록 이하를 암호화 할 때 뿐이다.

7. 운용모드를 사용하여 데이터를 암호화 한다면, 초기화 벡터(Initialization Vector)는 저장된 값을 쓰지 말라

프로그램이 실행된 후에 생성해낸 값을 초기화 벡터로 사용하는 편이 해커를 귀찮게 만들 수 있다. 초기화 벡터란 운용모드에서 같은 암호화 키를 사용해도 다른 암호문을 만드는 효과를 갖도록 하는 추가 정보인데, 경험이 없는 프로그래머들중 많은 수가 0을 쓰거나 암호 키를 그대로 사용한다. 아무래도 정확한 의미를 모르는 상황에서 주어진 샘플 코드를 그대로 사용하다보니 생기는 문제이고, 샘플 코드를 만드는 사람 입장에서도 이 값을 선택할 때 적당한 것이 없기 때문에 보통 상수를 넣어 샘플 코드를 작성하기 때문이다. 그러나 초기화 벡터를 잘 이용하면 공격자를 골치아프게 만들 수 있다.

초기화 벡터를 얻어내는 것에 대한 예를 들자면, 아주 중요한 파일의 파일 크기를 해쉬 함수에 넣어서 만들어진 값을 암호화 할 때 쓰는 초기화 벡터로 사용하면 된다. 물론, 그 중요한 파일은 파일의 크기가 변경되거나 하면 안된다. 항상 일정한 크기여야 한다. 이렇게 해주면 해커는 코드를 분석하기 전에는 암호화 할 때 사용된 초기화 벡터가 뭔지 알 방법이 없게된다. 좋은 초기화 벡터를 선택하는 방법은 프로그래머 자신의 창의력을 발휘해 보는 것도 재미 있을 것이다.

주의할 점이 하나 있다. 실행시에 만들어 내는 초기화 벡터는 사용하기 직전에 계산해 내고, 사용한 직후에 0 값을 채워 넣어서 완전히 지워줘야 한다. 초기화 벡터는 첫번째 블럭을 암호화 할 때 단 한번 사용되므로, 첫번째 블럭을 암호화 한 다음에 반드시 각 바이트마다 0을 채워넣어서 지워야 한다. (물론 다음번 벡터 값을 덮어 씌워도 무방하다. 일단 최초의 벡터값을 알 수 없게 하는게 가장 중요하다.) 아니면 힘들여 창의력을 발휘한 보람 없이 해커는 초기화 벡터를 계산해내는 방법을 알아낼 필요 없이 단순히 메모리를 스캔 하는 것 만으로 초기화 벡터 얻어낼 수 있게 될 것이다.

*     *     *

조낸 재미있는 글을 만들어야 하는데... 정말 쉽지 않네요. 역시 원자재 값이 많이 들지 않은 의상을 입고 있는 젊은 처자들의 사진을 끌어들이는 수 밖에 없는 저질 글인 건가... 어흑!

  1. 바이러스류는 바로 이런점을 이용해서 동작합니다. 스태틱 데이터 영역 끝쪽에 바이러스 코드를 심고, 가장 첫 위치의 점프 주소를 바이러스 코드의 시작 주소로 변경한 후, 바이러스의 리턴 주소를 main 함수의 시작주로로 바꾸어 놓습니다(바이러스 코드 부분이 호출된 후 스택을 조작합니다). 그러면 운영체제가 프로그램을 로드하고 실행할 때, main() 함수가 아니라 바이러스 코드를 불러주게 됩니다. 바이러스는 할일 다 하고 리턴만 하면 되는 겁니다. 쉽지요? [본문으로]
  2. 검증을 위해 만들어진 해쉬함수의 대표적인 예는 MD5, SHA-1, SHA-256, HAS-160 등이 있습니다. 이중에 MD5와 SHA1은 안전하지 않은 해쉬 함수들로 알려져 있으며, 충돌쌍 - 해쉬함수의 세 조건을 깨는 두 값을 발견하였습니다. 그러나 아직도 많이 사용되고 있기도 하지요. HAS-160은 SHA-1 계열의 해쉬로 한국정보진흥원이 개발해서 발표한 국산 해쉬함수 입니다. [본문으로]
  3. 여기에서 말하는 '아주 어렵다'는 말의 의미는, '그 결과를 가지고 의미 있는 작업을 할 수 있을만한 시간내에는 풀수 없는'이라는 뜻이다. 조금 비약해서 예를 들자면 '10년동안 비밀로 해야하는 문서가 있는데, 이 문서를 암호화 하면, 암호화된 문서를 가지고 키를 알아내기 어렵다.'는 말의 의미는 '10년 내에는 키를 알아낼 수 없다'는 의미로 이해하면 된다. [본문으로]
  4. '해쉬함수가 깨기 어렵다'는 말의 의미는 '위의 세가지 특성중 최소한 하나의 답을 알아내려면 천문학적인 시간이 필요하다'는 의미로 이해해도 무방하다. [본문으로]
  5. 언뜻 보기엔 2번하고 3번이 비슷해 보이겠지만, 그 의미는 다르다. 그리고, 게임에서 데이터나 프로그램 코드를 위조하는 것을 막는 목적으로는 3번의 특성은 필요 없다. 3번의 특성은 이중장부를 만들고 싶어하는 사람들을 엿먹이기 위해 필요한 특성이다. [본문으로]
  6. 이 diffusion 효과에 대해서는 4-ㄱ 에서 이미 설명을 했으니 모두모두 잘 아시리라 믿씹니다. [본문으로]
반응형
,
Posted by 알 수 없는 사용자
지난글에서는  Hash String을 사용하는 장점에 대해서 설명하였습니다.
Hash String을 사용하는 가장 큰 이점은 속도라고 설명을 드렸었는데, 이에 대한 컴파일러 최적화가 
어떻게 이루어 지는가에 대한 내용이 포프님께서 작성하신 글 ( http://www.gamedevforever.com/50 )에
 잘 설명되어 있습니다. Hash String을 사용할 때 문제가 되는 해쉬의 중복에 대한 내용은 
  잘 설명 되어 있습니다.

이번 글에서는 문자열을 Hash로 치환하고 이를 관리하는 시스템에 대해서 설명하도록 하겠습니다. 
여기서는 위 블로그 주인장이신 techsharer님의 테스트 결과에 따라 CRC32를 가지고 가장 해쉬 분포도가 
높은 공인된 다항식인 0x04C11DB7을 사용하도록 하겠습니다.

CRC32를 사용하기 위해서는 선행되어야 할 작업은 CRC32 테이블을 초기화 하는 것입니다. 
이러한 작업들을 설명하기 위한 클래스를 작성해 보도록 하겠습니다.

class CRC32Hash
{
public:
// Constructor
CRC32Hash();
// Creates a CRC from a text string
INT GetCRC(char* InText);
        INT GetCRC(wchar_t* InText); 
 

protected:
// Builds lookup table array
void InitTable();
// Reflects CRC bits in the lookup table
ULONG Reflect( ULONG Ref, char ch);

protected:
// Lookup table array
ULONG Table[256];
};


클래스의 헤더는 위와 같습니다. Init() 함수가 CRC32 테이블을 초기화 하는 함수이며 이는 내부에서 한번만
호출 되도록 protected 영역에 놓았습니다. Reflect는 테이블을 초기화 할 때 내부적으로 사용되는 함수 입니다.
저는 이 테이블 초기화를 생성자에서 자동 호출하도록 사용하고 있습니다. 위의 선언에 따라 생성자 및
 테이블 초기화를 구현해 보도록 하겠습니다.

CRC32Hash::CRC32Hash()
{
InitTable();
}

void CRC32Hash::InitTable()
{
// 이 함수는 CRC 테이블을 초기화 할 때 한번만 호출되어야 합니다.

// 이 테이블 초기화 함수는 PKZip, WinZip과 이더넷의 CRC-32가 사용하는 공식적인 다항식을 사용합니다.
ULONG Polynomial = 0x04C11DB7;

// 256개의 값들이 ASCII 문자 코드들을 표현하게 됩니다.
for ( INT i = 0; i <= 0xFF; i++ )
{
Table[i] = Reflect( i, 8 ) << 24;
for ( INT j = 0; j < 8; j++ )
{
Table[i] = ( Table[i] << 1 ) ^ ( Table[i] & ( 1 << 31 ) ? Polynomial : 0 );
}

Table[i] = Reflect( Table[i], 32 );
}
}

ULONG CRC32Hash::Reflect( ULONG Ref, char Ch )
{
ULONG Value( 0 );

// 7번째 비트와 0번째 비트를 교환합니다.
// 6번째 비트와 1번째 비트를 교환합니다.
// 이 작업 계속 진행합니다.
for ( INT i = 0; i < ( Ch + 1 ); i++ )
{
if ( Ref & 1 )
{
Value |= 1 << ( Ch - i );
}

Ref >>= 1;
}

return Value;
}


CRC32 테이블 초기화가 위의 함수들을 통해 이루어 지게 됩니다. 다음은 문자열을 이 테이블을 사용하여 CRC를
구하는 것입니다.

INT CRC32Hash::GetCRC( char* Text )
{
// 문자열을 이 함수에 넘겨 CRC를 생성하게 합니다.

// 위 테이블 초기화 함수들로 검색 테이블이 초기화되면, 이 함수는 검색 테이블을 사용하여 CRC들을 생성합니다.

// unsigned 변수들을 사용하도록 해야하는데, 음의 값을 가질 수 있는 변수들은 0 비트들이 요구될 때
// 상위 비트들을 사용하기 때문입니다.

//모든 비트들을 모두 켜서 시작합니다.
ULONG CRC( 0xFFFFFFFF );
// 문자열의 길이를 구합니다.
INT Len = strlen( Text );

// 버퍼의 텍스트를 저장합니다.
unsigned char* Buffer = Text;

// 문자열내의 각 문자에 대해 검색 테이블 값들을 사용하여, 알고리즘을 실행합니다.
while ( Len-- )
{
CRC = ( CRC >> 8 ) ^ Table[ ( CRC & 0xFF ) ^ *Buffer++ ];
}

// 초기 값과 Exclusive OR로 결과를 산출 합니다.
return CRC ^ 0xFFFFFFFF;
}

// Ansi character
INT CRC32Hash::GetCRC( char* Text )
{
// 문자열을 이 함수에 넘겨 CRC를 생성하게 합니다.

// 위 테이블 초기화 함수들로 검색 테이블이 초기화되면, 이 함수는 검색 테이블을 사용하여 CRC들을 생성합니다.

// unsigned 변수들을 사용하도록 해야하는데, 음의 값을 가질 수 있는 변수들은 0 비트들이 요구될 때
// 상위 비트들을 사용하기 때문입니다.

//모든 비트들을 모두 켜서 시작합니다.
ULONG CRC( 0xFFFFFFFF );
// 문자열의 길이를 구합니다.
INT Len = strlen( Text );

// 버퍼의 텍스트를 저장합니다.
unsigned char* Buffer = Text;

// 문자열내의 각 문자에 대해 검색 테이블 값들을 사용하여, 알고리즘을 실행합니다.
while ( Len-- )
{
char Ch = *Buffer++;
unsigned char* B = unsigned char(Ch);
CRC = ( CRC >> 8 ) ^ Table[ ( CRC & 0xFF ) ^ B ];
}

// 초기 값과 Exclusive OR로 결과를 산출 합니다.
return CRC ^ 0xFFFFFFFF;
}

// wide character
INT CRC32Hash::GetCRC( wchar_t* Text )
{
// 문자열을 이 함수에 넘겨 CRC를 생성하게 합니다.

// 위 테이블 초기화 함수들로 검색 테이블이 초기화되면, 이 함수는 검색 테이블을 사용하여 CRC들을 생성합니다.

// unsigned 변수들을 사용하도록 해야하는데, 음의 값을 가질 수 있는 변수들은 0 비트들이 요구될 때
// 상위 비트들을 사용하기 때문입니다.

//모든 비트들을 모두 켜서 시작합니다.
ULONG CRC( 0xFFFFFFFF );
// 문자열의 길이를 구합니다.
INT Len = strlen( Text );

// 버퍼의 텍스트를 저장합니다.
unsigned char* Buffer = Text;

// 문자열내의 각 문자에 대해 검색 테이블 값들을 사용하여, 알고리즘을 실행합니다.
while ( Len-- )
{
wchar_t Ch = *Buffer++;
                unsigned char B = unsigned char(Ch); 
CRC = ( CRC >> 8 ) ^ Table[ ( CRC & 0xFF ) ^  B ]; 
// wide character이기 때문에 한번 더 알고리즘을 실행합니다. 16bit 이기 때문에...
B = Ch >> 8;
CRC = ( CRC >> 8 ) ^ Table[ ( CRC & 0xFF ) ^  B ];  
  }

// 초기 값과 Exclusive OR로 결과를 산출 합니다.
return CRC ^ 0xFFFFFFFF;
}


이제 위의 함수를 사용하여 문자열에 대한 Hash Key (CRC)를 얻어올 수 있습니다. 이로서 기본적인 Hash String ID를 사용하기 위한 준비가 완료 되었습니다. GetCRC(...) 함수를 사용하여 얻어온 INT형으로의 비교만으로 문자열에 대한 비교 속도가 최대화 될 수 있습니다.

하지만 이것을 실제로 사용하기에는 편의성이 떨어지게 됩니다. 여기에 추가될 가장 기본적인 기능은 Hash Key를 가지고 이에 대한 문자열을 다시 얻어올 수 있어야 합니다. 또한 중복에 대한 분포도가 높을지라도 게임에서 많이사용되는 문자열들에 대한 처리를  해주어 중복을 더 회피할 수 있는 방법이 존재합니다. 다음 2회의 글에 걸쳐서 이러한 기법들에 대한 설명을 해 보도록 해 보겠습니다.

- by 김영민

- 참고 문서: 위키페디아 순환 중복 검사
반응형
,
Posted by 알 수 없는 사용자
안녕하세요, 한국에 있는 게임 사운드 스튜디오에 근무중인 정사인PD입니다.
벌써 13년째 근무중인 회사라서 회사 같다는 느낌보다는 
신체의 일부 같은 느낌이 들기도 합니다. 좀 무섭네요....

이번에 필자로 추천을 받아서 글을 쓰게 되었습니다.
첫 공개되는 글쓰기인데, 아무래도 글과 문서를 다루는 직종도 아니고, 언어능력이나, 사고능력 스탯이 상대적으로 낮게 생성된 캐릭이라 
문체나 내용이 부실할 수 밖에 없을듯 한데요, 계속 회를 거듭하면서 발전을 꾀하려고 하고 있으니 기대해주세요~ 

그럼 시작해 보겠습니다.

@ 사운드 디렉터, 또는 오디오 디렉터는 무엇을 하는 사람인가.

크게 2 가지로 나눠봤습니다.

1.  게임 기획, 아트, 프로그램, 연출 파트와 함께  게임에 들어가는 소리를 개발사 내부에서 조언하고 책임지는 사람
2. 사운드 크리에이터, 폴리아티스트, 작곡가, 세션, 편곡가, 사운드 디자이너, 성우,엔지니어 들과 함께 소리에 대한 모든것을 결정하는 사람. 

1번은 개발사 안에서 활동, 2는 사운드 팀 내지는 사운드 제작사에서 진행하는 것들이군요
2번에 있는 직책들은 잘 못보던 것도 있고, 뭐하는 사람인지 모르는것도 있을 수 있겠지만, 일단 진행하겠습니다..

1번과 2번의 큰 차이는 조언과 결정입니다. 
개발사 안에는 총괄 PD 또는 본부장이라는 직책이 있거든요. 또는 대표님....

2번에서는 협의나 결정을 사운드(오디오) 디렉터가 할 수 있지만,
1번의 예에선 좀더 신중하게 진행을 하게 됩니다.


@ 그럼 이 많은 것들 각 담당 자들과 어떤 협의가 이뤄지고 있는 것일까. 설마 혼자 다 하는건 아니겠(?)..

네, 절대 혼자 할 수 있는 일이 아닙니다. 모두가 함께 해야 좋은 사운드가 나오는 법이지요.
아무리 13년전에 패키지 게임 개발적때는 모두가 1인 10역하는 시대가 있긴 했었습니다.

기획자가 3D하고, 코딩했었을 적.  사운드도 마찬가지로
음악 만들고 편곡하고, 보이스 녹음(?)하고, 폴리 녹음해서 디자인 하고, 최종 마스터링까지!! (...)


이 모든게 잘 되었을까요?
물론 재미는 있었지만, 지금 생각하면 토나오고 ..... 부끄럽네요. 부끄럽고요..

이제는 놀랍게도, 산업화, 분업화가 잘 되어있는 게임 개발사가 참 많아서 햄볶아용.
아래와 같은 예가 천국 같은 곳이죠! 

위에 1번  - 개발사에서의 사운드 디렉터에게 도움 주시는 분들. 

 - 기획팀에선 게임의 전반적인 내용과 시나리오, 재미를 느끼게 할 시스템, 연출 들을 알려주고, 아이디어를 제시합니다.
 - 아트 팀에선 원화나 스크린샷, 맵, 캐릭터등 을 통해, 게임의 시각적 분위기나 향기를 느끼게 해주죠.
 - 프로그램 팀에선 게임이 영화처럼 일방통행, 주입식 교육이 되지 않기 위해, 온갖 사운드 인터렉션을 만들어 주기도 합니다. (물론 사운드     프로그래밍은 개발일정에서 후순위에 있긴 합니다만..)
 - 게임QA팀에선 사운드 버그나, 파티 플레이를 통해 다른 사용자간의 사운드 벨런스를 확인 시켜줍니다.
 - 마케팅 팀 또는 PM은 일정이나 진행상황을 통제 또는 지원합니다.

뭔가 천국 스럽지만, 또 그렇지만도 않을 듯 하네요.

사운드 디렉터가 하는 업무의 양이 과히 장난이 아님을 슬슬 실감을 하시게 될텐데요
위 1번 예의 개발사에서 날라온 피드백과 이슈들은 이제 사운드 디렉터의 선택과 집중,
그리고 효율성을 모두 검토한 후, 2번으로 넘어가게 됩니다 

2번. 사운드 스튜디오, 또는 사운드 팀에서 하는 일들은 완전 헬.. ㅜㅜ.

이제 2번 사운드 스튜디오에서 진행하는 디렉터의 업무가 남아있는데, 
이건, 다음 회로 넘기도록 하겠습니다.

할 말이 너무 있는데, 정리가 안되다 보니 머리 밖으로 꺼내는 과정이 좀더 필요 할 것 같네요.
감성을 근거로 일하는 사람들에겐  참 쉽지 않은 일 인것 같습니다. :)

----------------------------잡설------------------------------------------------
위에 효율성 얘기가 나와서 말씀드리면,
넣고 싶은거, 하고 싶은거 다 하면서 살 순 없을까요(...) 이런건 해외 개발사들이 참 부럽긴 합니다. 

오래되긴 했지만, 바쁜와중에 플레이 했던, 레드 데드 리뎀션의 경우 완전한 세계를 소리로 구현을 해 두었을 정도였으니까요.
정말 모든 사물, 환경, 인터렉션이 현실과 구분이 안갈정도로, 

눈을 감고 게임안에 있다보면, 서부의 세계에 내가 있는것 처럼 온몸을 감싸는 소리를 느낄 수 있었습니다.

아쉽게도 한국에선 콘솔게임이나 패키지 게임을 만들 일이 많지 않네요. 이 말은 고해상도 사운드, 고퀄리티를 항상 외칠수만은 없는
온라인 환경이라는 특수성인데, 물론 온라인이라고 스팩을 항상 줄여야 하는것은 아니지만, 되도록 효율성을 살리는게 나중을 위해 좋죠.

싸구려 조악한 스피커로 게임을 하는 피시방 문화나, 몰래 소리없이 게임을 즐겨야 하는 아이들에겐 배부른 소리같지만,
게임이라는 문화가 당당하게 평가받는 시대가 오길 바라면서

글 마무리 짓겠습니다.

감사합니다.










 
반응형
,
Posted by ozlael

들어가며

최근들어 교육과학기술부(이하 교과부)는 게임의 폭력성이 학교 폭력을 유발시킨다고 몰아세우며 쿨링 오프제 도입을 주장합니다. 몇몇 보수 언론들은 게임이 펑소년의 폭력성을 유발시킨다며 지원 사격을 가하기 시작했습니다. 정말로 게임이 학교 폭력의 원인인지, 게임이 청소년들을 폭력적이게 만든다는 주장에 대해 따져보도록 하겠습니다. (이것만도 한가득이라서 뇌드립이나 기타 사항들은 따로 다루도록 하겠습니다.)  


대구 자살 사건

교과부가 이 전쟁에 뛰어든 표면적인 계기는 대구 중학생 자살사건입니다.(삼가 고인의 명복을 빕니다.) 가해 학생은 평소에 게임을 즐겼고, 계정이 해킹을당하자 피해 학생에게 억지로 게임을 시킨것이지요. 이 때문에 게임이 폭력성을 유발시킨다고 몰아가고 있습니다.
 일단, 게임이 괴롭힘의 도구로 사용된 것인데 이 도구더러 범인이라 하는 것도 이해가 가지 않습니다. 게다가 이 사건의 게임은 다름아닌 “메이플 스토리” 입니다. 아기자기한 케릭터가 나오고 피 한방울 튀지도 않습니다. 게다가 폭력성이 전혀 없음을 인정받아 전체 이용가로 분류된 게임입니다. 이런 게임을 가지고 폭력성을 운운하는 것은 심의 등급 제도를 무시하는 발언입니다. 

이 게임이 폭력적이라구요?


언론의 몰아가기 

 사실 게임이 이러한 일에 휘말린 것이 처음은 아닙니다. 살인이나 폭력 사건이 나올 때 마다 게임이 항상 그 죄를 뒤집어 써왔습니다. 지난 2007년 버지니아 공대에서 일어난 조승희 사건 때, 국내 언론들은 범인이 평소에 총싸움 게임을 즐겼고 그로 인해 살인을 하게 되었다고 보도했습니다. 하지만 조사 결과 게임을 전혀 즐기지 않았고, 오히려 "친구들은 게임을 하지 않는 범인을 이상히 여겨왔다"는 것이 알려지기도 하였습니다.[link]
 최근 보수 언론들은 또 다시 이러한 몰아가기를 시작하고 있습니다. 조선일보는 얼마 전  게임이 폭력성을 유발시킨다고 기사를 써냈습니다. "맨헌트"라는 국내에서 판매 금지된 게임을 웹하드에서 다운 받아서 플레이해보고서는 게임의 폭력성을 이야기하고 있습니다.[link] 기사에서 대놓고 불법 다운로드를 받은 사실을 서술 한 것도 우습지만, 국내 뿐 아니라 해외에서도 금지된 게임을 억지로 가져다가 국내 청소년들에게 해롭다고 말 하는 현상 자체가 우습기 그지없습니다.
 중앙일보에서도 역시 몰아가기를 시도하고 있습니다.[link] "친구 살해 고교생은 게임광"이라는 선동적인 제목의 기사를 써냈는데, 내용을 보면 우습기 그지 없습니다. 막상 그 학생이 했다는 게임은 유명한 축구 게임인 피파 온라인입니다. 축구 게임을 하면 살인마가 된다는 논리라면 2002년 대한민국은 살인마 천지였을 것입니다.

축구를 하면 살인마가 된다구요!?!?


한국 정소년의 게임 이용 시간

교과부에서는 학교 폭력이 심한 이유가 국내 청소년들의 게임 이용 시간이 많기 때문이라고 주장합니다. 청소년의 평균 게임 이용 시간은 핀란드는 10분, 미국은 25분이지만 국내는 46분으로써 다른 나라에 비해 월등히 많다는 것입니다. 하지만 이 자료들의 신빙성은 0에 가깝습니다. [link] 
 핀란드 청소년의 게임 이용 시간이 10분이라는 근거로 삼은 보고서는 십년도 훨씬 넘은 2000년 초반의 자료입니다. 오히려 2007년의 조사 자료에 의하면 핀란드 청소년의 게임 이용 시간은 1시간 17분으로 한국 청소년의 이용 시간보다 훨씬 많습니다.
 미국 청소년의 하루 게임 이용 시간이 25분이라는 근거 역시 2004년의 조사 자료입니다. 오히려 2007년의 조사 자료에 의하면 미국 청소년의 게임 이용 시간은 2시간으로써 이 역시 한국 청소년의 이용 시간보다 훨씬 많습니다.
 이토록 최근 자료에 의하면 국내 청소년의 게임 이용 시간이 다른 나라에 비하면 낮은 것으로 나오지만, 교과부가 억지 자료를 꺼내와서 현실을 왜곡 호도하는 것입니다. 


게임과 폭력의 연구 사례

 이토록 몇몇 언론과 국가 기관이 근거도 없이 게임을 청소년 폭력의 원인으로 몰아가고 있지만, 중앙대학교 정신과의 민경준 교수와 한덕현 교수는 게임과 폭력의 관계는 긴 시간 많은 연구가 필요하며 성급한 속단은 이르다고 하였습니다.[link] 또한, 해외의 많은 연구 기관들은 게임과 폭력이 관계가 없다는 발표를 내놓고 있습니다.
 캐나다 라이어슨 대학에서 연구 조사한 결과 폭력적인 게임을 한다고 해서 사람의 기본 감정 성향이 바뀌지 않는다고 발표하였습니다.[link] 
 텍사스 A&M 국제 대학의 크리스토퍼 J. 퍼거슨 교수 역시 게임의 폭력성이 청소년의 실제 폭력성과는 상관 관계가 없다는 연구 결과를 발표했습니다. 이는 단기간이 아닌 3년에 걸친 장기간 조사입니다.[link][link]
 미시간 주립 대학교 연구팀은 대략 500명의 아이들을 대상으로 실험 한 결과, 게임을 즐기는 아이들은 게임의 폭력성과는 상관없이 창의적이라는 발표를 내놓았습니다.[link]


해외 정부 기관의 사례
 
해외에서는 이런 연구 기관들 뿐 아니라 정부 차원에서도 게임과 폭력성의 관계를 부정하고 있습니다.
호주 내무부 장관인 브랜던 오코너는 폭력적인 게임과 현실 속 공격성의 연관성에 대한 결론은 내려지지 않았다는 보고서를 발표하기도 하였습니다.[link]
캘리포니아에서는 아놀드 슈왈츠제네거 주지가사 청소년에 대한 폭력적인 게임의 판매를 금지하는 법안을 내놓았지만 게임과 실제 폭력의 상관 관계가 없기에 위헌판결난 사례도 있습니다.[link]

아니 판사양반! 그게 무슨소리요! 내가 위헌이라니!


마치며

이토록 게임의 폭력이 청소년의 실제 폭력과는 상관 관계가 없다는 연구 발표 및 사례들이 많습니다. 하지만 간사한 교과부는 학생인권조례안과의 기싸움을 목적으로 학생들의 자유를 제한하기 위해 게임을 규제하려 들고있습니다. 게으른 교과부는 근본적으로 고치기 어려운 학교 폭력의 책임을 게임에 떠넘기며 마녀 사냥을 하고 있습니다.
 사실 정부 교육 기관의 이러한 마녀사냥은 오래 전 부터 있어왔습니다. 다만 예전에는 그 대상이 만화와 에니메이션이였고 이제는 게임으로 대상이 바뀐 것 뿐입니다. 교과부는 해묵은 책임 전도 방법을 중단하고 책임감 있는 정부 기관으로 거듭나기를 희망합니다.

 게임협을 방문한 교과부 이주호 장관
반응형
,
Posted by 알 수 없는 사용자
안녕하세요 T모사에 근무하는 배경아티스트/TA Silverchime입니다. 
이번에는 전공따라 배경관련해서 편하게 교양 수준의 글을 한번 적어볼까 합니다.  

배경이란게 참 난감해요 대체 배경이 뭘까요? 

캐릭터를 제외한 것이 다 배경인지. 그냥 건물있고 나무있고 땅있으면 배경인지. 전 그래서 다른 분들에게 가끔 설명할때 어딘가에 던져졌을때 자신의 모든 오감을 통해 세계에서 얻는 정보. 라고 말하곤 했습니다. 한번 이런 식으로 설명을 해보도록 하겠습니다. 


여러분은 어떤 캄캄한 곳에 뚝 하니 떨어졌습니다. 그곳엔 암흑뿐이고 아무런 정보도 없습니다.


물방울이 떨어지는 소리가 들립니다. 이 소리는 마치 공동에서 울리는 듯 여운을 남깁니다. 멀리서 들릴락말락한 희미한 물소리도 들려옵니다.


청각
오감 중 청각적인 부분입니다. 
공간의 폐쇄도, 반사 잔향, 들리는 위치, 크기, 거리, 음원의 대상, 그리고 음원대상의 상태... 
잘 만들어진 엠비언스 사운드가 첨가될수록 현재 상태와 위치등을 정확히 그려 내는데 도움이 됩니다. 최근에 급격히 발전한 3D 오디오랑 더불어서 잘 설계된 음향을 들으면 정말 현장에 서 있는 듯하게 느껴질 정도로 현장감의 큰 부분, 그리고 즐거움을 제공한다고 말하고 싶습니다. 완성도에 어마어마한 + 적인 요소. 사실상 배경 분위기의 절반이라고 봅니다. 정보가 없는 상황에서 총 소리, 애기울음과 고통에 찬 비명이 들리는지, 아니면 아이들의 즐거운 노래소리가 들리는지에 따라 장르자체도 즉시 예측할 것이고 (FPS, 호러, 아동용) 반응이 다를 것입니다.


바닥은 습기와 이끼로 덮여 있어 차갑고 미끄럽습니다. 젖은 흙냄새와 곰팡이가 어우러진 불쾌한 향이 느껴집니다. 상당히 추워서 몸이 떨립니다. (후각과 촉각/통각/온냉감)

후각
금새 적응하고, 이외로 둔감한 부분입니다만 시각이 명민하지 않을때 주변 상황을 파악하는 보조 수단입니다.
만일 여기서 캔디나 달콤한 향이 난다면, 조금 릴랙스할 테지만, 만일 고기 썩은냄새나 불쾌한 냄새가 난다면 바로 상황이 좋지 않다는 것을 알아 차리겠죠.

호러/고어게임류(사일런트 힐이라던지요.)에서 어떤식의 향기가 제공될지 가상으로 생각하면. 
함께 사는 사람에게는 날벼락일 수도 있겠네요.  

향기 프린터라던가  몇 차례 용기있는 시도가 있긴 했습니다만... 후각은 아직 비디오게이머들에게 제공되지 않는 감각입니다. 

촉각/통각/온냉감
아... 뭔가 맞으면 진동으로 피드백이 오는 정도면 모르겠지만. 일단 아픈것은 저도 사양이고요
혹한지나 남극빙해속의 추위 정글의 고온다습한 더위, 사막의 고온...이런건 그저 정보라기보다는 스트레스겠죠. 온냉감은 비주얼 이펙트의 힘을 빌어, 입김이나 아지랑이 등 시각적인 정보로 보조가 가능합니다.



 촉각으로 들어가면 물론 좋은 감각이나 정보도 있겠지만 동물의 시체나 사체 만지는 느낌  이런건...음 

(우리는 그간 해부학적 퀘스트를 너무 많이 봐 왔지요.)  

기술발전단계의 아주 최후의 최후 체감형 VR이 성립된 후나 
그리고 무엇보다 심/의/를 통과해야 가능할거 같습니다. 

요즘 최고 잘나가는 진보스 이길수가 없어... 


캄캄한 곳을 손으로 짚으면서 앞으로 나아가니 아주 희미한 빛의 잔영이 사각형으로 보입니다.
닫힌 나무 문을 발견했습니다. 이제 문을 열고 방으로 들어갑니다.



시각 정보 : 사물에서 전해주는 이야기.

이제 본격적으로 문화/재료/기술수준에 관한 글입니다.
우리는 사물을 시각적으로 보면서 단지 그 모양과 볼륨만을 보는 것이 아니라 재료/기술수준/문화와 같은 복합적인 정보들을 한번에 폭발적으로 받아들입니다. 말이나 글로 설명하려는 몇 페이지를 할애해야 할지 모를 정보들을 '어 그래'정도로 그대로 받아들여 버리는 걸 보면 그야말로 
놀라운 일입니다. 한가지 짚고 넘어가야 할 아주 상식적인 것들이 있습니다. 

문화Civilization와 기술Technology 재료Materials는 뗄 수 없는 관계로서 인과관계에 따라 발전합니다. 

가구 家具 Furnitures
 
가구란 실내에 놓여지는 여러가지 도구 의 총칭입니다. 대부분 수납이나 편의를 의해 제작되지요. 가장 원시적인건 아무래도 지푸라기나 대나무 등 섬유질로 짠 바구니였을 것입니다. 카펫이나... 이러한 Fabric 기술이 기본적으로 발달합니다. 


그러나 불을 다루고, 요리를 하기 시작하면서 섬유로 된 가구는 저장용으로는 꽤 불편한 점이 많습니다.  사람들은 요업pottery, 가마를 만들고 불을 다루기 시작하면서 진흙을 구워 항아리등 물이나, 알콜(매우 중요하죠)등 수분이 있는 것들을 담을 수 있는 가구를 만들기 시작합니다.


목재 가구를 만들수 있다는건 일단 제제소lumbermill가 있어야 하겠고 (나무판자제작), 최소한 톱과 도끼 및 집게, 못 등이 필요하니 원시적인 단계라도 대장간이 필요 합니다. 


(좌)carpenter’s tools
(우)제재소는 대부분 흘려보내는 식의  원목 수송의 편의를 위해 물가에 맞닿아 있었습니다. 

대부분 게임은 아바타에 입힐 장비+향상시킬 장비가 필요하므로 최소한 금속을 다룰 수 있는 시대 이상으로 설정하는것이 대부분일 것입니다. 병기로서의 금속은 최소한 청동을 다룰 수 있는 시대가 낫겠지요(신화랑 엮어서 미케네 문명정도는 되어야겠죠, 아마 프리히스토릭 게임은 나와도 으음... 어떤 부분으로 상향을 시킬지 뭔가 어렵습니다. 일반 뾰족한 돌에서 흑요석 정도의 상향...일까요? )

다음 눈에 들어오는 것이 나무 클럽이라고 생각해보지요. 


나무 클럽도 천차만별이라 원시인이 쓰는 그저 뭉툭한 나무’가지’일수도 있습니다. 그러나 금속을 박거나 가죽을 말아 손잡이를 만들어 둔 제대로 된 클럽이라면 이것으로 문명도를 추측해 낼 것입니다. 

가죽 스트랩을 만드려면 가죽 무두질을 할 기술이 있어야 하고, 그것을 잘게 끈으로 잘라낼 도구도 있어야 겠지요. 이쯤되면 날카로운 연장(연모)등을 사용할 수있으리라 추측할 수 있습니다. 거기에 아름다운 문양까지 새겨져 있다. 그러면 훨씬 문명화된 사회를 예측할 수 있겠지요.


자 이번엔 칼이 벽에 걸려있는 것을 발견했다고 해 보겠습니다. 

 
금속을 전문적으로 다룰 수 있다는 이야기는 이미 농경을 넘어서서 교역,화폐, 집단사회로서 광부나 대장장이 등의 전문직이 등장했다는 의미입니다. 집단사회의 단계에 따라 왕정/군주/참주와 같은 정치형태도 있을 것이고 거기 따르는 관료들이 등장했을 수 있다는 의미입니다. 
장식이 없고 칼의 길이가 짧다. 근거리 집단전투의 형태가 이루어진다고 추측할 수 있으며
장식이 화려하다면. 고위층, 즉 고도화된 정치형태, 또는 계급사회가 있다고 생각할 수 있습니다.  

강철Steel로 병기를 마련할 정도라면 청동기Bronze Age를 넘어섰다고 봐야겠지요. 초기 연철 Iron은 전투용으로 쓰기는 강도가 약간 부족하므로 초기에는 청동기를 차라리 무기로 쓰는 경우가 많았습니다. 그러나 시간이 흐르며 근성으로 두들기며 강철을 만드는 대장야금기술Metallurgical Technology이 발달하면서 강도가 높고 값싼 철제 기구들이 많은 부분을 대치하게 되고 오히려 장식품 도구들에 청동의 이용도가 더 높아지는 결과를 낳았습니다.

철로 장식품을 만들었다면... 수많은 인류문화가 남아나질 않았겠지요. 

겨우 50년 남짓 지난 유보트의 잔해.

 
이번에는 총을 발견했습니다


이제부터는 문제가 심각해 집니다. 화약이 발견되었다는것은 시대의 건물 양식이 돌변하는 계기가 됩니다. 화약과 대포가 있다는것은 시민들을 보호하기 위한 성벽이 유명무실해지고 성은 방어개념의 포트리스 형태에서 주거의 팰리스 형태로 분화하는 분기점이 되기 때문입니다. 전쟁의 양상Warfare도 도시방벽에서 옮겨져 외곽 들판에서 일렬로 서서 싸우는 형태로 바뀌었지요 Linear tactics

포트리스의 높은 벽도 대포를 막을수는 없었습니다. 

무대가 지구이고 SF나 외계가 아니라면 17~19세기 양식이 어울릴 것입니다. (바로크 로코코 고딕까지)

동네 포격으로 다 초토화시키면 점령해도 이득이 없으니 우리 들판에서 해결합시다.
Linear Tactics 

문득 집에서 유리창을 발견하셨다면 산업혁명, 18세기 이후가 됩니다.
그 이전에는 민간에서 접근할 만한 가격대가 아니었습니다. 

기계의 발명으로 우리는 유리를 가질 수 있게 되었지만,
수많은 공해와 아동 노동자등의 부작용도 함께 왔습니다. 

단지 집안에 있는 사물 만으로도 꽤 많은 정보를 얻었습니다.
이제 문을 열고 밖으로 나가면


식생, 기후, 조경, 건축양식 등과 맞닥뜨리게 됩니다.


 
전반적인 세계를 구성하는 더 많은 것들의 정보를 시각적으로 얻을 수 있습니다.  한랭지, 습지대, 사막 등 기후에 따른 나무나 수풀등의 형태, 길의 형태나 포장상태에 따른 시대 추측, 다리나 건물에서 알수있는 대략적인 연대 등입니다. 

자 오감으로 인지하는 배경에 관해 간단한 설명을 했습니다.  여기서 짧게 저만의 결론을 내려보겠습니다.

배경은 결국 세계와 문화를 구축하고 전달하는 일이라고 생각합니다. 
 
음향/조명/기후/지형/식생/풍화/행태/문화/재료/기술/정치/역사를 아우르며 대화와 스크립트를 통하지 않아도 플레이어에게 배경 그 자체로 수많은 이야기를 전합니다. 강요하지 않고 스스로 체험하며 느끼도록 하지요.  감정을 조절하기도 합니다. 상상하기도 끔찍한 무섭고 두려운 장소에서부터 아늑하고 고양감을 느끼는 공간까지. 

그러나 역으로 실수로 인하여 잘못된 연결고리도 많이 발생하기도 합니다.일례로,
합당한 설명이 뒷받침되지 않은 기술과 재료의 등장, 기후나 환경에 순응하지 않은 디자인, 상호 연계성이 없는 건축물, 문명과 딱히 어울리지 않는 알수없는 장식등은 전체적인 세계의 통일성을 깨고 심지어 크게 잘못된 고증은 현지에서의 크고작은 비난을 불러일으킬 수도 있습니다. 초기에 한국을 배경으로 한 예전의 한국전쟁 게임들에서 그 예를 찾을 수 있습니다. 한국을 베트남 오지 처럼 표현해 놓았지요. (기와지붕 라인이 딱 베트남... 서울 민가에 야자수가 서 있다던지요...) 무려 기원전 배경에 첨두아치가 서는 경우도 있었습니다. 이런경우는 거의 천칠백년을 타임워프 합니다.... Orz  신라시대에 호치키스 머신건을 등장시키는 급입니다...

고증? 그거 혹시 먹는겁니까
 
단순히 '배경디자이너/모델러' 또는 ‘환경 아티스트’ 라는 단 한 직군으로 우리나라에서는 통용되고 있지만 사실은 조명전문가, 텍스타일 디자이너, 건축가(아키텍트), 식물학자, 생태학자, 조경전문가, 사진가, 때로는 석공의 마음으로부터 목수의 손놀림까지 필요한 직업이라고 생각합니다. 사실 분화되어야 하는 부분이 맞고 많은 부분이 이미 해당 전문가나 필름영상쪽과 콜라보레이션 하고 있습니다. 

가깝게는 직군중 레벨디자이너, 원화가 사이에서 수많은 조율을 해야 합니다. 월드라이팅이 추가되게 되면 그때부터는 이제 프로그래머 (렌더링 쪽) 파트와도 수많은 빛과 그림자, 날씨표현(눈/비)와 쓸 수 있는 버짓에 관한 대화를 해야 하고요.  
이런 직업을 가진 것에 많은 자부심을 가지고 있으며, 차후 하드웨어의 발전과 렌더링 기술의 진보에 따라 많은 발전이 이루어질것이라 믿고 있습니다. ^^

다음 글에는 
동굴, 고인돌부터 마천루까지 인류가 중력을 기술로 이겨내며 발전한 건축양식에 대해 써 볼까 합니다. 

쓰다보니 마감을 넘겨 버렸네요 ^^; 20일이 되어버렸습니다. Orz
월요일 입니다. 아침 커피 한잔으로 좋은 아침, 행복한 한주 시작하세요~  



반응형
,
Posted by 대마왕J

0. 오늘부턴 이론 좀 배워봅시다.

5강동안 잘 따라오셨는지요? 어렵진 않으셨는지요?

... 쉬웠지요?
솔직해 말해봐. 쉬웠잖아....

괜찮아괜찮아 쫄지말고 솔직히 말해봐.. 응? 친한척해 친한척해 그동안 너무 쉽다고 댓글도 안달리고 관심도 적었던거 다 알고 있어 ...






5강까지는 일단 '휘리릭' 하고 큰 줄기를 훑어 보았습니다. 이론이고 뭐고 대충 대충 넘어갔지요.
기본적으로 '이 정도는 뭐 쉽네... ' 라고 생각하시면서 지나오셨다면 정상입니다.
굳이 따라해보지 않고 눈으로 봐도 그냥그냥 따라 올 수 있을만큼이었지요.



... 노린거니까요.



그래서 여태까지를 1부라고 생각하도록 해 보겠습니다.
한마디로 유저를 낚기위한 낚시였달까.

월척이구나




그럼 이제 맛을 들였으니까, 조금 레벨을 올려보도록 해 볼까요?
이제 다음으로 계획되고 있는건 다음과 같습니다. 대충 이렇게 생각하고 있긴 한데, 뭐 상황에 따라 변할 수도 있겠..

2부
일단 실무에서 바로 사용하기 좋게, 몇 가지 함수와 이론를 이용한 예제로 응용작품 만들기 튜터리얼을 해 보겠습니다. 이것으로 일단 급한대로 실무에서도 사용가능!

3부
5강에서 휘리릭 넘어갔던 라이팅 이론을 '처음부터 구현해 봅시다' 노말맵도 그냥 있는거 쓰는게 아니라, 원리를 깨닫고 사용하고 응용하는 것 까지 해 봅시다. 기본적으로 Diffuse 라이트와 Specular 정도는 그냥 dot이랑 pow 써가면서 짜버릴 수 있게 .. 그러면서 프로그래머들이 잘난체하듯 어렵게 써놓은 쉐이더 코드들을 아주 쉽게 풀어서 쉐이더 FX로 짜 볼까요. (이건 과연 할 수 있을 것인가...)



대충 이렇게 생각해 봤는데요. 오늘부터 2부라고 할 수 있겠지요. 예정된 것도 아닙니다. 그냥 하다보니 이 정도에서는 해야겠다는 생각이 들었어요. 글도 손가는대로 막 쓰는 겁니다. 이 무개념에 무계획 같으니라고...

자아, 그래서 오늘은 뭘 해 볼까요...
아무 생각없이 쓸 수 있는 기본 조작은 끝났으니까...

오늘부터는 이제 실제로 이론도 약간 필요한 기본 조작들을 해 보도록 하지요.
오늘 해볼 건 UV 조절입니다.





1. UV? UV가 뭐지?


UV는 천재뮤지션 유세윤과 뮤지 2인으로 이루어진 가수를 의미합니다.
개인적으로 이태원 프리덤이라는 노래를 가장 좋아하지요.

출처 : 네이버 인물정보


.... 내 이럴 줄 알았어라면서 피식 웃은거 알아요.
이것은 당신의 얼굴. 당신 비웃는다 나를.

이 자식이 상평통보 시절 개그를...






이런 뻔한 낚시에 낚이지 않으실 거라는거 다 알고 있었습니다.
네, 사실대로 말씀드리지요. UV는 사실 (Ultraviolet: 자외선) 을 의미하는 말이었지요. 다 아시잖아요?
우리 눈에는 보이지 않지만, 화학작용과 살균작용이 강하고 피부암 등을 발생시킬 수도 있는 전자파입니다.
썬크림 바르는 이유가 이 빛을 차단하기 위해서인거 다 알고 계시지요?






... 죄송합니다. 이것도 개드립입니다. 사실대로 말씀드리겠습니다.

컴퓨터 그래픽스에서 UV는 , 3D 모델에 2D 텍스쳐를 입힐 때 사용하는 좌표입니다.[각주:1]

http://en.wikipedia.org/wiki/UV_mapping



그리고 UV는 이렇게 0~1 사이의 float 값으로 표현됩니다. 그림이 아무리 넓어도 , 정사각형이 아니더라도 말이죠.
.... 0~1 사이의 flaot 값이라? 우리가 이전에 RGBA 칼라의 채널 얘기할 때 하던 말 아닙니까? 흐음...
여기서 눈치가 빠르신 분들은 뭔가 눈치를 채 주셔야 합니다 후후후.
일반적으로 이렇게 표현하는데요,

http://wiki.modsrepository.com/index.php/Call_of_Duty:_Font_System


3D max에서 이걸 보시려면 Unwrap UVW 모디파이어에서 Edit 버튼을 누르시면 이런 그림을 보실 수 있습니다 .
광활한 가운데 파랑색으로 좀 진한 박스가 하나 그려져 있지요.
이 박스가 바로 UV의 0~1 까지를 나타내는 영역이며, 이렇게 생각하시면 됩니다. [각주:2]





자, 예를 들어 이런 물체에 이런 텍스쳐가 입혀진다고 해 봅시다.



그럼 이렇게 입혀지도록 UV를 조절하셨겠죠.



맥스에서 보면, 이렇게 말이죠. 이렇게 만드시잖아요.
저기 있는 Edit UVWs 안에 그려진 '좀 굵은 사각형' 안에 텍스쳐를 채워 넣으라고 배웠잖아요. 이유는 모른채.
그랬잖아요. 그렇게 살아왔잖아요.
조금 아시는 분은 저 칸 넘어가도 동일한 그림이 나온다는걸 알고 그걸 이용하시기도 하고...


그래서 실제 복잡한 작업 하실 때에는 저 영역에서 가능한한 낭비없이 만드시려고 애쓰시곤 합니다. 이렇게도 배치해 보고 , 저렇게도 배치해 보고 말이죠. 여기까지가 그래픽 디자이너 분들의 생각.


그래서 그렇게 해서 UV를 맞추고 나면,

그 UV 위치값은 "vertex" 에 저장되게 됩니다.

vertex가 이런 정보를 가지고 있는 거지요

"나 1번 버텍스(vertex)는 [grass.dds] 텍스쳐 파일을 (0.0 , 0.0) 이라는 좌표로 가지고 있습니다"

이렇게 vertex에는, 다른 많은 정보와 함께 UV 정보도 float2로, 0.0~1.0 사이의 값으로 가지고 있게 되는 것입니다.[각주:3]
아래 그림에서처럼 말이지요.


이것이 UV 정보입니다. 텍스쳐가 입혀진 오브젝트라면 반드시 버텍스에 UV 좌표 정보가 들어가 있습니다.

그러므로, 정리해 보면 3D 오브젝트에 텍스쳐가 입혀지려면 두 가지 중요한 정보가 필요하다는 것을 알 수 있습니다.

바로

1. 어떤 텍스쳐를 입힐 것이냐
(Sampling 이라고 합니다.말그대로 텍스쳐에서 칼라값을 추출하는 기능이죠)


2. 어느 좌표에 입힐 것이냐
(UV 좌표. UV coordinate 라고 합니다. )


이 두 가지 정보 말입니다.








2. ShaderFX에서 제대로 된 방법으로 만들어 봅시다.

자... 그럼 shader FX 에서 , 위 그림과 똑같은걸 한 번 만들어 봤습니다.
이제 이건 뭐 눈감고도 하시겠지요 허허허. 아니, 진짜 눈감고는 하지 마세요.


그런데, 위 단원에서 분명 이렇게 말했습니다.
"텍스쳐가 오브젝트에 입혀지려면 반드시 텍스쳐 정보 (샘플러)와 UV 좌표가 있어야 한다"
라고 말이죠.




그런데 우리는 그런 정보 입력한 적 없거든요?

네가 나몰래 넣었냐?






뭔가 이상합니다. 뭐 우리 그래픽 디자이너들은 원래 탁하면 척하고 잘 알아서 붙는 프로그램에 익숙해져 있다 보니 이런 일이 생겨도 의문을 가지지 않던게 보통이었습니다.

그렇지만 이젠 그렇게 에이 몰라 하고 넘어가면 안되지유.
어쨌건 이건 뭔가 이상합니다. 아무것도 없는데 그림이 나오다니 !!! 텍스쳐는 넣었다 쳐도 '샘플러'라는 것은, 'UV'는 어디서 와서 어디로 간건가!!

그렇게 생각하고 다시 찬찬히 shaderFX를 보니 뭔가 이상한게 보입니다.


으응?

너무도 당당하게 샘플러(Sampler)랑 UV Coords(UV Coordinate : UV좌표) 라고 씌여 있습니다.
보통 shaderFX는 오른쪽에서 입력받아서 왼쪽으로 출력하는 방식이니...
보니까 이 두 값을 입력받아야 하는데 비어 있습니다 !!!! 값이 없는데 작동하고 있어요!!!
심장이 없는데 움직이는 좀비처럼 말이죠!!!

으아아아아아아악

잠깐 심호흡을 하시고 진정하세요. 아직 심장마비에 걸리시지 않아도 좋습니다.
다행히도 shaderFX에는 좀비가 살고 있지 않으며, 정상으로 동작하고 있는 것입니다.

shaderFX는 그래픽 디자이너들이 쉽게 쉽게 쉐이더를 짤 수 있게끔, 이 값을 넣지 않으면 자동으로 처리해 주는 기능을 가지고 있습니다. 즉, 넣지 않아도 자동으로 적절한 값을 넣어 준다는 말이지요. 특별이 이 값을 만질 이유가 없다면, 그냥 두셔도 상관 없습니다.

그렇지만 이번 시간엔 이 값을 만져볼 생각이므로, 이 값을 넣어보도록 하겠습니다.
샘플러랑 UV coords 노드를 만들어 보겠습니다.


샘플러는 TextureSampler란 이름으로 Maps 아래에 있습니다. [각주:4]

UV coords는 vertex에서 입력받는거라 Input에 있습니다.

이 둘을 만들고, 각각 맞는 곳에 연결해 줍니다.
이렇게 되면, 정말 정식 방법으로 완성되는 것이지요. [각주:5]

단, 아주 약간 귀찮은 것이 있습니다. 이제 더이상 Texture를 TextureMap 노드에서 불러오지 않습니다. 기존에 불러온건 무시됩니다. 이제 Texture는 TextureSampler에서 불러와야만 합니다. (저는 혼동을 피하기 위해, 아예 TextureMap 노드를 지웠다가 다시 만들었습니다 ) 이론적으로 이게 당연하겠지요? 샘플러가 텍스쳐를 불러오는 것이 정석이니까요.



그림으로 보면 아래 그림처럼 되겠지요. 더 이상 TextureMap 노드에 넣었던 그림은 사용되지 않습니다.

모양은 똑같지만. "이게 정석입니다" 프로그래머들이 이해하는 개념과 같은 모양이지요.



3. UV를 움직여 봅시다.

자 이렇게 만들었으니, UV 를 좀 써먹어 봐야 서운하지 않겠지요.
기존에 그냥 텍스쳐만 넣는 것 만으로는 안되었던 것. 그런 것을 해봅시다.
어떻게 쓸 수 있을까요?

일단, 샘플러는 그대로 두고, UV에다가 우리가 알고 있던 사칙연산을 써 봅시다.

여기다가 뭔가 해 봅시다.


이미 기초 조작법 시간에 충분히 했으므로, 사칙연산을 하는 법은 굳이 다시 설명하지 않겠습니다. 

MathOperator 로, Constant(상수)에 더해보도록 합시다.
간편하게 1을 더하고 싶으나, UV에서는 1을 더하면 원하지 않는 결과가 나오니 0.2 정도를 더하는 것으로 하겠습니다.
아래 그림처럼 만들어 보세요.

못하겠으면 1강부터 다시 보고 와

자, 0.2를 UV 값에 더했습니다.
무슨 일이 일어났습니까?


으음? 그림이 살짝 옮겨졌습니다. 약간 왼쪽 위로 올라간 것 처럼 보이는군요.
덕분에 윗부분의 그림과 왼쪽 부분의 그림이 짤렸습니다.

근데 웃긴건, 그 짤린 이미지가 아래쪽과 오른쪽에 나타났다는 것이지요.
이게 뭔 일일까요?

이상하니, 상수의 값을 0.4로 올려 보겠습니다.
뭔가 이상할 때, Hybrid아저씨처럼 수학적 증명에 재주가 없을 때에는 조금씩 값을 변화시켜 보면서 규칙을 찾아 보는 것은 좋은 방법입니다. :)


그랬더니 응?
그림이 더 올라갔습니다.
마치 지금 화살표 방향으로 올라가는 것 처럼 말이지요.

그 이유를 한 번 생각해 보지요.
뭐 간단합니다. 벌써 아시는 분들도 326분쯤 계시군요.

그림은 여기에서부터 시작합니다. vertex는 구석에 있는 4 개만 일단 보지요.


아까 버텍스가 UV좌표를 가지고 있다고 했었지요?



여기에 각각의 vertex에다가 0.2를 더했으니까요.
이렇게 되었다는 겁니다. [각주:6]



0.4를 더한다면 이렇게 되는 거겠지요.


자, 이제 좀 이해가 되시겠지요? UV가 움직이는 이론도, 사실 아주 간단한 이론입니다.



그럼, 이번엔 곱하기는? 곱하기를 하면 어떻게 될까요?

자 숙제입니다.

아래 그림에 1.5를 곱해 보세요.

그리고 2도 곱해보세요.


미리 답보기 금지.















자, 푸셨나요?




정답 공개입니다. 아래와 같이 되겠지요?

엇 ...? 뭔가? 늘어났...?


2를 곱해보면 그럼 어떻게 되는 것일까요?

어엇? 2를 곱했더니, 풀 그림이 4개가 나왔습니다!

그도 그럴 것이, 곱하기는 0에다가 뭘 곱해도 0이고... 1을 곱하면 그대로고... 2를 곱하면 2배인 습성을 가진 아주 특이한 녀석이니까요. 게다가 소숫점을 곱하면 오히려 더 작은 숫자가 나오기까지 합니다. 이 나이 먹어서 곱하기에 감동을 하다니


자아, 그럼 우리 그래픽 디자이너 여러분, 특히 3D 그래픽 디자이너 여러분.
뭔가 깨닫는게 있지 않으신가요?

UV의 덧셈 (혹은 뺄셈) 은
여러분이 자주 쓰던 UV의 이동 (Offset) 과 같은 것이고,


UV의 곱셈 (혹은 잘 안쓰지만 나눗셈) 은
UV의 타일링 (Tiling)과 같은 것입니다.


자, 이해가 잘 가셨는지요?
정말 쉽지 않습니까?
정말 별거 아니지 않습니까?

멋지죠?


자 그럼 이 때쯤 되면 이제...

 

내 짤방은 내가 그린다,jpg







이 때쯤 되면 이런 질문을 하실 타이밍인것 맞습니다만...
확실히 지금은 float2에다가 그냥 한번에 숫자를 더하다 보니 동시에 움직이는게 맞지요. 그러다보니 대각선으로밖에 못 움직이고, 대각선으로 커지거나 작게 되는 수 밖에 없습니다.

이걸 따로따로 계산하려면, float2를 각 float 별로 따로따로 떼내어야 합니다.
이건 좀 귀찮으니까 나중에 하도록 하지요. 절대 제가 게으른게 아닙니다 .




4. 샘플러(Sampler)의 세계

이번엔 약간 간단한 겁니다.
위에서 본 그림에서 ....



요 그림을 보고 좀 이상하게 생각될 만한 거 있으셨나요?

아니, 이상하진 않겠구나... 늘 이렇게 봐 왔으니까요.

그럼, 그냥 곰곰히 생각해 봤을 때 "생각해 보니 뭐 이래?" 라는거 없었나요?



저는 저걸 봤을 때, "뭐야 UV가 1.0 넘어가니까 왜 또 그림이 반복되는건데?" 라고 생각했었습니다.
그리고 그게 나중에서야 샘플러 옵션에 그런게 있다는 것을 알게 되었지요.

바로 여기에요.

이렇게 , 샘플러를 선택하면 오른쪽에 옵션이 좌아악 펼쳐지게 됩니다.[각주:7]

일단 Mip Filter , Min Filter, Mag Filter 라고 하는 3가지 옵션이 있는데요.



이건 쉽게 말해서 '텍스쳐가 (화면에서 멀어져서 )줄어들거나 (화면에 가까이 다가와서 )커질때 각 텍스쳐의 이미지를 어떤 공식으로 크게 혹은 작게 다시 만들어주냐' 라는 옵션입니다.

Mip Filter 는 '밉맵[각주:8]을 처리할 때의 필터링 옵션' 이고,
Min Filter 는 '오브젝트가 화면에서 멀어져서, 작아보이게 되었을 때 텍스쳐의 처리방법' 이며
Mag Filter 는 '오브젝트가 화면에서 가까워져서, 커보이게 되었을 때 텍스쳐의 처리방법' 입니다.


필터의 옵션에는


대충 저런 것들이 있습니다.
물론 실제 사용되는건 저게 다가 아니예요. 좀 더 있습니다만..
일단 shaderFX 적용해도 실제로 맥스화면에서 볼 수가 없는게 문제입니다. (shaderFX가 3Dmax의 렌더링 엔진까지 건드리지는 않기 때문이지요 ) 그러므로 이걸로 제작해서, 나중에 게임 엔진에 넘겨서 봐야 볼 수 있다는게 문제지요.

그러므로 여기서는 이론만 공부하고 넘어가는 것으로 하겠습니다. 이게 눈에 들어오실 레벨이 된다면 그때 사용하셔도 상관없어요. (아 무책임하다...)

위에 얘기했듯 3Dmax에서는 볼 수가 없기 때문에, 이번에는 Unity 엔진을 켜고 엔진에서 간단하게 보도록 하겠습니다.


자 아래 그림을 보겠습니다.
원래 격자 텍스쳐가 2D 이미지로 존재하고 있던 것을, 3D 에 입힌 거지요.
그리고 그 3D 이미지가 기울어졌습니다. 졸지에 2D 이미지도 기울어지게 된 거지요.

이렇게 FOV가 있는 카메라에서 기울어지니까, 가까이 있는 부분의 격자는 원래의 격자보다 크게 보입니다.
그리고 멀리 있는 부분의 격자 그림은, 원래의 격자 그림보다 작게 보이게 될 것입니다. 뭐 당연하겠지요?

그렇다면 우리의 그래픽 카드는, 이 격자 그림을 '기울여서, 작게 혹은 크게' 보여주어야 할 타이밍입니다.
화면 가까운데 있으면 크게 보여줘야 겠고, 화면에서 멀리 있으면 작게 보여줘야 할겁니다.

이런 이미지의 각 '픽셀(Pixel)' 을 텍스쳐에 입히면, 구별하기 위해서 '텍셀(Texel)' 이라고 부른답니다.
벡셀(Bexel) 건전지와는 관계가 없어요


이게 Point 옵션을 사용했을때의 모습입니다. 멀리 있는 격자 텍셀들을 보세요. 안티알리아싱이 없는 것처럼 자글자글대지요?
이게 Point의 특징입니다. 이미지를 축소하거나 확대할 때, 그냥 옆 픽셀의 색 상관없이 무식하게 선택해 버려요. -_-;;
때문에 저렇게 타협없는 이미지가 나오게 됩니다 .


이게 리니어 (Linear) 혹은 바이리니어(Bilinear) 라고 불리는 옵션입니다.
이건 좀 바로 옆 텍셀이랑 타협한 티가 나지요? Point보단 살짝 부드럽습니다.

요건 필터링 옵션이 아니라... 밉멥(Mipmap) 을 사용하였을때 나오는 모습을 보여드리고 싶어서 만들어 봤습니다. 사실 이정도까지 구리게 나오지 않는데, 세부 옵션들을 무식하게 만져서 잘 보이도록 만들어 봤어요.
저 화살표 라인정도를 기점으로, 뒤에 있는 이미지는 뭔가 흐립니다. 저게 '작은 텍스쳐' 가 나타나는 기점이예요.
물론 잘 블렌딩 하고, 샘플링 (여기까지 되면 Trilinear 라고 합니다..) 되면 저건 더 자연스럽게 되지요. 단 , 좀 흐려지는건 어쩔 수 없뜸.


그래서 나온 궁극의 샘플링이 애니소트로픽(Anisotropic:비등방성 필터링) 샘플링 기법입니다. 이건 좀 쉽게 말하자면, 위치나 기울기까지 인식해서 주변의 텍셀 색을 샘플링해서 만들기 때문에, 기울어졌을때 아주 강력한 효과를 나타내며, 가장 정확하고 가장 무거운 샘플링 방법입니다.[각주:9]




그 다음에 볼 수 있는 AdressU와 AdressV ..

요건 딸랑 두 개 밖에 없네요? Clamp와 Wrap이라니...
여기서 Warp이 우리가 늘 봐 왔던 그것입니다. UV가 계속 , 영원히 타일링 되는 거지요.

*5 한 번 해봤뜸.




그에 반해 Clamp는, 이렇게 됩니다.
AdressU와 V를 모두 Clamp로 해 보았습니다.


호오... 마지막 텍셀의 색이 주욱 늘어나는군요?
네, 뭐 이런 것입니다. 이 외에도 Border나 Mirror 등의 옵션이 있습니다만,
개인적으로Mirror 외엔 써본적이 없어서 어디에 써야 할지 잘 모르겠군요 .[각주:10]
일반적으로는 wrap으로 사용되는 것이 보통이니, 그게 당연하다라고 생각하고 계셔도 큰 문제 없겠습니다. 단 , 수정 가능하다는 것 정도만 알아두세요.


이것이 Sampler의 옵션입니다. 사실 일반적으로 많이 쓰이는 옵션들은 아니고, ShaderFX 배우시는 동안에는 잊으셔도 상관 없는 옵션이라고 할 수 있겠습니다. 무엇보다 3Dmax 화면에서는 안보이거든요!!! [각주:11]

그러므로 사실 이 샘플러 부분은 그냥 이론 시간이라고 생각하시면 되겠습니다. 앞으로 강의 동안에는 사용하지 않겠습니다.

보이지도 않는걸 공부했다고 울고 불고 짜도 소용없습니다.


너무 억울해 하지 마세요.
그래도 Number of Mip Maps(밉맵의 갯수) 랑 Linear Gamma (감마 보정 옵션) 에 대해 설명 안한게 어디예요... [각주:12]



자, 이렇게 해서 조금 어려워진 '이론이 약간 가미된 shader FX 2부 강의의 첫 시간' 을 끝마치도록 하겠습니다.
다음 시간에 뭘 할까요...? 천천히 생각해 볼께요. 아유 힘들어 ...

아우 이론 나오니까 내가 힘들다.


다음 시간에는 UV를 한 방향으로 움직여 볼까...
그리고 UV를 칼라로 보기 해 볼까... (잊어버릴까봐 적어놓기)
  1. 3차원 텍스쳐라고 해서, UVW를 입히는 기술도 있습니다만 여기서 설명하지는 않겠습니다. 그리고... 왜 굳이 UVW라는 이름을 붙였냐면. XYZ와 헷갈리지 않게 하기 위해서 붙인 이름일 뿐입니다. -_- 사실은 XYZ랑 똑같은 겁니다. [본문으로]
  2. 다이렉트 X 에서는 지금 그림이 맞습니다 . 즉 게임에서는 지금 그림처럼 인식된다고 생각하시면 되지요. 하지만 OpenGL 등에서는 좀 다르게 UV를 정해놨는데요, 거기서는 지금 그림의 왼쪽 아래 점인 (0.0,1.0) 지점부터 시작합니다. 그리고 지금 그림을 보면, MAX도 그렇게 시작하는 것으로 보입니다. 물론 게임으로 넘길때 Exporter들이 알아서 컨버팅 해주니까 일반적으로는 크게 신경쓰시진 않아도 됩니다. [본문으로]
  3. 1.0 이상의 값이나 0.0 이하의 값은 없냐구요? 있지요 물론. 대신 그럴땐, 그 넘어가는 텍스쳐의 처리 옵션을 wrap이냐 clamp냐 등으로 처리해 놓은 것에 따라 다릅니다. 일반적으로는, 반복됩니다. 즉 2.0 도 1.0 으로 처리되는 거지요.(2.0, 2.0) = (1.0, 1.0) 뭐, 이건 나중에 또 얘기합시다. [본문으로]
  4. 빈 화면에서 오른쪽 클릭. 잊으셨습니까? [본문으로]
  5. 두 값을 모두 넣는 것이 정석이지만, 둘 중 하나만 넣어도 shaderFX에서는 알아서 자동으로 처리해 줍니다. [본문으로]
  6. 아! 그렇구나! 하시면서 3Dmax에서 Unwrap UVW를 열어보셔도, 저렇게 안되어 있습니다. 이건 맥스에서 고친게 아니라 shader에서 고친것이기 때문이지요 :) 즉 내부적으로만 '저런 모양으로 돌아간다' 라는걸 알려 드리도록 쓴 글이고, 실제 '맥스를 움직여 버리는' 것은 아닙니다. 맥스를 움직이는건 맥스 스크립트지요. :) [본문으로]
  7. 굳이 샘플러를 만들지 않아도, 원래 만들었던 Texture Map 옵션에도 동일한 옵션이 있습니다. 그러므로 샘플러 조작을 뭔가 계산해서 특이하게 만들 생각이 아니고 옵션만 조절해도 될 정도라면, 굳이 샘플러를 만들지 않아도 shaderFX에서는 충분합니다. [본문으로]
  8. Mipmap. dds 파일 포멧의 옵션에는, 텍스쳐가 입혀진 오브젝트가 멀리 떨어졌을때 작은 이미지의 텍스쳐로 전환하는 기능이 들어 있습니다. 이것을 밉맵(Mipmap) 이라고 합니다. [본문으로]
  9. http://gtgames.egloos.com/4777075 [본문으로]
  10. http://cafe.naver.com/tgedev.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=471&연결이 안된다면 네이버에서 "6. [Shader Study, HLSL 기본문법] 변수의 선언과 사용: Type -2" 을 검색. [본문으로]
  11. 제가 Filtering을 썼던 기억은... 이펙트를 날카롭게 보일 수 있도록 하기 위해서 이펙트 텍스쳐는 강제로 point로 조절되게 만들었었던 기억 뿐입니다. :) [본문으로]
  12. 감마 코렉션은 제가 예전에 트위터에서 질문 한 번 했다가 프로그래머 분들의 시간을 잔뜩 허비하게 만든 적이 있었던 바로 그 주제.. http://chulin28ho.egloos.com/5626565 [본문으로]
반응형
,