赞
踩
Living without an aim is like sailing without a compass.(John Ruskin)
接下来要做的就是对官方的着色器案例进行讲解,本着学习的态度,我会尽量解释每一行代码,因为还没有毕业,剩下的时间比较多,我会写的比较详细(慢&懒)
因为我也是新手,所以我很理解新手的痛处吗,在一开始我不会一下子列出好多好多的语法,或者是好多 好多的关键字,咱们一起从例子中不断的学习,虽然很慢,但是shader这条路是没有捷径的
若有不足之处 还望路过的前辈们不吝赐教(拱手状 O(∩_∩)O)
突然发现自己学和写出来一步一步进行讲解真的很不一样,应该是技术水平过于拙劣吧
step1
从最基础讲SurfaceShader,需要介绍其常用的标准的表面着色器输出结构(SurfaceOutput)
struct SurfaceOutput
{
half3 Albedo; //表面着色器当中常于做漫反射的颜色值,也就是SurfaceShader常用来进行输出的颜色值
half3 Normal; //游戏物体(mesh)的表面法线坐标
half3 Emission; //自发光颜色
half Specular; //镜面高光
half Gloss; //光泽系数
half Alpha; //透明度系数
};
看完很蒙?
那就对了。。。说明我不是一个人O(∩_∩)O哈哈~(狂笑)
没关系,大家先放一放,紧接着会在案例中对这些属性及其作用进行讲解,先有个印象好了
step2
表面着色器的编译指令
我们在写vertex&*fragment shader 时 经常会为其指定一个通道进行渲染,但是SurfaceShader不可以放在通道(pass)内,因为表面着色器会自身编译为多个通道。
Shader"Example / AutisticPatient SurfaceShader1"
{
SubShader
{
CGPROGRAM
//表面着色器编译指令, #pragma + surface + surfaceFunction + LightModle
//这里指定了unity3D的内建光照模型:Lambert
#pragma surface surf Lambert
//其中“Input”是自定义的结构。Input 结构应包含表面函数所需的任何纹理坐标和额外自动变量。
//SurfaceOutput刚才说了 是表面着色器标准输出结构体,这里Input将作为输入结构体,SurfaceOutput将用于输出
void surf(Input IN, SurfaceOutput o)
{
}
ENDCG
}
}
step3
表面着色器的输入结构体
下面是一部分可以放在输入结构体当中的值
struct Input
{
float2 uv_MainTex; //主纹理UV坐标值
float2 uv2_MainTex; //使用第二纹理坐标值
float3 viewDir; //包含视线方向
float4 screenPos; //屏幕空间位置
float3 worldPos; // 将包含世界坐标空间位置。
};
剩下的不管有没有提到 都会在接下来的shader实例中进行讲解
表面着色器实例
(1)
因为是对官方案例的讲解,所以就按照官方的顺序来,我会逐句进行解释
并配上效果图供大家参考(图片是Down的)
从一个简单的SurfaceShader开始
Shader"Example / AutisticPatient SurfaceShader2"
{
//刚开始官方给的是一个不需要纹理的shader,所以这里并没有大家常见的Properties
//开始一个子shader
SubShader
{
//Tags 用来指示渲染引擎如何渲染,以及何时渲染。+ 标签有多种,灯光标签,队列标签等
//这行代码的意思是此shader渲染不透明对象
//RenderType tag 是渲染标签,它常用的有:
//Opaque
//Transparent
//TransparentCutout
//Background
//Overlay
Tags{"RenderType" = "Opaque"}
//开始CG
CGPROGRAM
//定义表面着色器,并指定了unity内置的光照模式lambert(漫反射光照模式)
#pragma surface surf Lambert
//表面着色器输入结构体
//为什么里面能写颜色值上边已经说过了
struct Input
{
float4 color : COLOR;
};
//这个函数便是我们上面定义好的表面着色器 名称一定要完全相同.
//然后将我们定义好的输入结构体放进去
//想要使得表面着色器能够输出我们想要的颜色值,还必须将标准的表面着色器结构体作为输出放进形参内.
//这里使用了inout关键字,意思是 SurfaceOutput结构体中传进来的参数既作输入也做输出.
void surf(Input IN,inout SurfaceOutput o)
{
//相当于o.Albedo = (1,1,1)不要问为啥了吧(痛哭状)
o.Albedo = 1;
//所以最后整个表面着色函数输出的便是SurfaceOutput下的Albedo值了.
}
ENDCG
}
//这里需要设置一个备胎着色器,如果以上着色器不能被设备支持
//便会使用下面的Diffuse着色器
fallback"Diffuse"
}
这个shader就不上效果图了,实在是没啥可看的,咳咳~
(2)
接下来是有纹理贴图的shader
Shader"Example / AutisticPatient SurfaceShader3"
{
//属性块,这一代码块中定义的属性是对整个shader的定义(这句话可能不太恰当)
//比如说,我们想要一个融化效果,那么在shader中肯定会有融化纹理以及主纹理的定义
//还有包括融化速度,融化边缘效果等等,这些属性都是要在Properties中进行定义的
Properties
{
//_MainTex的作用是关联整个shader代码,下面我们会在CG中进行关联,只有关联上,我们才能对这个纹理进行修改等操作
//"MainTex" 的作用是在Inspector面板中创建一个可视化操作台,方便开发者在外部进行修改贴图,不需要修改shader.
//2D的作用的指定我们所定义的对象的类型,这里是指2D纹理类型,如果你想定义一个贴图,那么就要用到它了
//等号后面,不说了,就是初始化而已
_MainTex("MainTex",2D) = "white"{}
}
SubShader
{
Tags{"RenderType" = "Opaque"}
CGPROGRAM
#pragma surface surf Lambert
//输入结构体用于描述贴图的uv坐标,只有得到了uv坐标,才能对纹理进行采样等操作
struct Input
{
//命名格式 uv + _MainTex
float2 uv_MainTex;
};
//properties里已经说过了,想要对纹理贴图进行操作,就必须关联上
//而为什么用sampler2D呢
//如果在Properties使用2D,CG里要用sampler2D,代表使用的是2维纹理
//这是王八的屁股,规定(龟腚)
sampler2D _MainTex;
void surf(Input IN,inout SurfaceOutput o)
{
//tex2D是CG程序中用来对一张贴图(这里是_MainTex)中对一个点(IN.uv_MainTex)进行采样的方法
//返回一个float4类型,并将其颜色的rgb值赋给了输出的像素颜色
//总的来说,着色器会找到贴图上对应的UV坐标点,直接使用这个点的颜色信息rgb来进行着色.
o.Albedo = tex2D(_MainTex,IN.uv_MainTex).rgb;
}
ENDCG
}
FallBack"Diffuse"
}
ok 上个效果图先
本节就到这里吧
刚开始有很多细节是不能跳过的,所以注释会显得过于冗长(其实就是表达能力弱(。・・)ノ)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。