2010. 5. 12. 16:53

Direct3D에서의 Color값


다이렉트에서는 크게 두가지의 컬러값이 있어요.
하나는 D3DCOLOR와 또 하나는 D3DCOLORVALUE입니다.(여기서 D3DXCOLOR는 논외대상입니다)
각각의 원형은..

typedef DWORD D3DCOLOR; // 여기서 DWORD는 unsigned long타입입니다.

typedef struct _D3DCOLORVALUE {
    float r;
    float g;
    float b;
    float a;
} D3DCOLORVALUE;

여기서 D3DCOLOR는 A R G B 순으로 각각 1바이트씩 4바이트 데이터타입입니다. 따라서 각각은 0~255의 값을 갖게 되어있겠죠. 16진수로 나타내면 최대 0xffffffff가 되겠습니다. 0xffff0000하면.. 알파값을 최대로 갖는(불투명) 빨간색이 되겠죠.

D3DCOLORVALUE는 D3DCOLOR의 A R G B값을 각각 255로 나눈 값이라고 생각하시면 되겠습니다. 그럼 각각 0~1의 값을 갖게 되는데, 왜 이런 부분이 있느냐하고 의아해 하실 수 있습니다.

예를 하나 들어보겠습니다. 바로 이전에 포스팅했던 텍스쳐블렌딩에 대해서요.
텍스쳐 블렌딩 중, D3DTOP_MODULATE값인 경우는 두 컬러값을 곱해서 결과값을 매핑하게 됩니다.
( SRGBA= Arg1 × Arg2, DX 도움말 발췌)

빨간색의 경우 어느한쪽은 255이고, 어느한쪽은 그의 반인 127이라면.. 그대로 곱해버리면 32385가 되어버리겠죠. 32385란 빨간색값이 있었나요? 그리하여 각각이 0~1값을 갖도록 정규화되어진 것입니다.
255는 1이구요. 127은 약 0.5가 되죠. 이 둘을 곱하면 0.5가 됩니다. 즉, red값은 127이 됩니다. 나머지 컬러값도 비슷한 방식으로 계산되겠죠?

이 부분은 알파블렌딩의 경우도 마찬가지입니다. 흔히 말하는 알파블렌딩 방식은 다음과 같죠.
src = color*alpha
dest = color*(1-alpha)

final color = src+dest

여기서도 alpha값과 컬러값은 0~1의 값을 갖게됩니다. 알파값이 76(30%)이라면, 소스에서는 현재 컬러값 RGB값에 각각 0.3를 곱해주고 대상 컬러값엔 0.7를 각각 곱해서 블렌딩하게 되겠죠. 알파값이 255(100%)라면 어떨까요? 상상해 보시기 바랍니다. 어쨌든, D3DCOLORVALUE값으로 계산되어진단 얘기입니다. 그 이유 때문에선지, D3DMATERIAL9의 각 변수들은 아래와 같이 D3DCOLORVALUE값을 데이터타입으로 갖습니다.

typedef struct D3DMATERIAL9 {
    D3DCOLORVALUE Diffuse;
    D3DCOLORVALUE Ambient;
    D3DCOLORVALUE Specular;
    D3DCOLORVALUE Emissive;
    float Power;
} D3DMATERIAL9, *LPD3DMATERIAL9;


2010. 5. 12. 14:09

IDirect3DDevice9::SetTextureStageState 설계방식에 대한 실험


SetTextureStageState의 원형은 다음과 같습니다.(출처 - DX 도움말)
HRESULT SetTextureStageState(
  DWORD Stage,
  D3DTEXTURESTAGESTATETYPE Type,
  DWORD Value
);
Parameters
Stage 
[in] Stage identifier of the texture for which the state value is set. Stage identifiers are zero-based. Devices can have up to eight set textures, so the maximum value allowed for Stage is 7.
Type
[in] Texture state to set. This parameter can be any member of the D3DTEXTURESTAGESTATETYPE enumerated type.
Value
[in] State value to set. The meaning of this value is determined by the Type parameter.
일단 기본적으로 DX9에서의 Stage는 0~7까지이구요, 각각 D3DTEXTURESTAGESTATETYPE에 의해 값이 전달되고 제어됩니다. 텍스트 스테이지 상태변수라고 보시면 되겠구요. 렌더링 하기전에 상태변수값을 세팅하는 겁니다. (상태변수에 대해서 잘 모르시면 관련 아티클을 참조하세요)

