UnityShader——基础篇之UnityShader基础

news2024/12/28 20:25:45

UnityShader基础

UnityShader概述

材质和UnityShader

  总的来说,在Unity中需要配合使用材质(Material)和 Unity Shader 才能达到需要的效果,常见流程为:

  • 创建一个材质
  • 创建一个 Unity Shader,并把它赋给上一步中创建的材质
  • 把材质赋给需要渲染的对象
  • 在材质面板中调整 Unity Shader 的属性,以得到满意的效果

在这里插入图片描述

  Unity Shader定义了渲染所需的各种代码(如顶点着色器和片元着色器)、属性(如使用哪些纹理等)和指令(渲染和标签设置等)

  材质允许调节这些属性,将其最终赋给对应的模型

Unity 中的材质

  Unity 中的材质需要结合一个 GameObject 的 Mesh 或者 Particle systems 组件来工作,它决定了游戏对象看起来是什么样子的(也需要 Unity Shader 的配合)

  创建一个新的材质,可以在 Unity 的菜单栏中选择 Assets -> Create -> Material 来创建,也可以直接在 Project 视图中右击 -> Create -> Material 来创建

  当创建了一个材质后,就可以把它赋值给一个对象,这可以通过把材质直接拖拽到 Scene 视图中的对象来实现,或者在该对象的 Mesh Renderer 组件中直接赋值,如图:

在这里插入图片描述

  在 Unity 的 2020.x 版本中,默认情况下,一个新建的材质将使用Unity内置的 Standard Shader,这是一种基于物理渲染的着色器

  Unity的材质和许多建模软件(如 Cinema 4D、Maya 等)中提供的材质工鞥呢类似,他们都提供了一个面板来调整材质的各个参数,这种可视化的方法使得开发者不再需要自行在代码中设置和改变所需的各种参数,如图:

在这里插入图片描述

Unity 中的 Shader

  创建一个新的 Unity Shader,可以在 Unity 的菜单栏中选择 Assets -> Create -> Shader 来创建,也可以直接在 Project 视图中右击 -> Create -> Shader 来创建,Unity 一共提供了5种 Unity Shader 模板供选择 —— Shader Surface Shader, Unlit Shader, Image Effect Shader, Compute Shader 以及 Ray Tracing Shader。

  Standard Surface Shader 会产生一个包含了标准光照模型的表面着色器模板

  Unlit Shader会产生一个不包含光照(但包含雾效)的基本的顶点/片元着色器

  Image Effect Shader 为实现各种屏幕后处理效果提供了一个基本模板

  Compute Shader 会产生一种特殊的 Shader 文件,这类 Shader 旨在利用 GPU 的并行性来进行一些常规渲染流水线无关的计算

  Ray Tracing Shader是一种用于Unity中的实时光线追踪的Shader。光线追踪是一种通过追踪从相机到场景中各个像素的光线的技术,以模拟光线在真实世界中的传播和反射。Ray Tracing Shader可以帮助开发者实现更加逼真的光影效果,包括实时反射、折射、阴影和环境光照等效果。


  一个单独的 Unity Shader 是无法发挥任何作用的,它必须和材质结合起来。

  所以,可以在材质面板最上方的下拉菜单中选择需要使用的 Unity Shader,当选择完毕后,材质面板中就会出现该 Unity Shader 可用的各种属性。这些属性可以是颜色、纹理、浮点数、滑动条(限制了范围的浮点数)、向量等

  当把材质赋给场景中的一个对象,就可以看到调整属性所发生的视觉变化


  Unity Shader本质上就是一个文本文件,和 Unity 中的很多外部文件类似,Unity Shader 也有导入设置(Import Settings)面板,在 Project视图中选中某个 Unity Shader即可看到,如图:

在这里插入图片描述

  在该面板上,可以在 Default Maps 中指定该 Unity Shader 使用的默认纹理。当任何材质第一次使用该 Unity Shader 时,这些纹理就会自动被赋予到相应的属性上。在下方的面板中,Unity 会显示出和该 Unity 相关的信息,例如它是否是一个表面着色器(Surface Shader)、是否是一个固定函数着色器(Fixed Function Shader)等,还有一些信息是和在 Unity Shader 中的标签设置有关,例如是否会投射阴影、使用的渲染队列、LOD值等

  对于表面着色器来说,可以通过单击 Show generated code 按钮来打开一个新的文件,在该文件里将显示 Unity 在背后为该表面着色器生成的顶点/片元着色器。这可以方便对这些生成的代码进行修改(需要复制到一个新的 Unity Shader 中才可保存)和研究

  如果 Unity Shader 使一个固定函数着色器,在 Fixed function 的后面也会出现一个 Show generated code 按钮,来查看该固定函数着色器生成的顶点/片元着色器。Compile and show code 下拉列表可以让开发者检查该 Unity Shader 针对不同图像编程接口(例如 OpenGL、D3D9、D3D11等)最终编译成的 Shader 代码,如图所示:

在这里插入图片描述

  直接单击该按钮可以查看生成的底层的汇编指令。可以利用这些代码来分析和优化着色器

  除此之外,Unity Shader 的导入面板还可以方便地查看其使用的渲染队列(Reder queue)、是否关闭批处理(Disable batching)、属性列表(Properties)等信息

Unity Shader 的基础:ShaderLab

什么是 ShaderLab

  Unity Shader 是 Unity 为研发者提供的高层记得渲染抽象层,Unity 希望以这种方式来让开发者更加轻松的控制渲染,见下图:

在这里插入图片描述

  在 Unity 中,所有的 Unity Shader 都是使用 ShaderLab 来编写的

  ShaderLab 是 Unity 编写 Unity Shader 的一种说明性语言,它使用了一些嵌套在花括号内部的**语义&&(syntax)来描述一个 Unity Shader 文件的结构,这些结构包含了许多渲染所需的数据,例如 Properties 语句块中定义了着色器所需的各种属性,这些属性将会出现在材质面板中

  从设计上来说,ShaderLab 类似于 CgFX 和 Direct3D Effects(FX)语言,他们都定义了要显示一个材质所需的所有东西,而不仅仅是着色器代码

  一个 Unity Shader 的基础结构如下所示:

Shader "ShaderName"{
    Properties{
        //属性
    }
    SubShader{
        //显卡A使用的子着色器
    }
    SubShader{
        //显卡B使用的子着色器
    }
    Fallback "VertexLit"
}

UnityShader的结构

给Shader起名字

  每个Unity Shader文件的第一行都需要通过 Shader 语义来制定该 Unity Shader 的名字,这个名字由一个字符串来定义

  当为材质选择使用的 Unity Shader 时,这些名称就会出现在材质面板的下拉列表里,通过在字符串中添加斜杠(“/”),可以控制 Unity Shader 在材质面板中出现的位置,如下:

Shader "Unlit/001Shader"{}

  那么,这个 Unity Shader在材质面板中的位置就是:Shader -> Unlit -> 001Shader,如图:

在这里插入图片描述

材质和 Unity Shader 的桥梁:Properties

  Properties语义块中包含了一系列属性(property),这些属性将会出现在材质面板中

  Properties语义块的定义通常如下:

Properties{
    Name("display name",PropertyType) = DefaultValue
    Name("display name",PropertyType) = DefaultValue
    //更多属性
}

  开发者声明这些属性是为了在材质面板中能够方便的调整各种材质属性

  如果需要在 Shader 中访问它们,就需要使用每个属性的名字(Name),Unity中,这些属性的名字通常由一个下划线开始,显示的名称(display name)则是出现在材质面板上的名字,需要为每个属性指定它的类型(PropertyType),常见的属性如表:

属性类型默认值的定义语法例子
Intnumber_Int(“Int”,Int) = 2
Floatnumber_Float(“Float”,Float) = 1.5
Range(min,max)number_Range(“Range”,Range(0.0,5.0) = 3.0
Color(number,number,number,number)_Color(“Color”,Color) = (1,1,1,1)
Vector(number,number,number,number)_Verctor(“Vector”,Vector) = (2,3,6,1)
2D“defaulttexture”{}_2D(“2D”,2D) = “”{}
Cube“defaulttexture”{}_Cube(“Cube”,Cube) = “white”{}
3D“defaulttexture”{}_3D(“3D”,3D) = “black”

  除此之外,还需要为每个属性指定一个默认值,在第一次把该 Unity Shader 赋给某个素材时,菜盒子面板显示的就是这些默认值

    对于 Int、Float、Range ,这些数字类型的属性,其默认值就是一个单独的数;

    对于 ColorVector 这类属性,默认值是用圆括号包围的一个四维向量;

    对于 2D、Cube、3D 这3种纹理类型,默认值的类型稍微复杂,他们的默认值是通过一个字符串后跟一个花括号来指定的,其中,字符串要么是空的,要么是内置的纹理名称,如 “white”“black”“gray” 或者 “bump”。或括号的用处原本是用于制定一些纹理属性的。

  如果需要控制固定管线的纹理坐标的生成,就需要再顶点着色器中编写计算相应纹理坐标的代码

  如下方的代码:

Shader "Unlit/001Shader"
{
    Properties
    {
        _Int("Int",int) = 2
        _Float("Float",float) = 1.5
        _Range("Range",range(0.0,5.0)) = 1.0
        _Color("Color",Color) = (1,1,1,1)
        _Vector("Vector",Vector) = (2,3,6,1)
        _2D("2D",2D) = ""{}
        _Cube("Cube",Cube) = "white"{}
        _3D("3D",3D) = "black"{}
    }

	FallBack "diffuse"
}

  材质面板中的显示结果,如图:

在这里插入图片描述

  Unity 允许重载默认的材质编辑面板,以提供更多自定义的数据类型

  为了在 Unity 中可以访问到这些属性,需要在 Cg 代码片中定义和这些属性类型相匹配的变量,需要说明的是,即使不在 Properties 语义块中生命这些属性,也可以直接在 Cg 代码片中定义变量

  此时,可以通过脚本向 Shader 中换地这些属性,因此,Properties与一块的作用仅仅是为了让这些属性可以出现在材质面板中

SubShader

  每一个 Unity Shader 文件可以包含多个 SubShader 语义块,但最少要有一个。

    当 Unity 需要加载这个 Unity Shader 时,Unity 会扫描所有的 SubShader 语义块,然后选择第一个能够在目标平台运行的SubShader

    如果都不支持的话,Unity 就会使用 Fallback 语义指定的 Unity Shader

  Unity 提供这种语义的原因在于,不同的显卡具有不同的能力。例如:一些旧的显卡仅能支持一定数目的操作指令,而一些更高级的显卡可以支持更多的指令数

  那么就希望在旧的显卡上使用计算复杂度低的着色器,在高级的显卡上使用计算复杂度较高的着色器,以便提供更出色的画面

  SubShader 语义块中包含的定义通常如下

SubShader{
    //可选
    Tags

    //可选
    RenderSetup

    Pass{}

    //Other Passes
}

  SubShader 中定义了一系列 Pass 以及可选的状态(RenderSetup)和标签(Tags)设置。

  每个 Pass 定义了一个完整的渲染流程,但如果 Pass 数目过多,往往会造成渲染性能的下降

  因此,应该尽量使用最小数目的 Pass,状态和标签同样可以在 Pass 声明,不同的是,SubShader 中的一些标签是特定的

  也就是说,这些标签设置和 Pass 中使用的标签是不一样的,对于状态设置来说,使用的语法是相同的

  但是如果在 SubShader 进行了这些设置,呢么将会用于所有的 Pass

  状态设置

  ShaderLab 提供了一系列渲染状态的设置指令,这些指令可以设置显卡的各种状态,例如是否开启混合/深度测试等

  ShaderLab 中常见的渲染状态设置选项如下表:

状态名称设置指令解释
CullCull Back|Front|Off设置剔除模式:剔除背面/正面/关闭剔除
ZTestZTest Less Greater|LEqqual|GEqual|Equal|NotEqual|Always设置深度测试时使用的函数
ZWriteZWrite On|Off开启/关闭深度写入
BlendBlend SrcFactor DstFactor开启并设置混合模式

  当在 SubShader 块中设置了上述渲染状态时,将会应用到所有的 Pass,如果不想这样(如在双面渲染中,希望第一个 Pass 中剔除正面来对背面进行渲染,在第二个 Pass 中剔除背面来对正面进行渲染),可以在 Pass 语义块中单独进行上面的设置

  SubShader的标签

  SubShader 的标签(Tags)是一个键值对(Key/Value Pair),它的键和值都是字符串类型,这些键值对是 SubShader 和渲染引擎之间的沟通桥梁。它们用来告诉 Unity 的渲染引擎希望怎样以及何时渲染这个对象:

  标签的结构如下:

Tags{"TagName1" = "Value1" "TagName2" = "Value2"}

  SubShader 的标签快支持的标签类型如表:

标签类型说明例子
Queue控制渲染顺序,指定该物体属于哪一个渲染队列,通过这种方式可以保证所有的透明物体可以在所有不透明物体后面被渲染,也可以自定义使用的渲染队列来控制物体的渲染顺序Tags{“Queue” = “Transparent”}
RenderTyep对着色器进行分类,例如这是一个不同明德着色器,或是一个透明的着色器等,这可以被用于着色器替换(Shader Replacement)功能Tags{“renderType”=“Opaque”}
DisableBatching一些 SubShader 在使用 Unity 的批处理功能时会出现问题,例如使用了模型空间下的坐标进行顶点动画,这是可以通过该标签来直接指明是否对该 SubShader 使用批处理Tags{“DisableBatching” = “True”
ForceNoShadowCasting控制使用该 SubShader 的物体是否会投射阴影Tags{“ForceNoShadowCasting”=“True”
IgnoreProjector如果该标签为"True",那么使用该 SubShader 的物体将不会受 Projector 的影响,通常用于半透明物体Tags{“IgnoreProjector”=“True”}
CanUseSpriteAtlas当该 SubShader 是用于精灵(sprite)时,将该标签设置为"False"Tags{“CanUseSpriteAtlas”=“False”
PreviewType知名材质面板将如何预览改材质。默认情况下,材质将显示为一个球形,可以通过把这些标签的值设为"Plane""SkyBox"来改变预览类型Tags{“PreviewType”=“Plane”}

  需要注意的是,上述标签仅可以在 SubShader 中声明,而不可以在 Pass 块中声明。Pass 块虽然也可以定义标签,但这些标签是不同于 SubShader 的标签类型

  Pass 语义块

  Pass 语义块包含的语义如下:

Pass{
    Name
    Tags
    RenderSetup
}

  首先,可以在 Pass 中定义该 Pass 的名称,例如:

Name "MyPassName"

  通过这个名称,可以使用 ShaderLab 的 UsePass 命令来直接使用其他 UnityShader 中的 Pass,例如:

UsePass "MyShader/MYPASSNAME"

  这样可以提高代码的复用性,需要注意的是,由于 Unity 内部会把所有 Pass 的名称转换成大写字母的表示,因此,在使用 UsePass 命令时必须使用大写形式的名字

  其次,可以对 Pass 设置渲染状态。SubShader 的状态设置同样适用于 Pass。除了上面提到的状态设置外,在 Pass 中我们还可以使用固定管线的着色器命令

  Pass 同样可以设置标签,但它的标签不同于 SubShader 的标签,这些标签也是用于告诉渲染引擎希望怎样来渲染该物体

  Pass 中使用的标签类型如下表:

标签类型说明例子
LightMode定义该 Pass 在 Unity 的渲染流水线中的角色Tags{“LightMode”=“ForwardBase”}
RequireOptions用于指定当满足某些条件时才渲染该 Pass,它的值是一个由空格分割的字符串。Tags{“RequireOptions”=“SoftVegetation”}

  除了上面普通的 Pass 定义外,UnityShader 还支持一些特殊的 Pass,以便进行代码复用或实现更复杂的效果:

    UsePass:如之前提到的一样,可以使用该命令来复用其他 UnityShader 中的 Pass

    GrabPass:该 Pass 负责抓取屏幕并将结果存储在一张纹理中,以用于后续的 Pass 处理

Fallback

  紧跟在各个 SubShader 语义块后面的,可以是一个 Fallback 指令,它用于告诉 Unity,“如果上面所有的 SubShader 在这块显卡上都不能运行,那么就是用这个最低级的 Shader”

  它的语义如下:

Fallback "name"
//或者
Fallback Off

  如上所述,可以通过一个字符串来告诉 Unity 这个“最低级的 UnityShader”是谁,也可以关闭 Fallback 功能,但一旦这么做,那么意思就是“如果一块显卡跑不了上面所有的 Shader,那就不管他了”

  例子如下:

Fallback "VertexLit"

  事实上,Fallback还会影响阴影的投射

  在渲染阴影纹理时,Unity 会在每个 UnityShader 中寻找一个阴影投射的 Pass,通常情况下,不需要自己专门实现一个 Pass,这是因为 Fallback 使用的内置 Shader 中包含了这样一个通用的 Pass,因此,为每个 UnityShader 正确设置 Fallback 是非常重要的

ShaderLab还有其他的语义吗

  除了上述的语义,还有一些不常用到的寓意。

  例如:如果不满足于 Unity 内置的属性类型,想要自定义材质面板的编辑界面,就可以使用 CustomEditor 语义来拓展编辑界面。还可以使用 Category 语义来对 UnityShader 中的命令进行分组。

UnitySahder 的形式

  尽管 UnityShader 可以做的事情很多(例如设置渲染状态等),但其最重要的任务还是指定各种着色器所需的代码。这些着色器代码可以写在 SubShader 语义块中(表面着色器的做法),也可以写在 Pass 语义块中(顶点/片元着色器和固定函数着色器的做法)

  在 Unity 中,可以使用下面 3 种形式来编写 UnityShader,而不管使用哪种形式,真正意义上的 Shader 代码都需要包含在 ShaderLab 语义块中,如下所示:

Shader "MyShader"{
    Properties{
        //所需的各种属性
    }

    SubShader{
        //真正意义上的 Shader 代码会出现在这里
        //表面着色器{Surface Shader}或者
        //顶点/片元着色器{Vertex/Fragment Shader}或者
        //固定函数着色器{Fixed Function Shader}
    }

    SubShader{
        //和上一个 SubShader 类似
    }
}

表面着色器

  表面着色器(Surface Shader) 是 Unity 自己创造的一种着色器代码类型,他需要的代码量很少,Unity 在背后做了很多工作,渲染的代价比较大。

  本质上和顶点/片元着色器是一样的,当给Unity提供一个便面着色器的时候,在背后仍旧需要把它装换成对应的顶点/片元着色器

  它的价值在于:Unity 处理了很多光照细节,不需要去操心这些“烦人的事情”

  示例代码如下:

Shader "Custom/Simple Surface Shader"{
    SubSHader{
        Tags{"RenderType"="Opaque"}
        CGPROGAM
        #pragma surface surf Lambert
        struct Input{
            float4 color : COLOR;
        };
        void surf(Input IN,inout SurfaceOutput o){
            o.Albedo = 1;
        }
        ENDCG
    }
    Fallback "Diffuse"
}

  表面着色器被定义在 SubShader 语义块(不是 Pass 语义块)中的 CGPROGRAM 和 ENDCG 之间

  原因是表面着色器不需要开发者关心使用多少个 Pass,每个 Pass 如何渲染等问题,Unity 会在背后做好这些事情

  CGPROGRAM 和 ENDCG 之间的代码是使用 Cg/HLSL 编写的,也就是说,需要把 Cg/HLSL 语言嵌套在 ShaderLab 语言中

  这里的 Cg/HLSL 是 Unity 经封装后提供的,它的语法和标准的 Cg/HLSL 语法几乎一样,但还是有细微的不同

顶点/片元着色器

  Unity 中可以使用 Cg/HLSL 语言来编写顶点/片元着色器(Vertex/Fragment Shader)。它们更加复杂,但灵活性更高

  示例代码如下:

Shader "Custom/Simple VertexFragment Shader"{
    SubShader{
        Pass{
            CGPROGRAM

            #progama vetex vert
            #pragma fragment frag

            float4 vert(float4 v : POSITION) : SV_POSITON{
                return mul(UNITY_MATRIX_MVP,v);
            }

            fixed4 frag() : SV_Target{
                return fixed4(1.0,0.0,0.0,1.0);
            }

            ENDCG
        }
    }
}

  顶点/片元着色器的代码需要定义在 CGPROGRAM 和 ENDCG 之间,不同的是,顶点/片元着色器是写在 Pass 语义块内,而非 SubShader内的

  这样的原因是,需要自己定义每个 Pass 需要使用的 Shader 代码,虽然可能需要编写更多的代码,但好处是灵活性很高,更重要的是,可以空时渲染的实现细节

固定函数着色器

  对于一些较旧的设备(其GPU仅支持 DirectX 7.0、OpenGL 1.5 或 OpenGL ES 1.1),它们不支持可编程管线着色器,因此,这时候就需要使用固定函数着色器(Fixed Function Shader) 来完成渲染。这些着色器网网址可以完成一个非常简单的效果

  示例代码如下:

Shader "Tutorial/Basic"{
    Properties{
        _Color("Main Color",Color} = {1,0.5,0.5,1}
    }
    SubShader{
        Pass{
            Material{
                Diffuse [_Color]
            }
        }
    }
}

  固定着色器的代码被定义在 Pass 语义块中,这些代码相当于 Pass 中的一些渲染设置

  对于固定函数着色器来说,需要完全使用 ShaderLab 的语法(使用 ShaderLab 的渲染设置命令)来编写,而不是使用 Cg/HLSL

  由于现在绝大多数 GPU 都支持可编程的渲染管线,这种编程方式已经被逐渐抛弃,在新版的 Unity 中,所有固定函数着色器都会在背后被 Unity 编译成对应的顶点/片元着色器

选择哪种 UnityShader 形式

  如果有非常明确的需求必须要使用固定函数着色器,否则使用可编程管线的着色器,即表面着色器或顶点/片元着色器

  如果要和各种光源打交道,可能更需要使用表面着色器,但需要小新在移动平台中的性能表现

  如果需要使用的光照数目非常少,那么使用顶点/片元着色器使一个更好的选择

  如果有很多自定义的渲染效果,使用顶点/片元着色器

其他的一些问题

UnityShader != 真正的Shader

  尽管UnityShader翻译过来就是Unity着色器,在Unity里,UnityShader实际上指的就是一个ShaderLab文件——硬盘上以.shader作为文件后缀的一种文件

  在UnityShader里,可以做的事情远多于一个传统意义上的Shader

    传统的Shader中,仅可以编写特定类型的Shader,例如顶点着色器、片元着色器等,在UnityShader中,可以在同一个文件里同时包含需要的顶点着色器和片元着色器代码

    在传统的Shader中,无法设置一些渲染设置,例如是否开启混合、深度测试等,这些是开发者在另外的代码中自行设置的。而在UnityShader中,通过一行特定的指令就可以完成这些设置

    在传统的Shader中,我们需要编写荣昌的代码来设置着色器的输入和输出,要小心的处理这些输入输出的位置对应关系等。而在UnityShader中,只需要在特定的语句块中生命一些属性,就可以依靠材质来方便的改变这些属性。而且对于模型自带的数据(如定点位置、纹理坐标、法线等),UnityShader也提供了直接访问的方法,不需要开发者自行编码来传给着色器

  UnityShader出了上述这些优点外,也有一些缺点。

    由于UnityShader的高度封装性,可以编写的Shader类型和语法都被限制了。对于一些类型的Shader,例如曲面细分着色器(Tessellation Shader)、几何着色器(Geometry Shader)等,Unity的支持就相对差一些。例如:Unity 4.x 仅在 DirectX 11平台下提供曲面细分着色器、几何着色器的相关功能,而对于OpenGL平台则没有这些支持。除此之外,一些高级的Shader语法UnityShader也不支持

  可以说,UnityShader提供了一种让开发者同时控制渲染流水线中多个阶段的一种方式,不仅仅是提供Shader代码。作为开发者而言,绝大部分时候只需要和UnityShader打交道,而不需要关心渲染引擎底层的实现细节

UnityShader和Cg/HLSL之间的关系

  UnityShader是用ShaderLab语言编写的,但对于表面着色器和顶点/片元着色器,可以在ShaderLab内部嵌套Cg/HLSL语言来编写这些着色器代码。这些Cg/HLSL代码是嵌套在 CGPROGRAM 和 ENDCG 之间的。由于Cg和DX9风格的HLSL从写法上来说几乎是同一种语言,因此在Unity里Cg和HLSL是等价的。可以说,Cg/HLSL代码是区别于ShaderLab的另一个世界

  通常,Cg的代码片段是位于Pass语义块内部的,如下所示

Pass{
    //Pass的标签和状态设置

    CGPROGRAM
    //编译指令,例如:
    #pragma vertex vert
    #pragma fragment frag

    //Cg代码

    ENDCG
    //其他一些设置
}

  在提供给编程人员这些便利的背后,Unity编辑器会把这些Cg片段编译成低级语言,如汇编语言等。同城,Unity会自动把这些诶Cg片段编译到所有相关平台(这里的平台是指不同的渲染平台,如Dirext3D 9、OpenGL、Direct3D 11、OpenGL ES等)上。这些编译过程比较复杂,Unity会使用不同的编译器来吧Cg转换成对应平台的代码。这样就不会在切换平台时再重新编译,而且如果代码在某些平台上发生错误就可以立刻得到错误信息。

  可以在UnityShader的导入设置面板上查看这些编译后的代码,查看这些代码有助于进行Debug或优化等

  如图:

在UnityShader的导入设置面板中可以通过Compile and show code按钮来查看Unity对Cg片段编译后的代码,通过单击Compile and show按钮右侧的倒三角可以打开下拉菜单,在这个下拉菜单中可以选择变异的平台种类,如职位当前的显卡设备编译特定的汇编代码,或为所有的平台编译汇编代码,也可以自定义选择编译到哪些平台上
  但当发布游戏的时候,游戏数据文件中质保函目标平台需要的编译代码,而那些在目标平台上不需要的代码部分就会被移除。例如,当发布到Mac OS X平台上时,DirectX对应的代码部分就会被移除。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1852994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AcWing算法基础课笔记——求组合数4

求组合数Ⅳ 用来解决求 C a b C_a^b Cab​的问题(没有模运算) 解决办法:分解质因数,实现高精度乘法。 C a b a ! b ! ( a − b ) ! C_a^b \frac{a!}{b!(a - b)!} Cab​b!(a−b)!a!​ 其中 a ! a! a!可以用 p p p的倍数来表示…

自动驾驶仿真:Carsim转向传动比设置

文章目录 一、转向传动比概念二、设置转向传动比1、C factor概念2、Steer Kinematics概念3、传动比计算公式 三、转向传动比验证 一、转向传动比概念 转向传动比(Steering Ratio)表示方向盘转动角度与车轮转动角度之间的关系。公式如下: 转向…

计算机网络 动态路由OSPF

一、理论知识 1.OSPF基本概念 ①OSPF是一种链路状态路由协议,使用Dijkstra算法计算最短路径。 ②OSPF使用区域(Area)来组织网络,区域0(Area 0)是主干区域。 ③路由器通过通告直连网络加入OSPF域。 ④反…

QT中制作带有界面的静态库

1、可参考以下文章 QT中制作带有界面的动态库 2、相比动态库,静态库就更简单了,,, 1)创建静态库项目 2)直接右键创建同名窗口类进行覆盖 3)编译生成静态库 4)使用

