Shader编程学习笔记(七)—— Surface shader 1

Surface shader

  本小结对Unity的Surface Shader做一个大概的了解。主要了解在Surface Shader当中比较重要的几个部分,分别是:

  • SurfaceOutput
  • Input
  • lighing
  • shadow

  首先查看一下Unity的官方手册中的Writing Surface Shaders,其中描述道:如果要编写一个shader去和光进行交互是比较复杂的,因为光照会有不同的光照类型,不同的阴影选项和不同的渲染路径(包括foward和deferred rendering等),因此shader需要找到处理这些复杂事物的方法。

  在使用Surface Shader时,它可以自动生成一些代码,比直接去使用低阶的顶点和像素着色器来说要容易许多。但是需要注意的是Surface Shader并不是一种定制的语言,也不是一种神奇的东西,它只不过自动生成了以前必须去手写的代码。Surface Shader还是使用Cg或HLSL语言编写。在前面课程当中,已经初步解到,Surface Shader实际上就是对顶点和像素着色器的一种包装,它让我们不用去关注更多的顶点和片段程序的细节,能够快速地得到想要的着色器。接下来试着编写一些Surface Shader程序。

  创建一个默认的Surface Shader,如下:

 1 Shader "Lesson/SurfaceShader1" {
 2     Properties {
 3         _Color ("Color", Color) = (1,1,1,1)
 4         _MainTex ("Albedo (RGB)", 2D) = "white" {}
 5         _Glossiness ("Smoothness", Range(0,1)) = 0.5
 6         _Metallic ("Metallic", Range(0,1)) = 0.0
 7     }
 8     SubShader {
 9         Tags { "RenderType"="Opaque" }
10         LOD 200
11
12         CGPROGRAM
13         // Physically based Standard lighting model, and enable shadows on all light types
14         #pragma surface surf Standard fullforwardshadows
15
16         // Use shader model 3.0 target, to get nicer looking lighting
17         #pragma target 3.0
18
19         sampler2D _MainTex;
20
21         struct Input {
22             float2 uv_MainTex;
23         };
24
25         half _Glossiness;
26         half _Metallic;
27         fixed4 _Color;
28
29         void surf (Input IN, inout SurfaceOutputStandard o) {
30             // Albedo comes from a texture tinted by color
31             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
32             o.Albedo = c.rgb;
33             // Metallic and smoothness come from slider variables
34             o.Metallic = _Metallic;
35             o.Smoothness = _Glossiness;
36             o.Alpha = c.a;
37         }
38         ENDCG
39     }
40     FallBack "Diffuse"
41 }

  首先来了解一下这个Shader结构。这个Shader在Properties中有四个属性:

  • _Color为颜色值。
  • _MainTex是主纹理。
  • _Glossiness是一个浮点值,用于计算高光的光泽度。
  • _Metallic也是一个浮点值,用于计算表现金属的光泽度。

  该shader有一个SubShader,但是,在这个SubShader中并没有Pass通道。这里需要注意的是,在Surface Shader当中不需要去编写Pass通道,原因是Surface Shader就是对Vertex & Fragment Shader的一种包装,它能够在自动生成着色器代码,生成的过程不需要我们干预,Pass通道也能自动生成,因此,如果添加了Pass通道,就会出现编译错误。最后,作为ShaderLab的基本结构,该默认的Surface Shader拥有一个FallBack,如果shader中的某一种特性不能够被使用,那么会回滚到Diffuse。

  接下来重点了解一下SubShader拥有哪些内容。其中“Tags { "RenderType"="Opaque" }”描述的是渲染类型,“Opaque”表示不透明的物体;“LOD 200”是指层级细节;“CGPROGRAM”到“ENDCG”是一个代码块,表示其中使用Cg语法,要真正地学会Surface Shader编程,有必要先学会Cg语言,不过现在可以简单地从Surface Shader的结构出发,基本了解一下Surface Shader的内容。

  首先“#pragma surface surf Standard fullforwardshadows”是Surface Shader当中比较重要的一部分。“pragma”是一个编译指令,这个编译指令有具体的格式,可以从Unity官方手册中了解一下有关的内容,其格式为:“#pragma surface surfaceFunction lightModel [optionalparams]”。

  • 以“#”开头,“surface”关键词表示该shader以Surface Shader格式来编写,Unity引擎在处理这个shader结构的时候,就会自动地进行编译低阶的代码。
  • “surfaceFunction”是指surface的函数,在一定条件下可以随便取名,在默认创建的Surface Shader中的"surf"就是函数名,下面也有对应的函数体。
  • “lightModel”描述的是光照模型,在默认创建的Surface Shader中使用的是“Standard”,那么这个光照模型实际上也是一个函数,我们可以在Unity(5.0以上)的安装目录上找到一个光照的代码文件"UnityPBSLighting.cginc",其中的函数“LightingStandard”,其中“Lighting”后的名称是我们真正使用的函数名。
  • “[optionalparams]”表示其他的一些选项,默认Surface Shader使用的是“fullforwardshadows”,从字面上理解是关于阴影的一些功能,查看Unity手册可以了解到默认使用的“fullforwardshadows”表示它能够在Forward渲染路径下支持所有的阴影类型,默认的shader仅仅能支持一个方向光的阴影,如要在Forward渲染路径下使用点光源或聚光灯产生的阴影就需要使用该指令。这里需要注意的是,在其上还有一个“addshadow”指令,它的主要功能就是生成一个阴影投射器,在现目前的代码当中也可以直接使用“addshadow”。

  接下来在工程中实际使用一下这个shader。

  创建一个材质并使用该shader,然后在场景中创建一个Cube当做地面,在其上创建一个Sphere,并使用我们创建的材质,可以看到球体的检视面板中已经拥有了shder当中编写的四个属性:“Color”是颜色,默认为白色;“Albedo (RGB)”是主纹理,这里先拖放一张贴图;“Smoothness”是平滑度,描述的是高光的强度;“Metallic”表示的是金属质感,调整这个系数可以修改金属质感的强度,金属质感原理就是如果光照射非常光滑的金属物体,有镜面反射的部分光会很集中,形成高亮,没有镜面反射的地方就会很暗淡。效果如图:

  以上就是对该shader的基本使用。

  接下来在该shader中,“#pragma target 3.0”表示我们将要对这个着色器使用硬件的“shader model 3.0”的能力,硬件的“shader model”是硬件一个用于着色处理的基础的指令范围和能力,值越高表示能使用越高级的功能,如果没有使用“#pragma target 3.0”这句指令,默认使用的是“shader model 2.0”。

  “sampler2D”是一个二维纹理,这里表示该shader的主纹理参数。

 struct Input {
   float2 uv_MainTex;
 };

  之后的Input结构体,用于描述纹理的uv坐标,查看Unity文档,在"Surface Shader input structure"目录中,关于这个纹理坐标,必须以“uv”或“uv2”开头,使用“uv”表示用第一套uv坐标集合,用“uv2”表示第二套uv坐标集合。因此,如果在Properties中使用类似"_MainTex"纹理属性,就需要在SubShader中的一个输入结构体当中必须以“uv”开头的变量,否则就得不到该纹理采样值。

  除了Input结构体之外,在CGPROGRAM要对Properties中的属性做对应的声明。两者的类型不一样,“2D”对应“sampler2D”,“Range”对应“half”,“Color”对应“fixed4”。

