본문 바로가기
대학생활/수업

게임그래픽프로그래밍심화 5주차 - 그래픽스 API 혼합처리와 스텐실

by se.jeon 2023. 9. 25.
728x90
반응형

다음주, 다다음주 2주간 연달아 휴강이게 되면서 중간고사 시점이 좀 늦어지게 되었다. 10월 말 정도.

Render State

렌더링 파이프라인의 특정 렌더링 설정의 구성에 쓰이는 주요 상태

 

Render State의 대표 인터페이스들

- ID3D11Rasterizer : Rasterizer의 상태를 구성할 때 사용되는 설정들의 상태 집합

- ID3D11BlendState : 혼합 연산을 할 때 사용되는 설정들의 상태 집합

- 1D3D11DepthStencilState : depth & stencil test를 진행 시 사용되는 설정들의 상태 집합

 

ID3D11RasterizerState 처리 과정

- Rasterizer의 상태를 구성할 때 사용되는 설정들의 집합

- ID3D11RasterizerState 생성을 위해 D3D11_RASTERIZER_DESC 구조체 구성

 

typedef struct D3D11_RASTERIZER_DESC {
    D3D11_FILL_MODE FillMode; // 렌더링 형태 지정 , 기본값 : D3D11_FILL_SOLID, 추가 지원 : 와어이 프레임으로 렌더링시 (D3D11_FILL_WIREFRAME)
    D3D11_CULL_MODE CullMode; // Culling 모드 지정, 기본값 : D3D11_CULL_BACK(Backface Culling) , 추가 지원 : D3D11_CULL_NONE, D3D_CULL_FRONT
    BOOL FrontCounterClockwise; // 전면 지정을 CCW로 지정 여부, 기본값 : False, DirectX는 CW가 전면을 나타냄,
    INT DepthBias; // 기본값 : 0 , Depth에 추가된 깊이 값
    FLOAT DepthBiasClamp; // 기본값 0.0, , Depth의 추가된 깊이의 최대값
    FLOAT SlopeScaledDepthBias; // 기본값 0.0, Depth의 추가된 깊이값의 지정된 기울기에 대한 스칼라값
    BOOL DepthClipEnable; // 기본값 True, z값에 대한 클리핑 여부
    BOOL ScissorEnable; // 기본값 False, scissor 여부
    BOOL MultisampleEnable; // 기본값 False , 멀티 샘플링 여부
    BOOL AntialiasedLineEnable; // 기본값 : False, 선에 대해서 안티얼라이싱 여부
} D3D11_RASTERIZER_DESC;


https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ns-d3d11-d3d11_rasterizer_desc

뒷면을 그리지 않는 것은 최적화를 위함.

 

ID3D11Device::CreateRasterizerState 메서드를 통한 생성
ID3D11DeviceContext::RSSetState 메서드를 통해 디바이스에 설정
Rasterizer 상태를 기본상태로 돌리기위해서 RSSetState(0)으로 설정

 

 

TextureBox를 이용한 WireFrame & SolidFrame 예제

 

TextureBox를 이용한 Backface Culling 예제

그래픽스와 혼합 처리

혼합(Blending)

현재 래스터화 하는 픽셀을 후면 래스터화 되어 있는 픽셀과 섞는 기법

- 반투명이나 투명한 객체를 렌더링할 때 주로 사용

- 게임 개발에서는 Particle, UI, Postprocessing, Water, Shadow 등

 

혼합 공식

가로 i번째 세로 j번째 위치한 Source(원본)의 Pixel에 대해서 Pixel
Shader를 통해서 화면에 출력한 RGB 색상값 𝑪𝐬𝐫𝐜
▪ Back Buffer 가로 i번째 세로 j번째 위치한 Destination(대상) Pixel에
대한 RGB 색상값 𝑪𝐝𝐬𝐭
▪ 𝑪𝐬𝐫𝐜와 𝑪𝐝𝐬𝐭 를 혼합공식에 의해서 색을 섞어서 새로운 색상 𝑪𝒇𝒊𝒏𝒂𝒍생성
▪ 혼합되어서 생긴 새로운 색상 𝑪𝒇𝒊𝒏𝒂𝒍이 Back Buffer의 새로운 색이 됨
▪ Blend Factor (𝑭) : 픽셀 값에 적용될 혼합 계수
▪ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜 × 𝑭𝒔𝒓𝒄◎ 𝑪𝐝𝐬𝐭 × 𝑭𝐝𝐬𝐭 (◎ ∶ 𝑩𝒍𝒆𝒏𝒅 𝑶𝒑𝒆𝒓𝒂𝒕𝒐𝒓)

 

