πŸ“˜ Direct3D Tutorial7

파인·2022λ…„ 2μ›” 11일
0

Directx

λͺ©λ‘ 보기
7/8
post-thumbnail

https://docs.microsoft.com/en-us/previous-versions//ff729724(v=vs.85)?redirectedfrom=MSDN

μœ„ λ‚΄μš©μ„ μ°Έκ³ ν•˜μ—¬ μ •λ¦¬ν•œ λ‚΄μš©μž…λ‹ˆλ‹€.

Tutorial7 : ν…μŠ€μ²˜ 맀핑


πŸ“Œ Texture Mapping

ν…μŠ€μ²˜ 맀핑은 2D 이미지λ₯Ό 3D ν˜•μƒμ— νˆ¬μ˜ν•˜λŠ” 것을 λ§ν•œλ‹€. 그리기 μœ„ν•΄μ„œλŠ” ν‘œλ©΄μ˜ 점듀이 2D 이미지와 μ–΄λ–»κ²Œ λŒ€μ‘λ˜λŠ”μ§€ λͺ…μ‹œν•΄μ•Ό ν•œλ‹€.

이번 νŠœν† λ¦¬μ–Όμ˜ μ˜ˆμ‹œμ—μ„œλŠ” 정점에 μ˜ν•΄ ν…μŠ€μ²˜ μ’Œν‘œκ°€ κ²°μ •λ˜λ©°, λ³΄κ°„λœλ‹€.


πŸ“Œ Creating a Shader Resource from the Texture and Sampler State

ν…μŠ€μ²˜λŠ” 셰이더 λ¦¬μ†ŒμŠ€ λ·°λ₯Ό λ§Œλ“œλŠ” 데 μ‚¬μš©λ˜λŠ” 2D 이미지이닀.

hr = D3DX11CreateShaderResourceViewFromFile( g_pd3dDevice, L"seafloor.dds", NULL, NULL, 
         &g_pTextureRV, NULL );

셰이더가 필터링(filtering), addressing λ“±μ˜ 방식을 μ œμ–΄ν•˜λŠ” sampler stateλ₯Ό λ§Œλ“€μ–΄μ•Ό ν•œλ‹€. ν…μŠ€μ³ addressing은 UVμ’Œν‘œκ°€ 0κ³Ό 1 사이가 μ•„λ‹Œ λ‹€λ₯Έ 값이 λ˜μ—ˆμ„ λ•Œ, μ–΄λ–»κ²Œ ν‘œν˜„λ  것인 지λ₯Ό κ²°μ •ν•˜λŠ” μ˜΅μ…˜μ΄λ‹€.
sampler stateλ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ D3D11Device::CreateSamplerState()λ₯Ό ν˜ΈμΆœν•œλ‹€.

    // Create the sample state
    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory( &sampDesc, sizeof(sampDesc) );
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
    hr = g_pd3dDevice->CreateSamplerState( &sampDesc, &g_pSamplerLinear );

πŸ“Œ Defining the Coordinates (μ’Œν‘œκ³„ μ •μ˜ν•˜κΈ°)

이미지λ₯Ό νλΈŒμ— λ§€ν•‘ν•˜κΈ° 전에 λ¨Όμ € 큐브의 각 정점에 ν…μŠ€μ²˜ μ’Œν‘œλ₯Ό μ •μ˜ν•΄μ•Ό ν•œλ‹€. μ‚¬μš©λœ μ’Œν‘œκ³„λŠ” [0, 1]둜 ν‘œμ€€ν™” λ˜μ—ˆλ‹€. (ν…μŠ€μ²˜μ˜ μ™Όμͺ½ 상단 λͺ¨μ„œλ¦¬λŠ” (0,0), 였λ₯Έμͺ½ ν•˜λ‹¨ λͺ¨μ„œλ¦¬λŠ” (1,1))

λ¨Όμ € 정점을 μ •μ˜ν•  λ•Œ ν…μŠ€μ²˜ μ’Œν‘œλ₯Ό ν¬ν•¨μ‹œμΌœ μ£Όμ—ˆλ‹€.

