Unity3D Shader编程实践——“Hello Shader"
2014-03-18 20:45
417 查看
Shader和Material是3D开发必不可少的部分,D.S.Qiu一开始对这两个关系及作用一直搞不透,所以很有必要先介绍下Shader和Material的基本概念:Shader(着色器)其实就是一小段程序,它将输入的Texture(贴图),颜色或其他参数以指定方式输出。Shader都是指定给Material,Material为Shader提供输入的贴图等参数。在Material上输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设置,将这些内容(Shader及输入参数)打包存储在一起,得到的就是一个Material(材质)。之后,便可以将材质赋予Mesh(网格)的Renderer(渲染器)来进行渲染(输出)了,绘图单元根据这个输出就得到屏幕输出的图像。简而言之:Material为Shader提供具体的输入参数,而Shader是对输入参数的具体处理逻辑。
Hello Shader
学习编程语言都习惯以一个Hello World 开始,这里也以“Hello Shader"开始,介绍Shader的基本结构,首先创建Material 和 Shader,而且都命名为Hello,并放入一张图片,项目工程如下图:
下面看下HelloShader的代码:
在场景里创建一个Cube,把Hello Material 指定给 Mesh Renderer 的 Materials的Element 0 ,就得到下面的效果(只有一块红色):
显然,这个Shader就是将贴图上的像素都设为红色。 下面逐行讲解下这个Shader的语句:
第一行定义的是这个Shader的名字一般的格式是分类+名字,并用“/"分隔:
Shader "Custom/HelloShader"
在 Properties {} 的结构中,定义的属性就是前面说到的Shader输入参数,而且 Properties{} 中定义的属性也是Material提供得到的,在Unity中Material 的 Inspector面板上可以设置对应属性的值。先看下定义 Property 的格式:
上图中,_Color是在Shader内的变量,Main Color是在Inspector 面板显示的名字,Color是属性的类型,(1,1,0)是属性的默认值。Hello Shader在Properties只定义了一张贴图:
_MainTex ("Base (RGB)", 2D) = "white" {}
SubShader{} 结构就是一个具体的处理,对于不同的显卡可以有不同的处理,即可以定义多个SubShader{}结构,不同的设备优先选择一个可以允许的SubShader运行。在SubShader前面定义了 Tags{} 和 LOD ,这里可以先不管,只需要理解成设置 SubShader 的参数就可,后面会做详细的介绍。
在看下最后一句 FallBack "Diffuse",这个语句的作用是如果前面的 SubShader都不能在设备上运行的情况下,就运行FallBack 指定的Shader运行。
FallBack "Diffuse"
前面讲解的是 Shader 的结构的东西,更多细节会后面的章节做介绍。本文主要介绍Hello Shader的主要处理过程:
首先 CGPRPGRAM 和 ENDCG 表示这是一段CG程序,分别表示CG程序的开始和介绍。Unity的Shader用的是Nvidia Cg 语言。
接下来 #pragma surface surf Lambert 声明了HelloShader 定义的是一个表面(Surface)Shader(后面会有介绍),它的处理函数式 surf ,并且指定的光照模型是 Lambert。语句的原型是这样的:
#pragma surface surfaceFunction lightModel [optionalparams] 其中 surface 是声明为 表面Shader, surfaceFuction 是Shader的指定实现方法, lightMode[optionalparams]是Shader使用的光照模型
这里的 surf 相当于 C语言的main函数,可以认为是Shader的执行入口,不过跟main不同的是,他可以随意命名,然后在 #pragma surface 指定就行了。
surf 有两个参数,Input IN 和 SurfaceOutput o(inout 是一个形参的修饰符,表示可做输入或输出的引用类型),其中Input 是HelloShader定义的输入参数结构体:
Input结构里中指定定义了一个 float2 uv_MainTex 变量,uv_MainText表示贴图 _MainTex 的uv向量。而 _MainTex 就是前面定义 sampler2D _MainTex ,这里 sampler2D 和 float2 都是Cg的数据类型(后面会有专门章节介绍Cg的数据类型已经基本语法)。
SurfaceOutput 类型是预定义的,可先不去深究:
也就是说 surf 方法其实对输入结构 Input IN 进行处理,得到输出 SurfaceOutput o的像素结构。那HelloShader进行什么样的处理呢?
half4 c = tex2D (_MainTex, IN.uv_MainTex); //tex2D 是对_MainTex 的 IN.uv_MainTex位置进行采样得到(r,g,b,a)的四元组 c
o.Albedo = fixed3(1,0,0); //直接返回红色作为输出像素的颜色,这样导致看到就是一个红色块
o.Alpha = c.a; //返回c的alpha值,作为输出像素的alpha值
将 o.Albedo = fixed3(1,0,0) 改为 o.Albedo = c.rgb 在屏幕就会输出原来的贴图。
小结:
万事开头难,写的很简单,本来昨晚就应该写好的,但后面还是去睡觉了。只是对Shader进行了简单的介绍,很多细节都没交代清楚,意犹未尽,D.S.Qiu后面进行专门的介绍会更好些:
Cg的基础语法
Unity Shader的结构
Unity Shader类型(Surface,Vert,Fragment)
Hello Shader
学习编程语言都习惯以一个Hello World 开始,这里也以“Hello Shader"开始,介绍Shader的基本结构,首先创建Material 和 Shader,而且都命名为Hello,并放入一张图片,项目工程如下图:
下面看下HelloShader的代码:
Shader "Custom/HelloShader" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); //o.Albedo = c.rgb; o.Albedo = fixed3(1,0,0); //返回红色 o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
在场景里创建一个Cube,把Hello Material 指定给 Mesh Renderer 的 Materials的Element 0 ,就得到下面的效果(只有一块红色):
显然,这个Shader就是将贴图上的像素都设为红色。 下面逐行讲解下这个Shader的语句:
第一行定义的是这个Shader的名字一般的格式是分类+名字,并用“/"分隔:
Shader "Custom/HelloShader"
在 Properties {} 的结构中,定义的属性就是前面说到的Shader输入参数,而且 Properties{} 中定义的属性也是Material提供得到的,在Unity中Material 的 Inspector面板上可以设置对应属性的值。先看下定义 Property 的格式:
上图中,_Color是在Shader内的变量,Main Color是在Inspector 面板显示的名字,Color是属性的类型,(1,1,0)是属性的默认值。Hello Shader在Properties只定义了一张贴图:
_MainTex ("Base (RGB)", 2D) = "white" {}
SubShader{} 结构就是一个具体的处理,对于不同的显卡可以有不同的处理,即可以定义多个SubShader{}结构,不同的设备优先选择一个可以允许的SubShader运行。在SubShader前面定义了 Tags{} 和 LOD ,这里可以先不管,只需要理解成设置 SubShader 的参数就可,后面会做详细的介绍。
在看下最后一句 FallBack "Diffuse",这个语句的作用是如果前面的 SubShader都不能在设备上运行的情况下,就运行FallBack 指定的Shader运行。
FallBack "Diffuse"
前面讲解的是 Shader 的结构的东西,更多细节会后面的章节做介绍。本文主要介绍Hello Shader的主要处理过程:
CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); //o.Albedo = c.rgb; o.Albedo = fixed3(1,0,0); //返回红色 o.Alpha = c.a; } ENDCG
首先 CGPRPGRAM 和 ENDCG 表示这是一段CG程序,分别表示CG程序的开始和介绍。Unity的Shader用的是Nvidia Cg 语言。
接下来 #pragma surface surf Lambert 声明了HelloShader 定义的是一个表面(Surface)Shader(后面会有介绍),它的处理函数式 surf ,并且指定的光照模型是 Lambert。语句的原型是这样的:
#pragma surface surfaceFunction lightModel [optionalparams] 其中 surface 是声明为 表面Shader, surfaceFuction 是Shader的指定实现方法, lightMode[optionalparams]是Shader使用的光照模型
这里的 surf 相当于 C语言的main函数,可以认为是Shader的执行入口,不过跟main不同的是,他可以随意命名,然后在 #pragma surface 指定就行了。
surf 有两个参数,Input IN 和 SurfaceOutput o(inout 是一个形参的修饰符,表示可做输入或输出的引用类型),其中Input 是HelloShader定义的输入参数结构体:
struct Input { float2 uv_MainTex; };
Input结构里中指定定义了一个 float2 uv_MainTex 变量,uv_MainText表示贴图 _MainTex 的uv向量。而 _MainTex 就是前面定义 sampler2D _MainTex ,这里 sampler2D 和 float2 都是Cg的数据类型(后面会有专门章节介绍Cg的数据类型已经基本语法)。
SurfaceOutput 类型是预定义的,可先不去深究:
struct SurfaceOutput { half3 Albedo; //像素的颜色 half3 Normal; //像素的法向值 half3 Emission; //像素的发散颜色 half Specular; //像素的镜面高光 half Gloss; //像素的发光强度 half Alpha; //像素的透明度 };
也就是说 surf 方法其实对输入结构 Input IN 进行处理,得到输出 SurfaceOutput o的像素结构。那HelloShader进行什么样的处理呢?
half4 c = tex2D (_MainTex, IN.uv_MainTex); //tex2D 是对_MainTex 的 IN.uv_MainTex位置进行采样得到(r,g,b,a)的四元组 c
o.Albedo = fixed3(1,0,0); //直接返回红色作为输出像素的颜色,这样导致看到就是一个红色块
o.Alpha = c.a; //返回c的alpha值,作为输出像素的alpha值
将 o.Albedo = fixed3(1,0,0) 改为 o.Albedo = c.rgb 在屏幕就会输出原来的贴图。
小结:
万事开头难,写的很简单,本来昨晚就应该写好的,但后面还是去睡觉了。只是对Shader进行了简单的介绍,很多细节都没交代清楚,意犹未尽,D.S.Qiu后面进行专门的介绍会更好些:
Cg的基础语法
Unity Shader的结构
Unity Shader类型(Surface,Vert,Fragment)
相关文章推荐
- Unity3D Shader编程实践——“Hello Shader"
- 【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&混合操作合辑
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质
- Unity3d之Shader编程:子着色器、通道与标签的写法 & 纹理混合
- 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
- 【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&混合操作合辑
- Unity3D Shader编程】之九 深入理解Unity5中的Standard Shader (一)&屏幕水幕特效的实现
- Unity3D Shader编程】之十一 深入理解Unity5中的Standard Shader(三)&屏幕像素化特效的实现
- 【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&混合操作合辑
- Unity3D Shader编程】之十二 可编程Shader初步 & 漫反射可编程Shader的实现
- "JavaScript语言精髓与编程实践"之调用函数的几种方法
- 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合
- Unity3D Shader编程】之十三 单色透明Shader & 标准镜面高光Shader
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质
- 【浅墨Unity3D Shader编程】之五 圣诞夜篇: Unity中Shader的三种形态对比&混合操作合辑
- 【浅墨Unity3D Shader编程】之一 游戏场景的创建 & 第一个Shader的书写
- 【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
- Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 & 第一个Shader的书写
- 【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&颜色、光照与材质