Chicken shader: L12 SD processing textures to make clock animation

insert image description here

SD processing map

Uh, I feel that a large part of this class is how to use SD to process textures. I will simply put the screenshots of the get out of class here. I followed suit. Although the twelve numbers on the dial are arranged at different intervals, they are still made sparsely.

  • Vertex color
    This part of the model actually needs to be made by yourself, adding different vertex colors to the hour hand, minute hand, and second hand, but I used Blender to do it before, and I still don’t quite understand how to add vertex colors to the model completely. I use the method of selecting vertices, and the model that is not completely selected cannot match the texture (smile
    insert image description here
    insert image description here

  • Then there is the SD part, the picture below is the teacher's:
    insert image description here

  • Then this picture is mine:
    insert image description here

This part is mainly to get a little understanding before learning SD. It feels good. In fact, it is Lianliankan, but SD provides a lot of computing nodes, and some data does not need to be calculated by writing programs yourself.

Show me the results of my sparse processing:

  • Main Texture:
    insert image description here

  • normal map
    insert image description here

  • specular map
    insert image description here

Here is the teacher's explanation of this part:

  • This picture is to erase all the eyes, nose and mouth on the original model, and make it faceless.
    insert image description here
    insert image description here

  • This part is to make the dial, make 12 numbers arranged on the disc, and then perform the dial processing of the main texture, normal and specular maps on these numbers.
    insert image description here

  • This part is to deal with the main texture, normal and specular map of the previously made dial, and make a mask.
    insert image description here

The final appearance in Unity:
insert image description here
the intervals between the dials are different, and the needles on the back move strangely.

Shader code

  • Explain this _RotateOffset, this variable is mainly used for position offset later.
    insert image description here

  • I didn't use the cginclude file here, and wrote it directly in the fragment shader. You can see my code for details.
    insert image description here

  • Explain in detail the usage of _RotateOffset in the RotateZWithOffset function. It means: for example, the center of our model is in the middle of its body. If we directly calculate the three needles, it will only rotate around the middle of our body, that is, the center of the model. In this way, it can be imagined that the diameter is a red line, rotating along the largest circle, but we only want it to stay in the small circle above. So we first move the position of the needle to the center of the red diameter, and then the rotation is complete. Move it back to its original position so that it doesn't go wrong.
    insert image description here
    insert image description here

Shader "shader forge/L20_OldSchoolPlusWithClock"
{
    
    
    Properties
    {
    
    
        [Header(Texture)]
        _MainTex ("Main Tex   RGB:Base Color  A:AO_Tex", 2D) = "white" {
    
    }        
        _normal ("normal", 2D) = "bump" {
    
    }
        _SpecTex ("Spec Tex   RGB:Spec Color  A:Spec Pow", 2D) = "white" {
    
    }
        _EmittTex ("Emitt Tex   RGB:Env Tex", 2D) = "black" {
    
    }
        _cubemap ("cubemap", Cube) = "_Skybox" {
    
    }
       
        [Header(Diffuse)]
        _MainCol ("Main Color", Color) = (0.5,0.5,0.5,1.0)
        _EnvDiffInt ("Env Diff Int", Range(0, 1)) = 0.2
        _E_Lambert_UpColor ("E_Lambert_UpColor", Color) = (0.8679245,0.5444998,0.5444998,1)
        _E_Lambert_DownColor ("E_Lambert_DownColor", Color) = (0.4400143,0.6626909,0.9056604,1)
        _E_Lambert_MidColor ("E_Lambert_MidColor", Color) = (0.4800081,0.8962264,0.4016109,1)

        [Header(Specular)]
[PowerSlider(2)]        _SpecPow ("Spec Pow", Range(1, 90)) = 30        
        _EnvSpecInt ("Env_SpecInt", Range(0, 5)) = 0.7826087
        _fresnel_exp ("fresnel_exp", Range(0, 90)) = 0.6956522
        _mipmap_level ("Env Mipmap", Range(0, 7)) = 0

        [Header(Emission)]
        _EmittInt ("Emitt Int", Range(1,10)) = 1

        [Header(Clock)]
        _HourHandAngle ("Hour Angle", Range(0,360)) = 0
        _MinuteHandAngle ("Minute Angle", Range(0,360)) = 0
        _SecondHandAngle ("Second Angle", Range(0,360)) = 0
        _RotateOffset ("Rotate Offset", Range(0,5)) = 0
    }
    SubShader
    {
    
    
        Tags {
    
     "RenderType"="Opaque" }
        LOD 100

        Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
             #include "AutoLight.cginc"
            #include "Lighting.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
                float3 normal : NORMAL;
                float4 tangent : TANGENT;
                float4 color : COLOR;       //因为要做分针秒针的遮罩,所以需要顶点色
            };

            struct v2f
            {
    
    
                float2 uv0 : TEXCOORD0;                
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD1;
                float3 nDirWS : TEXCOORD2;
                float3 tDirWS : TEXCOORD3;
                float3 biDirWS : TEXCOORD4;
                LIGHTING_COORDS(5,6)
            };

            //Texture
            uniform sampler2D _MainTex;            
            uniform sampler2D _normal;
            uniform sampler2D _SpecTex;
            uniform sampler2D _EmittTex;
            uniform samplerCUBE _cubemap;           
            //Diffuse
            uniform float3 _MainCol;
            uniform float _EnvDiffInt;
            uniform float3 _E_Lambert_UpColor;
            uniform float3 _E_Lambert_DownColor;
            uniform float3 _E_Lambert_MidColor;
            //Specular
            uniform float _SpecPow;            
            uniform float _EnvSpecInt;            
            uniform float _fresnel_exp;
            uniform float _mipmap_level;
            //Emitt
            uniform float _EmittInt;
            //Clock
            uniform float _HourHandAngle;
            uniform float _MinuteHandAngle;
            uniform float _SecondHandAngle;
            uniform float _RotateOffset;

            #define TWO_PI 3.1415926*2
            //沿偏移中心做旋转
            void RotateZWithOffset(float angle, float offset, float mask, inout float3 vertex){
    
    
                //将遮罩顶点移动到模型中心点
                vertex.y -= offset * mask;
                //对遮罩顶点做旋转
                float radZ = radians(angle * mask);
                float sinZ, cosZ;
                sincos(radZ, sinZ, cosZ);
                vertex.xy = float2(vertex.x * cosZ - vertex.y * sinZ, vertex.x * sinZ + vertex.y * cosZ);
                //将遮罩顶点从模型中心点移回到原来的位置上
                vertex.y += offset * mask;
            }

            //时钟动画
            void ClockAnim(float3 color, inout float3 vertex){
    
    
                RotateZWithOffset(_HourHandAngle, _RotateOffset, color.r, vertex);
                RotateZWithOffset(_MinuteHandAngle, _RotateOffset, color.g, vertex);
                RotateZWithOffset(_SecondHandAngle, _RotateOffset, color.b, vertex);
            }

            v2f vert (appdata v)
            {
    
    
                v2f o;
                ClockAnim(v.color.rgb, v.vertex.xyz);
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv0 = v.uv0;
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);
                o.nDirWS = UnityObjectToWorldNormal(v.normal);
                o.tDirWS = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,0.0)).xyz);
                o.biDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
                TRANSFER_VERTEX_TO_FRAGMENT(o)
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                //贴图采样
                float3 nDirTS = UnpackNormal(tex2D(_normal,i.uv0)).rgb;

                //向量准备
                float3x3 TBN_Matrix = float3x3(i.tDirWS,i.biDirWS,i.nDirWS);
                float3 nDirWS_FT = normalize(mul(nDirTS, TBN_Matrix));
                float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
                float3 lrDirWS = normalize(reflect(-lightDir, nDirWS_FT));
                float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                float3 halfDir = normalize(lightDir + viewDir);
                float3 vrDir = normalize(reflect(-viewDir,nDirWS_FT));

                //准备点积结果
                float NoL = max(0.0,dot(lightDir,nDirWS_FT));
                float NoH = max(0.0,dot(nDirWS_FT,halfDir));
                float NoV = max(0.0,dot(nDirWS_FT,viewDir));
                float VoR = max(0.0,dot(viewDir, lrDirWS));

                //采样纹理
                float4 var_MainTex = tex2D(_MainTex,i.uv0);
                float4 var_SpecTex = tex2D(_SpecTex,i.uv0);
                float3 var_EmitTex = tex2D(_EmittTex,i.uv0);

                //光照模型(直接光照部分)
                float3 baseCol = var_MainTex.rgb * _MainCol;
                float lambert = max(0.0,NoL);
                float specCol = var_SpecTex.rgb;
                float specPow = lerp(1, _SpecPow,var_SpecTex.a);
                float phong = pow(max(0.0, lrDirWS), specPow);
                float shadow = LIGHT_ATTENUATION(i);
                float3 dirLighting = (baseCol * lambert + specCol * phong) * _LightColor0 * shadow;

                //光照模型(环境光照部分)

                //使用3Col环境色方法
                /*下面是环境光的漫反射部分,也就是三色环境光*/
                //上层光
                float upNor = clamp(nDirWS_FT.g,0.0,1.0);
                float3 upColor = upNor * _E_Lambert_UpColor;
                //下层光
                float downNor = clamp(nDirWS_FT.g * -1,0.0,1.0);
                float3 downColor = downNor * _E_Lambert_DownColor;
                //中层光
                float midNor = clamp(1 - upNor - downNor,0.0,1.0);
                float3 midColor = midNor * _E_Lambert_MidColor;
                /*环境光的漫反射部分  三色环境光*/
                float3 env_diff_all = clamp(upColor + downColor + midColor,0.0,1.0);

                /*下面是环境镜面反射光部分*/
                //cubemap
                float3 cubemap_Dir = vrDir;
                float3 cubemap_color = texCUBElod(_cubemap,float4(cubemap_Dir,_mipmap_level));

                //fresnel
                float OneMinusNoV = 1 - NoV;
                float fresnel = pow(OneMinusNoV,_fresnel_exp);

                float occlusion = var_MainTex.a;
                float3 envLighting = (baseCol * env_diff_all * _EnvDiffInt + cubemap_color * fresnel * _EnvSpecInt * var_SpecTex.a) * occlusion;

                //光照模型(自发光部分)
                float3 emission = var_EmitTex * _EmittInt * (sin(_Time.z) * 0.5 + 0.5);

                ///返回结果
                float3 finalRGB = dirLighting + envLighting + emission;
                return float4(finalRGB, 1.0);              
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

