庄懂的TA笔记(十四十六)<特效:火焰 + 水流>

news2024/11/29 0:53:50

庄懂的TA笔记(十四&十六)<特效:火焰 + 水流>

目录

一、作业展示:

二、示范:火:

        参考资料:

        实现思路:

        实践操作:

三、示范:水:

        实现思路:

        实践操作:


正文:

一、作业展示:

二、示范:火

(内焰 + 外焰)

参考资料:

1、火焰参考视频:

2、博客推荐:Simon schreibt.

实现思路:

1、通道使用

红:代表 火的 外 焰

绿:代表 火的 内 焰

蓝:剩余其他部分

2、噪波和形状结合

分别对 红R 绿G 两个通道 相乘* Noise 噪波图,做UV 流动Tilling

3、Noise 噪波图:

这里因为用到了两张noise噪波图,所以,分别将 两个灰度噪波图 放在 R通道,和G通道中。

这样,两张噪波混合,通过流速,和方向的修改,可以带来更多的随机性

4、实现下图右下角扰动效果

噪波1 + 噪波2 * a指形遮罩 * 渐变遮罩 = 随即流动 的 指型噪波

这里是 = 黑不透 白透.

他想要火焰下面的部分扰动少一些,所以下面黑色多一些。

他想要火焰集中在本身,所以在中间多一些白色

5、将UV和上面的遮罩相加,只用到了 V,就是Y轴,向上滚动 。

得到的结果就如下图,右下角效果。

Resulut(结果) = UV + R噪波 + G噪波 * A-1透贴 * A-2透贴

然后这里的Result 就可以 添加 自定义色彩,

绿色部分(内焰)给他一个什么颜色,

红色部分(外焰)给他一个什么颜色,

蓝色 或 A 部分 (透贴),把他们掏干净,这个事情就结束了。

如下图

实践操作:

引用AB模板开始Code代码.

1、声明出贴图和 对应 的 控制 参数:

_Mask(“R: 外焰 G:内焰 B:透贴 ”,2d )=“blue”{}

_Noise (“R: 噪波1 , G:噪波2 ”,2d)="gray"{}

对应控制参数:控制 两张噪波图的 Tilling大小流速扭曲强度 .

_Noise1Parms ("X: 大小 Y: 流速 Z: 强度 W: 无 " , vector) = (1,0.2,0.2,1)

_Noise2Parms ("X: 大小 Y: 流速 Z: 强度 W: 无 " , vector) = (1,0.2,0.2,1)

2、输出结构中定义输出3个UV,对3个UV进行控制。

UV1 采样 到 Mask

UV2 采样 到 Noise1

UV3 采样 到 Noise2

3、在 顶点shader中 将上述3个UV对应上.

o.uv0 = v.uv0;

注意:因为之前加Tilling是直接加 _ST进行控制的,但是这里,我们把两个噪波图放到了一个贴图中,如果按照_ST写,那么会让两个噪波图按照一个Tillng进行参数变换,所以这里需要我们 把他们分开来写。

重温:_ST的Tilingoffset 原理是什么 ?

** UV 乘以_ST的 XY 分量,+ ZW 分量 = 实现Tiling offset .

这里我们用的图 都是 四方连续的,所以,这里可以用一个 float 来进行 Tiling (XY)的控制,也就是XY的分量都等于一个值,做等比放缩

那么我们就可以将 已声明的_Noise1Parms 中的X分量和 o.uv1 相乘即可。

(这里噪波1 和噪波2 同理)

o.uv1 = v.uv * _Noise1Parms . x ;

o.uv2 = v.uv * _Noise2Parms . x ;


3.1、让 噪波1 和噪波2 流动起来

通过 + 取余和Time.x,并用_Noise1-2Parms中Y分量 相乘 控制(流速).

o.uv1 = v.uv * _Noise1Parms . x + frac(_Time.x * _Noise1Parms.y) ;

o.uv2 = v.uv * _Noise2Parms . x  + frac(_Time.x * _Noise2Parms.y) ;  


3.2、修正斜上流动方式;

修正:我们需要的是向上流动,而不是 斜上流动,这里发生这种情况的 原因是因为,

我们用一个一维向量(float)加到了一个 二维向量UV(float2)当中了float1同时给float2的两个参数相加所以出现了斜上的状态

解决方法:我们自己 构造 一个 二维向量,给他 加上去==其实就是float2 (0,流动).

o.uv1 = v.uv * _Noise1Parms . x + float2( 0.0, frac(_Time.x * _Noise1Parms.y)) ;

