Unity Shaders学习笔记之表面着色器

Posted 程序员小毛驴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity Shaders学习笔记之表面着色器相关的知识,希望对你有一定的参考价值。

一、表面着色器

   1.1 简介

  表面着色器代码直接在SubShader中编写,不需要使用Pass,编译器会将代码编译到合适的Pass中

   1.2 标签 

  硬件将通过判定标签来决定什么时候调用该着色器

  属性RenderType:
  值Opaque:在渲染非透明物体时调用
  值Transparent:表示渲染含有透明效果的物体时调用
  例:Tags "RenderType"="Opaque"

   1.3 申明变量

#pragma surface surfaceFunction lightModel [optionalparams] //声明写一个表面Shader


名字 说明
surface 申明这是表面着色器
surfaceFunction 着色方法的名字,如surf,在下面会出现surf函数
lightModel 使用的光照模型,如Lambert(就是普通的diffuse)

顶点处理函数 -> 表面处理函数 -> 光照模型函数 ->颜色值
sampler2D _MainTex;

sampler2D就是GLSL中的2D贴图的类型,相应的还有sampler1D,sampler3D,samplerCube等格式

提问:在property中已经定义过_MainTex了,这里为什么又要声明一次呢?
 答:这个shader是由两个相对独立的块组成的,外层的属性、回滚等是Unity可以使用和编译的ShaderLab;CGPROGRAM...ENDCG代码块是一段CG程序。对于这段CG程序,要想访问在Properties中定义的变量,必须使用和之前变量相同的名字进行声明。sampler2D _MainTex; 再次声明并链接了_MainTex,使得接下来的CG程序能够使用这个变量

   1.4 函数定义

  在#pragma段已经指出了着色方法的名字叫做surf,这段surf代码就是着色器的工作核心。着色器就是给定了输入,然后给出输出进行着色的代码CG规定了声明为表面着色器的方法(这里是surf函数)的参数类型和名字,因此我们没有权利决定surf的输入输出参数的类型,只能按照规定写。这个规定就是第一个参数是一个Input结构,第二个参数是一个inout的SurfaceOutput结构接下来分别介绍Input、SurfaceOutput结构。

   1.5 Input结构

  Input是需要我们去定义的结构,可以把所需要参与计算的数据都放到这个Input结构中,传入surf函数使用作为输入的结构体必须命名为Inputfloat和vec都可以在之后加入一个2到4的数字,来表示被打包在一起的2到4个同类型数,如float2表示由两个float数构成的一个数据变量的访问:可以只使用名称来获得整组值,也可以使用下标的方式(比如.xyzw,.rgba或它们的部分比如.x等)来获得某个值。在CG程序中约定,在一个贴图变量(如_MainTex)之前加上uv两个字母,就代表提取它的uv值UV mapping的作用是将一个2D贴图上的点按照一定规则映射到3D模型上,是3D渲染中最常见的一种顶点处理手段。

  1.5 SurfaceOutput结构

  着色函数已经定义好了输出结构,但内容是空白的,需要向里面填写输出,这样就可以完成着色了

truct SurfaceOutput 
half3 Albedo; //像素的颜色,反射值
half3 Normal; //像素的法向值
half3 Emission; //像素的发散颜色
half Specular; //像素的镜面高光
half Gloss; //像素的发光强度
half Alpha; //像素的透明度
;
half指的是半精度浮点数,精度最低,运算性能相对比高精度浮点数高一些,因此被大量使用

  1.5 表面着色函数

  在计算输出时Shader会多次调用surf函数,每次给入一个贴图上的点坐标,来计算输出,然后把输出结构填上函数tex2d:这是CG程序中用来在一张贴图中对一个点进行采样的方法,返回一个float4。这里对_MainTex在输入点上进行了采样,并将其颜色的rbg值赋予了输出的像素颜色,将a值赋予透明度。于是,着色器就明白了应当怎样工作:即找到贴图上对应的uv点,直接使用颜色信息来进行着色Unity中cg函数的路径: C:\\ProgramFiles\\Unity\\Editor\\Data\\CGIncludes ,查看UnityCG.cginc文件

二、代码示例

1.在Unity编辑器的Project面板上,点击Assets文件,选择Create|Folder,命名为Materials 2.创建另一个文件夹Create|Shader 3.创建一个Shader文件 命名为BasicDiffuse 如下图
4.创建一个材质球 命名为BasicDiffuse 如下图

5.双击BasicDiffuse着色器,打开MonoDevelop,你会看到Unity已经为我们添加了一些基本的着色器代码。
Shader "liulongling/BasicDiffuse" 
	Properties 
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" 
		_Glossiness ("Smoothness", Range(0,1)) = 0.5
		_Metallic ("Metallic", Range(0,1)) = 0.0
	
	SubShader 
		Tags  "RenderType"="Opaque" 
		LOD 200
		
		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf Standard fullforwardshadows

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input 
			float2 uv_MainTex;
		;

		half _Glossiness;
		half _Metallic;
		fixed4 _Color;

		void surf (Input IN, inout SurfaceOutputStandard o) 
			// Albedo comes from a texture tinted by color
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			// Metallic and smoothness come from slider variables
			o.Metallic = _Metallic;
			o.Smoothness = _Glossiness;
			o.Alpha = c.a;
		
		ENDCG
	 
	FallBack "Diffuse"
6.现在我们需要给着色器一个自定义文件夹路径。着色器代码中的第一行是对着色器的自定义描述,这样我们可以在着色器的下拉列表中找到它,并且将它赋给在第四步创建BasicDiffuse材质球。如图所示:

7.选中BasicDiffuse材质球,在Inspector面板点击select,给它添加一张纹理图片


8.创建3个Sphere,我们把BasicDiffuse材质球拖到其中一个Sphere上 看看有什么效果 参考资料:
<<
Unity Shaders and Effects Cookbook>>
   作者: 小毛驴,一个游戏人 
   梦想:世界和平   
   原文地址: http://blog.csdn.net/liulongling      本博客中未标明转载的文章归作者 小毛驴所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

以上是关于Unity Shaders学习笔记之表面着色器的主要内容,如果未能解决你的问题,请参考以下文章

Unity Shaders学习笔记之为创建自定义慢反射光照模型

Unity Shaders and Effects Cookbook (6-1) 使用 alpha 参数的 半透明着色器

Unity Shaders学习笔记之通过修改UV坐标实现纹理贴图的滚动

Unity学习——纹理材质&着色器

unity3d游戏开发学习分享之表面着色器讲解

Unity Shaders学习笔记之法线贴图