일단 들어가기 앞서 텍스쳐관련 단어의 의미를 잘 파악하여 봐주시기 바랍니다.
텍스쳐를 올린다. 스테이지에 올린다/올라온 → SetTexture로 해당 스테이지에 올려진 텍스쳐
전 스테이지에서 블렌딩된, 이전/다음스테이지로 넘어가는/넘어온→ 해당스테이지에서 블렌딩된 텍스쳐

역시 이 시스템에서 가장 중요한점은 다음스테이지로 넘어가는 부분이 아닐까.. 생각됩니다.

이를테면 라이트맵등을 작업할때....
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );

pDevice->SetTexture( 0, pDiffuseTex );
pDevice->SetTexture( 1, pLightMap );

0번에 세팅한 확산맵을 다음스테이지(인덱스1)로 넘기고, 다음스테이지에서는 이전 스테이지에서 넘어온 텍스쳐를 받아서 현 스테이지의 라이트맵과 블렌드시키고 있습니다. 이는 블렌딩 시키는 가장 간단한 예 중 하나인데 이와 관련해서 여러가지 예들을 포스팅하려고 합니다.
어찌보면 간단한 부분인데.. DX설명서에도 잘 나와있지 않아서 정리해서 올리려고 합니다.

결론부터 말씀드리면, D3DTSS_COLOROP을 D3DTOP_DISABLE로만 하지 않는다면, 다음 스테이지로 넘어간다는 것입니다. 최종적으로 선택된 블렌딩 텍스쳐는 다음 스테이지의 COLOROP이 DISABLE인지 아닌지에 따라 결정됩니다. 다음 스테이지의 COLOROP이 DISABLE이라면 현 스테이지의 블렌딩 텍스쳐가 최종적으로 선택되고, 다음 스테이지의 COLOROP이 DISABLE이 아니라면 다음스테이지에서 한번더 블렌딩 되는 과정을 거치게 됩니다. 아래를 보시죠.

일반텍스쳐블렌딩 예1
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_DISABLE);

pDevice->SetTexture( 0, pDiffuseTex1 );
pDevice->SetTexture( 1, pDiffuseTex2 );
pDevice->SetTexture( 2, pDiffuseTex3 );

위와같이 설정하면, DiffuseTex1, DiffuseTex2는 무시되어버립니다. 왜냐하면 0~2번에서 COLOROP이 DISABLE상태가 일단 아니고, D3DTA_TEXTURE는 현 스테이지에 올라온 텍스쳐를 선택하는 부분으로써 마지막 스테이지에서 이전 스테이지에서 블렌딩된 텍스쳐(D3DTA_CURRENT)를 선택하지 않았기 때문입니다.

일반텍스쳐블렌딩 예2
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 3, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 3, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 4, D3DTSS_COLOROP, D3DTOP_DISABLE);

pDevice->SetTexture( 0, pDiffuseTex1 );
pDevice->SetTexture( 1, pDiffuseTex2 );

위와 같이 설정하면, 결국엔 DiffuseTex1이 매핑될 것입니다. 1번 스테이지에 DiffuseTex2가 올라오긴 했지만, 그것을 선택하라는 옵션이 어디에도 없기 때문입니다.

일반텍스쳐블렌딩 예3
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE);
pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );

pDevice->SetTexture( 0, pDiffuseTex1 );
pDevice->SetTexture( 2, pDiffuseTex2 );

위와 같이 설정하면, 0번에 설정한 DiffuseTex1만 매핑될 것입니다. 2번스테이지에 현재 스테이지에 올라온 텍스쳐를 선택하라..라고 나와있지만, 1번 스테이지의 COLOROP이 DISABLE로써, 0번 스테이지를 끝으로 블렌딩이 종료되었기 때문입니다.


하지만 ALPHAOP의 경우는 좀 다릅니다. 이전 스테이지에서 DISABLE이더라도, 현재 스테이지에서 ALPHAOP을 적용해줘도 되더군요. 아무래도 ALPHAOP과는 무관하게 COLOROP에 따라 스테이지가 늘어나는 것 같습니다. 하지만 ALPHAOP을 적용하려면 마지막 스테이지에서 ALPHAOP이 설정되야겠지요(물론 끝에만 설정될 필욘 없습니다만, 마지막 스테이지에 설정되어있어야함은 맞습니다).

