Unity 6.3
0 онлайн 118 гостей 3 в системе
Вход
Материалы и шейдеры Шаг 324 из 442

Примеры тесселяционных поверхностных шейдеров во встроенном Render Pipeline

В Built-in Render Pipeline, Shaders поверхности имеют некоторую поддержку для DirectX 11 / OpenGL Core GPU Tessellation.

  • Тесселяция обозначается модификатору tessellate:FunctionName. Эта функция вычисляет коэффициенты тесселяции рёбер треугольника и внутренней части треугольника.
  • Когда используется тесселяция, “вершинный модификатор” (vertex:FunctionName) вызывается после тесселяции, для каждой генерируемой вершины в домене шейдера. Здесь вы обычно будете отображать смещение.
  • Поверхностные шейдеры могут по желанию вычислять фонг-тесселяцию для гладкости поверхности модели даже без какого-либо отображения смещения.

Тесселяция и геометрия шейдеров

При написании собственных Shader программ, вы можете использовать полный набор возможностей DX11 shader model 5.0, включая геометрию, hull, и domain Shaders.

Текущие ограничения поддержки тесселяции:

  • Только треугольное доменное имя — нет квадов, нет изолиной тесселяции.
  • При использовании тесселяции, шейдер автоматически компилируется в Shader Model 4.6 target, что исключает поддержку работы на более старых графических целях.

Совместимость конвейера отображения

Название особенности Universal Render Pipeline (URP) High Definition Render Pipeline (HDRP) Изготовленный на заказ SRP Built-in Render Pipeline
Шейдеры поверхностей Нет

Упрощенный способ создания объектов Shader в URP см. в Shader Graph.
Нет

Упрощенный способ создания объектов Shader в HDRP см. в Shader Graph.
Нет Да

Фиксированное количество тесселяции

Если лица вашей модели имеют примерно одинаковые размеры на экране, добавьте фиксированное количество тесселяции в сетку (одинаковый уровень тесселяции по всей сетке).

