반응형

BLOG main image





texture Map_Tex

<

   string ResourceName = ".\\";

>;

sampler2D MapSampler = sampler_state

{

   Texture = (Map_Tex);

};


굵은글씨의 경로를 넣어보면 됨, 경로 설정

반응형
반응형

BLOG main image



GetSurfaceLevel()

GetRenderTarget(),
GetDepthStencilSurface()


을 사용할때 레퍼런스 카운트 1씩이 증가해 Release() 로 참조카운트 수를 감소시켜 해제하도록 해야함







http://cretom.egloos.com/583755

셰이더 책에 보면

보관했던 렌더링 표면을 복구시키는 부분에 이런 코드가 있다



//-----------------------------------------------------
// 기존 렌더링타겟 복구
//-----------------------------------------------------

m_pd3dDevice->SetRenderTarget(0, pOldBackBuffer);
m_pd3dDevice->SetDepthStencilSurface(pOldZBuffer);
m_pd3dDevice->SetViewport(&oldViewport);

pOldBackBuffer->Release();
pOldZBuffer->Release();


// 버퍼 클리어
m_pd3dDevice->Clear( 0L, NULL , D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER
      , 0x00404080, 1.0f, 0L );

// pOldBackBuffer에 렌더링하는 코드
.......
....
..




빨간색 부분이 주목해야 할 부분!

그 코드 뒤 복구한 렌더링타겟 'pOldBackBuffer' 에 Clear하고 렌더링하는 코드가 있는데

그러기 전 'pOldBackBuffer'를 Release 시켜버리고 있다.

왜 이러나.. 이해가 되질 않았는데

pDevice->GetRenderTarget(),
pDevice->GetDepthStencilSurface() 메소드의 설명을 찾아보니 의문이 풀렸다.




이 메서드를 호출하면,IDirect3DSurface9 인터페이스에 대한
내부 참조 카운트가 증가한다.
 IDirect3DSurface9 인터페이스를 사용해 끝냈을 때에
IUnknown::Release 를 호출하지 않으면 메모리 누수가 발생한다.


그러니까 스마트 포인터처럼 Get 메소드를 사용하면 내부 참조카운트가 증가하고,

내부 참조 카운트가 0일때 Release하면 최종적으로 메모리에서 내려가는 구조라서

메모리에서 해제시키려고 Release를 호출한 게 아니라,

GetRenderTarget() 호출로 +1 됐던 참조 카운트를

-1 시키려고 Release()를 호출했던거였다.








반응형
반응형



http://blog.naver.com/sorkelf/40156769867

멀티 패스 렌더링 이란 여러개의 경로를 가지는 렌더링 방법을 말한다. 보통 백 버퍼만으로 렌더링하는것을 싱글 패스 렌더링이라고 하며

멀티 패스 렌더링은 1개의 화면을 만들기 위해 여러개의 서피스에 렌더링하는 기술을 말한다


여기서는 멀티 패스 렌더링을 더욱 좁은뜻으로 다룰 것이다. 

멀티 패스 렌더링에는 [ 한번에 여러개의 서피스에 렌더링 하는 기술] 이라는 의미도 있다. 

예를들면 Tex1과 Tex2라는 서피스를 사용하여 백 버퍼에 렌더링 하는 경우 

Tex1 생성, Tex2 생성, 백 버퍼로의 렌더링이라는 3번(3패스)의 렌더링이 필요하게 된다.


멀티 패스 렌더링을 사용하면 Tex1의 생성과 Tex2의 생성을 1패스에서 한번에 수행할수 있다.

렌더링 회수가 2번이 되기 때문에 퍼포먼스를 큰 폭으로 향상시킬 수 있다. 



① 일단 렌더 타겟이 무엇인가..


   렌더링에 대해서 조금 복습해보자. 우리들이 평소에 아무렇지도 않게 렌더링하고잇는 백버퍼...

왠지 [ 렌더링 = 백버퍼 ]라고 생각하기 쉽지만, 실은 여기에도 조금 생략되어있는 부분이 있다. 


렌더링 디바이스는 디폴트 값으로 [ 렌더 타겟 0번]에 렌더링하도록 설정되어있으며,

백버퍼는 디폴트 값으로 렌더타겟 0번에 설정 되어있다. 


즉 렌더링 디바이스와 백버퍼 사이에는 [ 렌더 타겟 ] 이라는 서피스 저장소가 있는 것이다.

이것을 확실히 알면 멀티 패스 렌더링도 쉽다






② IDirect3DDevice9::SetRenderTarget 함수

    위의 그림처럼 백버퍼는 디폴트로 RT0에 설정되어 있긴 하지만 여기가 백버퍼의 고정석은 아니다.


IDirect3DDevice9::SetRenderTarget 함수를 사용하면 미리 만든 서피스를 RT0이나 RT1등으로 설정할 수 있다.:


 IDirect3Device9::SetRenderTarget 함수

HRESULT SetRenderTarget(
   DWORD RenderTargetIndex,
   IDirect3DSurface9 *pRenderTarget
);


RenderTargetIndex 에는 렌더 타겟의 번호를 설정한다

pRenderTarget에는 서피스를 넘긴다


주의 할 것은 SetRenderTarget 함수를 사용하면 이전에 설정되어있던 서피스의 포인터를 잃게 된다.

예를들어 RT0에 다른 서피스를 설정하면 백버퍼로 되돌아 올 수 없다

따라서 보통은 미리 설정된 서피스는 IDirect3DDevice9::GetRenderTarget으로 미리 저장해두고 그것을 바꾸는 형태로 사용한다



③ 지정한 렌더타겟에 렌더링 하기


   RT0 이외의 서피스에서의 렌더링은 고정 기능 파이프라인에서는 불가능하며(아마도..)프로그래머블 셰이더에서 가능하다


셰이더(HLSL)을 사용하면 픽셀 셰이더에서 아래와같은 형태로 사용한다


float4 Test_PS( float2 texCoord : TEXCOORD0 ) : COLOR0   //<- 여기!!!

{
   float outColor
   // 무언가 처리
   return outColor;
}


COLOR0라고 표시되어 있는 부분에 주목 한다.

이 부분이 실은 렌더타겟 0번에 렌더링 하세요~라는 의미의 시멘틱스이다.

COLOR의 뒷부분의 숫자가 실은 쓰여질 렌더타겟의번호 라는 것이다. 즉 이 말은..


 float4 Test_PS( float2 texCoord : TEXCOORD0 ) : COLOR1 //<- 여기!!!

{
   float outColor
   // 무언가 처리
   return outColor;
}


이렇게 하면 렌더타겟 1번에 쓰여진다는 것이 된다.

[ 이것은 싱글 패스 렌더링이잖아!!. 그럼 0번과 1번에 동시에 쓰려면 어떻게 해야하지?]

라고 생각할지도 모르지만 이 부분은 반환값을 구조체로 만들어 버리면 된다


 struct OUTPUT_PS 

{

   float4 color0 : COLOR0;
   float4 color1 : COLOR1;
};

OUTPUT_PS  Test_PS( float2 texCoord : TEXCOORD0 )
{
    OUTPUT_PS  outColor
    // 무언가 처리
   return outColor;
}



④ MRT를 서포트 하는가에 주의


   멀티 렌더 타겟은 비교적 최근엔 많이 쓰이지만 조금 옛날 비디오 카드면 서포트 하지 않는 경우도 있다

멀티 렌더 타겟으로써 가질 수 있는 서피스의 최대 수는 IDirect3DDevice9::GetDeviceCaps함수로 얻을수 있는 D3DCAPS9 구조체에서NumSimultaneousRTs의 체크한다


D3DCAPS9 Caps;

pDev->GetDeviceCaps( &Caps );
DWORD MaxRT = Caps.NumSimultaneousRTs;

멀티 렌더 타겟의 최대 수


이것이 1일 경우, 멀티 패스 렌더링은 할 수 없다. ELSA GLADIAC FX746Ultra DDR3(Geforce FX 5700 Ultra)에서는 1, 노트북 그래픽 카드인 (FMV-BIBLO MG70H 2004년 봄 모델 Intel(R) 82852/82855 GM/GME Graphics Controller)에서도 1이었다.

NVIDIA GeForce6600에서는 4였다.


대충 2005년 이후 나온 모델은 사용가능 할 것이라 판단된다


프로그램상에서 이것을 확인하는 것이 귀찮은 사람은 DirectX의 유틸리티 중DirectX Caps Viewer(DXCapsViewer.exe)」를 사용하길 바란다. 이것은 비디오 카드의 능력을 열거해 주는 어플리케이션이다.

자신의 비디오카드 폴더 내에서 [D3D Device Types]→[HAL]→[Caps]안에 위 플래그가 있을 것이다



⑤ 멀티 패스 렌더링으로 무엇을 할 것인가?


  멀티 패스 렌더링을 함으로 뭐가 가능한가? 이것은 딱 이거다 라고 할순 없지만 근래의 복잡하며 여러 장의 텍스처를 겹쳐서 사용하는 렌더링 표현에서는 필수 항목인 기술인 것은 확실하다.

특히 [ 동적으로 텍스처를 만드는 ] 이펙트에서 효과적이다

동적으로 만든다고 하면 포스트 이펙트 (렌더링한 그림에 뭉개기 효과나 세피아톤등으로 가공하는 후처리), 큐브 맵 생성, 거울 효과등등 여러가지 있을 것이다.


멀티 패스 렌더링에서의 또다른 장점은 버텍스 셰이더와의 균형이다.

버텍스 셰이더에서는 매우 복잡한 본 조작, 픽셀 셰이더에서의 라이트 처리를 위한 법선 설정, 

버텍스 변환등 귀찮은 것을 여러가지 수행한다.


싱글 패스 렌더링의 경우 매번 이 작업을 반복해야 하는 반면 멀티 패스 렌더링에서는 대부분의 버텍스 셰이더 작업을 1번으로 끝낼 수 있다. 이것은 퍼포먼스 향상으로 연결 된다.


멀티 패스 렌더링에서 뭐가 가능한가는 셰이더 프로그램을 배워가면 자연히 알게 되겠지만 연습을 위해 RGB 칼라와 알파 정보를 2개의 서피스( 하나는 백 버퍼)에 동시에 렌더링해보자



⑥ 멀티 패스 렌더링 예 -1:색과 알파 값을 동시에 렌더링


   이것은 DirectX 부록으로 있는 비행기 모델을 렌더링 한다.

이때 RGB 칼라와 알파 값을 분해 해어 별도의 텍스처로 한번 렌더링 한다.

그리고 이 결과를 교대로 화면에 렌더링 한다.

이것이 어디에 쓰이는가 보다는 멀티 패스 렌더링의 본질을 이해 하는데 집중해주길 바란다.)


○ 셰이더 프로그램

   우선은 셰이더 프로그램을 만든다. 목표는 픽셀 셰이더에서 렌더링 정보를 RGB와 알파값으로 분해하는 것이다


float4x4 WVP;   // WorldViewProjection Matrix

texture Tex;    // Texture
sampler2D TexSampler = sampler_state {  Texture = (Tex); };

struct OUTPUT_VS
{
    float4 pos      : POSITION;
    float2 texCoord : TEXCOORD0;
};

struct OUTPUT_PS
{
    float4 color : COLOR0;
    float4 alpha : COLOR1;
};

OUTPUT_VS SimpleVS( float4 inPos : POSITION, float2 inTexCoord : TEXCOORD0 )
{
    OUTPUT_VS outVS = (OUTPUT_VS)0;
    outVS.pos = mul( inPos, WVP );
    outVS.texCoord = inTexCoord;
    return outVS;
}

OUTPUT_PS RGBAndAlphaMPR_PS( float2 texCoord : TEXCOORD0 )
{
    OUTPUT_PS PSout = (OUTPUT_PS)0;
    PSout.color = tex2D( TexSampler, texCoord );
    PSout.alpha = PSout.color.a;
    PSout.alpha.a = 1.0f;
    return PSout;
}

technique RGBAndAlphaMPR
{
    pass p0
    {
        // 렌더 스테이트 설정
        AlphaBlendEnable = TRUE;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        ColorOp[0] = SELECTARG1;
        ColorArg1[0] = TEXTURE;
        ColorArg2[0] = DIFFUSE;
        AlphaOp[0] = SELECTARG1;
        AlphaArg1[0] = TEXTURE;
        AlphaArg2[0] = DIFFUSE;
        ColorOp[1] = DISABLE;
        AlphaOp[1] = DISABLE;

        // 셰이더
        VertexShader = compile vs_2_0 SimpleVS();
        PixelShader = compile ps_2_0 RGBAndAlphaMPR_PS();
    }
}

셰이더 프로그램 (RGBAndAlphaMPR.fx)


월드-뷰-프로젝션 행렬로써 WVP를 선언한다. 

다음으로 Tex는 모델의 입히는 텍스처이다

이것은 픽셀 셰이더에서 사용한다

sampler는 텍스처로부터 색을 취하는 형태이지만 이번엔 Tex로부터 얻을 수 있도록 설정하였다.

원래는 샘플링 방법등을 정의하지만 여기서는 간단하게 하기 위해 생략한다.


다음 OUTPUT_VS는 버텍스 셰이더의 반환값에 대한 구조체이다.

이번엔 변환후의 버텍스 단위와 텍스처 좌표(UV 좌표)가 필요하므로 위와 같이 설정한다.

그 다음에 있는 OUTPUT_PS가 여기에서의 핵심이다. 여기에는 2개의 COLOR가 설정되어있다.

OUTPUT_PS::alpha에 알파 정보가 저장되며, 이것이 렌더타겟 1번에 출력될 값이다.


SimpleVS 버텍스 셰이더는 딱히 무언가 하는 것은 아니다 입력된 로컬 버텍스를 WVP행렬을 사용해 스크린 좌표로 변환한다

UV좌표도 구조체에 복사해서 반환값을 전달 하고 있다


픽셀 셰이더에서는 넘어온 UV 좌표에 해당하는 텍셀(텍스처 좌표상의 픽셀)을 tex2D함수로 얻어온다.

이것은 픽셀 셰이더의 기본이다.


얻어온 색으로부터 알파값을 PSout.alpha에 대입하고 있다.

마지막으로 return에서 구조체를 반환한다.

이것으로 한번에 2개의 렌더 타겟에서 렌더링된다


○ 테크닉



technique RGBAndAlphaMPR

{
    pass p0
    {
        // 렌더 스테이트 설정
        AlphaBlendEnable = TRUE;
        SrcBlend = SRCALPHA;
        DestBlend = INVSRCALPHA;
        ColorOp[0] = SELECTARG1;
        ColorArg1[0] = TEXTURE;
        ColorArg2[0] = DIFFUSE;
        AlphaOp[0] = SELECTARG1;
        AlphaArg1[0] = TEXTURE;
        AlphaArg2[0] = DIFFUSE;
        ColorOp[1] = DISABLE;
        AlphaOp[1] = DISABLE;

        // 셰이더
        VertexShader = compile vs_2_0 SimpleVS();
        PixelShader = compile ps_2_0 RGBAndAlphaMPR_PS();
    }
}

테크닉 (RGBAndAlphaMPR.fx)


알파 블렌드를 유효하게 해야 하므로 AlphaBlendEnable을 TRUE로 이하 알파 블렌드를 구현하는 스탠다드한 설정을한다


○ 프로그램


 // 멀티 렌더 타겟 테스트


#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <math.h>

TCHAR gName[100] = _T("멀티 렌더 타겟");

#define SAFERELEASE(x) if(x){x->Release();}
#define FULLRELEASE \
       SAFERELEASE(pAlphaSurf);   \
       SAFERELEASE(pBackBuffer);  \
       SAFERELEASE(pEffect);      \
       SAFERELEASE(pErrorBuffer); \
       SAFERELEASE(pAirPlaneTex); \
       SAFERELEASE(pAirPlane);    \
       SAFERELEASE(pAlphaTex);    \
       SAFERELEASE(g_pD3DDev);    \
       SAFERELEASE(g_pD3D);

#define FAILEDCHECK(x) \
if(FAILED(x)) {        \
        FULLRELEASE;   \
       return 0;       \
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
   if(mes == WM_DESTROY || mes == WM_CLOSE ) {PostQuitMessage(0); return 0;}
   return DefWindowProc(hWnd, mes, wParam, lParam);
}


int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
   // 어플리케이션 초기화
   MSG msg; HWND hWnd;
   WNDCLASSEX wcex ={sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
                                    (HBRUSH)(COLOR_WINDOW+1), NULL, (TCHAR*)gName, NULL};
   if(!RegisterClassEx(&wcex))
      return 0;

   if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 640, 480,
                                    NULL, NULL, hInstance, NULL)))
      return 0;

   // Direct3D 초기화
   LPDIRECT3D9 g_pD3D;
   LPDIRECT3DDEVICE9 g_pD3DDev;
   if( !(g_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) ) return 0;

   D3DPRESENT_PARAMETERS d3dpp = {640,480,D3DFMT_UNKNOWN,0,D3DMULTISAMPLE_NONE,0,
                                                      D3DSWAPEFFECT_DISCARD,NULL,TRUE,TRUE,D3DFMT_D24S8,0,D3DPRESENT_RATE_DEFAULT,D3DPRESENT_INTERVAL_DEFAULT};

   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pD3DDev ) ) )
   {
      g_pD3D->Release();
      return 0;
   }

   D3DCAPS9 Caps;
   g_pD3DDev->GetDeviceCaps( &Caps );
   DWORD RT = Caps.NumSimultaneousRTs;
   if ( RT <= 1 ) {
       MessageBox( hWnd, _T("멀티 렌더 타겟을 지원하지 않습니다 종료합니다"), _T("그 외 에러"),0);
       g_pD3DDev->Release();
       g_pD3D->Release();
       return 0;
   }

   // 변수 정의
   ID3DXMesh *pAirPlane = 0;
   IDirect3DTexture9 *pAirPlaneTex = 0;
   IDirect3DTexture9 *pAlphaTex = 0;
   ID3DXEffect *pEffect = 0;
   ID3DXBuffer *pErrorBuffer = 0;
   IDirect3DSurface9 *pAlphaSurf = 0;
   IDirect3DSurface9 *pBackBuffer = 0;

   // 비행기 오브젝트 생성
   DWORD NumMaterials;
   FAILEDCHECK( D3DXLoadMeshFromX( _T("airplane 2.x"), D3DXMESH_MANAGED, g_pD3DDev, NULL, NULL, NULL, &NumMaterials, &pAirPlane) );
   FAILEDCHECK( D3DXCreateTextureFromFile( g_pD3DDev, _T("AirPlaneTex.png"), &pAirPlaneTex ) );

   // 이펙트 생성
   FAILEDCHECK( D3DXCreateEffectFromFile( g_pD3DDev, _T("RGBAndAlphaMPR.fx"), 0, 0, 0, 0, &pEffect, &pErrorBuffer) );

   // 알파용 텍스처 생성
   FAILEDCHECK( g_pD3DDev->CreateTexture( 640, 480, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pAlphaTex, 0 ) );

   // 렌더 타겟 세팅
   pAlphaTex->GetSurfaceLevel( 0, &pAlphaSurf );
   g_pD3DDev->SetRenderTarget( 1, pAlphaSurf );
   g_pD3DDev->GetRenderTarget( 0, &pBackBuffer );

   // 각 행렬 생성
   D3DXMATRIX WorldMat, ViewMat, ProjMat, WVP;
   D3DXMatrixIdentity( &WorldMat );
   D3DXMatrixPerspectiveFovLH( &ProjMat, D3DXToRadian(45), 640.0f/480.0f, 0.1f, 100.0f);

   ShowWindow(hWnd, nCmdShow);

   // 메시지 루프
   int count = 0;
   double angle = 0.0;
   do{
      Sleep(1);
      if( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ){ DispatchMessage(&msg);}

         g_pD3DDev->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(40,40,80), 1.0f, 0 );
         g_pD3DDev->BeginScene();

         // 뷰 회전
         angle += 0.01f;
         D3DXMatrixLookAtLH(
             &ViewMat,
             &D3DXVECTOR3((float)(10.0f*cos(angle)),5,(float)(10.0f*sin(angle))),
             &D3DXVECTOR3(0,0,0),
             &D3DXVECTOR3(0,1,0)
             );
         WVP = WorldMat * ViewMat * ProjMat;

         // 렌더 타겟 교환
        if ( count++ % 60 == 0 ) {
            IDirect3DSurface9 *pTmp = pAlphaSurf;
            pAlphaSurf = pBackBuffer;
            pBackBuffer = pTmp;
            g_pD3DDev->SetRenderTarget( 1, NULL );      // 이부분
            g_pD3DDev->SetRenderTarget( 0, pBackBuffer );
            g_pD3DDev->SetRenderTarget( 1, pAlphaSurf );
        }

         // 렌더 디바이스에 이펙트 세팅
         pEffect->SetMatrix("WVP", &WVP );
         pEffect->SetTexture("Tex", pAirPlaneTex );
         pEffect->SetTechnique( "RGBAndAlphaMPR" );
         unsigned int numPass;
         pEffect->Begin( &numPass, 0 );
         pEffect->BeginPass( 0 );
        unsigned int i;
        for( i = 0; i < NumMaterials; i++ )
             pAirPlane->DrawSubset( i );
        pEffect->EndPass();


         g_pD3DDev->EndScene();
         g_pD3DDev->Present( NULL, NULL, NULL, NULL );
   }while(msg.message != WM_QUIT);

   FULLRELEASE;

   return 0;
}

메인 프로그램(main.cpp)




반응형
반응형

BLOG main image




오브젝트들이 파이프라인을 통과하면서 최종 그려질 화면을 만들게 된다, D3D에서는 화면에 출력할때


중간의 끊김없이 화면을 보여주기 위해서 back buffer 와 front buffer 를 사용해 끊김을 해결하고있다


front buffer 에서는 화면에 보여주는 역할을 하게 되고 back buffer 에서는 그릴 화면을 저장하는 메모리용도로 사용한다



이때 back buffer 에서 front buffer 로 스위치되면서 화면에 출력되는 시간단위를 '프레임' 이라고 한다


현재 게임에선 프레임이 1초에 몇번 스위치 됐는지를 계산해 FPS로 계산한다




또한 D3D에서는 보여질 버퍼를 텍스처에 쓸 수 있게도 지원한다, 즉 메모리에 화면을 출력할 수 있도록 허용하며


그 출력 대상은 텍스처가 될 수도 있다, 이때 그려지는 대상이 되는 텍스처의 명칭을 렌더타겟이라고 한다




이로써 Shader 에서 멀티패스로 다양한 효과처리가 가능해지게 된다



반응형
반응형

http://www.kwxport.org/


kW X-port 3ds Max X file exporter

For some reason, users are getting "cannot display page" and "content decoding" errors on this kw X-port plugin site. It 
works in FireFox, but not in Chrome or IE9. I have no idea why -- perhaps Drupal, or one of the plug-ins I'm using, is 
generating bad UTF-8? Or maybe Dreamhost changed proxies and suddenly something is broken. I simply don't have 
the time to run this site any longer -- it's bad enough that I still haven't updated the exporter to 3ds Max version 
2012.

Any year now -- Real Soon Now -- Promise!)

So, my drastic fix is this: You can read this text. You can download the installers. However, all the log-in and forums 
and contact-me functionality is gone. This is pretty much a static web page now! If you need to talk to me, try 
tweeting @jwatte or contacting me as hplus0603 on gamedev.net.


Source code access should still work. Try the following:

svn co http://svn.kwxport.org/kwxport kwxport

Also, the ads weren't really making me any money, so they're gone, too. If it had been wildly successful, I imagine 

I'd have had more time to run the site itself :-)


반응형
반응형

http://blog.naver.com/frustum/150008165621