알파 혼합 공식

가로 i번째 세로 j번째 위치한 Source(원본)의 Alpha에 대해서 Pixel
Shader를 통해서 화면에 출력한 Alpha 값 𝑨𝐬𝐫𝐜
▪ Back Buffer 가로 i번째 세로 j번째 위치한 Destination(대상) Alpha에
대한 Alpha 값 𝐀𝐝𝐬𝐭
▪ 𝑨𝐬𝐫𝐜와 𝐀𝐝𝐬𝐭를 혼합공식에 의해서 색을 섞어서 새로운 색상 𝑨𝒇𝒊𝒏𝒂𝒍생성
▪ 혼합 후 생긴 새로운 Alpha값 𝑨𝒇𝒊𝒏𝒂𝒍이 Back Buffer의 새로운 Alpha 값
▪ Blend Factor (𝑭) : 픽셀 값에 적용될 혼합 계수
▪ 𝑨𝒇𝒊𝒏𝒂𝒍 = 𝑨𝐬𝐫𝐜 × 𝑭𝒔𝒓𝒄 ◎ 𝑨𝐝𝐬𝐭 × 𝑭𝐝𝐬𝐭 (◎ ∶ 𝑩𝒍𝒆𝒏𝒅 𝑶𝒑𝒆𝒓𝒂𝒕𝒐𝒓)

 

혼합 연산 (Blend Operator) : DX11에서의 지원하는 혼합 연산

typedef enum D3D11_BLEND_OP {
    D3D11_BLEND_OP_ADD = 1, // 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜×𝑭𝒔𝒓𝒄 + 𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭
    D3D11_BLEND_OP_SUBTRACT = 2, // 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭 − 𝑪𝐬𝐫𝐜 ×𝑭𝒔𝒓𝒄
    D3D11_BLEND_OP_REV_SUBTRACT = 3, // 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜×𝑭𝒔𝒓𝒄 − 𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭
    D3D11_BLEND_OP_MIN = 4, // 𝑪𝒇𝒊𝒏𝒂𝒍 = min(𝑪𝐬𝐫𝐜 , 𝑪𝐝𝐬𝐭)
    D3D11_BLEND_OP_MAX = 5 // 𝑪𝒇𝒊𝒏𝒂𝒍 = max(𝑪𝐬𝐫𝐜 , 𝑪𝐝𝐬𝐭)
} ;

 

혼합 계수 (Blend Factor)

DX11에서의 지원하는 혼합 계수 (COLOR로 끝나는 것들은 ALPHA혼합 공식에 사용 불가)

typedef enum D3D11_BLEND {
    D3D11_BLEND_ZERO = 1,
    D3D11_BLEND_ONE = 2,
    D3D11_BLEND_SRC_COLOR = 3,
    D3D11_BLEND_INV_SRC_COLOR = 4,
    D3D11_BLEND_SRC_ALPHA = 5,
    D3D11_BLEND_INV_SRC_ALPHA = 6,
    D3D11_BLEND_DEST_ALPHA = 7,
    D3D11_BLEND_INV_DEST_ALPHA = 8,
    D3D11_BLEND_DEST_COLOR = 9,
    D3D11_BLEND_INV_DEST_COLOR = 10,
    D3D11_BLEND_SRC_ALPHA_SAT = 11,
    D3D11_BLEND_BLEND_FACTOR = 14,
    D3D11_BLEND_INV_BLEND_FACTOR = 15,
    D3D11_BLEND_SRC1_COLOR = 16,
    D3D11_BLEND_INV_SRC1_COLOR = 17,
    D3D11_BLEND_SRC1_ALPHA = 18,
    D3D11_BLEND_INV_SRC1_ALPHA = 19
} ;

참고 : https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_blend

 

D3D11_BLEND (d3d11.h) - Win32 apps

Blend factors, which modulate values for the pixel shader and render target.