o.uv2 = v.uv * _Noise2Parms . x + float2( 0.0, frac(_Time.x * _Noise2Parms.y)) ;

这样就可以使UV在一个轴向上运动了。

上下,可以通过 更改 + - 来修改流向.

4、在像素shader中采样 和计算:

float var_Noise1 = tex2D(_Noise,i.uv1).r; (采样噪波图1,在R通道中)。

float var_Noise1 = tex2D(_Noise,i.uv1).g; (采样噪波图2,在G通道中)。


4.2、在像素shader中 开始混合 两个 Noise ,并控制强度:

//混合噪波图 = 噪波1 * Noise1Parms的Z分量(强度) + 噪波2 * Noise2Parms的Z分量(强度).

float noise = var_Noise1 * _Noise1Parms.z + var_Noise2 * _Noise2Parms.z;


4.3、在像素shader中 开始 构造 扰动 到 Mask 图:

像素shader中声明一个二维UV向量, 为扰动 Mask做准备,这里只需把i.uv0 + noise(流动扰动).

//声明一个WarpUV,用noise 来 扰动Mask的uv.

float2 warpUV = i.uv0 + noise;

(这里注意,i.uv0是二维的,noise是一维的,需要更正为构造为二维向量)。

float warpMask = tex2D(_Mask, i.uv0).b;(采样B通道渐变)

* warpMask 是为遮罩 扭曲UV 的强度

float2 warpUV = i.uv0 + float2(0,noise) * warpMask;

(这里可以看下UV长什么样子)

return float4 (i.uv0,0,1);

(这里在看下UV扰动之后的样子)

return float4(warpUV,0,1);

4.4、用扰动后的UV(WarpUV)采样Mask贴图。

float3 var_Mask = tex2D(_Mask,warpUV);

return float4 (finalRGB , 1);

4.5、添加自定义色彩 + 扣除透明:

外焰的Color * 外焰的Mask + 内焰的Color * 内焰的Mask = finalRGB

float3 finalRGB = _Color1 * var_Mask.r + _Color2 * var_Mask.g;

//扣除透明通道 红通道区域的空白 + 蓝通道区域的空白 = 黑的数值扣除。

因为retrun本身的 A 通道 就相当于 (1-输入进去的区域数值)黑的数值区域扣掉,白的数值区域保留。

float opacity = var_Mask.r + var_Mask.g;

return float4(finalRGB,opacity);

代码模板:

Shader "AP01/L16/Fire" {
    Properties {
        _Mask           ("R:外焰 G:内焰 B:透贴", 2d) = "blue"{}
        _Noise          ("R:噪声1 G:噪声2", 2d) = "gray"{}
        _Noise1Params   ("噪声1 X:大小 Y:流速 Z:强度", vector) = (1.0, 0.2, 0.2, 1.0)
        _Noise2Params   ("噪声2 X:大小 Y:流速 Z:强度", vector) = (1.0, 0.2, 0.2, 1.0)

        [HDR]_Color1    ("外焰颜色", color) = (1,1,1,1)
        [HDR]_Color2    ("内焰颜色", color) = (1,1,1,1)
    }
    SubShader {
        Tags {
            "Queue"="Transparent"               // 调整渲染顺序
            "RenderType"="Transparent"          // 对应改为Cutout
            "ForceNoShadowCasting"="True"       // 关闭阴影投射
            "IgnoreProjector"="True"            // 不响应投射器
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }
            Blend One OneMinusSrcAlpha          // 修改混合方式One/SrcAlpha OneMinusSrcAlpha
            
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入参数
            uniform sampler2D _Mask;    uniform float4 _Mask_ST;
            uniform sampler2D _Noise;
            uniform half3 _Noise1Params;
            uniform half3 _Noise2Params;
            uniform half3 _Color1;
            uniform half3 _Color2;
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv0 : TEXCOORD0;         // UV信息 采样Mask
                float2 uv1 : TEXCOORD1;         // UV信息 采样Noise1
                float2 uv2 : TEXCOORD2;         // UV信息 采样Noise2
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                    o.pos = UnityObjectToClipPos( v.vertex);    // 顶点位置 OS>CS
                    o.uv0 = TRANSFORM_TEX(v.uv, _Mask);
                    o.uv1 = o.uv0 * _Noise1Params.x - float2(0.0, frac(_Time.x * _Noise1Params.y));
                    o.uv2 = o.uv0 * _Noise2Params.x - float2(0.0, frac(_Time.x * _Noise2Params.y));
                return o;
            }
            // 输出结构>>>像素
            half4 frag(VertexOutput i) : COLOR {
                // 扰动遮罩
                half warpMask = tex2D(_Mask, i.uv0).b;
                // 噪声1
                half var_Noise1 = tex2D(_Noise, i.uv1).r;
                // 噪声2
                half var_Noise2 = tex2D(_Noise, i.uv2).g;
                // 噪声混合
                half noise = var_Noise1 * _Noise1Params.z + var_Noise2 * _Noise2Params.z;
                // 扰动UV
                float2 warpUV = i.uv0 - float2(0.0, noise) * warpMask;
                // 采样Mask
                half3 var_Mask = tex2D(_Mask, warpUV);
                // 计算FinalRGB 不透明度
                half3 finalRGB = _Color1 * var_Mask.r + _Color2 * var_Mask.g;
                half opacity = var_Mask.r + var_Mask.g;
                return half4(finalRGB, opacity);                // 返回值
            }
            ENDCG
        }
    }
}

