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

文章目录

  • 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 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"#include "AutoLight.cginc"#include "Lighting.cginc"#pragma multi_compile_fwdbase_fullshadows#pragma target 3.0struct 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)};//Textureuniform sampler2D _MainTex;            uniform sampler2D _normal;uniform sampler2D _SpecTex;uniform sampler2D _EmittTex;uniform samplerCUBE _cubemap;           //Diffuseuniform float3 _MainCol;uniform float _EnvDiffInt;uniform float3 _E_Lambert_UpColor;uniform float3 _E_Lambert_DownColor;uniform float3 _E_Lambert_MidColor;//Specularuniform float _SpecPow;            uniform float _EnvSpecInt;            uniform float _fresnel_exp;uniform float _mipmap_level;//Emittuniform float _EmittInt;//Clockuniform 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);/*下面是环境镜面反射光部分*///cubemapfloat3 cubemap_Dir = vrDir;float3 cubemap_color = texCUBElod(_cubemap,float4(cubemap_Dir,_mipmap_level));//fresnelfloat 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.mzph.cn/news/7832.shtml

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

相关文章

脉冲频率、转速相关计算(信捷PLC C语言FC编程应用)

转速、线速度、角速度转换和计算关系请查看下面文章链接: 转速/线速度/角速度计算FC_RXXW_Dor的博客-CSDN博客里工业控制张力控制无处不在,也衍生出很多张力控制专用控制器,磁粉制动器等,本篇博客主要讨论PLC的张力控制相关应用和算法,关于绕线机的绕线算法,大家可以参看…

12.Netty源码之整体架构脉络

Netty 整体架构脉络 Netty 的逻辑处理架构为典型网络分层架构设计,共分为网络通信层、事件调度层、服务编排层,每一层各司其职。 网络通信层 网络通信层的职责是执行网络 I/O 的操作。它支持多种网络协议和 I/O 模型的连接操作。当网络数据读取到内核缓冲…

闲置旧手机搭建服务器?在安卓手机上使用Termux搭建web服务「公网远程访问」

文章目录 概述1.搭建apache2.安装cpolar内网穿透3.公网访问配置4.固定公网地址5.添加站点 概述 Termux是一个Android终端仿真应用程序,用于在 Android 手机上搭建一个完整的Linux 环境,能够实现Linux下的许多基本操作,不需要root权限Termux就…

docker系列5:docker安装nginx

传送门 前面介绍了docker的安装:docker系列1:docker安装 还有docker镜像加速器:docker系列2:阿里云镜像加速器 以及docker的基本操作: docker系列3:docker镜像基本命令 以及容器的基本命令:…

【iOS】多界面传值

文章目录 前言一、属性传值二、协议传值三、block传值四、KVO传值五、KVO的自动触发与手动触发六、通知传值总结 前言 在写网易云音乐以及3GShare包括后面的学生管理系统时,用到许多界面传值方法,特撰写博客记录目前学过的几种多界面传值方法 一、属性…

【Docker】Docker部署私有仓库的配置及应用

文章目录 一、Docker-registry 搭建本地私有仓库1. Registry 的概念2. Registry 的部署过程 二、Docker-harbor 搭建私有仓库1. 什么是Harbor2. Harbor 的特性3. Harbor的构成4. Harbor 的部署过程4.1 安装 harbor4.2 创建项目并进行上传下载4.3 上传镜像到私有仓库4.4 从私有仓…

Vue--插槽

一、插槽-默认插槽 1.作用 让组件内部的一些 结构 支持 自定义 2.需求 将需要多次显示的对话框,封装成一个组件 3.问题 组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办 4.插槽的基本语法 组件内需要定制的结构部分,改用**…

mysql的主键选择

一.没有定义主键有什么问题 如果定义了主键,那么InnoDB会使用主键作为聚簇索引如果没有定义主键,那么会使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作为聚簇索引如果既没有主键也找不到合适的非空索引,那么In…

【数据挖掘】时间序列的傅里叶变换:用numpy解释的快速卷积

