Unity制作下雨中的地面效果

news2024/12/27 12:08:36

Unity引擎制作下雨效果

  大家好,我是阿赵。
  之前介绍了Unity引擎里面通过UV偏移做序列帧动画的做法,这里再介绍一个进阶的用法,模拟地面下雨的雨点效果。

一、原理

在这里插入图片描述

  最基本的原理,还是基于这个序列帧动画的做法。不过这里做一点改变。我不再用网格的UV作为计算的UV,而是通过worldPosition的xz轴去计算,并且,我加上了一个frac方法。

float2 uv = frac(i.worldPos.xz*_tiling);
uv = GetSequenceAnimUV(uv,_cols,_rows,_speed, _startFrame);

  这样做的好处是,UV不再依赖网格模型,可以平均的铺在地面上,而且地面可以无限延伸,特别适合做地面雨滴效果。
这样做的效果是这样的:
在这里插入图片描述

  由于frac的效果是把数值只保留小数部分,所以之前的uv坐标,就被划分成很多个小的0-1之间的区域。于是UV序列帧动画,也变成了多个。
  接下来要做的事情,就是把这张1-9的数字图片,换成一张雨点扩散的序列帧图片。由于如果是真的水面,固有色部分还需要做其他效果,所以这个雨点的序列图最好是法线贴图。
  然后通过之前介绍过的法线贴图的用法,把序列帧动画的UV采样法线贴图,然后把法线的效果加强,就出现了雨点打地面的效果。
在这里插入图片描述

二、代码

  于这里只是介绍雨点的效果,所以固有色我就不去认真做了,只是做了个固有色,然后雨点的法线效果是通过高光来表现的。组合了一下之前介绍过的光照模型的代码,还有序列帧动画的代码,就得到了这么一个shader代码了。

Shader "azhao/Rain"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
		_color("Color",Color) = (1,1,1,1)
		_cols("Cols",int) = 1
		_rows("Rows",int) = 1
		_tiling("Tiling",int) = 1
		_speed("Speed",float) = 25
		_startFrame("startFrame",int) = 0
		_NormalTex("Normal Tex", 2D) = "black"{}
		_normalScale("normalScale", Range(0 , 1)) = 0
		_specColor("SpecColor",Color) = (1,1,1,1)
		_shininess("shininess", Range(1 , 100)) = 1
		_specIntensity("specIntensity",Range(0,1)) = 1

    }
    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;
				float3 normal:NORMAL;
				float3 tangent:TANGENT;
            };

            struct v2f
            {
                
                float4 vertex : SV_POSITION;
				float2 uv : TEXCOORD0;
				float3 worldPos:TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				float3 worldTangent :TEXCOORD3;
				float3 worldBitangent : TEXCOORD4;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
			float4 _color;
			float _cols;
			float _rows;
			float _tiling;
			float _speed;
			float _startFrame;
			sampler2D _NormalTex;
			float4 _NormalTex_ST;
			float _normalScale;
			float4 _specColor;
			float _shininess;
			float _specIntensity;
			float _ambientIntensity;


			float2 GetSequenceAnimUV(float2 uv,float cols,float rows,float speed,float startFrame)
			{
				float totalTiles = cols * rows;

				float colsOffset = 1.0f / cols;
				float rowsOffset = 1.0f / rows;
				float speedVal = _Time.y * speed;
				float2 offsetTiling = float2(colsOffset, rowsOffset);
				float currentIndex = round(fmod(speedVal + startFrame, totalTiles));
				currentIndex += (currentIndex < 0) ? totalTiles : 0;
				float lineNum = round(fmod(currentIndex, cols));
				float offsetX = lineNum * colsOffset;
				float rowCount = round(fmod((currentIndex - lineNum) / cols, rows));
				rowCount = (int)(rows - 1) - rowCount;
				float offsetY = rowCount * rowsOffset;
				float2 offsetXY = float2(offsetX, offsetY);
				float2 result = uv*offsetTiling +offsetXY;
				return result;
			}

			//简化版的转换法线并缩放的方法
			half3 UnpackScaleNormal(half4 packednormal, half bumpScale)
			{
				half3 normal;
				//由于法线贴图代表的颜色是0到1,而法线向量的范围是-1到1
				//所以通过*2-1,把色值范围转换到-1到1
				normal = packednormal * 2 - 1;
				//对法线进行缩放
				normal.xy *= bumpScale;
				//向量标准化
				normal = normalize(normal);
				return normal;
			}

			//获取HalfLambert漫反射值
			float GetHalfLambertDiffuse(float3 worldPos, float3 worldNormal)
			{
				float3 lightDir = UnityWorldSpaceLightDir(worldPos);
				float NDotL = saturate(dot(worldNormal, lightDir));
				float halfVal = NDotL * 0.5 + 0.5;
				return halfVal;
			}

			//获取BlinnPhong高光
			float GetBlinnPhongSpec(float3 worldPos, float3 worldNormal)
			{
				float3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
				float3 halfDir = normalize((viewDir + _WorldSpaceLightPos0.xyz));
				float specDir = max(dot(normalize(worldNormal), halfDir), 0);
				float specVal = pow(specDir, _shininess);
				return specVal;
			}

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldTangent = UnityObjectToWorldDir(v.tangent);
				o.worldBitangent = cross(o.worldNormal, o.worldTangent);
                return o;
            }

            half4 frag (v2f i) : SV_Target
            {
				float2 uv = frac(i.worldPos.xz*_tiling);
				float2 normalUV = GetSequenceAnimUV(uv,_cols,_rows,_speed, _startFrame);

				//采样法线贴图的颜色
				half4 normalCol = tex2D(_NormalTex, normalUV);
				//得到切线空间的法线方向
				half3 normalVal = UnpackScaleNormal(normalCol, _normalScale).rgb;

				//构建TBN矩阵
				float3 tanToWorld0 = float3(i.worldTangent.x, i.worldBitangent.x, i.worldNormal.x);
				float3 tanToWorld1 = float3(i.worldTangent.y, i.worldBitangent.y, i.worldNormal.y);
				float3 tanToWorld2 = float3(i.worldTangent.z, i.worldBitangent.z, i.worldNormal.z);

				//通过切线空间的法线方向和TBN矩阵,得出法线贴图代表的物体世界空间的法线方向
				float3 worldNormal = float3(dot(tanToWorld0, normalVal), dot(tanToWorld1, normalVal), dot(tanToWorld2, normalVal));

				//用法线贴图的世界空间法线,算漫反射
				half diffuseVal = GetHalfLambertDiffuse(i.worldPos, worldNormal);

				//用法线贴图的世界空间法线,算高光角度
				half3 specCol = _specColor * GetBlinnPhongSpec(i.worldPos, worldNormal)*_specIntensity;

                half4 col = tex2D(_MainTex,i.uv);
				col.rgb = col.rgb*_color.rgb + specCol;
                return col;
            }
            ENDCG
        }
    }
}

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

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

