計(jì)算機(jī)圖形學(xué)與Shader

一、計(jì)算機(jī)圖形學(xué)

1. 概述

  1. Unity的代碼在CPU中運(yùn)行,圖形學(xué)的代碼在GPU中運(yùn)行
  2. 圖形學(xué)使用CG(C Graph)語(yǔ)言,是英偉達(dá)和微軟聯(lián)合開(kāi)發(fā)的跨平臺(tái)語(yǔ)言
  3. 操作系統(tǒng)中的圖形處理軟件DX12,使用GLSL(OpenGL Shading Language)、DX語(yǔ)言
  4. shader 1.0實(shí)現(xiàn)的功能很少,更像設(shè)置參數(shù);shader 2.0,為開(kāi)發(fā)者留下了開(kāi)發(fā)接口,可以進(jìn)行可編程式的開(kāi)發(fā);Unity的shader,表面著色器,介于1.0和2.0之間,翻譯成2.0然后發(fā)給GPU
  5. shader 1.0 :固定管線著色器、shader 2.0:頂點(diǎn)片段著色器、Unity shader:表面著色器
  6. shader:著色器,使用紋理、數(shù)據(jù)、顏色等原材料,通過(guò)編程的方式進(jìn)行一些邏輯運(yùn)算,設(shè)置到材質(zhì)球上
  7. 寫(xiě)shader,要使用的原材料盡量可以變化,適應(yīng)多種平臺(tái)多種需求

2. 渲染繪圖管線

  • 圖像從GPU里的體現(xiàn)過(guò)程:一個(gè)個(gè)頂點(diǎn)連線,組成三角形作為面,由面拼成一個(gè)圖形。
  • 繪圖流程:頂點(diǎn)處理、面處理、光柵化、像素處理

2.1 頂點(diǎn)處理

頂點(diǎn)處理就是坐標(biāo)轉(zhuǎn)換,將物體的本地坐標(biāo)最終轉(zhuǎn)換成屏幕坐標(biāo)

  • 坐標(biāo)按這四種坐標(biāo)系的順序進(jìn)行轉(zhuǎn)換:本地坐標(biāo),世界坐標(biāo),觀察坐標(biāo)系,投影坐標(biāo)系
  • unity中拼合的頂點(diǎn)分開(kāi)算頂點(diǎn),例如一個(gè)Cube有4 * 6 = 24個(gè)頂點(diǎn)

2.2 面的處理

  1. 面組裝:將頂點(diǎn)處理得到的點(diǎn)集合進(jìn)行處理,把點(diǎn)連成面
  2. 面截?。哼B成面之后,判斷哪些在屏幕范圍,將這些面截取
  3. 面剔除:面截取后,判斷哪些面會(huì)被別的面擋住,顯示不出來(lái),將這些面剔除

2.3 光柵化

  • 將面處理得到的面轉(zhuǎn)換成一個(gè)個(gè)像素,稱為光柵化
  • 邊緣鋸齒等問(wèn)題出在這步

2.4 像素處理

輸入像素的位置、深度、貼圖坐標(biāo)、法線、切線、顏色等,給像素著色,使用四通道RGBA

2.5 shader各版本能做的事情

  • shader 1.0:像素處理
  • shader 2.0:像素處理、頂點(diǎn)處理

3. 固定管線著色器(Fixed Shader、Shader 1.0)

每有一個(gè)像素,就執(zhí)行一次

3.1 結(jié)構(gòu)

// Shader關(guān)鍵字 路徑
Shader "AShader/FixedShader/Base001"{
    // 屬性模塊
    Properties
    {
    
    }
    
    // 子著色器,可以有多個(gè),作用是面對(duì)不同的設(shè)備,從上到下做嘗試
    // 質(zhì)量高,渲染效果好的,性能消耗大的
    SubShader
    {
        // 通道1
        Pass
        {
            
        }
        
        // 通道2
        Pass
        {
            
        }
    }
    
    // 中等質(zhì)量
    SubShader
    {
        Pass
        {
            
        }
    }
    
    // 質(zhì)量差
    SubShader
    {
        Pass
        {
            
        }
    }
    
    // 最基礎(chǔ)的,Unity 4.x 預(yù)設(shè)的漫反射
    Fallback "Diffuse"
}

3.2 屬性

