ShaderLab顶点和片元着色器

ShaderLab 着色器不仅仅包括“硬件着色器”。这些着色器做很多事情。它们描述在材质检视器 (Material Inspector) 中显示的属性,容纳用于不同图形硬件的多种着色器实现,配置固定函数硬件状态等等。实际可编程着色器 - 如顶点和片元程序 - 只是整个 ShaderLab“着色器”概念的一部分。请查看着色器教程中的基本简介。在这里,我们将调用低级硬件着色器着色器程序。

如果您想编写与光照交互的着色器,请查看表面着色器文档。本页剩余部分将假设着色器不与 Unity 光照交互(例如:特殊效果、Image Effects|图像效果等。)

着色器程序的编写采用 Cg/HLSL 语言,是通过在着色器文本中 Pass 命令内的某处嵌入“代码片段”的来实现的。它们通常看起来像这样:

 Pass {
      *// ...常用的通道状态设置...*
      **CGPROGRAM**
      *// 该代码片段的编译指令,例如:*
      **#pragma vertex** vert
      **#pragma fragment** frag
      *// Cg 代码自身*
      **ENDCG**
      *// ...通道设置的剩余部分...*
  }

Cg 代码片段

Cg 程序代码片段被编写在 CGPROGRAMENDCG 之间。

在代码片段编译指令的开头,可以使用 #pragma 指令。指示编译哪些着色器函数的编译指令:

  • #pragma vertex 名称 - 将函数名称编译为顶点着色器。
  • #pragma fragment 名称 - 将函数名称编译为片元着色器。
  • #pragma geometry 名称 - 将函数名称编译为 DX10 几何结构着色器。要使这个选项自动打开#pragma target 4.0,请参阅下文。
  • #pragma hull 名称 - 将函数名称编译为 DX11 外壳着色器。要使这个选项自动打开#pragma target 5.0,请参阅下文。
  • #pragma domain 名称 - 将函数名称编译为 DX11 域着色器。要使这个选项自动打开#pragma target 5.0,请参阅下文。

其他编译指令:

  • #pragma target 名称 - 要编译成哪个着色器目标。有关详细信息,请参阅着色器目标。
  • #pragma only_renderers 空格隔开的名称 - 仅为给定渲染器编译着色器。默认情况下,为所有渲染器编译着色器。有关详细信息,请参阅渲染器。
  • #pragma exclude_renderers 空格隔开的名称 - 不仅为给定渲染器编译着色器。默认情况下,为所有渲染器编译着色器。有关详细信息,请参阅渲染器。
  • #pragma glsl - 为桌面 OpenGL 平台编译着色器时,将 Cg/HLSL 转换成 GLSL (而不是默认设置,即 ARB 顶点/片元程序)。使用此指令可启用导数指令 (derivative instruction)、具有明确 LOD 等级的纹理采样等。
  • #pragma glsl_no_auto_normalization - 为移动 GLSL (iOS/Android) 编译着色器时,关闭法线和切线向量的自动规范化性能。默认情况下,法线和切线是在 iOS/Android 平台上的顶点着色器中被规范化的。
  • #pragma fragmentoption 选项 - 添加选项到已编译的 OpenGL 片元程序。有关允许使用的选项的列表,请参阅ARB 片元程序详述。该指令对顶点程序或被编译成非 OpenGL 目标的程序无影响。

每个代码片段都必须包含一个顶点程序或一个片元程序或两者皆包含。因此,要求使用一个 #pragma vertex 指令或一个#pragma fragment 指令或两者都使用。

着色器目标

