πŸ“˜ Direct3D Tutorial4

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

Directx

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

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

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

Tutorial4 : 3D 객체 λ§Œλ“€κΈ°


πŸ“Œ 3D Spaces (3D 곡간)

컴퓨터 κ·Έλž˜ν”½μŠ€μ—μ„œλŠ” 3D 곡간을 주둜 데카λ₯΄νŠΈ μ’Œν‘œκ³„(Cartesian coordinate system)μ—μ„œ κ°€μž₯ ν”ν•˜λ‹€.
이 μ’Œν‘œκ³„λŠ” 왼손 μ’Œν‘œκ³„μ™€ 였λ₯Έμ† μ’Œν‘œκ³„λ‘œ λ‚˜λ‰œλ‹€.


πŸ“Œ Object Space

object spaceλŠ” 3D λͺ¨λΈμ„ λ§Œλ“€ λ•Œ μ‚¬μš©ν•˜λŠ” 곡간을 λ§ν•œλ‹€.


πŸ“Œ World Space

World SpaceλŠ” μ”¬μ˜ λͺ¨λ“  사물이 κ³΅μœ ν•˜λŠ” 곡간이닀. λ Œλ”λ§ν•˜λ €λŠ” κ°μ²΄λ“€μ˜ μœ„μΉ˜λ₯Ό μ •μ˜ν•œλ‹€.


πŸ“Œ View Space

View space(camera space)λŠ” 전체 씬이 μ‚¬μš©λœλ‹€λŠ” μ μ—μ„œ World space와 μœ μ‚¬ν•˜λ‹€. κ·ΈλŸ¬λ‚˜ 원점이 viewerλ‚˜ camera냐 κ°€ λ‹€λ₯΄λ‹€. (World SpaceλŠ” viewer의 μ’Œν‘œκ°€ 원점, Camera Space은 camera μ’Œν‘œκ°€ 원점)


πŸ“Œ Projection Space (투영 곡간)

투영 곡간은 λ·° μŠ€νŽ˜μ΄μŠ€μ—μ„œ 투영 λ³€ν™˜μ„ μ μš©ν•œ ν›„μ˜ 곡간을 λ§ν•œλ‹€.
X, YλŠ” -1~1 이고, ZλŠ” 0~1 이닀.


πŸ“Œ Screen Space (슀크린 곡간)

슀크린 곡간은 ν”„λ ˆμž„ λ²„νΌμ˜ μœ„μΉ˜λ₯Ό μ°Έμ‘°ν•˜λŠ”λ° μ‚¬μš©λœλ‹€. ν”„λ ˆμž„ λ²„νΌλŠ” 보톡 2D ν…μŠ€μ²˜μ΄κΈ° λ•Œλ¬Έμ— 슀크린 곡간 μ—­μ‹œ 2D 곡간이닀.
μ™Όμͺ½ 상단 λͺ¨μ„œλ¦¬κ°€ 0,0 이닀.


πŸ“Œ Space-to-space Transformation (곡간 λ³€ν™˜)

νŒŒμ΄ν”„λΌμΈμ— World, View, Projection transfrom 3가지 λ³€ν™˜μ΄ μžˆλ‹€.


πŸ“Œ World Transformation (μ›”λ“œ λ³€ν™˜)

정점을 객체 곡간(Object Space)μ—μ„œ μ›”λ“œ 곡간(World Space)둜 λ³€ν™˜ν•œλ‹€. 크기 쑰절, νšŒμ „, 이동 등이 μžˆλ‹€. μ”¬μ˜ 물체듀은 각각 κ³ μœ ν•œ μ›”λ“œ λ³€ν™˜ 행렬을 가진닀.


πŸ“Œ View Transformation

