2011년 10월 10일
DX11 참 좋은데.. 정말 좋은데.. 글로 표현할 방법이 없네~
네 제목 그대로 입니다. 나름 개그스럽게 적었지만 개그 같지 않습니다. ㅋ DX11 튜토리얼에 수많은 주석질을 하고 해보았지만 이것에 대해 문서화해서 블로그에 올리기에는 확실히 빡센감이 있군요.

그래서 생각해 본게 요즘 학교 수업에서 OpenGL를 다루고 있는데 교수님이 워낙에 뛰어나셔셔 이것에 대한 체계적인 엔진(과는 아주 조금 비슷한)을 만들어가고 있습니다. 이제 기초부분이지만 하나하나씩 추가되고 있는 것이죠.

저의 목표는 이 OpenGL로 만들어지고 추가되는 부분들인 "3D 라이브러리 파일 및 응용 프로그램"을 DX11로 포팅하는 것입니다.

여러가지 변수가 있을 듯 하네요.

1. 지금 수업상에서의 제가 아는 바로는 OpenGL 자체적으로 수학 라이브러리를 지원을 하지 않기 때문에 교수님이 직접 만들어 놓으신 수학 라이브러리를 사용하고 있습니다. 결국 이것을 DX11에서 쓰이는 수학 라이브러리인 XNAMath로 사용하게끔 해야 함.

2. 당연한 얘기겠지만 OpenGL 자체의 렌더링 함수들을 전부 DX11에 맞게 바꿔야 함.
<디바이스 초기화부터 월드, 뷰, 프로젝션 변환 매트릭스 등등 이것들의 형태를 전부 변환해야 됨>

3. DX11은 고정 파이프라인은 지원하지 않으므로 셰이더 함수를 만들어야 함.

결론, OpenGL 및 Dx11 렌더링 구조를 둘다 파악해야 포팅 가능.

이것을 하나하나 추가하면서 DX11에 대한 설명을 부가적으로 올릴 예정입니다. 뭐 쉬울지 어려울지는 모르겠지만 할때까지 해볼려고요 ㅎㅎ.
by 프롬 | 2011/10/10 02:46 | 뻘글제조공간~ >.< | 트랙백 | 덧글(0)
2011년 10월 08일
연봉? 이것 하나에 열정마저 포기해야 하는가?
게임업계의 연봉은 대체적으로 낮다고 많이 알려져 있고 저 자신도 그것을 명백한 사실로 받아들이고 있습니다.

제가 많은 이들에게 게임 프로그래머가 되겠다고 선뜻 입밖으로 말하지 못하는 이유 중 하나가 바로 "연봉이 낮으니 다른 일을 하는것이 어떻겠냐?" 라는 소리를 듣기 싫어서 일지도 모르죠.

확실히 알고 있습니다. 다른(몇몇을 제외하고) 개발직 보다도 힘들고, 연봉은 낮고.. 그것을 알면서도 이 길을 간다고 하면 한심해 하는 사람들도 많습니다.

고3때 과를 선택할 시에도 막연히 게임 개발을 하고 싶다는 이유로 컴퓨터과학과에 들어왔고, 지금도 게임 개발과 관련된 과목만 상당부분 쫓아가며 듣고 있습니다.

하지만 이 일을 천직으로 생각하며 하고 싶은데도 연봉이란 부분 때문에 그 열정까지 포기하라는 소리를 들으면 정말 힘이 많이 빠집니다.
뭐 실제 우리나라의 현재 게임 개발자들의 현실도 문제이긴 하지만요.

결국 게임 개발을 꿈꾸었던 많은 사람들이 이 보수의 액수라는 벽 앞에서 자신의 꿈을 너무나도 쉽게 포기하고 다른길로 가버립니다.
최소한 자기만 가지 않으면 상관은 없을텐데 그것을 다른사람에게 까지 부추긴다는 게 더 큰 문제일지도 모르겠죠.