默认情况下,Unity 将着色器编译为简约 Shader Model 2.0 的相等物。使用 #pragma target 可使着色器被编译成其他能力等级。当前支持以下目标:

  • #pragma target 2.0 (默认) - 简约 Shader Model 2.0
    • Direct3D 9 上的 Shader Model 2.0。
    • 具有 256 位指令限制的ARB_vertex_program、具有 96 位指令限制(32 位纹理 + 64 位算法)的ARB_fragment_program、16 个临时寄存器 (temporary register) 和 4 个纹理间接 (texture indirection)。
  • #pragma target 3.0 - 编译成 Shader Model 3.0:
    • Direct3D 9 上的 Shader Model 3.0。
    • 无指令限制的 ARB_vertex_program、具有 1024 位指令限制(512 位纹理 + 512 位算法)的 ARB_fragment_program、32 个临时寄存器 (temporary register) 和 4 个纹理间接 (texture indirection)。可使用#pragma profileoption 指令覆盖这些限制。例如:#pragma profileoption MaxTexIndirections=256 将纹理间接限制增加到 256 个。请注意,一些 Shader Model 3.0 功能(如导数指令)是不受 ARB_vertex_program/ARB_fragment_program 支持的。您可以使用#pragma glsl 转换成限制较少的 GLSL 来代替。当编译成 3.0 或更大目标时,顶点和片元程序都需要被展示。
  • #pragma target 4.0 - 编译成 DX10 Shader Model 4.0。当前只有 DirectX 11 渲染器支持该目标。
  • #pragma target 5.0 - 编译成 DX11 Shader Model 5.0。当前只有 DirectX 11 渲染器支持该目标。

渲染平台

Unity 支持几个渲染 API(例如,Direct3D 9 和 OpenGL),默认情况下,所有着色器程序都编译成受支持的渲染器。使用 #pragma only_renderers 或 #pragma exclude_renderers 指令,您可以指示编译成哪些渲染器。如果您知道您将只把 Mac OS X (无 Direct3D)或 Windows(Unity 默认为 D3D)作为目标,或者如果某个特定着色器只在一个渲染器中可用,而在其他渲染器中不可用,这样是有用的。当前受支持的渲染器名称有:

  • d3d9 - Direct3D 9.
  • d3d11 - Direct3D 11.
  • opengl - OpenGL.
  • gles - OpenGL ES 2.0.
  • xbox360 - Xbox 360.
  • ps3 - PlayStation 3.
  • flash - Flash.

例如,以下这行指令只会将着色器编译为 D3D9 模式:

在着色器程序中,您通常需要访问一些全局状态,例如当前模型视图投影矩阵 (modelviewprojection matrix)、当前环境颜色等等。无需声明这些内置状态变量,您可以直接在着色器程序中使用它们。

内置矩阵

受支持的矩阵 (float4x4):

UNITY_MATRIX_MVP当前模型视图投影矩阵 (modelviewprojection matrix)

UNITY_MATRIX_MV 当前模型视图矩阵 (modelview matrix)

UNITY_MATRIX_V 当前视图矩阵 (view matrix)。

UNITY_MATRIX_P 当前投影矩阵 (projection matrix)

UNITY_MATRIX_VP 当前视图投影矩阵 (viewprojection matrix)

UNITY_MATRIX_T_MV 模型视图矩阵 (modelview matrix) 的转置

UNITY_MATRIX_IT_MV 模型视图矩阵 (modelview matrix) 的逆转置

UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3 纹理变换矩阵

内置向量

受支持的向量 (float4):
UNITY_LIGHTMODEL_AMBIENT 当前环境色。

ShaderLab 语法:Properties

着色器可以定义一系列的参数,这些参数将由 Unity 材质检视器中的设计师设定。在着色器文件中的属性 (Properties) 块定义参数。

语法

属性 (Properties) { Property [Property ...] }

定义属性块。括号内,多个属性定义如下。

*name* ("*display name*", **Range** (*min*,*max*)) =*number*

定义浮点属性,代表检视器中从最小值 (min)最大值 (max)的滑块。

*name* ("*display name*", **Color**) = (*number*,*number*,*number*,*number*)

定义颜色属性。

*name* ("*display name*", **2D**) = "*name*" {*options* }

定义二维纹理属性。

*name* ("*display name*", **Rect**) = "*name*" {*options* }

定义矩形(非 2 的幂)纹理属性。

*name* ("*display name*", **Cube**) = "*name*" {*options* }

定义立方体贴图纹理属性。

*name* ("*display name*", **Float**) = *number*

定义浮点属性。

*name* ("*display name*", **Vector**) = (*number*,*number*,*number*,*number*)

定义四分量向量属性。

详细信息

着色器内部的每个属性都被名称 (name) 引用(Unity 中,着色器属性名称以下划线开头是很常见的)。在材质检视器中属性会显示为显示名称 (display name)。对每个属性来说,默认值放在等号之后:

  • 对于范围 (Range)浮点 (Float) 属性,默认值只是一个数字。
  • 对于颜色 (Color)向量 (Vector) 属性来说,默认值为圆括号中的四个数字。
  • 对纹理(二维 (2D)矩形 (Rect)立方体 (Cube))来说,默认值可以是一个空字符串或者是以下内置默认纹理中的一种:"白色”、“黑色”、“灰色”或“凹凸贴图”。

