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

news2024/11/27 7:30:37

最终效果对比

在这里插入图片描述

文章目录

  • 最终效果对比
  • 前言
  • 第一种办法
  • 方法二
    • 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");
        
        // 根据滚轮滑动的值调整 FOV
        playerCamera.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);
        // 将物体的屏幕坐标传递给 Shader
        material.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");
        
        // 根据滚轮滑动的值调整 FOV
        playerCamera.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是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

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

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

相关文章

安卓端出现https请求失败(转)

背景# 某天早上,正在一个会议时,突然好几个同事被叫出去了;后面才知道,是有业务同事反馈到领导那里,我们app里面某个功能异常。 具体是这样,我们安卓版本的app是禁止截屏的(应该是app里做了拦…

vue3的大致使用

<template><div class"login_wrap"><div class"form_wrap"> <!-- 账号输入--> <el-form ref"formRef" :model"user" class"demo-dynamic" > <!--prop要跟属性名称对应-->…

呜呜呜我要拿Go赢他~ 入门,Go的最简单的 Web 服务器!

前言 继续接入上章节的呜呜呜我要拿Go赢他~ 入门,Go的基础语法! 的文章现在要学的是Go的最简单的 Web 服务器! 补充 上章节的基础语法-方法声明与调用 方法声明 四个部分&#xff1a; 关键字 func方法名字&#xff1a;首字母是否大写决定了作用域参数列表&#xff1a;返回…

C++面试宝典第6题:访问数组和联合体元素

题目 阅读下面的代码段,并给出程序的输出。 (1)访问数组元素。 int a[] = {61, 62, 63, 64, 65, 66}; int *p = (int *)(&a + 1); printf("%d, %d\n", *(a + 1), *(p - 1)); (2)访问联合体元素。 union {short i;char x[2]; }a;a.x[0] = 10; a.x[1] = 1; …

Qt/C++音视频开发60-坐标拾取/按下鼠标获取矩形区域/转换到视频源真实坐标

一、前言 通过在通道画面上拾取鼠标按下的坐标&#xff0c;然后鼠标移动&#xff0c;直到松开&#xff0c;根据松开的坐标和按下的坐标&#xff0c;绘制一个矩形区域&#xff0c;作为热点或者需要电子放大的区域&#xff0c;拿到这个坐标区域&#xff0c;用途非常多&#xff0…

UE5 C++(二)— 游戏架构介绍

架构关系如下&#xff1a; 这里只简单描述下&#xff0c;具体的查看官方文档 AGameMode: AGameMode 是 AGameModeBase 的子类&#xff0c;拥有一些额外的功能支持多人游戏和旧行为。 所有新建项目默认使用 AGameModeBase。 如果需要此额外行为&#xff0c;可切换到从 AGameM…

【LangChain学习之旅】—(3) LangChain快速构建本地知识库的智能问答系统

【LangChain学习之旅】—&#xff08;3&#xff09; LangChain快速构建本地知识库的智能问答系统 项目及实现框架开发框架核心实现机制数据准备及加载加载文本文本的分割向量数据库存储文本的“嵌入”概念向量数据库概念 相关信息获取RetrievalQA生成回答并展示示例小结 Refere…

云服务器部署vue/node项目

此处以阿里云服务器为例&#xff0c;配置的是LNMP环境 vue部署云服务器&#xff1a; 以阿里云服务为例&#xff0c;端口自定义99 1、在 /usr/share/nginx/html/ 该目录下新建文件夹&#xff0c;该文件夹是部署的打好包的前端项目 例&#xff1a; 2、进入nginx目录配置相关配…

【Qt开发流程】之TCP

概述 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输协议。它是互联网协议套件中的一部分&#xff0c;用于在网络上可靠地传输数据。 TCP通过建立连接、数据传输和连接终止三个阶段来进行通信…

音频I2S

前言 基于网上资料对相关概念做整理汇总&#xff0c;部分内容引用自文后文章。 学习目标&#xff1a;简单了解相关概念、相关协议。 1 概述 数字音频接口DAI&#xff0c;即Digital Audio Interfaces&#xff0c;顾名思义&#xff0c;DAI表示在板级或板间传输数字音频信…

