ShadowMapping ´ÙÀÌ·ºÆ®X

´ÙÀÌ·ºÆ®X ÇÁ·Î±×·¥¿¡¼­ ½ÇÇàµÈ È­¸éÀÌ´Ù.

·»´õ¸ùÅ°¿¡¼­ ÇÒÀÏ

´ÙÀÌ·ºÆ®¿¡¼­ ÄÚµùÇϱâ Àü¿¡ ·»´õ¸ùÅ°¿¡¼­ ÇÒ ÀÛ¾÷ÀÌ ÀÖ´Ù.
¸ðµ¨ ÀúÀå, ¼ÎÀÌ´õ ÆÄÀÏ ¼öÁ¤ÀÌ´Ù.

¸ðµ¨ ÀúÀå

¿øȯü ¸ðµ¨ torus.x¿Í Æò¸é ¸ðµ¨ disc.xÀ» ÀúÀåÇÑ´Ù.

 

2°³ÀÇ fx ÆÄÀÏ ÀúÀå

ShadowMapping.rfx ÆÄÀÏÀ» CreateShadow.rfx¿Í ApplyShadowDisc.rfx·Î µÎ ¹ø ÀúÀåÇÑ´Ù.

CreateShadow ¼öÁ¤

ApplyShadowTorus, ApplyShadowDisc µÎ °³ÀÇ Æнº¸¦ »èÁ¦ÇÑ´Ù.

CreateShadowÀÇ Á¤Á¡ ¼ÎÀÌ´õ¸¦ ¿ÀÇÂÇÑ´Ù.

Á¤Á¡ ¼ÎÀÌ´õÀÇ ±¤¿ø-ºäÇà·ÄÀ» »èÁ¦ÇÑ´Ù.
´ÙÀÌ·ºÆ® X ÇÁ·¹ÀÓ¿öÅ©¿¡¼­ ±¤¿ø-ºäÇà·ÄÀ» Á÷Á¢ ³Ñ±æ °ÍÀÌ´Ù.

gWorldLightPos, gViewProjMat Àü¿ª º¯¼ö´Â CreateShadow Æнº¿¡¼­ »ç¿ëµÇÁö ¾Ê´Â´Ù.
·»´õ¸ùÅ°¿¡¼­ »èÁ¦ÇØÁØ´Ù.

//»èÁ¦ µÇ´Â ±¤¿ø-ºäÇà·Ä
float3 dirZ = -normalize( gWorldLightPos);
 float3 up = float3( 0, 1, 0);
 float3 dirX = cross( up, dirZ);
 float3 dirY = cross( dirZ, dirX);

 lightViewMat = float4x4(
    float4( dirX, -dot( gWorldLightPos.xyz, dirX)),
    float4( dirY, -dot( gWorldLightPos.xyz, dirY)),
    float4( dirZ, -dot( gWorldLightPos.xyz, dirZ)),
    float4( 0, 0, 0, 1));   
 
 lightViewMat = transpose( lightViewMat);

 

»èÁ¦µÈ ÈÄÀÇ Á¤Á¡ ¼ÎÀÌ´õ ÄÚµåÀÌ´Ù.

VS_OUTPUT vs_main( VS_INPUT input)
{
   VS_OUTPUT output;
   
   float4x4 lightViewMat = gLightViewMat;  
      
   output.pos = mul( input.pos, gWorldMat);
   output.pos = mul( output.pos, lightViewMat);
   output.pos = mul( output.pos, gLightProjMat);
   
   output.clipPos = output.pos;
      
   return output;
}

ApplyShadow ¼öÁ¤

CreateShadow, ApplyShadowDisc µÎ °³ÀÇ Æнº¸¦ »èÁ¦ÇÑ´Ù.
ApplyShadowTorus ÆнºÀÇ Á¤Á¡ ¼ÎÀÌ´õ¸¦ ¿ÀÇÂÇÑ´Ù.

¿©±â¿¡¼­µµ Á¤Á¡ ¼ÎÀÌ´õÀÇ ±¤¿ø-ºäÇà·ÄÀ» »èÁ¦ÇÑ´Ù.
´ÙÀÌ·ºÆ® X ÇÁ·¹ÀÓ¿öÅ©¿¡¼­ ±¤¿ø-ºäÇà·ÄÀ» Á÷Á¢ ³Ñ±æ °ÍÀÌ´Ù.

