Unity 3D图形学 Shader之定义属性Porperties以及使用(三)

转自零基础入门Unity Shader(四) - 知乎

由于在Unity中Shader就是运行在图形显卡上的一段包含指令的代码,所以我们需要再创建一个材质来关联它,这样才能把材质赋给场景中的物体来实现我们想要的效果。

什么是材质球:

形象来说可以比喻成人的衣服。

什么是Shader?

看到的衣服为什么是蓝色的呢?就是太阳光把其他颜色吸收了只反射出蓝色;

类比到虚拟世界里shader 决定材质跟灯光的作用,图文解释如下:

Shader与材质的关系:

  1. 一个Shader可以与无数个材质关联。
  2. 一个材质同一时刻只能关联于一个Shader。(为什么说是同一时刻,因为我们可以通过代码去动态改变材质所关联的Shader)
  3. 材质可以赋与模型,但是Shader不行。
  4. 材质就像是Shader的实例,每个材质都可以参数不一样呈现不同的效果,但是当Shader改变时,关联它的所有材质都会相应的改变。
  5. 举个例子:比如游戏中的怪物,我们只需做一个Shader,然后每个怪物给它一个材质球,材质球上赋与不同的贴图与参数来表现不同的怪物。

Porperties属性部分

上一章节介绍了Shader的大致结构,下面来细说一下Porperties属性部分。

     Properties可以理解为是材质与Shader的连接通道,我们在材质面板上需要设置的内容都必须通过Properties来实现并暴露。

Porperties属性语法格式

属性的写法有个通用的格式:

[Attribute]_Name ("Display Name",Type) = Default Value

  • Attribute

属性标记,说白了就是Unity内置的几个属性标记关键字,用于对当前这条属性进行一些特殊的处理,在下面会进行详细介绍。

此标记不是必选项,可以不添加,同时一条属性上也可以有多条属性标记。
  • _Name

属性的名称,也就是变量名,在Shader的CG代码中就是通过这个名称来调用此属性内容的,在外部利用脚本调用时也是这个名称,所以一定要用英文。

在名称前一定要加上下划线,否则会出现编绎错误!至于为什么加下划线,没有去细究原因,有知道的可以告知分享下〜

关于此变量名,有一点很重要!
就是如果此Shader有FallBack的话,一定要将此Shader中的变量名与FallBack中的变量名保持一致,否则会出现FallBack后原有的属性值获取不到的情况,切记!
  • Display Name:

显示在材质面板上的名称,主要起到说明解释的作用,可中文(正式项目中建议最好还是用英文)。

建议这里的显示名称要起的有意义,要知道最终在材质上调节的人很大部分情况下不会是你自己,别人更不可能知道每个属性内部是如何关联以及有什么作用,所以当我们TA在做完一个Shader给到使用人员的时候,一定要给他讲解一下,不管是有个说明文档还是简单沟通下都是有必要的。这样才能最大发挥Shader的使用效果,所以显示名称起着一半说明书的作用,一定要重视。
什么样的名字是有意义的呢?
作用与通道的组合(在需要说明通道的情况下)。
比如:一张基础表面色贴图,可以用"Base (RGB)",这样即说明了此贴图是基本贴图,同时又说明了此贴图在表面色上只使用到了RGB三个通道。
  • Type

属性的类型,常用的有以下几种:

  1. Color颜色
  2. Int整数
  3. Float浮点数
  4. Vector四维数
  5. 2D纹理
  6. 3D纹理
  7. Cube立方体纹理

每条属性是什么,以及在材质面板上应该显示什么都是由此类型来决定的,在下面会进行详细介绍说明。

  • Default Value

默认值,当第一次指定此Shader时,或者在材质面板上执行Reset时,属性的值会自动恢复到默认值,不同的类型具体写法也不太一样,下面会结合类型进行详细说明。

Color(类型:颜色)

示例如下:

	Properties
	{
		_Color("我是Color", Color) = (1,1,1,1)
	}

变量名:_Color

显示名称:我是Color

类型:Color

默认值:(1,1,1,1)

颜色属性是个四维分量,也就是由四个数值来组成的,每个数值代表着颜色的一个通道。四个数值依次为RGBA(红,绿,蓝,透明)。

RGB的取值是0-255(2的8次方个值域),而在Shader中被归一化为0-1间。

Shader中的浮点数值后不需要加后缀f,否则会出错。
零点几的值可以省略零,比如0.95可以写成.95

