카메라의 깊이 텍스처
쉐이더 LOD(Shader Level of Detail)

플랫폼 별 렌더링 차이

Unity는 다양한 플랫폼에서 동작하며, 몇 가지 경우에서는 동작에 차이가 나옵니다. 대부분의 경우, Unity는 차이를 숨겨 주지만 그래도 다시 표면화되는 경우가 있습니다.

Render Texture 좌표

수직 텍스처 좌표의 표현 방법은 Direct3D와 OpenGL 유사 플랫폼 간에 차이가 있습니다:

  • Direct3D와 Metal에서는 상단이 제로의 좌표 위치가 되며, 아래쪽으로 갈수록 증가합니다.
  • OpenGL과 OpenGL ES는 하단이 제로의 좌표 위치가 되며, 위쪽으로 갈수록 증가합니다.

대부분의 경우에 영향은 없지만, Render Texture에 렌더링하는 경우, 영향이 있습니다. 이 경우 Unity는 Direct3D에서 렌더링 할 때 의도적으로 렌더링을 거꾸로 반전하기 때문에 플랫폼 사이의 규칙은 그대로 유지됩니다.

Image Effects, upside-down RenderTextures, and MSAA

이 반전이 실행되지 않는 경우는 Image Effects 및 안티 앨리어싱이 사용되는 경우입니다. 이 경우 Unty가 안티 앨리어싱하여 이후 이미지 효과를 처리하기 위해 Render Texture에 대해 렌더링을 합니다. 결과 이미지 효과 소스 텍스처는 Direct3D에서 상하반전이 되지 않습니다 (다른 Render Texture와 달리).

만약 이미지 효과가 간단한 경우(하나의 텍스처를 한번만 처리하는), Graphics.Blit이 처리하기 때문에, 이것을 신경 쓸 필요는 없습니다.

그러나 이미지 효과로 한개 이상의 Render Texture 처리하는 경우 , 각각 다른 수직 방향으로 출력됩니다( Direct3D와 같은 플랫폼이면서 안티 앨리어싱이 사용되는 경우만). 정점 쉐이더에서 수동으로 화면 텍스처를 거꾸로 “반전”해야 합니다.

// On non-GL when AA is used, the main texture and scene depth texture
// will come out in different vertical orientations.
// So flip sampling of the texture when that is the case (main texture
// texel size will have negative Y).

#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
        uv.y = 1-uv.y;
#endif

Shader Replacement 샘플 프로젝트로 엣지 검출을 하고 있는 씬을 확인하시기 바랍니다. 여기에서 엣지 검출은 씬의 텍스처와 카메라 깊이 및 법선 텍스처 모두에서 사용되고 있습니다.

Rendering in UV space

When rendering in texture coordinate (UV) space for special effects or tools, you might need to adjust your shaders so that the rendering is consistent between D3D-like and OpenGL-like systems, and between rendering into the screen vs. rendering into a texture. The built-in variable _ProjectionParams.x contains a +1 or –1 value which indicates whether projection has been flipped upside down or not. You can check this value in your shaders if you need to do different things based on this.

float4 vert(float2 uv : TEXCOORD0) : SV_POSITION
{
    float4 pos;
    pos.xy = uv;
    // we're rendering with upside-down flipped projection,
    // so flip the vertical UV coordinate too
    if (_ProjectionParams.x < 0)
        pos.y = 1 - pos.y;
    pos.z = 0;
    pos.w = 1;
    return pos;
}

Clip space coordinate differences

수직 텍스처 좌표의 표현 방법은 Direct3D와 OpenGL 유사 플랫폼 간에 차이가 있습니다:

  • Direct3D와 Metal에서는 상단이 제로의 좌표 위치가 되며, 아래쪽으로 갈수록 증가합니다.
  • OpenGL과 OpenGL ES는 하단이 제로의 좌표 위치가 되며, 위쪽으로 갈수록 증가합니다.

Inside shader code, you can use UNITY_NEAR_CLIP_VALUE macro to get the near plane value based on platform.

Inside script code, GL.GetGPUProjectionMatrix can be used to convert from Unity’s coordinate system (which follows OpenGL conventions) to what the platform expects.

Precision of shader computations

PC GPUs treat all floating point types (float, half and fixed) as the same, and do all calculations using full 32 bit precision. Many mobile GPUs do not do this, so make sure to test your shaders on the target platform to avoid precision issues. See the data types and precision page for details.

Similarly, all samplers/textures declared in shader code default to “low precision”. This does not matter for PC GPUs, but on some mobile GPUs you might want to use sampler2D_half (declares half-precision texture), sampler2D_float (full precision texture) etc.