随后在着色器中,通过使用方括号内的属性名称访问属性值:[name].

示例

Properties {
    // 水着色器的属性
    _WaveScale ("Wave scale", Range (0.02,0.15)) = 0.07 // 滑块
    _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.5
    _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.4
    _RefrColor ("Refraction color", Color)  = (.34, .85, .92, 1) // 颜色
    _ReflectionTex ("Environment Reflection", 2D) = "" {} // 纹理
    _RefractionTex ("Environment Refraction", 2D) = "" {}
    _Fresnel ("Fresnel (A) ", 2D) = "" {}
    _BumpMap ("Bumpmap (RGB) ", 2D) = "" {}
} 

纹理属性选项

在纹理属性的花括号内的选项 (options) 为可选项。可用选项有:

  • TexGen texgenmode: 该纹理的自动纹理协调生成模式。可以是 ObjectLinearEyeLinearSphereMapCubeReflectCubeNormal 中的一种;这些直接对应 OpenGL texgen 模式。请注意:如果使用自定义顶点程序,则 TexGen 模式将被忽略。
  • LightmapMode 如果启用此模式,该纹理会受到每个渲染器光照贴图参数的影响。也就是说,将使用的纹理可以不在材质中,而是来自渲染器设置,请参见渲染器脚本文档。

示例

// EyeLinear texgen 模式示例

Shader "Texgen/Eye Linear" {
    Properties {
        _MainTex ("Base", 2D) = "white" { TexGen EyeLinear }
    }
    SubShader {
        Pass {
            SetTexture [_MainTex] { combine texture }
        }
    }
} 

ShaderLab 语法:子着色器 (SubShader)

Unity 中的每个着色器都是由一系列的子着色器构成的。当 Unity 必须显示网格时,会找到要使用的着色器,并选择在用户显卡上运行的第一个子着色器。

语法

Subshader { [Tags] [CommonState] Passdef [Passdef ...]}
定义子着色器为可选的标记、普通状态和一系列通道定义。

详细信息

子着色器定义一系列的渲染通道并视情况对所有通道设置成普通状态。此外,可以设置子着色器特定的标记。

当 Unity 选择使用哪个子着色器进行渲染时,它对每个定义的通道渲染对象一次(因为光交互也可能渲染多次)。由于每次渲染对象都是一次昂贵的操作,所以要使用尽可能最少的通道定义着色器。当然,有时在一些图形硬件上,使用一个通道不能达到需要的效果;那么您别无选择,只能使用多通道。

每个通道定义可以是一个常规通道、一个使用通道或一个捕获通道。

通道定义中允许的任何声明也可以出现在子着色器块中。这将使所有通道使用这种“共享”状态。

Example

// ...
SubShader {
    Pass {
        Lighting Off
        SetTexture [_MainTex] {}
    }
}
// ...

该子着色器定义了一个单通道,其关闭了所有光照并只显示纹理名称为 _MainTex 的网格。

ShaderLab 语法:Pass

通道 (Pass) 块使对象的几何结构被渲染一次。

语法

Pass { [Name and Tags] [RenderSetup] [TextureSetup]}

基本通道命令包含了渲染设置命令的可选列表,后面可跟随一系列纹理以供使用。

名称和标记

通道 (Pass) 可以定义其名称和任意数量的标记 - 名称/值字符串告知渲染引擎“通道”(Pass) 的目的。

渲染设置

通道可设置图形硬件的各种状态,例如,是否应打开 alpha 混合,是否使用雾化等。其命令如下:

Material { Material Block }
定义在顶点光照管线中使用的材质。有关详细信息,请参阅材质页面

Lighting On | Off

开启或关闭顶点光照。有关详细信息,请参阅材质页面

Cull Back | Front | Off

设置多边形剔除模式。

ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)

设置深度测试模式。

ZWrite On | Off

设置深度编写模式。

Fog { Fog Block }

设置雾化参数。

AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)CutoffValue

开启 alpha 测试。

Blend SourceBlendMode DestBlendMode

设置 alpha 混合模式。

Color Color value