네이버에 "게임 프로그래머"만 검색해봐도 지식인에 수많은 학생들이 이 직업을 어떻게 하냐는 질문이 올라옵니다. 확실히 이들은 이것을 해보고 싶다는 막연한 기대감에서 글을 쓴것일지도 모르겠습니다. 하지만 실제 과연 이 학생들의 몇 퍼센트가 목표를 달성할까요? 저 또한 그런 기로에 놓였습니다.

게임 아카데미 다닐때쯤 하더라도 다들 열정이 뛰어난 친구들이 많았습니다. 돈 안 받아도 좋으니 게임 회사에 취직만 시켜달라고 하던 친구들도 있었을 정도였으니까요. 하지만 지금에 여기 오니 확실히 달라졌다는 것을 깨달은 지도 꽤 됬습니다. 보수에 따라 자신의 해야 할 일이 선택되고, 보수에 따라 자신이 원하는 길을 너무나도 쉽게 포기하는 지금의 현실이 슬플 뿐입니다.

요컨데 제가 내린 결론은 이렇습니다.
"꿈만 가지고 취직 하려는 것은 멍청한 짓이다. 초봉이 내 꿈을 결정하여 준다. 이것을 따르지 않는 사람은 확실히 바보 취급을 당해야 마땅하다."
우리나라에서만 이렇게 되었든 뭐가 되었든 제 개인적인 생각의 현실은 이런 것 같습니다. 어쩔 수가 없는 모양입니다.

그리고 전 이런 개 같은 룰을 한번 깨보고 싶습니다.

→ 개인적인 화를 참지 못하고 블로그에 나마 이런글을 한번 적어 봅니다. 다른사람 보라고 적은게 아닌 그냥 넋두리이니 덧글은 사양합니다.
충분히 논란의 여지가 될 수도 있습니다. 하지만 이건 그냥 개인적인 생각일 뿐입니다.

P.S 직업은 어찌보면 한 사람의 꿈이 될 수도 있습니다. 돈이 됬든 뭐가 됬든 자기 기준에 맞지 않는다고 함부로 말하지 맙시다.
by 프롬 | 2011/10/08 23:36 | 뻘글제조공간~ >.< | 트랙백
2011년 09월 23일
아~ 이 얼마만의 포스팅인가..
정말 오래간만의 포스팅입니다.

한참을 방치한 것 치고는 스팸댓글 이런거는 없네요. (뭐 이 블로그 인기가 없는지라 -ㅁ-)

아직까지도 취업을 하진 못하였지만 그렇다고 게임 개발 포기했나 뭐 이런거는 결코 아닙니다.

여러가지로 바쁜일도 많은 관계로 포스팅이 아주 다소 늦어지고 있죠 ㅎㅎ
( 사실 게으른 점도 아주 많이 있었습니다. 죄송합니다. ㅠㅠ )

DirectX 11이라.. 튜토리얼을 통해서 어느정도는 파악하였고, 다만 문서화의 벽이 크게 남아있습니다.

DX11은 우리나라 서적도 없을뿐더러 다른 전문가 분들의 개발관련 포스팅도 그닥 많지 않은 터라 그나마 알려주시는 개발자 님들 포스팅도 보고 있고 DirectX11 개발문서를 직접 레퍼런스해가며 공부하고 있습니다. 시간이 된다면 빨리 포스팅 해 보고 싶구요.

최근 Deferred Shading 및 MultiThread Render 부분에 대해서도 관심을 가지게 되었습니다.
멀티 코어의 시대이니 만큼 렌더링도 이 시대를 따라가는게 중요하다고나 할까요? ㅎㅎ
사실 이 부분이 크게 땡겼던 이유가 배틀필드3에서 이 기술을 사용했다고 하였기 때문이죠.
뭐 하지만 이 부분은 워낙에 어렵고 분량도 많기에 다소 시간이 걸리겠지만 반드시 이거 관련해서 포스팅을 해보고는 싶습니다.


