前1篇介绍了如果编写最基本的shader,接下来本文将会简单的深入1下,我们先来看下效果吧
呃,gif效果不好,实际效果是很平滑的动态过渡
1.首先我们要实现1个彩色方块
2.让色采动起来
over
先看代码吧:
Shader "LT/Lesson2"
{
Properties {
_OffsetX ("Offset X", Range (-1.5, 1.5) ) = 0
_OffsetY ("Offset Y", Range (-1.5, 1.5) ) = 0
_OffsetZ ("Offset Z", Range (-1.5, 1.5) ) = 0
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct VertextOutput {
float4 pos : SV_POSITION ;
fixed4 col : COLOR ;
};
uniform float _OffsetX;
uniform float _OffsetY;
uniform float _OffsetZ;
VertextOutput vert ( appdata_base input )
{
VertextOutput result;
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
return result;
}
fixed4 frag ( VertextOutput input ) : COLOR
{
return input.col;
}
ENDCG
}
}
}
恩~~,首先呢,我们这次输出的色彩不同的位置色彩不同,所以我们需要1个同时能存位置和色彩的结构体:
struct VertextOutput {
float4 pos : SV_POSITION ;
// 位置信息, 后面的: SV_POSITION是必须的,固然你也能够换成: POSITION
fixed4 col : COLOR ;
// 色彩信息, 后面的: COLOR不是必须的,你可以随意取名字比如 : FUCK
// 但是嘛,为了代码方便浏览,还是写成COLOR吧
};
然后呢我们只有这样1个模型:
24个顶点(每一个面顶点单算的),12个3角形,两个空的UV(这个是unity自带的cube模型)
这个模型是没有任何色彩信息,所以我们需要自己在shader中生成他的色彩
出于方便斟酌,我们将这个模型的顶点(XYZ)变成RGB的色彩,由于恰好3个值都有变化嘛
因而有了这样的代码
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
前面顶点位置就不作处理了,直接换算成Unity坐标就完了
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
然后我们来讲说传入参数中的appdata_base
对VertextOutput vert ( appdata_base input )这个函数命名
学过C语言的应当知道前面是返回值类型 括号里面是传入值类型和名字吧
然后这个appdata_base呢是定义在#include “UnityCG.cginc”的1个结构体
(强行带节奏引入了UnityCG.cginc,其实也能够像前面1篇1样使用float4 position : POSITION,只是这里为了早点引入UnityCG.cginc而已)
我们可以看1下UnityCG.cginc的部份代码:
// Dynamic & Static lightmaps contain indirect diffuse ligthing, thus ignore SH
#define UNITY_SHOULD_SAMPLE_SH ( defined (LIGHTMAP_OFF) && defined(DYNAMICLIGHTMAP_OFF) )
struct appdata_base {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct appdata_tan {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
};
struct appdata_full {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
#if defined(SHADER_API_XBOX360)
half4 texcoord4 : TEXCOORD4;
half4 texcoord5 : TEXCOORD5;
#endif
fixed4 color : COLOR;
};
全部有点小长,我只粘贴1部份,其实就是1大堆Unity的定义而已,
我们再来看看
struct appdata_base {
float4 vertex : POSITION; //位置
float3 normal : NORMAL; //法线
float4 texcoord : TEXCOORD0; // 纹理
};
其实这是1个简化的模型数据,包括了1些经常使用的参数,如果我们写的shader主要是给手机使用的话,这些数据基本也就够了,而且目前我们也就用了他的位置的信息,固然你也能够传入1个appdata_full 类型,区分不大
至于_OffsetX,_OffsetY,_OffsetZ3个外接属性的定义就不多做赘述了
然后我们就通过
VertextOutput vert ( appdata_base input )
{
VertextOutput result;
result.pos = mul(UNITY_MATRIX_MVP , input.vertex ) ;
result.col = input.vertex + float4( _OffsetX, _OffsetY, _OffsetZ, 0);
return result;
}
计算出了相应顶点的色彩
然后直接在面片渲染函数中把对应点的色彩赋值给他就好了
return input.col;
注意这里我们的传入参数变成了vert 的返回值
fixed4 frag ( VertextOutput input ) : COLOR
好来看下初步的效果:
这里我们就完成了1个RBG CUBE了。
下面对1些原理性的东西简单解释1下
前面我解释过vert函数是1个顶点调用1次,这里我们的模型1共才24个顶点,但是为啥出来这么多个色彩呢,这里就跟渲染流程的光栅化有关。默许情况下,光栅化会保持平滑过渡,如果两边不匹配就会在中间插值,然后对我们的模型而言,1个面上每一个顶点的色彩都不同,所以他就会自动插入很多个顶点,并且自动渐变色彩来满足平滑过渡(也就是说如果你色彩都1样,就不会插点了,固然你也能够手动不让它插点,概念比较多,这里就不展开了,我们要快速上手嘛)
这里是我强行要加的1个功能,不然感觉这篇blog就太少内容咯,哈哈
有两种实现方法:
1.unity中通过C#代码去控制刚才开放出来的参数
2.shader中自己通过时间去更改色彩
我们既然是学shader,固然是在shader中进行更改啦
直接上代码:
result.col = input.vertex + float4( _SinTime.w + 0.5, _SinTime.w + 0.5, _SinTime.w + 0.5, 0);
呃,对,就改这1行。效果就是实现啦,大家可以自己行试1下
下面解释1小下下:
_SinTime是unity为shader内置的1个时间的sin值得变量(看名字也看的出来吧)
需要引入#include “UnityCG.cginc” (这也是为啥我前面强行带节奏的缘由)
然后来普及下Unity为我们内置了哪些东西吧:
Transformations 变换
float4x4 UNITY_MATRIX_MVP
Current model*view*projection matrix
当前物体*视*投影矩阵。(注:物体矩阵为 本地->世界)
float4x4 UNITY_MATRIX_MV
Current model*view matrix
当前物体*视矩阵
float4x4 UNITY_MATRIX_P
Current projection matrix
当前物体*投影矩阵
float4x4 UNITY_MATRIX_T_MV
Transpose of model*view matrix
转置物体*视矩阵
float4x4 UNITY_MATRIX_IT_MV
Inverse transpose of model*view matrix
逆转置物体*视矩阵
float4x4 UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3
Texture transformation matrices
贴图变换矩阵
float4x4 _Object2World
Current model matrix
当前物体矩阵
float4x4 _World2Object
Inverse of current world matrix
物体矩阵的逆矩阵
float3 _WorldSpaceCameraPos
World space position of the camera
世界坐标空间中的摄像机位置
float4 unity_Scale
xyz components unused; .w contains scale for uniformly scaled objects.
不适用xyz份量,而是通过w份量包括的缩放值等比缩放物体。
_ModelLightColor float4 Material's Main * Light color 材质的主色彩*灯光色彩
_SpecularLightColor float4 Material's Specular * Light color 材质的镜面反射(高光)*灯光色彩。
_ObjectSpaceLightPos float4 Light's position in object space. w component is 0 for directional lights, 1 for other lights
物体空间中的灯光为,平行光w份量为零其灯光为1;
_Light2World float4x4 Light to World space matrix 灯光转世界空间矩阵
_World2Light float4x4 World to Light space matrix 世界转灯光空间矩阵
_Object2Light float4x4 Object to Light space matrix 物体转灯光空间矩阵
float4 _Time : Time (t/20, t, t*2, t*3), use to animate things inside the shaders
时间: 用于Shasder中可动画的地方。
float4 _SinTime : Sine of time: (t/8, t/4, t/2, t)
时间的正弦值。
float4 _CosTime : Cosine of time: (t/8, t/4, t/2, t)
时间的余弦值
float4 _ProjectionParams : 投影参数
x is 1.0 or ⑴.0, negative if currently rendering with a flipped projection matrix
x为1.0 或⑴.0如果当前渲染使用的是1个反转的投影矩阵那末为负。
y is camera's near plane y是摄像机的近剪裁平面
z is camera's far plane z是摄像机远剪裁平面
w is 1/FarPlane. w是1/远剪裁平面
float4 _ScreenParams : 屏幕参数
x is current render target width in pixels x是当前渲染目标在像素值中宽度
y is current render target height in pixels y是当前渲染目标在像素值中的高度
z is 1.0 + 1.0/width z是1.0+1.0/宽度
w is 1.0 + 1.0/height w是1.0+1.0/高度
呃,格式不是很好看的模样,这里有链接,自己去看吧http://www.ceeger.com/Components/SL-BuiltinValues.html
有了这些东西以后呢,我们就能够简单的根据时间变化做1些动态shader了,比如甚么UV活动啊,色彩动态变化啊,动态模型(是动态模型不是模型动画哈)啥的,瞬间就高大上了有不有,性能嘛取决于你写的代码(一样的代码级别下,shader速度秒杀你在c#中写)
这1篇感觉写的比较乱,主要是知识点比较杂(这理由不是很好找啊….谅解我语文老师是数学老师教大的)
主要知识点是介绍1下光栅化那个插值,这个很重要https://en.wikibooks.org/wiki/Cg_Programming/Rasterization(虽然我讲的1笔带过,大家去看看官方解释吧)
然后介绍1下UnityCG.cginc,我们既然是写的unityshader,固然还是要常常使用这个库的啦,后面还有光照,空间矩阵啥的,基本我们要想做高级殊效离不开这个库的,大家可以去看看这个库源码
了解了这些以后,就是单纯的算法了(比如怎样通过时间更改模型顶点位置实现好看的动画啥的)
恩~~~再次坦白下写的比较乱,如有疑问欢迎联系QQ:8215804671起探讨