ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [28] - Bindable/Drawable System - 2
    Graphics 2021. 8. 2. 14:30

    (28) C++ 3D DirectX Tutorial [Bindable / Drawable System Part 2] - YouTube

    planetchili/hw3d at T21.2-End (github.com)

     

    GitHub - planetchili/hw3d: C++ 3D graphics engine under Direct3D 11. Developed in a Planet Chili video tutorial series that can

    C++ 3D graphics engine under Direct3D 11. Developed in a Planet Chili video tutorial series that can be found on YouTube. https://youtu.be/_4FArgOX1I4 - GitHub - planetchili/hw3d: C++ 3D graphics e...

    github.com

    바로 직전에 대충 80개 정도의 상자를 화면에 출력하도록 만들었습니다. 한 가지 아쉬운 점이 있는데 그것은 바로 Box라는 완전히 같은 인스턴스 80개를 만들어 낭비가 심했다는 겁니다. 완전히 같은 Mesh는 위치나 움직임에 대한 요소를 제외하면 완전히 같은 성질을 공유합니다. 따라서 박스 인스턴스 간에 자원을 공유하게 만든다면 효율적인 코드를 만들 수 있을 것입니다. 정확히 무엇을 공유하면 좋겠느냐, 박스 간에 공통된 Bindable을 공유하면 좋은 것입니다. 대체 어떻게 같은 Class로부터 생성된 인스턴스들이 자원을 공유할 수 있는지 알고 싶습니다. 다행히 'Static'이라는 선택지가 있으며 실제로 이것을 사용하게 될 것입니다. 여기서 드는 의문은 static variables을 어떻게 그리고 어디에 두느냐는 것입니다.

    Drawable과 Box의 상속 관계 사이에 어떤 Class를 생성하게 될 것입니다. 이 Class는 Class template이며 DrawableBase<T>로 이름을 붙일 예정입니다. 어떤 Object를 출력하기 위해서는 반드시 DrawableBase에서 상속을 받아야 하고 이 Class에 같은 Objects 간에 공유할 자원을 Static으로 선언해 둘 것입니다. 따라서 Box가 아닌 가령 Spear나 Pyramid, Ellipse 따위의 Objects를 생성한다고 하더라도 공유할 자원을 일일이 복사/붙어 넣기를 하지 않더라도 Compiler가 우리를 대신해서 수행하게 만들 수 있습니다. 그럼 여기서 또 발생할 수 있는 문제는 생성할 다른 Mesh들 마다 각각 다른 template를 넣어 주어야 하는 것입니다. 실제 DrawableBase Class를 보면서 이해를 하면 빠릅니다.

    class template이라는 사실을 확인할 수 있고 Drawable로부터 상속을 받습니다.
    그리고 static vector의 모습입니다.

    당연히 static member staticBinds는 scope 밖에서 한 번 선언이 되어야 합니다.

    어떤 상자라는 똑같은 Objects를 하나 이상 만든다고 가정해봅시다. 첫 번째 상자와 두 번째 그리고 n번째 상자 모두 같은 DrawableBase의 Static member인 staticBinds를 공유합니다. 따라서 가장 먼저 생성된 상자가 한 번 staticBinds를 initialise하면 두 번째부터는 또 초기화를 진행할 필요가 없습니다. 바로 그 포인트를 점검하는 함수입니다. 완전무결한 방법은 아니지만 당장은 작동을 잘 할 것입니다. 그리고 다음 함수가 이 파트에서 가장 까다로운 부분입니다.

    이 부분을 이해하기 전에 Drawable Class에 가해진 변화에 주목해봅니다. 가장 먼저 눈에 띄는 것은 Drawable class가 DrawableBase의 Friend class로 선언이 되어 있다는 점입니다. 따라서 DrawableBase는 Drawable의 Internal Data에 접근할 수 있는 권한을 갖게 됩니다. (About Friend Class)

     더불어서 Drawable에는 위와 같은 순수 가상 함수가 선언되어 있습니다. Drawable의 Childern들인 DrawableBase가 서로 다른 Mesh들을 생성하기 위해 만들어지면 공유할 자원(Bindable)이 들어있는 벡터가 생성됩니다. 그리고 Drawable에서 벡터 안의 요소들을 파이프 라인에 Bind하기 위해서는 모든 Children들이 Bind할 수 있는 함수가 필요합니다.

    그래서 Draw함수에 개별 Bindable 뿐만 아니라 static Bindable도 파이프 라인에 bind할 수 있도록 코드가 추가되어 있습니다. 그러면 어떻게 Mesh를 만들 수 있는지 Box를 확인해봅니다. 기존 Drawable과 Box와 같은 Object 사이에 DrawableBase라는 새로운 class를 만들고 이 class에 static vector container를 만들어 같은 Objects 사이에 공유할 수 있는 자원(bindable)은 최대한 공유하기로 했습니다. 문제는 이 class를 class template로 만들었다는 것인데 단순히 template를 다음과 같이 사용하는 것으로 잘 작동한다는 사실을 알 수 있습니다. 

    이것이 Box class의 Ctor[Constructor]입니다. mt19937은 무작위 난수 생성을 위한 효과적인 라이브러리에 불과합니다. 이렇게 생성한 난수를 바탕으로 상자의 위치와 여타 속성을 결정합니다. 포인트는 class Box : public DrawableBase<Box>라는 선언으로도 충분히 코드를 유효하게 사용할 수 있었다는 점입니다. 만약 다른 Mesh를 만든다고 하면 가령 Pyramid의 경우에는 class Pyramid : public DrawableBase<Pyramid>처럼 사용할 수가 있다는 뜻입니다. 

    그런데 한 가지 짚고 넘어가야 할 부분이 있습니다. 다음 코드는 Box의 Ctor입니다. 위에서 언급했던 것처럼 만약 이 Object가 처음 생성되는 것이 아니라면 처음부터 전부 Setup을 진행합니다. 그런데 단 한 가지, Static한 요소가 아닌 것이 있는데 그것은 Constant Buffer입니다.

    마지막 AddBind는 static이 아닙니다. TransformCbuf라는 상수 버퍼를 파이프 라인에 Binding하는 모습입니다. 당연한 것입니다. 각 상자는 상자마다 다른 Transform을 갖고 있을 테니까요. 여기서 마무리를 지을 수가 없습니다. else 부분에 SetIndexFromStatic();이 왜 존재하는지 알아야 합니다.

    바로 위의 코드에서 한 번만 Initialise하는 부분이 존재했습니다. 실제로 우리가 원하는 기능이었습니다. 그런데 해당 Scope에서 우리가 원하는 바가 아닌 요소가 딱 하나 존재합니다. 바로 AddStaticIndexBuffer입니다.

    첫 Box object는 모든 static 요소를 초기화하며 생성되기 때문에 문제 없이 동작합니다. 그러나, 두 번째 instance를 만들기 시작하면 이 함수를 호출하지 않습니다. 첫 번째 Box에 대한 index pointer는 static Binds를 통해서 파이프 라인에 잘 전달이 되었으나 두 번째 Box부터는 위의 함수를 호출하지 않기 때문에 index buffer pointer가 nullptr를 가리키고 있어서 정의되지 않은 행동이나 오류를 만들어 냅니다. 문제는 Static Bindable Buffer에는 Bindable 요소들이 들어있기는 하지만 우리 입장에서는 어떤 것이 정확히 Index Buffer인지 알 방법이 없습니다. 그래서 index buffer pointer를 Setup 할 수 있는 방법을 강구해야 합니다. 그래서 아래와 같은 코드가 필요하게 된 것입니다.

    static bindable vector의 bindable을 dynamic cast해서 index buffer를 setup하는 모습입니다. 

     

Designed by Tistory.