VS_OUTPUT vs_main( VS_INPUT input)
{
   VS_OUTPUT output;
   
   float4x4 lightViewMat = gLightViewMat;  
   
   //render world-view-projection position
   float4 worldPos = mul( input.pos, gWorldMat);
   output.pos = mul( worldPos, gViewProjMat);
   
   //light world-view-projection position
   output.clipPos = mul( worldPos, lightViewMat);
   output.clipPos = mul( output.clipPos, gLightProjMat);
   
   float3 lightDir = normalize( worldPos.xyz - gWorldLightPos.xyz);
   float3 worldNormal = normalize( mul( input.normal, (float3x3)gWorldMat));
   
   output.diffuse = dot(-lightDir, worldNormal);
   
   return output;
}

ÇÁ·¹ÀÓ¿öÅ©

·»´õ¸µÀ» Å©°Ô ±×¸²ÀÚ ¸¸µé±â¿Í ±×¸²ÀÚ ÀÔÈ÷±â·Î ³ª´¶´Ù.

Àü¿ªº¯¼ö

¿øÇü Æò¸é ¸Þ½Ã gBackgroundMesh¿Í ±×¸²ÀÚ ¸¸µé±â ¼ÎÀÌ´õ gCreateShadowShader¸¦ º¯¼ö¸¦ Ãß°¡ÇÑ´Ù.
Åä·¯½º¿ë ¸Þ½Ã´Â ±âÁ¸¿¡ ÀÖ´ø gMesh¸¦ »ç¿ëÇÑ´Ù.
±×¸²ÀÚ ÀÔÈ÷±â´Â gShader¸¦ »ç¿ëÇÑ´Ù.

LPD3DXMESH gBackgroundMesh = NULL;
LPD3DXEFFECT gCreateShadowShader = NULL;

¼ÎÀÌ´õÀÇ ¸Þ½Ã¿ë »ö»óÀ» À§ÇÑ º¯¼öµµ Ãß°¡ÇÑ´Ù.
Åä·¯½º´Â gMeshColor, ¿øÇü Æò¸éÀº gBackgroundColorÀÌ´Ù.

//¸Þ½Ã »ö»ó
D3DXVECTOR4 gMeshColor(1, 1, 0, 1);
D3DXVECTOR4 gBackgroundColor(1, 1, 0, 1);

±×¸²ÀÚ ¸¸µé±â¿ë ·»´õ Ÿ°ÙÀ» Ãß°¡ÇÑ´Ù.

//±×¸²ÀÚ ·»´õŸ°Ù
LPDIRECT3DTEXTURE9 gShadowRenderTarget = NULL;
LPDIRECT3DSURFACE9 gShadowDepthStencil = NULL;

LPDIRECT3DSURFACE9´Â ±×¸²ÀÚ ¸ÊÀ» ±×¸±¶§ »ç¿ëÇÒ ±íÀÌ ¹öÆÛÀÌ´Ù.
±×¸²ÀÚ¸ÊÀÇ Å©±â°¡ È­¸éÀÇ Å©±âº¸´Ù ÈξÀ Å©±â ¶§¹®¿¡ Çϵå¿þ¾î ±íÀÌ ¹öÆÛ¸¦ »ç¿ëÇÒ ¼ö ¾ø´Ù.

DestroyDirectX( ) ÇÔ¼ö

Ãß°¡Çß´ø º¯¼öµéÀ» ÇØÁ¦ÇÑ´Ù.

_RELEASE_(gBackgroundMesh);
_RELEASE_(gCreateShadowShader);

_RELEASE_(gShadowRenderTarget);
_RELEASE_(gShadowDepthStencil);

LoadAsset( ) ÇÔ¼ö

¼ÎÀÌ´õ¿Í ¸ðµ¨À» ·ÎµùÇÑ´Ù.

// ¼ÎÀÌ´õ ·Îµù
gShader = LoadShader("ApplyShadow.fx");
if(gShader == NULL)
    return false;

