菜鸡shader:L12 SD处理贴图制作时钟动画

news2024/12/28 1:55:53

文章目录

  • SD处理贴图
  • Shader代码
  • C#代码
  • 最后效果

在这里插入图片描述

SD处理贴图

呃呃感觉这节课,很大一部分都是在将怎么用SD来处理贴图,在这里就简单放一下课上的截图吧,我也跟着做了一下,虽然表盘十二个数排列间隔不一样,但还是稀碎地做出来了。

  • 顶点色
    这部分的模型其实还是需要自己来制作的,给时针分针秒针加上不同的顶点色,但是之前用Blender做了一下,还是不太明白怎么完整地给模型加上顶点色,我用的是选中顶点的方式,没有完全选中做出来的模型不能匹配贴图(苦笑
    在这里插入图片描述
    在这里插入图片描述

  • 然后是SD部分,下面这张图是老师的:
    在这里插入图片描述

  • 然后这张图是我的:
    在这里插入图片描述

这部分主要还是为了在学习SD之前有点了解,感觉还行,其实就是连连看,但是SD提供了非常多的计算节点,一些数据完全不需要自己写程序来算。

展示一下我稀碎的处理结果:

  • 主纹理:
    在这里插入图片描述

  • 法线贴图
    在这里插入图片描述

  • 高光贴图
    在这里插入图片描述

放一下老师对于这部分的解释:

  • 这张图是要将原来模型上的眼睛鼻子嘴巴全部抹掉,无脸化处理。
    在这里插入图片描述
    在这里插入图片描述

  • 这部分是要制作表盘,做出12个排列在圆盘上的数字,然后对这些数字分别进行主纹理,法线和高光贴图的表盘处理。
    在这里插入图片描述

  • 这部分是要处理之前做好的表盘的主纹理,法线和高光贴图,并制作遮罩。
    在这里插入图片描述

最后在Unity里的样子:
在这里插入图片描述
表盘间隔不一样,后面针走起来也很怪。

Shader代码

  • 解释下这个_RotateOffset,这个变量主要还是为了后面做位置偏移的时候用的。
    在这里插入图片描述

  • 这里我没用cginclude文件,直接写在片元着色器里了。具体可以看我代码。
    在这里插入图片描述

  • 具体解释下RotateZWithOffset函数中_RotateOffset的用法,它的意思是是:比如说我们一个模型的中心在它的身体正中间,儿如果我们直接对三根针进行计算的话,它只会绕着我们的身体正中间也就是模型中心进行旋转,这样就可以想象成直径是红线,沿着最大的那个大圆旋转,但我们只想让它呆在上面的小圆中旋转,所以我们先将这跟针的位置移动到红色直径的中心,旋转完了,再移回原本的位置,这样就不会出错了。
    在这里插入图片描述
    在这里插入图片描述

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#代码

然后是C#代码,这部分主要还是为了获取系统的实时时间并传送给我们做好的shader。这部分比较简单,就了解下获取属性ID和赋值的API就行了,不过多介绍。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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);
    }
}

最后效果

最后想要一个完整动起来的效果还是需要我们手动挂载一下C#脚本的,选中我们的模型,将脚本拖到模型的Inspector面板下就挂载了,然后再选择我们的shader,点击运行就能看见三根针动起来了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
很离谱啊,这个间隔不精准的话时间肯定是错的,不过主要还是为了学习效果,这些细节有需要的时候再进行细调。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/783047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ARM Cache 系列文章 2 -- Cache Coherence及内存顺序模学习】

文章目录 Cache Coherence 背景1.1 内存顺序模型简介(Memory Model)1.1.1 Normal Memory1.1.2 Device Memory 1.2 Cache 一致性问题解决方案1.2.1 Shareability 属性1.2.2 Non-Shareable 属性1.2.3 Inner-Shareable 属性1.2.4 Out-Shareable 属性 1.3 Shareability 和 PoC/PoU …

【MATLAB第59期】基于MATLAB的混沌退火粒子群CSAPSO-BP、SAPSO-BP、PSO-BP优化BP神经网络非线性函数拟合预测/回归预测对比

【MATLAB第59期】基于MATLAB的混沌退火粒子群CSAPSO-BP、SAPSO-BP、PSO-BP优化BP神经网络非线性函数拟合预测/回归预测对比 注意事项 不同版本matlab 不同电脑 加上数据集随机,BP权值阈值随机,进化算法种群随机,所以运行结果不一定和我运行…

20.matlab数据分析极限(matlab程序)