Следующий пример скрипта применяет фиксированное количество тесселяции.

    Shader "Tessellation Sample" {
        Properties {
            _Tess ("Tessellation", Range(1,32)) = 4
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessFixed nolightmap
            #pragma target 4.6

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _Tess;

            float4 tessFixed()
            {
                return _Tess;
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

В вышеприведённом примере функция тесселляции tessFixed возвращает четыре фактора тесселляции в виде одного значения float4: три фактора для каждого края треугольника и один фактор для внутренней части треугольника.

Пример возвращает постоянное значение, которое установлено в свойствах Материал.

Постоянное количество тесселяции применяется к треугольникам.
Постоянное количество тесселяции применяется к треугольникам.

Расстояние-ориентированная тесселяция

Вы также можете изменить уровень тесселяции в зависимости от расстояния от камеры. Например, вы можете определить два значения расстояния:

  • Расстояние, на котором тесселяция максимальна (например, 10 метров).
  • Расстояние, на котором уровень тесселяции постепенно уменьшается (например, 20 метров).
    Shader "Tessellation Sample" {
        Properties {
            _Tess ("Tessellation", Range(1,32)) = 4
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessDistance nolightmap
            #pragma target 4.6
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _Tess;

            float4 tessDistance (appdata v0, appdata v1, appdata v2) {
                float minDist = 10.0;
                float maxDist = 25.0;
                return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, minDist, maxDist, _Tess);
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

Здесь функция тесселяции принимает вершинные данные трех углов треугольника до тесселяции в качестве своих трех параметров.

Unity требуется это для вычисления уровней тесселяции, которые зависят от положения вершин.

Пример включает в себя встроенный файл помощника, Tessellation.cginc, и вызывает функцию UnityDistanceBasedTess из файла, чтобы выполнить всю работу. Эта функция вычисляет расстояние каждой вершины до камеры и получает окончательные коэффициенты тесселяции.

Коэффициенты тесселяции зависят от расстояния каждой вершины от камеры.
Коэффициенты тесселяции зависят от расстояния каждой вершины от камеры.

Тесселяция на основе длины края

Чистое расстояние, основанное на тесселляции, эффективно только тогда, когда размеры треугольников довольно схожи. На изображении выше, GameObjects, которые имеют маленькие треугольники, слишком много тесселляции, в то время как GameObjects, которые имеют большие треугольники, недостаточно тесселляции.

Одним из способов улучшить это является вычисление уровней тесселяции на основе длины края треугольника на экране. Unity должен применять более высокий коэффициент тесселяции к длинным краям.

    Shader "Tessellation Sample" {
        Properties {
            _EdgeLength ("Edge length", Range(2,50)) = 15
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _DispTex ("Disp Texture", 2D) = "gray" {}
            _NormalMap ("Normalmap", 2D) = "bump" {}
            _Displacement ("Displacement", Range(0, 1.0)) = 0.3
            _Color ("Color", color) = (1,1,1,0)
            _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessEdge nolightmap
            #pragma target 4.6
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            float _EdgeLength;

            float4 tessEdge (appdata v0, appdata v1, appdata v2)
            {
                return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
            }

            sampler2D _DispTex;
            float _Displacement;

            void disp (inout appdata v)
            {
                float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
                v.vertex.xyz += v.normal * d;
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;
            sampler2D _NormalMap;
            fixed4 _Color;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Specular = 0.2;
                o.Gloss = 1.0;
                o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
            }
            ENDCG
        }
        FallBack "Diffuse"
    }

В этом примере вы вызываете функцию UnityEdgeLengthBasedTess из Tessellation.cginc для выполнения всей работы.

Коэффициенты тесселяции зависят от длины края треугольника на экране. Unity применяет более высокий коэффициент тесселяции к длинным краям.
Коэффициенты тесселяции зависят от длины края треугольника на экране. Unity применяет более высокий коэффициент тесселяции к длинным краям.

По соображениям производительности, вместо этого вызовите функцию UnityEdgeLengthBasedTessCull, которая выполняет вычеркивание фрустумов патча. Это делает шейдер немного дороже, но экономит много работы GPU для частей мешей, которые находятся вне поля зрения Camera.

Тесселяция Фонга

Тесселяция Пхонга изменяет позиции разделённых поверхностей, так что получаемая поверхность немного следует за нормалями меши. Это довольно эффективный способ сделать меши с низким количеством поли более гладкими.

Поверхностные шейдеры Unity могут автоматически вычислять тесселляцию Phong с помощью компиляционной директивы tessphong:VariableName. Вот пример шейдера:

    Shader "Phong Tessellation" {
        Properties {
            _EdgeLength ("Edge length", Range(2,50)) = 5
            _Phong ("Phong Strengh", Range(0,1)) = 0.5
            _MainTex ("Base (RGB)", 2D) = "white" {}
            _Color ("Color", color) = (1,1,1,0)
        }
        SubShader {
            Tags { "RenderType"="Opaque" }
            LOD 300
            
            CGPROGRAM
            #pragma surface surf Lambert vertex:dispNone tessellate:tessEdge tessphong:_Phong nolightmap
            #include "Tessellation.cginc"

            struct appdata {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float2 texcoord : TEXCOORD0;
            };

            void dispNone (inout appdata v) { }

            float _Phong;
            float _EdgeLength;

            float4 tessEdge (appdata v0, appdata v1, appdata v2)
            {
                return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
            }

            struct Input {
                float2 uv_MainTex;
            };

            fixed4 _Color;
            sampler2D _MainTex;

            void surf (Input IN, inout SurfaceOutput o) {
                half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
                o.Albedo = c.rgb;
                o.Alpha = c.a;
            }

            ENDCG
        }
        FallBack "Diffuse"
    }

Вот сравнение между обычным шейдером (верхний ряд) и тем, который использует Phong tessellation (нижний ряд). Посмотрите, что даже без какого-либо отображения смещения поверхность становится более круглой.

Верхняя строка изображения: шейдер без тесселяции. Нижняя строка изображения: шейдер с тесселяцией Phong.
Верхняя строка изображения: шейдер без тесселяции. Нижняя строка изображения: шейдер с тесселяцией Phong.