티스토리 뷰
developer.arm.com/documentation/100140/0401/Advanced-graphics-techniques
Documentation – Arm Developer
developer.arm.com
커스텀 쉐이더
Shader structure
Shader "Custom/ctTextured"
{
Properties
{
_AmbientColor ("Ambient Color", Color) = (0.2,0.2,0.2,1.0)
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma target 3.0
#pragma glsl
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// User-specified uniforms
uniform float4 _AmbientColor;
uniform sampler2D _MainTex;
struct vertexInput
{
float4 vertex : POSITION;
float4 texCoord : TEXCOORD0;
};
struct vertexOutput
{
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
};
// Vertex shader.
vertexOutput vert(vertexInput input)
{
vertexOutput output;
output.tex = input.texCoord;
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
return output;
}
// Fragment shader.
float4 frag(vertexOutput input) : COLOR
{
float4 texColor = tex2D(_MainTex, float2(input.tex));
return _AmbientColor + texColor;
}
ENDCG
}
}
Fallback "Diffuse"
}
첫 번째 키워드 Shader다음에 쉐이더의 path/name가옵니다 . 경로는 재질을 설정할 때 드롭 다운 메뉴에 셰이더가 표시되는 범주를 정의합니다. 예제의 셰이더는 드롭 다운 메뉴의 사용자 지정 셰이더 범주 아래에 표시됩니다.
Properties {} 블록은 인스펙터에서 볼 수 있는 셰이더 매개 변수와 상호 작용할 수있는 매개 변수를 나열합니다.
Unity의 각 셰이더는 sub 셰이더 목록으로 구성됩니다. Unity가 메시를 렌더링 할 때 사용할 셰이더를 찾고 그래픽 카드에서 실행할 수있는 첫 번째 sub 셰이더를 선택합니다. 이러한 방식으로 셰이더는 다른 셰이더 모델을 지원하는 다른 그래픽 카드에서 올바르게 실행됩니다. 이 기능은 GPU 하드웨어와 API가 지속적으로 발전하고 있기 때문에 중요합니다. 예를 들어 Mali Midgard GPU를 대상으로하는 메인 셰이더를 작성하여 OpenGL ES 3.0의 최신 기능을 사용하고 별도의 하위 셰이더에서 OpenGL ES 2.0 이하를 지원하는 그래픽 카드 용 대체 셰이더를 작성할 수 있습니다.
Pass 블록은 객체의 지오메트리가 한 번 렌더링되도록합니다. 셰이더에는 하나 이상의 패스가 포함될 수 있습니다. 이전 하드웨어에서 여러 패스를 사용하거나 특수 효과를 얻을 수 있습니다.
Unity가 지오메트리를 올바르게 렌더링 할 수있는 셰이더 본문에서 하위 셰이더를 찾을 수없는 경우 Fallback 문 다음에 정의 된 다른 셰이더로 롤백됩니다. 예제에서 이것은 Diffuse 빌트인 셰이더입니다.
Cg 프로그램 스니펫은 CGPROGRAM과 ENDCG 사이에 작성됩니다.
컴파일 지시문
컴파일 지시문을 #pragma 문으로 전달합니다. 컴파일 지시문은 컴파일 할 셰이더 함수를 나타냅니다.
각 컴파일 지시문에는 vertex 및 fragment 셰이더를 컴파일하기위한 지시문 (#pragma vertex name, #pragma fragment name)이 포함되어야합니다.
기본적으로 Unity는 셰이더를 셰이더 모델 2.0으로 컴파일합니다. #pragma target 지시문을 사용하면 셰이더를 다른 기능 수준으로 컴파일 할 수 있습니다. 셰이더가 커지면 다음 유형의 오류가 발생합니다.
Shader error in 'Custom/MyShader': Arithmetic instruction limit of 64 exceeded; 83 arithmetic instructions needed to compile program;
이 경우 #pragma target 3.0 문을 추가하여 셰이더 모델 2.0에서 셰이더 모델 3.0으로 변경해야합니다. 셰이더 모델 3.0에는 훨씬 더 높은 명령 제한이 있습니다.
버텍스 셰이더에서 프래그먼트 셰이더로 여러 가지를 전달하면 다음 오류가 발생할 수 있습니다.
Shader error in 'Custom/MyShader': Too many interpolators used (maybe you want #pragma glsl?) at line 75.
이 경우 컴파일 지시문 #pragma glsl을 추가하십시오. 이 지시문은 Cg 또는 HLSL 코드를 GLSL로 변환합니다.
#pragma only_renderers 지시문.
Unity는 gles, gles3, opengl, d3d11, d3d11_9x, xbox360, ps3 및 flash와 같은 여러 렌더링 플랫폼을 지원합니다. 기본적으로 셰이더는 #pragma only_renderers 뒤에 빈 공간을 남겨두고 싶은 렌더링 API를 사용하여이 수를 명시 적으로 제한하지 않는 한 이러한 모든 플랫폼에 컴파일됩니다.
모바일 장치를 대상으로하는 경우 셰이더 컴파일을 gles 및 gles3로만 제한하십시오. Unity 에디터에서 사용하는 OpenGL 및 d3d11 렌더러도 추가해야합니다.
#pragma only_renderers gles gles3 [opengl, d3d11]
Includes
셰이더에는 여러 Unity 기본 제공 변수를 사용할 수 있습니다. 이들은 포함 UnityShaderVariables.cginc에 있습니다. Unity는이 파일을 자동으로 수행하므로 셰이더에이 파일을 포함 할 필요가 없습니다. 셰이더에서 몇 가지 유용한 변환 행렬 및 크기를 직접 사용할 수 있습니다. 작업이 중복되지 않도록이 모든 것을 아는 것이 중요합니다. 예를 들어, 매트릭스를 셰이더, 카메라 위치 또는 투영 매개 변수 또는 조명 매개 변수에 전달하는 방법을 고려하기 전에 포함이 이미이를 제공하는지 확인하십시오.
성능을 향상시키기 위해 때때로 모든 정점에 대해 정점 셰이더에서 실행하는 대신 CPU에서 작업을 실행하고 결과를 GPU에 전달하는 것이 바람직합니다. 예를 들어, 이것은 행렬 균일의 곱셈의 경우입니다. 이것이 Unity가 여러 복합 매트릭스를 내장형 유니폼으로 사용할 수있게 한 이유입니다. 중요한 Unity 셰이더 내장 값 중 일부는 다음 표에 나와 있습니다.
Built-in UniformDescription
Built-in Uniform | 설명 |
UNITY_MATRIX_V | 현재 view 행렬 |
UNITY_MATRIX_P | 현재 projection 행렬 |
Object2World | 현재 model 행렬 |
_World2Object | Inverse of current world matrix |
UNITY_MATRIX_VP | Current view * projection matrix |
UNITY_MATRIX_MV | Current model * view matrix |
UNITY_MATRIX_MVP | Current model * view * projection matrix |
UNITY_MATRIX_IT_MV | Invert transpose of current model * view matrix |
_WorldSpaceCameraPos | Camera position in world space |
_ProjectionParams | 근거리 및 원거리 평면 및 1 / farPlane을 벡터의 구성 요소로 사용 |
_Time | 현재 시각 and 벡터의 일부 (t/20, t, t*2, t*3) |
OpenGL ES 3.0 그래픽 파이프 라인
그래픽 파이프 라인에서 프로그래밍 가능한 정점 및 조각 셰이더가있는 위치를 아는 것이 중요합니다.
다음 그림은 OpenGL ES 3.0 그래픽 파이프 라인 흐름의 개략도를 보여줍니다. OpenGL ES 3.0은 임베디드 그래픽 발전의 주요 단계이며 OpenGL 3.3 사양에서 파생되었습니다.
Primitives
Primitive Stage에서 파이프 라인은 꼭지점, 점, 선 및 다각형으로 설명되는 기하학적 기본 요소에서 동작합니다.
Vertex Shader
버텍스 셰이더는 정점에서 작동하기위한 범용 프로그래밍 가능 방법을 구현합니다. 버텍스 셰이더는 버텍스를 변형하고 조명합니다.
Primitive assembly
기본 어셈블리에서 정점은 기하학적 기본 요소로 어셈블됩니다. 결과 프리미티브는 클리핑 볼륨으로 클리핑되어 래스터 라이저로 전송됩니다.
Rasterization
버텍스 셰이더의 출력 값은 생성 된 모든 Fragment에 대해 계산됩니다. 이 프로세스를 보간이라고합니다. 래스터 화 중에 프리미티브는 2 차원 Fragment세트로 변환 된 다음 Fragment셰이더로 전송됩니다.
Transform feedback
변환 피드백은 정점 셰이더가 출력하고 나중에 정점 셰이더로 다시 전송되는 출력 버퍼에 선택적 쓰기를 기록 할 수 있도록합니다. 이 기능은 Unity에 의해 노출되지 않지만, 예를 들어 캐릭터의 스키닝을 최적화하기 위해 내부적으로 사용됩니다.
Fragment shader
프래그먼트 셰이더는 프래그먼트가 다음 단계로 전송되기 전에 프래그먼트 작업을 위해 프로그래밍 가능한 범용 메서드를 구현합니다.
Per-fragment operations
Per-fragment 작업에서 여러 기능과 테스트가 각 fragment에 적용됩니다.
픽셀 소유권 테스트, 가위 테스트, 스텐실 및 깊이 테스트, 블렌딩 및 디더링.
이 조각 별 단계의 결과로 조각이 삭제되거나 조각 색상, 깊이 또는 스텐실 값이 화면 좌표의 프레임 버퍼에 기록됩니다.
버텍스 셰이더
정점 셰이더 예제는 지오메트리의 각 정점에 대해 한 번씩 실행됩니다. 정점 셰이더의 목적은 객체의 로컬 좌표에 주어진 각 정점의 3D 위치를 화면 공간에서 투영 된 2D 위치로 변환하고 Z- 버퍼의 깊이 값을 계산하는 것입니다.
변환 된 위치는 정점 셰이더의 출력에서 예상됩니다. 정점 셰이더가 값을 반환하지 않으면 콘솔에 다음 오류가 표시됩니다.
Shader error in 'Custom/ctTextured': '' : function does not return a value: vert at line 36
예제에서 정점 셰이더는 로컬 공간의 정점 좌표와 텍스처 좌표를 입력으로받습니다.
정점 좌표는 UNITY_MATRIX_MVPUnity 내장 값인 Model View Projection 매트릭스를 사용하여 로컬에서 화면 공간으로 변환됩니다
output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
텍스처 좌표는 Fragment 셰이더에 가변으로 전달되지만 이것이 변형되지 않았음을 의미하지는 않습니다.
법선은 다른 방식으로 오브젝트 공간에서 월드 공간으로 변환됩니다. 비균일스케일링 작업 후에도 법선이 삼각형에 대해 여전히 법선임을 보장하려면 변환 행렬의 역전치를 곱해야합니다. 전치 연산을 적용하려면 곱셈에서 요인의 순서를 뒤집습니다. 로컬 대 월드 매트릭스의 역은 내장 된 World2Object Unity매트릭스입니다. 이것은 4x4 행렬이므로 3 성분 노멀 입력 벡터에서 4 성분 벡터를 만들어야합니다.
float4 normalWorld = mul(float4(input.normal, 0.0), _World2Object);
네 가지 구성 요소 벡터를 만들 때 네 번째 구성 요소로 0을 추가합니다. 이는 4 차원 공간에서 벡터 변환을 올바르게 처리하는 데 필요하며 좌표의 경우 네 번째 구성 요소는 단위(Unit)이여야합니다.
이미 표준 좌표에 법선이 제공된 경우 법선 변환 프로세스를 건너 뛸 수 있습니다. 이렇게하면 정점 셰이더 작업이 절약됩니다. 이 경우 노멀이 오브젝트 좌표에서 예상되기 때문에 오브젝트 메시가 Unity 내장 셰이더에서 잠재적으로 처리 될 수있는 경우 이 힌트를 피하십시오.
대부분의 그래픽 효과는 fragment셰이더에서 구현되지만 버텍스셰이더에서 일부 효과를 수행 할 수도 있습니다.
변위 매핑이라고도하는 정점 변위 매핑은 예를 들어 높이 맵을 사용하는 지형 생성에서 텍스처를 사용하여 다각형 메시를 변형하여 표면 세부 사항을 추가 할 수있는 잘 알려진 기술입니다. 이 텍스처 (변위 맵이라고도 함)에 대한 정점 셰이더에 액세스하려면 셰이더 모델 3.0에서만 사용할 수 있으므로 pragma 지시문 #pragma target 3.0을 추가해야합니다. 셰이더 모델 3.0에 따르면 버텍스 셰이더 내에서 최소 4 개의 텍스처 단위에 액세스 할 수 있어야합니다. 편집기가 OpenGL 렌더러를 사용하도록 강제하는 경우 #pragma glsl 지시문도 추가해야합니다. 이 지시문을 선언하지 않으면 오류 메시지가 발생합니다.
Shader error in 'Custom/ctTextured': function "tex2D" not supported in this profile (maybe you want #pragma glsl?) at line 57
정점 셰이더에서 "절차적 애니메이션"기술을 사용하여 정점을 애니메이션 할 수도 있습니다. 셰이더에서 시간 변수를 사용하여 시간 함수로 정점 좌표를 수정할 수 있습니다. 메시스키닝은 버텍스셰이더에 구현된 또 다른 유형의 기능입니다. Unity는 이를 사용하여 캐릭터 스켈레톤과 관련된 메시의 정점을 애니메이션합니다.
Vertex shader output and varyings
정점 셰이더 출력은 정점 변환 된 좌표를 포함해야하는 출력 구조에 정의됩니다. 다음 예에서 출력 구조는 매우 간단하지만 다른 크기를 추가 할 수 있습니다
struct vertexOutput
{
float4 pos : SV_POSITION;
float4 tex : TEXCOORD0;
float4 texSpecular : TEXCOORD1;
float3 vertexInWorld : TEXCOORD2;
float3 viewDirInWorld : TEXCOORD3;
float3 normalInWorld : TEXCOORD4;
float3 vertexToLightInWorld : TEXCOORD5;
float4 vertexInScreenCoords : TEXCOORD6;
float4 shadowsVertexInScreenCoords : TEXCOORD7;
};
변환 된 정점 좌표는 SV_POSITION으로 정의됩니다. 의미론적 TEXCOORDn을 호출하는 서로 다른 공간에있는 두 개의 텍스처, 여러 벡터 및 좌표도 조각 셰이더에 전달됩니다.
TEXCOORD0은 일반적으로 UV 용으로 예약되고 TEXCOORD1은 라이트 맵 UV 용으로 예약되어 있지만 기술적으로는 TEXCOORD0에서 TEXCOORD7까지 무엇이든 조각 셰이더로 보낼 수 있습니다. 각 시맨틱인 각 보간은 최대 4개의 부동소수점 만 처리 할 수 있습니다. 행렬과 같은 더 큰 변수를 여러 보간에 넣습니다. 즉, 가변으로 전달할 행렬을 정의하는 경우 : float4x4 myMatrix : TEXCOORD2는 Unity가 TEXCOORD2에서 TEXCOORD5까지 보간을 사용합니다.
정점 셰이더에서 조각 셰이더로 보내는 모든 것은 기본적으로 선형 보간됩니다. 꼭지점에 의해 정의되는 삼각형 내의 모든 픽셀에 대해 V1, V2그리고 V3정점 및 조각 쉐이더의 그래픽스 파이프 라인에있는 래스터 라이저, 상기 무게 중심 좌표 λ1, λ2 및 λ3을 이용하여 정점 좌표의 선형 보간 등의 화소의 좌표를 산출합니다.
다음 다이어그램은 정점 색상이 빨강, 녹색 및 파랑 인 삼각형의 색상 보간 결과를 보여줍니다.
버텍스에서 프래그먼트 셰이더로 전달되는 모든 가변에 동일한 보간이 적용됩니다. 하드웨어 선형 보간기가 있기 때문에 이것은 매우 강력한 도구입니다. 예를 들어, 평면이 있고 중심 C까지의 거리 함수로 색상을 적용하려는 경우 중심 C의 좌표를 정점 셰이더에 전달하고 정점에서 C까지의 제곱 거리를 계산하고 통과합니다. 조각 셰이더에 그 크기. 거리 값은 모든 삼각형의 모든 픽셀에서 자동으로 보간됩니다.
값은 선형 보간되므로 정점 별 계산을 수행하고 이를 조각 셰이더에서 재사용 할 수 있습니다. 즉, 조각 셰이더에서 선형으로 보간 할 수있는 값을 정점 셰이더에서 대신 계산할 수 있습니다. 버텍스 셰이더가 프래그먼트 셰이더보다 훨씬 더 작은 데이터 세트에서 실행되기 때문에 이는 상당한 성능 향상을 제공 할 수 있습니다.
Fragment Shaders
프래그먼트 셰이더는 기본 래스터 화 이후의 그래픽 파이프 라인 단계입니다.
프리미티브에 포함 된 픽셀의 각 샘플에 대해 조각이 생성됩니다. 조각 셰이더 코드는 생성된 각 조각 마다 실행됩니다. 정점보다 많은 조각이 있으므로 조각 셰이더에서 수행되는 작업 수에 주의해야합니다.
조각 셰이더에서 정점 셰이더에서 보간 된 모든 정점 별 출력 값을 포함하는 다른 값 중에서 window 공간의 조각 좌표에 액세스 할 수 있습니다.
쉐이더 구조의 예제에서 프래그먼트 셰이더는 정점 셰이더에서 보간된 텍스처 좌표를 수신하고 텍스처 조회를 수행하여 이러한 좌표에서 색상을 얻습니다. 이 색상을 주변 색상과 결합하여 최종 출력 색상을 생성합니다. 프래그먼트 셰이더의 선언 에서 프래그먼트 색상을 생성 할 것으로 예상 됨이 분명합니다. 프래그먼트 셰이더는 필요한 효과를 얻기 위해 작업을 수행하는 곳입니다. 이것은 궁극적으로 조각에 올바른 색상을 할당하는 것으로 구성됩니다.
// Fragment shader.
float4 frag(vertexOutput input) : COLOR
{
float4 texColor = tex2D(_MainTex, float2(input.tex));
return _AmbientColor + texColor;
}
셰이더에 데이터 제공
Pass 블록에서 uniform으로 선언 된 모든 데이터는 버텍스 셰이더와 프래그먼트 셰이더 모두에서 사용할 수 있습니다.
uniform은 셰이더 내에서 수정할 수 없기 때문에 전역 상수 변수의 한 유형으로 간주 될 수 있습니다.
다음과 같은 방법으로이 유니폼을 셰이더에 제공 할 수 있습니다.
- Properties블록 사용 .
- 스크립트에서 프로그래밍 방식으로.
속성 블록을 사용하면 Inspector에서 대화식으로 유니폼을 정의 할 수 있습니다. 속성 블록에서 선언 된 모든 변수는 변수 이름과 함께 나열된 마테리얼 인스펙터에 나타납니다.
Properties
{
_AmbientColor ("Ambient Color", Color) = (0.2,0.2,0.2,1.0)
_MainTex ("Base (RGB)", 2D) = "white" {}
}
Ambient Color 및 Base (RGB)라는 이름으로 각각 Properties 블록에 선언 된 변수 _AmbientColor 및 _MainTex는 해당 이름으로 Material Inspector에 나타납니다.
데이터를 셰이더로 전달하는 다른 방법은 스크립트에서 프로그래밍 방식으로 수행하는 것입니다.
머티리얼 클래스는 머티리얼과 관련된 데이터를 셰이더로 전달하는 데 사용할 수있는 여러 메서드를 노출합니다. 다음 표에는 가장 일반적인 방법이 나열되어 있습니다.
Method |
SetColor (propertyName: string, color: Color); |
SetFloat (propertyName: string, value: float); |
SetInt (propertyName: string, value: int); |
SetMatrix (propertyName: string, matrix: Matrix4x4); |
SetVector (propertyName: string, vector: Vector4); |
SetTexture (propertyName: string, texture: Texture); |
다음 코드에서 기본 카메라가 장면을 렌더링하기 직전에 보조 카메라 shwCam은 기본 카메라 렌더패스와 결합될 텍스처로 그림자를 렌더링합니다.
그림자 텍스처 투영 프로세스의 경우 정점을 편리한 방식으로 변환해야합니다. 그림자 카메라 투영 행렬 (shwCam.projectionMatrix), 세계에서 로컬로의 변환 행렬 (shwCam.transform.worldToLocalMatrix) 및 렌더링 된 그림자 텍스처 (m_ShadowsTexture)가 셰이더에 전달됩니다.
이 값은 셰이더에서 _ShwCamProjMat, _ShwCamViewMat 및 m_ShadowsTexture라는 이름의 유니폼으로 사용할 수 있습니다.
다음 코드는 shwMats 목록에 포함 된 재료를 사용하여 매트릭스와 텍스처를 셰이더로 보내는 방법을 보여줍니다.
// Called before object is rendered.
public void OnWillRenderObject()
{
// Perform different checks.
...
CreateShadowsTexture();
// Set up shadows camera shwCam.
...
// Pass matrices to the shader
for(int i = 0; i < shwMats.Count; i++)
{
shwMats[i].SetMatrix("_ShwCamProjMat", shwCam.projectionMatrix);
shwMats[i].SetMatrix("_ShwCamViewMat", shwCam.transform.worldToLocalMatrix);
}
// Render shadows texture
shwCam.Render();
for(int i = 0; i < shwMats.Count; i++)
{
shwMats[i].SetTexture( "_ShadowsTex", m_ShadowsTexture );
}
s_RenderingShadows = false;
}
Unity에서 셰이더 디버깅
Unity에서는 기존 코드와 같은 방식으로 셰이더를 디버깅 할 수 없습니다. 그러나 조각 셰이더의 출력을 사용하여 디버그하려는 값을 시각화 할 수 있습니다. 그런 다음 생성 된 이미지를 해석해야합니다.
다음 그림은 로컬 큐브 맵으로 반사 구현(ctReflLocalCubemap.shader)에서 바닥의 반사 표면에 적용된 셰이더의 출력을 보여줍니다 .
반사 된 이미지 대신 색상으로 정규화 된 반사 벡터의 구성 요소를 시각화합니다.
바닥의 붉은 색 영역은 반사 된 벡터에 강한 X 구성 요소가 있음을 나타냅니다. 즉, 대부분 X 축 방향으로 향합니다. 붉은 부분은 그 방향, 즉 창문이있는 벽에서 오는 반사를 보여줍니다.
푸르스름한 영역은 Z 축 방향, 즉 오른쪽 벽에서 반사 된 반사 벡터의 우세를 나타냅니다.
검은 색 영역에서 벡터는 주로 -Z 방향이지만 음수 구성 요소가 0으로 고정되기 때문에 색상은 양수 구성 요소 만 가질 수 있습니다.
다음 그림은 조각의 출력 색상을 정규화 된 로컬 반사 벡터로 대체 한 결과를 보여줍니다.
처음에는 디버깅하는 동안 색상의 의미를 해석하기 어려울 수 있으므로 단일 색상 구성 요소에 집중하십시오. 예를 들어 정규화 된 로컬 수정 반사 벡터의 Y 구성 요소 만 반환 할 수 있습니다.
float3 normLocalCorrReflDirWS = normalize(localCorrReflDirWS);
return float4(0, normLocalCorrReflDirWS.y, 0, 1);
이 경우 출력은 주로 카메라 위 지붕에서 나오는 반사입니다. 즉, Y 축을 향한 방의 일부입니다. 방 벽의 반사는 X, Z, -Z 방향에서 나오므로 검은 색으로 렌더링됩니다.
다른 값은 자동으로 고정되므로 색상으로 디버깅하는 크기가 0과 1 사이인지 확인하십시오. 음수 값에는 0이 할당되고 1보다 큰 값에는 1이 할당됩니다.
'Unity > 최적화' 카테고리의 다른 글
Unity 개발자를 위한 ARM 설명서 v4.1 - part 3 (0) | 2021.04.06 |
---|---|
Unity 개발자를 위한 ARM 설명서 v4.1 - part 1 (0) | 2021.04.06 |
Unity Particle Draw call 절약 (0) | 2021.04.06 |
Diagnosing Performance Problems - 2019.3 (0) | 2021.03.26 |
Fixing Performance Problems - 2019.3 (0) | 2021.03.22 |
- Total
- Today
- Yesterday