时间: 2024-08-06 04:25:08

Shader编程学习笔记(七)—— Surface shader 1的相关文章

Shader编程学习笔记(八)—— Surface Shader 2

Surface Shader 上一小结主要了解了Surface Shader使用了“#pragma surface surf Standard fullforwardshadows”指令的意义,这一小节主要了解“surf”surface函数. void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex,

Shader编程学习笔记(四)——Unity Shader的组织形式(ShaderLab)

Unity Shader的组织形式 Unity Shader的形态 Unity官方手册上讲Unity Shader有三种不同的编写方案,这三种编写方案分别是surface shaders.vertex and fragment shaders和fixed function shaders. 从前面几篇笔记中可以了解到,可编程图形管线中能够编写shader的主要是两个部分:vertex shader和fragment shader,但Unity还有surface shaders和fixed fun

Shader编程学习笔记(三)——三大主流编程语言 HLSL/GLSL/Cg

三大主流编程语言 HLSL/GLSL/Cg Shader Language Shader Language的发展方向是设计出在便携性方面可以和C++.Java等相比的高级语言,“赋予程序员灵活而方便的编程方式”,并“尽可能的控制渲染过程”同时“利用图形硬件的并行性,提高算法效率”. Shader Language目前主要有3种语言:基于OpenGL的OpenGL Shading Language,简称GLSL;基于DirectX的High Level Shading Language,简称HLS