그래도 지금의 가장 큰 적은 이 부분을 같이 연구 할 사람이 없다는 것 같습니다.

"클라이언트 게임 프로그래밍" "게임 엔진 프로그래밍" 이런 부분을 같이 할 사람(최소한 아마츄어들 중에는)은 일단 지금 제 주변에는 거의 전무한 상황입니다.

그렇다고 안할수도 없겠죠. 조금만 더 흥미를 가지고 배워보고 싶습니다.

- 적다보니 넋두리 비슷한게 되어버렸네요. 다음 포스팅때는 좋은 지식 올리도록 하겠습니다. ^^
by 프롬 | 2011/09/23 20:26 | 뻘글제조공간~ >.< | 트랙백 | 덧글(2)
2011년 05월 30일
최근근황.

요즘 하도 포스팅이 뜸한듯 해서 대놓고 뻘글을 작성합니다.~ -.-v

기말고사를 약 한주 정도 남기고 과제 및 프로젝트에 열을 올리고 있습니다.
< 변명아닌 변명입니다. ㅎㅎㅎㅎ;;; >

역시 과제들 분량이 분량인지라 블로그에 시간내기가 쉽지가 않네요.

덜자고 공부하면 될 것을.. 잠 덜자는 것도 아직은 무리가 있는듯 합니다. ^^a

그래도 이번 학기는 좋은 교수님들을 많이 만나뵈어서 예전에 비하면 많은 것들을 배웁니다.
< 정 반대의 위인들도 있지만. >

다음학기도 좋은 과목들이 많아서 기대가 되는군요. XNA나 위모트 등등 재밌는게 많을것 같습니다.
< 이 과목들이 사람적어서 폐강만 되지 않는다면야 ㅠ.ㅠ 영혼이라도 바쳐서 공부할 준비가 되있습니다.>

방학타임 찍짜마자 바로 블로그 및 운동, 외국어 공부 위주로 할 예정입니다.

이번 방학안에 다이렉트 X 11 부분을 (가능하다면) 많이 포스팅해보고 싶습니다.
< 그 전에 일단 그래픽 카드부터 요고 지원하는 걸로 바꾸고 싶다만 아직도 가난모드는 벗어나지 못했습니다. >

by 프롬 | 2011/05/30 14:39 | 뻘글제조공간~ >.< | 트랙백 | 덧글(2)
2011년 05월 11일
C++ 0x : lambda-03 → 람다의 응용

▣ 클래스 내에서 람다 사용하기

★ 클래스 내부의 멤버 함수 내에서 람다를 사용할 수 있다.

→ 여기서 this (자기 클래스에 대한 포인터)를 캡쳐하면 자기 클래스 내의 멤버 변수, 멤버 함수를 람다 내에서 모두 사용할 수 있다.
→ 클래스 내에서의 람다 식은 클래스에서 프렌드 함수로 인식하게 되므로 this 캡쳐시에 private 멤버까지 접근할 수 있다.

#include <stdio.h>
#include <vector>
#include <algorithm>
#include <functional>
 
class CCharacterList
{
private:
    std::vector<int> _viCharacterLevel;
    
    void PrintLevel( int nLevel )
    {
        printf( "Level : %d\n", nLevel );
    }
public:
    CCharacterList()
    {
        _viCharacterLevel.push_back( 1 );
        _viCharacterLevel.push_back( 54 );
        _viCharacterLevel.push_back( 99 );
    }
 
public:
    void PrintAll()
    {
        std::for_each( _viCharacterLevel.begin(), _viCharacterLevel.end(), 
            [this](int i){ PrintLevel(i); } );
    }
};
 
void main( void )
{
    CCharacterList *pcharacterlist = new CCharacterList;
    pcharacterlist->PrintAll();
    delete pcharacterlist;
}

