效果图(动图中的重影是动图软件的问题,不是shader的效果)
顶点着色器
v2f vert(a2v a)
{
v2f v;
v.objPos = a.vertex.xyz + float3(0.5, 0.5, 0.5);
v.pos = UnityObjectToClipPos(a.vertex);
v.normal = UnityObjectToWorldNormal(a.normal);
v.worldPos = mul(unity_ObjectToWorld, a.vertex);
return v;
}
简单的顶点着色器
像素着色器
float4 frag(v2f v) : SV_TARGET
{
float3 worldNormal = normalize(v.normal);
float3 viewDir = normalize(_WorldSpaceCameraPos - v.worldPos);
float3 env = _Color * 0.7f;
float3 ambient = _Color * 0.3 * max(0, dot(viewDir, worldNormal));
fixed3 result = env + ambient;
fixed skyPercent = 0.55;
fixed riverPercent = 0.2;
fixed3 riverFlowColor = float3(1, 1, 1) * 0.2;
float randomRange = sin(v.objPos.x - _Time.y / 20) * 10;
float randomRange1 = sin(v.objPos.x - _Time.y / 15) * 14;
float cloudXRange = v.objPos.x + sin(_Time.y / 15) * 0.1;
float cloudXRange1 = v.objPos.x + sin(_Time.y / 15) * 0.1;
fixed treeX = 0.77;
if (v.objPos.z == 0)
{
fixed3 background = _SkyColor * step(skyPercent, v.objPos.y);
background += _GroundColor * step(v.objPos.y, skyPercent) * step(riverPercent, v.objPos.y);
background += _RiverColor * step(v.objPos.y, riverPercent);
background += riverFlowColor * step(v.objPos.y, riverPercent / 7 * sin(randomRange) + riverPercent / 1.7);
background += riverFlowColor * step(v.objPos.y, riverPercent / 10 * cos(randomRange1) + riverPercent / 5);
background += (_SunColor - background) * step(1 - v.objPos.y, sqrt(pow(0.17, 2) - pow(v.objPos.x, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.4, 2) / pow(0.12, 2)) * pow(0.09, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.4, 2) / pow(0.12, 2)) * pow(0.09, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.3, 2) / pow(0.1, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.3, 2) / pow(0.1, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.5, 2) / pow(0.1, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.5, 2) / pow(0.1, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.8, 2) / pow(0.12, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.8, 2) / pow(0.12, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.75, 2) / pow(0.1, 2)) * pow(0.05, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.75, 2) / pow(0.1, 2)) * pow(0.05, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.85, 2) / pow(0.1, 2)) * pow(0.05, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.85, 2) / pow(0.1, 2)) * pow(0.05, 2)));
background += (_HouseColor - background) * step(v.objPos.y, 0.6) * step(0.5, v.objPos.y) * step(v.objPos.x, 0.19) * step(0.15, v.objPos.x);
background += (_HouseColor - background) * step(v.objPos.y, 0.5) * step(0.3, v.objPos.y) * step(v.objPos.x, 0.47) * step(0.13, v.objPos.x);
background += (_CeilingColor - background) * step(v.objPos.y, 0.75 * v.objPos.x + 0.425) * step(0.5, v.objPos.y)
* step(v.objPos.x, 0.3) * step(0.1, v.objPos.x);
background += (_CeilingColor - background) * step(v.objPos.y, -0.75 * v.objPos.x + 0.875) * step(0.5, v.objPos.y)
* step(v.objPos.x, 0.5) * step(0.3, v.objPos.x);
background += (_DoorColor - background) * step(v.objPos.y, 0.37) * step(0.3, v.objPos.y) * step(0.26, v.objPos.x) * step(v.objPos.x, 0.34);
background += -background * step(v.objPos.y, 0.37) * step(0.3, v.objPos.y) * step(0.298, v.objPos.x) * step(v.objPos.x, 0.302);
background += (_CloudColor - background) * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.17, v.objPos.x) * step(v.objPos.x, 0.23);
background += (_CloudColor - background) * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.37, v.objPos.x) * step(v.objPos.x, 0.43);
background += -background * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.198, v.objPos.x) * step(v.objPos.x, 0.202);
background += -background * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.398, v.objPos.x) * step(v.objPos.x, 0.402);
background += -background * step(0.428, v.objPos.y) * step(v.objPos.y, 0.432) * step(0.17, v.objPos.x) * step(v.objPos.x, 0.23);
background += -background * step(0.428, v.objPos.y) * step(v.objPos.y, 0.432) * step(0.37, v.objPos.x) * step(v.objPos.x, 0.43);
background += (_LeafColor - background) * step(v.objPos.y, 0.6 + sqrt(pow(0.13, 2) - pow(v.objPos.x - treeX, 2)))
* step(0.6 - sqrt(pow(0.13, 2) - pow(v.objPos.x - treeX, 2)), v.objPos.y);
background += (_LeafColor - background) * step(v.objPos.y, 0.53 + sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX - 0.07), 2)))
* step(0.53 - sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX - 0.07), 2)), v.objPos.y);
background += (_LeafColor - background) * step(v.objPos.y, 0.53 + sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX + 0.07), 2)))
* step(0.53 - sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX + 0.07), 2)), v.objPos.y);
background += (_TreeColor - background) * step(0.3, v.objPos.y) * step(v.objPos.y, 0.5) * step((treeX - 0.03), v.objPos.x) * step(v.objPos.x, (treeX + 0.03));
result = background;
}
return float4(result, 1.0);
}
这个像素着色器由12部分组成:
- 简单的光照模拟(跟图画没什么关系,只是不想矩形太奇怪)
float3 worldNormal = normalize(v.normal);
float3 viewDir = normalize(_WorldSpaceCameraPos - v.worldPos);
float3 env = _Color * 0.7f;
float3 ambient = _Color * 0.3 * max(0, dot(viewDir, worldNormal));
fixed3 result = env + ambient;
- 参数设置(三色背景的占比、河流不同层次的占比、云来回的范围,树的位置)
fixed skyPercent = 0.55;
fixed riverPercent = 0.2;
fixed3 riverFlowColor = float3(1, 1, 1) * 0.2;
float randomRange = sin(v.objPos.x - _Time.y / 20) * 10;
float randomRange1 = sin(v.objPos.x - _Time.y / 15) * 14;
float cloudXRange = v.objPos.x + sin(_Time.y / 15) * 0.1;
float cloudXRange1 = v.objPos.x + sin(_Time.y / 15) * 0.1;
fixed treeX = 0.77;
- 天空、地面、河流颜色分层
fixed3 background = _SkyColor * step(skyPercent, v.objPos.y);
background += _GroundColor * step(v.objPos.y, skyPercent) * step(riverPercent, v.objPos.y);
background += _RiverColor * step(v.objPos.y, riverPercent);
- 河流分层流动
background += riverFlowColor * step(v.objPos.y, riverPercent / 7 * sin(randomRange) + riverPercent / 1.7);
background += riverFlowColor * step(v.objPos.y, riverPercent / 10 * cos(randomRange1) + riverPercent / 5);
- 太阳(四分之一圆)
background += (_SunColor - background) * step(1 - v.objPos.y, sqrt(pow(0.17, 2) - pow(v.objPos.x, 2)));
- 左右飘动的云(每一片云由三个椭圆组成)
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.4, 2) / pow(0.12, 2)) * pow(0.09, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.4, 2) / pow(0.12, 2)) * pow(0.09, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.3, 2) / pow(0.1, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.3, 2) / pow(0.1, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.5, 2) / pow(0.1, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.85 + sqrt((1 - pow(cloudXRange1 - 0.5, 2) / pow(0.1, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.8, 2) / pow(0.12, 2)) * pow(0.07, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.8, 2) / pow(0.12, 2)) * pow(0.07, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.75, 2) / pow(0.1, 2)) * pow(0.05, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.75, 2) / pow(0.1, 2)) * pow(0.05, 2)));
background += (_CloudColor - background) * step(0.87 - sqrt((1 - pow(cloudXRange1 - 0.85, 2) / pow(0.1, 2)) * pow(0.05, 2)), v.objPos.y)
* step(v.objPos.y, 0.87 + sqrt((1 - pow(cloudXRange1 - 0.85, 2) / pow(0.1, 2)) * pow(0.05, 2)));
- 房身(一个矩形)
background += (_HouseColor - background) * step(v.objPos.y, 0.6) * step(0.5, v.objPos.y) * step(v.objPos.x, 0.19) * step(0.15, v.objPos.x);
background += (_HouseColor - background) * step(v.objPos.y, 0.5) * step(0.3, v.objPos.y) * step(v.objPos.x, 0.47) * step(0.13, v.objPos.x);
- 房顶(两个直角三角形)
background += (_CeilingColor - background) * step(v.objPos.y, 0.75 * v.objPos.x + 0.425) * step(0.5, v.objPos.y)
* step(v.objPos.x, 0.3) * step(0.1, v.objPos.x);
background += (_CeilingColor - background) * step(v.objPos.y, -0.75 * v.objPos.x + 0.875) * step(0.5, v.objPos.y)
* step(v.objPos.x, 0.5) * step(0.3, v.objPos.x);
- 门(由两个矩形组成,一个大矩形作为门身,另一个小矩形则是门缝)
background += (_DoorColor - background) * step(v.objPos.y, 0.37) * step(0.3, v.objPos.y) * step(0.26, v.objPos.x) * step(v.objPos.x, 0.34);
background += -background * step(v.objPos.y, 0.37) * step(0.3, v.objPos.y) * step(0.298, v.objPos.x) * step(v.objPos.x, 0.302);
- 窗(每个窗由三个矩形组成,一个大矩形为窗身,另外两个为窗缝)
background += (_CloudColor - background) * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.17, v.objPos.x) * step(v.objPos.x, 0.23);
background += (_CloudColor - background) * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.37, v.objPos.x) * step(v.objPos.x, 0.43);
background += -background * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.198, v.objPos.x) * step(v.objPos.x, 0.202);
background += -background * step(0.4, v.objPos.y) * step(v.objPos.y, 0.46) * step(0.398, v.objPos.x) * step(v.objPos.x, 0.402);
background += -background * step(0.428, v.objPos.y) * step(v.objPos.y, 0.432) * step(0.17, v.objPos.x) * step(v.objPos.x, 0.23);
background += -background * step(0.428, v.objPos.y) * step(v.objPos.y, 0.432) * step(0.37, v.objPos.x) * step(v.objPos.x, 0.43);
- 树冠(由三个圆形组成)
background += (_LeafColor - background) * step(v.objPos.y, 0.6 + sqrt(pow(0.13, 2) - pow(v.objPos.x - treeX, 2))) * step(0.6 - sqrt(pow(0.13, 2) - pow(v.objPos.x - treeX, 2)), v.objPos.y);
background += (_LeafColor - background) * step(v.objPos.y, 0.53 + sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX - 0.07), 2))) * step(0.53 - sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX - 0.07), 2)), v.objPos.y);
background += (_LeafColor - background) * step(v.objPos.y, 0.53 + sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX + 0.07), 2))) * step(0.53 - sqrt(pow(0.1, 2) - pow(v.objPos.x - (treeX + 0.07), 2)), v.objPos.y);
- 树干
background += (_TreeColor - background) * step(0.3, v.objPos.y) * step(v.objPos.y, 0.5) * step((treeX - 0.03), v.objPos.x) * step(v.objPos.x, (treeX + 0.03));
总结
这个小学生图画的效果看上去内容很多,但实际难度在于怎么拆分成简单图形以及图形的函数该怎么转化。因此当你大概知道怎么实现以后,更多的是觉得麻烦而不是难。
另外就是,因为我实现这个效果是在做完上一个颜色闪烁的效果后做的,所以绘制图形的时候也是用的物体本地坐标,但实际用uv坐标可能会好一点点。