Properties
{
    // 屬性定義語(yǔ)法:屬性名("面板顯示名稱",屬性類(lèi)型) = 初值
    
    // 浮點(diǎn)型(使用較少)
    _FloatValue("浮點(diǎn)數(shù)", float) = 0.5
    // 范圍浮點(diǎn)型(常用)
    _RangeValue("范圍浮點(diǎn)數(shù)", Range(0, 100)) = 30
    // 四維數(shù) (x, y, z, w) (使用較少)
    _VectorValue("四維數(shù)", Vector) = (1, 1, 1, 1)
    // 顏色,范圍[0 - 1](常用)
    _ColorValue("顏色值", Color) = (1, 0, 0, 1)
    // 2階貼圖,材質(zhì)的長(zhǎng)寬是2的多少次冪 2x2 4x4 8x8 16x16(常用)
    // Tiling x, y :平鋪
    // Offset x, y :起始位置
    _MainTexture("主紋理", 2D) = ""{}
    // 非2階貼圖(使用較少)
    _RectTexture("非2階紋理", Rect) = ""{}
    // 立方體貼圖 6個(gè)紋理,每個(gè)紋理表示一個(gè)面(使用很少)
    _CubeTexture("3D紋理", Cube) = ""{}
}

3.3 命令

  • Tag命令
    寫(xiě)在SubShader中
// 標(biāo)簽
Tags
{
    // 渲染隊(duì)列,數(shù)字越小越先渲染,數(shù)字大的會(huì)擋住數(shù)字小的
    // 隊(duì)列在賦值的時(shí)候可以使用運(yùn)算,但是是字符串賦值,所以+號(hào)左右不能有空格
    "Queue" = "Transparent+1"
}

預(yù)設(shè)的四種渲染隊(duì)列級(jí)別

級(jí)別 翻譯 代表數(shù)字
Background 后臺(tái) 1000
Geometry(默認(rèn)) 幾何體 2000
Transparent 透明 3000
Overlay 覆蓋 4000
  • 渲染命令
    寫(xiě)在Pass(通道)中
命令 作用
Color(r, g, b, a) 用指定顏色渲染
Color[Color] 用屬性顏色渲染
Lighting On/Off 開(kāi)啟/關(guān)閉頂點(diǎn)光照
Cull Front/Back/Off 剔除正面/剔除背面/關(guān)閉剔除
ZWrite On/Off(默認(rèn)為On) 是否要將像素的深度寫(xiě)入深度緩存中
ZTest Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off(默認(rèn)為L(zhǎng)Equal) 通過(guò)比較深度來(lái)更改深度緩存的值,Always指的是直接將當(dāng)前像素顏色(不是深度)寫(xiě)進(jìn)顏色緩沖區(qū)中,Never指的是永遠(yuǎn)不會(huì)將當(dāng)前像素顏色寫(xiě)進(jìn)顏色緩沖區(qū)中,相當(dāng)于消失,Off指的是關(guān)閉深度測(cè)試
SeparateSpecular On/Off 鏡面反射開(kāi)啟/關(guān)閉

利用渲染隊(duì)列修改顯示順序

