Unity制作旋转光束
Unity制作旋转光束
大家好,我是阿赵。
这是一个在很多游戏里面可能都看到过的效果,在传送门、魔法阵、角色等脚底下往上散发出一束拉丝形状的光,然后在不停的旋转。

这次来在Unity引擎里面做一下这种效果。
一、准备材料
需要准备的素材很简单。
第一个是一个圆柱形的网格模型,删除了上下盖,然后展平UV。
第二个是一张噪声贴图
二、制作过程
1、控制形状
由于准备的输出是一个圆柱网格,但实际显示的效果是一个类似于扇形的形状。所以需要通过控制顶点来实现。原理很简单,UV的V坐标,是从模型的底部到顶部从0到1变化,所以只要沿着法线方向,乘以UV的V坐标,然后再乘以一个控制值,加到顶点坐标上,就能做到底部不变,越往上宽度越大了。
float3 vertexValue = ( v.normal * _normalScale * v.uv.y );
v.vertex.xyz += vertexValue;
o.vertex = UnityObjectToClipPos(v.vertex);
效果入下图
2、拉丝效果
先把噪声图赋给网格模型,得到这样的效果:
然后设置一下平铺次数
就得到了拉丝的效果了。
这里给固有色添加一个HDR的颜色叠加,然后把这个拉丝效果作为Alpha通道输入,设置Transparent透明渲染,就能得到这样的效果:
3、透明渐变效果
上面的效果太强烈,需要对它的透明度做一定的控制。先看看UV坐标的V坐标的实际范围:
之前提到过,V坐标是从模型底部到顶部从0到1变化。接下来就可以通过这个值做一些处理。
1.上下边缘控制
首先控制的是上下边缘,现在边缘太硬,我把它用两个SmoothStep,分别对应顶部和底部,让边缘变得柔和:
float tempOneMinueVal = ( 1.0 - i.uv.y );
float smoothstepResultV1 = smoothstep( _vMin , _vMax , ( tempOneMinueVal - _vOffset ));
float smoothstepResultV2 = smoothstep( _vMin2 , _vMax2 , i.uv.y);
float clampResult = clamp( min( min( smoothstepResultV1 , tempOneMinueVal ) , smoothstepResultV2 ) , 0.0 , 1.0 );
把这个上下边缘柔和的结果和原来的拉丝Alpha值相乘,得到了这个效果:
2.左右边缘控制
上面的效果已经很接近我们想要的效果了,但还差一点,左右边缘也很硬,所以用世界法线方向和观察方向做点乘,最后还是加一个SmoothStep,让左右边缘有个柔和渐变。
float3 worldNormal = i.worldNormal.xyz;
float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);
worldViewDir = normalize(worldViewDir);
float dotResult = dot( worldNormal , worldViewDir );
float smoothstepResultEdge = smoothstep( _edgeMin , _edgeMax , abs( dotResult ));
计算结果是这样的左右两边渐变的变暗:
3.叠加遮罩
把上面的3个SmoothStep结果相乘,就得到了这样一个遮罩范围:
然后和拉丝的Alpha值相乘,得到了这样的效果:
4、遮挡问题解决
这里有一个半透明渲染的问题,在某些角度看,会出现错误显示:
这里我再复制一份网格模型:
然后两个网格模型使用不同的CullMode
然后两个网格模型一起显示,就得到了正确的效果:
三、Shader源码
Shader "azhao/LightColumn"
{Properties{[HDR]_emissCol("emissCol", Color) = (0,0,0,0)_emissScale("emissScale", Float) = 1_noiseTex("noiseTex", 2D) = "white" {}_flowSpeed("flowSpeed", Vector) = (0,0,0,0)_vOffset("vOffset", Float) = 0_edgeMin("edgeMin", Range( 0 , 1)) = 0_edgeMax("edgeMax", Range( 0 , 1)) = 1_vMin("vMin", Range( 0 , 1)) = 0_vMax("vMax", Range( 0 , 1)) = 1_normalScale("normalScale", Range(-2,2)) = 1 _vMin2("vMin2", Range( 0 , 1)) = 0_vMax2("vMax2", Range( 0 , 1)) = 1
[Enum(UnityEngine.Rendering.CullMode)]_CullMode("CullMode", Float) = 2}SubShader{Tags { "RenderType"="Opaque" }LOD 100CGINCLUDE#pragma target 3.0ENDCGBlend SrcAlpha One, SrcAlpha OneAlphaToMask OffCull [_CullMode]ColorMask RGBAZWrite OnZTest LEqualOffset 0 , 0Pass{Name "Unlit"Tags { "LightMode"="ForwardBase" }CGPROGRAM#ifndef UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX//only defining to not throw compilation error over Unity 5.5#define UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input)#endif#pragma vertex vert#pragma fragment frag#pragma multi_compile_instancing#include "UnityCG.cginc"#include "UnityShaderVariables.cginc"struct appdata{float4 vertex : POSITION;float4 color : COLOR;float3 normal : NORMAL;float2 uv : TEXCOORD0;UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float4 vertex : SV_POSITION;float3 worldPos : TEXCOORD0;float2 uv : TEXCOORD1;float3 worldNormal : TEXCOORD2;UNITY_VERTEX_INPUT_INSTANCE_IDUNITY_VERTEX_OUTPUT_STEREO};uniform float _CullMode;uniform float _normalScale;uniform float4 _emissCol;uniform float _emissScale;uniform sampler2D _noiseTex;SamplerState sampler_noiseTex;uniform float2 _flowSpeed;uniform float4 _noiseTex_ST;uniform float _vMin;uniform float _vMax;uniform float _vOffset;uniform float _vMin2;uniform float _vMax2;uniform float _edgeMin;uniform float _edgeMax;v2f vert ( appdata v ){v2f o;UNITY_SETUP_INSTANCE_ID(v);UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);UNITY_TRANSFER_INSTANCE_ID(v, o);float3 worldNormal = UnityObjectToWorldNormal(v.normal);o.worldNormal = worldNormal; o.uv.xy = v.uv.xy; float3 vertexValue = ( v.normal * _normalScale * v.uv.y );v.vertex.xyz += vertexValue;o.vertex = UnityObjectToClipPos(v.vertex);o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;return o;}half4 frag (v2f i ) : SV_Target{UNITY_SETUP_INSTANCE_ID(i);UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);float2 uv_noiseTex = i.uv.xy * _noiseTex_ST.xy + _noiseTex_ST.zw;float2 panner6 = ( 1.0 * _Time.y * _flowSpeed + uv_noiseTex);float tempOneMinueVal = ( 1.0 - i.uv.y );float smoothstepResultV1 = smoothstep( _vMin , _vMax , ( tempOneMinueVal - _vOffset ));float smoothstepResultV2 = smoothstep( _vMin2 , _vMax2 , i.uv.y);float clampResult = clamp( min( min( smoothstepResultV1 , tempOneMinueVal ) , smoothstepResultV2 ) , 0.0 , 1.0 );float3 worldNormal = i.worldNormal.xyz;float3 worldViewDir = UnityWorldSpaceViewDir(i.worldPos);worldViewDir = normalize(worldViewDir);float dotResult = dot( worldNormal , worldViewDir );float smoothstepResultEdge = smoothstep( _edgeMin , _edgeMax , abs( dotResult ));half4 finalColor = (float4((( _emissCol * _emissScale )).rgb , ( tex2D( _noiseTex, panner6 ).r * clampResult * smoothstepResultEdge )));return finalColor;}ENDCG}}}
相关文章:

Unity制作旋转光束
Unity制作旋转光束 大家好,我是阿赵。 这是一个在很多游戏里面可能都看到过的效果,在传送门、魔法阵、角色等脚底下往上散发出一束拉丝形状的光,然后在不停的旋转。 这次来在Unity引擎里面做一下这种效果。 一、准备材料 需要准备的素材很简…...

考研王道强化阶段(二轮复习)“算法题”备考打卡表 记录
问题:做408真题_2010_42题,即王道书 2.2.3_大题_10 思路: 回头补 代码: int moveL(SqlList &L,SqlList &S,int p) {// 健壮性表达if( L.len 0 ){return 0;}// 调用另外一个顺序表存储pos前面的元素for( int i0;i<p;…...

UE4/5数字人MetaHuman通过已有动画进行修改
目录 通过已有动画修改动画 开始制作 创建一个关卡序列 将动画序列烘焙到控制绑定 打开我们自己创建的动画序列 之后便是烘焙出来 通过已有动画修改动画 首先架设我们已经有相关的MetaHuman的动画,但是这个动画因为是外部导入进来的,所以可能会出…...
在Mac M2本地注册GitLab runner
最近在搞公司的CI/CD,简单记录下部分过程 安装runner sudo curl --output /usr/local/bin/gitlab-runner "https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-arm64" 创建runner 这个步骤需要在gitlab中进行&am…...

「大数据-2.2」使用命令操作HDFS文件系统
目录 一、HDFS文件系统基本信息 1. HDFS的路径表达形式 2.HDFS和Linux的根目录的区分 二、 使用命令操作HDFS文件系统 0. Hadoop的两套命令体系 1. 创建文件夹 2. 查看指定目录下内容 3. 上传文件到HDFS指定目录下 4. 查看HDFS文件内容 5. 下载HDFS文件 6. 拷贝HDFS文件 7.…...

面试买书复习就能进大厂?
大家好,我是苍何。 现在进大仓是越来越难了,想通过简单的刷题面试背书,比几年前难的不少, 但也并非毫无希望,那究竟该如何准备才能有希望进大厂呢? 我总结了 4 点: 1、不差的学历背景 2、丰富…...
使用Http Interface客户端解析text/html类型参数
前言 Spring6和Spring Boot3的正式发布也有一段时间了,最低支持的java版本也是直接跳到了17。而且最近java21也出来了,作为一个javaer,你不会还在坚守java8吧? Http Interface是Spring6新推出的一个声明式http客户端,…...
Linux - linux命令进阶
打包压缩解压 基本概述 打包 将多数文件或目录汇总成一个整体 打包默认没有压缩功能,不节省磁盘空间 压缩 将大文件压缩成小文件 可以节省磁盘空间 打包压缩 将一堆零散的文件打包到一起,然后再压缩,可以节省磁盘空间 打包命令 命令格式 ta…...

排序篇(一)----插入排序
1.直接插入排序 插入排序的思想: 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。 你可以想像成打牌一样,比如说斗地主,一张一张的摸牌,然后把手上的这些牌变成手续的排列.…...

通俗讲解深度学习轻量网络MobileNet-v1/v2/v3
MobileNet网络是由google团队在2017年提出的,专注于移动端或者嵌入式设备中的轻量级CNN网络。相比传统卷积神经网络,在准确率小幅降低的前提下大大减少模型参数与运算量。(相比VGG16准确率减少了0.9%,但模型参数只有VGG的1/32)。MobileNet网络…...
mmpretrain学习笔记
深度学习模型的训练涉及几个方面 1、模型结构:模型有几层、每层多少通道数等 2、数据:数据集划分、数据文件路径、批大小、数据增强策略等 3、训练优化 :梯度下降算法、学习率参数、训练总轮次、学习率变化策略等 4、运行时:GPU、…...

rhel8 网络操作学习
一、查询dns服务器地址汇总 1.查询dns服务器地址: (1)方法一:执行命令 cat /etc/resolv.conf 执行结果如下: nameserver后面就是dns服务器的ip地址。 (2)方法2:查看/etc/syscon…...
有车型(CarModel),车厂(CarFactory),经销商(Distributor)三个表
用drf编写 1 有车型(CarModel),车厂(CarFactory),经销商(Distributor)三个表, 一个车厂可以生产多种车型,一个经销商可以出售多种车型,一个车型可以有多个经销商出售车型:车型名,车型…...

Python函数:chr()和ord()
两个函数是基于Unicode编码表进行进行字符与字码之间的转换。 chr()函数是通过字码转换成字符: 如图,坐标(1,4e10)丑 使用chr需要线将坐标相加得到:4e11 chr默认传入10进制的字码. 如图是各进制的字码。 也可以传入其他进制,不过需要在前面传入的参数最前…...
flink sql 使用
1.准备工作 安装flink 1.16.2 将以下jar包放到/data/cmpt/flink-1.16.2/lib 目录下 antlr-runtime-3.5.2.jar flink-connector-hive_2.12-1.16.2.jar flink-connector-jdbc-1.16.2.jar mysql-connector-java-6.0.6.jar hive-exec-3.1.3.jar libfb303-0.9.3.ja…...

面试官:谈谈 Go 泛型编程
大家好,我是木川 泛型编程是一种编程范式,它允许编写具有参数化类型的代码,从而增加代码的复用性和灵活性。在泛型编程中,你可以编写一段代码,使其适用于不同类型的参数,而不需要为每种类型编写不同的实现。…...
脚手架开发流程详解
开发流程 创建npm项目创建脚手架入口文件,最上方添加 #!/usr/bin/env/ node配置package.json,添加bin属性编写脚手架代码将脚手架发布到npm 使用流程 安装脚手架 npm install -g your-own-cli使用脚手架 your-own-cli脚手架开发难点解析 分包&…...
架构真题2021(四十三)
产品配置是指一个产品在其生命周期各个阶段所产生的各种形式(机器刻可读或人工可读)和各种版本()的集合。 需求规格说明、设计说明、测试报告需求规则说明、设计说明、计算机程序设计说明、用户手册、计算机程序文档、计算机程序…...

数据统计和分析怎么做?spss如何做好数据分析?
为什么要做数据分析?数据分析有什么意义?数据分析可以为企业和组织提供多方面的帮助,包括提高工作效率、优化业务流程、升职加薪、提高管理效率以及改进汇报效果等方面。 IBM SPSS Statistics 26是一款功能强大的统计分析软件,适用于Mac操作…...
【多线程】线程安全的集合类
文章目录 1. 多线程环境使用ArrayList1.1 自己使用同步机制1.2 Collections.synchronizedList(new ArrayList);1.3 使用 CopyOnWriteArrayList 2. 多线程使用队列3. 多线程环境使用哈希表3.1 HashTable3.2 ConcurrentHashMap3.3 Hashtable和HashMap、ConcurrentHashMap 之间的区…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...

【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...
uniapp获取当前位置和经纬度信息
1.1. 获取当前位置和经纬度信息(需要配置高的SDK) 调用uni-app官方API中的uni.chooseLocation(),即打开地图选择位置。 <button click"getAddress">获取定位</button> const getAddress () > {uni.chooseLocatio…...

react-pdf(pdfjs-dist)如何兼容老浏览器(chrome 49)
之前都是使用react-pdf来渲染pdf文件,这次有个需求是要兼容xp环境,xp上chrome最高支持到49,虽然说iframe或者embed都可以实现预览pdf,但为了后续的定制化需求,还是需要使用js库来渲染。 chrome 49测试环境 能用的测试…...

循环语句之while
While语句包括一个循环条件和一段代码块,只要条件为真,就不断 循环执行代码块。 1 2 3 while (条件) { 语句 ; } var i 0; while (i < 100) {console.log(i 当前为: i); i i 1; } 下面的例子是一个无限循环,因…...