1.简述 计算极限 MATLAB提供计算极限的limit函数。在其最基本的形式中,limit函数将表达式作为参数,并在独立变量为零时找到表达式的极限。 例如,要计算函数f(x)(x^3 5)/(x^4 7)的极限,因为x趋向于零。 syms xlimit((x^3 5)/…

设计模式 ~ 职责链、策略、适配器、MVC、MVVM

职责链模式 一种行为型设计模式,它允许多个对象按照特定的顺序处理请求,直到其中一个对象能够处理该请求为止; 一个流程,需要多个角色处理,通过 一个“链”串联起来,各个角色相互分离,互不干扰…

使用 Cpolar 内网穿透实现 Windows 远程 WebDAV 访问

文章目录 windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户…

机器学习术语解析与应用(一)

文章目录 🍀引言🍀数据集🍀特征工程(Feature Engineering)🍀模型(Model)🍀算法(Algorithm)🍀训练(Training)&a…

【广州华锐互动】VR汽车故障维修模拟系统

随着汽车行业的发展,汽车机械检修技术也变得越来越重要。传统的教学方式已经不能满足现代汽车维修的需求,因此VR汽车故障维修模拟系统应运而生。这个平台具有许多实用的功能,可以帮助学生更好地学习和掌握汽车机械检修技能。 VR汽车故障维修模…

【Linux】无法获得dpkg前端锁的解决方法

问题如下: 解决方法如下: sudo rm /var/lib/dpkg/lock sudo rm /var/lib/dpkg/lock-frontend sudo rm /var/cache/apt/archives/lock经过证明,输入以上三个命令即可解除占用。 解除后,继续运行apt命令,已经顺利运行了…

2023-07-19-Ubuntu火狐浏览器不能播放视频

layout: post # 使用的布局 title: Ubuntu火狐浏览器不能播放视频 # 标题 subtitle: linux系统 #副标题 date: 2023-07-19 # 时间 author: BY ThreeStones1029 # 作者 header-img: img/no_found_html5.jpg #这篇文章标题背景图片 catalog: true # 是否归档 tags: Ubuntu #标签 …

vue实现excel数据下载,后端提供的list由前端转excel并下载

前言,因为项目需求需要,我们需要把后端传来的list转成excel模板,并且下载下来) 之前有用的插件,但是会有少0的情况,如下 所以采用另一个项目用过的方法,最终完美实现效果,如下: 1,首先我们来看下后端提供的数据结构 2,具体前端代码如下 封装的组件,需要的同学直接copy就行(这…

【Linux】VMware 安装 Centos7 超详细

1、下载✈ VMware链接:https://pan.baidu.com/s/1DnleWeV-JHjZiV9_ENwFmg?pwdb1tj 提取码:b1tj 阿里云镜像:centos安装包下载_开源镜像站-阿里云 CentOS官网镜像: Download 2、虚拟机准备 2.1、打开VMware选择新建虚拟机…

vector 容器相关的练习

目录 一、只出现一次的数字 二、只出现一次的数字 II 三、只出现一次的数字 III 四、删除有序数组中的重复项 五、杨辉三角 六、数组中出现次数超过一半的数字 七、电话号码的字母组合 一、只出现一次的数字 class Solution { public:int singleNumber(vector<int&g…

springboot()—— springboot整合mybatis

总结&#xff1a; 和SSM相比&#xff0c; 1&#xff09;导入的包不同 2&#xff09;不再有mybatis的核心配置文件了&#xff0c;也不同单独写db.properties了&#xff0c;以前“开启二级缓存&#xff0c;起别名”等在核心配置文件里的配置全都配置到application.properties里…

前端实现文件上传的方式

这个文章总结了四种前端上传文章的方式 <inputtype"file"multipleonChange{(e) > {const c [].slice.call(e.target.files);console.log(e.target.files, e.target.files);console.log(e.target.files.arrary, c);const v new FormData();v.append(file, c[…

K8S初级入门系列之九-共享存储

一、前言 Pod里面的容器都有自己独立的文件系统&#xff0c;来自容器镜像&#xff0c;用于保存容器运行的数据&#xff0c;但容器的文件存储有两个弊端&#xff0c;一个是无法持久化&#xff0c;其生命周期与容器一致&#xff0c;一旦容器销毁&#xff0c;相关的数据也就随之一…

0134 数据的表示和运算3

目录 2.数据的表示和运算 2.3浮点数的表示与运算 2.3部分习题 2.数据的表示和运算 2.3浮点数的表示与运算 2.3部分习题 1.下列关于对阶操作&#xff0c;正确的是&#xff08;&#xff09; A.在浮点加减运算的对阶操作中&#xff0c;若阶码减小&#xff0c;则尾数左移 …

pytorch工具——认识pytorch

目录 pytorch的基本元素操作创建一个没有初始化的矩阵创建一个有初始化的矩阵创建一个全0矩阵并可指定数据元素类型为long直接通过数据创建张量通过已有的一个张量创建相同尺寸的新张量利用randn_like方法得到相同尺寸张量&#xff0c;并且采用随机初始化的方法为其赋值采用.si…

数值线性代数:知识框架

记录数值线性代数研究的知识框架。 软件包线性方程组直接法Guass消元法/LU分解、Cholesky分解 LAPACK oneAPI MKL ARPACK Octave 迭代法Jacobi迭代、SOR迭代、共轭梯度法最小二乘特征值/特征向量非对称幂法、QR、Arnoldi分解对称QR、Jacobi、二分法、分治法、SVD 参考资料 G…

【C语言day03】

参数a是指针&#xff0c;要接收地址&#xff0c;BD错误。参数b可以接收的是char*&#xff0c;而&c的类型是char(*)[10]&#xff0c;C错误全局变量i&#xff0c;在main()中修改为5&#xff0c;第一次在prt()中执行循环输出三次*&#xff0c;i被修改为8&#xff0c;回到main(…

MyBatis学习笔记——3

MyBatis学习笔记——3 一、MyBatis小技巧1.1、#{}和${}1.2、typeAliases1.3、mappers1.4、插入数据时获取自动生成的主键 二、MyBatis参数处理2.1、单个简单类型参数2.2、 Map参数2.3、实体类参数2.4、多参数2.5、 Param注解&#xff08;命名参数&#xff09;2.6、 Param源码分…