Unityshader官⽹⽂档全⽅位学习(⼀)
原⽂的代码没⽤代码块 读起来要死要活的 重新抄了⼀遍 嘿嘿嘿~
What?? Shader,看起来好⾼级的样⼦,是的,这是Unity中⾼级进阶的必备。因此,兄弟我就在此记下我学习官⽹的⼀些⼼得。
此为⼀。主要介绍些Surface Shaders的知识。具体的⼤家也可去官⽹(如下)学习。
⼀、概念篇
1.基准:unity⾥的shader并不是⼀门独特的语⾔,⽽是⼀种代码⽣成⽅式,且可将低层次且复杂的shader编程进⾏简化。但同时你也还是得使⽤Cg/HLSL来写的。
2.原理:写⼀个函数,以UVs或者⼀些数据为⼊⼝,然后以SurfaceOutput为输出。同时在SurfaceOutput这个结构体⾥还有不同的属性。这样对于这个函数来说,他的执⾏过程会⽣成vertex和pixel的Shader,并且传递⼀些渲染的路径。
3.结构:输出结构:
struct SurfaceOutput {
half3 Albedo;
half3 Normal;
half3 Emission;
half Specular;
half Gloss;
half Alpha;
家常粉丝
};
Albedo,是漫反射的颜⾊值。
Normal,法线坐标
Emission,⾃发光颜⾊
Specular,镜⾯反射系数
Gloss,光泽系数
Alpha,透明度系数
⼆、编程规则
1.要写在CGPROGRAM..ENDCG的SubShader的块⾥。不可写在Pass⾥。
2.shader的名字是可以重复的,重复后,以后来的shader为主。热爱祖国的演讲稿
3.指令详细:
#pragma surface surfaceFunction lightModel [optionalparams]
=>surfaceFunction,没什么好说,肯定是函数名了。
=>lightModel是所采⽤的光照模型。可以⾃⼰写也可使⽤内置如Lambert和BlinnPhong.
=>optionalparams:可选参数,⼀堆可选包括透明度,顶点与颜⾊函数,投射贴花shader等等。具体⽤到可以细选。
另外这⾥有⼀个功能。在Surface shader的CGPROGRAM⾥添加 #pragma debug [内容]。可在编译结果的⽂件中看到。写多少都⾏。但尝试在其他种shader下不⾏。
三、实例学习:
1.Simple:
Shader "Example/Diffu Simple" {
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input { float4 color : COLOR; };
void surf (Input IN, inout SurfaceOutput o) {
o.Albedo = 1;
}
培训就业ENDCG
}
Fallback "Diffu" }
第⼀个。⾏⾏来:
第⼀⾏:写个名字。这也有讲究的。斜线左边为其⽗类的组,⽆则新增,有则累加,右边才是真正的名字。注意,这些shader名不像C#脚本,⽆需⽂件名与shader名相同。
第⼆、三⾏:接下来就在SubShader⾥添加内容,SubShader是可以有多个的。然后上⼀个Tags,此处只⽤到RenderType这种,另外的还有Rendering order, ForceNoShadowCasting..等。这些本阶段暂不研究。
第四⾏:上⼀条指令,⾥⾯指定响应⽅法为surf且采⽤Lambert的光照模型。这个必须有的。
第五⾏:这个结构体,记得名字不能改,只能为Input。⾥⾯⼀个四元素的颜⾊值(RGBA)。
第七到第九⾏:第⼀个参数,纯输⼊的上述结构体参数。第⼆个参数,inout标识,意思是可为输⼊参数也可为输出参数。Albedo根据前⾯介绍到的,是⼀个rgb的值,如果给⼀个1,其实就是float3(1,1,1),就是反射出来的颜⾊为⽩⾊,如果为100,则是加强反射强度,并不会改变其颜⾊。为0或为负数时道理类似。
最后Fallback,后⽅的是⾃带的shader,可以⽤⾃⼰⾃定义好的。这⾥这句的意思是,如果所有subshader在当前显卡都不⽀持,则默认返回⾃带的Diffu。
2.Texture:
Shader "Example/Diffu Texture"
{ Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader {
骆驼祥子读书心得
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input { float2 uv_MainTex; }; sampler2D _MainTex;
void surf (Input IN, inout SurfaceOutput o) {
胡萝卜炒蛋o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
}
ENDCG
}
Fallback "Diffu"
}
这个例⼦呢。其实只是第⼀个的基础上添加了⼀个2D属性显⽰名为Texture。以下解析:
第⼀个⿊体:添加⼀个名叫_MainTex的属性,指定其为2D类型且显⽰为Texture。"white"那块可不是乱写的,是unity的build-in的⼀些textures的名称,⽽不是单纯颜⾊名字。意思是当默认时显⽰为名叫white的材质。如改成red(即使⽤名叫red的材质,如果有其他也可叫其名字),则效果如下:
第⼆个⿊体:uv_MainTex。这其中⼤有⽞机,uv开头指代后⽅材质的uv值,因此uv不变,后⾯的可以根据开头起的名字动态换。还有哦,这种类似于_MainTex的命名⽅式是CG推荐的,其实不⽤下划线也OK的。
第三个⿊体:这个Sampler2D,可以理解为引⽤⼀个2D Texture。因为下⾯的Tex2D函数需要这种类型。所以说这个后⾯的名字要与Properties⾥的对应⼀样才⾏。
第四个⿊体:Tex2D,这玩意就是根据对应材质上所有的点找指定 2DSample上的Texture信息,此处需要其RGB信息,就打出来赋给了其反射值。所以对有材质图的情况下,要显⽰出图,还是要相应的反射其原图的rgb值。
3.Normal mapping
Shader "Example/Diffu Bump" {
Properties {
_MainTex (
"Texture", 2D) = "white" {}
_BumpMap ("Bumpmap", 2D) = "bump" {}
}
SubShader {
Tags { "RenderType" = "Opaque" }
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float2 uv_MainTex;
float2 uv_BumpMap;
};
sampler2D _MainTex;
sampler2D _BumpMap;
void surf (Input IN, inout SurfaceOutput o) {西安幼儿园
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap)); }
ENDCG
}
Fallback "Diffu"英国人家
}
这个例⼦⾥加了个凹凸贴图,可实现类似⼀些很漂亮的凹凸效果。
第⼀个⿊体:加⼀个2D类型的材质,默认为bump。(即带有凹凸效果的)。
第⼆个⿊体:上⼀个采集器。采集下来上⾯的材质。
第三个⿊体:有讲究,这个UnpackNormal是unity⾃带的标准解压法线⽤的,所谓解压,我暂时学习到的只是将法线的区间进⾏变换。由于tex2D(_BumpMap, IN.uv_BumpMap)取出的是带压缩的[0,1]之间,需要转成[-1,1]。这个函数会针对移动平台或OPENGL ES平台采⽤ RGB法线贴图,其他采⽤DXT5nm贴图。为此也可⾃⼰写。也在⽹上找到了⼀些资料,如下参考:
// Shader: 带法线贴图的Surface Shader
// Author: 风宇冲
蓝颜知己什么意思Shader "Custom/3_NormalMap" {
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_NormalMap ("NormalMap", 2D) = "white" {}
}
Subshader
{
CGPROGRAM
#pragma surface surf BlinnPhong
struct Input
{
float2 uv_MainTex;
};
//法线范围转换:单位法线 float3(x,y,z),x,y,z的取值范围是 [-1,1]。在法线贴图中被压缩在颜⾊的范围[0,1]中,所以需要转换
//(1)RGB法线贴图
float3 expand(float3 v) { return (v - 0.5) * 2; }
//(2)DXT5nm法线贴图
float3 expand2(float4 v)
{
fixed3 normal;
< = v.wy * 2 - 1;
normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
return normal;
}