Shader编程学习笔记(一)—— 图形硬件简史与可编程管线

图形处理器(GPU)简史 GPU发展简史 GPU英文全称Graphic Processing Unit,中文翻译为“图形处理器”,在现代计算机系统中的作用变得越来越重要. 20世纪六.七十年代,受硬件条件的限制,图形显示器只是计算机输出的一种工具.限于硬件发展水平,人们只是纯粹从软件实现的角度来考虑图形用户界面的规范问题.此时还没有GPU的概念. GPU概念在20世纪70年代末和80年代初被提出,使用单片集成电路(monolithic)作为图形芯片,此时的GPU被用于视频游戏和动画方面,它能够很

Shader编程学习笔记(二)—— Shader和渲染管线

Shader和渲染管线 什么是Shader Shader,中文翻译即着色器,是一种较为短小的程序片段,用于告诉图形硬件如何计算和输出图像,过去由汇编语言来编写,现在也可以使用高级语言来编写.一句话概括:Shader是可编程图形管线的算法片段. 它主要分为两类:Vertex Shader和Fragment Shader. 什么是渲染管线 渲染管线也称为渲染流水线,是显示芯片内部处理图形信号相互独立的并行处理单元.一个流水线是一序列可以并行和按照固定顺序进行的阶段.就像一个在同一时间内,不同阶段不同

DirectX 11游戏编程学习笔记之7: 第6章Drawing in Direct3D(在Direct3D中绘制)(重点回顾+勘误)

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题欢迎联系[email protected]         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候,会使用章节号而非页码.同样的情况适合于"龙书"第二版. 上一期的地址: DX 11游戏编程学习笔记之6 这一章应该是本书最长的一章了,可能也是最难的一章,所以大家一定要好好消化,仔细学习!这一章大致相当于"龙书"第二版的第7章和第8章,还添加了一些别的东西. 由于这一

Lua学习笔记(七):迭代器与泛型for

1.迭代器与闭包 迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素.在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素. 迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,也就是他知道来自于哪里和将要前往哪里.闭包提供的机制可以很容易实现这个任务.记住:闭包是一个内部函数,它可以访问一个或者多个外部函数的外部局部变量.每次闭包的成功调用后这些外部局部变量都保存他们的值(状态).当然如果要创建一个闭包必须要创建其外部局部变量.所以一个典型的闭包的结构包含

Linux System Programming 学习笔记(七) 线程

1. Threading is the creation and management of multiple units of execution within a single process 二进制文件是驻留在存储介质上,已被编译成操作系统可以使用,准备执行但没有正运行的休眠程序 进程是操作系统对 正在执行中的二进制文件的抽象:已加载的二进制.虚拟内存.内核资源 线程是进程内的执行单元 processes are running binaries, threads are the smal

多线程编程学习笔记——线程同步(三)

接上文 多线程编程学习笔记——线程同步(一) 接上文 多线程编程学习笔记——线程同步(二) 七.使用Barrier类 Barrier类用于组织多个线程及时在某个时刻会面,其提供一个回调函数,每次线程调用了SignalAndWait方法后该回调函数就会被执行. 1.代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; //