'unity'에 해당되는 글 3건

  1. 2020.07.16 [Unity] 유니티 셰이더 최적화 정리

[Unity] 유니티 셰이더 최적화 정리

나중에 안잊어버리려고 써두는 정리.

1. 가능한 연산은 버텍스 셰이더 영역에서.

per-vertex
per-pixel

UV와같은 어떤 연산들은 꼭 프래그먼트 셰이더 안에서 실행 하지 않아도 거의 품질에 차이가 없는 경우가 있다. 혹은 위 사진과 같이 품질은 낮아지지만 멀리서 보이는 물건이라던가 하는 등 특수한 상황에 처했을때에도 고려할 수 있다.

2. 노이즈 등의 복잡한 기능은 텍스쳐로 해결하자.

주로 이펙트를 만들때 랜덤하게 버텍스를 움직인다던가 하는데에 노이즈를 만들어내야하는 경우가 있다. 이를 복잡한 계산으로 처리하는 것 보다는 노이즈 텍스쳐를 외부에서 받아 쓰는 것이 효율적이다.여기에는 앰비언트 오클루전도 포함된다. 만들고자 하는 게임에 AO가 필요한데

보통 많이보는 이런 것들.

실시간으로 AO 를 계산해서 멋진 그림자를 만들어낼 필요까지는 없는 경우라면 그냥 알베도에 AO를 미리 베이크해서 한장의 텍스쳐로 만들거나, AO 텍스쳐를 따로 받아서 뭘 할수도 있을것이다. 

3. 연산의 최적화.

float width = 12.7;
width = width/2.0;
float newsin = sin(33.21);
newsin *= 3.0;

이를 아래와 같이 바꿀 수 있다.

float width = 12.7/2.0;
float newsin = sin(33.21) * 3.0;

매번 다시 계산하지 않아도 결과가 다르지 않다면 가능한 줄이자.

#define PI 3.14159
#define HALF_PI 1.57079
#define TWO_PI 6.28318

변하지 않는 수치들은 미리 선언해두기. 아래와 같이 활용할 수도 있다.

Shader "Unlit/Red"
{
    Properties
    {
	}
		SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			static const fixed4 red = fixed4(1,0,0,1); //변하지 않는 색 빨간색

            struct appdata
            {
                float4 vertex : POSITION;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };
            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
				return red;
            }
            ENDCG
        }
    }
}

위의 결과로 만들어진 빨간 공이다.

4. 가능한 한 낮은 정확도의 단위를 사용하자.

모바일 환경이 아닌경우에는 크게 중요치않을 수 있지만, 모바일 환경이라면 이 부분 또한 잘 챙겨줄 필요가 있다.float , half, fixed 는 각자 다른 정확도, 즉 자릿수를 가지고 있다. float은 32비트, half는 16비트, fixed는 11비트의 정보량을 가진다. 당연히 굳이 큰 정밀도, 혹은 큰 수치가 필요하지 않은 곳에 힘을 쓸 필요는 없으므로, 결과값이 충분히 기대한 만큼 나온다면, 가능한 한 낮은 단위를 사용하는 것이 유리하다. float: 모든 숫자 / 월드 스페이스 포지션이나 복잡한 연산에 사용하자.half: -60.000 ~ + 60.000 / 수치가 크지않은 벡터, 오브젝트 스페이스 포지션, UV 등에 사용하자.fixed: -2.0 ~ +2.0 / 단순한 컬러, 각종 수치 등에 사용하자.유니티 도큐먼트에서는 일반적으로 텍스쳐 및 포지션에 관련된 수치가 아닌 경우 half를 사용할것을 권고하고있다. half에서 충분히 예상한 결과가 나오지 않을 경우 float을 사용하면 된다.

Unlit 셰이더를 기본으로 생성했을때 최종 Color 는 fixed4로 되어있다.

추가적으로 정수인 int가 있는데, 이를 지원하지 않는 경우가 존재하기 때문에 (Direct 9.x / OpenGL ES 2.0) 잘 확인하는 것이 좋을듯.관련 내용은 아래 유니티 도큐먼트에도 적혀 있다.

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

 