learn.microsoft.com

 

혼합 상태 (Blend State)

Direct3D에서 혼합을 처리하기 위한 과정
→ ID3D11BlendState 인터페이스를 통해서 혼합 처리 제어 가능
→ ID3D11BlendState 생성을 위해 D3D11_BLEND_DESC 구조체 구성

typedef struct D3D11_BLEND_DESC {
    BOOL AlphaToCoverageEnable; // 기본값 : FALSE, Alpha To Coverage 변환 활성화 (뒤에서 설명), multi sampling 활성화 필요
    BOOL IndependentBlendEnable; // 기본값 : FALSE, Direct3D 11에서는 8개 장면까지 렌더링 대상에 동시 렌더링 가능, 개별적으로 혼합 설정 가능
    D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[8]; // i번째 원소는 다중 렌더 대상의 i번째 렌더 대상에 적용할 혼합 설정을 표현한 구조체
} D3D11_BLEND_DESC;

→ ID3D11Device::CreateBlendState 메서드를 통한 생성

HRESULT CreateBlendState(
    [in] const D3D11_BLEND_DESC *pBlendStateDesc, // 혼합상태를 결정하는 구조체
    [out, optional] ID3D11BlendState **ppBlendState // 혼합상태 인터페이스 포인터
);

→ 생성된 Blend State 객체는 Output Merger 단계에서 적용 필수

→ ID3D11DeviceContext::OMSetBlendState를 이용

void OMSetBlendState(
    [in, optional] ID3D11BlendState *pBlendState, // Device에 적용한 BlendState 객체 포인터
    // RGBA 색상벡터 정의 , D3D11_BLEND_BLEND_FACTOR나 D3D11_BLEND_INV_BLEND_FACTOR를 지정 시 혼합계수로 이용
    [in, optional] const FLOAT [4] BlendFactor,
    [in] UINT SampleMask // 기본값 0xffffffff , 32비트 정수값으로 멀티샘플링시 32개의 표본의 적용에 대한 On/Off 적용,
);

→ 혼합 상태의 기본은 혼합 비활성화 이며, OMSetBlendState의 첫
매개변수 값을 NULL로 지정해서 적용 가능
→ 혼합 상태는 렌더링 부하를 주게 되므로 초기화 시점에 필요한 혼합
상태들을 모두 생성 후 필요할 때마다 처리 필요

 

Direct3D에서 혼합상태 예제

D3D11_BLEND_DESC transparentDesc = {0}; // D3D11_BLEND_DESC 채워 넣기
transparentDesc.AlphaToCoverageEnable = false;
transparentDesc.IndependentBlendEnable = false;
transparentDesc.RenderTarget[0].BlendEnable = true;
transparentDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
transparentDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
transparentDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
transparentDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
transparentDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
transparentDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
transparentDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
ID3D11BlendState* TransparentBS;
HR(device->CreateBlendState(&transparentDesc, &TransparentBS)); // ID3D11BlendState 생성
…
float blendFactors[] = {0.0f, 0.0f, 0.0f, 0.0f};
md3dImmediateContext->OMSetBlendState(TransparentBS, blendFactor, 0xffffffff); // Output Merger 단계에 적용

혼합 계수, 연산자 조합 예제

대상 픽셀을 유지하고 싶을 경우
→ 원본 픽셀의 영향없이 대상 픽셀 그대로 유지 시킬 경우 처리
→ 렌더링 결과를 깊이,스텐실 버퍼에만 기록하고, BackBuffer 기록
 안 하는 경우에 사용
→ 원본 픽셀의 혼합계수는 D3D11_BLEND_ZERO, 대상 픽셀 혼합 계수를
D3D11_BLEND_ONE 설정, 혼합 연산자는 D3D11_BLEND_OP_ADD

→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜× 𝑭𝒔𝒓𝒄 + 𝑪𝐝𝐬𝐭 × 𝑭𝐝𝐬𝐭
= 𝑪𝐬𝐫𝐜 ×(0,0,0) + 𝑪𝐝𝐬𝐭×(1,1,1) = 𝑪𝐝𝐬𝐭

 