정점을 μ›”λ“œ κ³΅κ°„μ—μ„œ λ·° κ³΅κ°„μœΌλ‘œ λ³€ν™˜ν•œλ‹€. λ·° λ³€ν™˜ 행렬은 viewerλ‚˜ 카메라가 μ•„λ‹Œ 정점에 μ μš©λœλ‹€. 즉 μΉ΄λ©”λΌμ˜ κ΄€μ μ—μ„œ 정점을 μ΄λ™μ‹œν‚¨λ‹€.
XNA Mathμ—λŠ” view matrixλ₯Ό κ³„μ‚°ν•˜κΈ° μœ„ν•΄ XMMatrixLookAtLH()λΌλŠ” APIκ°€ μ’…μ’… μ‚¬μš©λœλ‹€. 카메라가 어디에 μžˆλŠ”μ§€, μ–΄λ””λ₯Ό 보고 μžˆλŠ”μ§€, 업벑터 등을 μ•Œλ €μ£Όλ©΄ 이에 μƒμ‘ν•˜λŠ” λ·° 맀트릭슀λ₯Ό 얻을 수 μžˆλ‹€.


πŸ“Œ Projection Transformation (투영 λ³€ν™˜)

투영 λ³€ν™˜μ€ μ›”λ“œ, λ·° 곡간과 같은 3D κ³΅κ°„μ—μ„œ 투영 κ³΅κ°„μœΌλ‘œ 정점을 λ³€ν™˜ν•œλ‹€. 투영 κ³΅κ°„μ—μ„œ μ •μ μ˜ X, Y μ’Œν‘œλŠ” 3차원 κ³΅κ°„μ—μ„œ μ •μ μ˜ X/Z, Y/Z λΉ„μœ¨μ— μ˜ν•΄ ꡬ해진닀.

3D 곡간을 μ •μ˜ν•˜λŠ” 맀개 λ³€μˆ˜ 쀑 ν•˜λ‚˜λ₯Ό FOV(Field-Of-View)라고 ν•œλ‹€. FOVλŠ” νŠΉμ • λ°©ν–₯을 바라볼 λ•Œ νŠΉμ • μœ„μΉ˜μ—μ„œ μ–΄λ–€ 물체가 λ³΄μ΄λŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚Έλ‹€.

컴퓨터 κ·Έλž˜ν”½μŠ€μ—μ„œ FOVλŠ” view frustum에 ν¬ν•¨λ˜μ–΄ μžˆλ‹€. view frustum은 3Dμ—μ„œ 6개의 ν‰λ©΄μœΌλ‘œ μ •μ˜λœλ‹€.

GPUλŠ” view frustum 밖에 μžˆλŠ” κ°œμ²΄λŠ” λΊ€λ‹€. 이 과정을 클리핑(clipping) 이라고 ν•œλ‹€. 클리핑 κ²°κ³Ό view frustum은 윑면체(μƒμž)κ°€ λœλ‹€.

Direct3D 11μ—μ„œ 투영 행렬을 μ–»λŠ” κ°€μž₯ μ‰¬μš΄ 방법은 XMMatrixPerspectiveFovLH() λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” 것이닀. λ§€κ°œλ³€μˆ˜λŠ” FOVy, Aspect, Zn, Zf 4개 이닀.

  • FOVy : y λ°©ν–₯ μ‹œμ•Ό λ²”μœ„
  • Aspect : κ°€λ‘œ(view space width) μ„Έλ‘œ(height) λΉ„μœ¨
  • Zn : near Z κ°’
  • Zf : far Z κ°’

πŸ“Œ Using Transformation

μ•žμ„œ ν•˜λ‚˜μ˜ μ‚Όκ°ν˜•μ„ 화면에 λ Œλ”λ§ ν• λ•ŒλŠ” 정점 버퍼가 λ°”λ‘œ 투영 곡간에 μžˆλ„λ‘ ν–ˆκΈ° λ•Œλ¬Έμ— λ³€ν™˜μ„ ν•  ν•„μš”κ°€ μ—†μ—ˆλ‹€.
이제 정점 버퍼가 객체 곡간에 μ •μ˜λ˜λ„λ‘ ν•œ 후에 정점 셰이더λ₯Ό μˆ˜μ •ν•˜μ—¬ 정점을 객체 κ³΅κ°„μ—μ„œ 투영 κ³΅κ°„μœΌλ‘œ λ³€ν™˜ν•΄λ³΄μž.