[HDR]

	Properties
	{
		[HDR]_Color("Color", Color) = (1,1,0,1)
	}

当给颜色添加了HDR后,则在材质面板中的颜色上会显示HDR的字样。同时点击颜色弹出来的取色器面板中也会多出一条Intensity的选项(2018.3版本,2017版本是Brightness)。

HDR可以使颜色亮度的值超过1,通过这个值可以配合镜头Bloom效果做出物体泛光的视觉效果。


Int(类型:整型)

示例如下:

	Properties
	{
		_Int("我是Int", Int) = 1
	}

变量名:_Int

显示名称:我是Int

类型:Int

默认值:1

虽然在材质面板中我们可以随意输入数值,比如0.55,但是在Shader内部它却只能被识别为整数。

注意,此值并不是四舍五入,而是直接取整,比如1.999,结果是1.

Float(类型:浮点数)

示例如下:

	Properties
	{
		_Float("我是Float", Float) = 0.5
	}

变量名:_Float

显示名称:我是Float

类型:Float

默认值:0.5

和Int长的很像,只不过Float中支持浮点数。

在Shader中Float是最基本的类型,而Int只是一种伪整型,从Shader精度上来讲并不存在整型。所以在Properties内完全可以用Float替代Int。

[Range]

	Properties
	{
		_Float("我是Float", Range( 0 , 1)) = 0.5
	}

很常用的一种属性标记,主要是用来将浮点数限制在一个可以通过滑动条来选择的一个区间。

将此属性中原有的Float替换成Range (Min,Max)即可,Min=最小值,Max=最大值。

[PowerSlider]

	Properties
	{
		[PowerSlider(3)]_Float("我是Float", Range( 0 , 1)) = 0.5
	}

先上张图:

我们拿它跟上面的不加PowerSlider来对比,同样是值0.5,在材质面板上滑杆的位置是不一样的。

PowerSlider (Value)

其中Value的值我们可以自由定义,支持浮点数,值越大会导致滑条的曲度变化越大,值为1时不改变。

此属性标记的主要作用,是方便用户调节滑杆。比如有个属性值是从0-1,但是很大部分情况下所用到的值都是0-0.1左右,同时需要更精细的在这区间进行微调。那么正常情况下,用户在整个滑条上想选择0-0.1之间本身就变的很难了,更不要说在这区间微调了。所以这个时候就可以利用PowerSlider来解决此问题。

[IntRange]

	Properties
	{
		[IntRange]_Float("我是Float", Range( 0 , 1)) = 1
	}

加了它之后呢,你在材质面板上拖动时就只能生成整数了。所以说我们完全可以用Float来代替Int。

注意,当添加了[IntRange]后,默认值会被自动进行处理,假如默认值你写的是0.1,则在Shader内部会自动向下取整,取值为0.

[Toggle]

开关,0代表关,1代表开,就这么简单。

	Properties
	{
		[Toggle]_Float("我是Float", Range( 0 , 1)) = 1
	}

[Enum]

枚举,美术问:啥是枚举呀?答:你可以理解为就是下拉列表啦〜

	Properties
	{
		[Enum(UnityEngine.Rendering.CullMode)]_Float("我是Float", Float) = 1
	}

关于Toggle和Enum我们会在后续的篇章中详细探讨,到时会结合具体用法与功能再来说明,这样比较好理解。这里仅仅只是知道下我们可以通过Float来实现这些功能。

Vector(类型:四维向量)

示例如下:

	Properties
	{
		_Vector("我是Vector", Vector) = (0,0,0,0)
	}

变量名:_Vector

显示名称:我是Vector

类型:Vector

默认值:0,0,0,0

由四个Float组合而成的Vector,在材质面板中显示的是四个数值输入框。

四个分量分别对应XYZW,也可以叫做RGBA。

XYZW与RGBA同样都是四个分量组合,只是在用于颜色时我们通常用RGBA来表示,用作坐标时习惯用XYZW来表示而已,同样我们也是可以用Vector来输出颜色,只是不那么方便直观而已。

2D(类型:2D纹理)

示例如下:

	Properties
	{
		_MainTex("我是2D纹理", 2D) = "white" {}
	}

变量名:_MainTex

显示名称:我是2D纹理

类型:2D

默认值:white

纹理贴图,也是Shader中最最常用的属性之一。

[NoScaleOffset]

	Properties
	{
		[NoScaleOffset]_MainTex("我是2D纹理", 2D) = "white" {}
	}

