Home 9. 커맨드와 프로퍼티
Post
Cancel

9. 커맨드와 프로퍼티

들어가기에 앞서


과제를 작성할 때 조금이나마 과제의 흐름을 보여주고 싶어서 순서를 조금 바꾼 부분이 있었습니다.

그런데 최근 수강하는데 앞 뒤 맥락을 모르니 전 주차에서 과제로 작성했던 내용이 일부 있고,

강의 주차에 맞춰 작성하자니 정보가 파편화 되어 과거 작성글을 수정해야할지 어떻게해야할지 잘 모르는 상황이 되었습니다..

과제로 한번 싹 작성한 다음 나중엔 아마 한 페이지로 만들어버리지 않을까 하는 생각이 듭니다.

페이지가 아닌 위키처럼 작성하는게 옳았던걸까요? 잘 모르겠습니다..

작성에서 문법 해부에 프로퍼티,프로퍼티 어트리뷰트,쉐이더랩 태그,패스 태그,커맨드가 한장에 나와야 이쁘게 정리될 것 같은데 세 게시글에 거쳐 작성되니 추후 자료참고시 어려움이 존재한다고 생각합니다.. 수학과제처럼 이쁘게가 안되네요…

아무튼 저번주차, 저저번주차와 일부 겹치는 항목이 있어 중복된 부분은 기술하지 않습니다.

이번주차는 강의 파일 제목의 압박이 상당합니다. 이번주차는 강의 파일 제목의 압박이 상당합니다.

ShaderLab

Pass Name


말 그대로 패스에 이름을 설정할 수 있습니다.

렌더링 오류가 발생하거나, 디버깅하거나, 어딘가에서 사용하기 위한 식별 자료로써 사용됩니다.

특히 use pass에서 사용하기 위해 필요한데,

UsePass “Shader object name/PASS NAME IN UPPERCASE”

와 같은형식으로 사용됩니다.

code.png

와 같이 말이죠.

커맨드와 프로퍼티


Commands

https://docs.unity3d.com/kr/2021.2/Manual/shader-shaderlab-commands.html

커맨드란 무엇일까요?

단순합니다. 말 그대로 명령어입니다. 쉐이더는 결국 사용자가 마음대로 처리할 수 있게 하기위해 만들어 졌기 때문에, 몇몇 동작에 대해 명령으로 어떻게 동작하라를 지정할 수 있습니다.

subShader에 존재하는 Tag와 Pass의 Tag는 서로 다른 존재이기 때문에 선언 위치가 중요합니다.

하지만 Commands는 동일하여 subshader 블록에 작성할 경우 하위의 모든 Pass에서 해당 Command가 적용됩니다.

AlphaToMask <On,Off>

https://docs.unity3d.com/kr/2021.2/Manual/SL-AlphaToMask.html

하..MSAA..에 대해 설명해야 하는데,

Untitled

Untitled

Multi Sampling Anti Aliasing의 경우,

한 픽셀당 얼마나 포함되어있는지 n번씩 연산을 처리하게 됩니다.

이때 만약 투명맵을 사용하는 텍스쳐가 존재할 경우,

투명한 픽셀들 모두에 테스트를 하게 되므로 해당부분을 줄여야합니다.

그렇게 알파 테스팅을 하게 되죠.

하지만 알파테스팅으로 인해 파기된 픽셀 경계,

즉 프리미티의 경계에 대해 MSAA는 처리할 수 없으니(과거, DX9),

내부적으로 다음과 같은 원리로 작동하는 기법을 제작하게 됩니다.

  1. 픽셀 쉐이더에서 나온 Color값을 n-Step Coverage Mask를 생성합니다.
  2. n-Step Coverage Mask와 MultiSampleCoverageMask를 AND합니다.
  3. 위 결과를 가지고 멀티샘플링 혹은 슈퍼샘플링 합니다.

이를 Alpha to Coverage라고 말하며,NVIDIA에서는 Transparency AA라고 말합니다.

그 기능을 켜거나 끄는 옵션입니다.

(이 한마디 때문에…)

Untitled

Blend

https://docs.unity3d.com/kr/2021.2/Manual/SL-Blend.html