πŸ“Œ Modifying the Vertex Buffer (정점 버퍼 μˆ˜μ •ν•˜κΈ°)

πŸ”Ž 큐브


SimpleVertex vertices[] =
    {
        { XMFLOAT3( -1.0f,  1.0f, -1.0f ), XMFLOAT4( 0.0f, 0.0f, 1.0f, 1.0f ) },
        { XMFLOAT3(  1.0f,  1.0f, -1.0f ), XMFLOAT4( 0.0f, 1.0f, 0.0f, 1.0f ) },
        { XMFLOAT3(  1.0f,  1.0f,  1.0f ), XMFLOAT4( 0.0f, 1.0f, 1.0f, 1.0f ) },
        { XMFLOAT3( -1.0f,  1.0f,  1.0f ), XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) },
        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 0.0f, 1.0f, 1.0f ) },
        { XMFLOAT3(  1.0f, -1.0f, -1.0f ), XMFLOAT4( 1.0f, 1.0f, 0.0f, 1.0f ) },
        { XMFLOAT3(  1.0f, -1.0f,  1.0f ), XMFLOAT4( 1.0f, 1.0f, 1.0f, 1.0f ) },
        { XMFLOAT3( -1.0f, -1.0f,  1.0f ), XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) },
    };

이 8개의 점을 톡해 μ •μœ‘λ©΄μ²΄λ₯Ό ν˜•μ„±ν•˜λŠ” μ‚Όκ°ν˜•μ„ 지정해야 ν•œλ‹€.

λ§Žμ€ μ‚Όκ°ν˜•λ“€μ€ 같은 꼭짓점을 κ³΅μœ ν•  κ²ƒμ΄λ―€λ‘œ 8개의 점만 μ§€μ •ν•œ λ‹€μŒ Driect3Dκ°€ μ‚Όκ°ν˜•μ— λŒ€ν•΄ μ–΄λ–€ 점을 선택해야 ν•˜λŠ”μ§€ μ•Œλ €μ£ΌλŠ” 방법을 μƒμš”ν•  것이닀. μ΄λŠ” 인덱슀 버퍼(index buffer)λ₯Ό 톡해 μˆ˜ν–‰λœλ‹€. 인덱슀 λ²„νΌλŠ” λ²„νΌμ˜ 정점 인덱슀λ₯Ό μ°Έμ‘°ν•˜μ—¬ 각 μ‚Όκ°ν˜•μ—μ„œ μ‚¬μš©ν•  점을 μ§€μ •ν•˜λŠ” 리슀트λ₯Ό ν¬ν•¨ν•œλ‹€.

인덱슀 λ²„νΌλŠ” 정점 버퍼와 맀우 μœ μ‚¬ν•˜λ‹€.

πŸ”Ž index buffer

    // Create index buffer
    WORD indices[] =
    {
        3,1,0,
        2,1,3,

        0,5,4,
        1,5,0,

        3,4,7,
        0,4,3,

        1,6,5,
        2,6,1,

        2,7,6,
        3,7,2,

        6,4,5,
        7,4,6,
    };

    D3D11_BUFFER_DESC bd;
    ZeroMemory( &bd, sizeof(bd) );
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof( WORD ) * 36;        // 36 vertices needed for 12 triangles in a triangle list
    bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
    bd.CPUAccessFlags = 0;
    bd.MiscFlags = 0;
    InitData.pSysMem = indices;
    if( FAILED( g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pIndexBuffer ) ) )
        return FALSE;