// ¸ðµ¨ ·Îµù
gMesh = LoadModel("torus.x");
if(gMesh == NULL)
    return false;

//CreateShadow ¼ÎÀÌ´õ ·Îµù
gCreateShadowShader = LoadShader("CreateShadow.fx");
if(gCreateShadowShader == NULL)
    return false;

//¿øÇü Æò¸é ¸Þ½Ã ·Îµù
gBackgroundMesh = LoadModel("disc.x");
if(gBackgroundMesh == NULL)
    return false;

InitShadowRenderTarget(  ) ÇÔ¼ö

±×¸²ÀÚ¸ÊÀÇ Å©±â¸¦ 2048·Î ÇÑ´Ù.

CreateTexture( )¿¡¼­ D3DUSAGE_RENDERTARGET,  D3DFMT_R32F Æ÷¸ËÀ¸·Î ·»´õŸ°Ù ÅؽºÃĸ¦ ¸¸µç´Ù.

CreateDepthStencilSurface( )¿¡¼­ ±×¸²Àڸʰú µ¿ÀÏÇÑ Å©±â·Î ±íÀÌ ¹öÆÛ¸¦ ¸¸µç´Ù.

//·»´õŸ°Ù »ý¼º
const int shadowMapSize = 2048;
if( FAILED(gD3DDevice->CreateTexture(
        shadowMapSize, shadowMapSize,
        1, //¹Ó¸ÊÀÇ ¼ö, ·»´õŸ°ÙÀº Çϳª¸¸ ¸¸µç´Ù.
        D3DUSAGE_RENDERTARGET, //·»´õŸ°Ù¿ë ÅؽºÃÄ
        D3DFMT_R32F, //ÅؽºÃ³ Æ÷¸Ë, ·»´õ¸ùÅ°ÀÇ R32F Æ÷¸Ë
        D3DPOOL_DEFAULT,
        &gShadowRenderTarget, NULL)))
{
    return false;
}

//±×¸²Àڸʰú µ¿ÀÏÇÑ Å©±âÀÇ ±íÀ̹öÆÛ »ý¼º
if (FAILED(gD3DDevice->CreateDepthStencilSurface(
        shadowMapSize, shadowMapSize,
        D3DFMT_D24X8, //ÅؽºÃ³ Æ÷¸Ë, ±íÀÌ ¹öÆÛ·Î 24ºñÆ®
        D3DMULTISAMPLE_NONE,
        0, //¸ÖƼ»ùÇÃÀ» »ç¿ëÇÏÁö ¾ÊÀ¸´Ï 0ÀÌ´Ù
        TRUE, //±íÀ̹öÆÛ¸¦ ¹Ù²Ü ¶§, ±× ¾È¿¡ ÀÖ´ø ³»¿ëÀ» º¸Á¸ÇÏÁö ¾Ê´Â´Ù.
        &gShadowDepthStencil, NULL)))
{
    return false;
}

RenderScene( ) ÇÔ¼ö

·»´õ¸µ¿¡¼­ »ç¿ëÇÒ º¯¼öµéÀ» ¾Ë¾Æº¸ÀÚ.

CreateShadow Æнº¿¡¼­ ÇÊ¿äÇÑ º¯¼ö´Â gWorldMat, gLightViewMat, gLightProjMatÀÌ´Ù.

ApplyShadowTorus Æнº¿¡¼­ ÇÊ¿äÇÑ º¯¼ö´Â gWorldLightPos, gWorldMat, gLightViewMat, gLightProjMat, gViewProjMat, gObjectColorÀÌ´Ù.

µÎ Æнº¿¡¼­ ÇÊ¿äÇÑ º¯¼öµéÀ» ¹Ì¸® ±¸ÇÑ´Ù.

gLightViewMat, gLightProjMat¸¦ ¼³Á¤Çϱâ À§ÇØ ±¤¿ø-ºä Çà·Ä, ±¤¿ø-Åõ¿µ Çà·ÄÀ» ±¸ÇÑ´Ù.