Shader "AShader/FixedShader/Fixed003"
{
    Properties
    {
        _MainColor("主顏色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {

        // 標(biāo)簽
        Tags
        {
            // 渲染隊(duì)列
            "Queue" = "Transparent+1"
        }

        Pass
        {
            // 關(guān)閉深度測(cè)試
            ZTest Off

            Lighting On

            Material
            {
                Diffuse[_MainColor]
            }
        }
    }
}
  • 透明混合命令
命令 作用
Blend SrcAlpha OneMinusSrcAlpha 透明混合,有時(shí)候后面的東西會(huì)消失,不穩(wěn)定,基本不在shader 1.0中使用
Blend One One 相加,主顏色更亮
Blend One OneMinusDstColor 更柔和的相加
Blend DstColor Zero 相乘
Blend DstColor SrcColor 2倍乘法
Shader "AShader/FixedShader/Fixed009"{

    Properties
    {
        _MainTexture("主紋理", 2D) = ""{}

    }

    SubShader
    {
        // 透明混合
        //Blend SrcAlpha OneMinusSrcAlpha
        //Blend One One
        //Blend One OneMinusDstColor
        //Blend DstColor Zero
        Blend DstColor SrcColor

        Pass
        {
            SetTexture[_MainTexture]
            {
                combine texture
            }
        }
    }
}
  • Alpha測(cè)試命令
命令 作用
AlphaTest Off 關(guān)閉
AlphaTest Greater 大于
AlphaTest GEqual 大于等于
AlphaTest Less 小于
AlphaTest LEqual 小于等于
AlphaTest Equal 等于
AlphaTest NotEqual 不等于
AlphaTest Always 渲染所有像素
AlphaTest Never 不渲染任何像素
Shader "AShader/FixedShader/Fixed008"{

    Properties
    {
        _AlphaTest("透明測(cè)試", Range(0, 1)) = 1

        _MainTexture("主紋理", 2D) = ""{}
    }

    SubShader
    {
        Pass
        {
            // 溶解效果
            AlphaTest Greater [_AlphaTest]

            SetTexture[_MainTexture]
            {
                combine texture
            }
        }
    }
}
  • Material 材質(zhì)命令
    寫(xiě)在Pass -> Material中
命令 作用
Diffuse[Color] 漫反射顏色
Ambient[Color] 環(huán)境光反射顏色
Shininess[float] 光澤度
Specular[Color] 高光顏色
Emission[Color] 自發(fā)光顏色
Shader "AShader/FixedShader/Fixed006"{

    Properties
    {
        _MainColor("主顏色", Color) = (1, 1, 1, 1)
        _SpecularColor("高光顏色", Color) = (1, 1, 1 ,1)
        _Shininess("光澤度", Range(0.1, 1)) = 0.5
        _Ambient("環(huán)境光顏色", Color) = (1, 1, 1, 1)
        _Emission("自發(fā)光顏色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            Color[_MainColor]
            Lighting On
            SeparateSpecular On
            Material
            {
                Diffuse[_MainColor]
                Specular[_SpecularColor]
                Shininess[_Shininess]
                Ambient[_AmbientColor]
                Emission[_EmissionColor]
            }
        }
    }
}
  • Texture 紋理命令
    紋理命令寫(xiě)在Pass中,紋理命令不區(qū)分大小寫(xiě)
SetTexture[Texture]
{
    // 定義constantColor
    constantColor(r, g, b, a)
    constantColor[Color]
    // 合并命令
    // 因?yàn)镽GBA的值范圍是[0 - 1],所以 + 更趨向于(1, 1, 1, 1)(白色)更亮,* 更趨向于(0, 0, 0, 0)(黑色)更暗
    combine src1 + src2
    combine src1 * src2
    
    // -src 為補(bǔ)色
    combine src1 - src2
    // 使用src2的透明通道值在src1和src3之間取插值,插值是反向的,透明度為0的時(shí)候取src3,透明度為1的時(shí)候取src1
    combine src1 lerp(src2) src3
}
源類(lèi)型(src) 描述
primary 來(lái)自光照計(jì)算的顏色或是當(dāng)它綁定時(shí)的頂點(diǎn)顏色
texture 在SetTexture中定義的紋理的顏色
previous 上一次SetTexture的結(jié)果
constant 被constantColor定義的顏色
  • 兩張紋理圖漸變切換

Fixed007.shader

Shader "AShader/FixedShader/Fixed007"{

    Properties
    {
        _LerpScale("插值比例", Range(0, 1)) = 1
        _MainTexture("主紋理", 2D) = ""{}
        _DetailTexture("細(xì)節(jié)紋理", 2D) = ""{}
    }

    SubShader
    {
        Pass
        {
            SetTexture[_MainTexture]
            {
                constantColor(1, 0, 0, 0)
            }

            SetTexture[_DetailTexture]
            {
                constantColor(1, 1, 1, [_LerpScale])

                combine texture lerp(constant) previous
            }
        }
    }
}

SkinLerp.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkinLerp : MonoBehaviour 
{
    // 拿到meshRenderer
    private MeshRenderer _meshRenderer;
    // 當(dāng)前的lerpScale
    private float lerpScale;
    // 目標(biāo)lerpScale
    private float targetScale;

    private void Awake()
    {
        _meshRenderer = GetComponent<MeshRenderer>();
    }

    private void Update()
    {
        // 取插值
        lerpScale = Mathf.Lerp(lerpScale, targetScale, Time.deltaTime * 2);
        // 0 - 1 之間來(lái)回切換
        if (Mathf.Abs(lerpScale - targetScale) < 0.05)
            targetScale = (targetScale == 0) ? 1 : 0;

        // 使用代碼控制
        // name : 屬性名
        // value : 值
        _meshRenderer.material.SetFloat("_LerpScale", lerpScale);

        // 修改Offset使圖片動(dòng)起來(lái)
        _meshRenderer.material.SetTextureOffset("_MainTexture", new Vector2(Time.time, 0));
        _meshRenderer.material.SetTextureOffset("_DetailTexture", new Vector2(-Time.time, 0));

    }
}

4. 表面著色器(Surface Shader)

4.1 CG語(yǔ)言

  • 基本數(shù)據(jù)類(lèi)型(所有的數(shù)據(jù)類(lèi)型后面都可以加數(shù)字,表示多個(gè)該類(lèi)型的,類(lèi)似Vector)

    • float:32位 浮點(diǎn)數(shù)
      • float2:2個(gè)浮點(diǎn)數(shù)
      • float3:3個(gè)浮點(diǎn)數(shù)
      • float4:4個(gè)浮點(diǎn)數(shù)
    • half:16位 浮點(diǎn)數(shù)
    • int:32位 整型
    • fixed:12位 定點(diǎn)數(shù),取值范圍 [0 - 1] 的小數(shù) 或 整數(shù)
    • bool
    • sampler2D:紋理對(duì)象
    • string
  • 預(yù)設(shè)的Structure

    • 輸入

      變量名 代表內(nèi)容
      float2 uv_MainTex 紋理貼圖UV,模型上每個(gè)像素對(duì)應(yīng)到紋理圖的坐標(biāo),_MainTex為紋理圖的名字
      float3 viewDir 像素的視圖方向
      float3 worldPos 像素的世界坐標(biāo)位置
      float4 screenPos 屏幕空間位置,是float4類(lèi)型,只需用前兩個(gè)值
      float4 color:COLOR 每個(gè)頂點(diǎn)的內(nèi)插值顏色
    • 輸出

      變量名 代表內(nèi)容
      half3 Albedo 反射率,即顏色紋理RGB
      half3 Normal 法線,即法向量(x, y, z)
      half3 Emission 自發(fā)光顏色RGB
      half Specular 鏡面反射度
      half Gloss 光澤度
      half Alpha 透明度
  • 語(yǔ)義綁定
    語(yǔ)法:變量名:語(yǔ)義定義,表示這個(gè)變量代表著某種指定的值,例:color:COLOR 表示color這個(gè)變量是顏色

4.2 結(jié)構(gòu)

  • 表面著色器沒(méi)有Pass通道
  • 外部是Shader Lab,內(nèi)部嵌入CG語(yǔ)言
Shader "Ashader/SurfaceShader/Shader001"
{
    Properties
    {
        
    }
    
    SubShader
    {
        // 不需要Pass通道

        // 預(yù)編譯指令 粉色高亮
        // --------- CG語(yǔ)言開(kāi)始 ---------
        CGPROGRAM

        // 表面著色器 入口函數(shù)名稱 蘭伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 輸入結(jié)構(gòu)體
        struct Input
        {
            float3 viewDir;
        };              // CG語(yǔ)言結(jié)構(gòu)體定義后要加";"

        // 聲明外部屬性,要求和屬性名字相同
        fixed4 _MainColor;

        // 入口函數(shù)
        // 參數(shù)
        // Input IN : 輸入結(jié)構(gòu)體
        // in/out/inout SurfaceOutput o : 常用于輸出
        // in:輸入 out:輸出 inout:既能輸入又能輸出
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 輸出純色
            o.Albedo = float3(1, 0, 0);
            // 四個(gè)數(shù)字rgba或xyzw 轉(zhuǎn)三個(gè)數(shù)字:變量.rgb .gba .xyz .yzw,用到哪個(gè)寫(xiě)哪個(gè)
            o.Albedo = _MainColor.rgb;
        }
        
        // --------- CG語(yǔ)言結(jié)束 ---------
        ENDCG
    }
}

