포스트

[ Dx11 ] (solution) Motion Blur 코드 최적화

문제


기존 코드는 pd3dDevice에 만들 물체의 개수만큼 buffer를 생성하여 순차적으로 그린다. 이는 모델이 추가될 때마다 코드 수정이 많이 필요하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
ID3D11Buffer* g_pcbVSPerObject_1 = NULL;
ID3D11Buffer* g_pcbVSPerObject_2 = NULL;
ID3D11Buffer* g_pcbVSPerFrame_1 = NULL;
ID3D11Buffer* g_pcbVSPerFrame_2 = NULL;
Animation* g_pModel_1 = NULL;
Animation* g_pModel_2 = NULL;
ID3D11ShaderResourceView* g_pTextures_1 = NULL;
ID3D11ShaderResourceView* g_pTextures_2 = NULL;
...

//--------------------------------------------------------------------------------------
// Create any D3D resources that aren't dependant on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11CreateDevice(ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,void* pUserContext)
{
    HRESULT hr = S_OK;

    auto pd3dImmediateContext = DXUTGetD3D11DeviceContext();
    V_RETURN(g_DialogResourceManager.OnD3D11CreateDevice(pd3dDevice, pd3dImmediateContext));
    V_RETURN(g_D3DSettingsDlg.OnD3D11CreateDevice(pd3dDevice));
    g_pTxtHelper = new CDXUTTextHelper(pd3dDevice, pd3dImmediateContext, &g_DialogResourceManager, 15);

    // Compile and create the effect.
    DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
    dwShaderFlags |= D3DCOMPILE_DEBUG;
    dwShaderFlags |= D3DCOMPILE_SKIP_OPTIMIZATION;

    hr = D3DX11CompileFromFile(L"DynamicShaderLinkageFX11.fx", 0, 0, 0, "fx_5_0", dwShaderFlags, 0, 0, &effectBlob, &errorsBlob, 0);

    if (errorsBlob)
    {
        MessageBoxA(0, (char*)errorsBlob->GetBufferPointer(), 0, 0);
        errorsBlob->Release();
    }

    hr = D3DX11CreateEffectFromMemory(effectBlob->GetBufferPointer(), effectBlob->GetBufferSize(), 0, pd3dDevice, &g_pEffect);
    assert(SUCCEEDED(hr));
    effectBlob->Release();
    
    g_pTextureClear_Tech = g_pEffect->GetTechniqueByName("TextureClear");
    g_pStencilBufferClear_Tech = g_pEffect->GetTechniqueByName("StencilBufferClear");
    g_pRendering_Tech = g_pEffect->GetTechniqueByName("Rendering");
    g_motionVectorMomentMap_Rendering_Tech = g_pEffect->GetTechniqueByName("motionVectorMomentMap_Rendering");
    g_pSorting_Tech = g_pEffect->GetTechniqueByName("Sorting");
    g_pMakeMotionBlur_Tech = g_pEffect->GetTechniqueByName("MakeMotionBlur");
    g_pDenoising_Tech = g_pEffect->GetTechniqueByName("Denoising");

    D3DX11_PASS_DESC passDesc;
    g_pRendering_Tech->GetPassByIndex(0)->GetDesc(&passDesc);

    const D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
        { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };

    V_RETURN(pd3dDevice->CreateInputLayout(layout, ARRAYSIZE(layout), passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &g_pLayout));

    // Create constant buffers of Main Object 1
    D3D11_BUFFER_DESC cbDesc_1;
    ZeroMemory(&cbDesc_1, sizeof(cbDesc_1));
    cbDesc_1.Usage = D3D11_USAGE_DYNAMIC;
    cbDesc_1.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    cbDesc_1.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    cbDesc_1.ByteWidth = sizeof(CB_VS_PER_OBJECT);
    V_RETURN(pd3dDevice->CreateBuffer(&cbDesc_1, NULL, &g_pcbVSPerObject_1));
    DXUT_SetDebugName(g_pcbVSPerObject_1, "CB_VS_PER_OBJECT");
    cbDesc_1.ByteWidth = sizeof(CB_VS_PER_Frame);
    V_RETURN(pd3dDevice->CreateBuffer(&cbDesc_1, NULL, &g_pcbVSPerFrame_1));
    DXUT_SetDebugName(g_pcbVSPerFrame_1, "CB_VS_PER_FRAME");

    // Create constant buffers of Main Object 2
    D3D11_BUFFER_DESC cbDesc_2;
    ZeroMemory(&cbDesc_2, sizeof(cbDesc_2));
    cbDesc_2.Usage = D3D11_USAGE_DYNAMIC;
    cbDesc_2.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    cbDesc_2.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    cbDesc_2.ByteWidth = sizeof(CB_VS_PER_OBJECT);
    V_RETURN(pd3dDevice->CreateBuffer(&cbDesc_2, NULL, &g_pcbVSPerObject_2));
    DXUT_SetDebugName(g_pcbVSPerObject_2, "CB_VS_PER_OBJECT");
    cbDesc_2.ByteWidth = sizeof(CB_VS_PER_Frame);
    V_RETURN(pd3dDevice->CreateBuffer(&cbDesc_2, NULL, &g_pcbVSPerFrame_2));
    DXUT_SetDebugName(g_pcbVSPerFrame_2, "CB_VS_PER_FRAME");

    LoadModels(pd3dDevice);
    LoadTextures(pd3dDevice, pd3dImmediateContext);
}


