【shader自娱自乐】shader绘制小学生图画

本文展示了使用Unity的Shader实现的一个小学生图画效果,包括顶点着色器和像素着色器的细节。通过简单的图形拆分和函数转化,模拟了天空、地面、河流、房屋、树木等元素,虽然看似复杂,但实际上难点在于图形的拆分和组织。作者还提到,使用物体本地坐标实现图形,而使用UV坐标可能更优。
摘要由CSDN通过智能技术生成

效果图(动图中的重影是动图软件的问题,不是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部分组成:

  1. 简单的光照模拟(跟图画没什么关系,只是不想矩形太奇怪)
  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;
  1. 参数设置(三色背景的占比、河流不同层次的占比、云来回的范围,树的位置)
   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;
  1. 天空、地面、河流颜色分层
   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);
  1. 河流分层流动
   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);
  1. 太阳(四分之一圆)
  background += (_SunColor - background) * step(1 - v.objPos.y, sqrt(pow(0.17, 2) -  pow(v.objPos.x, 2)));
  1. 左右飘动的云(每一片云由三个椭圆组成)
   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)));
  1. 房身(一个矩形)
    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);
  1. 房顶(两个直角三角形)
    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);
  1. 门(由两个矩形组成,一个大矩形作为门身,另一个小矩形则是门缝)
    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);
  1. 窗(每个窗由三个矩形组成,一个大矩形为窗身,另外两个为窗缝)
    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);
  1. 树冠(由三个圆形组成)
    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);
  1. 树干
    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坐标可能会好一点点。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值