人工智能导论笔记

目录 ​编辑 绪论篇 有关知识表示和推理的零碎知识点 机器学习篇 K-近邻算法(KNN) 人工神经网络与深度学习篇 人工神经元模型 人工神经网络 BP神经网络 卷积神经网络 搜索策略 状态空间表示法 盲目搜索 启发式图搜索策略 绪论篇 3个学派&a…

实战篇:GY-906红外测温模块 + 万年历(定时器计数中断版本) -STM32篇

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布: https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…

视频批量剪辑新境界:一键转码MP4至MP3并自动删除原文件,轻松优化存储空间与播放体验

随着数字媒体的飞速发展,视频文件已成为我们生活中不可或缺的一部分。然而,大量视频文件的累积不仅占据了宝贵的存储空间,而且在某些情况下,我们更希望提取视频中的音频内容。为了满足这一需求,我们推出了全新的视频批…

LLVM——安装多版本LLVM和Clang并切换使用(Ubuntu)

1、描述 本机(Ubuntu22)已经安装了LLVM-14,但是需要使用LLVM-12。安装LLVM-12和Clang-12并切换使用。 2、过程 安装LLVM-12和Clang-12。 sudo apt-get install llvm-12 sudo apt-get install clang-12 【注】运行 sudo apt-get install ll…