struct SimpleVertex
{
    XMFLOAT3 Pos;
    XMFLOAT2 Tex;
};

그런 λ‹€μŒ 셰이더에 input layout도 μ—…λ°μ΄νŠΈν•˜μ—¬ ν¬ν•¨μ‹œμΌœμ£Όμ—ˆλ‹€.

// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

input layout이 λ³€κ²½λ˜μ—ˆμœΌλ―€λ‘œ ν•΄λ‹Ή 정점 셰이더 μž…λ ₯도 μΌμΉ˜ν•˜λ„λ‘ μˆ˜μ •ν•΄μ•Ό ν•œλ‹€.

struct VS_INPUT
{
    float4 Pos : POSITION;
    float2 Tex : TEXCOORD;
};

λ§ˆμ§€λ§‰μœΌλ‘œ 정점에 λŒ€μ‘λ˜λŠ” ν…μŠ€μ²˜ μ’Œν‘œλ₯Ό μž…λ ₯ν•΄μ€€λ‹€. 큐브의 각 꼭지점은 ν…μŠ€μ²˜μ˜ λͺ¨μ„œλ¦¬μ— ν•΄λ‹Ήν•œλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 각 꼭짓점이 (0,0) (0,1) (1,0) λ˜λŠ” (1,1)을 μ’Œν‘œλ‘œ κ°–λŠ” λ‹¨μˆœ 맀핑이 λ§Œλ“€μ–΄μ§‘λ‹ˆλ‹€.

// Create vertex buffer
SimpleVertex vertices[] =
{
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ) },

    { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) },
    { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) },
    { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) },
};

πŸ“Œ Bind Texture as Shader Resource (ν…μŠ€μ²˜λ₯Ό 셰이더 λ¦¬μ†ŒμŠ€λ‘œ 바인딩)

ν…μŠ€μ²˜μ™€ sampler stateλŠ” 이전 νŠœν† λ¦¬μ–Όμ—μ„œ μ‚΄νŽ΄λ³Έ Constant와 같은 객체이닀. 셰이더가 μ‚¬μš©ν•˜κΈ° 전에 ID3D11DeviceContext::PSSetSamplers(), ID3D11DeviceContext::PSSetShaderResources() 등을 ν˜ΈμΆœν•΄μ£Όμ–΄μ•Ό ν•œλ‹€.

    g_pImmediateContext->PSSetShaderResources( 0, 1, &g_pTextureRV );
    g_pImmediateContext->PSSetSamplers( 0, 1, &g_pSamplerLinear );

μ΄λ ‡κ²Œ ν•˜λ©΄ μ…°μ΄λ”μ—μ„œ ν…μŠ€μ²˜λ₯Ό μ‚¬μš©ν•  μ€€λΉ„κ°€ λλ‚œλ‹€.


πŸ“Œ Applying the Texture (ν…μŠ€μ²˜ μ μš©ν•˜κΈ°)

ν…μŠ€μ²˜λ₯Ό λ§€ν•‘ν•˜κΈ° μœ„ν•΄ ν”½μ…€ μ…°μ΄λ”μ—μ„œ texture lookup function을 ν˜ΈμΆœν•œλ‹€. 2D ν…μŠ€μ²˜λ₯Ό μ‘°νšŒν•œ λ‹€μŒ μƒ˜ν”Œ 색상을 λ°˜ν™˜ν•œλ‹€.

μ•„λž˜ ν”½μ…€ μ…°μ΄λ”λŠ” 이 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ λ©”μ‹œ 색상(λ˜λŠ” 머터리얼 색상)으둜 κ³±ν•œ λ‹€μŒ μ΅œμ’… 색상을 좜λ ₯ν•œλ‹€.

  • txDiffuse : μš°λ¦¬κ°€ λ¦¬μ†ŒμŠ€λ·° g_pTextureRVλ₯Ό 바인딩할 λ•Œ μ „λ‹¬λœ ν…μŠ€μ²˜λ₯Ό μ €μž₯ν•˜λŠ” 객체
// Pixel Shader
float4 PS( PS_INPUT input) : SV_Target
{
    return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}