// ±¤¿ø-ºä Çà·Ä
D3DXMATRIXA16 matLightView;
{
    D3DXVECTOR3 vEyePt(gWorldLightPos.x, gWorldLightPos.y, gWorldLightPos.z);
    D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    D3DXMatrixLookAtLH(&matLightView, &vEyePt, &vLookatPt, &vUpVec);
}

// ±¤¿ø-Åõ¿µ Çà·Ä
D3DXMATRIXA16 matLightProjection;
D3DXMatrixPerspectiveFovLH(&matLightProjection, D3DX_PI / 4.0f, 1, 1, 3000);

gViewProjMat¸¦ ¼³Á¤Çϱâ À§ÇØ ºä-Åõ¿µÇà·ÄÀ» ±¸ÇÑ´Ù.

// ºä-Åõ¿µÇà·Ä
D3DXMATRIXA16 matViewProjection;
{
    //ºäÇà·Ä
    D3DXMATRIXA16 matView;
    D3DXVECTOR3 vEyePt(gWorldCameraPos.x, gWorldCameraPos.y, gWorldCameraPos.z);
    D3DXVECTOR3 vLookatPt(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 vUpVec(0.0f, 1.0f, 0.0f);
    D3DXMatrixLookAtLH(&matView, &vEyePt, &vLookatPt, &vUpVec);

    //Åõ¿µÇà·Ä
    D3DXMATRIXA16 matProjection;
    D3DXMatrixPerspectiveFovLH(&matProjection, FOV, ASPECT_RATIO, NEAR_PLANE, FAR_PLANE);
    D3DXMatrixMultiply(&matViewProjection, &matView, &matProjection);
}

Åä·¯½º¿Í ¿øÇüÆÇÀÇ ¿ùµåÇà·Ä matTrousWorld, matDiscWorld¸¦ ±¸ÇÑ´Ù.

// Åä·¯½º ¿ùµåÇà·ÄÀ» ¸¸µç´Ù.
D3DXMATRIXA16 matTorusWorld;
{
    // ÇÁ·¹ÀÓ¸¶´Ù 0.4µµ¾¿ ȸÀüÀ» ½ÃŲ´Ù.
    gRotationY += 0.004f * PI / 180.0f;
    if (gRotationY > 2 * PI)
    {
        gRotationY -= 2 * PI;
    }

    D3DXMatrixRotationY(&matTorusWorld, gRotationY);
}

//¿øÇüÆÇÀÇ ¿ùµåÇà·ÄÀ» ¸¸µç´Ù.
D3DXMATRIXA16 matDiscWorld;
{
    D3DXMATRIXA16 matScale;
    D3DXMatrixScaling(&matScale, 2, 2, 2);

    D3DXMATRIXA16 matTrans;
    D3DXMatrixTranslation(&matTrans, 0, -40, 0);

    D3DXMatrixMultiply(&matDiscWorld, &matScale, &matTrans);
}

±×¸²ÀÚ¸ÊÀ» ¸¸µé¶§ ·»´õŸ°ÙÀ» ¼³Á¤Çϱâ Àü¿¡ ´Ù½Ã Çϵå¿þ¾î ¹é¹öÆÛ¿¡ ±×¸®±â À§ÇØ ÇöÀç ·»´õŸ°ÙÀ» ´Ù¸¥ º¯¼ö¿¡ º¸°üÇØ µÐ´Ù.

// ÇöÀç Çϵå¿þ¾î ¹é¹öÆÛ¿Í ±íÀ̹öÆÛ¸¦ º¸°üÇÑ´Ù.
LPDIRECT3DSURFACE9 pHWBackBuffer = NULL;
LPDIRECT3DSURFACE9 pHWDepthStencilBuffer = NULL;
gD3DDevice->GetRenderTarget(0, &pHWBackBuffer);
gD3DDevice->GetDepthStencilSurface(&pHWDepthStencilBuffer);

 

1. ±×¸²ÀÚ ¸¸µé±â

±×¸²ÀÚ¸Ê¿ë ·»´õŸ°ÙÀ» ¼³Á¤ÇÑ´Ù. SetRenderTarget( )¿¡ Ç¥¸éÀ» ÀÎÀÚ·Î ³Ö¾îÁØ´Ù.

// ±×¸²ÀÚ ¸ÊÀÇ ·»´õŸ±ê°ú ±íÀ̹öÆÛ¸¦ »ç¿ëÇÑ´Ù.
LPDIRECT3DSURFACE9 pShadowSurface = NULL;
if (SUCCEEDED(gShadowRenderTarget->GetSurfaceLevel(0, &pShadowSurface)))
{
    gD3DDevice->SetRenderTarget(0, pShadowSurface);
    pShadowSurface->Release();
    pShadowSurface = NULL;
}
gD3DDevice->SetDepthStencilSurface(gShadowDepthStencil);

ÀÌÀü ÇÁ·¹ÀÓ¿¡ ±×·È´ø ±×¸²ÀÚ¸ÊÀ» ÇϾá»öÀ¸·Î Áö¿î´Ù. ÇѾá»öÀÌ¸é ±×¸²ÀÚ¸¦ Àû¿ëÇÏÁö ¾Ê´Â´Ù.
±íÀÌ ¹öÆÛµµ ¸¶Âù °¡Áö·Î Áö¿î´Ù.

//ÀÌÀü ÇÁ·¹ÀÓ¿¡ ±×·È´ø ±×¸²ÀÚ Á¤º¸¸¦ Áö¿ò
gD3DDevice->Clear(0, NULL, (D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER), 0xFFFFFFFF, 1.0f, 0);

±×¸²ÀÚ ¸¸µé±â ¼ÎÀÌ´õ gCreateShadowShader¸¦ À§ÇØ ¿ùµåÇà·Ä, ±¤¿ø-ºäÇà·Ä, ±¤¿ø-Åõ¿µÇà·ÄÀ» ¼³Á¤ÇÑ´Ù.

// ±×¸²ÀÚ ¸¸µé±â ½¦ÀÌ´õ Àü¿ªº¯¼öµéÀ» ¼³Á¤
gCreateShadowShader->SetMatrix("gWorldMat", &matTorusWorld);
gCreateShadowShader->SetMatrix("gLightViewMat", &matLightView);
gCreateShadowShader->SetMatrix("gLightProjMat", &matLightProjection);

±×¸²ÀڸʿëÀ¸·Î »ç¿ëµÉ ¸Þ½Ã¸¦ ±×¸°´Ù.

// ±×¸²ÀÚ ¸¸µé±â ½¦ÀÌ´õ¸¦ ½ÃÀÛ
{
    UINT numPasses = 0;
    gCreateShadowShader->Begin(&numPasses, NULL);
    {
        for (UINT i = 0; i < numPasses; ++i)
        {
            gCreateShadowShader->BeginPass(i);
            gMesh->DrawSubset(0); //torus ±×¸®±â
            gCreateShadowShader->EndPass();
        }
    }
    gCreateShadowShader->End();
}

2. ±×¸²ÀÚ ±×¸®±â

Åä·¯½º¿Í ¿øÇüÆÇ¿¡ ¾Õ¿¡¼­ ¸¸µç ±×¸²ÀÚ¸ÊÀ» ±×¸°´Ù.

·»´õŸ°ÙÀ» Çϵå¿þ¾î ¹é¹öÆÛ, ±íÀ̹öÆÛ·Î ¿ø»óº¹±¸ ½ÃŲ´Ù.

pHWBackBuffer, pHWDepthStencilBuffer¸¦ ÇØÁ¦ÇÏ´Â °ÍÀº GetRenderTarget( ), GetDepthStencilSurface( ) ÇÔ¼ö¸¦ È£ÃâÇÒ ¶§ D3D ³»ºÎÀûÀ¸·Î ¹öÆÛµéÀÇ ÂüÁ¶Ä«¿îÅ͸¦ Áõ°¡½ÃÄÑ Áֱ⠶§¹®ÀÌ´Ù.

//Çϵå¿þ¾î ¹é¹öÆÛ, ±íÀ̹öÆÛ »ç¿ë
gD3DDevice->SetRenderTarget(0, pHWBackBuffer);
gD3DDevice->SetDepthStencilSurface(pHWDepthStencilBuffer);

pHWBackBuffer->Release();
pHWBackBuffer = NULL;
pHWDepthStencilBuffer->Release();
pHWDepthStencilBuffer = NULL;

¹°Ã¼¸¦ ±×¸®±â À§ÇÑ º¯¼öµéÀ» ¼³Á¤ÇÑ´Ù.

³­¹Ý»ç¸¦ °è»êÇϱâ À§ÇÑ ±¤¿øÀÇ À§Ä¡( gWorldLightPos )°¡ ÇÊ¿äÇÏ´Ù.
¹°Ã¼ ·»´õ¸µÀ» À§ÇÑ ¿ùµå Çà·Ä, ºä-Åõ¿µÇà·ÄÀÌ ÇÊ¿äÇÏ´Ù.
±¤¿øÀ¸·ÎºÎÅÍ ¹°Ã¼±îÁöÀÇ ±íÀ̸¦ ±¸Çϱâ À§ÇÑ ±¤¿ø-ºäÇà·Ä°ú ±¤¿ø-Åõ¿µÇà·Äµµ ÇÊ¿äÇÏ´Ù.
¹°Ã¼ÀÇ »ö±òÀ» À§ÇÑ gObjectColorµµ ÇÊ¿äÇÏ´Ù.

// ±×¸²ÀÚ ÀÔÈ÷±â ½¦ÀÌ´õ Àü¿ªº¯¼öµéÀ» ¼³Á¤
gShader->SetVector("gWorldLightPos", &gWorldLightPos);
gShader->SetMatrix("gWorldMat", &matTorusWorld);    //¿øȯü
gShader->SetMatrix("gLightViewMat", &matLightView);
gShader->SetMatrix("gLightProjMat", &matLightProjection);
gShader->SetMatrix("gViewProjMat", &matViewProjection);

gShader->SetVector("gObjectColor", &gMeshColor);

·»´õ¸ùÅ°ÀÇ ¼ÎÀÌ´õ¸¦ fx·Î ÀͽºÆ÷Æ®Çϸé texture À̸§¿¡ Á¢¹Ì»ç "_Tex"¸¦ Ãß°¡ÇÑ´Ù.
¿ø·¡ ÅؽºÃÄÀÇ À̸§À½ ShadowMapÀ̾úÁö¸¸ ÀͽºÆ÷Æ®Çϸé ShadowMap_Tex°¡ µÈ´Ù.

CreateShadown.fx³ª ApplyShadow.fx¸¦ ¿­¾îº¸¸é "_Tex"°¡ ÀÚµ¿À¸·Î Ãß°¡µÈ´Ù.

texture ShadowMap_Tex

gShader->SetTexture("ShadowMap_Tex", gShadowRenderTarget);

Åä·¯½º¸¦ ±×¸°´Ù.

UINT numPasses = 0;
gShader->Begin(&numPasses, NULL);
{
    for (UINT i = 0; i < numPasses; ++i)
    {
        gShader->BeginPass(i);
        {
            //torus ±×¸®±â
            gMesh->DrawSubset(0);

¿øÇüÆÇÀ» ±×¸°´Ù.

BeginPass( )¿Í EndPass( ) »çÀÌ¿¡ º¯¼ö°ªÀ» ¼öÁ¤ ÇÒ ¶§´Â CommitChanges( ) ÇÔ¼ö¸¦ È£ÃâÇÑ´ÙÀ½¿¡ ¿øÇüÆÇÀ» ±×¸°´Ù.

            //¿øÇüÆÇ ±×¸®±â
            gShader->SetMatrix("gWorldMat", &matDiscWorld);
            gShader->SetVector("gObjectColor", &gBackgroundColor);
            gShader->CommitChanges();
            gBackgroundMesh->DrawSubset(0);
        }
        gShader->EndPass();
    }
}
gShader->End();

´Ù¿î·Îµå : ApplyShadow.rfx , CreateShadow.rfx , ShadowMapping5.rfx , DxDemo_ShadowMapping.zip

Âü°í : ÇѺû¹Ìµð¾î ¼ÎÀÌ´õ ÇÁ·Î±×·¡¹Ö ÀÔ¹®