Const declarations in shaders

In HLSL const has much the same meaning as it does in C# and C++, such that the variable declared is read-only within its scope, but can be initialised in any way.

In GLSL however, const means that the variable is effectively a compile time constant, and so must be initialised with compile time constants - either literal values, or calculations on other constants.

It is best to follow the GLSL semantics and only declare a variable as const when it is truly invariant, and avoid initialising a const variable with some other mutable values e.g. as a local variable in a function. This will work just fine in HLSL and avoid confusing errors on only some platforms.

Const declarations in shaders

In HLSL const has much the same meaning as it does in C# and C++, such that the variable declared is read-only within its scope, but can be initialised in any way.

In GLSL however, const means that the variable is effectively a compile time constant, and so must be initialised with compile time constants - either literal values, or calculations on other constants.

It is best to follow the GLSL semantics and only declare a variable as const when it is truly invariant, and avoid initialising a const variable with some other mutable values e.g. as a local variable in a function. This will work just fine in HLSL and avoid confusing errors on only some platforms.

Semantics used by shaders

To get shaders working on all platforms, some special shader values should use these semantics:

  • Vertex shader output (clip space) position: SV_POSITION. Sometimes shaders use POSITION semantics for that, but this does not not work on Sony PS4 or when tessellation is used.
  • Fragment shader output color: SV_Target. Sometimes shaders use COLOR or COLOR0 for that, but again this does not work on PS4.

When rendering meshes as Points, make sure to output PSIZE semantics from the vertex shader (for example, set it to 1). Some platforms, such as OpenGL ES or Metal, treat point size as “undefined” when it’s not written to from the shader.

See the shader semantics page for more details.

Direct3D 9/11 쉐이더 컴파일러는 문법에 더 까다로움

Direct3D 기반 플랫폼들은 Microsoft의 HLSL 쉐이더 컴파일러를 사용합니다. HLSL 컴파일러는 다양한 곳에서 쉐이더의 약간의 오류에 대해 약간 엄격합니다. 예를 들어, 올바르게 초기화되지 않은 함수의 출력 값이 있으면 수락하지 않습니다.

가장 일반적으로 실행 하는 곳은 :

  • “out” 파라메터를 가지고 있는 Surface shader 정점 모디파이어의 경우. 다음과 같이 반드시 출력을 초기화하도록 하십시오 :
      void vert (inout appdata_full v, out Input o) 
      {
        **UNITY_INITIALIZE_OUTPUT(Input,o);**
        // ...
      }
  • 부분적으로 초기화 된 값, 예를 들면 float4를 반환하는 함수가 있지만, 코드가 .xyz만 리턴된 경우. 모든 값을 리턴하거나 세개의 값만 필요 한경우 float3로 변경합니다.
  • tex2D를 정점 쉐이더에서 사용할 때. 정점 쉐이더에서 UV 파생물이 존재하지 않기 때문에 유효하지 않습니다. 대신 명시적으로 밉 레벨의 샘플링을 추가해야 하며, 예를 들어 tex2Dlod (tex, float4(uv,0,0))를 사용합니다. 쉐이더 모델 3.0에서 제대로 작동하기 위해서는#pragma target 3.0을 추가해야 합니다.

DirectX 11 HLSL 문법 및 표면 쉐이더

현재 표면 쉐이더의 일부 컴파일 파이프 라인에서는 DirectX 11 특유의 HLSL 문법이 해석되지 않습니다. 만약 StructuredBuffers, RWTextures 및 기타 비 DirectX 9 문법의 HLSL 기능을 사용하는 경우, DirectX 11 전용 프리프로세서 매크로에 래핑해야 합니다 :

#ifdef SHADER_API_D3D11
// DX11-specific code, e.g.
StructuredBuffer<float4> myColors;
RWTexture2D<float4> myRandomWriteTexture;
#endif

Using Shader Framebuffer Fetch

Some GPUs (most notably PowerVR based ones on iOS) allow you to do a form of programmable blending by providing current fragment color as input to the fragment shader (see EXT_shader_framebuffer_fetch).

It is possible to write shaders in Unity that use the framebuffer fetch functionality. When writing HLSL/Cg fragment shader, simply use the inout color argument in it. For example:

CGPROGRAM
// only compile shader for platforms that can potentially
// do it (currently gles,gles3,metal)
#pragma only_renderers framebufferfetch

void frag (v2f i, inout half4 ocol : SV_Target)
{
    // ocol can be read (current framebuffer color)
    // and written into (will change color to that one)
    // ...
}   
ENDCG
카메라의 깊이 텍스처
쉐이더 LOD(Shader Level of Detail)