Unity - Manual: Shader data types and precision

Shader Compilation Target Levels Shader data types and precision The standard ShaderA built-in shader for rendering real-world objects such as stone, wood, glass, plastic and metal. Supports a wide range of shader types and combinations. More infoSee in Gl

docs.unity3d.com

5. 벡터를 곱하기 전에 스칼라값기리 먼저 연산해두자.

float height = 2.45;
float width = 1.22;
float3 world = float3(1, 3, 5);
float3 pos = height * (width * world);

위 코드에서는 float3 world 의 각 값에 1.22를 세번 곱한 후 나온 값에 다시 높이 2.45를 세번 곱하고있다.

float height = 2.45;
float width = 1.22;
float3 world = float3(1, 3, 5);
float3 pos = (height * width) * world;

이를 이렇게 바꾸면, height 와 width를 한 번만 계산하고 마지막으로 그것을 세 번 곱한다.

6. 동적 수치를 사용하는 분기를 줄이자.

보통 분기는 셰이더 성능에 큰 영향을 미친다. 다만 물론 분기도 분기 나름인데, 예를들면 셰이더 속성에있는 수치만 받아오는 등의 정적 분기 상황에서는 모든 픽셀이나 버텍스에 동일한 계산을 하기때문에 굉장히 나쁘지는 않다. (*유니티 공식 답변에 분기 자체에서 오버헤드가 발생한다고는 하나, 엄청난 정도의 성능 손실은 아닌 느낌으로 적혀있음.) 그런데 동적 분기의 경우 GPU는 분기로 달라지는 픽셀 / 버텍스당 계산을 전부 하고 이 과정에서 몇몇 계산은 손실이 일어난다. 다만 동적 분기도 이득인 상황이 존재하는데, 예를 들면 애초에 기본적으로 굉장히 무거운 셰이더를 하나 가정한다. 여기에 "만약 버텍스가 빛의 범위에서 벗어난 경우 연산하지 않는다." 라고 추가한다면 의미 있을 정도로 계산이 빠지게 될 것이다.위 문단의 유니티 답변 원문은 문서 하단에 첨부.

7. 여러 셰이더에 중복되는 연산, 수치는 미리 별도로 빼두자.

#ifndef shader
#define shader

fixed4 _Color;

struct input {

	float4 vertex : POSITION;
	half3 normal: NORMAL;
};

input vert(input v)
{
	input o;
	o.vertex = UnityObjectToClipPos(v.vertex);
	o.normal = v.normal;
	return o;
}
#endif

shader.cginclude

Input 도 공유하는 부분은 죄다 미리 넣어두고..

Shader "Unlit/Unlit_TestGreen"
{
	Properties
	{
		_Color("Color", Color) = (1,1,1,1)
	}
		SubShader
	{
		Tags { "RenderType" = "Opaque" }
		LOD 100

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"
			#include "Shader.cginc" //방금 만든 파일
			#define ADD //한 셰이더에는 넣고 한 셰이더에는 빼두었다

			fixed4 frag(input i) : COLOR
{
		fixed4 col = saturate(dot(i.normal, _WorldSpaceLightPos0)) * _Color;
		#ifdef ADD //색을 강제로 더해주도록 할 예정이다.
		col.rgb += 0.5;
		#endif
		return col;
		}

			ENDCG
		}
	}
}

초록 공룡에는 0.5가 더해져있고 빨강 공룡은 그렇지 않다.

8. 가능하면 한 면만 그리자.

특정 각도에서 퍼포먼스가 낮아지는 경우가 있다.

번역출처: https://www.bitshiftprogrammer.com/2018/11/shader-optimization-part-1.html

기타출처: https://forum.unity.com/threads/branches-how-expensive-are-they.152411/

            http://alextardif.com/UberShader.html

            https://docs.unity3d.com/2019.3/Documentation/Manual/OptimizingGraphicsPerformance.html

           https://forums.unrealengine.com/development-discussion/rendering/1425752-performance-cost-of-double-             sided-material-not-visible-in-stats

 

 

 

 

prev 1 2 3 next