정점 셰이더λ₯Ό 톡해 ν…μŠ€μ²˜ μ’Œν‘œλ₯Ό 전달해야 ν•œλ‹€.

// Vertex Shader
PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Tex = input.Tex;
        
    return output;
}

πŸ“Œ Constant Buffers (μƒμˆ˜ 버퍼)

Direct3D 11μ—μ„œ Constant Bufferλ₯Ό μ‚¬μš©ν•˜μ—¬ 셰이더 μƒμˆ˜(셰이더 λ³€μˆ˜)λ₯Ό μ„€μ •ν•  수 μžˆλ‹€. Constant BufferλŠ” 셰이더 μƒμˆ˜λ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ”λ° ν•„μš”ν•œ bandwidthλ₯Ό 쀄인닀.

이전 νŠœν† λ¦¬μ–Όμ—μ„œλŠ” ν•˜λ‚˜μ˜ Constant Bufferλ₯Ό μ΄μš©ν•˜μ—¬ ν•„μš”ν•œ λͺ¨λ“  셰이더 μƒμˆ˜λ₯Ό λ³΄κ΄€ν–ˆλ‹€. κ·ΈλŸ¬λ‚˜ Constant Bufferλ₯Ό 효율적으둜 μ‚¬μš©ν•˜λŠ” κ°€μž₯ 쒋은 방법은 셰이더 λ³€μˆ˜λ₯Ό μ—…λ°μ΄νŠΈ λΉˆλ„μ— 따라 κ΅¬μ„±ν•˜λŠ” 것이닀. 이λ₯Ό 톡해 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ€ 셰이더 μƒμˆ˜λ₯Ό μ—…λ°μ΄νŠΈ ν•˜λŠ”λ° ν•„μš”ν•œ bandwidthλ₯Ό μ΅œμ†Œν™” ν•  수 μžˆλ‹€.

예λ₯Ό λ“€μ–΄ 이 νŠœν† λ¦¬μ–Όμ—μ„œλŠ” μƒμˆ˜λ₯Ό 세가지 ꡬ쑰둜 κ·Έλ£Ήν™” ν•˜μ˜€λ‹€.
ν•˜λ‚˜λŠ” λͺ¨λ“  ν”„λ ˆμž„μ—μ„œ λ³€κ²½λ˜λŠ” λ³€μˆ˜, λ‹€λ₯Έ ν•˜λ‚˜λŠ” μ°½ 크기가 변경될 λ•Œλ§Œ λ³€κ²½λ˜λŠ” λ³€μˆ˜, λ‹€λ₯Έ ν•˜λ‚˜λŠ” 처음 ν•œ 번 μ„€μ •λœ ν›„ λ³€κ²½λ˜μ§€ μ•ŠλŠ” λ³€μˆ˜μ΄λ‹€.

    cbuffer cbNeverChanges
    {
        matrix View;
    };
    
    cbuffer cbChangeOnResize
    {
        matrix Projection;
    };
    
    cbuffer cbChangesEveryFrame
    {
        matrix World;
        float4 vMeshColor;
    };

Constant Bufferλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ 각 버퍼에 λŒ€ν•΄ ID3D11Buffer 객체λ₯Ό 생성해야 ν•œλ‹€. 그런 λ‹€μŒ ID3D11DeviceContext::UpdateSubresource()λ₯Ό ν˜ΈμΆœν•˜μ—¬ ν•„μš”ν•œ 경우 λ‹€λ₯Έ μƒμˆ˜ 버퍼에 영ν–₯을 λ―ΈμΉ˜μ§€ μ•Šκ³  각 μƒμˆ˜ 버퍼λ₯Ό μ—…λ°μ΄νŠΈ ν•  수 μžˆλ‹€.

    //
    // Update variables that change once per frame
    //
    CBChangesEveryFrame cb;
    cb.mWorld = XMMatrixTranspose( g_World );
    cb.vMeshColor = g_vMeshColor;
    g_pImmediateContext->UpdateSubresource( g_pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );
profile
κ³΅λΆ€μ •λ¦¬μš©

0개의 λŒ“κΈ€