Unity Shader入门教程(一)
参考文献:http://www.360doc.com/content/13/0923/15/12282510_316492286.shtml
Unity Shader是着色器,将纹理、网格信息输入,得到材质的一段程序,具体是个什么东西,还需要亲自实践才知道。一个Unity大神推荐我:如果要学计算机图形编程(游戏编程的基础),可以先学习UnityShader,往后再学习OpenGL和DX。不说废话,依我的风格,都是直接看实例,笔者的教程偏向于傻瓜式的,应该适合入门。
前提:安装了Unity和VS,并且有3天的Unity使用经验。
第一步:打开新工程。在内容浏览器中创建一个Shader。

命名为:

第二步:双击打开查看:
Shader "Custom/Shad0" {
Properties {
_Color ("Color", Color) = (,,,)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(,)) = 0.5
_Metallic ("Metallic", Range(,)) = 0.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD
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"
}
当然,你一开始看不懂,请逐行逐行看我的解释,下文中的代码和上文中的一样,只是加入了详细的注释:
/*首行声明了一个Shader,命名为Shad0,存放在路径Custom下(这个路径在哪里不是重点,它归类在自定义中),看上去是不是挺像结构体的声明*/
Shader "Custom/Shad0" { /*
在将第一块内容之前,请先去了解一下UV纹理。简单来说:A是一张图片(称A为纹理),B是一张坐标信息(称B为UV),用B来取A就是纹理贴图的精髓了,举个简单的例子:
A的色彩如下:
红 黄
蓝 绿 B的坐标信息如下:
(0,0) (1,1)
(1,1) (0,1) 那么取出来得到的纹理贴图就是:
红 绿
绿 黄 这样子,是不是很无聊?当这上面的点数达到很大的量级时,就很有意义了。
没完,你还需要了解镜面高光和金属度的概念,自行百度(或者先跳过这个知识点继续往下看)。
*/ /*第一块:属性声明*/
Properties { _Color ("Color", Color) = (,,,)
/*用_XX的声明方法来声明的变量就是称为属性了,这一句的语法是:
_XXX (展示名, 数据类型) = 默认值 展示名是在Unity中可见的名称,Color其实是一种数据类型(就像int那样,只是后者很简单,是基本数据类型)。
数据类型有哪些(参考上述博文):
Color - 一种颜色,由RGBA(红绿蓝和透明度)四个量来定义;
2D - 一张2的阶数大小(256,512之类)的贴图。这张贴图将在采样后被转为对应基于模型UV的每个像素的颜色,最终被显示出来;
Rect - 一个非2阶数大小的贴图;
Cube - 即Cube map texture(立方体纹理),简单说就是6张有联系的2D贴图的组合,主要用来做反射效果(比如天空盒和动态反射),也会被转换为对应点的采样;
Range(min, max) - 一个介于最小值和最大值之间的浮点数,一般用来当作调整Shader某些特性的参数(比如透明度渲染的截止值可以是从0至1的值等);
Float - 任意一个浮点数;
Vector - 一个四维数; 请看默认值(1,1,1,1),形如(g,b,a,A),其中的透明度A为0时,表示透明,为1时,表示完全不透明,所以应该称之为不透明度。
*/ _MainTex ("Albedo (RGB)", 2D) = "white" {}
/*这里表示一张图片,这张图片在这里仅仅用空白来表示*/ _Glossiness ("Smoothness", Range(,)) = 0.5
/*高光设置为.5*/ _Metallic ("Metallic", Range(,)) = 0.0
/*金属度*/
} /*第二块内容:什么是SubShader,如果你用过虚幻4,就能够很容易理解,其实SubShader对应了UE4中的材质表达式。
UE4中的材质表达式或者Unity中的shader本质是什么?简单来说就是将图片通过处理得到另一张图片(比如用图片+UV信息 -> 纹理贴图的过程)。
SubShader其实就是定义了图片处理过程。
*/
SubShader { /*Tags规定了混合模型。什么是混合模型?请看下面的附图1,当然,混合模型是UE4中的概念。
附图1:

这里贴一段相比Unity更为正确的解释:
Background - 最早被调用的渲染,用来渲染天空盒或者背景
Geometry - 这是默认值,用来渲染非透明物体(普通情况下,场景中的绝大多数物体应该是非透明的)
AlphaTest - 用来渲染经过Alpha Test的像素,单独为AlphaTest设定一个Queue是出于对效率的考虑
Transparent - 以从后往前的顺序渲染透明物体
Overlay - 用来渲染叠加的效果,是渲染的最后阶段(比如镜头光晕等特效) */
Tags { "RenderType"="Opaque" } /*LOD表示细节呈现级别(也即是画质,即粗糙/细腻程度)
当机器很差的时候,差到其评估值小于200时,本材质无效(也就是本shader罢工)。当机器的性能不错,大于200时,本shader继续工作。就是这么有个性。
别气馁,下面的内容是最重要的。
*/
LOD /*这是一个标记:CGPROGRAM,表示这是一段computer graph编程*/
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
/*请看这个奇怪的函数声明:
#pragma surface表面着色器 surffunction着色器的代码(在本例子中就是下面的surf) lightModel(光照模型,这个概念先跳过) [可选参数]
*/ // Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0 /*
用笔者的话来说:sampler2D就是一张图片……(还记得吗,就是上文说的A图片) 贴一段介绍: 接下来一句sampler2D _MainTex;,sampler2D是个啥?
其实在CG中,sampler2D就是和texture所绑定的一个数据容器接口。
等等..这个说法还是太复杂了,简单理解的话,所谓加载以后的texture(贴图)说白了不过是一块内存存储的,
使用了RGB(也许还有A)通道,且每个通道8bits的数据。而具体地想知道像素与坐标的对应关系,以及获取这些数据,
我们总不能一次一次去自己计算内存地址或者偏移,因此可以通过sampler2D来对贴图进行操作。
更简单地理解,sampler2D就是GLSL中的2D贴图的类型,相应的,
还有sampler1D,sampler3D,samplerCube等等格式。 解释通了sampler2D是什么之后,
还需要解释下为什么在这里需要一句对_MainTex的声明,
之前我们不是已经在Properties里声明过它是贴图了么。
答案是我们用来实例的这个shader其实是由两个相对独立的块组成的,
外层的属性声明,回滚等等是Unity可以直接使用和编译的ShaderLab;
而现在我们是在CGPROGRAM...ENDCG这样一个代码块中,这是一段CG程序。
对于这段CG程序,要想访问在Properties中所定义的变量的话,必须使用和之前变量相同的名字进行声明!【注意这里!!!】
于是其实sampler2D _MainTex;做的事情就是再次声明并链接了_MainTex,
使得接下来的CG程序能够使用这个变量。*/
sampler2D _MainTex; /*这是一个非常简单的结构体,称为Input,其中有一个float2数据类型,这是一个二维float矢量,也就是(a,b)这样的。*/
struct Input {
float2 uv_MainTex;
}; /*在坚持一下,这里还有几个变量:half类型的两个,fixed4类型的一个,
half类型表示半精度浮点数,计算性能好但是精度低,和float和double是同类型的浮点数;
fixed4不详,但是大意是四维的矢量*/ half _Glossiness;//必须使用和之前变量相同的名字进行声明!【注意这里!!!】 half _Metallic;//必须使用和之前变量相同的名字进行声明!【注意这里!!!】 fixed4 _Color;//必须使用和之前变量相同的名字进行声明!【注意这里!!!】 /*核心的处理函数:surf,输入一张二维浮点信息,也即是上面的uv_MainTex,
输出一个o表示材质(inout像c++里面的按照引入传入,虽说没有返回,但是也有信息传出的效果)*/
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
/*看这里:tex2D就是前面说的"利用UV去取图片获得纹理贴图"的做法,然后再乘以_Color, 这里用到了乘法的颜色算法,自己体会(这个_Color默认值为1,1,1,1,所以默认下不影响)
笔者到这里可以知道:fixed4表示一种四维矢量(用来表示颜色就挺合适的。此外,它是定点型小数而非浮点型小数)
*/ o.Albedo = c.rgb;
/* inout SurfaceOutputStandard o
这个结构有哪些包含的变量呢:
struct SurfaceOutput {
half3 Albedo; //像素的颜色
half3 Normal; //像素的法向值
half3 Emission; //像素的发散颜色
half Specular; //像素的镜面高光
half Gloss; //像素的发光强度
half Alpha; //像素的透明度
};
*/ // Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
/*结束CG编码*/
}
FallBack "Diffuse"
//这里还不太明白,先放着。
}
第三步:看完之后再重新看看没有注释的代码,整理十分钟,然后继续。
第四步:那篇参考的教程到这里就完了,我补上结尾:
导入一张图片:


第五步:创建材质Material,

在细节里面选择shader:

是不是很懵逼,为什么要这么做?还记得吗,shader的本质是将图片转化为Material的算法。
第六步:选择一张图片:


然后在右下方看到效果:(点箭头处切换预览样式)

第七步:随便新建一些物体,然后放入这个材质:



等等:好像没有反应?因为没有光线,加入直射光即可看到效果:


——原创 小江村儿的文杰 zouwj5@qq.com 2017年7月21日22:29:44
Unity Shader入门教程(一)的更多相关文章
- Unity Shader入门教程(三)自制光照模型
光照模型的概念目前还不明晰,因为笔者也是一个初学者,所以请小心对待笔者介绍的内容.笔者认为光照模型是规定光照算法的模型,比如说前面提到的Lambert光照模型,规定了材质表面的光线的表达式为 环境光+ ...
- Unity Shader入门教程(二)最基本的Diffuse和Normal样例
本教程参考了<猫都能学会的Unity3dShaderLab教程.CHM>, 1.请上网搜索并下载此文件. 2.随后再下载里面提到的素材: http://vdisk.weibo.com/s/ ...
- Unity Shader入门教程(四)反射光斑的实现
本节内容介绍PhongModel(也就是上文说的反射光的计算模型),采用的计算方法是BlinPhong(也即是用视线方向V+光源方向L的和,与N做点积,随后幂化得到高光反射系数)下图采用了csdn博文 ...
- Unity Shader入门
Unity Shader入门 http://www.cnblogs.com/lixiang-share/p/5025662.html http://www.manew.com/blog-30559-1 ...
- Unity Shader入门精要读书笔记(一)序章
本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数 ...
- 【我的书】《Unity Shader入门精要》出版上市
重要的事 先说重要的事,就是我的书籍<Unity Shader入门精要>在经过无数次跳票后,终于出版上市了(泪目-)! 购买传送门: 亚马逊 当当 京东 截止到我写这篇文章的时候,京东是没 ...
- Unity Shader入门精要之 screen post-processing effect
本篇记录了学习Unity Shader入门精要的屏幕后处理的一些知识点. OnRenderImage(RenderTexture src, RenderTexture dest) 以上函数是Unity ...
- Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘
转自 冯乐乐的<Unity Shader 入门精要> 2010年的Unity 3 中,Surface Shader 出现了. 表面着色器的一个例子. 我们先做如下准备工作. 1)新建一个场 ...
- Unity Shader入门精要学习笔记 - 第16章 Unity中的渲染优化技术
转自冯乐乐的 <Unity Shader 入门精要> 移动平台的特点 为了尽可能一处那些隐藏的表面,减少overdraw(即一个像素被绘制多次),PowerVR芯片(通常用于ios设备和某 ...
随机推荐
- Python中的模块介绍和使用
在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Python中要调用sqrt函数,必须用import关键字引入math这个模块,下面就来了解一 ...
- blog界面自己写了css,参考了网站设计,想要的自己拿
junhey这就把界面的代码公布下来,可以自己修改额~(ps:麻烦加个友链http://www.cnblogs.com/junhey/ 谢谢) /* 初始化样式 */ html, body, div, ...
- 调试JDK源码时,不能查看变量的值
前几天本来想以debug模式看一下JDK的源码,进入调试模式时才发现,根本看不到方法里面变量值的情况.为什么呢?JDK现在的版本中,编译过后,去除了里面的调试信息.解决办法是,编译那些类,使其带有调试 ...
- Function.prototyoe.call.apply
刚刚在一个群里看到有人问 Function.prototype.call.apply(obj, args) 如何理解,觉得挺有意思的.刚开始被惯性思维干扰了,一直都是 call 和 apply 分开用 ...
- [BZOJ1415]聪聪和可可
Input 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每 ...
- curl的使用
curl -v -0 -T 123.wav "127.0.0.1:80/saveSound?filename=18696770041_1379903830_xxx.wav&du ...
- 集成python双版本详解
最近要准备学习Python,由于版本上的差异,不知道要学哪个,现在好多东西都是基于python2基础的,但是python2在2020年左右就可能停止了,所以干脆决定两个都装上吧! 首先上官网上下载 ...
- maven下配置pom.xml
博主原创,转载请注明. 遇到的问题: 缺少依赖库.解决办法: 在build标签中添加: <plugin> <groupId>org.apache.maven.plugins&l ...
- 在Cenos系统安装Python3.5版本,使P2和P3共存
首先Cenos安装好后,系统自带python2.6版本 输入>>>exit() 退出 使用迅雷下载python3.5 链接:https://www.python.org/ft ...
- JS延时一秒执行
//JS延时一秒执行 setTimeout(function(){ window.history.go(0); }, 1000);