三、示范:水

实现思路:

1、水效果实现思路:

一个RampTex扰动贴图 ,用

不同Tiling大小值 ,

不同流向

不同速度

不同强度

来实现水面的 扰动,叠加。

2、总结参数:

baseTex 基础贴图

RampTex扰动贴图:

noise01 X:Tiling大小 Y:流向 Z:速度 W:强度

noise02 X:Tiling大小 Y:流向 Z:速度 W:强度

实践操作:

1、水卡通贴图MainTex 噪波贴图WarpTex 其他控制参数

_MainTex ("颜色贴图", 2d) = "white"{}//主水面卡通贴图

_Speed ("X:流速X Y:流速Y", vector) = (1.0, 1.0, 0.5, 1.0) //控制主图流动速度

_WarpTex ("扰动图", 2d) = "gray"{} //噪波图

//噪波1的控制参数

_Warp1Params ("X:大小 Y:流速X Z:流速Y W:强度", vector) = (1.0, 1.0, 0.5, 1.0)

//噪波2的控制参数

_Warp2Params ("X:大小 Y:流速X Z:流速Y W:强度", vector) = (2.0, 0.5, 0.5, 1.0)

2、顶点结构中 为 MainTex 和 WarpTex 增加 对应UV控制

MainTex占用1个UV。

WarpTex占用2个UV。

o.uv0 = TRANSFORM_TEX(v.uv, _MainTex) - frac(_Time.x * _Speed);

这里因为水面是需要 U 和 V两个方向都流动,就不能沿用上个火的案例来构造偏移量了。

那么两个轴 都需要 我们怎么写呢?

UV分量分别是 YZ的流速。

o.uv1 = v.uv * _Warp1Params.x - frac(_Time.x * _Warp1Params.yz);

o.uv2 = v.uv * _Warp2Params.x - frac(_Time.x * _Warp2Params.yz);

3、像素shader中,采样 Warp贴图和MainTex贴图:

采样Warp贴图和MainTex贴图:

half3 var_Warp1 = tex2D(_WarpTex, i.uv1).rgb; // 扰动1

half3 var_Warp2 = tex2D(_WarpTex, i.uv2).rgb; // 扰动2

混合两个扰动强度

half2 warp = (var_Warp1.yz - 0.5) * _Warp1Params.w +

                      (var_Warp2.yz - 0.5) * _Warp2Params.w;

UV扰动相加:

float2 warpUV = i.uv0 + warp;

采样MainTex 并输出:

half4 var_MainTex = tex2D(_MainTex, warpUV);

return float4(var_MainTex.xyz, 1.0);

代码示例:

Shader "AP01/L16/Water" {
    Properties {
        _MainTex        ("颜色贴图", 2d) = "white"{}
        _WarpTex        ("扰动图", 2d) = "gray"{}
        _Speed          ("X:流速X Y:流速Y", vector) = (1.0, 1.0, 0.5, 1.0)
        _Warp1Params    ("X:大小 Y:流速X Z:流速Y W:强度", vector) = (1.0, 1.0, 0.5, 1.0)
        _Warp2Params    ("X:大小 Y:流速X Z:流速Y W:强度", vector) = (2.0, 0.5, 0.5, 1.0)
    }
    SubShader {
        Tags {
            "RenderType"="Opaque"
        }
        Pass {
            Name "FORWARD"
            Tags {
                "LightMode"="ForwardBase"
            }


            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #pragma multi_compile_fwdbase_fullshadows
            #pragma target 3.0
            // 输入参数
            uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
            uniform sampler2D _WarpTex;
            uniform half2 _Speed;
            uniform half4 _Warp1Params;
            uniform half4 _Warp2Params;
            // 输入结构
            struct VertexInput {
                float4 vertex : POSITION;       // 顶点位置 总是必要
                float2 uv : TEXCOORD0;          // UV信息 采样贴图用
            };
            // 输出结构
            struct VertexOutput {
                float4 pos : SV_POSITION;       // 顶点位置 总是必要
                float2 uv0 : TEXCOORD0;         // UV信息 采样Mask
                float2 uv1 : TEXCOORD1;         // UV信息 采样Noise1
                float2 uv2 : TEXCOORD2;         // UV信息 采样Noise2
            };
            // 输入结构>>>顶点Shader>>>输出结构
            VertexOutput vert (VertexInput v) {
                VertexOutput o = (VertexOutput)0;
                    o.pos = UnityObjectToClipPos( v.vertex);    // 顶点位置 OS>CS
                    o.uv0 = v.uv - frac(_Time.x * _Speed);
                    o.uv1 = v.uv * _Warp1Params.x - frac(_Time.x * _Warp1Params.yz);
                    o.uv2 = v.uv * _Warp2Params.x - frac(_Time.x * _Warp2Params.yz);
                return o;
            }
            // 输出结构>>>像素
            float4 frag(VertexOutput i) : COLOR {
                half3 var_Warp1 = tex2D(_WarpTex, i.uv1).rgb;      // 扰动1
                half3 var_Warp2 = tex2D(_WarpTex, i.uv2).rgb;      // 扰动2
                // 扰动混合
                half2 warp = (var_Warp1.xy - 0.5) * _Warp1Params.w +
                             (var_Warp2.xy - 0.5) * _Warp2Params.w;
                // 扰动UV
                float2 warpUV = i.uv0 + warp;
                // 采样MainTex
                half4 var_MainTex = tex2D(_MainTex, warpUV);

                return float4(var_MainTex.xyz, 1.0);
            }
            ENDCG
        }
    }
    FallBack "Diffuse"
}

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

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

相关文章

Mybatis Plus 使用@TableLogic实现逻辑删除

文章目录 步骤1:修改数据库表添加deleted列步骤2:实体类添加属性步骤3:运行删除方法知识点1:TableLogic 接下来要讲解是删除中比较重要的一个操作,逻辑删除,先来分析下问题: 这是一个员工和其所签的合同表,关系是一个员工可以签多…

如何用 ChatGPT 帮你10分钟读完数据库论文

本周,OpenAI 向所有 ChatGPT Plus 用户开放了两个重要功能: Web Browsing 和 Plugins 它俩都需要用户自己开启,才能使用,如下: 作为对数据库论文的爱好者,我第一款挑选的 Plugin 便是 ChatWithPDF,毕竟真的…

基于脉冲神经网络的物体检测

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 研究的意义在于探索脉冲神经网络在目标检测上的应用,目前主流的脉冲神经网络训练算法有直接BP训练、STDP无监督训练和训练好的ANN的转化,虽然训练算法众多,但是SNN仍然没有一套成熟的训练算…

games101作业3

作业要求 修改函数 rasterize_triangle(const Triangle& t) in rasterizer.cpp: 在此 处实现与作业 2 类似的插值算法,实现法向量、颜色、纹理颜色的插值。 修改函数 get_projection_matrix() in main.cpp: 将你自己在之前的实验中 实现的投影矩阵填到此处&am…

【JUC基础】08. 三大工具类

1、前言 JUC包中包含了三个非常实用的工具类:CountDownLatch(倒计数器),CyclicBarrier(循环栅栏),Semaphore(信号量)。 2、倒计数器:CountDownLatch 2.1、…

基于Java+SpringBoot+Vue前后端分离机票预定/订购系统设计与实现(视频讲解)

博主介绍:✌全网粉丝3W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

章节2 Matplotlib 绘图基础

目录 课时 2 Matplotlib简介及绘制简单线型图 课时 3 图例和标题 课时 4 自定义图形样式 课时 4 绘制条形图 课时 2 Matplotlib简介及绘制简单线型图 线的画法 plt.plot,同时提供x轴坐标和y轴坐标 课时 3 图例和标题 x 轴数据默认即可,如下所示 x轴代…

SimpleDateFormat非线程安全问题