一、说明 本篇告诉大家一个高级数学模型,即傅里叶模型的使用; 当今,傅里叶变换及其所有变体构成了我们现代世界的基础,为压缩、通信、图像处理等技术提供了动力。我们从根源上理解,从根本上应用,这是值得付…

STM32MP157驱动开发——按键驱动(线程化处理)

文章目录 “线程化处理”机制:内核函数线程化处理方式的按键驱动程序(stm32mp157)编程思路button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “线程化处理”机制: 工作队列是在内核的线程的上下文中执行的 工作队列中有多个 work&#xff0…

Git远程仓库使用方法

目录 介绍 详细教程 1、创建远程仓库 2、在本地初始化仓库 3、关联远程仓库 4、提交代码 5、拉取到本地仓库 6、提交到Git仓库 5、将本地代码推送到远程仓库 介绍 远程仓库在协同开发中起着关键的作用,它提供了一个中央存储库,使多个开发者能够…

Hadoop中HDFS的架构

一、Switch语句 语法规则: ①语句中的变量类型可以是byte、short、int或者char;从javaSE5开始支持枚举类型; javaSE7开始,switch支持String。 ②没有break时,后续case的语句都会执行 二、修饰符 访问修饰符 Java中&#xff0c…

【C++】vector类的模拟实现(增删查改,拷贝构造,赋值运算,深浅拷贝)

文章目录 前言一、 整体1.命名空间:2构造函数:1普通构造2迭代器构造3初始化字符构造4拷贝构造: 3析构函数 二、成员函数实现1.大小1当前大小(size())2总体容量(capacity()) 2.返回头尾迭代器1begin()2end()…

小程序如何修改商品

​商家可能会遇到需要修改产品信息的情况。无论是价格调整、库存更新还是商品描述的修改,小程序提供了简便的方式来帮助你们完成这些操作。下面是一些简单的步骤和注意事项,帮助你们顺利地修改商品。 一、进入商品管理页面 在个人中心点击管理入口&…

矿井人员视频行为分析算法 opencv

矿井人员视频行为分析算法通过opencvpython网络模型技术,矿井人员视频行为分析算法实时监测人员的作业行为,并与安全标准进行比对,可以及时发现不符合安全要求的行为,预防事故的发生。OpenCV的全称是Open Source Computer Vision …

教师ChatGPT的23种用法

火爆全网的ChatGPT,作为教师应该如何正确使用?本文梳理了教师ChatGPT的23种用法,一起来看看吧! 1、回答问题 ChatGPT可用于实时回答问题,使其成为需要快速获取信息的学生的有用工具。 从这个意义上说,Cha…

【N32L40X】学习笔记10-外部触发方式计数

定时器采用外部触发方式计数 也就是外部时钟源模式2 此模式由 TIMx_SMCTRL .EXCEN 选择等于 1。计数器可以在外部触发输入 ETR 的每个上升沿或下降沿 计数。 极性选择分频选择过滤选择选择外部时钟ETR模式 bsp_time_counter_ETR.h #ifndef _BSP_TIME_COUNTER_ETR_H_ #defi…

AI数字人:金融数字化转型的“关键先生”

今年年初ChatGPT的火热,在全球掀起一阵生成式AI(AIGC)热潮。国外的OpenAI、国内的百度等企业,都在AIGC上强力布局。 各种应用场景中,AIGC助力的数字人引起了市场注意。 事实上,数字人不是个新鲜事。早在1…

在Ubuntu 系统下开发GUI,用哪种开发工具比较好?

在Ubuntu系统下开发GUI,你可以考虑使用以下几种开发工具:Qt Creator:Qt Creator是一个跨平台的集成开发环境,专门用于开发基于Qt框架的应用程序。它提供了丰富的图形界面设计工具和代码编辑器,支持C和QML编程。Qt Crea…

UI 自动化稳定性用例实战经验分享!

目录 前言: 大家常说 UI 自动化不稳定,那又如何提高稳定性呢? 操作界面非预期的弹框、广告、浮层 测试系统的 A/B 策略 总结: 前言: 稳定性测试是软件测试的一个重要方面,它旨在评估软件在不同负载和…