void LoadModels(ID3D11Device* pd3dDevice)
{
    g_pModel_1 = new Animation();
    g_pModel_2 = new Animation();
    g_pModel_1->LoadMesh("./models/Sphere/sphere.x", pd3dDevice);
    g_pModel_2->LoadMesh("./models/sphere/sphere.x", pd3dDevice);
}

HRESULT LoadTextures(ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext)
{
    HRESULT hr = S_OK;
    V_RETURN(DXUTCreateShaderResourceViewFromFile(pd3dDevice, L"./models/Sphere/billiard13.jpg", &g_pTextures_1));
    V_RETURN(DXUTCreateShaderResourceViewFromFile(pd3dDevice, L"./models/Sphere/red.jpg", &g_pTextures_2));
}


void RenderObject(ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, ID3DX11EffectTechnique* pTech)
{
    // Prepare for Motion of object
    const XMMATRIX mView = g_Camera.GetViewMatrix();
    const XMMATRIX mProj = g_Camera.GetProjMatrix();
    const XMMATRIX scale = XMMatrixScaling(3.5f, 3.0f, 3.0f);

    const XMMATRIX translation1 = XMMatrixTranslation(movePos_1.x, movePos_1.y, movePos_1.z);
    const XMMATRIX mWorld1 = scale * translation1;
    g_WVP_1b = mWorld1 * mView * mProj;
    SetEffect(g_WVP_1b, g_pTextures_1, g_mPreProjectionMatrix1);
    RenderObject(g_pModel_1, pd3dImmediateContext, g_pLayout, pTech);

    const XMMATRIX translation2 = XMMatrixTranslation(movePos_2.x, movePos_2.y, movePos_2.z);
    const XMMATRIX mWorld2 = scale * translation2;
    g_WVP_2b = mWorld2 * mView * mProj;
    SetEffect(g_WVP_2b, g_pTextures_2, g_mPreProjectionMatrix2);
    RenderObject(g_pModel_2, pd3dImmediateContext, g_pLayout, pTech);
}

그리고 렌더링이 1번 진행될 때는 괜찮으나, 여러 번 진행 시 매트릭스가 여러 번 업데이트되어 오류가 발생하기 쉽다.


해결