arrayλ₯Ό WORDλ₯Ό μ΄μš©ν•˜μ—¬ μ„ μ–Έν•΄μ£Όμ—ˆμœΌλ―€λ‘œ sizeof(WORD)λ₯Ό μ΄μš©ν•˜μ—¬ bd의 ByteWidthλ₯Ό μ§€μ •ν•΄μ£Όμ—ˆλ‹€.

Direct3Dκ°€ μ‚Όκ°ν˜•μ„ 생성할 λ•Œ 이 인덱슀 버퍼λ₯Ό μ°Έμ‘°ν•˜λ„λ‘ μ„€μ •ν•΄μ•Ό ν•œλ‹€.


 // Set index buffer
    g_pImmediateContext->IASetIndexBuffer( g_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
    

πŸ“Œ Modifying the Vertex Shader (정점 셰이더 μˆ˜μ •ν•˜κΈ°)

정점 μ…°μ΄λ”μ—μ„œ κ°μ²΄μ—μ„œ μ›”λ“œ κ³΅κ°„μœΌλ‘œ, μ›”λ“œμ—μ„œ λ·° κ³΅κ°„μœΌλ‘œ, λ·° κ³΅κ°„μ—μ„œ νˆ¬μ˜κ³΅κ°„μœΌλ‘œ λ³€ν™˜μ„ 진행해야 ν•œλ‹€.

κ°€μž₯ λ¨Όμ € ν•  일은 3개의 μƒμˆ˜ 버퍼(constant buffer) λ³€μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” 것이닀. μƒμˆ˜ λ²„νΌλŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ 셰이더에 전달해야 ν•˜λŠ” 데이터λ₯Ό μ €μž₯ν•˜λŠ”λ° μ‚¬μš©λœλ‹€.

μš°λ¦¬κ°€ μ‚¬μš©ν•  세가지 λ³€μˆ˜λŠ” μ›”λ“œ, λ·°, 투영 λ³€ν™˜ 행렬이닀.

이 행렬듀을 μ΄μš©ν•˜μ—¬ 정점 μ…°μ΄λ”μ—μ„œ μœ„μΉ˜λ₯Ό λ³€ν™˜ν•œλ‹€.

πŸ”Ž λ³€μˆ˜ μ„ μ–Έ 및 μƒˆλ‘œμš΄ 정점 셰이더

    cbuffer ConstantBuffer : register( b0 )
    {
        matrix World;
        matrix View;
        matrix Projection;
    }
    
    //
    // Vertex Shader
    //
    VS_OUTPUT VS( float4 Pos : POSITION, float4 Color : COLOR )
    {
        VS_OUTPUT output = (VS_OUTPUT)0;
        output.Pos = mul( Pos, World );
        output.Pos = mul( output.Pos, View );
        output.Pos = mul( output.Pos, Projection );
        output.Color = Color;
        return output;
    }

πŸ“Œ Setting up the Matrices (ν–‰λ ¬ μ„€μ •ν•˜κΈ°)

λ Œλ”λ§ ν•  λ•Œ μ‚¬μš©ν•  λ³€ν™˜μ„ μ €μž₯ν•œ μ„Έ 개의 행렬도 μ •μ˜ν•΄μ•Ό ν•œλ‹€. λ Œλ”λ§ν•˜κΈ° 전에 μ΄λŸ¬ν•œ ν–‰λ ¬μ˜ 값을 Constant buffer에 λ³΅μ‚¬ν•œλ‹€. 그러고 λ‚œ ν›„ Draw()λ₯Ό ν˜ΈμΆœν•˜μ—¬ λ Œλ”λ§μ„ μ‹œμž‘ν•˜λ©΄, 정점 μ…°μ΄λ”λŠ” Constant Buffer에 μ €μž₯된 행렬을 μ½λŠ”λ‹€.

    ID3D11Buffer* g_pConstantBuffer = NULL;
    XMMATRIX g_World;
    XMMATRIX g_View;
    XMMATRIX g_Projection;

ID3D11Buffer 객체λ₯Ό λ§Œλ“€κΈ° μœ„ν•΄μ„œλŠ” ID3D11Device::CreateBuffer()λ₯Ό μ‚¬μš©ν•˜κ³  D3D11_BIND_CONSTANT_BUFFERλ₯Ό λͺ…μ‹œν•΄μ•Ό ν•œλ‹€.

    D3D11_BUFFER_DESC bd;
    ZeroMemory( &bd, sizeof(bd) );
    bd.Usage = D3D11_USAGE_DEFAULT;
    bd.ByteWidth = sizeof(ConstantBuffer);
    bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    bd.CPUAccessFlags = 0;
    if( FAILED(g_pd3dDevice->CreateBuffer( &bd, NULL, &g_pConstantBuffer ) ) )
        return hr;

λ‹€μŒμœΌλ‘œ ν•  일은 λ³€ν™˜μ„ μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ μ‚¬μš©ν•  μ„Έ 가지 행렬을 λ§Œλ“œλŠ” 것이닀. μš°λ¦¬λŠ” μ‚Όκ°ν˜•μ΄ XY 평면에 ν‰ν–‰ν•˜κ²Œ 원점에 μœ„μΉ˜ν•˜κΈ°λ₯Ό μ›ν•œλ‹€. 객체 κ³΅κ°„μ˜ μ •μ λ²„νΌμ—μ„œ μ΄λŸ°μ‹μœΌλ‘œ 이미 μ €μž₯λ˜μ–΄ μžˆμœΌλ―€λ‘œ μ›”λ“œ λ³€ν™˜μ€ κΈ°λ³Έ 행렬이 λœλ‹€.
카메라가 [0 1 -5]에 μœ„μΉ˜ν•˜λ©° [0 1 0]을 λ°”λΌλ³΄κ²Œ ν•˜κ³ μž, XMMatrixLookAtLH()λ₯Ό ν˜ΈμΆœν•˜μ—¬ 계산할 수 μžˆλ‹€. +Y λ°©ν–₯이 μœ„μͺ½μœΌλ‘œ μœ μ§€λ˜μ–΄μ•Ό ν•œλ‹€.
λ§ˆμ§€λ§‰μœΌλ‘œ 투영 행렬을 μ–»κΈ° μœ„ν•΄ XMMatrixPerspectiveFovLH()λ₯Ό ν˜ΈμΆœν•œλ‹€.
이 세가지 행렬은 μ „μ—­ λ³€μˆ˜ g_World, g_View, g_Projection에 μ €μž₯λœλ‹€.


πŸ“Œ Updating Constant Buffers (μƒμˆ˜ 버퍼 μ—…λ°μ΄νŠΈ ν•˜κΈ°)

행렬을 μƒμˆ˜ 버퍼에 기둝해야 λ Œλ”λ§ν•  λ•Œ GPUκ°€ 읽을 수 μžˆλ‹€. ID3D11DeviceContext::UpdateSubresource() APIλ₯Ό μ‚¬μš©ν•˜μ—¬ μ…°μ΄λ”μ˜ μƒμˆ˜ 버퍼와 λ™μΌν•œ μˆœμ„œλ‘œ μ €μž₯된 행렬에 포인터λ₯Ό 전달 ν•  수 μžˆλ‹€. 이λ₯Ό μœ„ν•΄ μ…°μ΄λ”μ˜ μƒμˆ˜ 버퍼와 λ™μΌν•œ λ ˆμ΄μ•„μ›ƒμ„ 가진 ꡬ쑰체λ₯Ό λ§Œλ“€ 것이닀.

    //
    // Update variables
    //
    ConstantBuffer cb;
    cb.mWorld = XMMatrixTranspose( g_World );
    cb.mView = XMMatrixTranspose( g_View );
    cb.mProjection = XMMatrixTranspose( g_Projection );
    g_pImmediateContext->UpdateSubresource( g_pConstantBuffer, 0, NULL, &cb, 0, 0 );
profile
κ³΅λΆ€μ •λ¦¬μš©

0개의 λŒ“κΈ€