Blend는 몇가지 오버로드된 시그니처가 있습니다.

Untitled

보통 대부분 3번째, Blend 을 사용합니다.

result = sourceFactor ***** sourceValue **** destinationFactor * destinationValue 의 식입니다.

이때 Dst, destination Color는 FrameBuffer를 의미하는데,

즉 렌더 대상(Render Target, 예를 들어 _CameraColorAttachmentA)를 의미합니다.

Untitled

몇가지 방법들에 대한 예시를 들자면(연산은 기본인 더하기로 설정하겠습니다),

Blend One One

⇒ SrcColor * 1 + DstColor * 1

Blend SrcAlpha OneMinusSrcAlpha

⇒ SrcColor * SrcColor.a + DstColor * (1 - ScrColor.a)

인 것이죠.

값들은 다음과 같습니다.

Untitled

BlendOp (Blend Operation)

https://docs.unity3d.com/kr/2021.2/Manual/SL-BlendOp.html

result = sourceFactor ***** sourceValue **** destinationFactor * destinationValue

에서 중앙에 들어가는 연산을 설정할 수 있습니다.

기본값은 Add, + 입니다.

Untitled

ColorMask

https://docs.unity3d.com/kr/2021.2/Manual/SL-ColorMask.html

특정 채널에 대한 색상쓰기를 활성화 할 수 있는 명령구문입니다.

Untitled

Conservative

https://docs.unity3d.com/kr/2021.2/Manual/SL-Conservative.html

래스터화 과정에서 보통 적용범위가 ‘충분하면’ 포함된것으로 인지하는데,

이 충분하지 않아도 포함된 것으로 인지하는게 ‘보수적’입니다.

보수적으로 처리하게 되면 가장자리에서 더 많은 픽셀을 만들어내게 되며,

그에 따라 픽셀쉐이더 호출이 증가하여 GPU 처리시간이 증가할 수 있습니다.

래스터라이징을 보수적으로 하는지 아닌지에 대한 설정을 할 수 있습니다.

하드웨어 지원을 확인해야하며, 지원하지 않는 하드웨어에서 무시됩니다.

Untitled

Cull

https://docs.unity3d.com/kr/2021.2/Manual/SL-Cull.html

컬링

보통 컬링(culling)은 특성에 따라 그룹에서 분리하는 과정을 뜻합니다.

저희쪽에서는 렌더링을 할지를 결정한다고 보면 될 것 같네요.

보통 컬링의 종류는 세가지가 있는데,

  • 절두체 컬링 (Frustum Culling) - 카메라가 안보는 각도는 NO!
  • 오클루전 컬링(Occlusion Culling) - 가린건 NO!
  • 뒷면컬링(Backface Culling) - 뒷면은 NO!

후면을 컬링할 것인지,

앞면을 컬링할 것인지,

컬링하지 않을 것인지 에 대하여 설정하는 명령어입니다.

Untitled

Offset

https://docs.unity3d.com/Manual/SL-Offset.html

GPU의 깊이 바이어스를 설정합니다.

쉽게 생각하면 z파이팅 같은것을 해결할 수 있다는 뜻입니다.

예를 들면 레거시 데칼같은 경우,

비슷한 위치에 폴리곤이 존재하는 경우가 있을 수 있습니다.

Untitled

Stencil

https://docs.unity3d.com/kr/2021.2/Manual/SL-Stencil.html

스텐실기법을 생각하면 편합니다.

Untitled

스텐실 버퍼에 값을 기록하고, 대조해서, 변경을 정의합니다.

Unity uGUI의 Mask 컴포넌트가 해당방식으로 처리되는데,

생각보다 마스킹을 제외하곤 구성하기 조금 어렵습니다.

대조 번호 Ref,

비교 방식 Comp,

통과되었을 때 할 행동 Pass,

실패하였을때 할 행동 Fail,

깊이검사에 실패하였을때 할 행동 ZFail

로 나눠집니다.

Untitled

ZClip

https://docs.unity3d.com/kr/2021.2/Manual/SL-ZClip.html

잘안사용하는 기능입니다.

near/far 에 대한 클리핑시 처리를 설정합니다.

