【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果

本文主要是介绍【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最终效果对比

在这里插入图片描述

文章目录

  • 最终效果对比
  • 前言
  • 第一种办法
  • 方法二
    • 1. 创建URP环境
    • 2. 配置 Universal Render Pipeline Asset
    • 3. 这里向我们新建一个无光的ShaderGraph
    • 4. 主图配置
    • 4. 新建材质,挂载
    • 5. 下面是shaderGraph 的连线图
    • 6. 新增脚本控制ObjectScreenPosition随着瞄准镜移动而不断修改
    • 6. 新增脚本控制_ZoomAmount实现滚轮放大缩小效果
  • 第三种办法
    • 1. 新增渲染相机
    • 2. 创建一个渲染纹理
    • 3. 绑定渲染纹理
    • 4. 解决镜片穿模问题
    • 5. 脚本控制实现放大缩小效果
  • 总结
  • 参考
  • 完结

前言

在许多射击类游戏中,瞄具的放大变焦效果是提高射击精准度和游戏体验的重要部分。Unity作为一款流行的游戏开发引擎,提供了多种实现瞄准瞄具放大变焦效果的方法。本文将介绍三种常见的实现方式,并分别探讨它们的优缺点。

首先,我们将介绍如何通过调整摄像机的视野来实现放大变焦效果。其次,我们将讨论如何利用Shader来实现瞄具的放大效果,以及如何使用Render Texture来模拟变焦效果。每种方法都有其独特的应用场景和适用性,在本文中,我们将深入探讨这三种方法的具体实现和使用场景,帮助开发者根据自身需求选择合适的实现方式。

无论您是初学者还是有经验的开发者,本文都将为您提供全面的教程和示例代码,帮助您更好地理解和运用Unity中的瞄具放大变焦效果。让我们开始探索这些令人兴奋的技术吧!

第一种办法

调节相机FOV值

