Как преобразовать поверхностный шейдер в код вершины / фрагмента в Unity? - PullRequest
0 голосов
/ 08 мая 2018

Мне интересно, как я могу преобразовать этот код поверхностного шейдера в прагму Vertex / Fragment:

Shader "Custom/Diamond Opaque Test" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,1)
        _SpecColor ("Specular Color", Color) = (0.5,0.5,0.5,1)
        _Shininess ("Shininess", Range (0.01, 1)) = 0.078125
        _RimPower ("Rim Power", Range(0,8.0)) = 3.0
        _ReflectColor ("Reflection Color", Color) = (1,1,1,0.5)
        [NoScaleOffset] _Cube ("Cubemap", CUBE) = "" {}
    }

    SubShader {

        CGPROGRAM
        #pragma surface surf BlinnPhong

        struct Input {
            float3 worldRefl;
            float3 viewDir;
        };

        samplerCUBE _Cube;
        fixed4 _Color;
        fixed4 _ReflectColor;
        half _Shininess;
        half _RimPower;

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = _Color.rgb;
            o.Gloss = _Color.a;
            o.Specular = _Shininess;
            half rim = saturate(dot (normalize(IN.viewDir), o.Normal));
            o.Emission = texCUBE (_Cube, IN.worldRefl).rgb * _ReflectColor.rgb * pow(rim,_RimPower);;
        }
        ENDCG
    } 
    FallBack "Mobile/Diffuse"
}

Код шейдера выше - это красная жемчужина слева на картинке ниже:

no shadow

Моя цель - выглядеть так же, как камень справа. У меня есть несколько проблем на этом пути. Драгоценный камень слева непрозрачен и принимает тени. Драгоценный камень справа имеет прозрачность лицевой стороны, но не заднюю. Это, однако, не принимает тени. Мне нужно было сделать камень на летнем БлиннФонге, чтобы он мог отбрасывать и получать тени.

shadow

Можно ли создать разные элементы управления для прозрачности передней и задней граней? Также есть ли способ для прозрачных объектов принимать тени? Я хотел добавить очертания к драгоценному камню, чтобы его можно было увидеть дальше. Есть ли способ добавить контуры в один и тот же проход или у него должен быть свой отдельный проход? Кроме того, как вы можете затемнить полученную тень? Все ли эти требования облагают налогом ГПУ? Игра для мобильной платформы.

Я - новичок в программировании компьютерной графики. Мой первый шаг - понять программирование поверхности перевода в вершину / фрагмент. Любые примеры были бы чрезвычайно благодарны.

Я купил пару драгоценных активов в магазине активов, но некоторые из них могут отбрасывать тени, но не могут получать или не могут получать или вообще не получать. Что дает? Шейдер драгоценных камней справа находится в одном из приобретенных активов в магазине активов. Я не хочу делиться своими шейдерными скриптами на этом сайте без их разрешения.

1 Ответ

0 голосов
/ 28 декабря 2018

На самом деле это довольно сложный процесс, хотя я рекомендую начать с загрузки исходного кода Unity Shader с их сайта. Большая часть фактического затенения выполняется в UnityStandardBRDF.cginc, UnityPBSLighting.cginc и UnityStandardCore.cginc. Вы также можете найти эти файлы на GitHub, если вы их Google.

По сути, базовая структура шейдера с добавлением вперед выглядит следующим образом:

Shader "MyForwardAddShader"
{
    Properties
    {
        _MainTex("Some texture", 2D) = "white"{}
    }

    SubShader
    {
        Tags {"RenderType"="Geometry" "Queue" = "Geometry"}

        Pass 
        {
            // Forward Base pass - this applies main directional light and ambient
            Name "FORWARD"
            Tags { "LightMode" = "ForwardBase" }

            CGPROGRAM
            #pragma target 3.5

            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog
            #pragma multi_compile_instancing

            #pragma vertex vert
            #pragma fragment frag

            // I Like to keep these in separate include files
            #include "MyForwardBase.cginc"

            ENDCG
        }

        Pass
        {
            // Forward Add pass - this is added once per extra light source

            Name "FORWARD_DELTA"
            Tags { "LightMode" = "ForwardAdd" }
            Blend SrcAlpha One
            Fog { Color (0,0,0,0) } // in additive pass fog should be black
            ZWrite Off
            ZTest LEqual

            CGPROGRAM
            #pragma target 3.5

            #pragma multi_compile_fwdadd_fullshadows
            #pragma multi_compile_fog

            #pragma vertex vert
            #pragma fragment frag

            #include "MyForwardAdd.cginc"

            ENDCG
        }
    }
}

Обратите внимание, что вам также понадобится проход для заклинателя теней для отбрасывания теней (вы можете просто скопировать проход, использованный в исходном коде стандартного шейдера), а также проход Мета, если вы хотите использовать запеченное освещение.

Файл, подобный «MyForwardBase.cginc», должен содержать определения для структур ввода и вывода вершины, а также функции вершин и фрагментов для прохода. При такой настройке вам также необходимо определить униформу (переменные свойства). Некоторые переменные, которые могут вам понадобиться для легких расчетов:

// Calculate this in the vertex shader and normalize per fragment
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
float3 viewDir = _WorldSpaceCameraPos.xyz - o.worldPos;

// In the ForwardBase pass, _WorldSPaceLightPos0.xyz stores the direction of the main directional light, instead of position. 
// Use this in the vertex function:
half3 mainLightColor = _LightColor0.rgb;
half3 mainLightDir = _WorldSpaceLightPos0.xyz;

Для прохода ForwardBase вам необходимо включить «AutoLight.cginc» и использовать этот макрос в функции вершины:

COMPUTE_LIGHT_COORDS(o);

Что, в свою очередь, требует наличия этого макроса в структуре VertexOutput:

UNITY_LIGHTING_COORDS(6,7) // 6, 7 can be any texture interpolator IDs, they will translate to TEXCOORD6 and TEXCOORD7 in this case

ForwardAdd, ослабление света работает следующим образом:

UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos.xyz); // Here, worldPos is stored in the vertex output struct and calculated per vertex
half3 lightColor = _LightColor0.rgb * atten;

Существуют также макросы для определения, находится ли пиксель в тени, вы можете найти их в AutoLight.cginc. В проходе ForwardAdd направление света рассчитывается для каждой вершины следующим образом:

o.lightDir      = _WorldSpaceLightPos0.xyz - o.worldPos.xyz * _WorldSpaceLightPos0.w;

Лично мне нравится создавать небольшие CGInclude для каждой функции, такой как отражение, преломление, трипланарное отображение и т. Д., И просто включать их всякий раз, когда они мне нужны. Я также склонен хранить отдельную функцию под названием «Освещение» в своем собственном включаемом файле, поскольку расчеты освещения делятся между проходами. Эта функция принимает в качестве аргументов все переменные, такие как lightDir, viewDir, albedo, шероховатость и т. Д., И возвращает заштрихованный цвет фрагмента.

Как я уже сказал, это довольно сложный процесс, и это всего лишь учебник для начинающих. Реализация функции освещения - это отдельная история, хотя в этом может помочь просмотр UnityStandardBRDF.cginc. Я рекомендую вам начать с базовой модели blinn-phong для отладки и улучшить ее.

...