투영공간의 앞 뒤를 벗어나는 객체를

클리핑할지, 아니면 클램핑할지 설정합니다.

Clamp 처리시, 원평면이 1000거리에 있다면 12000거리에 존재하는 오브젝트와, 1500거리에 존재하는 오브젝트가 모두 1000에 존재할 수 있습니다.

ZTest

https://docs.unity3d.com/kr/2021.2/Manual/SL-ZTest.html

깊이 검사를 어떻게 할 지에 대한 설정입니다.

스텐실에서 Comp만 있다고 생각하시면 좋습니다.

테스트에 성공한 픽셀만 렌더링합니다.

ZWrite

https://docs.unity3d.com/kr/2021.2/Manual/SL-ZWrite.html

렌더링 도중 깊이 테스트를 성공한다면(?),

깊이를 다시 작성할지에 대한 설정입니다.

의문.

  1. 테스트에 성공한 것만 그리나?
  2. 테스트에 성공한다면, 사용자가 지정한 비교연산을 성공한 것만 작성하는가?
  3. 그렇다면 정상적인 깊이검사를 한번 하고(LE), 반댓값(G)을 다시 작성한다면 그 후 사용하는 깊이 검사는 G로 작성한 깊이텍스처를 기준으로 사용되나????

Property 2


그렇다면 이런 값들은 항상 쉐이더에 작성하지 않고

외부에서 받아올 수 있는 방법이 있을까요??

답은 『있다』 입니다.