이 문서의 저작권은 김용준( http://3dstudy.net )에게 있습니다.
상업적인 이용을 금지합니다.

 

제목 : ‘DirectX 9.0 셰이더 프로그래밍’

 

2부 고수준 셰이더 언어(High Level Shader Language)
DirectX 8.0부터 소개된 셰이더는 그 강력한 능력을 빠르게 3D프로그래밍 기술의 주류시장을 잠식해 들어가고 있다. 그러나, 8.0에서의 셰이더 프로그래밍은 불편한 어셈블러였기 때문에 개발자들을 상당히 힘들게했던 것이 사실이다. 이번에 DirectX 9.0에 포함된 HLSL을 사용해서 고수준의 셰이더를 제작해 보도록 하자.

 

1장 문법
셰이더는 기본적으로 C언어를 기반으로 하고 있으므로, C언어에 대한 이해를 필수이다. 여기서는 독자들이 C언어를 이미 알고있다고 가정하고 설명을 진행해 나가도록 하겠다. 그러나, C언어를 잘 모르는 독자라도 베이직등의 기본언어를 한번이라도 익혀본 독자라면 HLSL을 이해하는데 별로 무리가 없을 것이다. HLSL의 문법은 그만큼 쉽기 때문이다.

 

1절 자료형(data types)
HLSL은 많은 자료형을 지원하는데, 간단한 불린, 정수, 부동소수부터 벡터, 행렬, 구조체 처럼 확장된 자료형까지도 지원한다.

 

우리가 이번에 살펴볼 내용은 다음과 같다.
• 스칼라 형(Scalar Types)
• 변수 선언(Declaring a Variable)
• 형 변경자(Type Modifiers)
• 지억부류 변경자(Storage Class Modifiers)
• 벡터 형(Vector Types)
• 행렬 형(Matrix Types)
• 객체 형(Object Types)
• 구조체 형(Structure Types)
• 사용자정의 형(User-Defined Types)
• 형 변환(Type Casts)
• 변수(Variables)
• 구성성분 접근과 뒤섞기(Component Access and Swizzles)

 

1.1 스칼라 형(Scalar Types)
다음과 같은 스칼라 형을 지원한다.
 
bool : true 혹은 false    
int : 32비트 부호있는 정수    
half : 16비트 부동소수    
float : 32비트 부동소수    
double : 64비트 부동소수 


모든 타겟 플랫폼이 정수형을 지원하지는 않기 때문에 하드웨어에서 float를 사용해서 에뮬레이션 될 수도 있으며, 만약 정수형의 범위를 넘어서는 값이 있다면 이 값을 사용한 함수는 정확하게 작동하지 않을 수도 있다. 마찬가지로 half와 double역시 지원되지 않을 경우에는 float를 사용하여 에뮬레이션 된다.

 

1.2 변수 선언(Declaring a Variable)
C언어와 마찬가지로 변수를 선언한다. 다음은 fVar이라는 부동소수 변수를 선언한 것이다.
float fVar; 

 

특정한 값으로 선언과 동시에 초기화를 할 수도 있다. 
float fVar = 3.1f; 

 

배열형태로 선언하는 것도 가능하다. 
int iVar[3]; 

 

배열 선언과 동시에 초기화는 다음과 같이 한다. 
int iVar[3] = {1,2,3}; 


1.3 형 변경자(Type Modifiers)
형 변경자는 변수형의 바로앞에 붙어서 컴파일러에 추가적인 정보를 제공해주는 선택적 명령어이다. 다음과 같은 명령어가 있다.
• const
• row_major
• col_major

 

1.3.1 const
const는 변수가 상수임을 나타내는 명령어로서 셰이더 실행중에 값이 바뀌지 않는 다는 것을 나타낸다. 변수를 const로 선언하면 컴파일러는 변수를 쓰기접근이 불가능한 메모리 영역에 넣는다. 당연히 값을 바꿀 수 없으므로, 선언과 동시에 초기화가 되어야 한다.
const float fConstant = 0.2f; 


프로그램에 의해서 변화가 가능한 셰이더 상수는 static변경자를 사용하지 않은 전역변수이다. static에 대한 자세한 내용은 '1.4 지억부류 변경자(Storage Class Modifiers)'를 참고하자.

 

1.3.2 row_major, col_major
행렬성분은 행위주(row-major)나 열위주(column-major)방식으로 구성된다. 열위주란 행렬의 한 열이 하나의 상수레지스터에 보관되는 방식이며, 행위주는 행렬의 각 행이 하나의 레지스터에 보관되는 방식이다.
row_major float4x4 worldMatrix; 

 

행위주 행렬은 다음과 같이 놓이게 된다. 
11 12 13 14 
21 22 23 24 
31 32 33 34 
41 42 43 44    


col_major float4x4 transposedWorldMatrix; 

 

열위주 행렬은 다음과 같이 놓이게 된다. 
11 21 31 41 
12 22 32 42 
13 23 33 43 
14 24 34 44  

row_major와 column_major명령어는 행렬이 상수테이블이나 셰이더 입력으로부터 읽혀질때만 효력이 있으며, 행렬성분이 HLSL코드안에서 사용되는 데에는 아무런 효력이 없다.

 

1.4 지억부류 변경자(Storage Class Modifiers)
기억부류 변경자는 변수의 생성소멸시점과 접근범위를 컴파일러에게 지정해주는 역할을 한다. 단, 셰이더 전연벽수는 셰이더의 가장 앞머리에서 선언되어야 한다.(함수의 바깥쪽)


float globalShaderVariable;

void function()
{
  float localShaderVariable;
  ... 

 

HLSL은 다음과 같은 기억부류 변경자를 지원한다.
• static
• extern
• uniform
• shared

 

1.4.1 static
전역범위볼때 static은 다른 프로그램에서 이 변수에 접근할 수 없도록 한다. GetVertexShaderConstantx()나 SetVertexShaderConstantx(), ID3DXConstantTable을 통해서 이 변수에 접근 할 수 없다.


static float fConstant_Hidden_From_the_App = 0.2f; 

 

지역범위에서 볼때(함수의 내부에 선언될때) static은 다르게 해석되는데, 처음 함수가 실행되고 나서도 그 값이 계속 유지된다는 의미이다.

 

1.4.2 extern
extern은 static의 반대되는 의미이다. extern변수는 셰이더의 바깥에서 값이 설정되어야 한다. 전역변수는 extern과 static이 동시에 선언될 수 없다.


extern float4 fogColor; 

 

extern변수에 값을 설정하기 위해서는 SetVertexShaderConstantx()나 ID3DXConstantTable을 사용한다. 전역변수가 extern이나 static중 어느쪽도 지정되지 않았다면, 컴파일러는 extern으로 가정한다.

 

1.4.3 uniform
uniform변수는 API함수를 사용해서 화면에 그려질때만 값이 바뀔수 있다.


uniform float fConstant_Between_Draw_Calls = 0.2f; 

 

이 말은 일단 값이 설정되면, 모든 정점들(정점셰이더)이나 픽셀들(픽셀셰이더)에서 초기설정값이 일정하게 계속 유지된다는 뜻이다.

 

1.4.4 shared
effect들간에 공유될 전역변수에는 shared를 사용한다.


shared float sharedAlphaValue 

 

1.5 벡터 형(Vector Types)
벡터형은 하나 혹은 4개의 구성성분를 가진 특별한 자료 구조체이다.
 
bool    bVector;   // 1개의 Boolean값을 가진 스칼라
bool1   bVector;   // 1개의 Boolean값을 가진 벡터
int1    iVector;   // 1개의 int값을 가진 벡터
half2   hVector;   // 2개의 half값을 가진 벡터
float3  fVector;   // 3개의 float값을 가진 벡터
double4 dVector;   // 4개의 double값을 가진 벡터 

 

자료형의 바로뒤에 붙은 숫자가 벡터의 구성성분 개수를 나타낸다.

 

물론, 선언과 동시에 초기화도 가능하다.
bool    bVector = false;
int1    iVector = 1;
half2   hVector = { 0.2, 0.3 };
float3  fVector = { 0.2f, 0.3f, 0.4f };
double4 dVector = { 0.2, 0.3, 0.4, 0.5 }; 


vector라는 명령어를 사용해서 동일한 선언을 할수도 있다.
vector <bool,   1> bVector = false;
vector <int,    1> iVector = 1;
vector <half,   2> hVector = { 0.2, 0.3 };
vector <float, 3> fVector = { 0.2f, 0.3f, 0.4f };
vector <double, 4> dVector = { 0.2, 0.3, 0.4, 0.5 };  

vector형은 <>을 사용해서 자료형과 구성성분의 개수를 지정한다.

 

1.5.1 벡터 구성성분 접근하기
벡터는 4개의 구성성분을 가질수 있는데, 각각의 성분은 2가지 명명집합(naming set)을 사용해서 접근할 수 있다.

 

• 위치값 방식: x,y,z,w
• 컬러값 방식: r,g,b,a

 

다음의 소스는 모두 3번째 벡터성분의 값을 읽어온다. 
float4 pos = float4(0,0,2,1);
pos.z    // 값은 2
pos.b    // 값은 2 

 

명명집합은 한 개 이상의 성분을 사용할 수 있지만, 섞을 수는 없다. 
float4 pos = float4(0,0,2,1);
float2 temp;
temp = pos.xy  // 유효
temp = pos.rg  // 유효
temp = pos.xg  // 오류! 위치값 방식과 컬러값 방식은 섞어서 사용할 수 없다. 

 

1.5.2 벡터 구성성분 뒤섞기(swizzle)
값을 읽을 때 하나 혹은 그 이상의 구성성분을 지정하는 것을 뒤섞기라고 한다.
float4 pos = float4(0,0,2,1);
float2 f_2D;
f_2D = pos.xy;   // 2개의 값을 읽는다
f_2D = pos.xz;   // 어떠한 순서로 읽어도 상관없다
f_2D = pos.zx;

f_2D = pos.xx;   // 같은 값을 한번이상 읽는것도 가능하다
f_2D = pos.yy; 

 

1.5.3 벡터 구성성분 마스킹
마스킹은 몇개의 값이 쓰여질 것인지를 조절한다.
float4 pos = float4(0,0,2,1);
float4 f_4D;
f_4D    = pos;     // 4개의 성분을 쓴다

f_4D.xz = pos.xz;  // 2개의 성분을 쓴다
f_4D.zx = pos.xz;  // 쓰기 순서를 바꾼다

f_4D.xzyw = pos.w; // 하나의 성분을 여러 개에 쓸 수도 있다
f_4D.wzyx = pos; 

 

다음처럼 하나의 값에 두개의 값을 쓸수는 없다.
f_4D.xx = pos.xy;   // 오류! 

 

구성성분의 명명집합을 섞어서 사용할 수 없다.
f_4D.xg = pos.rgrg; // 오류! 

 

1.5.4 벡터 수학
HLSL은 표준수학 표기법과 약간 다른데, 그 이유는 연산자가 구성 성분별로 정의되기 때문이다. 예를들어서 float4 v = a*b 는 다음문장과 동일한 문장이다.
float4 v;

v.x = a.x*b.x;
v.y = a.y*b.y;
v.z = a.z*b.z;
v.w = a.w*a.w; 

 

이것은 4개의 구성성분 곱셈이며, 내적이 아니다. 내적은 •(a,b)로 표기한다. 두 연산의 차이를 비교해 보면 다음과 같다.


// 4개성분 벡터 곱셈의 첫번째 성분
a.x * b.x = a.x*b.x

 

// 4개성분 내적의 첫번째 성분
a.x • b.x = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; 

 

행렬도 구성성분별 연산을 사용한다.
float3x3 mat1,mat2;
...   
float3x3 mat3 = mat1*mat2;  

이것은 행렬곱이 아니라, 두 행렬의 구성성분별 곱셈이다.


// 구성성분별 행렬 곱셈
mOne._m00 * mTwo._m00 = mOne._m00 * mTwo._m00; 

 

행렬곱은 mul()이라는 내부함수를 사용한다.
float3x3 mat1,mat2;
...
float3x3 mat3 = mul(mat1,mat2); 

 

다음은 두 행렬의 적(product)이다.
// 4개성분 행렬 곱셈의 첫번째 성분
mul(mOne._m00, mTwo._m00) = mOne._m00 * mTwo._m00 + mOne._m01 * mTwo._m10
                           +  mOne._m02 * mTwo._m20 + mOne._m03 * mTwo._m30; 

 

중복지정된 mul()함수는 벡터와 행렬간의 곱셈을 수행한다.
예) vector * vector, vector * matrix, matrix * vector, matrix * matrix

 

다음 소스는 동일한 역할을 한다.
float4x3 World;

float4 main(float4 pos : POSITION) : POSITION
{
    float4 val;
    val.xyz = mul(pos,World);
    val.w = 0;

    return val;

 

float4x3 World;

float4 main(float4 pos : POSITION) : POSITION
{
    float4 val;
    val.xyz = (float3) mul((float1x4)pos,World);
    val.w = 0;

    return val;
 
이 예제는 pos벡터를 (float1x4)형변환을 사용해서 열벡터로 변환한다. 벡터를 형변환하거나, mul()함수에 전달되는 인수의 순서를 바꾸는 것은 행렬을 전치(transpose)하는 것과 같다.

 

자동형변환의 결과로 다음의 예제는 mul()과 dot()함수가 같은 결과를 반환하게 된다.
{
  float4 val;
  return mul(val,val);
}
mul()의 결과는 1x4 * 4x1 = 1x1벡터이다.  

 

{
  float4 val;
  return dot(val,val);
}
내적의 반환값은 하나의 스칼라 값이다. 

 

1.6 행렬 형(Matrix Types)
행렬은 행과 열을 가진 자료형이다. 행렬의 구성성분은 어떠한 스칼라 값도 가능하지만, 모든 구성성분은 동일한 자료형이어야 한다. 행과 열의 개수는 "행x열"의 형태로 자료형의 뒤에 추가된다.
int1x1    iMatrix;   // 1행1열의 int행렬
int2x1    iMatrix;   // 2행1열의 int행렬
...
int4x1    iMatrix;   // 4행1열의 int행렬
...
int1x4    iMatrix;   // 1행4열의 int행렬


double1x1 dMatrix;   // 1행1열의 double행렬
double2x2 dMatrix;   // 2행2열의 double행렬
double3x3 dMatrix;   // 3행3열의 double행렬
double4x4 dMatrix;   // 4행4열의 double행렬 

단, 행과 열의 최대 값은 4이며, 최소값은 1이다.

 

행렬은 선언과 동시에 초기화 될 수 있다.
float2x2 fMatrix = { 0.0f, 0.1, // 1행
                     2.1f, 2.2f // 2행 }; 

 

혹은 matrix라는 명령어를 사용해서 동일한 선언을 할 수도 있다.
matrix <float, 2, 2> fMatrix = { 0.0f, 0.1, // 1행
                                   2.1f, 2.2f // 2행 }; 

 

이 예제는 부동소수형의 2행 2열짜리 행렬을 생성한 것이다.
matrix형도 vector와 마찬가지로 <>을 사용해서 자료형과 구성성분의 개수를 지정한다.

 

다음 선언은 2행 3열의 half자료형 행렬을 정의한다.
matrix <half, 2, 3> fHalfMatrix; 

 

1.6.1 행렬성분 접근
행렬의 성분은 구조체 연산자인 "."을 통해서 접근가능한데, 2가지의 명명집합을 지원한다.


첨자가 0부터 시작하는 방식

_m00, _m01, _m02, _m03
_m10, _m11, _m12, _m13
_m20, _m21, _m22, _m23
_m30, _m31, _m32, _m33

 

 첨자가 1부터 시작하는 방식 

 _11, _12, _13, _14
_21, _22, _23, _24
_31, _32, _33, _34
_41, _42, _43, _44    


각각의 명명집합은 밑줄("_") 바로뒤에 행과 열의 숫자를 적어주면 된다. 첨자가 0부터 시작하는 명명집합은 앞에 "m"자를 붙여준다.

 

2개의 명명집합을 사용한 접근방식 예제를 보도록 하자.
float2x2 fMatrix = { 1.0f, 1.1f, // 1행
                     2.0f, 2.1f  // 2행 };

float f_1D;
f_1D = matrix._m00; // 1행 1열의 값 : 1.0
f_1D = matrix._m11; // 2행 2열의 값 : 2.1

f_1D = matrix._11;  // 1행 1열의 값 : 1.0
f_1D = matrix._22;  // 2행 2열의 값 : 2.1 

 

벡터와 마찬가지로, 명명집합은 하나이상의 성분을 동시에 사용할 수 있다.
float2x2 fMatrix = { 1.0f, 1.1f, // 1행
                     2.0f, 2.1f  // 2행 }; 
float2 temp;

temp = fMatrix._m00_m11 // 유효
temp = fMatrix._m11_m00 // 유효
temp = fMatrix._11_22   // 유효
temp = fMatrix._22_11   // 유효 

 

1.6.2 행렬의 배열접근
행렬은 첨자가 0으로 시작하는 배열표기법을 사용해서 접근할 수도 있다. 4x4행렬은 배열방식을 사용하면 다음과 같이 구성되어 있다.
[0][0], [0][1], [0][2], [0][3]
[1][0], [1][1], [1][2], [1][3]
[2][0], [2][1], [2][2], [2][3]
[3][0], [3][1], [3][2], [3][3]
 

 

행렬에 접근하는 예제를 보도록 하자.
float2x2 fMatrix = { 1.0f, 1.1f, // 1행
                     2.0f, 2.1f  // 2행 };
float temp;

temp = fMatrix[0][0] // 성분 하나 읽기
temp = fMatrix[0][1] // 성분 하나 읽기 

 

구조체 연산자인 "."이 사용되지 않았다는 것을 명심하자. 배열표기법은 하나이상의 값을 읽기위해서 뒤섞기(swizzle)를 사용할 수 없다.
float2 temp;
temp = fMatrix[0][0]_[0][1] // 오류! 2개의 성분을 읽을수 없다. 

 

그러나, 배열접근은 다중성분벡터를 읽을 수 있다.
float2 temp;
float2x2 fMatrix;
temp = fMatrix[0] // 첫번째 행을 읽는다 

 

1.6.3 행렬요소 뒤섞기(Swizzling)
벡터처럼, 행렬도 하나이상의 성분을 읽는 것을 뒤섞기라고 한다.
float4x4 worldMatrix = float4( {0,0,0,0}, {1,1,1,1}, {2,2,2,2}, {3,3,3,3} );
float4x4 tempMatrix;
float2  tempFloat; 

 

다음과 같은 대입은 유효한 대입연산이다.
tempMatrix._m00_m11 = worldMatrix._m00_m11; // 다중 성분
tempMatrix._m00_m11 = worldMatrix.m13_m23;

tempMatrix._11_22_33 = worldMatrix._11_22_33; // 뒤섞기 순서도 마음대로
tempMatrix._11_22_33 = worldMatrix._24_23_22; 

 

1.6.4 행렬성분 마스킹
몇개의 성분이 쓰여질 것인지를 제어하는 것을 마스킹이라고 한다.
float4x4 worldMatrix = float4( {0,0,0,0}, {1,1,1,1}, {2,2,2,2}, {3,3,3,3} );
float4x4 tempMatrix;

tempMatrix._m00_m11 = worldMatrix._m00_m11; // 2개의 성분 쓰기
tempMatrix._m23_m00 = worldMatrix.m00_m11; 

 

다음처럼 하나의 성분에 2개의 성분을 대입할 수 없다.
tempMatrix._m00_m00 = worldMatrix.m00_m11; // 오류! 

 

다음처럼 명명집합을 섞어서 사용할 수 없다.
tempMatrix._11_m23 = worldMatrix._11_22; // 오류! 

 

1.6.5 행렬 순서
행렬결합순서(matrix packing order)는 uniform인 경우 기본적으로 열위주(column-major)방식이다. 이 말은 행렬의 각 열이 하나의 상수 레지스터에 보관된다는 뜻이다. 행위주(row-major) 행렬결합은 각행이 하나의 상수레지스터에 저장된다.

 

행렬결합은 #pragma pack_matrix를 사용하거나, row_major, col_major명령을 사용해서 바꿀 수 있다.

 

일반적으로 열위주 행렬이 행위주 행렬보다 효율적인데, 다음 예제를 보면 이유를 알 수 있을 것이다.

 

<HLSL코드> 
// 열위주 행렬결합
float4x3 World;

float4 main(float4 pos : POSITION) : POSITION
{
    float4 val;
    val.xyz = mul(pos,World);
    val.w = 0;

    return val;
}

 

<컴파일한 어셈블리 코드 >

vs_2_0
def c3, 0, 0, 0, 0
dcl_position v0
m4x3 oPos.xyz, v0, c0
mov oPos.w, c3.x
// 4개의 명령슬롯 사용    

[표 1-1] 열위주 결합

 

<HLSL코드>
// 행위주 행렬결합
#pragma pack_matrix(row_major)

float4x3 World;

float4 main(float4 pos : POSITION) : POSITION
{
    float4 val;
    val.xyz = mul(pos,World);
    val.w = 0;

    return val;

 

<컴파일한 어셈블리 코드 >

vs_2_0
def c4, 0, 0, 0, 0
dcl_position v0
mul r0.xyz, v0.x, c0
mad r2.xyz, v0.y, c1, r0
mad r4.xyz, v0.z, c2, r2
mad oPos.xyz, v0.w, c3, r4
mov oPos.w, c4.x
// 5개의 명령슬롯 사용    
[표 1-2] 행위주 결합

 

2개의 어셈블리 코드를 비교해 보면 알 수 있지만, 열위주 행렬결합방식을 사용하면 명령슬롯이 더 절약되며, 사용하는 상수 레지스터의 개수도 적다.

 

1.7 객체 형(Object Types)
HLSL에서 지원하는 객체 형은 다음과 같은 것들이 있다.
• 샘플러(sampler)
• 구조체(structure)
• 문자열(string)
• 정점셰이더 객체(vertex shader object)
• 픽셀셰이더 객체(pixel shader object)
• 텍스처(texture)

 

1.7.1 샘플러(sampler)
샘플러는 샘플러 상태(sampler state)를 포함하고 있는데, 샘플러 상태란 샘플링될 텍스처를 정하고, 샘플링중에 사용할 필터링 방법을 정하는 것으로 다음의 3가지가 필요하다.
• 텍스처
• 샘플러
• 샘플링 명령

 

다음은 2차원 텍스처 샘플링을 하는 예제이다.
texture tex0;
sampler2D s_2D;

float2 sample_2D(float2 tex : TEXCOORD0) : COLOR
{
  return tex2D(s_2D, tex);
 

텍스처는 texture형의 tex0라는 이름으로 선언되며, 이 예제에서, s_2D라는 샘플러변수는 sampler2D형과 sampler_state명령으로 선언되었다. 샘플러는 샘플러 상태를 {}안에 포함하게 되는데, 여기에는 샘플링될 텍스처와 랩핑모드, 필터모드 등의 필터상태가 포함된다. 만약, 샘플러 상태가 생략되면, 기본 상태 선형필터링과 랩모드가 적용된다.

 

다음은 기본 샘플러 상태와 필터, 텍스처 주소 모드를 선택한 예이다.
texture tex0;
sampler3D s_3D;

float3 sample_3D(float3 tex : TEXCOORD0) : COLOR
{
  return tex3D(s_3D, tex);

 

이것은 입방체 맵핑 텍스처 샘플러이다.
texture tex0;
samplerCUBE s_CUBE;

float3 sample_CUBE(float3 tex : TEXCOORD0) : COLOR
{
  return texCUBE(s_CUBE, tex);

 

샘플러 상태 설정 중에서 밉맵필터를 선형(LINEAR)로 설정한 것이다.
sampler s = sampler_state { texture = NULL; mipfilter = LINEAR; }; 

 

마지막으로 1차원 샘플러를 보도록 하자.
texture tex0;
sampler1D s_1D;

float sample_1D(float tex : TEXCOORD0) : COLOR
{
  return tex1D(s_1D, tex);

 

DirectX 런타임이 1차원 텍스처를 지원하지 않기 때문에, 컴파일러는 y좌표을 무시하는 2차원 텍스처를 생성할 것이다. 결국, tex1D가 2차원 텍스처 탐색방법을 사용하기 때문에 컴파일러는 y좌표를 효율적으로 다루는 방법을 선택하게 된다. 조금 드문 경우지만, 컴파일러가 y항을 효율적으로 처리하는 방법을 선택할 수 없으면 경고를 발생시킨다.

 

다음의 특별한 예제는 컴파일러가 입력 좌표를 다른 레지스터로 옮겨야 하기 때문에 비효율적이다. (1차원 텍스처 검색은 2차원 검색으로 이루어지는데, 텍스처 좌표가 float1으로 선언되었기 때문이다.)만약 코드가 float2로 쓰여져 있다면 컴파일러는 y좌표를 뭔가 적절하게 초기화해서 텍스처 좌표를 사용할 수 있을 것이다.
texture tex0;
sampler s_1D_float;

float4 main(float texCoords : TEXCOORD) : COLOR
{
    return tex1D(s_1D_float, texCoords);

 

모든 텍스처 검색에는 bias나 proj가 추가될수 있다.(즉, tex2Dbias 혹은 texCUBEproj같은 방식). proj가 접미사가 붙으면 텍스처좌표는 w-성분으로 나눠지게 되고, bias가 붙으면 밉맵 단계가 w성분에 의해서 이동한다. 즉, 접미사가 붙은 모든 텍스처 검색은 float4형식의 입력이 필요하다는 것이다. tex1D와 tex2D는 각각 yz요소와, z요소를 무시한다.

 

샘플러는 또한 배열형태로 사용될 수도 있는데, 아직까지는 샘플러의 동적배열 형태를 지원하지는 않는다. 즉, tex2D(s[0],tex)는 컴파일 시에 값을 결정 할 수 있으므로 유효하지만, tex2D(s[a],tex)는 불가능하다는 얘기다. 샘플러의 동적 접근은 주로 루프를 다루는 코드 작성시에 매우 유용하다. 다음 코드를 보도록 하자.
sampler sm[4];

float4 main(float4 tex[4] : TEXCOORD) : COLOR
{
    float4 retColor = 1;

    for(int i = 0; i < 4;i++)
    {
        retColor *= tex2D(sm[i],tex[i]);
    }

    return retColor;

 

1.7.2 구조체(structure)
struct명령어는 구조체형을 정의한다.

 

다음 구조체는 위치값과 법선값, 2개의 멤버를 포함한다.
struct vertexData 
{ 
    float3 pos;
    float3 normal;
}; 

 

모든 HLSL기본 자료형은 구조체에서 사용할 수 있으며, 멤버변수에 접근하기 위해서는 "."연산자를 사용한다.
struct vertexData data = { { 0.0, 0.0, 0.0 }, 
                           { 1.1, 1.1, 1.1 } 
                         };
data.pos = float3(1,2,3);
data.pos = {1,2,3};
float3 temp = data.normal; 

 

구조체가 일단 정의되면, struct명령어가 없어도 이름에 의해서 참조할 수 있다.
vertexData main(vertexData in) 
{ 
    ... // 어쩌구 저쩌구
    return in;
}; 

 

구조체 멤버는 초기값을 가질수 없으며, 또한 static, extern, volatile, const등의 접근범위 명령어를 사용해서 개별적으로 선언될 수 없다.

 

1.7.3 문자열(String)
아스키 문자열, 문자열을 받아들이는 연산이나 상태는 없다. 문자열과 주석문은 effect에서만 사용될 수 있다.

 

1.7.4 정점셰이더 객체(Vertex Shader Object)
vertexshader 자료형은 정점셰이더 객체를 나타내는데, HLSL셰이더가 컴파일 되거나, 어셈블리 셰이더가 어셈블될때 대입된다.

<어셈블리  셰이더> 
vertexshader vs = 
  asm 
  { 
    vs_2_0 
    dcl_position v0
    mov oPos, v0 
  };  

 

<HLSL 셰이더 >

vertexshader vs=compile vs_2_0 vsmain();    
 

1.7.5 픽셀셰이더 객체(Pixel Shader Object)
pixelshader 자료형은 정점셰이더 객체를 나타내는데, HLSL셰이더가 컴파일 되거나, 어셈블리 셰이더가 어셈블될때 대입된다.
<어셈블리 셰이더> 
pixelshader ps = 
  asm 
  { 
    ps_2_0 
    mov oC0, c0 
  }; 

 

<HLSL 셰이더 >

pixelshader ps = compile ps_2_0 psmain();    


1.7.6 텍스처(Texture)
texture자료형은 텍스처 객체를 나타낸다. 이 자료형은 effect에서 텍스처를 디바이스에 설정하기 위해서 사용된다.
texture tex0; 


이 정의는 다음과 같은 의미를 갖는다.
• 텍스처 형
• 변수명은 tex0

 

일단 텍스처변수가 선언되면, 샘플러에 의해서 참조될 수 있다. 
texture tex0;
sampler Sampler_1D;
{
  texture = (tex0);
}; 

 

1.8 구조체 형(Structure Types)
struct명령어는 구조체 형을 정의할때 사용하며, 구조체가 정의되면 ID를 통해서 접근할 수 있다.
struct [id] { member_list } 

 

member_list는 하나 이상의 멤버 선언으로 구성되는데, 초기값을 가질수 없으며, 또한 static, extern, volatile, const등의 접근범위 명령어를 사용해서 개별적으로 선언될 수 없다.

 

1.9 사용자정의 형(User-Defined Types)
typedef라는 명령어는 형의 이름을 정의할 때 사용하는데, const를 사용해서 상수형 임을 명시할 수도 있다. 배열 접미사는 각 ID뒤에 붙을 수 있으며, 일단 형이 선언되면, ID를 사용해서 참조할 수 있다.
typedef [const] type id [array_suffix] [, id ...] ; 


배열접미사는 하나이상의 [정수]형태로 구성되어, 차원을 나타낸다.

 

D3DX 8.0과의 호환성을 위해서 다음과 같은 형들은 전역범위로 대소문자 구분없이 미리 선언되어 있다. 
typedef int DWORD;
typedef float FLOAT; 
typedef vector <float, 4> VECTOR;
typedef matrix <float, 4, 4> MATRIX;
typedef string STRING;
typedef texture TEXTURE;
typedef pixelshader PIXELSHADER;
typedef vertexshader VERTEXSHADER; 

 

편의를 위해서 다음과 같은 형들도 전역범위로 미리 선언되어 있다. 여기서 #은 1~4 사이의 정수값이다. 
typedef vector <bool, #> bool#;
typedef vector <int, #> int#;
typedef vector <half, #> half#;
typedef vector <float, #> float#;
typedef vector <double, #> double#;

typedef matrix <bool, #, #> bool#x#;
typedef matrix <int, #, #> int#x#;
typedef matrix <half, #, #> half#x#;
typedef matrix <float, #, #> float#x#;
typedef matrix <double, #, #> double#x#; 

 

1.10 형 변환(Type Casts)
다음과 같은 형 변환이 지원된다.
 
스칼라-스칼라 : 항상 가능. 불린형을 정수나 부동소수로 형변환 할 경우, false는 0, true는 1로 간주한다. 정수나 부동소수를 불린으로 형변환 할 경우에는 0이 false, 0이 아닌값이 true이다. 부동소수를 정수로 형변환 할 때는 소수점 이하는 0으로 짤린다.   


스칼라-벡터 : 항상 가능. 스칼라 값을 벡터에 구성요소들에 복제해 넣는다.   


스칼라-행렬 : 항상 가능. 스칼라 값을 벡터에 구성요소들에 복제해 넣는다.   


스칼라-객체 : 불가능   


스칼라-구조체 : 구조체의 모든 멤버가 숫자라면 가능. 스칼라 값을 벡터에 구성요소들에 복제해 넣는다.   


벡터-스칼라 : 항상 가능. 벡터의 첫번째 성분을 선택한다.   


벡터-벡터 : 대상벡터가 원본벡터보가 크면 안된다. 가장 좌측에 있는 값들부터 보관하고 나머지를 자른다. 이 형변환을 위해서 행-행렬(column matrix)과 열-행렬(row matrix), 수치 구조체는 벡터로 다뤄진다.   


벡터-행렬 : 벡터의 크기가 행렬의 크기와 일치해야 한다.   


벡터-객체 : 불가능   


벡터-구조체 : 구조체가 벡터보다 크지 않으며, 구조체의 구성요소가 수치형이면 가능.   


행렬-스칼라 : 항상 가능. 행렬의 좌측상단을 선택한다.   


행렬-벡터 : 행렬의 크기가 벡터의 크기와 일치해야 한다.   


행렬-행렬 : 두개의 차원 모두 대상 행렬이 원본행렬보다 크면 안된다. 좌측상단의 값들부터 보관하고, 나머지를 버린다.   


행렬-객체 : 불가능   


행렬-구조체 : 구조체의 크기가 행렬과 같아야 하며, 구조체의 모든 구성요소가 수치형이어야 한다.   


객체-스칼라 : 불가능   


객체-벡터 : 불가능   


객체-행렬 : 불가능   


객체-객체 : 객체형이 동일하면 가능   


객체-구조체 : 구조체는 하나이상의 멤버를 갖고 있으면 안된다. 구조체 멤버의 형이 객체와 동일해야 한다.   


구조체-스칼라 : 구조체는 적어도 하나의 수치형 멤버를 가져야 한다.   


구조체-벡터 : 구조체는 적어도 벡터의 크기여야 한다. 첫번째 구성요소는 벡터의 크기보다 큰 수치형이어야 한다.

    
구조체-행렬 : 구조체는 적어도 행렬의 크기여야 한다. 첫번째 구성요소는 행렬으 크기보다 큰 수치형이어야 한다.

    
구조체-객체 : 구조체는 적어도 하나의 멤버를 포함하고 있어야 한다. 구조체의 멤버는 객체와 동일해야 한다.   


구조체-구조체 : 대상구조체는 원본구조체보다 크면 안된다. 각각의 원본과 대상 구성요소간의 형변환 가능성에 달려있다. 

 

1.11 변수(Variables)
변수는 다음과 같이 선언한다.
[static uniform extern shared volatile] [const] 
type id [array_suffix] [: semantic] [= initializers] [annotations] [, id ...] ; 

 

변수 선언 앞에 static명령어를 붙일 수 있는데, 전역변수에 붙으면 이 변수가 셰이더 외부에서 접근할수 없다는 뜻이고, 지역변수에 사용되면 함수호출뒤에서 계속 값이 유효하다는 것이다. 지역 static변수는 오직 한번만 초기화되며, 명시적인 초기값이 없다면 0으로 가정한다.

 

• 전역 변수 선언 앞에 uniform을 붙이면, 셰이더에게 uniform입력임을 나타내주는 것이며, 모든 static이 아닌 전역변수는 uniform이다.
• 전역 변수 선언 앞에 extern을 붙이면, 외부입력 변수라는 뜻이며, 모든 static이 아닌 전역변수는 extern이다.
• 전역 변수 선언 앞에 shared를 붙이면, effect프레임워크로 하여금 effect들간에 공유되는 변수로 다루도록 해준다.
• 전역 변수 선언 앞에 volatie을 붙이면, effect프레임워크에 이 변수가 매우 빈번하게 바뀐다는 것을 알려주는 것이다.

 

초기값은 표현식이나 { expression [, expression [, ...]] }형태 일수 있는데, 전역 extern변수는 리터럴(literal)값이어야 하며, 다른 전역변수나 static지역변수는 상수이어야 한다.

 

변수는 의미자(semantic)가 붙을 수 있는데, 의미자는 언어적으로는 아무런 의미가 없지만, 
변수와 결합하여 하드웨어에 전달된다. 대소문자 구별도 없다. 의미자의 효용성과 의미는 사용자가 정의하는 기능에 달려있다. 예를 들어, 정점셰이더라면 입력과 출력 레지스터를 하드웨어에 맵핑하는데 사용된다.

 

전역 변수는 설명문(annotation)을 가질 수 있는데, 설명문은 { member_list }형태로 되어 있으며, 각 member_list의 멤버들은 리터럴 값으로 초기화 된다. 설명문은 effect와 전달인자를 교환하기위한 방법일 뿐이며, 프로그램안에서 참조할 수 없다. 또한 설명문의 멤버변수들은 의미자를 가질 수 없다.

 

1.12 구성성분 접근과 뒤섞기(Component Access and Swizzles)
기본 자료형의 부동소수 성분은 다음의 이름표 첨자를 사용해서 구조체의 멈버변수 처럼 각각 접근할수 있다.
 
_11, x, r _12, y, g _13, z, b _14, w, a    
_21       _22         _23        _24    
_31       _32         _33        _34    
_41       _42         _43        _44 

 

벡터의 특정 성분들은 두 세개의 첨자를 조합하여 접근 할 수 있다. 
bgr, yyzw, _12_22_32_42 

 

모든 이름들은 같은 첨자 집합을 사용해야 한다. 첨자집합은 섞어서 사용할 수 없으나, 같은 성분을 연속해서 사용할 수는 있다.

2절 문장과 식(statements & expressions)
HLSL에서 식(expression)은 변수와 리터럴, 연산자의 나열이며, 문장(statement)은 평가(evaluation)될 식의 순서를 결정한다.

 

2.1 식(Expression)
식은 리터럴과 변수를 연산자로 조합한 것이다.
변수 : 리터럴 리터럴이란 정수를 나타내는 숫자 1이나 , 부동소수를 나타내는 숫자 2.1처럼 명시된 자료값을 말하며, 주로 변수에 값을 대입할 때 사용된다    
연산자 :

- 1절의 자료형 항목을 참고    
- 연산자란 리터럴 혹은 변수들이 어떻게 결합, 비교,선택 될 것인지를 결정하며, 다음과 같은 연산자들이 있다.    
-  대입 =, +=, -=, *=, /=     
-  단항 !, -, +    
-  산술연산 +, -, *, /, %     
-  불린 &&, ||, ?:    
-  비교 <, >, ==, !=, <=, >=    
-  전위,후위 ++, --    
-  형변환 (type)    
-  콤마 ,    
-  구조체멤버 선택 .    
-  배열멤버 선택 [i]  
[표 2-1] 식에 사용되는 리터럴,변수,연산자

 

많은 수의 연산자들이 성분별(per component)로 지원된다. 즉, 변수의 각 구성성분별로 연산이 수행된다는 얘기다. 예를 들어서, 구성성분이 하나뿐인 변수는 연산이 한번만 일어나지만, 4개짜리 변수는 4번 연산이 일어나게 된다.

 

2.1.1 대입연산자(Assignment Operators)
연산자 : =, +=, -=, *=, /=

 

변수에는 리터럴 값이 대입될 수 있다. 
int i = 1;            
half h = 3.0;      
float f2 = 3.1f; 
bool b = false;
string str = "string"; 

 

변수에는 수학적 연산의 결과값이 대입될 수 있다. 
int i1 = 1;
i1 += 2;           // i1 = 1 + 2 = 3 

 

변수는 등호기호(=)의 양쪽에 사용될 수 있다. 
float f3 = 0.5f;
f3 *= f3;          // f3 = 0.5 * 0.5 = 0.25 

 

부동소수로 나누면 나머지 연산에 아무런 문제가 생기지 않는다. 
float f1 = 1.0;
f1 /= 3.0f;        // f1 = 1.0/3.0 = 0.333 

 

그러나, 나누어질 숫자가 정수일 경우에는 주의를 요한다. 특히 버림값이 결과에 영향을 미칠때는 말이다. 다음 예제는 앞의 예제와 같지만, 자료형이 다르기 때문에, 버림에 의해서 전혀 다른 결과가 나오게 된다. 
int i1 = 1;
i1 /= 3;           // i1 = 1/3 = 0.333, 소수점 이하를 버리므로 결국 0 

 

2.1.2 단항 연산자(Unary Operators)
연산자 : !, -, +

 

단항 연산자는 단일한 피연산자에 대해서 작용한다. 
bool b = false;
bool b2 = !b;      // b2 = true
int i = 2;
int i2 = -i;       // i2 = -2
int j = +i2;       // j = +2 


2.1.3 산술 연산자(Additive & Multiplicative Operators)
연산자 : +, -, *, /, %


int i1 = 1;
int i2 = 2;
int i3 = i1 + i2;  // i3 = 3
i3 = i1 * i2;        // i3 = 1 * 2 = 2  
  
i3 = i1/i2;       // i3 = 1/3 = 0.333. i3이 정수이므로 0으로 버려짐
i3 = i2/i1;       // i3 = 2/1 = 2  

  
float f1 = 1.0;
float f2 = 2.0f;
float f3 = f1 - f2; // f3 = 1.0 - 2.0 = -1.0
f3 = f1 * f2;         // f3 = 1.0 * 2.0 = 2.0  

  
f3 = f1/f2;        // f3 = 1.0/2.0 = 0.5
f3 = f2/f1;        // f3 = 2.0/1.0 = 2.0 

 

잉여 연산자(modulus operator) %는 나눗셈의 나머지 값을 반환한다. 
이 연산의 결과는 정수와 부동소수일 때의 결과가 다르다. 
int i1 = 1;
int i2 = 2;
i3 = i1 % i2;      // i3 = 1/2의 나머지는 1
i3 = i2 % i1;      // i3 = 2/1의 나머지는 0
i3 = 5 % 2;        // i3 = 5/2의 나머지는 1
i3 = 9 % 2;        // i3 = 9/2의 나머지는 1  

  
f3 = f1 % f2;      // f3 = 1.0/2.0의 나머지는 0.5
f3 = f2 % f1;      // f3 = 2.0/1.0의 나머지는 0.0

 

% 연산자는 양변이 양수이거나 양변이 음수일 때만 정의되며, C와는 다르게, 정수, 부동소수 모두에 대해서 작동한다.

 

2.1.4 불린 연산자(Boolean Math Operators)
연산자 : &&, ||, ?:


bool b1 = true;
bool b2 = false;
bool b3 = b1 && b2 // b3 = true AND false = false
b3 = b1 || b2      // b3 = true OR false = true 

 

C언어는 &&, ||, ?: 평가 시에 short-circuit을 사용 하는 반면, HLSL은 벡터연산이기 때문에 short-circuit을 사용 하지 않고, 양변의 식이 항상 모두 평가 된다.

 

<여기서 잠깐> short-circuit
short-circuit이란 한쪽 변을 먼저 평가하여 결과를 내는 방식이다.
( a || b ) 라는 경우를 생각해보자. 만약 a가 TRUE라면 b의 값이 무엇이던 ( a || b )는 항상 TRUE일 것이다. 반대로 ( a && b )를 생각해보면, a가 FALSE라면 b의 값과 무관하게 ( a && b )는 반드시 FALSE이다. 이처럼 한쪽 변의 결과값을 기준으로 빠르게 판정을 내리는 방식을 short-circuit이라 한다.
</여기서 잠깐>

 

불린 연산자는 구성요소별로 작동한다. 예를들어, 2개의 벡터를 비교한다면, 이 연산의 결과는 각 구성요소들을 비교한 결과값이 들어있는 벡터이다.

 

불린 연산자를 사용하는 식은 각 변수의 크기와 구성요소의 형이 같도록 늘어난다. 늘어나는 형은 연산이 발생할 크기와 식의 결과값에 따르게 되는데, 예를 들어서 int3 + float식은 float3+float3로 늘어나게 되고, 결과값도 float3가 된다.

 

2.1.5. 비교 연산자(Comparison Operators)
연산자 : <, >, ==, !=, <=, >=

 

스칼라 값의 크거나(작거나)를 비교한다. 
if( dot(lightDirection, normalVector)  >  0 )
   // 면에 조명처리

if( dot(lightDirection, normalVector)  <  0 )
   // 면이 뒷면 

 

혹은, 스칼라 값의 같음(같지 않음)을 비교한다. 
if(color.a  == 0)
   // 면이 보지이 않으므로 처리할 것 없음

if(color.a  != 0)
   // 알파값으로 두개의 색을 섞음
 

혹은, 스칼라 값의 크거나 같음(작거나 같음)을 비교한다.
if( position.z >= oldPosition.z )
   // 새로운 면이 현재 면보다 뒤에 있으므로 처리 생략

if( currentValue <= someInitialCondition )
   // 현재 값을 초기상태로 되돌림 

 

어떠한 스칼라 자료형도 비교 가능하다. 그러나, 비교 연산자는 벡터,행렬,객체형 등의 복합자료형(complex data type)은 지원하지 않는다.

 

2.1.6 전위, 후위 연산자(Prefix, Postfix Operators)
연산자 : ++, --
전위 연산자는 식이 평가되기 전에 변수의 값을 바꾸고, 후위연산자는 식을 평가한 다음에 값을 바꾼다.

다음 예제는 반복횟수를 세기 위해서 반복문에서 i값을 사용한다.
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };

for (int i = 0; i < 4; )
{
    arrayOfFloats[i++] *= 2; 

 

후위 증가 연산자 ++가 사용되었으므로, arrayOfFloats[i]가 i값이 증가하기 전에 2가 곱해진다. 이것을 전위연산자로 똑같이 구현하면 약간 복잡해 진다. 
float4 arrayOfFloats[4] = { 1.0f, 2.0f, 3.0f, 4.4f };

for (int i = 0; i < 4; )
{
    arrayOfFloats[++i - 1] *= 2; 

 

전위 증가 연산자 ++가 사용되었으므로, arrayOfFloats[i+1 - 1]는 i가 증가한 후에 2가 곱해진다.

 

전위 감소 와 후위 감소 연산자 --도 증가 연산자와 똑같이 사용하면 된다. 다만, 증가 연산자는 1을 더하는데 반해서 후위연산자는 1을 감소 시킨다는 점이 다를 뿐이다.

 

2.1.7 형변환 연산자(Cast Operator)
괄호안에 있는 자료형의 명은 명시적 형변환이다.
형변환은 원래의 식을 변환하려는 형으로 변환한다. 
일반적으로 간단한 자료형은 복합 자료형으로 형변환 될 수 있다. – 승격 형변환(promotion cast)
그러나, 일부분의 복합 자료형만이 간단한 자료형으로 형변환 될 수 있다. – 격하 형변환(demotion cast)
형변환이 가능한 경우에 대해서는 1절을 참고하도록 하자.

 

2.1.8 콤마 연산자(Comma Operator)
콤마 연산자는 하나이상의 식을 분할하여 순서대로 평가되도록 하며, 마지막 식의 값이 전체 식의 값이 된다.

 

매우 재미있는 예제를 하나 보도록 하자.

 

1. 다음 식에서 실수로 등호(=) 우측의 float4를 빼버리면 어떻게 될까? 
// 여기서 우측의 float4는 생성자 역할을 한다.
float4 x = float4(0,0,0,1);  

 

2. 아마도, 다음과 같은 모양이 될 것이다. 문제는 여기서부터 발생한다.
컴파일러는 (0,0,0,1)을 단순히 콤마가 3개인 식으로 평가하게 된다. 
float4 x = (0,0,0,1);  

 

3. 콤마 연산자는 왼쪽에서 오른쪽으로 식을 평가한다. 결국 최종적으로 다음의 식으로 변화된다. 맙소사! 
float4 x = 1;  

 

4. HLSL은 이 경우 스칼라 승격을 사용한다. float4 x의 구성요소에 모두 1을 넣는 것이다. 결국 다음 소스와 동일한 코드가 된다. 
float4 x = float4(1,1,1,1); 

 

이 예제에서 보다시피, 등호 우측의 float4를 빼는 것은 결과적으로 치명적인 오류가 된다. 왜냐면 float4 x = (0,0,0,1); 도 분명히 문법적으로 적법한 문장이기 때문이다.

 

2.1.9 구조체 연산자(Structure Operator)
연산자 : .


struct position
{
float4 x;
float4 y;
float4 z;
}; 

 

이것은 다음과 같이 사용한다. 
struct position pos = { 1,2,3 };

float 1D_Float = pos.x
1D_Float = pos.y 

 

각각의 멤버는 구조체 연산자를 사용해서 읽고 쓸 수 있다. 
struct position pos = { 1,2,3 };
pos.x = 2.0f;
pos.z = 1.0f;       // z = 1.0f
pos.z = pos.x      // z = 2.0f 

 

2.1.10 배열 연산자(Array Operator)
연산자 : [i]
배열 멤버 선택 연산자 [i]는 배열에서 하나 혹은 그 이상의 배열요소를 선택한다. 이때, []안의 첨자는 0부터 시작하는 정수이다.
int arrayOfInts[4] = { 0,1,2,3 };
arrayOfInts[0] = 2;
arrayOfInts[1] = arrayOfInts[0]; 

 

배열 연산자를 벡터에 접근할때도 사용된다. 
float4 4D_Vector = { 0.0f, 1.0f, 2.0f, 3.0f  };         
float 1DFloat = 4D_Vector[1];          // 1.0f 

 

추가적인 첨자를 붙여서 행렬에 접근할 수도 있다. 
float4x4 mat4x4 = {{0,0,0,0}, {1,1,1,1}, {2,2,2,2}, {3,3,3,3} };
mat4x4[0][1] = 1.1f;
float 1DFloat = mat4x4[0][1];      // 0.0f  
첫번째 첨자는 0부터 시작하는 행첨자이며, 두번째 첨자는 0부터 시작하는 렬첨자 이다.

 

2.1.11 연산자 우선순위
 
연산자 사용 방법 의미 결합법칙    
() (value) 부분식 왼쪽에서 오른쪽    
() id(arguments) 함수의 호출 왼쪽에서 오른쪽    
 type(arguments) 형 생성자    왼쪽에서 오른쪽    
[] array[int] 배열의 첨자 왼쪽에서 오른쪽    
.  structure.id 멤버의 선택 왼쪽에서 오른쪽    
 value.swizzle 성분의 교체 왼쪽에서 오른쪽    
++ variable++ 후위 증가 (성분마다) 왼쪽에서 오른쪽    
-- variable-- 후위 감소 (성분마다) 왼쪽에서 오른쪽    
++ ++variable 전위 증가 (성분마다) 오른쪽에서 왼쪽    
-- --variable 전위 감소 (성분마다) 오른쪽에서 왼쪽    
!  ! value 논리 NOT (성분마다) 오른쪽에서 왼쪽    
- -value 단항 마이너스 (성분마다) 오른쪽에서 왼쪽    
+ +value 단항 플러스 (성분마다) 오른쪽에서 왼쪽    
() (type) value 형 변환 오른쪽에서 왼쪽    
* value*value 곱셈 (성분마다) 왼쪽에서 오른쪽    
/ value/value 나눗셈 (성분마다) 왼쪽에서 오른쪽    
% value%value 잉여 (성분마다) 왼쪽에서 오른쪽    
+ value+value 덧셈 (성분마다) 왼쪽에서 오른쪽    
- value-value 뺄셈 (성분마다) 왼쪽에서 오른쪽    
< value < value 비교 : 보다 작은 (성분마다) 왼쪽에서 오른쪽    
> value > value 비교 : 보다 큰 (성분마다) 왼쪽에서 오른쪽    
<= value <= value 비교 : 이하 (성분마다) 왼쪽에서 오른쪽    
>= value >= value 비교 : 이상 (성분마다) 왼쪽에서 오른쪽    
== value == value 비교 : 동일한 (성분마다) 왼쪽에서 오른쪽    
!= value != value 비교 : 동일하지 않은 (성분마다) 왼쪽에서 오른쪽    
&& value && value 논리 AND (성분마다) 왼쪽에서 오른쪽    
|| value||value 논리 OR (성분마다) 왼쪽에서 오른쪽    
? : float? value:value 조건 오른쪽에서 왼쪽    
= variable=value 대입 (성분마다) 오른쪽에서 왼쪽    
*= variable*=value 곱셈 대입 (성분마다) 오른쪽에서 왼쪽    
/= variable/=value 나눗셈 대입 (성분마다) 오른쪽에서 왼쪽    
%= variable%=value 잉여 대입 (성분마다) 오른쪽에서 왼쪽    
+= variable+=value 덧셈 대입 (성분마다) 오른쪽에서 왼쪽    
-= variable-=value 뺄셈 대입 (성분마다) 오른쪽에서 왼쪽    
, value, value 콤마 왼쪽에서 오른쪽 

 

2.2 문장(statement)
문장 블럭은 하나 이상의 문장으로 이루어진 그룹으로서, {}으로 감싼 블럭이다.
{
   statement 1;
   statement 2;
   ...
   statement n;
 
문장 블럭이 단일문장이라면 {}을 써도 되고 안써도 된다.

 

또한 if문 다음에 한 줄짜리 문장이 온다면, {}으로 감싸는 것은 전적으로 개인의 자유이다. 
if( some expression)
   color.rgb = tex3D(Sampler, texturecoordinates);  

다음의 코드는 앞의 코드와 완전히 동일하다. 
if( some expression)
{
   color.rgb = tex3D(Sampler, texturecoordinates);

단, 블록 안에 선언된 변수는 그 블록 안에서만 유효하다는 것을 잊지 말자.

 

2.2.1 return 문(Return Statement)
return문은 함수의 끝을 나타낸다.

 

다음 코드는 가장 간단한 return문으로, 제어권을 호출자에게로 넘겨준다. 이 코드는 아무런 값도 반환하지 않는다. 
void main()
{
    return ;

 

return 문은 하나 이상의 값을 반환 할 수 있는데, 다음 코드는 리터럴 값을 반환하는 예이다. 
float main( float input : COLOR0) : COLOR0
{
    return 0;

 

다음 예제는 식의 스칼라 값을 반환한다. 
return  light.enabled = true ; 

 

다음 예제는 지역변수와 리터럴 값을 사용해서 생성한 float4를 반환한다.
return  float4(color.rgb, 1) ; 

 

다음 예제는 내부 함수로부터 반환된 값과 리터럴값으로 생성한 float4를 반환한다.
float4 func(float2 a: POSITION): COLOR
{
    return float4(sin(length(a) * 100.0) * 0.5 + 0.5, sin(a.y * 50.0), 0, 1);

 

다음 예제는 하나 이상의 멤버를 가진 구조체를 반환한다. 
float4x4 WorldViewProj;

struct VS_OUTPUT
{
    float4 Pos  : POSITION;
};

VS_OUTPUT VertexShader_Tutorial_1(float4 inPos : POSITION )
{
    VS_OUTPUT out;
    out.Pos = mul(inPos, WorldViewProj );
    return out;
}; 

 

2.2.2 흐름제어 문(Flow-Control Statements)
흐름제어 문은 다음 번에 실행된 문장이 어느 것인지를 결정 것으로, if, do for, while등이 있다.

 

2.2.2.1 if문
if문은 비교의 결과값에 근거해서 다음 번에 실행될 문장을 정한다. 
if ( (Normal dot LightDirection) > 0 ) 
{
    // 면에 조명처리, 확산광 색깔을 더할 것
    ...  

 

문장 블럭은 하나 이상의 문장으로 이루어 졌으며 {}으로 감싼 영역을 말하는데, 셰이더 명령슬롯의 크기를 넘지만 않는다면 얼마든지 커도 상관없다.

 

if문은 선택적으로 else블럭을 가질 수 있는데, if식이 참이라면 if문과 연계되어 있는 블럭이 처리되고, 그렇지 않다면 else에 연계된 블럭이 처리된다.

 

2.2.2.2 do 문
do문은 문장블럭을 실행 한 뒤 상태식(conditional expression)을 평가해서 문장블럭을 다시 실행할지 여부를 결정한다. 이 과정은 상태식의 값이 false가 될 때까지 반복된다. 
do  
{
  // one or more statements
  color /= 2;
} while ( color.a > 0.33f ) 

 

앞의 코드는 색깔 성분들을 2로 나누고나서 알파성분은 검사해서 반복할지 여부를 결정한다. 알파성분이 0.33f보다 크다면 색깔값의 성분들을 계속 반으로 나누는 과정을 반복하다가 알파성분이 0.33f보다 작아지면 비교식의 값이 거짓이 되어, 프로그램은 다음 번 명령으로 진행하게 된다.

 

이 코드는 한 줄짜리 문장블럭을 사용했지만, 다음과 같이 여러 줄짜리 문장 블럭을 사용해도 된다. 
do  {
    color.r /= 2;
    color.g /= 4;
    color.b /= 8;
    ....  // Other statements
    color.a /= 8; 
}  while ( color.a > 0.33f ) 

 

이 코드에서 알파값을 변화시키는 것을 잊으면 안된다. 만약 그걸 까먹었다가는 이 코드가 무한루프에 빠질 것이고, 셰이더 실행에 막대한 지장을 줄 것이다.

 

2.2.2.3 for문
for문은 정해진 횟수만큼 문장블럭을 반복하는 정적인 제어를 제공해 준다.

 

for문에는 초기식, 비교식, 증가식이 포함되며 문장블럭이 뒤따른다. 
for ( int i = 0; i < 2; i++)
{
   // 하나 이상의 문장블럭
   ...
   문장 n;
}; 

 

다음 예제는 4개의 다른 텍스처 좌표에서 텍스처를 읽어들이기 위해서 for반복문을 사용 하였다. 
sampler RenderTarget;
float4 textureCoordinates[4]; 
float4 outColor[4];

for(int i = 0; i < 3; i++)
{
    outColor[i] = tex2D(RenderTarget, textureCoordinates[i]);

 

문장 블럭은 비교식이 true일 때마다 반복해서 실행된다.

 

2.2.2.4 while문
while문은 식을 평가하여 문장블럭을 실행할지 여부를 판단해서 반복한다.
while ( color.a > 0.33f )
{
    color /= 2; 
 
이 코드는 알파성분이 0.33f보다 큰지 확인한 다음, 참이면 절반으로 나눈다. 알파값이 0.33f보다 작아지면 비교식이 거짓이 되어 프로그램은 다음 문장을 실행하게 된다.

 

다음 코드는 한줄짜리 문장이며, 한줄짜리 문장은 {}을 사용할지 여부를 선택할 수 있다. 
while ( color.a > 0.33f )
    color /= 2;  

 

문장 블럭은 n개로 확장할 수 있다. 
while ( color.a > 0.33f )
{
    color.r /= 2;
    color.g /= 4;
    color.b /= 8;
    ....  // Other statements
    color.a /= 8; 
 
알파값을 바꾸는 것을 잊지 말자. 무한루프에 빠질 수 있다.

 

3절 셰이더 의미자(shader semantics)부터는 다음에....


3절 셰이더 의미자(shader semantics)
3절에서는 다음과 같은 내용들을 살펴 볼 것이다.

• 정점셰이더 의미자(Vertex Shader Semantics)
• 픽셀셰이더 의미자(Pixel Shader Semantics)
• 명시적 레지스터 결합(Explicit Register Binding)

3.1 정점 셰이더 의미자(Vertex Shader Semantics)
HLSL 의미자의 역할은 셰이더 데이터의 입력과 출력을 식별하는 것이다. 의미자는 3가지 경우에 나타난다.

• 구조체 멤버 뒤에
• 함수의 입력 전달인자 리스트들 중의 전달인자 뒤에
• 함수의 입력 전달인자 리스트 뒤에

다음 예제는 하나이상의 셰이더 입력을 위해서 구조체를 사용한다. 그리고, 셰이더 출력을 위해서 다른 구조체를 사용하는데, 이들 구조체 멤버들이 의미자를 사용하고 있다.


vector vClr;

struct VS_INPUT
{
    float4 vPosition : POSITION;
    float3 vNormal : NORMAL;
    float4 vBlendWeights : BLENDWEIGHT;
};

struct VS_OUTPUT
{
    float4  vPosition : POSITION;
    float4  vDiffuse : COLOR;

};

float4x4 mWld1;
float4x4 mWld2;
float4x4 mWld3;
float4x4 mWld4;

float Len;
float4 vLight;

float4x4 mTot;

VS_OUTPUT VS_Skinning_Example(const VS_INPUT v, uniform float len=100)
{
    VS_OUTPUT out;

    // 스킨 위치(월드 공간으로)
    float3 vPosition = 
        mul(v.vPosition, (float4x3) mWld1) * v.vBlendWeights.x +
        mul(v.vPosition, (float4x3) mWld2) * v.vBlendWeights.y +
        mul(v.vPosition, (float4x3) mWld3) * v.vBlendWeights.z +
        mul(v.vPosition, (float4x3) mWld4) * v.vBlendWeights.w;


    // 스킨 법선(월드 공간으로)
    float3 vNormal =
        mul(v.vNormal, (float3x3) mWld1) * v.vBlendWeights.x + 
        mul(v.vNormal, (float3x3) mWld2) * v.vBlendWeights.y + 
        mul(v.vNormal, (float3x3) mWld3) * v.vBlendWeights.z + 
        mul(v.vNormal, (float3x3) mWld4) * v.vBlendWeights.w;
    
    // 출력할 것들
    out.vPosition    = mul(float4(vPosition + vNormal * Len, 1), mTot);
    out.vDiffuse  = dot(vLight,vNormal);

    return out;

입력 구조체는 정점버퍼로부터 셰이더 입력이 될 데이터를 식별한다.
앞서 소개한 코드의 셰이더는 정점버퍼로부터 들어오는 입력을 POSITION, NORMAL, BLENDWEIGHT요소로 구별해서 셰이더 레지스터에 맵핑(연결)한다.

HLSL의 입력 데이터는 정점선언 데이터형과 완벽하게 일치할 필요는 없는데, 데이터형이 맞지 않을 경우, HLSL에서 지정된 형으로 자동변환 되기 때문이다. 예를 들자면, 프로그램에서 UINT로 정의된 NORMAL형은 셰이더에서 읽혀질때는 float3형으로 변환된다는 것이다.

정점 스트림의 데이터가 셰이더에 선언된 데이터형보다 적을 경우, 없는 성분들은 0으로 초기화된다. 단 w성분은 예외적으로 1로 초기화 된다.

입력 의미자는 고정함수 파이프라인의 D3DDECLUSAGE 열거형 값과 비슷하다고 생각하면 된다.

출력 구조체는 정점 셰이더 출력 인자를 식별한다. 이 예제의 경우에는 위치값과 색깔값을 사용한다. 이들 출력값은 삼각형 레스터라이즈에 사용될 것인데, POSITION이라고 표기된 것이 스크린 좌표계에서의 좌표이다. 스크린 좌표계에서는 -1과 +1이 뷰포트에서의 x,y좌표의 최소,최대 값이며, z값은 z버퍼 테스트에 사용된다. 그리고, 어떠한 정점셰이더도 반드시 POSITION값만큼은 출력해야 한다.

출력 의미자도 고정함수 파이프라인의 D3DDECLUSAGE 열거형 값과 비슷하다고 생각하면 된다. 일반적으로 정점셰이더의 출력 구조체는 픽셀 셰이더의 입력 구조체로 사용된다.
픽셀셰이더의 경우에는 POSITION, PSIZE, FOG으로 연결된 값들은 읽을 수가 없는데, 만약, 이들 값들이 필요할 경우에는 픽셀 셰이더의 다른 출력 레지스터에 복사하여 의미자를 다른 형식(TEXCOORDn등)으로 사용하면 된다.


3.1.1 정점 셰이더 입력 의미자(Vertex Shader Input Semantics)

다음과 같은 입력 의미자가 있다.
 
POSITION[n] 위치(position)    
BLENDWEIGHT[n] 결합가중치(blend weight)    
BLENDINDICES[n] 결합인덱스(blend index)    
NORMAL[n] 법선(normal)    
PSIZE[n] 점크기(point size)    
COLOR[n] 확산,반사광(diffuse specular color)    
TEXCOORD[n] 텍스처 좌표(texture coordinate)    
TANGENT[n] 접선(tangent)    
BINORMAL[n] 종법선(binormal)    
TESSFACTOR[n] 분할 인수(tessellation factor)  
n은 0부터 시작하는 정수로서 지원되는 레지스터의 숫자이다. 예) PSIZE0, COLOR1, 등

3.1.2 정점 셰이더 출력 의미자(Vertex Shader Output Semantics)
다음과 같은 입력 의미자가 있다.


POSITION 위치(position)    
PSIZE 점크기(point size)    
FOG 정점 안개(vertex fog)    
COLOR[n] 색깔(Color) 예) COLOR0    
TEXCOORD[n] 텍스처 좌표(texture coordinate) 예) TEXCOORD0  
n은 0부터 시작하는 정수로서 지원되는 레지스터의 숫자이다. 예) TEXCOORD0, TEXCOORD1, 등

3.2 픽셀 셰이더 의미자(Pixel Shader Semantics)
HLSL 의미자의 역할은 셰이더 데이터의 입력과 출력을 식별하는 것이다. 의미자는 3가지 경우에 나타난다.

• 구조체 멤버 뒤에
• 함수의 입력 전달인자 리스트들 중의 전달인자 뒤에
• 함수의 입력 전달인자 리스트 뒤에

다음 예제는 정점셰이더 출력과 픽셀셰이더 입력으로 같은 구조체를 사용한다. 픽셀셰이더는 색깔값을 반환한다는 것을 나타내기 위해서, 함수의 전달인자의 뒤에 의미자를 사용하고 있다.
 
struct VS_OUTPUT
{
    float4 Position  : POSITION;
    float3 Diffuse : COLOR0;
    float3 Specular : COLOR1;               
    float3 HalfVector : TEXCOORD3;
    float3 Fresnel : TEXCOORD2;               
    float3 Reflection : TEXCOORD0;               
    float3 NoiseCoord : TEXCOORD1;               
};

float4 PixelShader_Sparkle(VS_OUTPUT In) : COLOR
{   
    float4 Color = (float4)0;
    float4 Noise = tex3D(SparkleNoise, In.NoiseCoord);
    float3 Diffuse, Specular, Gloss, Sparkle;

    Diffuse   = In.Diffuse * Noise.a;
    Specular  = In.Specular;
    Specular *= Specular;
    Gloss     = texCUBE(Environment, In.Reflection) * saturate(In.Fresnel);
    Sparkle   = saturate(dot((saturate(In.HalfVector) - 0.5) * 2, 
  (Noise.rgb - 0.5) * 2));
    Sparkle  *= Sparkle;
    Sparkle  *= Sparkle;
    Sparkle  *= Sparkle * k_s;

    Color.rgb = Diffuse + Specular + Gloss + Sparkle;
    Color.w   = 1;

    return Color;

VS_OUTPUT으로부터 들어오는 모든 입력은 의미자를 가지고 있다. 이들 값들은 정점셰이더로부터 반환된 값이므로, 픽셀셰이더 입력으로 읽혀진다. 다른 3개의 입력은 프로그램에서 설정된 전역 uniform변수들인 Environment, SparkleNoise, k_s값으로, Environment와 SparkleNoise는 모두 프로그램에 의해서 생성되고 설정되는 텍스처들이며, k_s도 프로그램에 의해서 설정된 상수 레지스터이다.

전역 변수들은 컴파일러에 의해서 자동적으로 레지스터에 할당된다. 전역변수들은 uniform전달인자로도 불리우는데, 그것은 이들 변수의 값이 셰이더가 호출될 때 처리되는 픽셀들에 대해서 항상 일정(uniform)하기 때문이다.
상수테이블에 있는 레지스터들은 ID3DXConstantTable를 통해서 접근 가능하다.

픽셀 셰이더의 입력 의미자는 정점셰이더와 픽셀셰이더의 값을 특정한 하드웨어에 연결(mapping)하게 되는데, 레지스터마다 특별한 성질이 있다. 현재까지는 오직 TEXCOORD와 COLOR의미자만이 유효하기 때문에 전달하려는 값이 텍스처좌표가 아니라 하더라도 TEXCOORD 의미자를 사용해야 한다.

정점셰이더의 출력 구조체에는 POSITION이 있지만, 픽셀셰이더 입력에서는 이 값이 없음을 유념하자. HLSL은 픽셀셰이더에서 유효하지 않은 값이라도 정점셰이더에서 유효한 출력값이면 이를 허용하는데, 결과적으로는 픽셀셰이더에서 참조 되지 않는다.

입력 인자는 배열일 수도 있다. 이 경우 의미자는 각 배열요소마다 자동적으로 컴파일러에 의해서 증가된다. 예를 들어 다음과 같은 명시적 선언을 생각해보자.
 
struct VS_OUTPUT
{
    float4 Position  : POSITION;
    float3 Diffuse : COLOR0;
    float3 Specular : COLOR1;               
    float3 HalfVector : TEXCOORD3;
    float3 Fresnel : TEXCOORD2;               
    float3 Reflection : TEXCOORD0;               
    float3 NoiseCoord : TEXCOORD1;               
};

float4 Sparkle(VS_OUTPUT In) : COLOR 

여기서 이루어진 명시적 선언은, 다음과 같이 선언할 경우 컴파일러에 의해서 의미자가 자동적으로 붙기 때문에 동일한 선언이 된다.
 
float4 Sparkle(float4 Position : POSITION,
                         float3 Col[2] : COLOR0,
                         float3 Tex[4] : TEXCOORD0) : COLOR0
{
   // shader statements
   ... 

입력 의미자처럼, 출력 의미자도 픽셀셰이더 출력데이터를 구분해 주는데, 대부분의 픽셀 셰이더는 출력값을 그냥 COLOR0로 하게 된다.

또한, 픽셀 셰이더는 DEPTH0값과 여러개(최대 4개)의 렌더타겟도 가질수 있다. 다음 셰이더 코드는 색깔값과 깊이값을 모두 출력하고 있다.
 
struct PS_OUTPUT
{
    float4 Color[4] : COLOR0;
    float  Depth  : DEPTH;
};

PS_OUTPUT main(void)
{
    PS_OUTPUT out;

   // 셰이더 문
   ...

  // 4개의 출력색깔 값을 쓴다.
  out.Color[0] =  ...
  out.Color[1] =  ...
  out.Color[2] =  ...
  out.Color[3] =  ...

  // Write pixel depth 
  out.Depth =  ...

    return out;

픽셀셰이더의 출력 색깔값은 float4형식만 가능하다. 여러가지 색깔값을 사용하고 싶다면, 연속적으로만 사용 가능한데, 이 말은 COLOR1을 사용하고 싶다면 먼저 COLOR0값을 출력해야만 한다는 뜻이다. 그리고, 픽셀셰이더에서 출력하는 깊이값의 경우에는 float1형만 가능하다.

3.2.1 픽셀 셰이더 입력 의미자(Pixel Shader Input Semantics)
다음과 같은 의미자를 지원한다.
 
COLOR[n] 확산,반사광 색깔  예) COLOR0, COLOR1    
TEXCOORD[n] 텍스처 좌표  예) TEXCOORD0  
n은 0부터 시작하는 정수로서 지원되는 레지스터의 숫자이다. 예) TEXCOORD0, TEXCOORD1, 등

3.2.2 픽셀 셰이더 출력 의미자(Pixel Shader Output Semantics)
다음과 같은 의미자를 지원한다.
 
COLOR[n] 색깔    예) COLOR0    
TEXCOORD[n] 텍스처좌표   예) TEXCOORD0    
DEPTH[n] 깊이값    예) DEPTH0  
n은 0부터 시작하는 정수로서 지원되는 레지스터의 숫자이다. 예) COLOR0, TEXCOORD1, DEPTH0, 등

3.3 명시적 레지스터 결합(Explicit Register Binding)
우리는 이미 컴파일러가 전역변수에 레지스터를 자동적으로 할당한다는 것을 알고있다. 그러나, 변수에 특정한 레지스터를 결합하도록 명시하는 것도 가능하다.

다음과 같은 3개의 전역변수가 있을 경우,
 
sampler Environment;
sampler SparkleNoise;
float4 k_s; 

컴파일러는 자동적으로 Environment에 샘플러 레지스터 s0를, SparkleNoise에 샘플러 레지스터 s1를 할당하고, k_s에 상수레지스터 c0를 할당할 것이다.(이전에 할당된 레지스터들이 없다고 가정하자)

그러나, 컴파일러에게 특정한 레지스터를 할당하도록 하려면 register(...)구문을 사용하면 된다.
 
sampler Environment : register(s1);
sampler SparkleNoise : register(s0);
float4 k_s : register(c12); 

이 경우 Environment는 s1샘플러 레지스터에, SparkleNoise는 s0샘플러 레지스터에, 마지막으로 k_s는 c12상수 레지스터에 할당될 것이다.


4절 흐름 제어(Flow Control)

대부분의 정점,픽셀 셰이더 하드웨어는 명령어를 한번씩만 수행하도록 선형적으로 디자인되어있다. 그러나, HLSL은 정적 분기(static branching), 프레디케이션 명령(predicated instructions), 정적 반복(static looping), 동적 분기(dynamic branching), 동적 반복(dynamic looping) 등의 흐름 제어를 지원한다.

전에는 HLSL에서 if문을 사용하면 어셈블리 셰이더 코드에서 if문의 참/거짓의 경우를 모두 수행하되, 한쪽의 결과값만 남도록 컴파일되었다.

다음 코드를 vs_1_1로 컴파일 해보자.
 
if (Value > 0)
    Position = Value1; 
else
    Position = Value2; 

다음 코드가 앞의 코드를 vs_1_1로 컴파일해서 만들어진 어셈블리 코드이다.
 
// 선형보간값 r0.w를 계산
mov r1.w, c2.x               
slt r0.w, c3.x, r1.w         
// value1과 value2사이를 선형보간
mov r7, -c1                      
add r2, r7, c0                   
mad oPos, r0.w, r2, c1 

그러나, 어떤 하드웨어는 정적이나 동적 반복 중 하나만 지원하며, 선형적인 수행을 필요로 한다. 반복을 지원하지 않는 모델에서는 반복할 내용을 반복 회수만큼 전개(unroll)해서 컴파일 하게 된다. 이러한 경우의 좋은 예는 DirectX 9.0 SDK의 DepthOfField예제인데, 여기서는 ps_1_1에서도 작동하도록 전개(unroll)를 사용해서 컴파일 하고 있다.

HLSL은 이제 다음과 같은 형태의 흐름제어도 포함되어 있다.

• 정적 분기(static branching)
• 프레디케이션 명령(predicated instructions)
• 정적 반복(static looping)
• 동적 분기(dynamic branching)
• 동적 반복(dynamic looping)

요즘 하드웨어에서 지원하는 대부분의 분기지원은 정적 분기이다. 정적분기는 불린 셰이더 상수에 의해서 특정 코드블럭이 실행될지 안될지를 결정하는 것이다. 이것은 현재 렌더링 되려는 오브젝트의 형태에 따라서 코드를 허용하거나 금지시킬 때 편리한 방법이다. 화면에 그려질 때, 현재 셰이더의 특정 기능을 사용할지를 결정 할 수 있는 것이다. HLSL에서는 분기를 허용하기 때문에서 불린 상수에 의해서 금지된 코드는 실행되지 않고 건너뛰게 된다.

개발자에게 가장 친숙한 분기는 동적분기이다. 동적분기에서는 비교해야 할 상태가 변수에 들어있어서, 비교가 컴파일 시(compile time)에 일어나는 것이 아니라 실행 시(runtime)에 일어나게 된다. 수행능력은 "분기에 필요한 비용 + 분기에 의해서 실행된 명령에 따른 비용"으로 결정된다. 동적분기는 현재 정점셰이더에서 사용 가능하다.


5절 함수(Functions)

• 함수 선언(Function Declaration)
• 함수 반환 형(Function Return Types)
• 함수 명(Function Name)
• 전달인자 리스트(Argument Lists)
• 함수 몸체(Function Body)
• 사용자 정의 함수(User-Defined Functions)

함수는 큰 작업을 작은 작업들로 분할하며, 작은 작업은 디버깅과 재사용이 훨씬 용이하다. 또한, 함수는 함수자체의 자세한 내용을 숨기기 위해서도 사용되며, 프로그램은 이러한 함수들의 조합으로 이루어져있다.

HLSL함수는 몇가지 면에서 C의 함수와 비슷하다. 일단, 함수는 '함수정의'와 '함수몸체'를 포함하고 있어야 하며, '반환형'과 '전달인자 리스트'를 선언해야 한다. C함수와 마찬가지로 HLSL도 셰이더 컴파일시에 문법의 적법성을 검사하기 위해 전달인자, 전달인자 형, 반환값을 체크한다.

그러나, C함수와는 다르게, HLSL의 진입함수는 함수 전달인자와 셰이더 입출력값을 결합하기 위해서 의미자를 사용하는데, 결과적으로 '버퍼 데이터를 셰이더와 결합하는 것'과 '셰이더 출력값을 셰이더 입력값과 결합하는 것'을 쉽게해준다.(내부적으로 호출되는 HLSL함수는 의미자를 무시한다.)



5.1 함수 선언(Function Declaration)
함수는 선언부와 몸체로 이루어져 있는데, 선언부는 몸체보다 먼저 나와야 한다.
 
float4 VertexShader_Tutorial_1(float4 inPos : POSITION ) : POSITION
{
    return mul(inPos, WorldViewProj );

함수 선언부에는 {}앞에 모든 것이 나와있어야 한다.
 
float4 VertexShader_Tutorial_1(float4 inPos : POSITION ) : POSITION 

함수 선언부에는 다음과 같은 것들이 포함되어 있다.
• 반환 값 
• 함수 명
• 전달인자 리스트(선택적)
• 출력 의미자(선택적)
• 설명문(annotation)(선택적)

5.2 함수 반환형(Function Return Types)
반환형은 float4처럼 HLSL의 어떠한 기본 자료형도 가능하다.


float4 VertexShader_Tutorial_1(float4 inPos : POSITION ) : POSITION
{
   ...

반환형은 미리 정의된 자료구조도 가능하다.
 
struct VS_OUTPUT
{
    float4  vPosition        : POSITION;
    float4  vDiffuse         : COLOR;
};

VS_OUTPUT VertexShader_Tutorial_1(float4 inPos : POSITION )
{
   ...

함수가 반환값이 없으면, 반환형을 void로 하면된다.
 
void VertexShader_Tutorial_1(float4 inPos : POSITION )
{
   ...

반환형은 항상 함수 선언의 앞부분에 나타나야 한다.



5.3 함수 명(Function Name)
함수명은 함수의 반환형 다음에 나타나는 식별자이다.


float4 VertexShader_Tutorial_1(float4 inPos : POSITION ) : POSITION 

함수명은 VertexShader_Tutorial_1처럼 이해하기 쉽게 짓는 것이 좋다.



5.4 전달인자 리스트(Argument Lists)
전달인자 리스트 함수에게 입력 인자와 반환될 값을 선언할 수 있다. 어떤 인자를 입력과 출력 모두에 사용될 수도 있다.

다음 예제는 4개의 입력 인자를 가진 셰이더이다.
 
float4 Light(float3 LightDir : TEXCOORD1, 
             uniform float4 LightColor,  
             float2 texcrd : TEXCOORD0, 
             uniform sampler samp) : COLOR 
{
    float3 Normal = tex2D(samp,texcrd);

    return dot((Normal*2 - 1), LightDir)*LightColor;


이 함수는 샘플링된 텍스처와 조명색깔을 혼합한 최종 색깔을 반환한다. 이 함수는 4개의 입력값이 있고, 그 중 2개는 의미자가 있는데, LightDir는 TEXCOORD1, texcrd는 TEXCOORD0이다. 이것은 이 변수들이 정점버퍼로부터 입력 된다는 뜻이다.
LightDir가 TEXCOORD1의 의미자를 갖고 있지만, 이 전달인자는 아마도 텍스처 좌표가 아닐 것이다. TEXCOORDn의미자는 주로 미리 정의되어 있지 않은 자료형일 경우에 자주 사용되는데, 이 경우에도 정점셰이더 의미자에는 광원방향에 대한 것이 없으므로 TEXCOORD1을 사용한 것으로 이해할 수 있을 것이다.


다른 2개의 입력인 LightColor와 samp는 uniform명령어가 있다. 그 얘기는 화면에 그려지는 중에 이 변수값이 바꾸지 않는 다는 뜻이다. 대부분 이런 전달인자는 셰이더 전역 변수로부터 전달된다.

전달인자는 입력값의 경우 in명령어, 출력값일 경우 out명령어와 함께 사용할 수 있다. 전달인자는 참조에 의해서 전달될 수 없으나, inout명령어를 사용하면 입출력값으로 사용될 수 있다. inout명령어로 선언되어 함수로 전달되는 전달인자는 함수 반환전까지는 원본의 복사본으로 간주되다가, 되돌아 갈때 다시 복사된다.

inout명령어를 사용한 예를 보도록 하자.
 
void Increment_ByVal(inout float A, inout float B) 
{ 
    A++; B++;

이 함수는 A와 B값을 증가시키고, 그 값을 반환한다.



5.5 함수 몸체(Function Body)
함수 몸체란 함수 선언다음에 나오는 모든 코드를 말하는 것으로, {}으로 둘러싸인 문장으로 구성되며, 변수, 리터럴, 식, 문장을 사용해서 구현한다.
 
float4 VertexShader_Tutorial_1(float4 inPos : POSITION ) : POSITION
{
    return mul(inPos, WorldViewProj );

이 셰이더 몸체는 2가지 일을 하는데, 행렬곱셈과 float4를 반환하는 것이다. 여기서, 행렬곱셈은 mul함수를 사용해서 이루어진다. mul은 HLSL라이브러리 함수에 이미 구현되어져 있기때문에 내부함수(intrinsic function)라 부른다.

이 코드의 행렬 곱셈은 입력벡터 Pos와 합성행렬인 WorldViewProj의 조합으로 이루어져있다. 결과적으로 위치값은 화면좌표계로 변환된다. 이것이 우리가 할수 있는 최소한의 정점셰이더 처리인 것이다. 만약 정점셰이더가 아닌 고정함수 파이프라인을 사용한다면 이 변환뒤에 정점데이터가 그려질 것이다.

함수몸체의 제일 마지막 문장은 반환문으로, C와 마찬가지로 return문은 제어권을 이 함수를 호출한 곳으로 되돌려 준다.



5.6 반환 형(Return Types)
함수 반환형은 HLSL에 정의된 bool, int, half, float, double등의 어떠한 자료형도 가능하다. 또한 복합 자료형인 vector, matrix도 가능하지만, pixelshader, vertexshader, texture, and sampler같은 객체형은 반환형이 될 수 없다.

구조체를 반환하는 자료형의 예를 보도록 하자.


float4x4 WorldViewProj : WORLDVIEWPROJ;

struct VS_OUTPUT
{
    float4 Pos  : POSITION;
};

VS_OUTPUT VS_HLL_Example(float4 inPos : POSITION )
{
    VS_OUTPUT Out;

    Out.Pos = mul(inPos,  WorldViewProj );

    return Out;



5.7 사용자 정의 함수(User-Defined Functions)
함수 정의는 C와 매우 비슷하다.


[static inline target] [const] type id ( [parameter_list] ) ;
[static inline target] [const] type id ( [parameter_list] ) { [statements] } ; 

타겟이란 선택적인 식별자로 함수가 사용될 플랫폼을 지정한다.
parameter_list는 하나 이상의 전달인자 선언들을 콤마(,)로 구분하여 나열한 것이다.


[uniform in out inout] type id [: semantic] [= default] 

전달인자 값은 항상 값에 의해서 전달된다.

• in명령어가 사용된 전달인자는 사용하기 전에 먼저 복사되어야 한다는 것이다.
• out명령어가 사용된 전달인자는 전달인자의 최종값이 복사되어, 함수를 호출한 곳으로 전달되어야 한다는 것이다.
• inout명령어가 사용된 전달인자는 in과 out을 동시에 지정하는 것이다.
• uniform명령어가 사용된 전달인자는 in명령어의 특별한 형태로, 최상위 함수일 경우 상수데이터가 전달인자로 전달된다는 것이다. 
• 최상위 함수가 아닐 경우에는 in과 동일한 역할을 한다.
• in,out,inout,uniform중 어떤것도 지정되지 않으면 in으로 간주한다.

함수몸체가 없는 함수는 함수형태만 선언한 것으로 간주되며, 뒤에 몸체와 함께 반드시 재정의 되어야 한다. 만약 함수 몸체가 정의되지 않은 함수가 참조될 경우에는 오류가 발생한다.

함수는 다중정의(overloading)될 수 있으며, 함수명, 전달인자 형, 타겟 플랫폼에 의해서 식별될 수 있다. 그러나, 함수 다중정의는 아직 구현되어 있지 않다.

현재 모든 함수는 인라인(inline)이므로, 되부름은 지원되지 않는다.

6절 내부함수(Intrinsic functions)
내부함수란 HLSL컴파일러에서 지원하는 라이브러리 함수이다. 이미 HLSL내부에 구현되어 있는 함수들이며, 상당한 최적화가 이루어져 있으므로, 내부함수를 많이 사용할수록 효율적인 코드가 만들어진다.



함수명 구문 설명    
abs value abs(value a) 절대값 (성분마다).     


acos acos(x) x 의 각 성분의 역코사인을 돌려준다. 각 성분은,[-1, 1] 의 범위로 한다.     


all all(x) x 의 모든 성분이 0 이외의 값인지 아닌지를 테스트한다.     


any any(x) x 의 몇개의 성분이 0 이외의 값인지 아닌지를 테스트한다.     


asin asin(x) x 의 각 성분의 역사인을 돌려준다. 각 성분은,[-pi/2, pi/2] 의 범위로 한다.     


atan atan(x) x 의 각 성분의 역탄젠트를 돌려준다. 반환값은,[-pi/2, pi/2] 의 범위이다.    

 
atan2 atan2(y, x) y/x 의 역탄젠트를 돌려준다. y 와 x 의 부호를 사용해 [-pi, pi] 의 범위에 있는 반환


값의 상한을 판단한다. atan2 는, x 가 0 으로 동일하고, y 가 0 으로 동일하지 않은 경우에서도, 원점 이


외의 각 점에 대해서 잘 정의(well-defined)되어 있다.     


ceil ceil(x) x 이상의 최소의 정수를 돌려준다.     


clamp clamp(x, min, max) x 를 [min, max] 의 범위로 제한한다.     


clip clip(x) x 의 어떤 성분이 0 보다 작은 경우, 현재의 픽셀을 파기한다. x 의 각 성분이 면으로부터의 


거리를 나타내는 경우, 이 함수를 사용해, 클립면을 시뮬레이션 한다.     


cos cos(x) x 의 코사인을 돌려준다.     


cosh cosh(x) x 의 쌍곡코사인(hyperbolic cosine)을 돌려준다.     


cross cross(a, b) 2 개의 3D 벡터 a 와 b 의 외적을 돌려준다.     


D3DCOLORtoUBYTE4 D3DCOLORtoUBYTE4(x) 4D 벡터 x 의 성분을 교체 및 스케일링 해, 일부 


하드웨어가 지원하지 않는UBYTE4를 지원한다.    


ddx ddx(x) 스크린 공간의 x 좌표에 대해, x 의 편미분을 돌려준다.     


ddy ddy(x) 스크린 공간의 y 좌표에 대해, x 의 편미분을 돌려준다.     


degrees degrees(x) x 를 라디안 단위로부터 도(degree)로 변환한다.     


determinant determinant(m) 정방 행렬 m 의 행렬식을 돌려준다.     


distance distance(a, b) 2 개의 점 a 와 b 간의 거리를 돌려준다.     


dot dot(a, b) 2 개의 벡터 a 와 b 의 내적을 돌려준다.     


exp exp(x) e 를 밑으로 하는 지수     


exp2 value exp2(value a) 2 를 밑으로 하는 지수     


faceforward faceforward(n, i, ng) -n * sign(dot(i, ng))를 돌려준다.     


floor floor(x) x 이하의 최대의 정수를 돌려준다.     


fmod fmod(a, b) a / b 의 부동 소수 나머지(잉여) f를 돌려준다.

단, i는 정수, f 는 x 와 부호가 같고, f의 절대값은 b 의 절대값보다 작아야 한다.    


frac frac(x) x의 소수부 f를 돌려준다.     


frc value frc(value a) 소수부 (성분마다).     


frexp frexp(x, out exp) x 의 가수와 지수를 돌려준다. frexp 는 가수를 돌려주며, 지수는 출력 인수 exp에 저장 된다. x 가 0 의 경우, 함수는 가수와 지수의 양쪽 모두에 0 을 돌려준다.     


fwidth fwidth(x) abs(ddx(x)) +abs(ddy(x))를 돌려준다.     


isfinite isfinite(x) x가 유한의 경우는 TRUE 를 돌려준다. 그 이외의 경우는 FALSE를 돌려준다.     


isinf isinf(x) x가 +INF나 -INF 의 경우는 TRUE를 돌려준다. 그 이외의 경우는 FALSE를 돌려준다.     


isnan isnan(x) x가 NAN 이나 QNAN의 경우는 TRUE를 돌려준다. 그 이외의 경우는 FALSE를 돌려준다.     


ldexp ldexp(x, exp) x * 2exp를 돌려준다.     


len float len(value a) 벡터의 길이.     


length length(v) 벡터 v 의 길이를 돌려준다.     


lerp lerp(a, b, s) a + s(b - a)를 돌려준다. 이 함수는, s가 0의 경우는 a, 1의 경우는 b를 돌려주도록, a와 b사이를 선형 보간 한다.    

 
lit lit(ndotl, ndoth, m) 조명의 벡터 (주변, 확산, 반사, 1)를 돌려준다. 

주변 = 1; 
확산 = (ndotl < 0) ? 0 : ndotl; 
반사 = (ndotl < 0) || (ndoth < 0) ? 0 : (ndoth * m);    

log log(x) 밑이 e인 x 의 자연대수를 돌려준다. x가 음수(-)일 경우, 무한을 돌려준다. x 가 0일 경우, +INF를 돌려준다.     


log10 log10(x) 밑이 10인 x 의 자연대수를 돌려준다. x가 음수(-)일 경우, 무한을 돌려준다. x 가 0일 경우, +INF를 돌려준다.     


log2 log2(x) 밑이 2인 x 의 자연대수를 돌려준다. x가 음수(-)일 경우, 무한을 돌려준다. x 가 0일 경우, +INF를 돌려준다.     


max max(a, b) a와 b중 큰 쪽을 선택한다.     


min min(a, b) a와 b중 작은쪽을 선택한다.     


modf modf(x, out ip) 값x를 소수부와 정수부로 나눈다. 부호있는 소수부는 반환값으로 돌려주고, 부호있는 정수부는 출력 인수 ip로 돌려준다.    

 
mul mul(a, b) a와 b 사이의 행렬 곱셈을 실행한다. a가 벡터일 행벡터로, b가 벡터의 경우, 열벡터로 처리한다. a행과 b열의 크기는 동일해야 하며, 연산의 결과는 a행x b열 크기의 차원을 갖는다.   

 
noise noise(x) 구현되어 있지 않음    


normalize normalize(v) 정규화된 벡터 v / length(v)를 돌려준다. v 의 길이가 0 의 경우, 결과는 무한이 된다.     


pow pow(x, y) xy 를 돌려준다.     


radians radians(x) x를 도에서 라디안 단위로 변환한다.     


reflect reflect(i, n) 입사 방향 i, 표면 법선 n으로 했을 경우의, v = i - 2 * dot(i, n) * n 에 의해 구할 수 있는, 반사 벡터 v 를 돌려준다.     


refract refract(i, n, eta) 입사 방향 i, 표면 법선 n, 굴절 eta인 상대 인덱스가 주어졌을 경우의, 굴절 벡터 v 를 돌려준다. i 와 n 의 사이의 입사각이 지정된 eta 보다 너무 크면 (0,0,0)을 돌려준다.     


round round(x) x를 가장 가까운 정수에 반올림한다.    


rsqrt rsqrt(x) 1 / sqrt(x)를 돌려준다.     


saturate saturate(x) x를 [0, 1] 의 범위에 제한한다.     


sign sign(x) x의 부호를 얻는다. x 가 0보다 작은 경우는 -1, 0과 동일한 경우는 0, 0 보다 큰 경우는 1을 돌려준다.     


sin sin(x) x의 사인을 돌려준다.     


sincos sincos(x, out s, out c) x의 사인과 코사인을 돌려준다. sin(x)는 출력 인수 s에 저장 되며 cos(x)는 출력 인수 c에 저장 된다.     


sinh sinh(x) x 의 쌍곡사인을 돌려준다.   

  
smoothstep smoothstep(min, max, x) x < min 의 경우는 0을 돌려준다. x > max 의 경우는 1을 돌려준다. x 가 [min, max] 의 범위내이면, 0부터 1 의 사이의 매끄러운 에르미트 보간을 돌려준다.     


sqrt value sqrt(value a) 제곱근 (성분마다).     


step step(a, x) (x >= a) ? 1 : 0 을 돌려준다.     


tan tan(x)  x 의 탄젠트를 돌려준다.     


tanh tanh(x) x 의 쌍곡탄젠트를 돌려준다.     


tex1D tex1D(s, t) 1D 의 텍스처 참조. s 는 샘플러 또는 sampler1D 객체. T는 스칼라     


tex1D tex1D(s, t, ddx, ddy) 도함수를 지정한, 1D 의 텍스처 참조. s 는 샘플러 또는 sampler1D 개체.

 t, ddx, ddy 는 스칼라    


tex1Dproj tex1Dproj(s, t) 1D의 투영 텍스처 참조. s 는 샘플러 또는 sampler1D 개체. t 는 4D 벡터. t 는, 참조가 실행되기 직전의 성분으로 나눗셈 된다.   

  
tex1Dbias tex1Dbias(s, t) 1D 의 바이어스 텍스처 참조. s 는 샘플러 또는 sampler1D 개체. t 는 4D 벡터. 참조를 실행하기 전에, 밉레벨이 t.w에 의해 바이어스 된다.  

  
tex2D tex2D(s, t) 2D 의 텍스처 참조. s 는 샘플러 또는 sampler2D 개체. t 는 2D 텍스처 좌표.    

 
tex2D tex2D(s, t, ddx, ddy) 도함수를 지정한, 2D 의 텍스처 참조. s 는 샘플러 또는 sampler2D 개체. t, ddx, ddy 는 2D 벡터.     


tex2Dproj tex2Dproj(s, t) 2D 의 투영 텍스처 참조. s 는 샘플러 또는 sampler2D 개체. t 는 4D 벡터. t 는, 참조가 실행되기 직전의 성분으로 나눗셈 된다.     


tex2Dbias tex2Dbias(s, t) 2D 의 바이어스 텍스처 참조. s 는 샘플러 또는 sampler2D 개체. t 는 4D 벡터. 참조를 실행하기 전에, 밉레벨이 t.w에 의해 바이어스 된다.    

 
tex3D tex3D(s, t) 3D 의 볼륨 텍스처 참조. s 는 샘플러 또는 sampler3D 개체. t 는 3D 텍스처 좌표.     


tex3D tex3D(s, t, ddx, ddy) 도함수를 지정한, 3D 의 볼륨 텍스처 참조. s 는 샘플러 또는 sampler3D 개체. t, ddx, ddy 는 3D 벡터.     


tex3Dproj tex3Dproj(s, t) 3D 의 투영 볼륨 텍스처 참조. s 는 샘플러 또는 sampler3D 개체. t 는 4D 벡터. t 는, 참조가 실행되기 직전의 성분으로 나눗셈 된다.   

  
tex3Dbias tex3Dbias(s, t) 3D 의 바이어스 텍스처 참조. s 는 샘플러 또는 sampler3D 개체. t 는 4D 벡터. 참조를 실행하기 전에, 밉레벨이 t.w에 의해 바이어스 된다.    


texCUBE texCUBE(s, t) 3D 의 큐브 텍스처 참조. s 는 샘플러 또는 samplerCUBE 개체. t 는 3D 텍스처 좌표.     


texCUBE texCUBE(s, t, ddx, ddy) 도함수를 지정한, 3D 의 큐브 텍스처 참조. s 는 샘플러 또는 samplerCUBE 개체. t, ddx, ddy 는 3D 벡터.     


texCUBEproj texCUBEproj(s, t) 3D 투영의 큐브 텍스처 참조. s 는 샘플러 또는 samplerCUBE 개체. t 는 4D 벡터. t 는, 참조가 실행되기 직전의 성분으로 나눗셈 된다.     


texCUBEbias texCUBEbias(s, t) 3D 의 바이어스 큐브 텍스처 참조. s 는 샘플러 또는 samplerCUBE 개체. t 는 4D 벡터. 참조를 실행하기 전에, 밉레벨이 t.w에 의해 바이어스 된다.    

 
transpose transpose(m) 행렬 m 의 전치행렬을 돌려준다. 입력의 크기가 m 행 x n 열의 경우, 결과차원은 n열x m행이다. 

반응형
반응형


http://goo.gl/0BzAS

 DirectX Graphics  레퍼런스  이펙트 레퍼런스  인터페이스  ID3DXBaseEffect   [목차열람] [주소복사] [슬롯비우기]
Microsoft DirectX 9.0

ID3DXBaseEffect 인터페이스


정수, 함수, 셰이더, 테크닉 등, 이펙트 파라미터의 취득 및 설정을 위한 메서드를 제공한다.

ID3DXBaseEffect 멤버

GetAnnotation어노테이션의 핸들을 얻어온다.
GetAnnotationByName이름으로 참조해, 어노테이션의 핸들을 얻어온다.
GetBool불리언 값을 얻어온다.
GetBoolArray불리언 값의 배열을 얻어온다.
GetDesc이펙트의 기술을 얻어온다.
GetFloat부동 소수점값을 얻어온다.
GetFloatArray부동 소수점값의 배열을 얻어온다.
GetFunction함수의 핸들을 얻어온다.
GetFunctionByName이름으로 참조해, 함수의 핸들을 얻어온다.
GetFunctionDesc함수의 기술을 얻어온다.
GetInt정수를 얻어온다.
GetIntArray정수의 배열을 얻어온다.
GetMatrix비전치행렬을 얻어온다.
GetMatrixArray비전치행렬의 배열을 얻어온다.
GetMatrixPointerArray비전치행렬의 포인터 배열을 설정한다.
GetMatrixTranspose전치행렬을 얻어온다.
GetMatrixTransposeArray전치행렬의 배열을 얻어온다.
GetMatrixTransposePointerArray전치행렬의 포인터 배열을 설정한다.
GetParameter최상정도 파라미터 또는 구조체 멤버 파라미터의 핸들을 얻어온다.
GetParameterByName이름으로 참조해, 최상정도 파라미터 또는 구조체 멤버 파라미터의 핸들을 얻어온다.
GetParameterBySemantic의미들로 참조해, 최상정도 파라미터 또는 구조체 멤버 파라미터의 핸들을 얻어온다.
GetParameterDesc파라미터 또는 어노테이션의 기술을 얻어온다.
GetParameterElement배열 요소 파라미터의 핸들을 얻어온다.
GetPass패스의 핸들을 얻어온다.
GetPassByName이름으로 참조해, 패스의 핸들을 얻어온다.
GetPassDesc패스의 기술을 얻어온다.
GetPixelShader픽셀 셰이더를 얻어온다.
GetString캐릭터 라인을 얻어온다.
GetTechnique테크닉의 핸들을 얻어온다.
GetTechniqueByName이름으로 참조해, 테크닉의 핸들을 얻어온다.
GetTechniqueDesc테크닉의 기술을 얻어온다.
GetTexture텍스처를 얻어온다.
GetValue임의의 파라미터 또는 어노테이션의 값을 얻어온다. 이것에는, 단순형, 구조체, 배열, 캐릭터 라인, 셰이더, 텍스처가 포함된다. ID3DXBaseEffect 의 Getxxx 형식의 거의 모든 호출의 대신으로서 이 메서드를 사용할 수 있다.
GetVector벡터를 얻어온다.
GetVectorArray벡터의 배열을 얻어온다.
GetVertexShader정점 셰이더를 얻어온다.
SetBool불리언 값을 설정한다.
SetBoolArray불리언 값의 배열을 설정한다.
SetFloat부동 소수점값을 설정한다.
SetFloatArray부동 소수점값의 배열을 설정한다.
SetInt정수를 설정한다.
SetIntArray정수의 배열을 설정한다.
SetMatrix비전치행렬을 설정한다.
SetMatrixArray비전치행렬의 배열을 설정한다.
SetMatrixPointerArray비전치행렬의 포인터 배열을 설정한다.
SetMatrixTranspose전치행렬을 설정한다.
SetMatrixTransposeArray전치행렬의 배열을 설정한다.
SetMatrixTransposePointerArray전치행렬의 포인터 배열을 설정한다.
SetPixelShader픽셀 셰이더를 설정한다.
SetString캐릭터 라인을 설정한다.
SetTexture텍스처를 설정한다.
SetValue임의의 파라미터 또는 어노테이션의 값을 얻어온다. 이것에는, 단순형, 구조체, 배열, 캐릭터 라인, 셰이더, 텍스처가 포함된다. ID3DXBaseEffect 의 Setxxx 형식의 거의 모든 호출의 대신으로서 이 메서드를 사용할 수 있다.
SetVector벡터를 설정한다.
SetVectorArray벡터의 배열을 설정한다.
SetVertexShader정점 셰이더를 설정한다.

인터페이스의 정보

상속받은곳IUnknown
헤더d3dx9effect.h
임포트 라이브러리d3dx9.lib
최저한의 operating systemWindows 98

참조

D3DXCreateEffect

반응형
반응형




DXSDK_DIR ( 환경변수 ) 설정법|… * Direct X
2011.10.25 15:26

 

내컴퓨터 -> 오른쪽 마우스 클릭후 "속성" -> 고급시스템 설정 -> 환경변수







http://cafe.naver.com/leafs/94884





그럼 위와 같은 창에서 VC++ 디렉토리를 클릭후, 우측에 포함 디렉토리에는 $(DXSDK_DIR)Include를 추가하고, 라이브러리 디렉토리에는 $(DXSDK_DIR)Lib\x86를 추가해 주세요.





반응형
반응형

http://d.hatena.ne.jp/runicalp/20081114/1226680735


  • error C2051 : case 식은 정수 상수이어야합니다. c : \ development \ sdk \ temp \ sdk ( c + + ) \ samples \ c + + \ common \ src\ d3dapp.cpp 1582

필자 환경에서는 HRESULT_FROM_WIN32가 인라인 함수 로 정의되어 있기 때문에 이것을 매크로 로 바꿉니다.

SDK ( C + + ) \ Samples \ C + + \ Common \ Src \ d3dapp.cpp 1582 행

case HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) :

case __HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) :

반응형
반응형

http://magic-finger.tistory.com/28

[HLSL] DX9 Effect에서 pass함수 변경사항.

최근에 DX9가 업데이트되면서 HLSL Effect의 패스호출 함수인 ID3DXEffec::Pass(UINT* UPass)가
ID3DXEffect::BeginPass(UINT* UPass) ID3DXEffect::EndPass();로 변경되었습니다.
대부분 D3D9책에서는 
ID3DXEffec::Pass(UINT* UPass)로 나왔을거에요.(현재 사용하고 있는 2010버전엔 없더라구요.) 
위 두 함수사이에 렌더함수를 호출하면되는데 문제는 우리가 원하는 결과가 아니라는겁니다.
문제의 원인이 되는 부분은 바로 BeginPass와 EndPass함수로서 BeginPass함수의 특성상 EndPass가 실행되기 전까지 다음 스테이트로 넘어가지않고 계속 호출하게되어 나중엔 제일 마지막에 설정한 부분에 모두 출력하게된다는 것이죠.
그렇담 여기서 몇가지 해결방법을 생각해볼 수 있겠군요.

첫번쩨로 렌더링함수를 호출할 때마다 BeginPass와 EndPass를 호출하는방법입니다. 이렇게하면 네군데에 물체가 잘나옵니다만 물체가 출력되는 결과물을 보니 원하는 순서가 아니네요? 맨 마지막에 출력되야할 물체가 맨 첫번째로 가있고, 맨처음 출력해야할 물체가 맨마지막으로 가있다는 사실을 발견할 수가 있어요. 이 방법이 해결된다고해도 반복되는 코드가 많아서 코드가 쓸때없이 길어지고 수십번이상 반복되는 코드라면 골치가 아파집니다. ㅋㅋ 어휴 

[첫번째 방법 소스코드]
ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[0]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[0]);
                Mesh[0]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[1]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[1]);
                Mesh[1]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[2]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[2]);
                Mesh[2]->DrawSubset(0);  
  
ToonEffect->EndPass();

ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[3]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[3]);
                Mesh[3]->DrawSubset(0);  
  
ToonEffect->EndPass();



두번째 방법으로 반복되는 코드를 예전과 같이 루프로 묶고 루프 안에 Begin/End Pass를 넣는 방법으로 생각해봅니다.

[두번째 방법 소스코드]
Device->Begin();

UINT Pass;
        ToonEffect->Begin(&Pass, 0);
        for(int j = 0 ; j < Pass ; j++)
        {
            
            for(int i = 0 ; i < 4 ; i++)
            {        
                ToonEffect->BeginPass(j);

                ToonEffect->SetMatrix(hWorldMatrix, &World[i]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[i]);
                Mesh[i]->DrawSubset(0); 

                ToonEffect->EndPass();   
            }
            
        }
        ToonEffect->End();

Device->End();


이렇게하면 매 루프때마다 Begin/End Pass를 호출해서 매 스테이트마다 넘어가겠지만 결과는 첫번째 방법과 동일하다는 것을 알 수가 있습니다.  

이것도 안된다 저것도 안된다...
정녕 해결방법은 없는 것일까요?

아직 포기하기엔 이릅니다! 
DirectX를 만든 MS에서 위 두 함수를 새로 만들었으면 두 함수를 책임을 져야하는 함수를 따로 안만들었을리는 없겠지요.
그것이 바로 ID3DXEffect::CommitChanges()함수입니다. 이를 이용하는 겁니다. 이 문제점의 해결방법이기도하구요.
위 함수를 렌더링함수를 불러오기 전에 호출해봅니다. (꼭 렌더링함수 호출 전에 호출해야합니다. 안그러면 첫번째나 두번째처럼 순서가 뒤바뀝니다.)

[해결방법 소스코드]
//호출순서 : 디바이스의 Begin > 이펙트의 Begin(이펙트 내의 패스 수 리턴) > 이팩트의 BeginPass(패스 수만큼 루프를 돈다)
Device->Begin();

UINT Pass;
        ToonEffect->Begin(&Pass, 0);
        for(int j = 0 ; j < Pass ; j++)
        {
            ToonEffect->BeginPass(j);
            for(int i = 0 ; i < 4 ; i++)
            {        
                ToonEffect->SetMatrix(hWorldMatrix, &World[i]);
                ToonEffect->SetMatrix(hViewMatrix, &View);
                ToonEffect->SetVector(hColor, &color[i]);
                ToonEffect->CommitChanges(); //BeginPass호출 시 그리기 전에 반드시 이 함수 호출
                Mesh[i]->DrawSubset(0);    
            }
            ToonEffect->EndPass();
        }
        ToonEffect->End();

Device->End();


결과가 어떤가요? 원하는 결과가 잘 출력되었나요?
BeginPass와 EndPass를 사용하게되면(특히 반복해서 렌더링하는 함수가 존재할 경우) CommitChanges함수도 같이 사용해야한다는 사실 잊지마세요.

ID3DXEffect::CommitChanges()호출 전

ID3DXEffect::CommitChanges()호출 후

샘플은 카툰렌더링기법입니다.

반응형
반응형

  
2007.07.10 17:53

error C2061: 구문 오류 : 식별자 'LPDIRECTXFILEDATA'

 

 

DirectX 9.0 에서 9.0C로 넘어가면서 바뀐었다

해결

 

#include <dxfile.h>






http://d.hatena.ne.jp/runicalp/20081114/1226680735


  • error C2051 : case 식은 정수 상수이어야합니다. c : \ development \ sdk \ temp \ sdk ( c + + ) \ samples \ c + + \ common \ src\ d3dapp.cpp 1582

필자 환경에서는 HRESULT_FROM_WIN32가 인라인 함수 로 정의되어 있기 때문에 이것을 매크로 로 바꿉니다.

SDK ( C + + ) \ Samples \ C + + \ Common \ Src \ d3dapp.cpp 1582 행

case HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) :

case __HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) :


반응형
반응형




이펙트로 렌더링 할 때 렌더링할때 ID3DXEffect::Begin 과 ID3DXEffect::End  블록을 사용하는데 


이때  Begin 함수에서  pEffect->Begin( NULL, var );  처럼 var 자리에 아래 값들을 지정해 각각 이펙트를 켜고 끄는 기능을 할 수 있다






http://goo.gl/0eRVP


zero ( 0 )                                         :   현재의 장치 상태와 셰이더 상태를 보관했다가 이펙트가 종료될때(ID3DXEffect::End 가 호출될때)

 상태를 복구할 것을 지시한다, 이펙트는 상태를 변겨할 수 있으며 이 플래그를 통해 이펙트가 시

 작 할 때의 상태로 되돌아 갈 수 있다


D3DXFX_DONOTSAVESTATE         : 장치의 상태를 보관했다가 복구할 것을 지시한다(셰이더 상태는 제외한다).


D3DXFX_DONOTSAVESHADERSTATE   :   셰이더 상태를 보관하고 복구하지 않을 것을 지정한다.

반응형
반응형




HatchTest_060123_parkch.zip




http://blog.naver.com/pch413/10001173790



< 자작 해칭 예제 스크린샷 >

 

 

아주~아주~아주~ 오래전에 제가 회사에서 세미나하고 올린

해칭 관련 예제 포스트(http://blog.naver.com/pch413/7330265)를 보시고

세부 구현이나 관련 자료를 문의하시는 분들이 가끔~가끔~ 계셨습니다.

(사실 REAL-TIME RENDERING 2nd Edition 책 보면 다 나옵니다.)

 

사실 자작 구현이라기 보다는 책에 있는 내용을 공부삼아 HLSL로 옮겨본 것 밖에 없고,

귀찮기도 하고 소스가 별로 깔끔하지도 못하고 엉망이라서 공개를 꺼렸는데...

이래저래 문의하시는 분들이 나중에도 생기면 더 귀찮아질 수도 있으므로

예제 실행 파일과 함께 HLSL 소스까지 공개합니다.

 

첨부된 HatchTest_060123_parkch.zip 압축파일을 받아서 적당한 곳에 풀어놓으신 후,

HatchTest 폴더 안에 있는 HatchTest.exe를 실행시키시면 예제를 돌려보실 수 있습니다.

HLSL 소스는 HatchTest.fx 파일을 참조하시면 됩니다.

 

예제를 실행하실려면 DirectX 9.0c 런타임 최신 버전이 깔려있어야 합니다.

(http://www.microsoft.com/downloads/details.aspx?displaylang=ko&FamilyID=3F2828FA-0E3C-4837-AFC0-6C67DCAA54BF)

그리고 Vertex Shader 1.1 이상, Pixel Shader 1.4 이상을 지원하는

그래픽 카드(ATI RADEON 8500급 이상)가 있어야 합니다.

 

실행시키시면 가상 광원의 위치를 나타내는 노란색의 구(sphere)가 물체 주위를 빙글빙글 돌아가는 것을 보실 수 있습니다. 그리고 그 광원 위치에 따라 해칭 패턴이 변화하게 됩니다. 마우스로 물체를 회전시킬 수도 있으니 조작해보시길 바랍니다. 그리고 우측에 있는 콤보 박스를 이용하면 표시되는 물체(구, 원뿔, 주전자, 호랑이)를 바꿀 수 있습니다.

 

< 해칭의 개념 >

 

해칭(Hatching) : 펜/잉크 소묘에서 가늘고 세밀한 평행선이나 교차선을 사용하여 객체의 음영 차이 및 요철을 표현하는 기법에 대한 일반적인 용어.

 

(개념 : 인간이 마땅히 알아야 할 상식과 도리로서 이를 알지 못하면 '개'가 된다고 하여 개념이라 함.)

 

이 예제에서 보여주는 해칭(Hatching)은 비실사 렌더링(Non-Photorealistic Rendering;NPR) 방식 중의 하나로서 해치 패턴의 밀도를 통해 그 지점의 표면이 얼마나 많은 빛을 반사하는지를 표현해주는 기법입니다. 여기서 사용하는 해칭 기법은 매우 드문드문한(빛을 많이 받는) 영역으로부터 매우 조밀한(빛을 받지 않는) 영역에 이르는 해치 패턴 맵을 이용하게 됩니다. 각 정점 별로 빛에 대한 가중치를 계산한 다음, 각 픽셀 별로 보간된 가중치에 따라 해치 패턴 맵을 적절히 혼합하여 표현해주는 방법을 사용하고 있습니다.


< Tonal Art Maps >

 

어떤 분께서 E-Mail로 Tonal Art Map(TAM)을 이용해서 구현했는지 물어보셨는데, 맞습니다.

앞서 언급한 해칭 패턴 맵이 바로 Tonal Art Map으로서 여기서는 6단계의 텍스처를 사용하게 됩니다.

하지만, 팔레트가 6개-즉, 텍스처를 6장이나 쓰게 되면 그만큼 처리 비용이 엄청나겠죠?

그래서 위의 그림과 같이 각 단계의 맵이 단색(Grayscale)임을 이용하여

텍스처의 각 색상 채널에 하나씩 할당해서 2장의 텍스처로 줄여 쓸 수 있게 합니다.

(단색 텍스처는 0~255 값을 가지는 하나의 채널로 표현할 수 있으므로

R, G, B 각각의 채널에 하나씩 집어넣을 수 있습니다.)

즉, 1,2,3 단계의 맵은 첫번째 텍스처, 4,5,6 단계의 맵은 두번째 텍스처에 할당됩니다.

(첨부된 압축 파일 안의 Hatch123.dds, Hatch456.dds가 이것입니다.)

 

이 내용은 "REAL-TIME RENDERING 2nd Edition" 책에 소개된 기법으로서

2001년 시그라프(SIGGRAPH) 논문에 있는 내용입니다.

 

Emil Praun, Hugues Hoppe, Matthew Webb, and Adam Finkelstein, "Real-time Hatching," (SIGGRAPH Proceedings, 2001), pp. 581-586.

 

아래 링크를 클릭해보시면 논문을 직접 보실 수 있습니다.

http://research.microsoft.com/~hoppe/hatching.pdf

(다소 영어의 압박을 느낄 수도 있습니다.)

 

< Vertex program source >

 

위의 소스는 정점 프로그램으로서 각 정점 별로 빛에 대한 가중치를 계산합니다.

워낙 코딩 실력이 딸려서 소스가 복잡하고 다소 더럽지만 그렇다고 나무라지는 마시길 바랍니다.

clamp, abs 함수들을 좀 복잡하게 써 놓긴 했지만, 내용은 단순합니다.

(abs는 절대값, clamp는 min~max 밖의 값을 잘라냄; max보다 크면 max로, min보다 작으면 min으로 함.)

 

쉽게 설명하면, 정점에 대한 노말 벡터와 광원 방향 벡터의

내적을 구해서 빛을 받는 정도를 [-1, 1] 구간 사이로 구한 다음, [0, 6] 구간으로 바꿉니다.

그리고나서 가장 적합한 단계들에게 가중치를 부여합니다.

 

예를 들어, 'n dot l'의 계산 결과가 0.5가 나왔다고 합시다. 어중간하게 좀 밝은 쪽이 되겠죠?

그러면, 1단계와 2단계 텍스처가 중간 정도 혼합된 형태가 되어야 할 것입니다.

위의 복잡한 식대로 계산하면 oTexWeight123과 oTexWeight456은 다음 값들을 가지게 됩니다.

 

oTexWeight123 == (0.5, 0.5, 0.0)

oTexWeight456 == (0.0, 0.0, 0.0)

 

의도한 대로 1단계와 2단계에 0.5씩 가중치가 들어갔죠?

한마디로, abs랑 clamp를 써서 적절한 단계에 가중치가 부여될 수 있도록 했습니다.

만일, 이 글을 보시는 다른 분들께서 조금 더 간단하게 쓸 수 있다고 생각하시면 알려주세요.

아직 HLSL를 많이 써보지 못하다보니 코드가 좀 엉망입니다.

(지금 생각해보니 clamp(..., 0.0, 1.0)이 아니라 saturate(...)를 쓰면 되었을 것을... 왜 저랬을까? 이런 바보같은 짓을... ㅡㅡ;)


< Fragment program source >

 

마지막으로 위의 소스는 프래그먼트 프로그램으로서

각 픽셀 별로 보간된 가중치에 따라 TAM을 혼합하게 됩니다.

 

앞 쪽에서 보여드린 TAM 그림을 다시 보시면 스트로크(stroke) 패턴들이 검정색,

바탕은 흰색으로 된 것을 알 수 있습니다.

사실 우리가 해야 할 일은 스트로크 패턴들만 뽑아내서 잘 혼합하는 것입니다.

 

그래서 이 프래그먼트 프로그램에서는 별도로 구현된

GetInverseColor 함수를 이용해서 색상을 뒤집습니다.

즉, 바탕이 검정(0.0)으로 바뀌고, 스트로크가 흰색으로 바뀌므로

스트로크 요소만 따로 혼합될 수 있습니다.

 

보간된 가중치를 각 채널에 들어있는 Grayscale 값과 곱해서 더하고,

이를 다시 GetInverseColor 함수로 뒤집어주면 우리가 원하던 최종 색상을 얻어낼 수 있게 됩니다.

 

< 참고 자료 >

 

 

1) Real-Time Rendering(2nd Edition)/Tomas Akenine-Moller, Eric Haines/A.K.Peters Limited

 

해칭 관련 내용은 이 책 보고 쁼(feel) 받고

실제로 돌려보고 싶다는 생각이 들어서 HLSL로 구현해봤던 겁니다.

현존하는 실시간 렌더링 관련 서적 중에서는 최고의 참고서입니다.

7장의 Non-Photorealistic Rendering 파트에 해칭 관련 내용이 소개되어 있습니다.

 


2) Direct3D ShaderX:Vertex and Pixel Shader Tips and Tricks/Wolfgang F. Engel/Wordware Publishing

 

사실 제 소스는 이 책에 있는 어셈블리로 작성된 해칭 소스를 거의 베끼다시피해서 HLSL로 옮긴 것에 불과합니다. 그리고 TAM 텍스처도 부록 CD 안에 들어 있는 것을 가져와서 쓴 것입니다. 원본 소스를 보고 싶으시다면 참조하십시오.


< 마침 >

 

간만에 긴 글을 포스팅해봤습니다. HLSL 써본지도 꽤 오래된 지라 가물가물하기도 하고, 글도 생각처럼 잘 써지지도 않는군요. 그리고 나름대로 머리 좀 굴려봤다고 자부했었는데... 오히려 글을 쓰고 보니 부족했던 점이 더욱 눈에 띕니다. 제가 참여하고 있는 프로젝트도 셰이더를 맘껏 쓸 수 있는 환경이 되면 좋겠지만... 렌더링과는 점점 더 멀어지는 일만 하고 있네요. 좀 더 재미있는 것을 할 수 있다면 좋으련만...

 

오뎅장수 P군

블로그 : http://blog.naver.com/pch413/

반응형
반응형



 InteliShade.msi




http://blog.naver.com/sorkelf/40147650136




cpp 파일이나 h 파일 작성시 비쥬얼 적으로 깔끔하게 해주는 컬러링과 

관련 함수등을 쉽게 찾아내게 도와주는 VS의 대표적인 기능인 Intelisense가 있다.


하지만 아직은 VS는 HLSL 편집할때의 이러한 기능을 지원하지 않는다..


NotePad++ 이나 UltraEdit등으로 편집해도 되긴 하지만..


VS에서 같이 쓰면 편한건 누구나 아는 사실이다..


분명히 누군가가 이런거 불편해서 만들어놨을텐데라고 해서 구글링 시작...


InteliShade 라는 놈을 찾아 냈다..


Step 1 : 위에 첨부한 파일을 다운 받아 설치한다





Step 2 : 설치된 폴더를 확인한다






Step 3 : VS가 깔린 폴더의 Addin 폴더에 해당 dll을 Ctrl +C, V 한다

           (일반적인 경로라면 : C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\AddIns )






Step 4 VS를 열고 도구 -> 옵션 -> 글꼴 및 색 에서 컬러링 지정을 한다 (굳이 안해도 될 듯)


적용되는 옵션들 

(Comments, DataTypes, Error, Intrinsic, Matrix, Operation, RenderState, Register, Statements Semantics, Variable, Void)





Step 5  : fx 파일을 편집한다






Utility이긴 하지만 Shader 관련이기 때문에 카테고리를 이곳으로 하기로 했다-.- 어차피 검색하면 나오겠지만..


쓰고 있는지는 프로젝트 시작하기 전부터였으나.. 올리기가 귀찮아서...


쓸데없는 부분에서 자동완성기능이 활성화 된다거나.. 처음부터 치지않으면 자동완성이 나오지 않는점..


변수명을 줄려고 한건데 자동완성기능으로 인해 시멘틱등으로 자동완성 되버리는 점등..


VS의 Intelisense 기능처럼 완벽하지는 않으나


이정도가 어디임... -_- 2010은 지원해 줄라나...

반응형

'그래픽스(Graphics) > Shader' 카테고리의 다른 글

셰이더[Effect] 함수들 ID3DXBaseEffect 인터페이스  (0) 2013.01.08
[소스] 해칭(Hatching) HLSL 소스  (0) 2013.01.05
쉐이더 기법  (0) 2012.11.02
셰이더 내장함수  (0) 2012.11.02
smoothstep  (0) 2012.11.02
반응형


http://blog.naver.com/nowcom77/20171445466


3D에서 글자를 출력하는 부분과 FPS를 출력하는 내용입니다. 

 

 

 

 

12문자 출력

   

Direct3D에서는 문자를 출력하기 위해서 LPD3DXFONT 객체를 사용한다.

   

12.1 LPD3DXFONT 객체 생성과 초기화

   

LPD3DXFONT 객체를 생성하고 초기화하는 함수로 D3DXCreateFont()가 있다.

 

HRESULT D3DXCreateFont(

__in LPDIRECT3DDEVICE9 pDevice,

__in INT Height,

__in UINT Width,

__in UINT Weight,

__in UINT MipLevels,

__in BOOL Italic,

__in DWORD CharSet,

__in DWORD OutputPrecision,

__in DWORD Quality,

__in DWORD PitchAndFamily,

__in LPCTSTR pFacename,

__out LPD3DXFONT *ppFont

);

[표 12-1] Font 생성 함수

   

Height와 Width는 글자의 가로세로 길이이며 Weight는 글자의 굵기를 결정하는 매개변수이다. Weight에 설정하는 값은WinGDI.h 헤더에 있으며 그 기본 값은 FW_NORMAL이다.

 

#define FW_THIN 100

#define FW_EXTRALIGHT 200

#define FW_LIGHT 300

#define FW_NORMAL 400

#define FW_MEDIUM 500

#define FW_SEMIBOLD 600

#define FW_BOLD 700

#define FW_EXTRABOLD 800

#define FW_HEAVY 900

   

#define FW_ULTRALIGHT FW_EXTRALIGHT

#define FW_REGULAR FW_NORMAL

#define FW_DEMIBOLD FW_SEMIBOLD

#define FW_ULTRABOLD FW_EXTRABOLD

#define FW_BLACK FW_HEAVY

[표 12-2] WinGDI.h 헤더

   

MipLevels에는 기본 값인 1을 설정하며 Italic에는 이텔릭체를 사용할 것인지의 여부를 설정하며 여기에는 일반적으로 FALSE를 설정한다.

그 외에는 기본값을 설정하면 되며 CharSet에는 DEFAULT_CHARSET을 설정하며 OutputPrecision에는OUT_DEFAULT_PRECIS으로 설정한다.

그리고 Quality에는 DEFAULT_QUALITY를 PitchAndFamily에는 DEFAULT_PITCH | FF_DONTCARE를 설정한다.

pFacename에는 글자체를 설정하는데 "Arial" 또는 “System“등을 설정한다.

여기까지 설명한 폰트의 설정값을 셋팅하여 D3DXCreateFont() 함수를 호출하면 다음과 같다.

   

LPD3DXFONT Font;

................. 생략 ................

D3DXCreateFont( m_pd3dDevice, 20, 0, FW_NORMAL, 1, FALSE, DEFAULT_CHARSET,

OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,

"Arial", &Font );

[표 12-3]

   

12.2 출력

   

글자를 출력해 주는 LPD3DXFONT 객체의 멤버 함수에는 DrawText()가 있으며 그 원형은 다음과 같다.

   

INT DrawText(

[in] LPD3DXSPRITE pSprite,

[in] LPCTSTR pString,

[in] INT Count,

[in] LPRECT pRect,

[in] DWORD Format,

[in] D3DCOLOR Color

);

[표 12-4] 출력 함수

 

pSprite에는 NULL을 설정하고 pString에는 출력하려는 문자열을 설정한다. Count에는 1을 설정하며 널문자까지를 출력하게 된다.

pRect에는 출력하려는 위치를 설정하는데 left와 top 값을 설정하면 되며 나머지는 0으로 설정한다. Format에는 문자의 정렬에 관련된 값을 설정하는데 DT_NOCLIP을 설정한다.

Color에는 출력할 색상값을 설정하며 색상값은 D3DXCOLOR()를 이용하여 설정한다.

색상값의 범위는 0.0 ~ 1.0f 까지면 그 원형은 다음과 같다.

   

D3DXCOLOR( FLOAT r, FLOAT g, FLOAT b, FLOAT a );

출력함수를 설정하면 다음과 같다.

   

RECT rt;

SetRect( &rt, 100, 430, 0, 0 );

   

Font->DrawText( NULL, "Test", -1, &rt, DT_NOCLIP, D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );

   

12.3 FPS 출력

   

FPS(Frame Per Second)는 1초에 화면 전환이 몇 번 일어났는가를 측정한 값을 말한다.

그래서 FPS로 게임 엔진의 렌더링 성능을 평가하는 경향이 있으며 게임 엔진의 개발 초기에 는 항상 FPS를 출력하면서 프로그래밍을 한다.

컴퓨터에서는 초 단위가 아닌 밀리세컨드 단위로 시간 값을 가져오므로 1초는 1000 밀리세컨드가 되며 경과된 시간이 1초인지를 알 수 있는 방법은 현재 시각과 이전 시각의 차를 이용하거나 매 프레임마다 경과된 시간을 누적하여 판단하는 방법등이 있다.

아래의 소스는 매 프레임마다 경과된 시간을 누적하여 판단하는 소스이다.

   

void CGameEdu01::OnInit()

{

int i;

   

RECT rect;

D3DVIEWPORT9 vp;

GetClientRect( m_hWnd, &rect );

   

vp.X = 0;

vp.Y = 0;

vp.Width = rect.right - rect.left;

vp.Height = rect.bottom - rect.top;

vp.MinZ = 0.0f;

vp.MaxZ = 1.0f;

   

m_Eye.x = 0.0f;

m_Eye.y = 10.0f;

m_Eye.z =-32.0f;

   

m_At.x = 0.0f;

m_At.y = 0.0f;

m_At.z = 0.0f;

   

m_Up.x = 0.0f;

m_Up.y = 1.0f;

m_Up.z = 0.0f;

   

D3DXMatrixLookAtLH( &m_matView, &m_Eye, &m_At, &m_Up );

m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_matView );

D3DXMatrixPerspectiveFovLH( &m_matProj, D3DX_PI / 4, 1.0f, 1.0f, 100.0f );

m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_matProj );

m_pd3dDevice->SetViewport( &vp );

   

D3DXCreateFont( m_pd3dDevice, 20, 0, FW_NORMAL, 1, FALSE, DEFAULT_CHARSET,

OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,

"System", &m_pFont );

}

   

void CGameEdu01::OnRender()

{

char string[100];

RECT rt = { 10, 10, 0, 0 };

   

sprintf( string, "FPS: %d", m_nFPS );

m_pFont->DrawText( NULL, string, -1, &rt, DT_NOCLIP, D3DXCOLOR( 1.0f, 1.0f,

0.0f, 1.0f ) );

m_nFPSCount++;

}

   

void CGameEdu01::OnUpdate()

{

DWORD dwCurTime = GetTickCount();

static DWORD dwOldTime = GetTickCount();

static DWORD dwAccumulateTime = 0; // 누적 경과 시간

   

m_dwElapsedTime = dwCurTime – dwOldTime; // 프레임 경과 시간

dwOldTime = dwCurTime;

   

dwAccumulateTime += m_dwElapsedTime; // 누적

if( dwAccumulateTime >= 1000 ) // 1초 경과 체크

{

dwAccumulateTime = 0;

m_nFPS = m_nFPSCount;

m_nFPSCount = 0;

}

}

   

void CGameEdu01::OnRelease()

{

      m_pFont->Release();

}

   

  

[출처] 12강. 글자 출력|작성자 nowcom77

반응형
반응형


http://dark0946.tistory.com/63


조명

환경광(Ambient Light)  : 

난반사광(Diffuse Light) :

정반사광(Specular Light) :




재질( = 머트리얼) 지정
D3DMATERIAL9
{
Diffuse  - 표면이 반사하는 난반사광
Ambient - 표면이 반사하는 환경광
Specular - 표면이 반사하는 정반사광
Emissive - 자체 발광
Power - 발광 정도
}




광원
 - 점 광원(Point Light)
멀리 갈수록 어두워지며, 멀리갈수록 그림자가 커진다.

- 방향성 광원(Directional Light)
 = 태양광과 비슷. 빛의 밝기는 똑같음. 각도의 영향

- 스포트 광원(Spot Light)
특정 영역에만 비춤.(스포트라이트, 손전등과 유사)
가운데 지점은 밝고 주변으로 갈수록 어두워짐.


D3DLIGHT9
{
D3DLIGHTTYPE  Type - 광원 종류
D3DCOLORVALUE Diffuse - 표면이 반사하는 난반사광 색상
D3DCOLORVALUE Ambient - 표면이 반사하는 환경광 색상
D3DCOLORVALUE Specular - 표면이 반사하는 정반사광 색상
D3DVECTOR Position  -   광원의 위치 지정 벡터 (방향성광원은 상관없음 - 거리에따라 빛의 세기가 변하지 않음.)
D3DVECTOR Direction  - 빛이 향하는 방향 지정. (점광원은 필요없음 - 주변으로 다 비치니까)
float Range;  - 빛이 소멸되는거리. (Ex. 남산 언덕에 있는 가로등 하나가 내 얼굴까지와서 비추진 않는다.)
float Falloff; - (스포트에서만 사용) 밝은 원과 주변 어두운 원의 밝기 차이
float Attenuation0; - 상수감소
float Attenuation1; - 선형감소
float Attenuation2; - 이차감소
float Theta;     -스포트 광원에서 가장 밝은부분 비추는 각도
float Phi; - 스포트 광원에서 전체를 비추는 각도
}





http://dark0946.tistory.com/65



 D3DLIGHT9 dir;
 ::ZeroMemory(&dir, sizeof(dir));
 dir.Type      = D3DLIGHT_DIRECTIONAL;   // 조명 종류
 dir.Diffuse   = d3d::WHITE;  // 난반사광 색상
 dir.Specular  = d3d::WHITE * 0.3f;  // 정반사광 색상
 dir.Ambient   = d3d::WHITE * 0.6f;  // 환경광 색상
 dir.Direction = D3DXVECTOR3(0.0f, 0.0f, -5.0f); // x축 방향에서 빛이 비춰짐.


  D3DXVECTOR3 pos(0.0f, 0.0f, -10.0f);   // 원점 to  벡터좌표 X  -> 벡터좌표 -> 원점  :: 화살표 방향을 기준
  D3DXCOLOR c1 = d3d::WHITE;
  D3DLIGHT9 p1  = d3d::InitDirectionalLight(&pos,&c1);


반응형
반응형



Device 초기화  Direct 2D 

2012/05/08 05:40

복사http://blog.naver.com/dyunarion/80159553505

디바이스 초기화

 

장치의 정보를 가져오는데 성공했으면 이제 장치를 원하는 방향으로 세팅해야 합니다.

이 단계는 D3DPRESENT_PARAMETERS 구조체 인스턴스를 채우는 일로 이 구조체는 IDirect3DDevice9 객체의 성격을 결정하는데

이용 됩니다.

 

우선 세팅할 구조체를 선언하겠습니다.

D3DPRESENT_PARAMETERS d3dpp;   //이 구조체는 앞으로 그래픽 장치의 설정을 담을 용도입니다.

ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));  //값을 넣어주기 전에 우선 전부 0으로 만들겠습니다.

 

D3DPRESENT_PARAMETERS 구조체의 멤버는 개수가 좀 많습니다.

 

BackBufferWidth 와 BackBufferHeight는 후면 버퍼의 너비와 높이이며 UINT형 입니다.

백버퍼의 가로길이, 세로길이를 넣어주시면 됩니다.

d3dpp.BackBufferWidth = WINSIZEX;  //저는 미리 const 해둔 클라이언트 가로와 세로로 하겠습니다.

d3dpp.BackBufferHeight = WINSIZEY;

 

BackBufferFormat 은 백퍼버의 픽셀 포멧으로 저는 32비트로 하겠습니다.

d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;

 

BackBufferCount 는 사용할 백버퍼의 수를 의미하는데 보통 1을 지정해서 한개의 백버퍼를 사용합니다.

d3dpp.BackBufferCount = 1;

 

MultiSampleType과 MultiSampleQuality는 멀티샘플링의 사용여부와 그 수위로 이미지를 보다 더 부드럽게 표현이 가능한 옵션입니다.

d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;  //저는 사용하지 않겠습니다.

d3dpp.MultiSampleQuality = 0; //사용하지 않으므로 0으로 두겠습니다.

 

SwapEffect 는 플리핑 체인의 버퍼가 교환되는 방법입니다. D3DSWAPEFFECT_DISCARD가 가장 효과적입니다.

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

 

hDeviceWindow는 사용할 윈도우의 핸들로 드로인의 대상이 될 윈도우를 지정해 줍니다.

d3dpp.hDeviceWindow = g_hWnd;  //미리 잡아둔 hWnd를 사용하겠습니다.

 

Windowed는 윈도우 모드를 지정합니다. true로 할 경우 윈도우 화면을 false로 할 경우 전체 화면이 지정됩니다.

d3dpp.Windowed = true; //창 모드로 하겠습니다.

 

EnableAutoDepthStencil은 Direct가 자동으로 깊이/스텐실 버퍼를 만들고 관리하게 하려면 true로 지정합니다.

d3dpp.EnableAutoDepthStencil = true;

 

AutoDepthStencilFormat은 깊이, 스텐실 버퍼의 포맷입니다.

d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; //깊이에 24bit 스텐실에 8bit 사용

 

Flags는 몇 가지 부가적인 기능으로 0으로 하거나 D3DPRESENTFLAG 집합의 멤머중에 하나를 지정할 수 도 있습니다.

d3dpp.Flags = 0; //저는 사용하지 않겠습니다.

 

FullScreen_RefreshRateInHz은 재생율을 지정합니다.

d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; //디폴트 재생율을 이용합니다. (모니터의 화면 주사율)

 

PresentationInterval은 시연 간격으로 일반적으로 IMMEDIATE(즉시시연)하거나 DEFAULT(재생율)로 합니다.

PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

//DEFAULT로 할 경우 모니터의 주사율에 따라 알아서 정해집니다.

 

D3DPRESENT_PARAMETERS의 값을 채운 뒤에는 새로운 메서드를 이용해 IDirect3DDevice9 객체를 만들 수 있습니다.

m_p3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, Vp, &d3dpp, &m_p3Device); 

//m_p3D 는 LPDIRECT3D9 (IDirect3D9 컴객체) 을 인스턴스한 것입니다. 

첫번째 원소는 Adapter로 디스플레이어 어댑터를 지정합니다. DEFAULT는 기본 장치

두번째 원소는 DeviceType으로 이용할 장치 타입을 지정합니다. REF도 있지만 여기서는 HAL을 지정하겠습니다.

세번째 원소는 hFocusWindow입니다. 장치가 드로잉할 윈도우의 핸들을 넘겨주면 됩니다.

네번째 원소는 BehaviorFlags로 버텍스 프로세싱 타입을 지정하시면 됩니다. 미리 만들어둔 Vp를 여기서 사용합니다.

다섯번째 원소는 pPresentationParameters 는 미리 초기화해둔 D3DPRESENT_PARAMETERS 인스턴스를 지정합니다.

마지막 원소로  ppReturnedDeviceInterface가 있습니다. 생성된 장치를 리턴함으로

미리 LPDIRECT3DDEVICE9을 인스턴스한 m_p3Devie를 지정합니다.

CreateDevice 는 HRESULT를 리턴함으로 FAILED 매크로를 이용하여 성공 실패를 알릴수도 있습니다.

 

if(FAILED(m_p3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd, Vp, &d3dpp, &m_p3Device)))

{

MessageBox(g_hWnd, L"디바이스 장치 생성 실패", L"SYSTEM ERROR", MB_OK);

}




[출처] Device 초기화 |작성자 서버

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

글자 출력  (0) 2013.01.04
D3DLIGHT9 광원  (0) 2013.01.02
D3D 에서의 HRESULT 값의 의미  (0) 2012.12.30
FPS 와 프레임 즉시 렌더링  (0) 2012.12.27
renderState를 쉽게 조작하기 IDirect3DStateBlock9  (0) 2012.12.22
반응형

http://blog.naver.com/maelblood/20161497755



Direct에서 Com 객체를 사용하다 보니 HRESULT를 사용하게 되었다.


HRESULT : 32bit signed 정수형이다.


HRESULT는 반환형 중 하나이다.


COM규정에 의한 것은 아니지만 COM Interface에 소속된 대부분의 함수들은   HRESULT의 반환값을 가진다.

이렇게 대부분  COM Interface에 소속된 함수들이 반환형으로 HRESULT를 사용함으로 클라이언트에게 일관성 있는

함수의 정보를 전달할 수 있게 된다.


HRESULT의 원래 목적은 공식적으로 OS/ 2 운영 체제의 여러 하위 시스템에 오류 코드간의 충돌을 방지하기 위해 

내부공개와 MS 모두 사용하기 위해 오류 코드의 범위를 배치하는 것이었다.


HRESULT내에는 에러코드의 본형과 출저에 대한 다양한 비트정보를 가지고 있다.(보통 COM 프로그래밍)


사용방법은 bool형의 true / false 똑같이 SUCCEEDED/FAILED를 사용한다.

bool형과 차이점이 있다면 굳이 리턴 값을 받지 않아도 되는 것이 다른 점이다.


Device초기화 하려고 GetDeviceCaps 함수로 장치 가져오기를 할때


if(FAILED(P3D->GetDeviceCaps(.....)))

{

MessageBox(L"장치 가져오기 실패!!");

return E_FAIL;

}

return S_OK;

이런식으로 사용이 가능 합니다.


디바이스 장치 가져오기가 실패를 하면 메시지를 출력하게 한 것인데 디버깅이 편리합니다.

(HRESULT 함수를 사용하는 이유는 디버깅이 용이하기 때문)


주의할 점

bool형은  true/ false 가 1/0 이지만 HRESULT의 SUCCEEDED/FAILED는 0/1의 값을 가지고 있는 점이 다른 점입니다.


HRESULT  의 구조


 Bit

 0

 1

 2

 3

 4

 5

 6

 7

 8

 9

 10

 12

 13

 14

 15

   ->

 Field

 Code


 Bit

 16

 17

 18

 19

 20

 21

 22

 23

 24

 25

 26

 27

 28

 29

 30

 31

 Field

 Facility

 X

 N

 V



 Field

 설명

 S

 Severity - 함수의 성공과 실패를 알려준다.

 (return : 0 - 성공과 실패를 알려준다.) 

 R

 실별코드의 예약부분

 (return : 1 - 실패) 

 C

 Customer - 그 값이 사용자 정의 인지 아닌지 식별하는 비트

 (return : 1 - 사용자 정의)

 N

 식별코드의 예약부분, 상태값 발견을 위해 쓰인다.

 X

 식별코드의 예약부분

 Facility

 에러를 담당하는 시스템 서비스를 알려준다. 식별 코드는 아래와 같다.

  ① RPC ② Dispatch ③ Storage ④ ITF ⑤ ⑥ ⑦ Win32 ⑧ windows ⑨ SSPI ⑩ Control ⑪ CERT

 Code

  Facility의 상태 코드


HRESULT의 상태 정보 요약


 S_OK

 때때로 Boolean TRUE 값(0x00)으로 S_FALSE와 함께 사용되며 함수가 성공하였음을 의미 한다.

 NOERROR

 S_OK와 동일한 의미 이다.

 S_FALSE

 S_OK와 반대로 Boolean FALSE 값(0x01)으로 함수가 실패 했음을 의미 한다.

 E_OUTOFMEMORY

 필요한 메모리를 할당할 수 없음 

 E_NOTIMPL

 멤버 함수에 구현 코드가 포함되어 있지 않다.

 E_UNEXPRCTED

 치명적인 실패를 의미한다.

 E_INVALIDARG

 하나 혹은 그 이상의 인자가 타당하지 않음

 E_NOINTERFACE

 요청한 인터페이스를 지원하지 않음

 E_POINTER

 타당하지 않은 포인터

 E_HANDLE

 타당하지 않은 처리

 E_ABORT

 작동 중지

 E_FAIL

 특정하지 않은 실패

 E_ACCESSDENIED

 일반적인 접근이 금지된 에러




LRESULT : long타입, Win32 환경에서 메시지 처리를 마친 후 OS에게 신호를 주기 위한 값


LRESULT는 long 변수의 다른 이름일 뿐이다. long 이라는 리턴값을 쓰지 않고 LRESULT라고 

재 선언한 것은 이 값이 리턴 값임을 좀 더 명확히 나타내기 위한 것이다.

Win32 API에서 CALLBACK함수 앞에는 LRESULT가 반환된다.


LRESULT CALLBACK WndProc(HWND hwnd, UINT iMessage, WPARAM wParam,.....)

{

....

}


LRESULT의 반환값은 무엇일까?


LRESULT는 long 타입형으로 Win32 환경에서 메시지 처리를 마친후 O/S 에게 어떤 신호를 주기위해 사용되는 값이다.

각각의 메시지 case에 대한 처리 값이 때로는 단순히 -1, 0, 1 등으로 어떤 때는 비트 플래그로 O/S 가 알수 있게 설정한다.

또는 포인터를 캐스팅해서 반환하기도 한다. 이는 포인터가 4Byte이기 가능하다. 윈도우 프로그램에서는 LRESULT값으로

객체의 포인터를 반환하는 것을 볼 수있다.


0을 리턴하면 OS는 더이상 메시지에 대한 처리를 하지 않고 프로그래머가 직접 처리한다는 의미를 갖는다.


-1을 반환할때도 있는대 이 경우 O/S가 진행하던 작업을 취소시키는 의미를 갖는다.

[출처] HRESULT / LRESULT |작성자 살발해

반응형
반응형


http://creaty.net/game/?menu=OpenFM&bid=3&mod=view&post=9



내용 :

 안녕하세요~ 

제가 간단한 게임을 만들고 있는데요 제가 만든 컴퓨터에서는 속도가 적당한데 

다른 컴퓨터에서 하면 엄청 빠르거든요. 그래서 이것저것 뒤져보다가 

프레임 동기화라는 것을 보았습니다. 그래서 검색도 해봤는데 원하는 답이 없어서요 

어떻게 적용시켜야되는건지 감이 잡히지가 않아서요. 

FPS 값을 구해서 이것으로 어떻게하는건가요? 

조언좀 부탁드립니다 ㅠㅠ

이 글은 GPG스터디와 연결된 글입니다. - [Gpg Study 원문보기]


D3DPRESENT_PARAMETERS 구조체를 설정하셔야 합니다.
내용 :

D3DPRESENT_PARAMETERS 구조체의 PresentationInterval 를 어떻게 설정하느냐에 따라 프레임이 천차만별로 달라질 수 있습니다.

보통 사용하는 플래그는 3종류가 있는데, 그것들은 다음과 같습니다.

 

D3DPRESENT_INTERVAL_DEFAULT : DirectX가 적절한 값을 선택하여 렌더링간격을 조절한다.

D3DPRESENT_INTERVAL_IMMEDIATE  : 기다리지 않고, 항상 렌더링한다. (프레임 무제한)

D3DPRESENT_INTERVAL_ONE  : 모니터 갱신이 1번 이루어지는 시간에 렌더링 간격을 맞춘다.


 

만약 프레임이 아니라, 이동에 관한 내용이셨다면 각 프레임간의 시간차이를 이용해 이동거리를 보간해주셔야 합니다.

 

// 시간지정

static time_t before_time = timeGetTime(); // 시간값 초기화

time_t now_time = timeGetTime(); // 현재시간

// 시간차이를 구한다.

time_t tick = timeGetTime() - before_time;

 

// 이동거리 계산 : 가장 간단하게 보간하는 방법은 시간값을 곱하는 것입니다.

position = position + move * tick / 1000.0f;

// 일반적으로 1초에 move 만큼 움직이기위해 1000을 나눠줍니다. 이것은 timeGetTime 함수의 해상도 때문

 

// 마지막으로 현재 프래임의 시간을 저장하고, 다음 프레임에 이용한다.

before_time = now_time;


반응형
반응형
http://blog.naver.com/dlqudgml81/50119354700


IDirect3DStateBlock9
기능 - 렌더링 스테이트를 캡슐화
다른 기능을 제외하더도 렌더링 스테이트를 제대로 관리 안하고 있을시에 초기로 돌리기에 아주 편했다.
사용법은 SDK를 참조하자!
 
ex ) 간단히 현재 렌더링 스테이트를 저장하고 초기화 하는 방법
1. CreateStateBlock ( ); // 생성한다.
2. IDirect3DStateBlock9 ->Capture();를해주면 이후에 모든 렌더링 스테이트를 저장한다.
3. IDirect3DStateBlock9 ->Apply(); 초기로 돌려준다.





http://diefish.egloos.com/10099055

DirectX에서 재공해주는 IDirect3DStateBlock9 를 이용하면
D3D렌더링 옵션정보를 잠시 기억했다가 다시 원복시켜주고 싶은 시점에서 전상태로 돌려주도록 할수 있다.


// 첫번째 파라미터 관련
typedef enum _D3DSTATEBLOCKTYPE
{
    D3DSBT_ALL                    = 1,          // capture all state
    D3DSBT_PIXELSTATE       = 2,         // capture pixel state
    D3DSBT_VERTEXSTATE   = 3,          // capture vertex state
    D3DSBT_FORCE_DWORD   = 0x7fffffff,
} D3DSTATEBLOCKTYPE;




[사용예]

// IDirect3DStateBlock9의 초기화 관련
IDirect3DStateBlock9* pStateBlock = NULL;
pd3dDevice->CreateStateBlock( D3DSBT_ALL, &pStateBlock );



g_pStateBlock->Capture();    // 현재 설정을 기억
    // <-- 이부분에서 다른 설정으로 랜더링

g_pStateBlock->Apply();       // Capture()를 호출했던 시점의 상태로 원복



http://gigaboy.egloos.com/10734021


IDirect3DStateBlock9를 사용한 렌더상태 조작 D3D
by gigaboy 2011/06/28 14:32 gigaboy.egloos.com/10734021 



IDirect3DStateBlock9* pStateBlock = NULL;
gd3dDevice->CreateStateBlock( D3DSBT_ALL, &pStateBlock );  // 프로그램 생성할 때 초기화



// 변경되는 렌더 스테이트 BeginStateBlock, EndStateBlock 사이에 입력.
gd3dDevice->BeginStateBlock(); 

gd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );  // 와이어 프레임.

gd3dDevice->EndStateBlock( &pStateBlock ); // pStateBlock에 상태들이 기록되어 있다.


gd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );  // 솔리드로 그리고 싶다.

drawObjectA(); // 솔리드로 그려진다.


pStateBlock->Apply(); // 이전에 기억해 두었던 렌더 상태로 되돌린다.

drawObjectB(); // 와이어 프레임으로 그려진다.
drawObjectC();

pStateBlock->Release(); // 프로그램 종료시 해제




구와 기둥은 WIRE 로 그려지고 있지만 바닥은 SOLID로 그려지고 있다.



 가능하면 렌더 상태들을 FX 안에서 사용하는게 편한것 같다.







반응형
반응형
http://goo.gl/JeVjN

출처 : GPG

소프트 파티클이란?

소프트 파티클을 만들어주는 기술의 정확한 명칭은 Depth bias blend이다.

Depth bias blend는 스프라이트 텍스처에 가상적인 두께를 만들어서 그 두께 정보가 무엇인가와 교차하면 교차하는 객체나 표면의 픽셀의 색과 그 스프라이트 텍스처의 교차되는 부분의 픽셀 색의 최대 근사값을 구해 교차하는 부분의 파티클 픽셀의 색을 보간하는 연산을 통해 교차선을 부드럽게 만들어주어 칼날과 같은 날카로운 교차선이 나타나지 않게 하는 기법이다.

이것을 스프라이트 기반의 Emitter파티클에 사용할 시에 소프트 파티클이라고 불리게 되는 것이며 활용되는 부분은 파티클뿐만이 아니라 여러 부분에 사용할 수 있다.

기존의 게임들에서 화염, 폭포수, 연기와 같은 파티클이 화면상의 다른 3D 객체나 월드 표면과 교차하면 그 칼날과 같은 교차선이 강하게 드러나는 매우 부자연스러웠던 연출을 본적이 때때로 있을것이다.

불꽃이나 탄피같은 파티클은 매우 작은 폴리곤 덩어리들에 알파값을 준 텍스처를 사용해 표현하기 때문에 다른 면과 교차해도 교차선같은게 드러나는 일이 없지만 자욱한 연기나 뿜어져 나오는 화염, 또는 사방으로 튀기는 물방울이나 폭포수와 같은 Emitter 파티클은 그 파티클의 모양을 그린 텍스처를 앏은 사각형 텍스처에 붙인 포인트 스프라이트 를 여러개를 사용해 만들어내는 것이기 때문에 다른 면과 교차한다면 그 교차선이 강하게 드러나게 된다.

이 기술의 알고리즘은 오래전부터 구상되었었고 사용되어 왔지만 그 명칭이 불분명하였다. 예를 들어 Infinity Ward의 2005년작 Call of Duty 2는 이 기술을 옵션에서 Zfeather Smoke라는 이름으로 명명하였고 어떤 게임들에선 종종 소프트 엣지 (Soft Edge)라는 이름으로 불리기도 한다. 이번에 MS에서 DX10 D3D 10 기술표를 내 놓으면서 거기에 기본적으로 포함된것중 하나가 이 기법인데 거기서는 소프트 파티클이란 이름으로 정의하고 있으며 최근의 게임이나 엔진들도 소프트 파티클이란 이름을 사용하고 있어서 소프트 파티클이란 이름으로 굳어지고 있다.

아래의 스크린샷들은 Capcom사의 Lost Planet의 게임 화면으로 위의 것은 소프트 파티클 처리가 되지 않은 스크린샷이고 아래의 것은 소프트 파티클 처리가 되어 있는 스크린샷이다. 서로 대조하여 그 교차선이 드러나고 안드러나고의 차이가 극명하게 드러난다.

화염 파티클 (스프라이트 텍스처)이 몬스터나 오브젝트, 벽, 바닥, 천장 등에 교차하여 그 교차선이 강하게 드러나고 있다.

소프트 파티클 처리가 되어서 화염 파티클 (스프라이트 텍스처)이 표면과 교차되는 부분의 픽셀의 색이 교차되는 표면 부분의 텍스처 색과 중간으로 보간되어 그 교차선이 마치 없는것처럼 부드럽게 보인다.

이 Depth bias blend처리를 물가의 부드러운 교차선 처리 (이것을 잘 활용한 예로는 2006년에 출시한 Ubisoft의 Splinter Cell: Double Agent가 있으며 곧 출시 예정인 Crysis에서도 구현)에 사용하는 것도 가능하며 특히 디자이너가 응용하기에 따라서 기존에 표현하기 힘들었던 것들을 부드럽게 표현 가능하다.

기본의 Depth bias blend처리를 하지 않은 상태에선 스프라이트 텍스처를 여러장을 사용해서 서로 겹치지 않게 정렬하면 자욱한 연기따위는 만들수 있었지만 어느 방향에서 바라보아도 입체적인 연기나 구름따위를 만들려면 그 스프라이트 텍스처들이 서로 교차해야하기 때문에 교차선이 드러나서 만들어도 비정상적인 모습으로 보이게되어 제대로 된 표현이 불가능 했었다.

Depth bias blend처리를 하고 스프라이트 텍스처를 여러장을 사용하여 서로 교차시키면서 입체감이 있게 구성한다면 볼륨감이 있는 연기, 혹은 구름 등을 만들어 낼수 있게 된다. 이것은 Volumetric Particles (볼류메트릭 파티클)이라고 불리기도 하는데 볼류메트릭 파티클이란 기법은 사실은 별도로 존재하는 것이 아니며 소프트 파티클을 6방향면체 혹은 그 이상으로 둘러싼 것에 불과하다.

이것을 응용하면 볼류메트릭 파티클에다가 광원과 음영처리도 보다 자유롭게 사용이 가능 하다. 왜냐하면 교차선이 드러나지 않고 부드럽게 보간되어 자연스러운 음영처리가 가능해지기 때문이다. 이를 응용하면 광원이 반사되는 연기, 햇빛이 반사되거나 투과되는 구름, 구름 아래로 뻗어나오는 구름 등의 그림자 등이 구현 가능하다.

그리고 이 Depth bias blend기법을 사용해서 안개속이나 수중에서의 부드럽게 보간되는 빛의 변화 (이것을 잘 활용한 예로 역시 2006년에 출시한 Ubisoft의 Splinter Cell: Double Agent가 있으며 앞으로 출시될 Crysis에서도 구현)가 표현이 가능하다.

이 기법들은 DX10의 D3D 10에 예제로 포함된 것들이며 복잡한 응용 단계는 DX9급 이상은 되야 가능하지만 기본적인 보간법 (위의 스크린샷에서 소프트 파티클 처리) 구현자체는 DX7 이하급의 고정 파이프라인 상으로도 구현이 가능한 매우 단순한 기술이다.

소프트 파티클을 최초로 구현해 출시한 게임은 2005년에 출시한 Ubisoft의 Splinter Cell: Chaos Theory이며 같은 해에 출시한 Call of Duty 2가 있었고 이후 게임들에선 거의 기본적으로 채용하고 있다.

최근에 발매된 게임들은 이와 같은 소프트 파티클 처리는 기본적으로 지원하는 단계에 이르렀다.

이를 응용해 볼류메트릭 파티클이나 음영 처리 등의 더 복잡한 기법들의 사용도 언리얼 엔진 3와 같은 최신의 게임 엔진들이라면 모두 지원하고 있는 기술들이다.


반응형
반응형

HRESULT h0 =D3DERR_NOTFOUND                ;                    //-2005530522

HRESULT h1 =D3DERR_MOREDATA                ;                    //-2005530521

HRESULT h2 =D3DERR_DEVICELOST              ;                    //-2005530520

HRESULT h3 =D3DERR_DEVICENOTRESET      ;                    //-2005530519

HRESULT h4 =D3DERR_NOTAVAILABLE          ;                    //-2005530518

HRESULT h5 =D3DERR_OUTOFVIDEOMEMORY;                    //-2005532292

HRESULT h6 =D3DERR_INVALIDDEVICE          ;                    //-2005530517

HRESULT h7 =D3DERR_INVALIDCALL             ;                   //-2005530516

HRESULT h8 =D3DERR_DRIVERINVALIDCALL ;                    //-2005530515

HRESULT h9 =D3DERR_WASSTILLDRAWING  ;                   //-2005532132

HRESULT h10 =D3DOK_NOAUTOGEN                ;                 //141953135                        양수





반응형
반응형


http://www.gpgstudy.com/gpgiki/D3D%20%EB%94%94%EB%B0%94%EC%9D%B4%EC%8A%A4%20%EC%86%8C%EC%8B%A4%20%EC%B2%98%EB%A6%AC




D3D 디바이스 소실 처리


이 페이지는 http://www.gpgstudy.com/forum/viewtopic.php?topic=1451 에 올라온 '과객' 님의 글에 기초한 것입니다. 수정, 보충 가능(1 인칭 언급을 제거하는 것도 포함해서요)

외부에서 링크를 걸 때 한글 관련 문제가 있다면 http://www.gpgstudy.com/gpgiki/DxDeviceLostHandling 를 사용하세요.

참여한 분들: 과객, ...

디바이스 소실의 두가지 경우

1. 디바이스 소실되었고 복구 불가능의 경우

: 이 경우에는 대책이 없다. 전부(IDirect3DDevice를 통해 생성된 모든 리소스들과 IDirect3DDeivce객체) 해제한 후 처음부터 다시 생성한다.

2. 디바이스 소실되었고 복구 가능의 경우

: 이 경우에는 디바이스에 올라간 리소스(리소스 생성시 D3DPOOL_DEFAULT 플래그를 이용하여 생성된 객체들)들만 새로 로딩하면 된다.

특이사항

디바이스가 소실되어도 IDirect3DDevice관련 함수들이 성공을 반환 할 경우가 있다.

도움말에 보면 "디바이스가 소실되어도 동작은 보증된다"고 되어있다. 물론 이때의 동작은 헛동작이다. 아무 효과가 없는것이다. 왜 이런식인가 생각해보니, 밑의 글을 읽어보면 알겠지만,, 언제 어떻게 디바이스 손실이 발생할지 모르니 프로그래머로써는 이런 상황을 대처 할 수 없는것이다. 디바이스와 관련된 모든 함수들에 대해서, 리턴값을 체크하지 않는한 불가능하다는 얘기이다. 그리고 손실된 디바이스 자원이 언제 넘어오게 될지도 모르는 상황에서 이런 처리는 너무 고난이도일껏 같다. 차라리 처리되는것 처럼 보이고, 실제로는 처리가 안되게 하는것이 훨씬 이득일껏 같다. 어디까지 제 추측입니다. 틀렸어도 양해를..

왜 이딴게 있는걸까?

예를들면, 2개의 응용프로그램 A와 B가 돌아가는 상황에서, A란 놈과 B란 놈 둘다 비디오 램을 많이 사용하는 프로그램이었다 치자. 이 상황에서 A란 프로그램이 돌아가고 있는 상황이어서 비디오 램의 여유분이 없었다 치자, 자.. 이제 문제의 B가 실행되어 졌을 경우,, 어떻게 해야할까? Win32는 멀티 태스킹 환경이다. 고로 여러 응용프로그램들이 같은 하드웨어 자원을 공유한다. 즉, DOS처럼 하나의 응용프로그램이 하드웨어 자원을 독점하면 안된다는 것이다. 고로 윈도우즈가 택한방식이활성화 애플리케이션에게 자원을 넘겨주자는 방식이다. A가 활성화되면, A에게 자원을 주고, B가 활성화되면 B에게 자원을 준다. 그러므로 사용자는 두 응용프로그램을 동시에 사용할 수 있는것이다. 덕분에 프로그래머는 귀찮지만은... 어디까지 제 추측입니다. 틀렸어도 양해를.. 아니지 지적을..

디바이스 소실 처리

IDirect3DDevice::TestCooperativeLevel()을 호출하여, 디바이스를 복구 할 수 있는지 검사해본다. 반환값(HRESULT)이

  • D3DERR_DEVICELOST인 경우 디바이스가 소실되었고 아직 복구할 수 없는 상태이다. 복구할 수 있을때까지 대기한다.
  • D3DERR_DEVICENOTRESET인 경우 디바이스가 소실되지만 지금 복구할 수 있는 상태이다. 디바이스를 복구한다.

디바이스 복구

  1. . D3DPOOL_DEFAULT로 잡은 리소스들을 전부 릴리즈한다. %%%(안그러면 다음에 호출될 IDirect3DDevice::Reset()이 실패할것이다.)
  2. . IDirect3DDevice::Reset()을 호출한다. %%%(Reset()을 그냥 IDirect3DDevice의 복구명령어라 생각하면 이해가 편함)
  3. . 디바이스를 다시 셋팅한다.(랜더스테이트, 뷰 행렬등..)
  4. . D3DPOOL_DEFAULT로 잡은 리소스들을 다시 로드한다.

Adapter나 D3DDEVTYPE이 변경되어야 하는 경우에는 디바이스를 다시 생성해야 한다.

  1. . 모든 리소스들을 릴리즈한다.
  2. . 디바이스를 릴리즈한다.
  3. . 디바이스를 새로 생성한다.
  4. . 디바이스를 다시 셋팅한다.(랜더스테이트, 뷰 행렬등..)
  5. . 모든 리소스들을 다시 로드한다.

디바이스가 소실되는경우

풀스크린 모드일때..

  • 다른 애플리케이션이 디바이스를 점유하는 경우.
    • 애플리케이션이 작업표시줄로 최소화 되는 경우.
    • 다른 애플리케이션이 풀스크린 모드로 생성될경우.
  • 전력관리 이벤트(WM_POWERBROADCAST)가 발생했을 경우.

윈도우 모드일때..

  • 전력관리 이벤트가 발생했을 경우.
  • 다른 애플리케이션이 풀스크린 모드로 생성될경우.. (이경우 제 카드에서는 문제가 없었음)
  • 디스플레이 등록정보에서 색상모드를 변경하는 경우.

테스트 사항

카드 : Radeon 9000 128M, OS : Win 2000

A,B : D3D를 사용하는 애플리케이션

  1. . A:win, B:win ==> A:full, B:win // (A를 풀스크린으로 전환) %%%-A:ok, B:ok
  2. . A:full, B:win ===> A:win B:win // (A를 윈도우모드로 전환) %%%- A:ok, B:lost(고칠수 있음)
  3. . A:full, B:win ===> A:full(minimize), B:win // (마우스로 바탕화면을 찍거나 Alt+Tab) %%%- A:lost(고칠수 없음), B:lost(고칠수 없음)
  4. . A:full(lost), B:win ===> A:full(lost), B:full // (B를 풀스크린으로 전환) %%%- A:lost상태 유지, B:ok (A는 시작하기 전에 이미 lost상태였음)
  5. . A:full(lost), B:full ===> A:full(lost), B:full(lost) // (바탕화면 찍음) %%%- A:(lost상태유지), B:lost(고칠수 없음) (A는 시작전에 이미 lost상태였음)
  6. . A:full, B:win ===> A:종료, B:win(lost) // (A를 종료) %%%- A:종료됨, B:lost(고칠수 있음)

X. 기타 등등, 여러 상황에 따라 디바이스 로스트가 발생 된다. 이런 상황이 더 있으나 해결책을 어느정도 찾은것 같으므로 더 이상은 생략.

X. 그리고 다른 그래픽 카드의경우는 어떻게 처리될지 잘모르겠음.

결론

1. Present()함수의 리턴값은 항상 체크해야 한다. 위와 같이 언제 디바이스 손실이 발생 할지 모른다.

2. 임의로 체크해 보고 싶은 경우. TestCooperativeLevel()함수를 이용하자.

방법론

필수사항 : Present()리턴값은 항상 반드시 꼭 체크하자. 언제 어떻게 어떤 이유로 Present()가 실패할지 모른다. 이건 필수이다.

그리고 Present()가 실패하면 위와같은 방법으로 복구하면 될꺼 같다.

0. Present()함수 실패시만 복원한다.

단점으로는 에러를 알아내는 시점이 Present()가 호출될때(뷰포트를 하나 생성한 경우라면 한프레임에 한번씩)뿐 이라는 것이다. 이 단점은 랜더링 결과물에 접근하여, 그것이 애플리케이션 로직에 적용되는 경우라면 치명적일 수 있다고 예상된다. 그점을 제외하면 가장 무난할 껏 같다.

1. CD3DApplication(Direct3D Wizzard에서 제공)의 방식

이 클래스를 보면,, 꽤나 복잡한 방식(주로 윈도우 메세지를 핸들링한다.)으로 처리 하는데(즉, 디바이스 손실이 일어나기전에 미치 처리함)으로 해결하고 있다. 꼭이렇게 까지 해야 하는지는 잘모르겠지만... 요는 여러가지 상황에 미리 대처한다는 방식이다. 위의 <테스트 사항>같은 짓을 많이 시도해보고, 어느때 디바이스가 손실되는지 정확하게 알아낸 후, 미리알 수 있는경우(풀스크린에서 Alt+tab에 의해 갑자기 비활성화 시킨다든지 등등) 할수 있는데까지 까지 하는것이다. 그런 눈물겨운 노력이 CD3DApplication에 보면 잘 나온다. 이런건 보고 베끼자...^^ 이경우 100% 문제를 해결했다고 볼 수는 없다고 생각되지만 0번의 경우보단 낫다. 이런 문제를 봐선 Direct3D의 설계의 결함같기도 하다. 결국 이런 문제들을 100% 해결 할 수는 없다고 생각된다.

결과 : 실제로 1번과 같이 대부분 예측되는 치명 적인 몇몇 가지들에 대해 미리 알아내서 처리해주면,, 거의 문제는 안생긴다. 대신 코딩이 지저분해지는건 어쩔수 없다.

stub code

void RenderAll()
{
    // ...
    // 모든 그래픽들에 대한 랜더링을 한다.
    // ...

    // 백버퍼 플리핑.
    hr = m_pDevice->Present( NULL, NULL, NULL, NULL );
    if ( FAILED(hr) )
    {
        if ( D3DERR_DEVICELOST == hr )
        {
            // 디바이스를 소실했고, 복구가 불가능 상태
        }
        else ( D3DERR_DEVICENOTRESET == hr )
        {
            // 디바이스를 소실했지만, 복구가 가능한경우.
        }
    }
}

설계

한가지 방법은 랜더러 클래스(또는 이런 이벤트를 처리할 객체)에 두가지상황(디바이스 손실시 복구가능/복구불가능)이 발생했을때, 로딩할 목록을 등록해 놓은 후, 이벤트가 발생하면 각각 해당 이벤트에 맞게끔 다시 로드하는 식으로, 구성하면 될 껏 같다.

//**** 디바이스 리소스 인터페이스.. // 디바이스 의존적인 리소스들의 추상클래스. struct IDeviceRes { virtual void Invalidate() = 0; virtual bool SetValidate() = 0; }; //**** 텍스쳐 클래스 class CTextureRes : public IDeviceRes { public: virtual void Invalidate() { 텍스쳐 해제; } virtual bool SetValidate() { 텍스쳐 다시 로드; } bool Load(); void Unload(); protected: char m_szFileName[256]; LPDIRECT3DTEXTURE9 m_pTexture; }; //**** 텍스쳐를 관리할 클래스(클라이언트에서 접근하여 사용) class CDataContainer { public: LoadTexture( const char* szFileName ) { // 1. 텍스쳐 로딩 // 2. 만약 텍스쳐가 VRam에 잡혔다면..(D3DPOOL_DEFAULT) // 2.1 랜더러의 의 VRam리스트에 등록(m_pRenderer->m_VRamRes) // 3. 텍스쳐가 다른모드로 생성되었다면..(D3DPOOL_MANAGED or etc..) // 3.1 랜더러의 의 Managed리스트에 등록(m_pRenderer->m_ManagedRes) } UnloadTexture( const char* szFileName ) { // 랜더러의 디바이스 목록에서 지운다. m_pRenderer->Unregist( szFileName ); } protected: vector<CTextureRes*> m_TextureContainer; CRenderer* m_pRenderer; } //**** 문제의 랜더러 클래스 class CRenderer { public: // 디바이스가 해제 &#46124;거나 해제 하라. // - 이 함수는 외부에서 임의로 호출이 가능하다. void InvalidateDevice( HRESULT hrDeviceState ) { if ( FAILED( hrDeviceState ) { if ( D3DERR_DEVICENOTRESET == hrDeviceState ) { // 1. m_VRamRes 리소스만 해제한다. // for_each(m_VRamRes의 시작에서 끝까지) { m_VRamRes[i]->Invalidate(); } } else if ( D3DERR_DEVICELOST == hrDeviceState ) { // 1. m_VRamRes과 m_ManagedRes들에 대해서 해제한다.(전 리소스들에 대해 수행) // for_each(m_VRamRes의 시작에서 끝까지) { m_VRamRes[i]->Invalidate(); } // for_each(m_ManagedRes의 시작에서 끝가지) { m_ManagedRes[i]->Invalidate(); } // 2. 디바이스를 릴리즈한다. } } m_hrDeviceState = hrDeviceState; // 디바이스 상태값 업데이트 } // 디바이스가 활성화하라. // - 이 함수도 외부에서 임의로 호출이 가능하다. bool SetValidateDevice() { if ( FAILED(m_hrDeviceState) ) { if ( D3DERR_DEVICENOTRESET == m_hrDeviceState ) { //**** 디바이스를 복구할수 있다. // 0. D3DPOOL_DEFAULT로 생성된 자원들 모두 해제 (이 문장은 포스팅하면서 추가) // 1. IDrect3DDevice::Reset()한다. // 2. 랜더 스테이트 / 뷰행렬 셋팅 // 3. m_VRamRes 리소스들을 다시 로딩한다. // for_each(m_VRamRes의 시작에서 끝까지) { m_VRamRes[i]->SetValidate(); } } else if ( D3DERR_DEVICELOST == m_hrDeviceState ) { //**** m_VRamRes 복구할수 없다. // 0. D3DPOOL_DEFAULT / D3DPOOL_MANAGED 리소스 해제(이 문장은 포스팅하면서 추가) // 1. 디바이스를 재생성한다. // 2. 랜더 스테이트 / 뷰행렬 셋팅 // 3. m_VRamRes / m_ManagedRes 리소스를 로딩한다. // for_each(m_VRamRes의 시작에서 끝까지) { m_VRamRes[i]->SetValidate(); } // for_each(m_ManagedRes의 시작에서 끝가지) { m_ManagedRes[i]->SetValidate(); } } // 검증해본다. m_hrDeviceState = m_pDevice->TestCooperativeLevel(); return SUCCEEDED(m_hrDeviceState); } return true; } // 랜더링한다. void RenderAll() { //**** 디바이스가 유효한 상태가 아니라면 그냥 리턴. if ( FAILED(m_hrDeviceState) ) return; // ... //**** 모든 그래픽들에 대한 랜더링을 한다. // ... //**** 백버퍼 플리핑. m_hrDeviceState = m_pDevice->Present( NULL, NULL, NULL, NULL ); if ( FAILED(m_hrDeviceState) ) { // 디바이스에 뭔가 이상이 있다면,, InvalidateDevice( m_hrDeviceState ); // 외부에 알려준다. 아마 누군가에게 알려줄 필요가 있을껏이다. // CApp나 혹은 다른 누군가에게.. } } protected: //**** properties // 디바이스 의존적인 메모리 관리 vector<IDeviceResource*> m_VRamRes; // POOL_DEFAULT vector<IDeviceResource*> m_ManagedRes; // MANAGED or etc HRESULT m_hrDeviceState; // 현재의 디바이스 상태값 LPDIRECT3DDEVICE9 m_pDevice; };

추신

괜찮은 방법이나, 사용되어지는 방법이 있으면 올려주세요. 저도 구현은 안해본 사람입니다. 아마 틀린 부분도 있으리라 생각됩니다. 많은 지적을.. 써놓고 보니 장문이네요.

< 덧글 >

그리고 업데이트 내용입니다. gpgstudy.com의 손님께서 쓰신글의 요약입니다.

TestCooperativeLevel()로 D3DERR_DEVICENOTRESET임을 확인한후 Reset()을 했을때 실패할 수도 있다는군요.

나중에 TestCooperativeLevel()로 확인해 보니 D3DERR_DEVICELOST였다고 합니다. 결국 Reset()이 실패했을경우에도 다시 체크를 한후 소실상태라면 디바이스를 다시 생성해야 할껏같습니다.

반응형
반응형


복사http://blog.naver.com/cra2yboy/90139675513


첨부파일 (1)

환경맵이란 무엇인가?

 

 

환경 맵핑이란 반사성이 있는 표면에 레이 트레이싱을 하지 않고 주변이 반사되는 듯 시뮬레이션하는 방법이다.

실제와 같은 반사를 위한 광선 추적 기법은 비용이 크기 때문에 환경맵을 통해 이와 비슷한 효과를 내는 것이다.

 

다양한 형태의 큐브맵

 

 

 

이 예제에서는 CreateCubeTexture 함수를 이용해 큐브 텍스쳐를 생성한다.

 

텍스쳐 좌표를 처리하기 위한 인자들

 

D3DTSS_TCI_PASSTHRU 는 정점에 주어진 텍스쳐 좌표를 그대로 사용

D3DTSS_TCI_CAMERASPACENORMAL 는 정점의 법선 정보를 카메라의 공간좌표로 변환 한 뒤 텍스쳐 변환 행렬 적용 후 텍스쳐 좌표로 사용(환경 맵핑)

D3DTSS_TCI_CAMERASPACEPOSITION 는 정점의 위치를 카메라 공간좌표로 변환한 뒤 텍스쳐 변환행렬 적용 후 텍스쳐 좌표로 사용(그림자 맵핑)

D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR 는 정점의 위치와 법선을 카메라 공간좌표로 변호나한 뒤 시선에 대한 반사벡터를 구하여 텍스쳐 변환행렬 적용 후 텍스쳐 좌표로 사용(반사 환경 맵핑)

D3DTSS_TCI_SPHEREMAP는 구면 맵핑을 위한 텍스쳐 좌표를 사용(구면 맵핑)

 

큐브 환경맵 생성하기

 

큐브 환경맵을 생성하기 위해서 이 예제에서 처리한 방법은 카메라를 기준이 되는 위치에 옮겨 놓고 6 방향을 향하도록 카메라를 각각 돌아가며 텍스쳐에 화면을 렌더링하는 방식을 사용 했다.

 

단축키 'E'를 누르면 CreateCubeMap 함수를 호출하도록 되어 있고 이곳에서 큐브맵 텍스쳐를 생성 후 렌더링 하고 파일에 저장하는 역할을 한다.

 

렌더링

 

 

g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR | 1);

 

주전자에 텍스쳐를 맵핑하여 렌더링 해야 하는데 텍스쳐의 맵핑 좌표는 카메라 위치를 기준으로 매번 재계산하여 적용시켜 준다.

반응형
반응형



http://blog.naver.com/sorkelf/40157348191



이번엔 환경맵(큐브맵, Cube Map)을 알아보자


환경맵이란 모델 표면의 배경등이 비추는 모습을 재현한 것으로,필요한 소재들이나 텍스처들을 가리킨다. 

(흔히들 말하는 잘 닦은 금속이 비추는 모습) 같은거 그런거







 

① 눈 →모델 표면 반사→배경의 어딘가


우리들의 시선으로부터 한 물건의 어떤 지점에 광선을 쏜다고 생각하자

그러면 광선은 면에 입사하여 다시 반사한다.


반사한 후의 광선은 분명 어딘가 먼곳으로 가다가 반드시 어딘가에 충돌한다.

그 부딪힌곳에 적어도 무언가의 색이 반드시 있다.


이와는 반대로 그 부딪힌 곳에서부터 물건의 반사지점까지 광선을 쏜다고하자

그러면 레이는 표면에 반사해서 분명 우리들 눈에 다시 들어 온다.

이러한 원리로 인해 우리들은 표면의 색을 알 수 있다.

반사한 색을 보고 있음

 

그럼 이 부분을 셰이더에서 생각해보자


버텍스 셰이더에는 로컬 공간의 버텍스 좌표가 인수로써 들어온다.

이것에 월드 변환행렬을 곱하면 월드 공간으로 이동한다.


지금 카메의 월드 위치가 있다고 하고 그 위치로부터 월드 공간에 있는 버텍스에 대해서 레이를 쏜다.

이 레이의 방향이 [ 시선 벡터 ] 이다.


버텍스에는 이미 또 다른 [ 법선 (Normal) ] 이라는 정보도 들어 있다.

법선은 표면을 가리키는 것이는 것이므로 

우리는 시선벡터와 법선 벡터만 알면 반사벡터는 간단히 구할 수 있다.

그 다음엔 반사한 곳에 있는 배경색으로부터 색을 얻어오면 끝이다.


물론 셰이더 내에는 월드에 있는  어떤 모델의 정보를 알 수 없다

셰이더 내에서 얻을 수 있는 것은 색정보와 버텍스 컬러 그리고 입혀진 텍스처 만이기 때문이다.


여기서 생각할 수 있는 것이 [ 3D 공간에 세계는 커다란 입방체! ]다 라는 것이다.

그렇게 하면 배경의 색정보는 6면의 텍스처로 모두 표현될 수 있다



 

셰이더내에서 입방체라고 생각하면 그 모델(배경) 에 대한 정보를 셰이더내에 전달할 필요는없다

이 후에는 시선이 닿을 것이라는 커다란 텍스처의 UV를 직접 지정하여 그 색을 출력하면

모델의 표면에 주위의 색이 반사한 것 처럼 보일 것이다


이 입방체의 내측에 붙어있는 텍스처를 [ 환경 맵 ] 이라고 한다



② IDirect3DCubeTexture + reflect함수 사용하면 끝



또한 위 텍스처는 큐브맵이라고도 하며 이러한 6면의 텍스처를 IDirect3DTexture9를 6개 사용해서 표현할 수도 있지만 

DirectX에서는 큐브맵 전용 IDirect3DCubeTexture라는 인터페이스가 준비되어 있으며 이것을 사용하면 

간단히 큐브 환경맵을 만들수 있다


큐브맵은 보통 D3DXCreateCubeTextureFromFile 함수를 사용하여 불러온다


 HRESULT D3DXCreateCubeTextureFromFile(

    LPDIRECT3DDEVICE9            pDevice,
    LPCTSTR                             pSrcFile,
    LPDIRECT3DCUBETEXTURE9 *ppCubeTexture
);

pDevice는 렌더링 디바이스
pSrcFile 에는 큐브 맵이 들어간 파일명 (단 dds 포맷)。
ppCubeTexture 에 큐브맵 오브젝트의 포인터를 전달한다。


이 함수에서 사용할 수 있는 파일은 dds 포맷 파일이며 DirectX Texture Tool로 다른 파일들로부터 만들수도 있다.



이렇게 해서 만든 큐브맵 텍스처를 셰이더에 전달한다.


 // 환경 매핑 버텍스 셰이더

const char *vertexShaderStr =
float4x4 view : register(c0);          // 보통 WVP로 한번에 보냄
float4x4 proj : register(c4);
float4x4 world : register(c8);
float3 cameraPosW : register(c12); // 카메라 월드 위치

struct VS_IN {
    float3 pos : POSITION;
    float3 normal: NORMAL;
};

struct VS_OUT {
   float4 pos : POSITION;
   float3 normalW: TEXCOORD0; // 월드 좌표상의 법선
   float3 viewVecW: TEXCOORD1; // 월드 좌표상의 시선벡터
};

VS_OUT main( VS_IN In ) {
  VS_OUT Out;
  Out.pos = mul( float4(In.pos, 1.0f), world );
  Out.viewVecW = Out.pos.xyz - cameraPosW;
  Out.pos = mul( Out.pos, view );
  Out.pos = mul( Out.pos, proj );

  Out.normalW = mul( float4(In.normal, 0.0f), world );

  return Out;
}


// 환경 매핑용 픽셀 셰이더
const char *pixelShaderStr =
textureCUBE cubeTex;
samplerCUBE cubeTexSampler =
sampler_state {
  Texture = <cubeTex>;
  MinFilter = LINEAR;
  MagFilter = LINEAR;
  MipFilter = LINEAR;
};

struct VS_OUT {
  float3 normalW: TEXCOORD0;
  float3 viewVecW: TEXCOORD1;
};

float4 main( VS_OUT In ) : COLOR {
  float3 vReflect = reflect( In.viewVecW, In.normalW );
  return texCUBE(cubeTexSampler, vReflect);
}


대부분이 변수나 샘플러등의 선언이지 실제 셰이더 코드는 얼마 없다


특히 픽셀 셰이더는 달랑 2행 뿐이다.

이게 가능한 것은 셰이더 자체가 큐브맵 텍스처로부터 샘플링을 하는것을 지원해주기 때문이다


우선 큐브맵은 textureCUBE라는 텍스처 형으로 얻어진다

그리고 이 텍스처 전용 샘플러로 samplerCUBE를 지원한다


texCUBE 함수를 통해 samplerCUBE샘플러에 대해서 반사 벡터를 전달하면 

그 벡터에 맞는 큐브맵의 색을 얻어 반사벡터와 입방체의 교점을 구하고

그것을 UV로 변환하고 뭐하고뭐 하고 하는 여러가지 계산을 전부 생략 가능하다


그러면 반사 벡터는 어떻게 구하는가?


3D게임 프로그래밍 & 컴퓨터 그래픽을 위한 수학 1판 160쪽에 있는 (2판이 없어 제길..)




R = 2(N·L)N-L 을 사용해도 되지만

셰이더에서는 reflect라는 함수를 지원하며 (내부가 저렇게 되있긴 하지만..)

입사벡터와 면의 법선벡터로부터 시선벡터에 진행방향인 반사벡터를 구해준다


시선벡터는 카메라의 위치와 카메라가 보고 있는 점을 알수 있으면 구할수 있다

(월드좌표로 변한된 버텍스 위치 - 카메라의 월드 좌표상의 위치)


이것을 TEXCOORD1로 하여 법선벡터와 함께 픽셀 셰이더에 보낸다



③ 애플리케이션 프로그램


애플리케이션에서는 IDirect3DDevice9::SetTexture 함수로 큐브맵 텍스처를 전달하고

버텍스 셰이더와 픽셀 셰이더를 각각 렌더링 디바이스에 설정하고 렌더링 하면 된다


 // 카메라 갱신

D3DXVECTOR3 cameraPos(350.0f * cos(a*0.5f), 450.0f * sin(0.2f*a), 350.0f * sin(a*0.5f));

g_pD3DDev->SetTexture(0, cubeTex); // 큐브맵 세팅

g_pD3DDev->SetVertexShader(vertexShader);
g_pD3DDev->SetPixelShader(pixelShader);

g_pD3DDev->SetVertexShaderConstantF(0, (float*)&view, 4);   //보통 SetMatrix로 한번에 보냄
g_pD3DDev->SetVertexShaderConstantF(4, (float*)&proj, 4);
g_pD3DDev->SetVertexShaderConstantF(8, (float*)&world, 4);
g_pD3DDev->SetVertexShaderConstantF(12, (float*)&cameraPos, 4);

cube->DrawSubset(0);


어려울지도 모르지만 봐왔듯이 환경 매핑은 큐브맵만 있으면 의외로 간단하다

반응형
반응형

http://hsengine.co.kr/20149811131

 

 

 


 CEGUI 설치와 CEGUI VC++ 설정

 

cegui 설치방법과 cegui 설정하는 방법에 대해 설명하겠다.

CEGUI를 다운받기 위해 CEGUI 사이트에 접속한다.

 

http://www.cegui.org.uk/wiki/index.php/Downloads 

 

 

 

 

Crazy Eddie's GUI System - Downloads 에서 최신버전을 클릭한다.

 

Library Source Downloads에서 운영체제에 맞는 소스코드를 다운받는다.

 

그리고 Binary Dependency Downloads for MSVC++에서 VC++버전에 맞는것을 찾아 다운받는다.

 

 

 

Library Source Downloads에서 다운받는 압축파일을 풀고. (예: C:\CEGUI)

 

Binary Dependency Downloads for MSVC++에서 받은 압축파일을 열어 dependencies 폴더안에 있는 파일들을 아까 압축푼곳에 압축을 풀어 덮어쓴다. 

 

이제 C:\CEGUI\projects\premake 로 이동한다.

 

여기서 오우거엔진이나 일리히트엔진에 이용할꺼면 config.lua 파일을 수정해야된다.

 

config.lua파일에 찾아보면 아래와 같은 내용이 있다.

 

자신에 맞게 직접 수정해주면 된다. (Direct3D9을 이용할꺼면 따로 수정하지 않아도 된다.)

 

그리고 오우거나 일리히트엔진은 따로 경로 설정을 해야된다.

 

 

 

이제  build_vs2008.bat 파일와 build_samples_vs2008.bat을 실행한다. (버전에 맞는걸로 실행)

 

 

 

 

 

그러면 CEGUI.sln, CEGUISamples.sln 파일이 생성된다.

 

열어서 빌드만 해주면 된다.

 

C:\CEGUI\bin 폴더에서 Samples 들을 실행해볼 수 있다.

 

 

VC++ 설정

 

 

 

lib

C:\CEGUI\lib

C:\CEGUI\lib\dynamic

C:\CEGUI\lib\ReleaseWithSymbols

C:\CEGUI\lib\static

 

include

C:\CEGUI\include

C:\CEGUI\cegui\include

C:\CEGUI\cegui\include\elements

C:\CEGUI\cegui\include\falagard

C:\CEGUI\cegui\include\RendererModules\Direct3D9 (여기서 Direct3D9 대신 Irrlicht, Ogre, OpenGL, Direct3D10 등.. 추가할 수 있다. 자신이 사용할것에 따라 설정한다.)

 


directx 는 render 프로젝트에 포함시켜주면된다 CEGUIBase 에도 해놨는데 없어도 되는지는 확인해봐야암

반응형

'그래픽스(Graphics) > GUI Library' 카테고리의 다른 글

cegui 튜토리얼 번역  (0) 2013.02.04
GUI 제공하는 사이트들  (0) 2012.11.02
반응형

출처 : hppt://cafe.naver.com/cafec/248627



직접 구한할려면 보통 일이 아닙니다. 그래서 이미 만들어진 라이브러리를 이용하곤 하죠.
대표적으로 
CEGUI(http://www.cegui.org.uk/wiki/index.php/Main_Page 너무 기능이 많아서 무겁습니다)
librocket(http://librocket.com/ )
guichan(http://guichan.sourceforge.net/ 중국사람이 만든건데 요즘 업데이트 안하는듯)
Scaleform(http://gameware.autodesk.com/scaleform/ flash 이용, 가격이 천만원 초반대ㄷㄷ, 요즘 대부분 온라인게임에 탑제되어서 거의 트렌드입니다.) 
등등,,, 
html, javascript를 이용하는것도 있고, 각양각색입니다. 구글신 검색해보면 많이 나옵니다.

반응형

'그래픽스(Graphics) > GUI Library' 카테고리의 다른 글

cegui 튜토리얼 번역  (0) 2013.02.04
CEGUI 설치  (0) 2012.11.02
반응형

//Slices는 나누어질 삼각형의 갯수 이며 Stack은 사진에서 Y축으로 나누어질 갯수
 if( FAILED(D3DXCreateSphere(_pD3dDevice,5,8,4,&_sphere, NULL)) ){
   AfxMessageBox(L"스피어 생성 실패");
}

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Direct3D9에서 큐브 환경맵 만들어 보기  (0) 2012.11.08
환경 맵(큐브 맵, Cube Map)  (0) 2012.11.08
투명처리와 알파 합성  (0) 2012.11.02
점 그리기 -크기 변환  (0) 2012.11.02
점그리기  (0) 2012.11.02
반응형

칼라키로 뺀다
  * 텍스쳐 생성시 칼러키를 지정하여 빼기

D3DCOLOR ColorKey = D3DCOLOR_XRGB(255,0,255);
D3DXCreateTextureFromFileEx( DXD9, 이름,  크기, 크기, 1, NULL,텍스쳐포맷, 메모리풀, 필터, 필터, ColorKey, NULL, NULL, 텍스쳐포인터);


픽셀에 투명값이 있다
  * 포토샵에서 저장시 알파채널을 포함해서 저장
  * TGA, PNG, DDS등의 포맷을 사용
  * SetRenderState에 알파를 사용한다는 옵션을 선택

m_pD3dD9->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
m_pD3dD9->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
m_pD3dD9->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);



SetTextureStage에서 FACTOR로 투명도를 조절한다
  * 이미지가 가지고 있는 알파값에 다시 알파값을 조정할수 있다.
  * 픽셀칼러(RGB) * 픽셀알파값(100%로계산) * 원하는 알파값(100%로계산)

m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_TFACTOR);
m_pD3dD9->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_ARGB( 원하는 알파값, 255, 255, 255 ) );



정점의 알파값을 사용한다
  * 정점의 칼라가 ARGB를 사용할경우 0xffffffff인데
  * 맨앞의 ff값을 수정해주면, 채워지는 face의알파도 영향을 받는다.
  * 픽셀칼러(RGB) * 픽셀알파값(100%로계산) * 정점알파값(100%로계산)

m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);

m_pD3dD9->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);

 

 

 

 

 

 


http://www.silverwolf.co.kr/4886

 

 

[알파합성]

 

2번 렌더링을 실시하는 , 이른바 투패스 라고 부르는 방법으로 알파 합성(알파 블렌딩) 을 의미 알파 합성이란 폴리곤을 렌더링할때, 폴리곤 색을 그냥 출력하는 것이 아니라 이미 렌더링 된 화면에 여러가지 합성을 해서 출력하는 방법이다. 

알파합성은 현재 그려져 있는 색과 렌더링하는 폴리곤의 색을 합성한다. 따라서 , 반투명 폴리곤을 렌더링하기 전에 불투명 오브젝트를 렌더링 하여야 한다.   

깊이 테스트를 하면서 렌더링 할 경우 , 렌더링 순서를 잘못하면 반 투명 폴리곤의 한쪽 부분은 오브젝트가 렌더링 되지 않고, 마술처럼 오브젝트의 일부분이 사라진 화면이 출력되게 됨. 

------------------------------------------------------------------------------------- 

반투명 on : 디바이스->SetRenderState(D3DRS_ALPHABLENDABLE , TRUE); 
반투명 OFF : 디바이스->SetRenderState(D3DRS_ALPHABLENDABLE , FLASE); 

------------------------------------------------------------------------------------- 
합성 설정 방법 : 디바이스->SetRenderState(D3DRS_BLENDOP , 값) 

D3DBLENDOP_ADD 
                          최종색 = A * 렌더링할 폴리곤 색 + B * 이미 렌더링 된 색 

D3DBLENDOP_SUBTRACT 
                          최종색 = A * 렌더링할 폴리곤 색 - B * 이미 렌더링 된 색 

D3DBLENDOP_REVSUBTRACT 
                          최종색 = -A * 렌더링할 폴리곤 색 + B * 이미 렌더링 된 색 

D3DBELNDOP_MIN 
                         최종색 = 작은값(A * 렌더링할 폴리곤 색 , B * 이미 렌더링 된 색) 

D3DBELNDOP_MAX 
                         최종색 = 큰값(A * 렌더링할 폴리곤 색 , B * 이미 렌더링 된 색) 

-------------------------------------------------------------------------------------- 
아무 것도 설정되지 않았을때는 D3DBLENDOP_ADD 가 사용되며 , D3DBLENDOP_ADD 는 색을 서로 더한다. 

합성 강도 또한 SetRenderState 로 설정한다. 
이제부터 렌더링 하려는 폴리곤의 합성 강도 
디바이스->SetRenderState(D3DRS_SRCDBLEND , 값A) 

이미 렌더링 된 렌더일 타겟 색의 합성 강도 
디바이스->SetRenderState(D3DRS_DESTBLEND , 값B) 

--------------------------------------------------------------------------------------- 
<다양한 합성 방법> 

1. 선형 합성 

이른바 , 알파 합성이라 부르는 합성방법입니다. 이미 그려진 색과 지금부터 렌더링 하려고 하는 폴리곤의 색을 다음과 같은 비율로 합성합니다. 

최종색 = (1 - a) * 바닥색 * a * 덮일색. 

// 선형합성 C = Cd(1-As)+CsAs 
RS(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 
RS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 

--------------------------------------------------------------------------------------- 
덧셈 합성 

이합성은 바닥색의 변함없이 폴리곤의 색을 위에 겹칩니다. 

최종색 = 바닥색 + a * 덮일색 

a의 값이 커지는 것 만큼 , 위에 그려지는 폴리곤을 강하게 합성한다. 

RS(D3DRS_DESTBLEND, D3DBLEND_ONE); 
RS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 

이상의 합성은 빛의 표현에 많이 사용, GLARE 효과. 

--------------------------------------------------------------------------------------- 

뺄셈 합성 

최종색 = 바닥색 - a* 덮일색 

// 뺄셈합성 C = Cd-CsAs 
RS(D3DRS_BLENDOP, D3DBLENDOP_REVSUBTRACT); 
RS(D3DRS_DESTBLEND, D3DBLEND_ONE); 
RS(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 

이 합성 방법은 그림자 표현에 사용됨. 

뺄셈 합성을 하는 폴리곤을 여러번 거듭해나가면, 마지막에는 까맣게 된다. 
---------------------------------------------------------------------------------------- 
곱셈 합성 

최종색 = 바닥색 * 덮일색 

// 곱셈합성 C = Cd*Cs 
RS(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR); 
RS(D3DRS_SRCBLEND, D3DBLEND_ZERO); 
---------------------------------------------------------------------------------------- 

제곱 합성 

어두운곳은 더 어둡게 하고, 밝은 곳은 그대로 표시함. 이를 식으로 표현하면 다음과 같음. 

최종색 = 바닥색 * 바닥색 

바닥색을 제곱해서 색의 채도를 강조함. 제곱 합성은 렌더링 하는 폴리곤의 색이나 알파 값에 영향을 받지 않기 때문에, 폴리곤을 입혀 렌더링해도 텍스쳐는 효과를 미치지 않음. 

RS(D3DRS_DESTBLEND, D3DBLEND_DESTCOLOR); 
RS(D3DRS_SRCBLEND, D3DBLEND_ZERO); 

---------------------------------------------------------------------------------------- 
네거티브 포지티브 반전 

흰 폴리곤을 렌더링하면, 검은 부분은 희게, 흰 부분은 검게 출려되도록 색을 역전하는 변환을 합니다. 

최종색 = ( 1 - 바닥색) * 덮일색 

RS(D3DRS_DESTBLEND, D3DBLEND_ZERO); 
RS(D3DRS_SRCBLEND, D3DBLEND_INVDESTCOLOR); 
---------------------------------------------------------------------------------------- 

불투명 

알파블렌딩을 설정한 채로 불투명한 것을 그리고 싶을때 

최종색 = 덮일색 

RS(D3DRS_DESTBLEND, D3DBLEND_ZERO); 
RS(D3DRS_SRCBLEND, D3DBLEND_ONE); 

 
 
 
 
 
D3DRS_ALPHATESTENABLE // 알파테스트 사용 유/무 디폴트: FALSE 
D3DRS_ALPHAREF // 시험 픽셀값 0x00 ~ 0xff 
D3DRS_ALPHAFUNC // D3DCMPFUNC에 대한 정의 디폴트: D3DCMP_ALWAYS 

D3DCMPFUNC 

D3DCMP_NEVER 항상시험에 실패한다. 
D3DCMP_LESS 시험 픽셀이 현재의 픽셀보다 작은 경우 통과한다. 
D3DCMP_EQUAL 시험 픽셀이 현재의 픽셀과 동일한 경우 통과한다. 
D3DCMP_LESSEQUAL 시험 픽셀이 현재의 픽셀보다 작거나 같은 경우 통과한다. 
D3DCMP_GREATER 시험 픽셀이 현재의 픽셀보다 큰 경우 통과한다. 
D3DCMP_NOTEQUAL 시험 픽셀이 현재와 같지 않은 경우 통과 한다. 
D3DCMP_GREATEREQUAL 시험 픽셀이 현재보다 크거나 같은 경우 통과한다. 
D3DCMP_ALWAYS 항상 시험에 통과한다. 


# 시험 픽셀은 D3DRS_ALPHAREF의 값이며 현재 픽셀은 출력될때 이미지의 알파픽셀의 값을 의미 합니다. 

# 시험에서 통과하지 않을경우는 그에 해당하는 현재픽셀은 무시하게 되어 출력하지 않습니다. 

통과 했을 경우는 현재픽셀의 알파값을 가지고 출력하게 됩니다. ( 말 그대로 알파 비교를 하게 되겠지여 ) 

알파 테스트는 픽셀에 들어있는 알파값을 비교해서 이 픽셀을 사용할것인지 안할것인지를 결정하게 되는 겁니다. 

이것을 잘만 사용하면 스프라이트 형식의 1555 포맷과 같은 이미지 형식이라면 알파소팅을 하지 않아도 됩니다. 

P.S 알파 테스트를 하는 목적중에 하나는 렌더링 속도를 올리기 위해서 입니다. 

이미지에서 알파를 사용하면 자신의 위치에서 뒤에 있는 이미지의 픽셀을 혼합해서 나오게 되는데 

알파테스트는 불필요한 혼합을 하지 않아도 되므로 속도 향상을 줄수가 있는 겁니다. 

설명이 제대로 됬는지 모르겠군여 틀린부분 있으면 질문&답변게시판에 지적해 주세여 
----------------------------------------------- 

벌날개의 메모... 
<알파채널이 있는 경우...(TGA)> 
텍스처 로드...(초기화에서) 
if( FAILED( D3DUtil_CreateTexture( g_pd3dDevice,"tree01s.tga", 
                                           &g_pTexture ) ) ) 
            return E_FAIL; 
(랜더링에서) 
g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE ); 
g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA ); 
g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); 

랜더링..... 

 
 
 
 
텍스쳐 알파 채널을 이용한 투명 표현
 

// 선형합성 C = Cd(1-As)+CsAs

theApp.m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
theApp.m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); 
theApp.m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );


블렌딩이 안되는건 텍스쳐 파일에 알파채널 값이 없기 때문이였다. -_-!


그리고 그 전에 컬러끼리 섞었는데 그 결과는 좀 진한 투명 색이였다.

두 색이 합쳐진건지 원.. ㅋ

theApp.m_pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
theApp.m_pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCCOLOR ); 
theApp.m_pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVDESTCOLOR );





알파 블렌딩에 관하여


눈에는 보이지 않는...일종의 색상들을 섞을때 파라메터로 사용되는...그런 '값'이죠.

예를 들어 D3D의 알파블렌딩은 아래와 같이 이루어집니다.

WriteColor = SrcBlend * SrcColor + DstBlend * DstColor ;

WriteColor : 화면에 찍고자 하는 색상
SrcColor  : 텍스쳐 블렌딩(쉐이딩,멀티텍스쳐링 따위...)처리된 텍스쳐색상
DstColor  : 현재 화면에 찍혀있는 색상

SrcBlend와 DstBlend를 적당히 잘 만들어 주면 재미있는 효과를 얻을수 있습니다.

SrcBlend = 1  DstBlend = 0 
그냥 색상을 찍음.

SrcBlend = 0  DstBlend = 1 
아무색상도 찍지 않음.

SrcBlend = SrcAlpha  DstBlend = 1-SrcAlpha 
SrcColor에 있는 알파값으로 블렌딩.
( 만약 모든 SrcAlpha값이 0.5 라면  반반씩 섞이는 셈이니...정말로 반.투.명)

SrcBlend = 1  DstBlend = 1
SrcColor와 DstColor를 그냥 더해서 찍음.
텍스쳐가 찍히는 곳은 원래 찍혀있던 색상보다 밝아집니다. 눈부시게 빛나는(광원)효과.

SrcBlend = 0  DstBlend = SrcColor
SrcColor와 DstColor를 그냥 곱해서 찍음.
텍스쳐의 색상으로 원래 찍혀있는 색상을 쉐이딩한다고 생각하시면 쉽죠.
멀티텍스쳐가 지원되지 않을때 라이트매핑따위.

음.........
따지고 보니 알파블렌딩과 알파값은 사실 별 상관이 없어보이죠?
맞습니다.
그냥 텍셀마다 하나의 '확장 매개변수값'을 가지고 있다고 생각하세요.
이걸 가지고 무얼하는지는 순전히 프로그래머 맘이죠.


반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

환경 맵(큐브 맵, Cube Map)  (0) 2012.11.08
Direct 에서 스피어함수  (0) 2012.11.02
점 그리기 -크기 변환  (0) 2012.11.02
점그리기  (0) 2012.11.02
Directx D3DXCreateSphere 구현  (0) 2012.11.02
반응형

//점의 색상에 알파값을 적용하기 위한state
   _pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
   _pD3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
   _pD3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );

   
   _pD3dDevice->SetRenderState(D3DRS_POINTSPRITEENABLE,TRUE);//점이 스프라이트로 그려지기 때문에 텍스쳐 가능을 켜야 한다
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALEENABLE,TRUE);//크기 크게 가능 

   //이 세 개의 상수는 거리에 따라 포인트 스프라이트의 크기가 변하는 방법을 제어한다. 야기에서 말하는 거리란 카메라와 포인트 스프라이트 간의 거리이다. 
   //이것을 쓰려면 A=x,B=y,C=z 세개다 몇시해 줘야 한다
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALE_A,0); 
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALE_B,0); 
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALE_C,1);


   float PointSize = 10.0f;
   _pD3dDevice->SetRenderState( D3DRS_POINTSIZE , *((DWORD*)&PointSize));
   _pD3dDevice->SetRenderState(D3DRS_POINTSIZE_MAX,*((DWORD*)&PointSize));   //max 가 0 이 아니어야 한다
   
   PointSize = 0.0f;
   _pD3dDevice->SetRenderState(D3DRS_POINTSIZE_MIN, *((DWORD*)&PointSize));

   _pD3dDevice->SetStreamSource( 0, NULL, 0, sizeof(VERTEX_POSCOLORPOINT) );
   _pD3dDevice->SetFVF( D3DFVF_POS_DIFFUSE );
   _pD3dDevice->SetIndices( NULL );

   _pointNodes[0]._color=D3DCOLOR_ARGB(33,0xff,0xff,0xff);
   _pD3dDevice->DrawPrimitiveUP( D3DPT_POINTLIST,_pointNodes.size(),(void*)&_pointNodes[0], sizeof(VERTEX_POSCOLORPOINT) );

   PointSize = 1.0f;
   _pD3dDevice->SetRenderState( D3DRS_POINTSIZE , *((DWORD*)&PointSize));
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALEENABLE,FALSE);
   _pD3dDevice->SetRenderState(D3DRS_POINTSPRITEENABLE,FALSE); 
   _pD3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
   _pD3dDevice->SetRenderState(D3DRS_POINTSCALE_C,0);

 

 

 

float 를 DWORD 로 변환할때 &,* 를 사용하는 이유

 

 

*(DWORD*)&PointSize 로 해야 제대로 소수부분또한 실수로 변환되어 DWORD 에서 실수에서의 값을 갖고 있게 된다

즉 *(DWORD*)&PointSize  에서 넘겨지는 DWORD 는 float 형을 DWORD의 비트열로 변환한 값을 필요로 한다는 것.

 

 

반응형

'그래픽스(Graphics) > DirectX9~12' 카테고리의 다른 글

Direct 에서 스피어함수  (0) 2012.11.02
투명처리와 알파 합성  (0) 2012.11.02
점그리기  (0) 2012.11.02
Directx D3DXCreateSphere 구현  (0) 2012.11.02
디바이스를 잃었을때의 복구 절차  (0) 2012.11.02

+ Recent posts