文章目录 1. SimpleDateFormat介绍2. 测试SimpleDateFormat的非线程安全性3. 解决方案一4. 解决方案二 1. SimpleDateFormat介绍 SimpleDateFormat是Java中的一个类,用于将日期对象格式化为特定的字符串表示形式,或者将特定格式的字符串解析为日期对象。…

netstat 连接通信的信息和状态、以及ss

netstat 常用参数 t 只显示tcpu只显示udpnnum 数字形式显示地址和端口号l listen 显示监听端口 pprogram 显示进程aall 所有连接和监听r显示路由表 netstat -lnp 显示服务监听端口tcpudpsocket ,socket 文件也用来同一台服务器的进程之间通信的…

Spring中的MergedBeanDefinitionPostProcessor有什么作用 ?

Spring中的MergedBeanDefinitionPostProcessor有什么作用 ? 引言调用时机加载bean定义的几种方式postProcessMergedBeanDefinition接口作用小结 引言 MergedBeanDefinitionPostProcessor这个Bean后置处理器大家可能关注的比较少,其本身也只提供了一个bean生命周期回调接口: …

iptable 防火墙一

目录 iptables概述netfilter/iptables 关系四表五链四表:五链: 规则链之间的匹配顺序主机型防火墙:规则链内的匹配顺序: iptables 安装iptables防火墙的配置方法:iptables 命令行配置方法:常用的控制类型&a…

一文读懂大语言模型

以ChatGPT为代表的大语言模型被很多人认为是新一轮科技革命的起点,本文旨在通过概念性介绍,让普通人能够尽可能理解人工智能以及大语言模型的基本概念,从而了解这些技术能做以及不能做什么。原文: A Very Gentle Introduction to Large Langu…

v4l2数据结构分析

v4l2数据结构分析 文章目录 v4l2数据结构分析Video4Linux2设备v4l2_device媒体设备media_deviceVideo4Linux2子设备v4l2_subdevVideo4Linux2子设备的操作集v4l2_subdev_opsVideo4Linux2子设备的内部操作集v4l2_subdev_internal_opsVideo4Linux2控制处理器v4l2_ctrl_handlerVide…

微信自动聊天机器狗,配置chatGPT,比Siri还智能!

大家好,我是TheWeiJun;最近看见微信里各个群聊都在聊chatGPT,甚至有的大佬们都把chatGPT接入了微信群聊,于是就有粉丝来找小编,希望能出一期chatGPT的文章;故今天这篇文章我将手把手教大家如何实现并自定义…

学习《信息系统项目管理师教程》第4版应关注的PMBOK的巨大变化

学习《信息系统项目管理师教程》第4版应关注的PMBOK的巨大变化 《信息系统项目管理师教程》的第4版比起第3版来有不少变化。但是,这种变化完全没有体现出PMBOK第7版带来的巨大变化。 因为,在从《信息系统项目管理师教程》第3版出版的2017年到现在&…

uvc驱动中的v4l2

uvc驱动中的v4l2 文章目录 uvc驱动中的v4l2v4l2_device_registervideo_register_devicev4l2_ioctlsvideo_usercopy v4l2_device_register /driver/media/v4l2-core/v4l2-device.c uvc_probe->v4l2_device_register v4l2_device_register 只是用于初始化一些东西&#xff0c…

【数项级数】无穷个数相加一定是个数吗?

数项级数 引入思考问题转化 定义总结重要的例子练习题 引入 思考 数项级数,其实就是要解决无穷个数相加的问题。 而对于无穷求和的问题,思考:无穷个数相加一定是个数吗? 下面,我们来举几个例子: 1 2 2 …

创世纪:比特币诞生记

比特币的诞生 1. 创始区块2. 第一个举手的人3. 比特币的疯狂 1. 创始区块 2008年10月31日纽约时间下午2点10分,自称中本聪的人向一个邮件列表,包括密码学专家和爱好者几百个成员,发送了一封电子邮件。“我一直在研究一个新的电子现金系统&am…

springboot旅游资源管理系统门票酒店预订系统_b0a6b

Spring Boot 是 Spring 家族中的一个全新的框架,它用来简化Spring应用程序的创建和开发过程。也可以说 Spring Boot 能简化我们之前采用SSM(Spring MVC Spring MyBatis )框架进行开发的过程。config:主要用来存储配置文件&#…

chatgpt赋能Python-pythoncontinue怎么用

Python continue语句:提高代码效率的绝佳工具 什么是Python continue语句? Python的continue语句可以使循环跳过当前的迭代。这意味着如果在循环内部存在满足某特定条件的语句,那么我们就可以使用continue语句跳过当前循环。Python中的cont…