알파텍스쳐블렌딩 예1
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );

pDevice->SetTexture( 0, pDiffuseTex );
pDevice->SetTexture( 1, pAlphaMap );

0번 스테이지엔 확산맵을 올렸고, 1번 스테이지엔 알파맵을 올렸다고 가정합시다. 0번 스테이지에서 diffuse와 texture를 곱한후(D3DTOP_MODULATE) 결과값을 1번 스테이지로 넘깁니다.(COLOROP이 DISABLE이 아닙니다) 0번 스테이지에서의 ALPHAOP은 DISABLE상태입니다. 1번 스테이지에서 이전 스테이지서 블렌딩된 블렌딩 텍스쳐를 선택합니다.(D3DTA_CURRENT) 그리고 1번 스테이지에 올라온 텍스쳐(알파맵)를 알파블렌딩 파라메터1로 설정해줍니다.(D3DTA_TEXTURE). 최종적으로 매핑된 텍스쳐는 1번 스테이지상에 존재하는 블렌딩 텍스쳐와 1번 스테이지에 올려논 알파맵의 알파값이 적절히 블렌딩되어 매핑됩니다.

알파맵과 디퓨즈맵의 스테이지를 뒤바꿀 수 있을까요? 당연히 됩니다만, 조금 주의하셔야 할 사항이있습니다.

알파텍스쳐블렌딩 예2
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_TEXTURE );

pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE);
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_CURRENT );

pDevice->SetTexture( 0, pAlphaMap );
pDevice->SetTexture( 1, pDiffuseTex );

알파맵의 경우 매핑할 필요가 없는데도, 지금까지 설명한 것처럼 COLOROP이 DISABLE이 되어있으면 안됩니다. (다음스테이지로 넘어가지 않겠죠) 따라서 적당히 아무거나... 선택합니다. 단, ALPHAOP은 현재 스테이지에 올라온 알파맵을 선택해주어야 합니다. 1번 스테이지에서는 1번 스테이지에 올라온 DiffuseTex와 diffuse값이 블렌딩됩니다. 즉, 이전 스테이지의 COLOROP에서 매핑될 예정이었던.. 부분은 삭제되게 되어있겠죠. 하지만, 1번 스테이지에서의 ALPHAOP을 보시면 이전 스테이지에서 블렌딩된 텍스쳐(알파맵)를 선택해주는 부분(D3DTA_CURRENT)를 볼 수 있습니다. 이로써 알파텍스쳐블렌딩 예1과 똑같은 결과를 보이게 됩니다.




추가사항
pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );

pDevice->SetTexture( 1, pDiffuseTex );
pDevice->SetTexture( 2, pAlphaMap );

위와 같은 경우는 거의없겠지만.. 위와 같이 코딩했다고 해봅시다. 0번 스테이지에 텍스쳐를 올리지 않은 상태죠. 결과는 아무것도 매핑 되지 않습니다. 아무런 일도 일어나지 않습니다.. 그 이유는 0번 스테이지에 텍스쳐가 등록되어있는 상태가 아닌데도 0번스테이지에서 COLORARG를 D3DTA_TEXTURE로 지정했기 때문입니다. 아마도 내부적으로 에러를 유발시키는 듯 싶군요. 아래와 같이 하면 고칠 수 있습니다. 참고용이니 그대로 사용하시면 안되요. 사용하실 일도 없겠지만...

pDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

pDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_MODULATE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_DIFFUSE );
pDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TEXTURE );
pDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE );

pDevice->SetTextureStageState( 2, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_CURRENT );
pDevice->SetTextureStageState( 2, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
pDevice->SetTextureStageState( 2, D3DTSS_COLORARG1, D3DTA_TEXTURE );

pDevice->SetTexture( 1, pDiffuseTex );
pDevice->SetTexture( 2, pAlphaMap );

0번 스테이지에서 텍스쳐를 선택하지 않았기 때문에 제대로 매핑됩니다. 이는 알파텍스쳐블렌딩 예1, 예2와 똑같은 결과를 보입니다.

'게임 > Direct3D' 카테고리의 다른 글

Direct3D에서의 Color값  (2) 2010.05.12