[Enum]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Properties
{
	[Enum(UnityEngine.Rendering.CullMode)]     _CullMode("Cull Mode", Float) = 2
	[Enum(UnityEngine.Rendering.CompareFunction)] _ZTest("Z Test", Float) = 0
	[Enum(Off, 0, On, 1)] _ZWrite("ZWrite", Float) = 1
	
	[Enum(UnityEngine.Rendering.BlendMode)] _SrcFactor("Src Factor", Float) = 5
	[Enum(UnityEngine.Rendering.BlendMode)] _DstFactor("Dst Factor", Float) = 10
}
SubShader
{
	Tags {...}
	Blend [_SrcFactor] [_DstFactor] //설정한 값으로 사용
	ZTest [_ZTest]
	ZWrite [_ZWrite]

이미 정의된 몇가지 enum type을 사용하여 모드를 선택하거나,(UnityEngine.Rendering.BlendMode 와 같이)

그냥 단순히 깡으로 값을 박아도 괜찮습니다. (ZWrite 같이)

[keywordEnum]

1
2
3
4
5
6
7
8
9
[KeywordEnum(AAA,BBB,CCC)] _Type("Type", Float) = 2

...

#if _Type_AAA
#elif _Type_BBB
#elif _Type_CCC
...
#endif

비슷한 방식으로 enum을 다음과 같은 방식으로 사용하여

전처리 구문을 사용할 수 있습니다

HLSLINCLUDE


역시 c를 기반으로 하는 언어입니다.

#include “” 구문은 단순히 해당 파일을 복사 + 붙여넣기 한다고 생각하면 되며,

극단적으로 이런 구성도 가능합니다.

C++로 다져진 흑마법을 받아라!!!

C++로 다져진 흑마법을 받아라!!!

전처리구문


hlsl Anatomy 2.png

7주차에 사용했던 #pragma vertex vert, fragment frag

라고 사용했던게 있습니다.

여기서 #pragma를 컴파일 지시문이라고 하며,

컴퓨터별 또는 운영 체제별 컴파일러 기능을 지정합니다

위의 두개는 버텍스 쉐이더와 프래그먼트 쉐이더를 지정한 것이지만

#pragma target

#pragma exclude_rederers

#pragma only_renderers

처럼 쉐이더 모델, 특정 플랫폼 혹은 대상에 대해서만 컴파일을 지정할 수 있습니다.

다이렉트X와 OpenGL등 동작방식이 다르다면 사용할 수 있겠죠?

Struct

구조체입니다.

1
2
3
4
struct structName
{
    type name : SEMANTIC;
};

다음과 같이 정의할 수 있으며,

만약 Vertex shader에서 특수한 값들을 받고 싶다면, SEMANTIC을 작성해야합니다.

대게 다음과 같은 데이터를 사용합니다.

1
2
3
4
5
TEXCOORD
SV_POSITION //POSITION
NORMAL
TANGENT
COLOR

관련내용은 다음에 다시 제대로 정리합니다.

CBuffer

상수버퍼입니다.

Untitled

SRP 배칭에서는 GPU메모리에 오래 살아있을 수록 속도가 빨라집니다.

이때 기존과 같이 메모리에 머테리얼을 오래 유지하는방식 말고,

몇몇 데이터를 대용량으로 GPU 메모리에 올려둘 수 있는 방법이 있습니다.

이것이 상수버퍼입니다.

Untitled

기존 렌더 파이프라인과 비교하였을 때

기존엔 매번 렌더링 할 때 마다 정보를 가져와서 사용했다면,

SRP에서는 Material 단위의 정보를 정보의 변환이 있을때만 GPU에 상주시켜둔다는 차이가 있습니다.

그래서 램에서 GPU까지 데이터를 보내는 시간을 절약할 수 있는 것이죠.

이를 사용하기 위해 코드에서 조금 처리를 해줘야합니다.

1
2
3
4
5
6
7
8
9
//머테리얼당
CBUFFER_START(UnityPerMaterial)
	//...
CBUFFER_END

//draw당
CBUFFER_START(UnityPerDraw)
	//...
CBUFFER_END

해당 CBUFFER_START와 CBUFFER_END 사이에 변수를 넣으면

머테리얼별 GPU 메모리에 상주하게 됩니다.

DX11기준으론 16bytes에 맞춰서 넣었어야 했는데 유니티는 잘 모르겠습니다?

SIMD / SIMT

Untitled

생성된 쉐이더 코드를 뜯어보면 float4하나, half 4개로 구성되어 있음을 볼 수 있지만,렌더 프로파일링 도구에서 상수버퍼를 직접 뜯어보면

float4 (4*4), half * 4 (2 * 4)가 float4 + float4

총 32바이트로 들어가는것을 알 수 있습니다.

아마 16바이트씩 들어가지 않을까 합니다.(추측)

Function

함수입니다.

선언,정의,입력,출력으로 되어있으며 c언어의 그것과 유사합니다.

1
2
3
4
5
6
7
8
9
10
<return-type> function-name(<type> argsName ...)
{
	...
}

//ex)
float Lerp(float a,float b,float t)
{
	return a + t * (b - a)
} 

다만 C의 함수와는 조금 다른게 있는데,

c#처럼 함수 선언시 inout키워드, 매개변수 한정자를 달 수 있습니다.

또한 Semantic을 달 수 있으며, InterpolationModifier 를 달 수 있습니다.

함수 인수

다음 구문을 사용하여 인수를 선언할 수 있습니다.

1
[InputModifier ] 형식 [ 이름: Semantic ] [ InterpolationModifier ] [ = Initializers]

매개변수한정자

c#에서의 매개변수한정자, HLSL에서의 InputModifier는

인수를 입력 혹은 출력 혹은 둘 다 로 식별하는 선택적 용어입니다.

in, inout, out, uniform 의 4개가 존재하며,

in은 함수가 시작되기 전에 호출 애플리케이션에서 매개 변수의 값을 복사해야 함을 나타냅니다.

out은 매개 변수의 마지막 값을 복사하고 함수가 반환될 때 호출 애플리케이션에 반환되어야 함을 나타냅니다.

inout은 둘 다 지정하기 위한 약식입니다.

uniform의 경우는 상수레지스터에서 가져오는데, 최상위수준이 아닌 함수의 경우 in과 동일하다고 보면 됩니다.

inline

인라인입니다. 함수를 호출하는것도 성능비용이 존재하므로, 이를 줄이기 위해 컴파일단계에서 치환해주는 느낌이지만 hlsl에서는 기본값이라 그냥 신경쓸 필요 없습니다.

자료출처


https://www.hardwaretimes.com/pc-graphics-settings-explained-msaa-vs-fxaa-vs-smaa-vs-taa/

This post is licensed under CC BY 4.0 by the author.
Contents