4.3 方法使用

  • 設(shè)置紋理圖
Shader "AShader/SurfaceShader/Surface002"
{
    Properties
    {
        _MainTexture("主紋理", 2D) = ""{}
        _MainColor("主顏色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        // --------- CG語(yǔ)言開(kāi)始 ---------
        CGPROGRAM

        // 表面著色器 入口函數(shù)名稱 蘭伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 聲明外部屬性
        sampler2D _MainTexture;
        fixed4 _MainColor;

        // 輸入結(jié)構(gòu)體
        struct Input
        {
            // 主紋理的UV坐標(biāo)
            float2 uv_MainTexture;
        };

        // 入口函數(shù)
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染紋理圖,通過(guò)UV坐標(biāo)在紋理貼圖中獲取當(dāng)前像素點(diǎn)的顏色值
            // 參數(shù)
            // _MainTexture:紋理圖
            // IN.uv_MainTexture:紋理圖UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 與顏色進(jìn)行混合
            o.Albedo *= _MainColor.rgb;
        }

        // --------- CG語(yǔ)言結(jié)束 ---------
        ENDCG
    }
}
  • 設(shè)置法線貼圖
Shader "AShader/SurfaceShader/Surface003"
{
    Properties
    {
        _MainTexture("主紋理", 2D) = ""{}
        _NormalTexture("法線紋理", 2D) = ""{}
    }

    SubShader
    {
        // --------- CG語(yǔ)言開(kāi)始 ---------
        CGPROGRAM

        // 表面著色器 入口函數(shù)名稱 蘭伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 聲明外部屬性
        sampler2D _MainTexture;
        sampler2D _NormalTexture;

        // 輸入結(jié)構(gòu)體
        struct Input
        {
            // 主紋理的UV坐標(biāo)
            float2 uv_MainTexture;
            float2 uv_NormalTexture;
        };

        // 入口函數(shù)
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染紋理圖,通過(guò)UV坐標(biāo)在紋理貼圖中獲取當(dāng)前像素點(diǎn)的顏色值
            // 參數(shù)
            // _MainTexture:紋理圖
            // IN.uv_MainTexture:紋理圖UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 設(shè)置法線貼圖
            o.Normal = UnpackNormal(tex2D(_NormalTexture, IN.uv_NormalTexture));
        }

        // --------- CG語(yǔ)言結(jié)束 ---------
        ENDCG
    }
}
  • 邊緣發(fā)光