원본 픽셀을 대상 픽셀과 더해서 혼합할 경우
→ 원본 픽셀과 대상 픽셀을 더해서 더 밝은 이미지 만들 때에 사용
→ 원본 픽셀의 혼합계수 : D3D11_BLEND_ONE
→ 대상 픽셀의 혼합계수 : D3D11_BLEND_ONE
→ 혼합 연산자 : D3D11_BLEND_OP_ADD

→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜×𝑭𝒔𝒓𝒄 + 𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭
= 𝑪𝐬𝐫𝐜×(1,1,1) + 𝑪𝐝𝐬𝐭 × (1,1,1) = 𝑪𝐬𝐫𝐜 + 𝑪𝐝𝐬𝐭

 

 

D3D11_BLEND_OP_ADD를 하면 색상 + 색상은 점차 하얀색에 가까워지기 때문에 밝은 이미지가 만들어진다.

 

대상 픽셀에서 원본 픽셀을 빼서 혼합한 경우
→ 대상 픽셀에서 원본 픽셀을 빼서 더 어두운 이미지 만들 때에 사용
→ D3D11_BLEND_OP_ADD와 다르게 대상 픽셀에서 원본 픽셀을 뺌
→ 대상 픽셀의 혼합계수 : D3D11_BLEND_ONE
→ 원본 픽셀의 혼합계수 : D3D11_BLEND_ONE
→ 혼합 연산자 : D3D11_BLEND_OP_SUBTRACT

→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭 - 𝑪𝐬𝐫𝐜 ×𝑭𝒔𝒓𝒄
= 𝑪𝐝𝐬𝐭×(1,1,1) − 𝑪𝐬𝐫𝐜 ×(1,1,1) = 𝑪𝐝𝐬𝐭 − 𝑪𝐬𝐫𝐜

 

원본 픽셀을 대상 픽셀과 곱할 경우
→ 원본 픽셀의 혼합계수 : D3D11_BLEND_ZERO
→ 대상 픽셀의 혼합계수 : D3D11_BLEND_SRC_COLOR
→ 혼합 연산자 : D3D11_BLEND_OP_ADD

→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜×𝑭𝒔𝒓𝒄 +𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭
= 𝑪𝐬𝐫𝐜×(𝟎, 𝟎, 𝟎) +𝑪𝐝𝐬𝐭×𝑪𝐬𝐫𝐜
= 𝑪𝐝𝐬𝐭×𝑪𝐬𝐫𝐜

 

픽셀 간의 투명도(Transparency) 처리
→ 픽셀의 Alpha값 : 𝑨
→ Alpha값 범위 : 0.0 ~ 1.0
→ Alpha값은 픽셀의 불투명도(opacity)에 해당 하는 비율
→ Alpha값이 0이라는 것은 opacity은 0%이므로 완전 투명
→ Alpha값이 1이라는 것은 opacity은 100%이므로 불투명
→ Transparency = 1 - 𝐀𝐥𝐩𝐡𝐚 (𝑨𝒍𝒑𝒉𝒂 : 0.4 이면 Transparency = 0.6)

 

원본 픽셀과 대상 픽셀 간의 투명도 연산
→ 원본 픽셀 투명도는 opacity에 비례
→ 대상 픽셀 투명도는 원본 픽셀 opacity에 의해 연동
→ 원본 혼합 계수 : D3D11_BLEND_SRC_ALPHA
→ 대상 혼합 계수 : D3D11_BLEND_INV_SRC_ALPHA
→ 혼합 연산자 : D3D11_BLEND_OP_ADD

→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜×𝑭𝒔𝒓𝒄 +𝑪𝐝𝐬𝐭×𝑭𝐝𝐬𝐭
= 𝑪𝐬𝐫𝐜 ×(𝑨𝒔𝒓𝒄,𝑨𝒔𝒓𝒄, 𝑨𝒔𝒓𝒄) + 𝑪𝐝𝐬𝐭 ×(𝟏−𝑨𝒔𝒓𝒄,𝟏−𝑨𝒔𝒓𝒄, 𝟏−𝑨𝒔𝒓𝒄)
= 𝑪𝐬𝐫𝐜𝑨𝒔𝒓𝒄 + 𝑪𝐝𝐬𝐭(𝟏−𝑨𝒔𝒓𝒄)

 