C# code

Then there is the C# code, which is mainly to obtain the real-time time of the system and send it to our finished shader. This part is relatively simple, just understand the API for obtaining attribute IDs and assigning values, but I will introduce more.
insert image description here
insert image description here
insert image description here
insert image description here
insert image description here

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ClockAnim : MonoBehaviour
{
    
    
    public Material Clock_Mat;

    private bool vailed = false;
    private int hourAnglePropID;
    private int minuteAnglePropID;
    private int secondAnglePropID;

    void Start()
    {
    
    
        if (Clock_Mat == null) return;

        hourAnglePropID = Shader.PropertyToID("_HourHandAngle");
        minuteAnglePropID = Shader.PropertyToID("_MinuteHandAngle");
        secondAnglePropID = Shader.PropertyToID("_SecondHandAngle");

        if (Clock_Mat.HasProperty(hourAnglePropID) && Clock_Mat.HasProperty(minuteAnglePropID) && Clock_Mat.HasProperty(secondAnglePropID))
            vailed = true;
    }

    void Update()
    {
    
    
        if (!vailed) return;
        //处理秒针
        float second = DateTime.Now.Second;
        float sec_rad = second / 60.0f * 360.0f;
        Clock_Mat.SetFloat(secondAnglePropID, sec_rad);
        //处理分针
        float minute = DateTime.Now.Minute;
        float mit_rad = minute / 60.0f * 360.0f;
        Clock_Mat.SetFloat(minuteAnglePropID, mit_rad);
        //处理时针
        float hour = DateTime.Now.Hour;
        //24个小时对应到时钟只有12个数来表示,一圈分为12格。分针转一圈,时针在表盘上移动30度。
        float hour_rad = (hour % 12) / 12.0f * 360.0f + mit_rad / 360.0f * 30.0f; 
        Clock_Mat.SetFloat(hourAnglePropID, hour_rad);
    }
}

final effect

Finally, if we want a complete moving effect, we still need to manually mount the C# script. Select our model, drag the script to the Inspector panel of the model and mount it. Then select our shader and click Run to see the three needles moving.
insert image description here
insert image description here
insert image description here
It's outrageous. If the interval is not accurate, the time must be wrong, but it is mainly for the learning effect, and these details will be fine-tuned when necessary.

Guess you like

Origin blog.csdn.net/weixin_43789369/article/details/131881471