02.13

신승빈·2023년 2월 13일
0

KGCA 수업

목록 보기
108/128

Blend

Standard Blend

	D3D11_BLEND_DESC BlendState;
    ZeroMemory( &BlendState, sizeof( D3D11_BLEND_DESC ) );
	BlendState.AlphaToCoverageEnable = TRUE;
    BlendState.RenderTarget[0].BlendEnable = TRUE;
	BlendState.RenderTarget[0].BlendOp		= D3D11_BLEND_OP_ADD;
	
	BlendState.RenderTarget[0].SrcBlend		= D3D11_BLEND_SRC_ALPHA;
    BlendState.RenderTarget[0].DestBlend	= D3D11_BLEND_INV_SRC_ALPHA;

	BlendState.RenderTarget[0].BlendOpAlpha		= D3D11_BLEND_OP_ADD;
	BlendState.RenderTarget[0].SrcBlendAlpha	= D3D11_BLEND_ONE;
    BlendState.RenderTarget[0].DestBlendAlpha	= D3D11_BLEND_ZERO;

    BlendState.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
    if( FAILED( hr = GetDevice()->CreateBlendState( &BlendState, &m_pAlphaBlend ) )) { }
    
    OMSetBlendState(BlendState, BlendFactor, Mask);
Texture2D g_txDiffuse: register (t0);
SamplerState samLinear: register (s0);
float4 PS(VS_OUTPUT vIn) : SV_Target
{
	return g_txDiffuse.Sample(samLinear, vIn.t) * vIn.c;
}

일반적인 Blend의 경우 BlendState를 작성한 후 DeviceContext에 저장한 후, Pixel Shader에서 Texture.Sample()을 수행하면 다음 공식에 의해 Pixel값이 결정된다
ResultPixel=(SrcSrcBlend)BlendOp(DestDestBlend)Result Pixel = ( Src * SrcBlend ) BlendOp ( Dest * DestBlend )
즉, Standard Blend는 Pixel Shader Stage에서 수행된다

Dual Source Color Blending

일부 BlendState option은 Dual Source Color Blending을 지원한다

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

여기서 Dual Source Color Blending이란 1장의 Texture가 Pixel Shader Stage를 거치면서 2장의 Output을 발생시키고, 이 Output이 Output Merger Stage에서 Blend되는 효과를 의미한다

	bd.AlphaToCoverageEnable = FALSE; // 알파 (0.5) 기준 알파테스팅 활성화 여부
    bd.IndependentBlendEnable = TRUE; // TRUE: 모든 랜더타켓 상태 적용, FALSE:0번만 적용됨.
    bd.RenderTarget[0].BlendEnable = TRUE;
    bd.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
    bd.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
    bd.RenderTarget[0].DestBlend = D3D11_BLEND_SRC1_COLOR;
    pd3dDevice->CreateBlendState(&bd, &g_pDualSourceBlend);

Dual Source Color Blending을 지원하는 Blend option을 지정한 후,

struct PS_OUT
{
	float4 a : SV_TARGET0; // +
	float4 b : SV_TARGET1; // *
};

PS_OUT PS(VS_OUT input) : SV_Target
{
	PS_OUT vOut;
	float4 vColor = g_txTex.Sample(g_SampleWrap , input.t);
	float alpha = max(max(vColor.r, vColor.g), vColor.b);
	vOut.b = float4(1.0f- alpha, 
					1.0f- alpha,
					1.0f- alpha,1.0f);
	vOut.a = vColor*input.c;
	return vOut;	
}

Pixel Shader에서 SV_Target0, 1에 Pixel Shader의 결과를 출력하면 Output Merger Stage에서 Blend작업을 수행한다

즉, Dual Source Color Blending은 Output Merger Stage에서 수행된다

Char GPT에게 질의한 답변에 의하면 각 출력은 1개는 RGB Channel로, 다른 1개의 출력은 Alpha채널로서 사용한다.

"The standard blend state in DirectX, also known as single-source blending, blends the new pixel color generated by the pixel shader with the existing pixel color in the render target. The result of the blending operation is written to the render target as the final pixel color.

On the other hand, dual-source blending is an advanced blending technique that allows you to use two separate blending factors for the new pixel color, one for the RGB channels and another for the alpha channel. This allows you to perform more complex blending operations and to generate more advanced visual effects.

In DirectX, dual-source blending is implemented as an extension to the standard blend state, and requires specific hardware support to work. To use dual-source blending, you need to set up two render targets and use the second render target as the second source in the blending operation.

In summary, the main difference between the standard blend state and dual-source blending is that the former uses a single blend factor for all channels, while the latter uses separate blend factors for the RGB and alpha channels, allowing for more advanced blending operations."

Pointer Particle

일반적으로 DirectX에서 결과물을 출력하기 위해서는 3개의 Vertex를 모아서 1개의 평면을 만드는 방식을 사용
그러나, Geometry Shader를 사용하면 1개의 Vertex만을 이용해서 Particle Effect효과를 낼 수 있음

m_pImmediateContext->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST);
struct G_OUT
{
	float4 p : SV_POSITION;
	float3 n : NORMAL;
	float4 c : COLOR0;
	float2 t : TEXCOORD0;
};

[maxvertexcount(4)]
void GS(in point VS_OUT vIn[1], inout TriangleStream<G_OUT> vOut)
{
	const float3 g_positions[4] =
	{
		float3(-1.0,  1.0, 0.0),
		float3(1.0,  1.0, 0.0),
		float3(-1.0, -1.0, 0.0),
		float3(1.0, -1.0, 0.0),
	};
	const float2 g_texcoords[4] =
	{
		float2(0.0, 0.0),
		float2(1.0, 0.0),
		float2(0.0, 1.0),
		float2(1.0, 1.0),
	};

	G_OUT vVertex;
	for (int i = 0; i < 4; i++)
	{
		vVertex.p = float4(vIn[0].p.xyz + g_positions[i].xyz, 1.0f);
		vVertex.c = vIn[0].c;
		vVertex.t = g_texcoords[i];
		vVertex.n = vIn[0].n;

		float4 vWorld = mul(vVertex.p, g_matWorld);
		float4 vView  = mul(vWorld, g_matView);
		vVertex.p	  = mul(vView, g_matProj);

		vOut.Append(vVertex);
	}
	vOut.RestartStrip();
}

위와 같이 1개의 정점을 중점으로 하는 평면을 생성하는 Geometry Shader를 설정하고, Primitive Topology를 PointList로 변경한 후, Vertex단위로 Draw()를 호출하면 Geometry Shader를 통해 생성된 평면이 입력으로 넘어오는 Vertex의 위치를 중점으로 하는 Particle Effect를 구현할 수 있음

profile
이상을 길잡이 삼아 로망을 추구합니다.

0개의 댓글