相关文章

深度入门 Android 车机核心 CarService 的构成和链路

作者&#xff1a;TechMerger 本文将结合 Android 系统整体&#xff0c;对 CarService 的构成和链路对其做一个全面的分析和理解。 构成 1. CarServiceHelperService 系统服务 SystemServer 中专门为了 Automotive OS 设立的系统服务&#xff0c;用来管理车机的核心服务 CarS…

计算机网络的故事——了解Web及网络基础

了解Web及网络基础 文章目录 了解Web及网络基础一、使用 HTTP 协议访问 Web二、HTTP 的诞生三、网络基础 TCP/IP四、与 HTTP 关系密切的协议 : IP、TCP 和 DNS 一、使用 HTTP 协议访问 Web 根据Web浏览器指定的URL&#xff0c;从对应的服务器中获取文件资源&#xff0c;从而显…

LeetCode(力扣)77. 组合Python

LeetCode77. 组合 题目链接代码 题目链接 https://leetcode.cn/problems/combinations/description/ 代码 class Solution:def combine(self, n: int, k: int) -> List[List[int]]:result []return self.backtracking(n, k, 1, [], result)def backtracking(self, n, k…

神经网络中的一些优化器整理

6 梯度平方的指数移动平均在神经网络优化中具有以下好处&#xff1a; 自适应学习率&#xff1a;梯度平方的指数移动平均允许每个参数的学习率自适应地调整。如果某个参数的梯度平方历史信息较大&#xff0c;那么其指数移动平均值会较大&#xff0c;从而减小学习率&#xff0c;使…

Linux下 /sys/class 一些操作

Linux下&#xff0c;/dev、/sys/class的区别 /dev下面有很多节点&#xff0c;每一个节点代表一个设备&#xff0c;/dev目录下面是按物理器件进行分类&#xff1b;而/sys/class下面的更多是按功能抽象出来的。 参考1 demo 在正点原子的基础上进行演示 #include <linux/ty…

Flink基础实操-计算单词出现次数

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

【python】读取.dat格式文件

import binascii# 打开二进制文件以只读二进制模式 with open(EXCEL/文件.dat, rb) as file:binary_data file.read()print(binary_data)# 将二进制数据转换为十六进制字符串 hex_data binascii.hexlify(binary_data).decode(utf-8) # binary_data 现在包含了文件的二进制内容…

R语言Meta分析核心技术

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…