public class RifleScopeZoom : MonoBehaviour
{[SerializeField] private Camera playerCamera;[SerializeField] private float zoomSpeed = 10f;[SerializeField] private float minFOV = 20f;[SerializeField] private float maxFOV = 60f;private void Update(){// 获取滚轮滑动的值float scrollValue = Input.GetAxis("Mouse ScrollWheel");// 根据滚轮滑动的值调整 FOVplayerCamera.fieldOfView -= scrollValue * zoomSpeed;// 限制 FOV 的范围在最小值和最大值之间playerCamera.fieldOfView = Mathf.Clamp(playerCamera.fieldOfView, minFOV, maxFOV);}
}

效果
在这里插入图片描述
这就是第一个实现方式,如你所见十分简单,它所作的就是调整主摄像机参数,这个方式的优点就是性能好,你不需要什么新Shader或者另一个相机,而只需要调整相机FOV,不过缺点就是不太好看,在理想情况下我们只会希望放大瞄准镜所看到的物体,不过现在整个画面都放大了

还有就是如果你的瞄准镜模型不是空心通透的可能无法使用这种方法,比如狙击枪的瞄准镜,我下面的例子就是,使用我只能去掉瞄准镜
在这里插入图片描述

方法二

对于第二个方法我们会需要用到Shader来放大某个物体背后的画面

1. 创建URP环境

如果不懂的可以看我之前的文章,有教具体如何配置URP环境:使用Shader Graph实现动物森友会的世界弯曲效果

2. 配置 Universal Render Pipeline Asset

由于实验中使用了 Scene Depth 和 Scene Color 节点获取深度缓冲区和颜色缓冲区信息,需要在 Universal Render Pipeline Asset 中勾选 Depth Texture 和 Opaque Texture,如下。
在这里插入图片描述

3. 这里向我们新建一个无光的ShaderGraph

在这里插入图片描述

4. 主图配置

由于镜子是透明的,需要在主图的 Graph Settings 中将 Surface Type 属性设置 Transparent
在这里插入图片描述

4. 新建材质,挂载

为了实现这个效果我在瞄准镜中放了个球,然后把它弄得很平,模拟一个镜面效果,绑定带前面ShaderGraph的材质
在这里插入图片描述

5. 下面是shaderGraph 的连线图

在这里插入图片描述
这里用了Scene Color节点它输出这个物体背后的场景颜色,然后用Tilling and offset节点修改其中的Tilling值来实现放大,然后就是用到物体屏幕坐标这个是最复杂的点ObjectScreenPosition,这个参数需要随着瞄准镜移动而不断修改。

6. 新增脚本控制ObjectScreenPosition随着瞄准镜移动而不断修改

因此我这里有另一个脚本RifleScopeShaderScreenPos,它的作用就是将物体世界坐标转屏幕坐标然后输入到Shader中,所以这个Shader不会放大所有画面,他只会放大瞄准镜里的东西

public class RifleScopeShaderScreenPos : MonoBehaviour
{// Shader 材质[SerializeField] private Material material;private void Update(){// 获取物体在屏幕上的像素坐标Vector2 screenPixels = Camera.main.WorldToScreenPoint(transform.position);// 将像素坐标转换为 0-1 的范围screenPixels = new Vector2(screenPixels.x / Screen.width, screenPixels.y / Screen.height);// 将物体的屏幕坐标传递给 Shadermaterial.SetVector("_ObjectScreenPosition", screenPixels);}
}

6. 新增脚本控制_ZoomAmount实现滚轮放大缩小效果

public class RifleScopeZoomMaterial : MonoBehaviour
{[SerializeField] private float zoomSpeed = 10f;[SerializeField] private float min  = 0f;[SerializeField] private float max = 1f;[SerializeField] private Material zoomMaterial;private void Update(){// 获取滚轮滑动的值float scrollValue = Input.GetAxis("Mouse ScrollWheel");scrollValue = zoomMaterial.GetFloat("_ZoomAmount") + scrollValue;// 限制的范围在最小值和最大值之间scrollValue = Mathf.Clamp(scrollValue, min, max);zoomMaterial.SetFloat("_ZoomAmount", scrollValue);}
}

在这里插入图片描述
和上一个方法相比优点就是它只放大瞄具所看到的东西,所以瞄具外的东西都不会变化,另一个优点就是相比于接下来的方法,这个方法不太吃性能,它只有一个Shader而且相机只渲染一次,当然也有缺点,有一个潜在的问题就是当你放大后画面会变成这样
在这里插入图片描述
当你放大倍率不是很高时画面凑合的过去,不过当你放的越大你就越会得到马赛克画面,这和画面的分辨率有关,Shader只是简单的放大了这个图片而不会改变它的分辨率,所以放的越大画面马赛克就会变明显,如果你放大的倍数不会太大这是个不错的方法,还有和前面有相同的问题,就是如果你的瞄准镜模型不是空心通透的可能不适合这种方法

第三种办法

我们得用一下渲染纹理特性,本质上来说就是可以把相机的画面渲染到一个纹理上

1. 新增渲染相机

所以我们需要一个新的相机,然后把它往前面拖一下,现在你可以把它拖到瞄准镜前面或者直接放在枪管上,然后通过拉低FOV来放大画面
在这里插入图片描述

2. 创建一个渲染纹理

我们再创建一个渲染纹理,这边主要设置一下尺寸,这主要取决于玩家分辨率以及瞄准镜在屏幕上的大小,这里1024*1024差不多够了

在这里插入图片描述
这样子我们就设置好了接下来让相机把渲染画面输出到这个纹理上
在这里插入图片描述
这样我门就能看到相机的画面己经渲染到这张纹理之中了
在这里插入图片描述

3. 绑定渲染纹理

接下来为了在瞄准镜中显示画面,我们直接在瞄准镜里边放一个Quad,我们只需要把渲染纹理拖进来就能得到瞄具画面了
在这里插入图片描述
这样就有效果了,下面就是放大后的相机画面了
在这里插入图片描述

4. 解决镜片穿模问题

不过还是有个小小的问题,那就是我门的Quad是方形的而瞄准镜是圆形的,所以你会看到它有些穿模了
在这里插入图片描述
一个很简单的解决办法就是只需要做一个透明度裁剪
在这里插入图片描述
这里也有个透明度裁剪预制,只需要确保你到设置面板理启出Alpha clip
在这里插入图片描述
做完之后点击这边的AlphaClipMask选择一张带透明背景的圆形贴图
在这里插入图片描述
完了之后你会看到遮罩外边的贴图被裁减了它只保留了中间的画面
在这里插入图片描述

5. 脚本控制实现放大缩小效果

最后一步就是要处理脚本了,我们要做的就是调整渲染纹理相机的FOV,可以复用前面的代码,不够记得把相机修改为我们的渲染相机,而不是主相机

public class RifleScopeZoom : MonoBehaviour
{[SerializeField] private Camera playerCamera;[SerializeField] private float zoomSpeed = 10f;[SerializeField] private float minFOV = 20f;[SerializeField] private float maxFOV = 60f;private void Update(){// 获取滚轮滑动的值float scrollValue = Input.GetAxis("Mouse ScrollWheel");// 根据滚轮滑动的值调整 FOVplayerCamera.fieldOfView -= scrollValue * zoomSpeed;// 限制 FOV 的范围在最小值和最大值之间playerCamera.fieldOfView = Mathf.Clamp(playerCamera.fieldOfView, minFOV, maxFOV);}
}

效果
在这里插入图片描述
我可以放大我想要的地方,如你所见和上一个方法相比没有马赛克问题,而且这个方法有一个有趣的特性,那就是即使我枪没有抬起来时瞄具上的画面也在变化
在这里插入图片描述
另一个优点就是由于我使用了另一个相机,因此我可以做一些有趣的东西,比如我可以用不同的后处理效果,我可以在主相机上加上景深效果,由于渲染纹理离相机很近所以它没被模糊化而外边的东西都模糊掉了
在这里插入图片描述

在这里插入图片描述
就个人而言这个观感效果最好,瞄具外的画面被模糊掉了但内部的画面仍然很清楚,如果你想的话你可以把镜子往前放一放来用其他的后处理效果,你可以实现镜内热成像或者夜视效果而镜外画面保持正常。

当然了这个方法也有一个大缺点那就是性能问题,这个方式使用渲染纹理来显示第二个相机的画面,本质上画面被渲染了2次,如果你做的游戏是PC端这可能不会是个大问题,而如果是手游的话可能就是大问题了,如果你可以承受性能代价,这个方法是最好的一个。

总结

好了你已经学完这三个瞄准镜放大方法了,第一个方法适合性能优先需求或者想找最简单实现方式的人,第二个方法稍优于第一
而最后一个你会得到最好的瞄具效果,去选一个适合的方法用在你的项目里吧!
在这里插入图片描述

参考

【视频】https://www.youtube.com/watch?v=9g2VqJvWnQI

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

这篇关于【unity小技巧】使用三种方式实现瞄准瞄具放大变焦效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Linux使用nload监控网络流量的方法

《Linux使用nload监控网络流量的方法》Linux中的nload命令是一个用于实时监控网络流量的工具,它提供了传入和传出流量的可视化表示,帮助用户一目了然地了解网络活动,本文给大家介绍了Linu... 目录简介安装示例用法基础用法指定网络接口限制显示特定流量类型指定刷新率设置流量速率的显示单位监控多个

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Debezium 与 Apache Kafka 的集成方式步骤详解

《Debezium与ApacheKafka的集成方式步骤详解》本文详细介绍了如何将Debezium与ApacheKafka集成,包括集成概述、步骤、注意事项等,通过KafkaConnect,D... 目录一、集成概述二、集成步骤1. 准备 Kafka 环境2. 配置 Kafka Connect3. 安装 D

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本