如果顶点光照是关闭的,则设置使用的颜色。

ColorMask RGB | A | 0 | any combination of R, G, B, A

设置颜色编写遮蔽图。编写 ColorMask 0 可关闭所有颜色通道的渲染。

Offset OffsetFactor , OffsetUnits

设置深度偏移。请注意,从 Unity 3.0 版本起,该命令只接受常量(即:非着色器参数)。

SeparateSpecular On | Off

打开或关闭顶点光照单独的高光颜色。有关详细信息,请参阅材质页面

ColorMaterial AmbientAndDiffuse | Emission

计算顶点光照时使用逐顶点颜色。有关详细信息,请参阅材质页面

纹理设置

渲染状态设置后,您可以应用 SetTexture 命令指定要应用的多种纹理及其组合模式:

SetTexture texture property { [Combine options] }

纹理设置可配置固定功能多层材质管线,并且如果使用自定义片段着色器,则纹理设置将被忽视。

详细信息

逐像素光照

逐像素光照管线通过在多通道中渲染对象作用。Unity 渲染对象一次以获得环境光照和所有顶点光照。然后渲染每个影响独立附加通道内的对象的像素光照。有关详细信息,请参阅渲染器管线。

逐顶点光照

逐顶点光照是对每个顶点都进行了计算的标准的 Direct3D/OpenGL 光照模式。Lighting on 可打开光照。光照受Material块、ColorMaterial 和SeparateSpecular 令影响。有关详细信息,请参阅材质页面。

ShaderLab 内置值

Unity 为着色器提供 少量内置值:当前对象变换矩阵、时间等类似值。

使用 ShaderLab 中的内置值就像使用其他任何属性一样,唯一的区别在于您不必在某处进行声明 - 它们都是“内置的”。

在可编程着色器中使用它们需要包含UnityCG.cginc文档。

变换

float4x4 UNITY_MATRIX_MVP当前模型视图投影矩阵 (modelviewprojection matrix)

float4x4 UNITY_MATRIX_MV当前模型视图矩阵 (modelview matrix)

float4x4 UNITY_MATRIX_V当前视图矩阵 (view matrix)。

float4x4 UNITY_MATRIX_P 当前投影矩阵 (projection matrix)

float4x4 UNITY_MATRIX_VP 当前视图投影矩阵 (viewprojection matrix)

float4x4 UNITY_MATRIX_T_MV 模型视图矩阵 (modelview matrix) 的转置

float4x4 UNITY_MATRIX_IT_MV 模型视图矩阵 (modelview matrix) 的逆转置

float4x4 UNITY_MATRIX_TEXTURE0UNITY_MATRIX_TEXTURE3 纹理变换矩阵

float4x4 _Object2World 当前模型矩阵

float4x4 _World2Object 当前世界坐标矩阵的逆转置

float3 _WorldSpaceCameraPos 相机的世界坐标空间位置

float4 unity_Scale xyz 组件未使用;.w 包含等比缩放对象的缩放。

光照

在普通的 ShaderLab 中,通过结尾追加零访问以下属性:例如光源的模型*光颜色是 _ModelLightColor0。在 Cg 着色器中,它们显示为单元素阵列,所以 Cg 中相同的是 _ModelLightColor[0]

名称 类型
_ModelLightColor float4 材质的主要*光色
_SpecularLightColor float4 材质的高光*光色
_ObjectSpaceLightPos float4 光源在对象空间中的位置。w 组件针对方向灯是 0,针对其他灯是 1
_Light2World float4x4 光到世界坐标 (World) 空间矩阵
_World2Light float4x4 世界坐标到光 (Light) 空间矩阵
_Object2Light float4x4 对象到光 (Light) 空间矩阵

种类

  • float4 _Time : 时间 (t/20, t, t2, t3),用于对着色器内的对象进行动画处理
  • float4 _SinTime : 时间正弦:(t/8, t/4, t/2, t)
  • float4 _CosTime : 时间余弦:(t/8, t/4, t/2, t)
  • float4 unity_DeltaTime : 差量时间:(dt, 1/dt, smoothDt, 1/smoothDt)
  • float4 _ProjectionParams :
    x 是 1.0 或 -1.0,如果当前用翻转投影矩阵渲染,则为负数
    y 是相机的近平面
    z 是相机的远平面
    w 是 1/FarPlane。
  • float4 _ScreenParams :
    x 是以像素为单位的当前渲染目标宽度
    y 是以像素为单位的当前渲染目标高度
    z 是 1.0 + 1.0/宽度
    w 是 1.0 + 1.0/高度