→ for_each() 알고리즘은 컨테이너 내부의 모든 원소들에 대해 인수 3에 해당하는 펑터를 적용시킨다. (단, 컨테이너의 원소 값을 변경해서는 안 된다.)
클래스 내부 멤버함수 PrintAll()에서 for_each()를 호출하여 그곳의 세 번째 인수에 람다를 쓰고 있다.
람다 내부에서 private 멤버 함수인 PrintLevel()을 호출하는데 이것은 이 람다가 this를 캡쳐하였기 때문에 가능한 것이다.


★ 또한 람다를 클래스 내의 멤버 그 자체로 선언할 수도 있다.


: 이 때에는 auto를 쓰면 안되고, std::function을 써서 선언해야 하며, 선언하자 마자 바로 초기화가 불가능하며, 선언 이후 생성자 등의 멤버함수에서 람다를 정의해 주어야 한다.



class CCharacterList
{
private:
    std::vector<int> _viCharacterLevel;
    std::function<void(int)> _funcPrintOne;
    
    void PrintLevel( int nLevel )
    {
        printf( "Level : %d\n", nLevel );
    }
public:
    CCharacterList()
    {
        _viCharacterLevel.push_back( 1 );
        _viCharacterLevel.push_back( 54 );
        _viCharacterLevel.push_back( 99 );
        _funcPrintOne = [this](int i){ PrintLevel(i); };
    }
public:
    void PrintAll()
    {
        std::for_each( _viCharacterLevel.begin(), _viCharacterLevel.end(), _funcPrintOne );
    }
};

→ 여기에서도 this를 캡쳐하면 private 멤버까지 접근 가능하다.


 


▣ 람다를 STL 컨테이너에 저장하기


★ std::function을 이용한다면 람다를 STL 컨테이너에 통째로 담아버릴 수도 있다.



std::vector< std::function<int(void)> > vfuncInContainer;
                    
vfuncInContainer.push_back( []() -> int { return 100; } );
vfuncInContainer.push_back( []() -> int { return 200; } );
 
printf( "RetValue : %d\n", vfuncInContainer[0]() );
printf( "RetValue : %d\n", vfuncInContainer[1]() );

→ vfuncInContainer라는 STL vector 컨테이너 안에 람다를 넣어서 그 내부에서 호출하는 코드이다.


 


▣ 함수에서 인수 혹은 리턴 값으로 람다 사용



#include <stdio.h>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
 
void funcWithLambda( std::function<int(int, int)> func, int lhw, int rhw )
{
    printf( "Function Value = %d\n", func( lhw, rhw ) );
}
 
std::function< void() > funcWithRetLambda( void )
{
    std::string str("lambda!!!");
    return [=] { std::cout << "Hello, " << str << std::endl; };
}
 
void main( void )
{
    funcWithLambda( []( int a, int b )->int{ return a + b; }, 3, 5 );
 
    auto funcTemp = funcWithRetLambda();
    funcWithRetLambda()();
    funcTemp();
}

→ funcWithLambda()는 std::function에 대한 객체를 인수로 받는다.
즉, 람다 자체를 인수로 줄 수 있다는 이야기이고, funcWithLambda() 호출 시 람다 인수를 줄 때 매개변수에 명시된 리턴 값 및 람다의 매개변수의 타입을 동일하게 줘야 한다.


→ funcWithRetLambda()는 람다를 리턴 받는 함수인데 복사 캡쳐를 사용한 점을 주목하기 바란다.
함수 내에서의 지역변수는 함수 리턴 시 소멸되어 사용하면 안 되는 메모리 영역이 되어버린다. 만약 코드상의 캡쳐가 = 대신 &이었다면 차후 람다 호출 시 문제가 생길 공산이 매우 크다. (당장에는 문제가 안 생길수도 있지만 아주 위험하다. 없어져버린 변수를 참조하고 있기 때문이다.)
: 그러므로 함수 내 람다 리턴 시 캡쳐가 필요할 때는 (지역변수에 대해서는) 꼭 복사 캡쳐를 사용하기 바란다.
: 포인터 캡쳐의 경우에도 잘 판단해야 한다. 만약 함수 내에서 선언한 포인터가 해당 함수의 지역변수를 가리키고 있다면, (즉, 함수가 리턴되면 사라져 버리는 변수들) 그 포인터는 캡쳐해서는 안될 것이다. 꼭 주의해서 캡쳐하도록 하자.


 


