Unity着色器shader开发知识
阅读原文时间:2021年04月25日阅读:1

简介


着色器

什么是着色器
着色器是通过代码来模拟物体表面在微观等级上发生的事情,使得我们眼睛看到的最终图像感觉很真实。换个层面讲,着色器是运行在 GPU 上的一段代码。

渲染是透视绘图
绘图过程可以分为:勾勒轮廓阶段、绘图阶段

固定函数渲染管线、可编程渲染管线

着色器的类型
1、顶点着色器—vertex shader:在每个顶点上执行的着色器
2、片元着色器—fragment shader:在每个最终图像中可能出现的像素上的着色器
3、无光照着色器—unlit shader:将 vertex 和 pixel 着色器放在一个文件内
4、表面着色器—surface shader:包含 vertex 和 fragment 着色器的功能。
5、图像特效着色器—image-effect shader:实现屏幕特效,诸如抗锯齿、环境光遮蔽、模糊、溢光等。
6、计算着色器—compute shader:进行一些计算的着色器,实现诸如物理模拟、图像处理、光线追踪等。

坐标系统
每个着色器中的计算都是在特定的坐标系统下面进行的。Shader中的坐标系统主要有如下几个:
1、本地空间(对象空间):指的是带渲染模型的相对坐标系。
2、世界空间:指的是整个带渲染场景的坐标系。
3、视图空间:从观察者(相机)的视角来看的相应的坐标系。
4、剪裁空间:范围从-1.0到1.0
5、屏幕空间:二维的坐标系统
6、切线空间:用来计算法线贴图
在着色器中,经常性地需要从一个坐标空间转换到另一个坐标空间,选择合适的坐标空间将会减少这些转换操作,从而使得计算更加方便,渲染更加快速。

光源类型
Unity中有以下几种光源类型:
1、点光源:一个点向周围相等地发射光,强度随距离衰减
2、方向光源(平行光源):发出的每条光线都是平行的,没有强度衰减
3、区域光源(面光源):只能在烘焙的时候使用,光从一个区域内发出。

渲染类型
前向渲染:在前向渲染中,场景的信息输入到渲染器中,每个三角面都被光栅化,对应每个光源都有一个着色通道。
延迟渲染:将光照/渲染计算推迟到第二步进行计算。我们这样做的目的是为了避免多次(超过1次)渲染同一个像素。


第一个Unity着色器

定义颜色

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            fixed4 _Color;

            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 _Color;
            }
            ENDCG
        }
    }
}

图形管线

图形API:
OpenGL
Metal
Vulkan
Direct3D

图形管线(渲染管线)通用结构:

栅格化器

无光照着色器的结构

数据流:

顶点数据结构体:

struct appdata
            {
                float4 vertex : POSITION;
            };

顶点函数:

v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                return o;
            }

片元数据结构体:

struct v2f
            {
                float4 vertex : SV_POSITION;
            };

片元函数:

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

添加顶点颜色支持:

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

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            fixed4 _Color;


            struct appdata
            {
                float4 vertex : POSITION;
                float4 color : COLOR;
            };

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float4 color : COLOR;
            };



            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.color = v.color;
                return o;
            }

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

坐标空间变换

对象空间(Object Space)
世界空间(World Space)
相机空间(Camera Space)
剪裁空间(Clip Space)
标准化设备坐标(Normalized Device Space)
屏幕空间(Screen Space)


第一个Unity光照着色器

漫反射(Diffuse)
镜面反射(Specular)
环境光(Ambient)

计算基本光照_漫反射部分

实现漫反射
添加纹理属性
添加环境光

Shader "Unlit/DiffuseShader"
{
    Properties
    {
        _Color("_Color", Color) =  (1,0,0,1)
        _DiffuseTex("Texture", 2D) = "white"{}
        _Ambient("Ambient", Range(0, 1))= 0.25
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"

            fixed4 _Color;
            sampler2D _DiffuseTex;
            float4 _DiffuseTex_ST;
            float _Ambient;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD1;
                float2 uv : TEXCOORD0;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldNormal = worldNormal;
                o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 normalDirection = normalize(i.worldNormal);
                float4 tex = tex2D(_DiffuseTex, i.uv);
                float nl = max(_Ambient, dot(normalDirection, _WorldSpaceLightPos0.xyz));
                float4 diffuseTerm = nl * _Color * tex * _LightColor0;
                return diffuseTerm;
            }
            ENDCG
        }
    }
}

实现镜面反射



在之前漫反射的基础上,增加镜面反射