在材质面板中除了显示贴图槽以外默认还会显示两组Float。

  1. Tiling (贴图重复度)
  2. Offset (贴图偏移值)
如需让这两组值产生作用,我们需要在Shader中添加一些代码以支持,在后续文章中会讲解。

如果我们不希望用户去调节此参数,或者为了使性能极致化,我们可以考虑把它们的代码功能移除掉,但一旦如此,材质面板中的参数将不起作用,这时我们就可以使用[NoScaleOffset]属性标记来将它们隐藏掉。

[Normal]

	Properties
	{
		[Normal]_MainTex("我是2D纹理", 2D) = "white" {}
	}

如果我们希望用户指定贴图时选择法线,那我们要怎么办呢,我们并不能控制用户会选择什么类型的贴图。

此时我们可以通过添加[Normal],来标记此属性是用来接收法线贴图的,当用户指定了非法线的贴图时会在材质面板上进行警告提示:

有一点一定要注意,有时美术在其它软件中导出了法线贴图,但在Unity直接拖上来还是会有警告提示,是因为没有在贴图导入面板中把Texture Type设置为Normal,只有这样这张贴图才会被Unity识别为法线。

默认值

2D纹理的默认值有以下几种:

  1. white
  2. black
  3. gray
  4. bump

如果不设置默认值,即=""{},则其实与="gray"{}相同。

当设置了默认值后,Shader内部会自动调用Unity内部准备的一张小图片,white就是纯白色,black就是纯黑色,gray就是灰色图,bump就是法线图。


3D(类型:3D纹理)

示例如下:

	Properties
	{
		_MainTex("我是3D纹理", 3d) = "" {}
	}

变量名:_MainTex

显示名称:我是3D纹理

类型:3d

默认值:空

3D纹理主要用在查找表或者体积数据上,默认值与2D的不同,不管如何设置都只会显示为灰色图。


Cube(类型:立方体纹理)

示例如下:

	Properties
	{
		_MainTex("我是Cube纹理", CUBE) = "" {}
	}

变量名:_MainTex

显示名称:我是Cube纹理

类型:CUBE

默认值:空

Cubemap是一个由六个独立的正方形纹理组成的集合,它将多个纹理组合起来映射到一个单一纹理。

基本上说CubeMap包含6个2D纹理,这每个2D纹理是一个立方体(cube)的一个面,也就是说它是一个有贴图的立方体。

想像成一个方形盒子被我们拆开铺平的情景。

CubeMap通常被用来作为具有反射属性物体的反射源。

通用属性标记

还有一些比较常用的属性标记,可以用于任何属性,下面来介绍下:

[Header]

	Properties
	{
		[Header(This is Header )]_Int("我是Int", Int) = 1
		_Float("我是Float", Range( 0 , 1)) = 1
	}

在材质面板上进行标注,通常用作分类组别用,注意只支持英文、数字、空格以及下划线。

[HideInInspector]

在材质面板中隐藏此条属性,在不希望暴露某条属性时可以快速将其隐藏。

Shader之在Properties模块儿定义属性:

   

至此Properties属性已经介绍完毕,下面介绍下属性如何使用??

    在Shader中,我们在Properties中定义的变量是为了在材质面板中显示并方便我们调节,在Pass中添加Cg/HLSL代码片断,就需要用到这些属性去实现效果,如果要在Cg/HLSL中使用Properties的话就必须要重新声明一次(要求命名一样)。那么Cg/HLSL中对应有哪些数据类型呢?

Cg/HLSL中的数据类型

声明的意思就是定义一个变量,告诉电脑我们会用这个变量去存储一些值,电脑就直接通过这个变量来获取相应的值就好了,而由于值是会变化的,所以被称为变量。

首先,我们先看下在Cg/HLSL中的几种常见数据类型:

  1. float/half/fixed(三个都是浮点数,只是精度不一样而已)
  2. integer(整型)
  3. sampler2D(2D纹理)
  4. samplerCUBE(3D纹理)
  • float

高精度类型,32位,通常用于世界坐标下的位置,纹理UV,或涉及复杂函数的标量计算,如三角函数、幂运算等。

  • half

中精度类型,16位,数值范围为[-60000,+60000],通常用于本地坐标下的位置、方向向量、HDR颜色等。

  • fixed

低精度类型,11位,数值范围为[-2,+2],通常用于常规的颜色与贴图,以及低精度间的一些运算变量等。