django学习入门系列之第三点《CSS基础样式介绍2》

文章目录 文字对齐方式外边距内边距往期回顾 文字对齐方式 水平对齐方式 text-align: center;垂直对齐方式 /* 注意&#xff0c;这个只能是一行来居中 */ line-height:/*长度*/ ;样例 <!DOCTYPE html> <html lang"en"> <head><meta charset…

【Oracle】实验一 安装和使用Oracle数据库

【实验目的】 掌握Oracle软件安装过程&#xff0c;选择安装组件掌握建立Oracle数据库&#xff0c;配置网络连接使用SQL*Plus&#xff0c;登录到实例和数据库掌握命令方式的关闭和启动实例及数据库 【实验内容】 安装Oracle19c&#xff0c;记录安装过程。切记&#xff1a;创建…

Jenkins定时构建自动化(二):Jenkins的定时构建

目录 ​编辑 一、 jenkins定时构建语法&#xff1a; 1. 语法规则&#xff1a; 2. 常见用法举例 3. 再次举例 接上一篇&#xff1a;Jenkins定时构建自动化(一)&#xff1a;Jenkins下载安装配置&#xff1a;Jenkins定时构建自动化(一)&#xff1a;Jenkins下载安装配置-CSDN博客 …

HTML静态网页成品作业(HTML+CSS)——故宫介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

