UnityShader入门精要-3.5 UnityShader的形式

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

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

Shader "MyShader"{
  Properties{
    //所需的各种属性
  }
  SubShader{
    //真正意义上的Shader代码会出现在这里
    //表面着色器(Surface Shader)或者
    //定点/片元着色器(Vertex/Fragment Shader)或者
    // 固定函数着色器 (Fixed Function Shader)
  }
  SubShader{
     //和上一个SubShader类似
  }
}
  1. 表面着色器

表面着色器(Surface Shader)是Unity自己创造的一种着色器代码类型。它需要的代码量很小,Unity在背后做了很多工作,但渲染的代价比较大。它在本质上和下面要讲到的定点/片元着色器是一样的。也就是说,当Unity提供一个表面着色器的时候,它在背后仍旧把它转换成对应的顶点/片元着色器。我们可以理解成,表面着色器是Unity对顶点/片元着色器的更高一层的抽象。它存在的价值在于,Unity为我们处理了很多光照细节,使得我们不需要操心这些“烦人的事情”。

一个非常简单的表面着色器的示例代码如下:

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

从上述程序中可以看出,表面着色器被定义在SubShader语义块(而非Pass语义块)中的CGPROGAM和ENDCG之间。原因是,表面着色器不需要开发者关心使用多少个Pass、每个Pass如何渲染等问题,Unity会在背后为我们做好这些事情,我们只要告诉他:“嘿!使用这些纹理去填充颜色,使用这个法线纹理去填充法线,使用Lambert光照模型,其他的事情不要来烦我!”。

CGPRORAM和ENDCG之间的代码使用CG/HLSL编写的,也就是说,我们需要把CG/HLSL语言嵌套在ShaderLab语言中。值得注意的是,这里的CG/HLSL是Unity经封装后提供的,他的语法和标准的CG/HLSL语法几乎一样,但还是有细微的不同,例如有些原生的函数和用法Unity并没有提供支持。

2。最聪明的孩子:定点/片元着色器

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

一个非常简单的顶点/片元着色器示例代码如下:

Shader "Custom/Simple VertexFragment Shader"{
    SubShader{
        Pass{
            CGPROGRAM
                #prama vertex vert
                #prama fragment frag
                float4 vert (float4 v : POSITION) : SV_POSITION{
                    return mul (UNITY_MATRIX_MVP ,  v);
                }

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

    }
}

和表面着色器类似,顶点/片元着色器的代码也需要定义在CGPROGRAM和ENDCG之间,但不同的是,顶点/片元着色器是写在Pass语义块内,而非SubShader内的,原因是,我们需要自已定义每个Pass需要使用的Shader代码。虽然我们可能需要编写更多的代码,但带来的好处是灵活性很高,更重要的是,我们可以控制渲染的实现细节,同样这里的CGPROGRAM和ENDCG之间的代码也是使用CG/HLSL编写的。

3. 被抛弃的角落:固定函数着色器

上面两种Unity Shader 形式都使用了可编程管线。而对于一些较旧的设备(其CPU仅支持DirectX7.0、OpenGL 1.5 或 OpenGL ES 1.1),例如iPhone3,他们不支持可编程管线着色器,因此,这时候我们就需要使用固定函数着色器(Fixed Function Shader)来完成渲染。这些着色器往往可以完成一些非常简单的效果。

一个非常简单的固定函数着色器示例代码如下:

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

可以看出,固定函数着色器的代码被定义在Pass语义块中,这些代码相当于Pass中的一些渲染设置,正如我们之前提到的一样。

对于固定函数着色器来说,我们需要完全使用ShaderLab的语法(即 使用ShaderLab的渲染设置命令) 来编写,而非使用 CG/HLSL。

由于现在大多数GPU都支持可编程的渲染管线,这种固定管线的编程方式已经逐渐被抛弃。实际上,在Unity5.2中,所有固定函数着色器都会在背后被Unity编译成对应的顶点/片元着色器,因此真正意义上的固定函数着色器已经不存在了。

对于选择Shader  的一些建议。

  • 除非你有非常明确的需求必须要使用固定函数着色器,例如需要在非常旧的设备上运行你的游戏(这些设备非常少见),否则请使用可编程管线的着色器,即表明着色器或顶点/片元着色器。
  • 如果你想和各种光源打交道,你可能更喜欢使用表明着色器,但需要小心他在移动平台的性能表现。
  • 如果你需要使用的光照数目非常少,例如只有一个平行光,那么使用顶点/片元着色器是一个更好的选择。
  • 最重要的是如果你有很多自定义的渲染效果,那么请选择顶点/片元着色器。
时间: 2024-10-10 04:16:01

UnityShader入门精要-3.5 UnityShader的形式的相关文章

UnityShader入门精要-3.3 UnityShader的结构

一个UnityShader的基础结构如下所示: Shader "ShaderName"{ Properties{ //属性 } SubShader{ //显卡A使用的子着色器 } SubShader{ //显卡B使用的子着色器 } Fallback "VertexLit" } Unity在背后根据使用的平台来吧这些结构编译成真正的代码和Shader文件,开发者只需要和UnityShader打交道即可.(Unity编写Shader的语言是ShaderLab) 属性:在

「UnityShader入门精要」第二章 渲染流水线

2.3 GPU流水线 2.3.2 顶点着色器 输入来自于CPU,处理顶点数据.输入的每个顶点都会调用一次顶点着色器,所以每次都是对单个顶点进行运算. 主要任务:坐标变换.逐顶点光照. 坐标变换:修改顶点的位置,例如模拟水面波纹效果.果冻效果等. 必须完成的工作,把顶点坐标从模型空间转换到齐次裁剪空间. 常见的如:o.pos = mul(UNITY_MVP, v.position); 2.3.3 裁剪 摄像机视野有限,视野外的物体不需要被处理,可以直接裁剪掉. 2.3.4 屏幕映射 将单位立方体内

UnityShader入门精要-第二章 渲染流水线笔记

渲染流程包括:应用阶段.几何阶段和光栅化阶段. 1.应用阶段 应用阶段是由我们的应用主导的,通常由CPU负责. 在这一阶段开发者有三个主要任务 首先 需要准备好场景的数据. 其次  为了提高渲染的性能,我们往往要做一个粗粒度剔除,把那些看不见的物体剔除出去,这样就不需要交给几何阶段去处理. 最后需要设置好每个模型的渲染状态.这些渲染状态包括但不仅限于它使用的材质(漫反射的颜色.高光反射的颜色).使用的纹理.使用的shader等.这一阶段最重要的是输出渲染所需要的几何信息,即渲染图元.渲染图元可以

Unity Shader入门精要读书笔记(一)序章

本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数学基础. 第五章:利用简单的顶点/片元着色器来实现辅助技巧. 第六章:基本光照模型. 第七章:法线纹理.遮罩纹理等基础纹理. 第八章:透明度测试和透明度混合. 第九章:复杂光照实现. 第十章:高级纹理(立方体纹理等). 第十一章:纹理动画.顶点动画. 第十二章:屏幕特效. 第十三章:深度纹理. 第十四章:非真

Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础

摘录自 冯乐乐的<Unity Shader入门精要> 笛卡尔坐标系 1)二维笛卡尔坐标系 在游戏制作中,我们使用的数学绝大部分都是计算位置.距离.角度等变量.而这些计算大部分都是在笛卡尔坐标系下进行的. 一个二维的笛卡尔坐标系包含了两个部分的信息: 一个特殊的位置,即原点,它是整个坐标系的中心. 两条过原点的互相垂直的矢量,即X轴和Y轴.这些坐标轴也被称为是该坐标的矢量. OpenGL 和 DirectX 使用了不同的二维笛卡尔坐标系.如下图所示: 2)三维笛卡尔坐标系 在三维笛卡尔坐标系中,

Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向. 最后,摄像机吸收了一些光,产生了一张图像. 在光学中,我们使用辐照度来量化光.对于平行光来说,它的辐照度可通过计算在垂直于l的单位面积上单位时间内穿过的能量来得到.在计算光照模型时,我们需要知道一个物体表面的辐照度,而物体表面往往是和l不垂直的,我们可以

Lucene入门精讲视频教程

课程目录:1.Lucene-全文检索是什么?2.Lucene-流程之原生文档3.Lucene-流程之创建文档对象4.Lucene-流程之分析文档5.Lucene-流程之创建索引6.Lucene-入门创建索引7.Lucene-全文检索搜索8.Lucene-入门查询索引9.Lucene-中文第3方插件分析器(IK分析器)10.Lucene-索引库删除11.Lucene-索引库修改12.Lucene-索引库查询(Query子类查询)13.Lucene-索引库查询(解析语法查询)14.Lucene-索引

Hibernate入门精讲

学习Hibernate ,我们首先要知道为什么要学习它?它有什么好处?也就是我们为什么要学习框架技术? 还要知道    什么是Hibernate?    为什么要使用Hibernate?    Hibernate的配置文件的作用是什么?          Hibernate映射文件的作用是什么?     Hibernate持久化对象的状态有哪些? 现在我先上面的问题解决了. 一.我们为什么要学习框架技术? 1.框架技术有哪些? 在Java开发中,我们经常使用Struts.Hibernate和Sp

ModelSim仿真入门 精讲

ModelSim仿真入门之一:软件介绍 编写这个教程之前,为了让不同水平阶段的人都能阅读,我尽量做到了零基础入门这个目标,所有的操作步骤都经过缜密的思考,做到了详细再详细的程度. 如果您是FPGA开发方面的初学者,那么这个教程一定能够帮助你在仿真技术上越过新人的台阶:如果您是FPGA开发的老手,这篇文档也并非对您没有帮助,您可以把教程发给其他刚入门的同事,免去您亲自上阵指导的麻烦,把主要的精力放在更有价值的地方. 一.FPGA设计仿真验证简介 严格来讲,FPGA设计验证包括功能仿真.时序仿真和电