Shader "AShader/SurfaceShader/Surface004"
{
    Properties
    {
        _MainTexture("主紋理", 2D) = ""{}
        _NormalTexture("法線紋理", 2D) = ""{}

        _RimColor("發(fā)光顏色", Color) = (1, 1, 1, 1)
        _RimPower("發(fā)光強(qiáng)度", Range(1, 10)) = 1
    }

    SubShader
    {
        // --------- CG語(yǔ)言開(kāi)始 ---------
        CGPROGRAM

        // 表面著色器 入口函數(shù)名稱 蘭伯特光照模型(漫反射)
        #pragma surface surf Lambert

        // 聲明外部屬性
        sampler2D _MainTexture;
        sampler2D _NormalTexture;
        fixed4 _RimColor;
        half _RimPower;

        // 輸入結(jié)構(gòu)體
        struct Input
        {
            // 主紋理的UV坐標(biāo)
            float2 uv_MainTexture;
            float2 uv_NormalTexture;
            // 視圖方向
            float3 viewDir;
        };

        // 入口函數(shù)
        void surf(Input IN, inout SurfaceOutput o)
        {
            // 渲染紋理圖,通過(guò)UV坐標(biāo)在紋理貼圖中獲取當(dāng)前像素點(diǎn)的顏色值
            // 參數(shù)
            // _MainTexture:紋理圖
            // IN.uv_MainTexture:紋理圖UV
            o.Albedo = tex2D(_MainTexture, IN.uv_MainTexture).rgb;
            // 設(shè)置法線貼圖
            o.Normal = UnpackNormal(tex2D(_NormalTexture, IN.uv_NormalTexture));

            // 計(jì)算邊緣發(fā)光系數(shù)
            float rim = 1 - saturate(dot(normalize(IN.viewDir), normalize(o.Normal)));
            // 系數(shù)直接乘
            //o.Emission =  _RimColor * rim * _RimPower;
            // 系數(shù)的光強(qiáng)次冪
            o.Emission = _RimColor * pow(rim, 10 - _RimPower);
        }

        // --------- CG語(yǔ)言結(jié)束 ---------
        ENDCG
    }
}