【教学类-36-09】20240622钓鱼(通义万相)-A4各种大小的鱼

背景需求&#xff1a; 用通义万相获得大量的简笔画鱼的图片&#xff0c;制作成不同大小&#xff0c;幼儿用吸铁石钓鱼的纸片&#xff08;回形针&#xff09;&#xff0c;涂色、排序等 补一张通义万相的鱼图 素材准备 &#xff08;一&#xff09;优质的鱼图片 &#xff08;二&a…

(2024)豆瓣电影TOP250爬虫详细讲解和代码

&#xff08;2024&#xff09;豆瓣电影TOP250爬虫详细讲解和代码 爬虫目的 获取 https://movie.douban.com/top250 电影列表的所有电影的属性。并存储起来。说起来很简单就两步。 第一步爬取数据第二步存储 爬虫思路 总体流程图 由于是分页的&#xff0c;要先观察分页的规…

VS Code安装及环境配置(超详细)

VS Code简介 Visual Studio Code&#xff08;简称 VS Code &#xff09;是 Microsoft 于2015年4月发布的一款代码编辑器&#xff0c;以界面简洁、轻量著称。 它是一款免费开源的现代化轻量级代码编辑器&#xff0c;支持几乎所有主流开发语言的语法高亮、智能代码补全、自定义…

