필요한 개념
반투명
Rain 텍스쳐를 보면 반투명인 부분이 있다.(하얀색 비가 위로 갈수록 Alpha값이 연해지도록 디자인 되어있음)
문제 : Rain의 비가 너무 진하다. Alpha값은 빠지긴 빠진다.
-> 이전에 했던 것은 알파값을 섞는 것이 아니라 알파값을 파기하므로 원래 색과 뒤의 색이 섞이지 않는다.(픽셀 삭제니까, 불투명)
반투명을 다룰라면 Blending을 알아야한다.(나중에 깊이들어가면 어려워짐)
BlendState로 세팅
d3d11.h
typedef struct D3D11_RENDER_TARGET_BLEND_DESC
{
BOOL BlendEnable;
D3D11_BLEND SrcBlend;
D3D11_BLEND DestBlend;
D3D11_BLEND_OP BlendOp;
D3D11_BLEND SrcBlendAlpha;
D3D11_BLEND DestBlendAlpha;
D3D11_BLEND_OP BlendOpAlpha;
UINT8 RenderTargetWriteMask;
} D3D11_RENDER_TARGET_BLEND_DESC;
typedef struct D3D11_BLEND_DESC
{
BOOL AlphaToCoverageEnable;
BOOL IndependentBlendEnable;
D3D11_RENDER_TARGET_BLEND_DESC RenderTarget[ 8 ];
} D3D11_BLEND_DESC;
나중에 RenderTarget이라고 해서 화면을 따는데, 화면을 다시 가져오는데, 8개를 다른 방법으로 렌더링해서 가져올 수 있다.(MRT)
우리는 하나밖에 없으니까 0번만 세팅
00_Global.fx
BlendState AlphaBlend
{
AlphaToCoverageEnable = false;
// 이런식으로도 되지만, 이런식으로 잘 안쓴다.
//RenderTarget[0].BlendEnable
// 이렇게 씀(배열 번호를 넣어줌)
BlendEnable[0] = true; // 블랜딩 할꺼다(true 시에 속도 느려져서, 할곳만 켜야함)
SrcBlend[0] = SRC_ALPHA;
DestBlend[0] = INV_SRC_ALPHA;
BlendOp[0] = ADD;
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
// 모든 색을 다 섞겠다.(전문적인 경우 제외하고 쓰는 경우없어서 이렇게 쓰는게 공식이라고 생각하자)
RenderTargetWriteMask[0] = 15; //0x0F;
};
결과적으로 반투명이 적용되었다. 뒤의 배경색이랑 섞임(blending됨)
극적인 효과가 하나 있다.
AlphaToCoverageEnable : 외곽선을 탐지해서 주변의 색과 자연스럽게 섞이도록 처리해주는 옵션
결과를 보면
0번 : 색이 찐함
1번(AlphaBlend) : 뒤에 색과 섞임, 반투명 효과 적용
2번(AlphaBlend_AlphaToCoverageEnable) : 뒤에 색과 섞이면서 외곽선이 깔끔함(외곽선이 줄음)
AlphaBlend 수식 설명
Src - 그릴 색
Dest - 이미 그려진 색(바닥 색)
SrcBlend[0] = SRC_ALPHA;
DestBlend[0] = INV_SRC_ALPHA;
BlendOp[0] = ADD; -> Add는 더하기
// 알파값을 얼마만큼 가져다 쓸지
// 이 두개는 알파값에 대해서만 수행함
// 예를 들어 SrcBlendAlpha[0] = One의 경우 텍스쳐의 알파가 0.5라면 0.5 * 1을 해서 SRC_ALPHA에 들어감
// SrcBlendAlpha[0] = Zero라면 텍스쳐의 알파가 0.5라면 0.5 * 0을 해서 SRC_ALPHA에 0이 들어감(Zero시에는 무조건 0이된다.)
SrcBlendAlpha[0] = One; -> 그릴색에 대한 알파를 전부 1로 써라(텍스쳐에 들어온 알파값을 그대로 쓰겠다.(*1이니깐))
DestBlendAlpha[0] = Zero; -> 바닥색의 알파는 일단 빼고 계산해라(그려진 것은 의미가 없어서 흔히 Zero를 쓴다.)
흔히 Src에는 One을, Dest에는 Zero를 준다.

