菜鸡shader:L10 帧序列动画和极坐标的使用

news2024/11/26 2:27:40

文章目录

  • 帧序列动画
    • 代码
    • 最后效果
  • 极坐标
    • 代码
    • 最后效果
  • 顶点色

这次笔记就直接放最后的效果了,因为课程上老师也没有给代码图片或是什么技巧说明。

  • 下图左边是帧序列动画(鬼火),右边是极坐标。
    在这里插入图片描述

帧序列动画

帧序列的原理是对一张有规律行列排序的序列帧贴图进行采样,伴随时间的变化,显示的贴图内容也不一样,序列帧贴图如下所示:
在这里插入图片描述

  • 可以看到是规律大小排列的一系列的图片。

我们的原理是:
在这里插入图片描述

  • 首先,整张图的UV坐标是以黄色坐标系为主的,原点在整张图片的左下角。
  • 我们为了得到每一张小图片,就需要对这张贴图进行切割,将每一张小图片均分,方便我们后面切换小图片。
  • 我们需要将大UV转变为一个小图片UV。所以我们用1分别除行数和列数,因为大UV的取值范围为[0,1],用1除以行数和列数,就能得到每一个小图片的uv的取值范围,U的取值就变成[0,1/列数],V的取值就变成[0,,1/行数]。
  • 注意,上面这步得到的UV就变成了左下角小图片的UV,uv坐标的原点依旧是左下角。
  • 但是我们想要的是从左到右,从上到下的一个顺序,所以还需要将UV原点移到第一行第一列的位置。
  • 当移动完UV坐标后,每切换下一张图片只需要一个算法就行了,具体看我代码。

在这里插入图片描述

  • 我们的动画是像壳子一样套在模型的外部的,所以我们需要模型的顶点法线,沿着法线方向向外偏移一定的距离,做出像壳子一样的效果。
  • 帧序列动画是做在壳子上的,所以需要用第二个Pass来处理,所以这部分shader用了双pass。
  • 第一个Pass就是普通地采样一张主纹理,用了AB方法。
  • 第二个Pass使用了法线,用来处理帧序列动画,用了AD方法。

代码

Shader "shader forge/L18_FireSequence"
{
    Properties
    {
        _MainTex ("Base Color With A", 2D) = "white" {}
        _Opacity ("Opacity", Range(0.0,1.0)) = 0.5
        _Sequence ("Sequence Texture",2D) = "gray" {}       //帧序列图
        _RowCount ("Row",Int) = 3                                       //行数
        _ColCount ("Col",Int) = 4                                          //列数
        //_SeqID ("Sequence ID",Int) = 0                                 //帧序列号
        _Speed ("Speed", Range(-10,10)) = 3
    }
    SubShader
    {
    	//主要做的
        Tags {
            "Queue"="Transparent" 
            "RenderType" = "Transparent"
            "ForceNoShadowCasting" = "True"
            "IgnoreProjector" = "True"
        }        

        Pass
        {
        NAME "FORWARD_AB"

        Tags{
            "LightMode" = "ForwardBase"
        }

        Blend SrcAlpha OneMinusSrcAlpha		//AB

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv0 : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            uniform sampler2D _MainTex;
            uniform float4 _MainTex_ST;	//我们的贴图偏移选项
            uniform float _Opacity;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv0 = TRANSFORM_TEX(v.uv0, _MainTex);		//加上贴图偏移
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 var_MainTex = tex2D(_MainTex, i.uv0);
                float3 finalRGB = var_MainTex.rgb;                
                half opacity = var_MainTex.a * _Opacity;
                return float4(finalRGB * opacity, opacity);
            }
            ENDCG
        }

        Pass
        {
        NAME "FORWARD_AD"
        Tags{
            "LightMode" = "ForwardBase"
        }
        Blend One One
        //Cull Front

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal:NORMAL;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            uniform sampler2D _Sequence;
            uniform float4 _Sequence_ST;	//我们的贴图偏移选项
            uniform half _RowCount;     //行数
            uniform half _ColCount;     //列数
            //uniform half _SeqID;            //帧序列号
            uniform half _Speed;

            v2f vert (appdata v)
            {
                v2f o;
                //因为第二个pass是用来处理帧序列动画的,这个动画就像是壳子一样套在原模型的外面一层,所以需要让这个pass的模型顶点位置沿着法线方向增加一定的距离
                v.vertex.xyz += v.normal * 0.003;     
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv,_Sequence);       //为了能让它支持Tiling和offset
                half seqID = floor(_Time.z * _Speed);         //根据时间来取序列号
                half rowID = floor(seqID / _ColCount);     //根据_SeqID算出行号
                half ColID = seqID % _ColCount;              //根据_SeqID算出列号
                half stepU = 1.0 / _ColCount;                        //计算每次移动的U值偏移,因为UV坐标的范围都为[0,1]
                half stepV = 1.0 / _RowCount;                       //计算每次移动的V值偏移,因为UV坐标的范围都为[0,1]
                half2 initUV = o.uv * float2(stepU,stepV);      //将uv从范围[0,1]缩放为[stepU,stepV]

                //因为默认uv坐标从左下角开始,我们要做一下缩放,将缩放成单个序列帧uv大小
                initUV += float2(0.0, stepV * (_RowCount - 1));                 
                //然后做偏移,将图片uv坐标的原点移动到第一个序列帧的uv坐标原点上
                o.uv = initUV + float2(stepU * ColID, -stepV * rowID);      
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 var_Sequence = tex2D(_Sequence, i.uv);
                fixed3 finalRGB = var_Sequence.rgb;
                fixed opacity = var_Sequence.a;
                return fixed4(finalRGB * opacity, opacity);
            }
            ENDCG
        }
    }
}