▣ 람다에서의 재귀호출


★ 일반 함수에서도 재귀호출이 가능하듯이 람다에서도 재귀호출이 가능하다. 단, 재귀호출로 람다를 작성시 반드시 std::function으로 써야 한다.
(auto는 안된다.)


→ 재귀호출의 상징적 함수인 팩토리얼을 예로 들어보겠다.



std::function<int(int)> funcFactorial = 
[&funcFactorial](int x) -> int
{
    return x == 0 ? 1 : x * funcFactorial(x - 1);
};
 
int Value = 5;
printf( "Factorial(%d) = %d\n", Value, funcFactorial( Value ) );

→ 자기 자신에 대한 객체 (funcFactorial)의 참조를 캡쳐하여 재귀호출하고 있다.


 


▣ 람다 (혹은 람다의 배열)에 대한 포인터


★ 람다는 std::function 타입으로 볼 때, 템플릿 클래스이다.
즉, 객체를 만들 수 있기 때문에 뒷장에서 해왔던 람다를 매개변수, 리턴 값, 클래스 멤버 변수, 컨테이너 원소 등으로 쓸 수 있게 되는 것이다.
그에 따라서 람다를 std::function으로 쓴다고 한다면 이걸로 배열도 만들 수 있고, 이것에 대한 포인터 또한 선언 가능하다.
< 참고로 std::function으로 만들어진 객체의 크기는 sizeof() 확인 결과 24바이트였다. (상황에 따라 틀릴지도 있습니다.) >



std::function<int(void)> *pfuncPtr = new std::function<int(void)>[3];
pfuncPtr[0] = []() -> int { return 100; };
pfuncPtr[1] = []() -> int { return 200; };
pfuncPtr[2] = []() -> int { return 300; };
 
for ( int i = 0; i < 3; i++ )
{
    printf( "pfuncPtr[%d]() => %d\n", i, pfuncPtr[i]() );
}
 
delete []pfuncPtr;

→ std::function 객체에 대한 포인터를 선언하고 3개 요소에 대한 공간을 new로 할당 받아서 사용하는 코드이다.
→ 결국 람다의 포인터를 사용할 수 있음으로써 이것 또한 힙 영역에서 관리가 가능하다는 것을 파악할 수 있다.


 


▷ 결국 람다 부분까지 마무리 하고 말았습니다. 이것으로 C++ 0x부분에 대한 포스팅은 마치겠습니다.
STL 알고리즘에서는 확실히 펑터 사용하기가 귀찮죠. 이것을 쓴다면 보다 더 쉽게 알고리즘들을 사용할 수 있을 것 같습니다.
( 많이 쓰일 수만 있다면 참 좋겠지만 아직 C++ 0x 자체가 대중화가 덜 되었다 보니 ㅠㅠ )

다음은 무엇을 포스팅 할까 하다가 역시나 DirectX 11 부분을 포스팅 하는 걸로 잠정 확정된 것 같습니다.
DirectX9 조차 포스팅을 안 했는데 감히 11을 포스팅 하는 게 다소 난해할 수도 있겠다만 어떻게든 배워서 열심히 올려 볼렵니다. 언젠가는 다들 쓸지도 모르니깐요.


※ 참고자료 출처 : Microsoft Visual Studio 「Visual C++ 10과 C++0x」 ( 최흥배님 저 )

by 프롬 | 2011/05/11 13:39 | Story Of C++ | 트랙백 | 덧글(2)


<< 이전 페이지 | 다음 페이지 >>