UnityCG.cginc中一些常用的函数和宏定义变量

_LightColor0 该变量表示第一个直射光的颜色
_WorldSpaceLightPos0 该变量表示第一个直射光的位置(世界坐标下)
UNITY_LIGHTMODEL_AMBIENT 该变量表示系统的环境光
_World2Object 这个矩阵用来把一个方向从世界空间转换到模型空间
UNITY_LIGHTMODEL_AMBIENT用来获取环境光

//摄像机方向(视角方向:从顶点到摄像机的方向)
float3 WorldSpaceViewDir(float4 v) 根据(模型空间)中的顶点坐标 --> (世界空间)视角方向
float3 UnityWorldSpaceViewDir(float4 v) 根据(世界空间)中的顶点坐标-->(世界空间)视角方向
float3 ObjSpaceViewDir(float4 v) 根据(模型空间)中的顶点坐标-->(模型空间)视角方向
//光源方向(从顶点到光源的方向)
float3 WorldSpaceLightDir(float4 v) 根据(模型空间)中的顶点坐标-->(世界空间)中光源方向
float3 UnityWorldSpaceLightDir(float4 v) 根据(世界空间)中的顶点坐标-->(世界空间)中光源方向
float3 ObjSpaceLightDir(float4 v) 根据(模型空间)中的顶点坐标-->(模型空间)中光源方向
//方向转换
float3 UnityObjectToWorldNormal(float3 norm) 把法线方向从(模型空间)-->(世界空间)
float3 UnityObjectToWorldDir(float3 dir) 把方向向量从(模型空间)-->(世界空间)
float3 UnityWorldToObjectDir(float3 dir) 把方向向量从(世界空间)-->(模型空间)

// 根据(模型空间)中的顶点坐标 --> (世界空间)视角方向
float3 WorldSpaceViewDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return _WorldSpaceCameraPos.xyz - worldPos;;
}
// 根据(世界空间)中的顶点坐标-->(世界空间)视角方向
float3 UnityWorldSpaceViewDir( in float3 worldPos )
{
    return _WorldSpaceCameraPos.xyz - worldPos;
}
// 根据(模型空间)中的顶点坐标-->(模型空间)视角方向
float3 ObjSpaceViewDir( in float4 v )
{
    float3 objSpaceCameraPos = mul(unity_WorldToObject, float4(_WorldSpaceCameraPos.xyz, 1)).xyz;
    return objSpaceCameraPos - v.xyz;
}
// 根据(模型空间)中的顶点坐标-->(世界空间)中光源方向
float3 WorldSpaceLightDir( in float4 localPos )
{
    float3 worldPos = mul(unity_ObjectToWorld, localPos).xyz;
    return UnityWorldSpaceLightDir(worldPos);
}
// 根据(世界空间)中的顶点坐标-->(世界空间)中光源方向
float3 UnityWorldSpaceLightDir( in float3 worldPos )
{
#ifndef USING_DIRECTIONAL_LIGHT
    return _WorldSpaceLightPos0.xyz - worldPos;
#else
    return _WorldSpaceLightPos0.xyz;
#endif
}
// 根据(模型空间)中的顶点坐标-->(模型空间)中光源方向
float3 ObjSpaceLightDir( in float4 v )
{
    float3 objSpaceLightPos = mul(unity_WorldToObject, _WorldSpaceLightPos0).xyz;
#ifndef USING_DIRECTIONAL_LIGHT
    return objSpaceLightPos.xyz - v.xyz;
#else
    return objSpaceLightPos.xyz;
#endif
}
// 把法线方向从(模型空间)-->(世界空间)
float3 UnityObjectToWorldNormal( in float3 norm )
{
    return normalize(mul((float3x3)unity_ObjectToWorld, norm ));
    //return normalize(mul(norm, (float3x3)unity_WorldToObject));
}
// 把方向向量从(模型空间)-->(世界空间)
float3 UnityObjectToWorldDir( in float3 dir )
{
    return normalize(mul((float3x3)unity_ObjectToWorld, dir));
}
// 把方向向量从(世界空间)-->(模型空间)
float3 UnityWorldToObjectDir( in float3 dir )
{
    return normalize(mul((float3x3)unity_WorldToObject, dir));
}