最后效果

在这里插入图片描述

极坐标

极坐标部分也是对UV坐标进行一种计算,但是是使用角度和长度来代替UV坐标。
如下图所示:
在这里插入图片描述

  • 首先,这张帖图的UV坐标是在这张帖图的左下角为原点的绿色坐标系。
  • 我们要把UV坐标移动到红色坐标系,UV的取值范围也从[0,1]变为[-0.5,0.5],坐标系的原点也就变成了图片的中心。
  • 然后根据UV坐标值,算出图片上某一点的角度θ,和距离原点的长度。
  • 因为角度θ是角度,取值范围是[-pi,pi],所以我们要将它的取值范围转变为0,1
  • 获取我们求的这一点距离原点的距离,并为它添加上不断变化的部分(为了有动画效果)
  • 然后将角度和长度作为新的UV去采样贴图,就能得到一个极坐标动画。

代码

Shader "shader forge/L18_PolarCoord"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Opacity ("Opacity",Range(0,1)) = 0.5
        _Color ("Color",Color) = (1.0,1.0,1.0,1.0)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            uniform sampler2D _MainTex;
            uniform half _Opacity;
            uniform half4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                i.uv -= float2(0.5,0.5);
                half theta = atan2(i.uv.y,i.uv.x);              //获得uv坐标的夹角
                theta = theta / 3.1415926 * 0.5 + 0.5;    //将夹角取值范围从(-pi,pi)转换到[-1,1]在转换到[0,1]
                half dist = length(i.uv) + frac(_Time.x * 3);
                i.uv = float2(theta, dist);

                half4 var_MainTex = tex2D(_MainTex,i.uv);
                half3 finalRGB = var_MainTex.rgb;
                half opacity = var_MainTex.a * _Opacity;
                //Alpha 通道是为保存选择区域而专门设计的通道,所以第四个值取1或者0或任意值都没什么变化
                return float4(finalRGB * opacity,opacity);      //真正让图片变透明的不是Alpha 实际是Alpha所代表的数值和其他数值做了一次运算
            }
            ENDCG
        }
    }
}

最后效果

在这里插入图片描述
在这里插入图片描述

顶点色

在这里要说一下,老师上课的这个极坐标动画的模型是事先在建模软件中处理过的,在面片的周围一圈和中心都是黑色,所以极坐标动画在这个面片上播放的时候会有一个渐显渐隐的效果:
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

35. 反转链表

目录 链接: 题目: 思路: 代码: 图片: 链接: 原题链接 题目: 定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。 思考题: 请同时…

逻辑(css)-背景网格制作(linear-gradient)

目录 linear-gradient需求实现 linear-gradient 语法:linear-gradient([direction], color-stop1, color-stop2, ...) 第一个参数为(可选)方向参数,可以是度数也可以是方位名词,方向与读书的关系如下: 角度方位文字说明示例0degto top从下…

centos7 环境下部署 nacos单机模式

1、官网下载 nacos 官网地址:home 去github上下载nacos-server。我下载的是 nacos-server-1.4.1.tar.gz 2、安装 nacos 下载完成后,将安装包上传到 centos 创建 nacos 目录(安装位置任意) mkdir -p /usr/local/nacos解压 nac…

springboot html乱码

一、问题重现 二、代码展示 代码的编码都是正常的 修改了File Encodings配置项,结果不管用 三、终极解决方案 终于解决

MATLAB 基于CPD的点云配准 (24)

MATLAB 基于CPD的点云配准 (24) 一、算法简介二、具体使用1.代码(注释详细)2.函数介绍3.使用技巧4.重复叠加配准效果如何一、算法简介 MATLAB 中包含了一种基于CPD的点云配准方法,这里对其进行使用,查看其配准效果,结果来看如上图所示,还是可用的。 二、具体使用 1.代…