<그림 13-1참고>
수식 :
SrcColor * SRC op DestColor * Dest
반투명이란? 뒤에 있는 색과 그릴 색을 반반씩 섞는것을 말함
알파블랜딩을 하려면 불투명 먼저 그려야 한다. 그 다음 반투명을 그려야한다.
그리는 순서가 나중에는 깊이도 추가되는데, 반투명과 깊이 먼저 뭐 추가해야하는지 골때리게 됨
Additive : 색을 더해서 밝은 색상을 만듬, 색이 진해짐
// 색을 진하게 만드는 효과
BlendState AdditiveBlend
{
AlphaToCoverageEnable = false;
BlendEnable[0] = true;
// 둘다 One을 줘서 더해서 더 밝은 색을 만듬 -> 그래서 Additive
SrcBlend[0] = One; // 파란색
DestBlend[0] = One; // 빨간색
BlendOp[0] = ADD; // 더해서 마젠타(자홍색) 색이나옴
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
RenderTargetWriteMask[0] = 15; //0x0F;
};
technique11 T0
{
//P_VP(P0, VS, PS_Discard)
P_BS_VP(P0, AlphaBlend, VS, PS)
P_BS_VP(P1, AlphaBlend_AlphaToCoverageEnable, VS, PS)
}
셰이더를 통해서 그리고 나면 Shader클래스의 End()함수에서 초기상태로 돌려놈, 다음꺼 그릴때는 원래대로 돌려놔서 꺼짐
주로 AlphaBlend나 Addtive를 적용해서 사용한다.
결과
3 : Additive
색이 진해짐
4 : AdditiveBlend_AlphaToCoverageEnable
struct VertexOutput
{
float4 Position : SV_Position;
float2 Uv : Uv;
float Alpha : Alpha; // 거리에 따른 투명도 조절을 위해
};
거리에 따른 투명도 조절을 하니
거리가 멀면 멀수록 알파가 많이 빠져서 자연스러워 보인다.
AlphaToCoverageEnable를 하면 양이 줄어든다, 외곽선에 대한 알파값이 줄어드는 것여서
00_Global.fx 추가된 내용
...
BlendState AlphaBlend
{
AlphaToCoverageEnable = false;
// 이런식으로도 되지만, 이런식으로 잘 안쓴다.
//RenderTarget[0].BlendEnable
// 이렇게 씀(배열 번호를 넣어줌)
BlendEnable[0] = true; // 블랜딩 할꺼다(true 시에 속도 느려져서, 할곳만 켜야함)
SrcBlend[0] = SRC_ALPHA;
DestBlend[0] = INV_SRC_ALPHA;
BlendOp[0] = ADD;
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
// 모든 색을 다 섞겠다.(전문적인 경우 제외하고 쓰는 경우없어서 이렇게 쓰는게 공식이라고 생각하자)
RenderTargetWriteMask[0] = 15; //0x0F;
};
BlendState AlphaBlend_AlphaToCoverageEnable
{
AlphaToCoverageEnable = true;
BlendEnable[0] = true;
SrcBlend[0] = SRC_ALPHA;
DestBlend[0] = INV_SRC_ALPHA;
BlendOp[0] = ADD;
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
RenderTargetWriteMask[0] = 15; //0x0F;
};
// 색을 진하게 만드는 효과
BlendState AdditiveBlend
{
AlphaToCoverageEnable = false;
BlendEnable[0] = true;
// 둘다 One을 줘서 더해서 더 밝은 색을 만듬 -> 그래서 Additive
SrcBlend[0] = One; // 파란색
DestBlend[0] = One; // 빨간색
BlendOp[0] = ADD; // 더해서 마젠타(자홍색) 색이나옴
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
RenderTargetWriteMask[0] = 15; //0x0F;
};
BlendState AdditiveBlend_AlphaToCoverageEnable
{
AlphaToCoverageEnable = true;
BlendEnable[0] = true;
SrcBlend[0] = One;
DestBlend[0] = One;
BlendOp[0] = ADD;
SrcBlendAlpha[0] = One;
DestBlendAlpha[0] = Zero;
BlendOpAlpha[0] = Add;
RenderTargetWriteMask[0] = 15; //0x0F;
};
85_Rain.fx 수정된 내용
#include "00_Global.fx"
#include "00_Light.fx"
cbuffer CB_Rain
{
float4 Color;
float3 Velocity;
float DrawDistance;
float3 Origin;
float CB_Rain_Padding;
float3 Extent;
};
struct VertexInput
{
float4 Position : Position;
float2 Uv : Uv;
float2 Scale : Scale; // 면의 크기
};
struct VertexOutput
{
float4 Position : SV_Position;
float2 Uv : Uv;
float Alpha : Alpha; // 거리에 따른 투명도 조절을 위해
};
VertexOutput VS(VertexInput input)
{
VertexOutput output;
float3 displace = Velocity;
// input.Scale.y 비의 길이의 크기가 큰게 비가 빨리 떨어져야 한다.
// 이 밑에 구문을 빼버리면 x,z도 y만큼 빨리 떨어질 것이다.
// x,z은 크기 만큼 비례해서 속도를 늦춘다.
// 만약 input.Scale.y가 작다면 크기에 비례해 x,z도 작은 값이 될 것이다.(비율로 만듬)
displace.xz /= input.Scale.y * 0.1f;
// Time을 곱해서 displcae 값이 커진다.
displace *= Time;
// 나눈 나머지는 계속 순환하는 값이 되므로 해당 공간안에서만 움직이도록 구현할 수 있다.
// 계속 값이 커질 것이고 어느순간 Extent(비가 내릴 구역의 부피)를 넘어설 것이다.
// 넘어서면 계속 순환되도록 한다.
// Extent+인 이유는 -값일 경우에 보정해줄려고 들어감
// 순환시킨 공간을 원래의 위치로 움직이게 하기 위해 +Origin을 수행
// Origin 만큼 또 이동했으므로 그 공간내에서 다시한번 순환(그 공간안에 들어오도록)시킨다.(% Extent)
// -(Extent * 0.5f) 다시 중심점을 잡아준다.(반만큼 빼줌)
// 순서 : 이동한 공간 내에서 순환되고 -1 ~ 1까지 옮겨져서 반에의해서 안에 들어감
input.Position.xyz = Origin + (Extent + (input.Position.xyz + displace) % Extent) % Extent - (Extent * 0.5f);
float4 position = WorldPosition(input.Position);
// float(0, 1, 0)을 써도 상관없는데 이거 좀 더 정확하니깐
// Velocity(속도)를 뒤집는다.
float3 up = normalize(-Velocity);
float3 forward = position.xyz - ViewPosition();
float3 right = normalize(cross(up, forward));
position.xyz += (input.Uv.x - 0.5f) * right * input.Scale.x;
position.xyz += (1.0f - input.Uv.y - 0.5f) * up * input.Scale.y;
position.w = 1.0f;
// View, Projection 변환
output.Position = ViewProjection(position);
output.Uv = input.Uv;
// 거리에 따른 알파값 조절하기
float4 view = mul(position, View);
// Position을 W * V로 변환한 위치의 Z의 값은 원점과 카메라의 거리
// 이 방법 외에도 ViewPosition()과 wPosition의 차로 계산해도 값은 같다.
// DrawDistance : 그릴 범위
// view.z / DrawDistance서 비율로 만든다음에 역수로 만들고(0 ~ 1)
// 얘에서 카메라를 바라보는 값이어서 즉, 값이 뒤집여져 있는 것이다.'
// 그래서 역수로 취한다.
// * 0.5f 해줬을때 이쁘드라 해서 넣은것
output.Alpha = saturate(1 - view.z / DrawDistance) * 0.5f;
return output;
}
float4 PS(VertexOutput input) : SV_Target
{
float4 diffuse = DiffuseMap.Sample(LinearSampler, input.Uv);
// * 2.0f 요정도 해줬을때 이쁘드라
diffuse.rgb *= Color.rgb * input.Alpha * 2.0f;
// 요것도 특별한 의미를 지닌값이 아님(1.5f는)
diffuse.a = diffuse.a * input.Alpha * 1.5f;
return diffuse;
}
technique11 T0
{
P_BS_VP(P0, AlphaBlend, VS, PS)
P_BS_VP(P1, AlphaBlend_AlphaToCoverageEnable, VS, PS)
P_BS_VP(P2, AdditiveBlend, VS, PS)
P_BS_VP(P3, AdditiveBlend_AlphaToCoverageEnable, VS, PS)
//P_VP(P0, VS, PS_Discard)
}
결과
'DirectX11 3D > 기본 문법' 카테고리의 다른 글
| <DirectX11 3D> 89 - ParticleSystem (0) | 2022.03.16 |
|---|---|
| <DirectX11 3D> 88 - Snow (0) | 2022.03.14 |
| <DirectX11 3D> 85 - Rain (0) | 2022.03.14 |
| <DirectX11 3D> 83 - Billboard (0) | 2022.03.14 |
| <DirectX11 3D> 82 - NormalMapping (0) | 2022.03.10 |