5. 頂點(diǎn)片段著色器(Shader 2.0)

5.1 頂點(diǎn)語(yǔ)義

* model本地坐標(biāo)
* view觀察坐標(biāo)
* projection投影坐標(biāo)
語(yǔ)義 代表內(nèi)容
float4 POSITION 頂點(diǎn)坐標(biāo)位置
float3 NORMAL 頂點(diǎn)法線向量坐標(biāo)
float4 TEXCOORD0 第一個(gè)UV坐標(biāo)(用作臨時(shí)變量,存坐標(biāo)存顏色等)
float4 TEXCOORD1/2/3... 第二/三/四...個(gè)UV坐標(biāo)
float4 TENGENT 頂點(diǎn)切線向量坐標(biāo)
float4 COLOR 頂點(diǎn)顏色值

5.2 常用函數(shù)庫(kù)

庫(kù)名 作用
HLSLSupport.cginc 輔助為跨平臺(tái)的著色器編譯宏和定義
UnityShaderVariables.cginc 常用全局變量
UnityCG.cginc 常用輔助函數(shù)
AutoLight.cginc 光、影函數(shù)
Lighting.cginc 光照模型相關(guān)
TerrainEngine.cginc 地形植被輔助

5.3 結(jié)構(gòu)

Shader "AShader/VFShader/VF001"
{
    Properties
    {
        _MainColor("主顏色", Color) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM

            //      著色器類(lèi)型 入口函數(shù)名稱
            #pragma vertex vert
            #pragma fragment frag
            // 聲明外部屬性
            fixed4 _MainColor;

            // 頂點(diǎn)著色器,進(jìn)行頂點(diǎn)處理
            // 返回值 入口函數(shù)名稱(參數(shù)類(lèi)型 參數(shù)名:語(yǔ)義綁定):返回值語(yǔ)義綁定
            float4 vert(float4 vertexPos:POSITION):SV_POSITION
            {
                // 完成頂點(diǎn)變換,返回投影坐標(biāo)
                // 5.4之前
                //return mul(UNITY_MATRIX_MVP, vertexPos);
                // 5.4之后
                return UnityObjectToClipPos(vertexPos);
            }

            // 片段著色器,著色
            fixed4 frag():COLOR
            {
                //return fixed4(1, 0, 0, 1);
                return _MainColor;
            }

            ENDCG
        }
    }
}

5.4 案例

  • 彩虹顏色
    將物體的坐標(biāo)作為顏色值,會(huì)呈現(xiàn)彩虹效果
Shader "AShader/VFShader/VF002"
{
    Properties
    {
        _ColorOffset("顏色偏移量", Range(0, 1)) = 0
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM
            
            #pragma vertex vert
            #pragma fragment frag
            // 聲明外部屬性變量
            fixed _ColorOffset;
            // 由于return只能返回一個(gè)變量,所以當(dāng)想返回多個(gè)值的時(shí)候使用結(jié)構(gòu)體
            // 頂點(diǎn)著色器輸出的結(jié)構(gòu)體
            struct v2f
            {
                // 0級(jí)紋理坐標(biāo)(臨時(shí)變量,用于存儲(chǔ)頂點(diǎn)著色器算出來(lái)的頂點(diǎn)坐標(biāo),給片段著色器用)
                float4 col:TEXCOORD0;
                // 屏幕坐標(biāo)
                float4 pos:SV_POSITION;
            };

            // 頂點(diǎn)著色器入口函數(shù)
            v2f vert(float4 vertexPos:POSITION)
            {
                // 定義結(jié)構(gòu)體對(duì)象
                v2f content;
                // 執(zhí)行頂點(diǎn)變換
                content.pos = UnityObjectToClipPos(vertexPos);
                // 獲取頂點(diǎn)坐標(biāo)
                content.col = vertexPos + float4(_ColorOffset, _ColorOffset, _ColorOffset, 0);

                return content;
            }

            // 片段著色器入口函數(shù)
            float4 frag(v2f content):COLOR
            {
                // 將頂點(diǎn)坐標(biāo)當(dāng)成顏色值輸出
                return content.col;
            }

            ENDCG
        }
    }
}
  • 設(shè)定漫反射