RenderObject Class로 그룹을 생성,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class RenderObject: public Model
{
public:
	RenderObject();
	RenderObject(const RenderObject&);

	float SetMovePosition(float sphereMovePosition, float displacement, float startPoint, float destinationPoint);
	void BeforeFrameRender(XMMATRIX viewMatrix, XMMATRIX projectionMatrix, float scale, float xPos, float yPos, float zPos);
	void AfterFrameRender();
	void Render(ID3D11DeviceContext* pd3dImmediateContext, ID3D11InputLayout* g_pLayout, ID3DX11EffectTechnique* g_pTech, D3DX11_TECHNIQUE_DESC techDesc, ID3DX11Effect* g_pEffect);
	void RenderFSQ(ID3D11DeviceContext* pd3dImmediateContext, ID3D11InputLayout* g_pLayout, ID3DX11EffectTechnique* g_pTech, D3DX11_TECHNIQUE_DESC techDesc, ID3DX11Effect* g_pEffect);

	void RenderSkybox(ID3D11DeviceContext* pd3dImmediateContext, ID3D11InputLayout* g_pLayout, ID3DX11EffectTechnique* g_pTech, D3DX11_TECHNIQUE_DESC techDesc, ID3DX11Effect* g_pEffect);
	void BeforeFrameRenderSkybox(XMMATRIX viewMatrix, XMMATRIX projectionMatrix, float scale, float xPos, float yPos, float zPos);


	XMMATRIX m_scale;
	XMMATRIX m_rotation;
	XMMATRIX m_world;
	XMMATRIX m_worldView;
	XMMATRIX m_worldViewProjection;
	XMMATRIX m_previousWVP;
	XMMATRIX m_translation;

	ID3DX11EffectMatrixVariable* m_effect_worldViewProjection = NULL;
	ID3DX11EffectMatrixVariable* m_effect_PreviousWVP = NULL;
	ID3DX11EffectShaderResourceVariable* m_effect_texture = NULL;

	ID3DX11EffectMatrixVariable* m_effect_world = NULL;

	float xPos, yPos, zPos;

};


void RenderObject::BeforeFrameRender(XMMATRIX viewMatrix, XMMATRIX projectionMatrix, float scale, float xPos, float yPos, float zPos)
{
	m_translation = XMMatrixTranslation(xPos, yPos, zPos);
	m_scale = XMMatrixScaling(scale, scale, scale);
	m_rotation = XMMatrixRotationY(XMConvertToRadians(0.f));
	m_world = m_scale * m_translation;
	m_worldView = m_world * viewMatrix;
	m_worldViewProjection = m_world * viewMatrix * projectionMatrix;
}

void RenderObject::AfterFrameRender()
{
	m_previousWVP = m_worldViewProjection;
}


void RenderObject::Render(ID3D11DeviceContext* pd3dImmediateContext, ID3D11InputLayout* g_pLayout, ID3DX11EffectTechnique* g_pTech, D3DX11_TECHNIQUE_DESC techDesc, ID3DX11Effect* g_pEffect)
{
	m_effect_worldViewProjection = g_pEffect->GetVariableByName("g_worldViewProjection")->AsMatrix();
	m_effect_PreviousWVP = g_pEffect->GetVariableByName("g_previousWorldViewProjection")->AsMatrix();
	m_effect_texture = g_pEffect->GetVariableByName("g_modelTexture")->AsShaderResource();

	m_effect_world = g_pEffect->GetVariableByName("g_world")->AsMatrix();

	XMFLOAT4X4 tmp4x4;
	XMStoreFloat4x4(&tmp4x4, m_worldViewProjection);
	m_effect_worldViewProjection->SetMatrix(reinterpret_cast<float*>(&tmp4x4));
	XMStoreFloat4x4(&tmp4x4, m_previousWVP);
	m_effect_PreviousWVP->SetMatrix(reinterpret_cast<float*>(&tmp4x4));

	XMStoreFloat4x4(&tmp4x4, m_world);
	m_effect_world->SetMatrix(reinterpret_cast<float*>(&tmp4x4));

	g_pTech->GetDesc(&techDesc);
	pd3dImmediateContext->IASetInputLayout(g_pLayout);
	Draw(m_effect_texture, g_pTech, techDesc , pd3dImmediateContext, g_pLayout);
}


객체 별 렌더링을 구현,

rendering pass 전에 매트릭스를 생성, pass가 완료되면 현재의 WVP가 previousWVP로 업데이트 된다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.