模板类和友元

模板类和友元 非模板友元约束模板友元 非模板友元 友元函数不是模板函数,而是利用模板类参数生成的函数,只能在类内实现。 友元函数访问类的私有变量的方法: 将模板类的引用传递给友元函数: 测试调用: 对于有多个…

Android oom_adj 更新原理(二)

源码基于:Android R 接上一篇:Android oom_adj 更新原理(一) 12. computeOomAdjLocked() frameworks/base/services/core/java/com/android/server/am/OomAdjuster.javaprivate final boolean computeOomAdjLocked(ProcessRecord app, int cachedAdj,Pr…

深入解析Android Lifecycle;从基本使用到源码实现,全面掌握生命周期管理

Lifecycle 是 Android Jetpack 中的一个组件,用于管理 Android 应用组件(如 Activity 和 Fragment)的生命周期。通过使用 Lifecycle,开发者可以更容易地管理组件的生命周期并执行相关的操作。 Lifecycle 提供了一组生命周期事件&…

关于torch.load()更改了cuda位置还是cuda内存不够的问题

关于torch.load()变了cuda位置还是cuda内存不够的问题 问题背景:在一次任务中,由于需要使用cuda进行代码运行,但是分明修改了cuda到一个空闲的卡位置,但是依然抱错cuda out of memory的问题 在任务中,最开始原始代码是…

Node+mysql-注册和登录账号实现(原生)

1.创建数据表 说明:创建id,username,password字段,并设置了类型。 2.导入mysql库 npm i mysql2.18.1 3.创建了db文件夹 说明:创建mysql数据池 // 导入mysql包 const mysqlrequire("mysql") // 创建mysql连接池 const…

react-flow实现dag工作流

1. 官方文档 Introduction to React Flow 2.效果 3. 代码 index.jsx import { useState, useCallback, useEffect } from react; import ReactFlow, {Controls,Background,applyNodeChanges,applyEdgeChanges,addEdge,ReactFlowProvider,useReactFlow } from reactflow;…

C++编程(二)—— 设计模式

文章目录 单例模式饿汉式单例模式懒汉式单例模式懒汉式单例模式2 工厂模式(创建型模式)简单工厂工厂方法抽象工厂总结 单例模式 一个类不管创建多少次多线,永远只能得到该类型一个对象的实例。 A* p1 new A(); A *p2 new A(); A *p3 new…

msvcr110.dll丢失的修复教程,找不到msvcr110.dll解决办法哪个更推荐

msvcr110.dll是微软的Visual C运行库文件之一。它是Microsoft Visual Studio 2012的一部分,用于支持运行在Windows操作系统上使用Visual C编写的应用程序。在Windows系统中非常重要,如果丢失或是损坏就会造成很多程序无法启动运行。 会出现以下的报错提…

将C++对象注册成QML控件并提供可被调用的函数

0x00 使用QML编写界面 import QtQuick 2.14 import QtQuick.Window 2.14 import QtQuick.Controls 1.4 import QtQuick.Controls 2.12 as Controls import QtQuick.Controls.Styles 1.4 import QtQuick.Controls.Material 2.12 //import com.HLD 1.0Window {visible: true;mini…

赛效:WPS文档怎么在文本中插入连续的编号

1:打开一个WPS文档,全选所有的段落。 2:点击“开始”选项卡里点击编号下拉菜单,选择一种编号样式并点击。 3:我们会看到每段前面已经自动出现编号,而且是连续的。这个时候,我们在文档末尾新增一…

基于串行和并行ADMM算法在分布式调度中的应用(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

管理软件开发平台:用科技提升数据治理能力,实现流程化办公!

如果实现流程化办公,想必是很多企业心心念念的发展愿望。但是,如何实现?利用什么样的平台可以完成这一目标?这是很多人值得深思的问题之一。管理软件开发平台实行100%全源码开放,是轻量级、可视化低代码开发平台&#…

6.带你入门matlab 协方差和相关系数( matlab程序)

1.简述 协方差 Vcov(X) Vcov(X,flag(同上)); X为矩阵 相关系数 Rcorr(X) X为矩阵 协方差和相关系数函数的使用如下 代码及运行结果 %% 协方差 clear a…

kaggle学习笔记-餐厅数据挖掘

Zomato Complete EDA and LSTM model 背景 分析Zomato数据集的基本思想是为了公平地了解影响在班加罗尔不同地方建立不同类型餐厅的因素,每个餐厅的总评级,班加罗尔是这样一个城市,拥有超过12,000家餐厅,餐厅供应来自世界各地的…

Android 源码编译方法

和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、查看项目所在分支二、切换到目标分支三、查看当前所在分支四、编译Android源码五、source Android 编译环境六、lunch 所需的编译项目七、单编 模块…