Shader "AShader/VFShader/VF003"
{
    Properties
    {
        _MainColor("漫反射顏色", COLOR) = (1, 1, 1, 1)
    }

    SubShader
    {
        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            // 引入庫(kù)
            #include "UnityCG.cginc"

            // 聲明外部變量
            fixed4 _MainColor;
            // 聲明內(nèi)置變量
            fixed4 _LightColor0;

            // 頂點(diǎn)著色器輸入結(jié)構(gòu)體
            struct appdata
            {
                // 頂點(diǎn)坐標(biāo)
                float4 vertexPos:POSITION;
                // 頂點(diǎn)法線
                float3 vertexNormal:NORMAL;
            };

            // 頂點(diǎn)著色器輸出結(jié)構(gòu)體
            struct v2f
            {
                // 屏幕坐標(biāo)
                float4 pos:SV_POSITION;
                // 屏幕法線
                float3 normal:NORMAL;
            };

            // 頂點(diǎn)著色器入口函數(shù)
            v2f vert(appdata data)
            {
                v2f content;
                content.pos = UnityObjectToClipPos(data.vertexPos);
                // 計(jì)算法線
                content.normal = mul(float4(data.vertexNormal, 1), unity_WorldToObject).xyz;
                return content;
            }

            // 片段著色器入口函數(shù)
            fixed4 frag(v2f content):COLOR
            {
                // 求法線的標(biāo)準(zhǔn)化向量
                float3 lightNormal = normalize(content.normal);
                // 求入射光的標(biāo)準(zhǔn)化向量
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                // 計(jì)算漫反射顏色
                float3 diffuseColor = _MainColor * _LightColor0 * -min(0, dot(lightNormal, lightDir));

                return fixed4(diffuseColor, 1) + UNITY_LIGHTMODEL_AMBIENT;
            }


            ENDCG
        }
    }
}
  • 技能釋放范圍
Shader "SkillShader/Skill1"
{
    Properties
    {
        // 技能釋放原點(diǎn)
        _BossPosition("BossPosition", Vector) = (1, 1, 1, 1)
        // 透明通道值
        _Alpha("BossSkillAlpha", Range(0, 1)) = 0
        // 用于代碼控制顯示范圍的值
        _Dis("SkillDis", Range(0, 10)) = 0
    }

    SubShader
    {
        Pass
        {
            // 開(kāi)啟透明混合
            Blend SrcAlpha OneMinusSrcAlpha

            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag

            float4 _BossPosition;
            float _Alpha;
            float _Dis;

            struct v2f
            {
                float4 vertPos:TEXCOORD0;
                float4 pos:SV_POSITION;
            };

            v2f vert(float4 vertexPos:POSITION)
            {
                v2f content;
                content.pos = UnityObjectToClipPos(vertexPos);
                content.vertPos = vertexPos;

                return content;
            }

            float4 frag(v2f content):COLOR
            {
                // 根據(jù)傳入坐標(biāo)計(jì)算需要渲染的地方
                if (distance(content.vertPos.z, _BossPosition.z) < _Dis && abs(distance(content.vertPos.x, _BossPosition.x)) < 1)
                {
                    return float4(1, 0, 0, _Alpha);
                }
                else
                {
                    return float4(1, 0, 0, 0);
                }
            }

            ENDCG
        }
    }
}

6. 小知識(shí)點(diǎn)

  • 法線貼圖:法線決定光的反射方向,法線是一個(gè)向量,向量是vector3,顏色的rgb也是vector3,所以法線貼圖使用顏色來(lái)代表向量(例:紅色(1, 0, 0)代表右)
  • 邊緣發(fā)光公式:
    RimColor = EmissionColor * (1 - clamp01(dot(normalize(normal), normalize(viewDir))))

附:Shader詞典

單詞 描述 單詞 描述 單詞 描述
Shader 著色器 Properties 屬性 SubShader 子著色器
Pass 通道 Color 顏色 Cull 剔除
ZTest 深度測(cè)試 SeparateSpecular 鏡面反射 Diffuse 漫反射
Ambient 環(huán)境光 Shininess 光澤度 Specular 高光
Emission 自發(fā)光 Combine 結(jié)合 Primary 基本的
Previous 之前的 Constant 恒定的 Gloss 光澤度
Vertex 頂點(diǎn) Fragment 片段
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容