显示贴图示例

Shader "Custom/UnlitShader"
{
    Properties{
        _MainTex("贴图",2D)="white"{}
    }

    SubShader
    {
        Tags{"RenderType"="Opaque"}
        LOD 200
        Pass{
            CGPROGRAM

            //渲染管线:应用阶段->几何阶段(顶点函数计算->片元函数计算)->光栅化
            #pragma vertex vert//顶点函数
            #pragma fragment frag//片元函数

            //应用阶段传输给几何阶段的顶点函数的参数
            struct appdata
            {
                float4 vertex :POSITION;//语义:代表顶点位置
                float2 uv:TEXCOORD0;//语义:贴图的UV
            };
            //顶点函数计算后传输给片元函数的参数
            struct v2f
            {
                float4 vertex :SV_POSITION;
                float2 uv:TEXCOORD0;
            };

            v2f vert(appdata a)
            {
                v2f o;
                //应用层顶点无法直接给几何阶段,需要从自身转屏幕
                o.vertex = UnityObjectToClipPos(a.vertex);
                o.uv = a.uv;
                return o;
            }

            sampler2D _MainTex;
            float4 _MainTex_ST;

            fixed4 frag(v2f i) :SV_Target
            {
                fixed4 c = tex2D(_MainTex, i.uv);
                return c;
            }

            ENDCG
        }
    }
}

法线转颜色显示

Shader "Custom/UnlitNormalColor"
{
    Properties{
        _MainTex("贴图",2D)="white"{}
    }

    SubShader
    {
        Tags{"RenderType"="Opaque"}
        LOD 200
        Pass{
            CGPROGRAM

            //渲染管线:应用阶段->几何阶段(顶点函数计算->片元函数计算)->光栅化
            #pragma vertex vert//顶点函数
            #pragma fragment frag//片元函数
            #include "UnityCG.cginc"//引入cg库,可以使用UnityObjectToWorldNormal等函数

            //应用阶段传输给几何阶段的顶点函数的参数
            struct appdata
            {
                float4 vertex :POSITION;//语义:代表顶点位置
                float2 uv:TEXCOORD0;//语义:贴图的UV
                half3 normal:NORMAL;//语义:法线
            };
            //顶点函数计算后传输给片元函数的参数
            struct v2f
            {
                float4 vertex :SV_POSITION;//语义:代表顶点位置
                float2 uv:TEXCOORD0;//语义:贴图的UV
                half3 normal:NORMAL;//语义:法线
            };
            v2f vert(appdata a)
            {
                v2f o;
                //应用层顶点无法直接给几何阶段,需要从自身转屏幕
                o.vertex = UnityObjectToClipPos(a.vertex);
                o.uv = a.uv;
                //把顶点转化后,当成颜色使用
                o.normal = UnityObjectToWorldNormal(a.normal);
                return o;
            }
            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed4 frag(v2f i) :SV_Target
            {
                fixed4 c;
                c.rgb= i.normal;//把法线赋值给颜色
                // c.rgb= fixed3(0.5,0,0.9);
                c.a=1;
                return c;
            }
            ENDCG
        }
    }
}

自定义光照

Shader "Custom/CustomDiffuse"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Pass
        {
            Tags {"LightMode"="ForwardBase"}
        
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc" // for UnityObjectToWorldNormal
            #include "UnityLightingCommon.cginc" // for _LightColor0

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                fixed4 diff : COLOR0; // diffuse lighting color
            };

            v2f vert (appdata_base v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);//顶点从自身坐标系转裁剪坐标系
                half3 worldNormal = UnityObjectToWorldNormal(v.normal);//法线从自身坐标系转世界坐标系
                o.uv = v.texcoord;
               
                //自定义 漫反射Lambert 光照模型
                half nl = dot(worldNormal, _WorldSpaceLightPos0.xyz);
                nl=nl*0.5+0.5;//漫反射遮蔽,半lambert
                o.diff = nl * _LightColor0;
                return o;
            }
            
            sampler2D _MainTex;

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                col *= i.diff;
                return col;
            }
            ENDCG
        }
    }
}

你可能感兴趣的:(ShaderLab顶点和片元着色器)