Shader "Custom/SpecularShader"
{
    Properties
    {
        _Color("_Color", Color) =  (1,0,0,1)
        _DiffuseTex("Texture", 2D) = "white"{}
        _Ambient("Ambient", Range(0, 1))= 0.25
        _SpecColor("Specular Material Color", Color) = (1,1,1,1)
        _Shininess("Shininess", Float) = 10
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            #include "UnityLightingCommon.cginc"

            fixed4 _Color;

            sampler2D _DiffuseTex;
            float4 _DiffuseTex_ST;

            float _Ambient;

            float _Shininess;

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 worldNormal : TEXCOORD1;
                float2 uv : TEXCOORD0;
                float4 vertexWorld : TEXCOORD2;
            };



            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.vertexWorld = mul(unity_ObjectToWorld, v.vertex);
                float3 worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldNormal = worldNormal;
                o.uv = TRANSFORM_TEX(v.uv, _DiffuseTex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                float3 normalDirection = normalize(i.worldNormal);
                float3 viewDirecttion = normalize(UnityWorldSpaceViewDir(i.vertexWorld));
                float3 lightDirection = normalize(UnityWorldSpaceLightDir(i.vertexWorld));
                //采样纹理
                float4 tex = tex2D(_DiffuseTex, i.uv);
                //漫反射计算
                float nl = max(_Ambient, dot(normalDirection, _WorldSpaceLightPos0.xyz));
                float4 diffuseTerm = nl * _Color * tex * _LightColor0;
                //镜面反射计算
                float3 reflectionDirection = reflect(-lightDirection, normalDirection);
                float3 specularDot = max(0.0, dot(viewDirecttion, reflectionDirection));
                float3 specular = pow(specularDot, _Shininess);
                float4 specularTerm = float4(specular, 1) * _SpecColor * _LightColor0;
                //计算最终颜色
                float4 finalColor = diffuseTerm +specularTerm;
                return finalColor;
            }
            ENDCG
        }
    }
}

支持多个光源

Tags { "RenderType"="Opaque" "LightMode" = "ForwardBase"}
            LOD 100

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

另一个pass

Tags { "RenderType"="Opaque" "LightMode" = "ForwardAdd"}
            Blend one one 
            LOD 100

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdadd

表面着色器

光照模型/光照函数 Light.cginc

表面着色器的数据流

编辑表面着色器
添加第二个Albedo纹理

Shader "Custom/SurfaceShaderSecondAlbedo" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}

        _SeconeAlbedo ("Second Albedo (RGB)", 2D) = "white" {}
        _AlbedoLerp("Albedo Lerp", Range(0,1)) = 0.5

        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        sampler2D _SeconeAlbedo;
        half _AlbedoLerp;


        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex);

            fixed4 seconeAlbedo = tex2D (_SeconeAlbedo, IN.uv_MainTex);         
            o.Albedo = lerp(c, seconeAlbedo, _AlbedoLerp) * _Color;

            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

添加法线纹理

属性中添加

_NormalMap("Normal Map", 2D) = "bump" {}

函数中设定

o.Normal = UnpackNormal(tex2D (_NormalMap, IN.uv_MainTex));

使用不同的内置光照模型

Shader "Custom/SurfaceShaderSecondModel" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}

        _SpecColor("Specular Material Color", Color) = (1,1,1,1)
        _Shininess("Shininess", Range(0.03, 1)) = 0.07
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf BlinnPhong fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        float _Shininess;

        struct Input {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutput o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Gloss = c.a;
            o.Specular =_Shininess;
            o.Alpha = 1.0;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

自定义光照模型

光照模型函数签名


SurfaceOutput 数据结构体

Shader "Custom/SurfaceShaderCustomModel" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}

        _SpecColor("Specular Material Color", Color) = (1,1,1,1)
        _Shininess("Shininess", Range(0.03, 128)) = 0.07
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Phong fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        float _Shininess;

        struct Input {
            float2 uv_MainTex;
        };

        fixed4 _Color;

        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutput o) {

            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Alpha = 1.0f;
        }

        inline fixed4 LightingPhong(SurfaceOutput s, half viewDir, UnityGI gi){
            UnityLight light = gi.light;
            float nl = max(0.0f, dot(s.Normal, light.dir));         
            float3 diffuseTerm = nl * s.Albedo.rgb * light.color;

            float3 reflectionDirection = reflect(-light.dir, s.Normal);
            float specularDot = max(0.0, dot(viewDir, reflectionDirection));
            float specular = pow(specularDot, _Shininess);
            float3 specularTerm = specular * _SpecColor.rgb * light.color.rgb;

            float3 finalColor = diffuseTerm.rgb + specularTerm;

            fixed4 c;
            c.rgb = finalColor;
            c.a = s.Alpha;

            #ifdef UNITY_LIGHT_FUNCTION_APPLY_INDIRECT
            c.rgb += s.Albedo * gi.indirect.diffuse;
            #endif

            return c;
        }

        inline void LightingPhong_GI(SurfaceOutput s, UnityGIInput data, inout UnityGI gi){
            gi = UnityGlobalIllumination(data, 1.0, s.Normal);
        }

        ENDCG
    }
    FallBack "Diffuse"
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章