投票多功能小程序(ThinkPHP+Uniapp+FastAdmin)

&#x1f389;你的决策小助手&#xff01; 支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c;Uniapp提供全部无加密源码。​ 一、引言&#xff1a;为什么我们需要多功能投票小程序&#…

1. ELK日志分析

ELK日志分析 一、ELK作用、组件1、作用2、核心组件2.1 beat软件2.1 Logstash2.2 Elasticsearch2.3 Kibana 二、ELK部署、测试1、环境规划2、确保SELinux关闭、时间同步3、所有主机添加主机名解析4、三台ES主机安装jdk 1.155、调整系统资源限制6、部署es集群6.1 创建普通用户elk…

HMI 的 UI 风格,超凡脱俗

HMI 的 UI 风格&#xff0c;超凡脱俗

“Driver not loaded“问题解决方案

这两天又碰到了离谱的&#xff0c;愚蠢的&#xff0c;莫名其妙的&#xff0c;丧尽天良的错误。 之前已经解决过这个问题。这几天又碰上了&#xff0c;明明都已经把相应的dll放到了exe的同级目录&#xff0c;NND还是有问题&#xff01;&#xff01;&#xff01;卡了我一个晚上加…

【服务器】之【如何不开外网连接GitHub】

登录GitHub官网 GitHub: Let’s build from here GitHub 注册账号 登录账号 输入一个自定义名字&#xff0c;点击创建存储库就可以了 首先 如何在不开外网的条件下使用GitHub 第一步 下载安装Steam(Watt TooklKit) 区分一下如何查看哪个官网&#xff08;没有百度广告就是…