在PC平台不管你Shader中写的是half还是fixed,统统都会被当作float来处理。half与fixed仅在一些移动设备上有效。
比较常用的一个规则是,余的全除了位置和坐标用float以外,其部用half。主要原因也是因为大部分的现代GPU只支持32位与16位,也就是说只支持float和half,不支持fixed。
  • interger

整型类型,通常用于循环与数组的索引。

在 Direct3D 9 和 OpenGL ES 2.0平台上整型可能会被直接用浮点数来处理,在Direct3D 11、OpenGL ES 3等现代GPU上可以正确的以整型类型来处理。
  • sampler2D、sampler3D与samplerCUBE

纹理,默认情况下在移动平台纹理会被自动转换成低精度的纹理类型,如果你需要中精度的或者高精度的需要用以下方式来声明:

sampler2D_half(中精度2D纹理)

sampler2D_float(高精度2D纹理)

sampler3D_half(中精度3D纹理)

sampler3D_float(高精度3D纹理)

samplerCUBE_halft(中精度立方体纹理)

samplerCUBE_float(高精度立方体纹理)


类型对应

好了,现在我们已经了解了Cg/HLSL中的数据类型,那么Properties中的与Cg/HLSL中的是如何对应的呢?

  • Int/float/Range用浮点值表示,也就是float、half或者fixed,根据自己需要的精度来定义。
  • Vector/Color用float4、half4或者fixed4表示。
  • 2D类型用sampler2D表示。
  • 3D类型sampler3D表示。
  • CUBE类型用samplerCUBE表示。

单个浮点数值比较好理解,像Vector与Color的float4要如何理解呢?

其实不管是Vector还是Color,都是由四个同样精度的浮点数值组成的,所以我们在定义的时候才会写成float4、half4或者fixed4.

比如,我们在Properties中声明了如下的颜色:

_Color("Color", Color) = (1,1,1,1)

在Cg/HLSL中我们需要同样再声明一次:

fixed4 _Color;

颜色的四个分量:

  • Red(红)
  • Green(绿)
  • Blue(蓝)
  • Alpha(透明)

在Cg/HLSL中我们可以通过_Color来访问颜色,也可以通过_Color.rgba来访问,这里的.rgba就是表示颜色的四个分量,如果只想获得颜色的红通道就是_Color.r又如果只想获取绿通道和透明通道就是_Color.ga,以此类推~

表示分量除了可以用.rgba,我们还可以使用.xyzw,它们的意义是一样的,你可以使用Vector.rgba,也可以使用Color.xyzw,这两者本身并没有什么区别,只是我们通常在颜色上用rgba,在向量上用xyzw,这样比较直观方便理解。

再说下矩阵,在Shader中,矩阵是一个按照长方形阵列排列的浮点数集合。

你可以想像成是一队站列整齐的士兵,横向有M人,竖向有N人。就可以用floatMxN来表示。如果是4x4矩阵,就是float4x4(同样支持其它精度),不过有一点要注意,在某些平台上是不支持非方矩阵的(比如float3x2),特别是OpenGL ES 2.0平台。

使用举例代码如下所示:

Shader "Custom/Test1" //Shader路径名
{
	Properties
	{
		_MainTex   ("Texture", 2D)   =   "white" {}  //定义属性显示,可调节属性
	   _TestColor    ("TestColor",   Color)  =  (0,0,0,0)
       _TestVector   ("TestVector", Vector) =  (2,2,2,2)

        _TestRange  ("TestRange",   Range (1, 10)) =  3
        _TestFloat   ("TestFloat",   Float) = 1.2   //定义数字类型
       _TestInt    ("TestInt",   Int)  =  1

    
       _TestCube   ("TestCube",    Cube) =   "" {}//cubeMap是六个面的纹理,天空盒其实就在一个很大的CubeMap里面
       _Test3D     ("Test3D",      3D)  = "" {}//3D纹理只能用脚本去创建,Opengl 3.0及以上才支持,用的比较少
	  	
		
		
	}              
	SubShader      //可以有多个SubShader      Subshader对应一个显卡,U3d进来以后会找对应的Subshader, //如果第一个SubShader代码块里面运行不报错,就会把第一个Subshader在显卡里运行,否则接着往下找,如果都达不到那么就会	              
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = v.uv;
				return o;
			}
			
			sampler2D _MainTex;

			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				// just invert the colors
				//col.rgb = 1 - col.rgb;
				return col;
			}
			ENDCG
		}
	}
      FallBack  "diffuse"//diffuse 适合所有的显卡
}

  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值