原生代理IP有哪些优势?

在互联网时代&#xff0c;隐私和安全成为人们越来越关注的问题&#xff0c;原生 IP 在网络通信和隐私保护方面拥有独特的优势。原生IP也称为本土IP&#xff0c;相较于其他代理IP质量更高&#xff0c;可以更快速、更稳定地请求目标服务器&#xff0c;同时也更难被目标服务器识别…

MFC中多线程的基础知识——1互斥对象

目录 1 多线程的基本概念1.1 进程一、程序和进程的概念二、进程组成三、进程地址空间 1.2 线程一、线程组成二、线程运行三、线程创建函数 1.3 多进程与多线程并发一、多进程并发二、多线程并发 2 线程同步2.1 一个经典的线程同步问题2.2 利用互斥对象实现线程同步一、创建互斥…

B093-springsecurity整合jwt和RSA

目录 前后端分离后springsecurity核心filter的应用场景介绍JWT令牌的组成部分JWT案例导包TestJwt RSARsaUtilsTestRSA分析图 JWTRSA导包JwtUtilsTestRSAJWT 完善spring-security整合后且不连数据库的代码案例流程分析图 前后端分离后springsecurity核心filter的应用场景介绍 账…

汽车电子系统网络安全解决方案

声明 本文是学习GB-T 38628-2020 信息安全技术 汽车电子系统网络安全指南. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 汽车电子系统网络安全范围 本标准给出了汽车电子系统网络安全活动框架&#xff0c;以及在此框架下的汽车电子系统网络安全活动…

redis 5.0.x 部署

PS&#xff1a;对于使用者来说&#xff0c;Redis5.0和4.0都是一样的&#xff0c;但是redis 4.0的集群部署需要额外安装ruby的东西&#xff0c;5.0中则集成到了redis-cli&#xff0c;部署起来更方便 1.1 安装Redis 本章基于CentOS 7.9.2009编写而成&#xff0c;由于Linux发行版…

Shotcut for Mac:一款强大而易于使用的视频编辑器

随着数码相机的普及&#xff0c;视频编辑已成为我们日常生活的一部分。对于许多专业和非专业用户来说&#xff0c;找到一个易于使用且功能强大的视频编辑器是至关重要的。今天&#xff0c;我们将向您介绍Shotcut——一款专为Mac用户设计的强大视频编辑器。 什么是Shotcut&…

C#-SQLite-使用教程笔记

微软官网资料链接&#xff08;可下载文档&#xff09; 教程参考链接&#xff1a;SQLite 教程 - SQLite中文手册 项目中对应的system.dat文件可以用SQLiteStudio打开查看 参考文档&#xff1a;https://d7ehk.jb51.net/202008/books/SQLite_jb51.rar 总结介绍 1、下载SQLiteS…

【GPT引领前沿】GPT4技术与AI绘图

推荐阅读&#xff1a; 1、遥感云大数据在灾害、水体与湿地领域典型案例实践及GPT模型应用 2、GPT模型支持下的Python-GEE遥感云大数据分析、管理与可视化技术 GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。例如在科研编程…

音视频技术开发周刊 | 309

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 腾讯云音视频及边缘平台专场邀你一起见证“连接”的力量 9月7日&#xff0c;腾讯全球数字生态大会之腾讯云音视频及边缘平台专场即将开启&#xff01;本次专场将重点分享腾…

最小生成树Kruskal、Prim算法C++

什么是最小生成树 连通图&#xff1a; 在无向图中&#xff0c;若从顶点v1到顶点v2有路径&#xff0c;则称顶点v1和顶点v2是连通的。如果图中任意一对顶点都是连通的&#xff0c;则称此图为连通图。 生成树&#xff1a; 一个连通图的最小连通子图称作为图的生成树。有n个顶点的…

OceanBase 里的 schema 是什么?

李博洋 OceanBase 技术部研发工程师。 OceanBase 开源社区里经常会看到一些类似于 “ schema 是什么” 的疑问&#xff1a; 很多同学经常会误以为在 OceanBase 里&#xff0c;schema 只是 database 的同义词&#xff0c;这次分享就从 schema 是什么这个问题稍微展开聊一下。 首…

【51单片机实验笔记】声学篇(一) 蜂鸣器基本控制

目录 前言硬件介绍PWM基础蜂鸣器简介 原理图分析蜂鸣器驱动电路 软件实现蜂鸣器短鸣蜂鸣器功能封装 总结 前言 蜂鸣器在生活中的应用实则相当广泛。通过本章你将学会制造噪声 &#xff08;笑~&#xff09;你将学会驱动它们&#xff0c;并发出响声。 硬件介绍 PWM基础 占空比…