UnityShader实例18:火焰材质

2024-05-28 23:32

本文主要是介绍UnityShader实例18:火焰材质,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

火焰材质



概述

       3D游戏中,火焰特效是一种3D游戏中的一种常见特效,通常是使用粒子播放器播放序列帧或者直接使用粒子模拟,在本文中将实现一个区别于这两种方法的火焰效果(如下图),这个火焰的效果来源于一个朋友推荐给我的文章,是一个老外的作品(演示效果源代码),效果非常不错,还模拟了风的效果,美中不足的是这个shader只支持target 3.0以上,鉴于此我做一些修改,并做了一定的优化,右图就是本文实现的效果,使之能支持target 2.0。






原理

       原作者火焰实现的效果主要使用了三张贴图(如下图),一张颜色梯度图,一张噪波图,以及一张alpha图;

       其shader主要通过几个个步骤实现火焰效果:

  • 将噪波贴图做了三次不同的uv位移动画采样,并将采样的颜色值叠加作为uv值,对颜色梯度图采样,实现火焰的流动效果以及火焰的絮状效果
  • 同时在vert函数中使用tex2Dlod函数(此函数需要target3.0以上支持)采样到噪波图的颜色值,对模型的顶点进行扰动,实现火焰的膨胀震动效果
  • 使用一个传入的向量结合模型的顶点色对模型顶点做偏移效果,实现火焰随风摆动的效果。
  • 第一步采样的噪波图颜色值做为uv值对alpha图采样作为火焰的alpha值,,当然还需要乘以一个边缘光的值使火焰的边缘透明。

       我实现的效果思路和这个基本一样,只是将第二步的顶点扰动效果,使用了unity内置的函数对模型顶点做的扰动,以保证对target 3.0以下版本的支持。





shader实现

       在开始实现火焰效果时首先需要建一个火焰的模型,如下图所示,其中刷了顶点色,需要使用到顶点色的红色通道和alpha透明通道。



       为了便于调整火焰的颜色以及形态,需要开放了一些参数:

  • _WindFreqScale:控制模型波动的频率;
  • _WindPower :xyz分量控制风的方向,w分量控制风的强度;
  • _FlameColor  :  xyz分量控制火焰的颜色比重以及大小火焰扰动的效果,w分量控制火焰流动的速度。

       下面就从Vert函数讲起,首先是处理噪波贴图的uv,在这里分了三层,每层的uv比例缩放大小和移动速度都不一样,以丰富火焰效果的层次,并且在这里使用了_FlameColor的w分量控制uv流动的速度,代码如下:

		VerttoFrag o;o.uvCoord = v.uvCoord;half3 scrollSpeedY = ((-0.41 * _Time.y),(-0.96 * _Time.y),(-2.36 * _Time.y))*_FlameColor.w;half scrollSpeedX =  _Time.z*_FlameColor.w;// half3 scales = (1, 2, 3);o.transUV1 = v.uvCoord.xy * 1 ;o.transUV1.y = o.transUV1.y + scrollSpeedY.x ;o.transUV1.x = o.transUV1.x + scrollSpeedX ;o.transUV2 = v.uvCoord.xy * 2 ;o.transUV2.y = o.transUV2.y + scrollSpeedY.y ;o.transUV2.x = o.transUV2.x + (-0.8 * scrollSpeedX) ;o.transUV3 = v.uvCoord.xy * 3 ;o.transUV3.y = o.transUV3.y + scrollSpeedY.z ;o.transUV3.x = o.transUV3.x + (0.37 * scrollSpeedX) ;


       然后处理火焰模型的顶点律动效果以及随风摆动的效果,原作者是通过对噪波图的颜色采样获得随机律动的效果,在这里我使用了unity的内置函数SmoothTriangleWave( )   ,这个函数的函数原型在TerrainEngine.cginc里实现(源代码如下):

float4 SmoothCurve( float4 x ) {     return x * x *( 3.0 - 2.0 * x );     
}  
float4 TriangleWave( float4 x ) {     return abs( frac( x + 0.5 ) * 2.0 - 1.0 );     
}  
float4 SmoothTriangleWave( float4 x ) {     return SmoothCurve( TriangleWave( x ) );     
}  

       该函数可以生成循环波动效果,通过控制输入的参数,以及对输出值的修改,可以模拟出比较自然的随机波动效果,用于Unity Terrain系统植物随风摆动的效果,效率据说要比正弦或者余弦函数要高(未求证),在这里我把它直接用于模拟火焰律动的效果,代码如下:


//将风的方向向量转换到世界坐标空间,并使用顶点色的红色通道控制_WindPower.xyz =normalize( mul((float3x3)_World2Object,_WindPower.xyz));_WindPower.w *=v.vertColor.r;
//控制风的律动频率float windTime = _Time.y * _WindFreqScale;float4 vWaves = (frac( windTime.xxxx * float4(1.975, 0.793, 0.375, 0.193) ) * 2.0 - 1.0);vWaves = SmoothTriangleWave( vWaves );float2 vWavesSum = vWaves.xz + vWaves.yw;
//bellyGradient控制火焰膨胀的梭状形体fixed bellyGradient = pow(v.uvCoord.y * (1-v.uvCoord.y),1.7);
//使火焰模型的顶点有规律的震动,和随风摆动v.vertex.xyz += normalize(v.inNormal.xyz) * bellyGradient * vWavesSum.xyx;v.vertex.xyz += _WindPower.xyz * _WindPower.w *  (vWavesSum.y+0.5)*(bellyGradient+0.2);o.outPos = mul(UNITY_MATRIX_MVP,v.vertex);
//displayV用于传入frag函数,控制火焰随形体膨胀而忽明忽暗的效果o.displaceV = vWavesSum.y*vWavesSum.x;

        vert函数最后一段代码,是用来控制模型的边缘透明的,和边缘光材质方法是一样的,只不过在这里是用来控制透明度,并且这里还使用顶点色的alpha通道控制模型的透明,代码如下:

		half4 worldPos = mul(_Object2World , v.vertex );		fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - worldPos.xyz);fixed3 normalDir = normalize(mul(_Object2World ,fixed4(v.inNormal.xyz,0) ).xyz);o.edgeAlpha = pow(abs(dot(normalDir,viewDir)*1.7),2) * v.vertColor.a;

        frag函数承接从vert函数传过来的参数,先对噪波图采样,得到的颜色值转化成颜色梯度图的uv值,求出火焰的颜色以及透明质,主要代码如下:

		fixed2 noiseColor1 = tex2D(_NoiseTex,i.transUV1.xy).xy;fixed2 noiseColor2 = tex2D(_NoiseTex,i.transUV2.xy).xy;fixed2 noiseColor3 = tex2D(_NoiseTex,i.transUV3.xy).xy;noiseColor1.y *= _FlameColor.x;noiseColor2.y *= _FlameColor.y;noiseColor3.y *= _FlameColor.z;half2 noiseCoords = noiseColor1 + noiseColor2 + noiseColor3;noiseCoords += i.uvCoord.xy;fixed4 baseColor = tex2D(_ColorTex,clamp(noiseCoords,0.05,0.97));fixed4 texColor = baseColor + baseColor * (i.displaceV - 0.2) * 0.2;fixed Alpha1 = tex2D(_AlphaTex,i.uvCoord.xy).r;fixed Alpha2 = tex2D(_AlphaTex,clamp(noiseCoords,0.05,0.98)).r;texColor.a = Alpha1 * Alpha2 * i.edgeAlpha ;  return texColor;	


总结

       这个火焰效果总体来说还可以,但是不大适合顶视的效果,容易穿帮,这个是由模型的形状决定的;相对于原作者的代码,做了不少的优化,在差不多效果的情况下,本文的火焰效果可以支持target 2.0,当然还有进一步的优化空间,比如可以把颜色梯度图的尺寸从256*256改成2*256,并设置成真彩色,这么可以减少很多的贴图大小,同样对alpha图也可以做相对应的处理,另外一种方式是可以把alpha图放到噪波图其中的一个通道,可以节省一张贴图的使用,当然与此相对应的就得修改shader的代码了。


下载链接

       火焰材质源代码







这篇关于UnityShader实例18:火焰材质的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1012005

相关文章

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

C++操作符重载实例(独立函数)

C++操作符重载实例,我们把坐标值CVector的加法进行重载,计算c3=c1+c2时,也就是计算x3=x1+x2,y3=y1+y2,今天我们以独立函数的方式重载操作符+(加号),以下是C++代码: c1802.cpp源代码: D:\YcjWork\CppTour>vim c1802.cpp #include <iostream>using namespace std;/*** 以独立函数

实例:如何统计当前主机的连接状态和连接数

统计当前主机的连接状态和连接数 在 Linux 中,可使用 ss 命令来查看主机的网络连接状态。以下是统计当前主机连接状态和连接主机数量的具体操作。 1. 统计当前主机的连接状态 使用 ss 命令结合 grep、cut、sort 和 uniq 命令来统计当前主机的 TCP 连接状态。 ss -nta | grep -v '^State' | cut -d " " -f 1 | sort |

Java Websocket实例【服务端与客户端实现全双工通讯】

Java Websocket实例【服务端与客户端实现全双工通讯】 现很多网站为了实现即时通讯,所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request 的模式带来很明显的缺点 – 浏 览器需要不断的向服务器发出请求,然而HTTP

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群

828华为云征文|华为云Flexus X实例docker部署rancher并构建k8s集群 华为云最近正在举办828 B2B企业节,Flexus X实例的促销力度非常大,特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求,一定不要错过这个机会。赶紧去看看吧! 什么是华为云Flexus X实例 华为云Flexus X实例云服务是新一代开箱即用、体

react笔记 8-18 事件 方法 定义方法 获取/改变数据 传值

1、定义方法并绑定 class News extends React.Component {constructor(props) {super(props)this.state = {msg:'home组件'}}run(){alert("我是一个run") //方法写在类中}render() {return (<div><h2>{this.state.msg}</h2><button onCli

LLVM入门2:如何基于自己的代码生成IR-LLVM IR code generation实例介绍

概述 本节将通过一个简单的例子来介绍如何生成llvm IR,以Kaleidoscope IR中的例子为例,我们基于LLVM接口构建一个简单的编译器,实现简单的语句解析并转化为LLVM IR,生成对应的LLVM IR部分,代码如下,文件名为toy.cpp,先给出代码,后面会详细介绍每一步分代码: #include "llvm/ADT/APFloat.h"#include "llvm/ADT/S

OpenStack离线Train版安装系列—11.5实例使用-Cinder存储服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack实例操作选项解释:启动和停止instance实例

关于启动和停止OpenStack实例 如果你想要启动和停止OpenStack实例时,有四种方法可以考虑。 管理员可以暂停、挂起、搁置、停止OpenStack 的计算实例。但是这些方法之间有什么不同之处? 目录 关于启动和停止OpenStack实例1.暂停和取消暂停实例2.挂起和恢复实例3.搁置(废弃)实例和取消废弃实例4.停止(删除)实例 1.暂停和取消暂停实例

Cmake之3.0版本重要特性及用法实例(十三)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