원본 픽셀과 대상 픽셀 간의 투명도 예시
→ 원본 픽셀 Alpha 0.3이면 opacity가 30%
→ 대상 픽셀의 Alpha는 원본 픽셀 Alpha와 연동되므로 1 - 0.3 = 0.7
→ 𝑪𝒇𝒊𝒏𝒂𝒍 = 𝑪𝐬𝐫𝐜 x 𝟎. 𝟑 + 𝑪𝐝𝐬𝐭 x 0.7
= 𝟎. 𝟑𝑪𝐬𝐫𝐜 + 0.7𝑪𝐝𝐬𝐭
→ 객체를 반투명한 상태를 만들 때에 사용
→ 원본의 알파 성분을 RGB성분과 혼합 처리하여 투명도 제어

 

투명 물체와 불투명한 객체들을 렌더링 시 주의 사항
→ 투명 및 반투명 객체들을 렌더링 시 그리는 순서가 중요
→ Blending 연산 미처리 객체들을 먼저 렌더링 (불투명)
→ Blending 연산 처리 객체들은 카메라 거리 기준 정렬 후 카메라와
거리가 먼 것 부터 가까운 순서대로 렌더링 (투명 혹은 반투명)
▪ 투명 및 반투명 객체들은 왜 카메라 기준 먼 순서 부터 렌더링 할까?
→ 투명 및 반투명 객체들은 뒤에 있는 객체들과 Blending되어 최종적인
색깔을 만들어 내기 때문

 

혼합과 깊이 버퍼

Blending과 Depth Testing을 동시에 할 경우 깊이 판정 문제
→ Blending 객체들에 대해 Depth Testing을 활성화 시 Depth Testing
통과하지 못하고 렌더링 되지 않는 경우 발생
→ Depth Testing을 피해야 하는 경우 Depth Write 비활성화
→ Depth Testing과 Depth 읽기는 활성화 유지
▪ Alpha Sorting : Blending 객체들을 올바르게 혼합하여 화면 표시 방법
→ Depth Write 비활성화 Depth Read는 활성화 후 Blending 객체들은
카메라 기준 먼 곳에서 부터 가까운 순서 대로 렌더링

 

텍스처와 알파 채널

→ 원본 픽셀 색상은 픽셀 셰이더가 출력 진행
→ Alpha값은 Material의 Diffuse의 Alpha값과 텍스처의 Alpha값 영향

loat4 PS(VertexOut pin) : SV_Target
{
    …
    // Common to take alpha from diffus e mate rial and te xture .
    litColor.a = gMaterial.Diffuse.a * texColor.a;
    return litColor;
}


→ 텍스처의 알파값 위해 알파채널 추가 필요
(32bit bmp, 32bit png, dds)

 

Clipping Pixel
▪ 원본 픽셀을 완전히 제거 해야 할 경우
→ HLSL의 clip(x) 함수를 이용하여 Pixel Shader 내에서 처리
→ x의 값이 0보다 작으면 픽셀을 처리 하지 않음
→ 완전히 불투명하거나 완전히 투명한 픽셀들을 처리할 때 유용

float4 PS(VertexOut pin, uniform int gLightCount, uniform bool gUseTexure,
uniform bool gAlphaClip, uniform bool gFogEnable d) : SV_Targe t
{
    pin.NormalW = normalize (pin.NormalW); // Inte rpolating normal can unnormalize it, so normalize it.
    
    float3 toEye = gEyePosW - pin.Pos W; // The toEye ve ctor is us e d in lighting.
    float distToEye = length(toEye ); // Cache the dis tance to the eye from this surface point.

    toEye /= distToEye ; // Normalize .
    float4 texColor = float4(1, 1, 1, 1); // De fault to multiplicative identity.
    
    if(gUseTexure )
    {
    	texColor = gDiffuseMap.Sample (samAnisotropic, pin.Tex); // Sample texture .
    if(gAlphaClip) 
    {
        // texColor의 alpha값이 0.1보다 작으면 픽셀 버림
        // 최대한 빨리 적용해서 셰이더의 나머지 코드 부분을 처리 하지 않도록 최적화
        clip(texColor.a - 0.1f);
    }
}

Back을 먼저 그려야 한다.

그래픽스와 스텐실 적용

(복습 필요)

 

과제 - 코드 분석

728x90
반응형