ELK(八)—Metricbeat部署

目录 介绍修改配置文件启动 Modulenginx开启状态查询配置Nginx module查看是否配置成功 介绍 Metricbeat 是一个轻量级的开源度量数据收集器&#xff0c;用于监控系统和服务。它由 Elastic 公司开发&#xff0c;并作为 Elastic Stack&#xff08;Elasticsearch、Logstash、Kiba…

Ubuntu18.04安装ffmpeg

前言 从本章开始我们将要学习嵌入式音视频的学习了 &#xff0c;使用的瑞芯微的开发板 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类&#xff09;_C…

解决:AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’

解决&#xff1a;AttributeError: module ‘scipy.misc’ has no attribute ‘imsave’ 文章目录 解决&#xff1a;AttributeError: module scipy.misc has no attribute imsave背景报错问题报错翻译报错位置代码报错原因解决方法方法一 scipy版本回退&#xff08;不推荐&#…

【物联网】EMQX(二)——docker快速搭建EMQX 和 MQTTX客户端使用

一、前言 在上一篇文章中&#xff0c;小编向大家介绍了物联网必然会用到的消息服务器EMQ&#xff0c;相信大家也对EMQ有了一定的了解&#xff0c;那么接下来&#xff0c;小编从这篇文章正式开始展开对EMQ的学习教程&#xff0c;本章节来记录一下如何对EMQ进行安装。 二、使用…

P2P如何使用register_attention_control为UNet的CrossAttention关联AttentionStore

上次的调试到这里了&#xff0c;写完这篇接着看&#xff0c;prepare_latents_ddim_inverted 如何预计算 inversion latents&#xff1a; /home/pgao/yue/FateZero/video_diffusion/pipelines/p2p_ddim_spatial_temporal.py 1. 原始的UNet3D的CrossAttention和SparseCausalAtte…

展示一段比较简单的人工智能自动做模型的程序

人工智能是一种模拟或模仿人类智能的技术。它通过使计算机系统具有一定的认知能力和学习能力&#xff0c;使其能够自动完成一系列复杂的任务。人工智能可以在各个领域应用&#xff0c;包括图像识别、语音识别、自然语言处理、机器学习等。人工智能还可以用于解决各种问题&#…

地平线前端实习一面复盘(加深对var的理解+展开运算符+平拍数组)

目录 前言一&#xff0c;var的作用二&#xff0c;展开运算符三&#xff0c;平拍数组总结 前言 地平线的面试&#xff0c;有提示&#xff0c;很专业&#xff0c;体验很好。 可惜后面未收到消息&#xff0c;但还是要做复盘。收获还是很大的。 一&#xff0c;var的作用 且看下…

30. 深度学习进阶 - 池化

Hi&#xff0c;你好。我是茶桁。 上一节课&#xff0c;我们详细的学习了卷积的原理&#xff0c;在这个过程中给大家讲了一个比较重要的概念&#xff0c;叫做input channel&#xff0c;和output channel。 当然现在不需要直接去实现, 卷积的原理PyTorch、或者TensorFlow什么的…

Python tkinter 初探Toplevel控件搭建父子窗口

目录 Toplevel控件搭建父子窗口 最简明的父子窗口框架 改进一&#xff1a;屏蔽和开放按钮 改进二&#xff1a;子窗口始终在主窗口之上 改进三&#xff1a;增加子窗口的关闭协议 改进四&#xff1a;使子窗口长获焦点 总结 Toplevel控件搭建父子窗口 最近&#xff0c;用P…

直播江湖:东方甄选与董宇辉的权力游戏

出品| 大力财经 文 | 魏力 近期&#xff0c;围绕东方甄选的小作文事件引起了广泛关注&#xff0c;有人将其解读为一场巧妙策划的事件营销&#xff0c;然而&#xff0c;舆情的不可控性使得事态逐渐演变为一场复杂的利益博弈。 东方甄选与董宇辉的“蜜月期”可以说是双方互相成就…