Unity环绕物体的摄像机,添加了遮挡的适应

2024-05-24 07:52

本文主要是介绍Unity环绕物体的摄像机,添加了遮挡的适应,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

第三人人称摄像机

支持的功能

设定目标后使用鼠标可以环绕目标点旋转,且会进行遮挡的适配,当有遮挡的时候会移动差值移动到没有遮挡的位置。

使用方式

vThirdPersonCamera 挂在与摄像机上然后为target赋值。
如果有需要检测遮挡的层级可以修改:cullingLayer
vExtensions 创建并复制代码即可,工具类。
如果高度有偏移就修改:height

请添加图片描述

using Invector;
using UnityEngine;public class vThirdPersonCamera : MonoBehaviour
{#region inspector properties    public Transform target;[Tooltip("Leep的速度")]public float smoothCameraRotation = 12f;[Header("遮挡的层")] public LayerMask cullingLayer = 1 << 0;[Tooltip("Debug purposes, lock the camera behind the character for better align the states")]public bool lockCamera;[Header("Camera Input")]public string rotateCameraXInput = "Mouse X";public string rotateCameraYInput = "Mouse Y";[Header("向右偏移角度")]public float rightOffset = 0f;[Header("距离目标的距离")]public float defaultDistance = 2.5f;public float height = 1.4f;public float smoothFollow = 10f;public float xMouseSensitivity = 3f;public float yMouseSensitivity = 3f;public float yMinLimit = -40f;public float yMaxLimit = 80f;#endregion#region hide properties    [HideInInspector]public int indexList, indexLookPoint;[HideInInspector]public float offSetPlayerPivot;[HideInInspector]public string currentStateName;[HideInInspector]public Transform currentTarget;[HideInInspector]public Vector2 movementSpeed;private Transform targetLookAt;private Vector3 currentTargetPos;private Vector3 lookPoint;private Vector3 current_cPos;private Vector3 desired_cPos;private Camera _camera;private float distance = 5f;private float mouseY = 0f;private float mouseX = 0f;private float currentHeight;private float cullingDistance;private float checkHeightRadius = 0.4f;private float clipPlaneMargin = 0f;private float forward = -1f;private float xMinLimit = -360f;private float xMaxLimit = 360f;private float cullingHeight = 0.2f;private float cullingMinDist = 0.1f;#endregionprivate void Start(){Init();}private void Init(){if (target == null)return;_camera = GetComponent<Camera>();currentTarget = target;currentTargetPos = new Vector3(currentTarget.position.x, currentTarget.position.y + offSetPlayerPivot, currentTarget.position.z);targetLookAt = new GameObject("targetLookAt").transform;targetLookAt.position = currentTarget.position;targetLookAt.hideFlags = HideFlags.HideInHierarchy;targetLookAt.rotation = currentTarget.rotation;mouseY = currentTarget.eulerAngles.x;mouseX = currentTarget.eulerAngles.y;distance = defaultDistance;currentHeight = height;}private void FixedUpdate(){if (target == null || targetLookAt == null){return;}//收到鼠标的输入var Y = Input.GetAxis(rotateCameraYInput);var X = Input.GetAxis(rotateCameraXInput);//旋转摄像机RotateCamera(X, Y);CameraMovement();}private void SetMainTarget(Transform newTarget){target = newTarget;currentTarget = newTarget;mouseY = currentTarget.rotation.eulerAngles.x;mouseX = currentTarget.rotation.eulerAngles.y;Init();}/// <summary>/// Camera Rotation behaviour/// </summary>/// <param name="x"></param>/// <param name="y"></param>private void RotateCamera(float x, float y){// free rotation mouseX += x * xMouseSensitivity;mouseY -= y * yMouseSensitivity;movementSpeed.x = x;movementSpeed.y = -y;if (!lockCamera){mouseY = Invector.vExtensions.ClampAngle(mouseY, yMinLimit, yMaxLimit);mouseX = Invector.vExtensions.ClampAngle(mouseX, xMinLimit, xMaxLimit);}else{mouseY = currentTarget.root.localEulerAngles.x;mouseX = currentTarget.root.localEulerAngles.y;}}/// <summary>/// Camera behaviour/// </summary>    private void CameraMovement(){if (currentTarget == null)return;distance = Mathf.Lerp(distance, defaultDistance, smoothFollow * Time.deltaTime);cullingDistance = Mathf.Lerp(cullingDistance, distance, Time.deltaTime);var camDir = (forward * targetLookAt.forward) + (rightOffset * targetLookAt.right);camDir = camDir.normalized;var targetPos = new Vector3(currentTarget.position.x, currentTarget.position.y + offSetPlayerPivot, currentTarget.position.z);currentTargetPos = targetPos;desired_cPos = targetPos + new Vector3(0, height, 0);current_cPos = currentTargetPos + new Vector3(0, currentHeight, 0);RaycastHit hitInfo;ClipPlanePoints planePoints = _camera.NearClipPlanePoints(current_cPos + (camDir * (distance)), clipPlaneMargin);ClipPlanePoints oldPoints = _camera.NearClipPlanePoints(desired_cPos + (camDir * distance), clipPlaneMargin);//Check if Height is not blocked if (Physics.SphereCast(targetPos, checkHeightRadius, Vector3.up, out hitInfo, cullingHeight + 0.2f, cullingLayer)){var t = hitInfo.distance - 0.2f;t -= height;t /= (cullingHeight - height);cullingHeight = Mathf.Lerp(height, cullingHeight, Mathf.Clamp(t, 0.0f, 1.0f));}//Check if desired target position is not blocked       if (CullingRayCast(desired_cPos, oldPoints, out hitInfo, distance + 0.2f, cullingLayer, Color.blue)){distance = hitInfo.distance - 0.2f;if (distance < defaultDistance){var t = hitInfo.distance;t -= cullingMinDist;t /= cullingMinDist;currentHeight = Mathf.Lerp(cullingHeight, height, Mathf.Clamp(t, 0.0f, 1.0f));current_cPos = currentTargetPos + new Vector3(0, currentHeight, 0);}}else{currentHeight = height;}//Check if target position with culling height applied is not blockedif (CullingRayCast(current_cPos, planePoints, out hitInfo, distance, cullingLayer, Color.cyan)) distance = Mathf.Clamp(cullingDistance, 0.0f, defaultDistance);var lookPoint = current_cPos + targetLookAt.forward * 2f;lookPoint += (targetLookAt.right * Vector3.Dot(camDir * (distance), targetLookAt.right));targetLookAt.position = current_cPos;Quaternion newRot = Quaternion.Euler(mouseY, mouseX, 0);targetLookAt.rotation = Quaternion.Slerp(targetLookAt.rotation, newRot, smoothCameraRotation * Time.deltaTime);transform.position = current_cPos + (camDir * (distance));var rotation = Quaternion.LookRotation((lookPoint) - transform.position);transform.rotation = rotation;movementSpeed = Vector2.zero;}/// <summary>/// Custom Raycast using NearClipPlanesPoints/// </summary>/// <param name="_to"></param>/// <param name="from"></param>/// <param name="hitInfo"></param>/// <param name="distance"></param>/// <param name="cullingLayer"></param>/// <returns></returns>private bool CullingRayCast(Vector3 from, Invector.ClipPlanePoints _to, out RaycastHit hitInfo, float distance, LayerMask cullingLayer, Color color){bool value = false;if (Physics.Raycast(from, _to.LowerLeft - from, out hitInfo, distance, cullingLayer)){value = true;cullingDistance = hitInfo.distance;}if (Physics.Raycast(from, _to.LowerRight - from, out hitInfo, distance, cullingLayer)){value = true;if (cullingDistance > hitInfo.distance) cullingDistance = hitInfo.distance;}if (Physics.Raycast(from, _to.UpperLeft - from, out hitInfo, distance, cullingLayer)){value = true;if (cullingDistance > hitInfo.distance) cullingDistance = hitInfo.distance;}if (Physics.Raycast(from, _to.UpperRight - from, out hitInfo, distance, cullingLayer)){value = true;if (cullingDistance > hitInfo.distance) cullingDistance = hitInfo.distance;}return hitInfo.collider && value;}
}
using System;
using System.Collections.Generic;
using UnityEngine;namespace Invector
{public static class vExtensions{public static T[] Append<T>(this T[] arrayInitial, T[] arrayToAppend){if (arrayToAppend == null){throw new ArgumentNullException("The appended object cannot be null");}if ((arrayInitial is string) || (arrayToAppend is string)){throw new ArgumentException("The argument must be an enumerable");}T[] ret = new T[arrayInitial.Length + arrayToAppend.Length];arrayInitial.CopyTo(ret, 0);arrayToAppend.CopyTo(ret, arrayInitial.Length);return ret;}public static T[] vToArray<T>(this List<T> list){T[] array = new T[list.Count];if (list == null || list.Count == 0) return array;for (int i = 0; i < list.Count; i++){array[i] = list[i];}return array;}public static float ClampAngle(float angle, float min, float max){do{if (angle < -360)angle += 360;if (angle > 360)angle -= 360;} while (angle < -360 || angle > 360);return Mathf.Clamp(angle, min, max);}public static ClipPlanePoints NearClipPlanePoints(this Camera camera, Vector3 pos, float clipPlaneMargin){var clipPlanePoints = new ClipPlanePoints();var transform = camera.transform;var halfFOV = (camera.fieldOfView / 2) * Mathf.Deg2Rad;var aspect = camera.aspect;var distance = camera.nearClipPlane;var height = distance * Mathf.Tan(halfFOV);var width = height * aspect;height *= 1 + clipPlaneMargin;width *= 1 + clipPlaneMargin;clipPlanePoints.LowerRight = pos + transform.right * width;clipPlanePoints.LowerRight -= transform.up * height;clipPlanePoints.LowerRight += transform.forward * distance;clipPlanePoints.LowerLeft = pos - transform.right * width;clipPlanePoints.LowerLeft -= transform.up * height;clipPlanePoints.LowerLeft += transform.forward * distance;clipPlanePoints.UpperRight = pos + transform.right * width;clipPlanePoints.UpperRight += transform.up * height;clipPlanePoints.UpperRight += transform.forward * distance;clipPlanePoints.UpperLeft = pos - transform.right * width;clipPlanePoints.UpperLeft += transform.up * height;clipPlanePoints.UpperLeft += transform.forward * distance;return clipPlanePoints;}}public struct ClipPlanePoints{public Vector3 UpperLeft;public Vector3 UpperRight;public Vector3 LowerLeft;public Vector3 LowerRight;}
}

这篇关于Unity环绕物体的摄像机,添加了遮挡的适应的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

KLayout ------ 旋转物体90度并做平移

KLayout ------ 旋转创建的物体 正文 正文 前段时间,有个小伙伴留言问我,KLayout 中如何旋转自己创建的物体,这里特来说明一下。 import pyapoly = pya.DPolygon([pya.DPoint(0, 0), pya.DPoint(0, 5), pya

【Unity Shader】片段着色器(Fragment Shader)的概念及其使用方法

在Unity和图形编程中,片段着色器(Fragment Shader)是渲染管线中的一个阶段,负责计算屏幕上每个像素(片段)的颜色和特性。片段着色器通常在顶点着色器和任何几何处理之后运行,是决定最终像素颜色的关键步骤。 Fragment Shader的概念: 像素处理:片段着色器处理经过顶点着色器和几何着色器处理后,映射到屏幕空间的像素。颜色计算:它计算每个像素的颜色值,这可能包括纹理采样、光

【Unity Shader】Alpha Blend(Alpha混合)的概念及其使用示例

在Unity和图形编程中,Alpha Blend(也称为Alpha混合)是一种用于处理像素透明度的技术。它允许像素与背景像素融合,从而实现透明或半透明的效果。Alpha Blend在渲染具有透明度的物体(如窗户、玻璃、水、雾等)时非常重要。 Alpha Blend的概念: Alpha值:Alpha值是一个介于0(完全透明)和1(完全不透明)的数值,用于表示像素的透明度。混合模式:Alpha B

Unity Meta Quest 开发:关闭 MR 应用的安全边界

社区链接: SpatialXR社区:完整课程、项目下载、项目孵化宣发、答疑、投融资、专属圈子 📕教程说明 这期教程我将介绍如何在应用中关闭 Quest 系统的安全边界。 视频讲解: https://www.bilibili.com/video/BV1Gm42157Zi 在 Unity 中导入 Meta XR SDK,进行环境配置后,打开 Assets > Plugins > An

【智能优化算法改进策略之局部搜索算子(五)—自适应Rosenbrock坐标轮换法】

1、原理介绍 作为一种有效的直接搜索技术,Rosenbrock坐标轮换法[1,2]是根据Rosenbrock著名的“香蕉函数”的特点量身定制的,该函数的最小值位于曲线狭窄的山谷中。此外,该方法是一种典型的基于自适应搜索方向集的无导数局部搜索技术。此法于1960年由Rosenbrock提出,它与Hooke-Jeeves模式搜索法有些类似,但比模式搜索更为有效。每次迭代运算分为两部分[3]: 1)

自适应iPhone的不同键盘高度

转自:http://blog.csdn.net/jasonblog/article/details/7285098 在iOS 5中,键盘的高度是会变化的,比如切换到中文输入法时会在键盘上方多出一层候选字区域,如下图: 而在英文输入法下是没有文字候选区域的。 因此在用户输入场景下,布局的美观和可用性可能受到键盘高度变化的影响,因此需要动态适应键盘高度。 解决

一款基于WordPress开发的高颜值的自适应主题Puock

主题特性 支持白天与暗黑模式 全局无刷新加载 支持博客与CMS布局 内置WP优化策略 一键全站变灰 网页压缩成一行 后台防恶意登录 内置出色的SEO功能 评论Ajax加载 文章点赞、打赏 支持Twemoji集成 支持QQ登录 丰富的广告位 丰富的小工具 自动百度链接提交 众多页面模板 支持评论可见 支持密码可见 支持Dplayer播放器 简约快捷的后台配置 更多功能,等你的提议 安装 请下载

智能优化算法改进策略之局部搜索算子(七)--自适应模式搜索法

1、原理介绍     模式搜索法[1]是Hooke与Jeeves提出的一种直接搜索算法,其目的是通过比较目标函数在有限点集中的函数值来优化目标函数。更重要的是,它不仅不使用任何导数知识,而且不需要隐式地建立任何一种导数近似。 在这种直接搜索技术中,将模式移动和探索移动相结合,迭代地寻找最优解。该技术首先沿着每个轴进行探索性移动,以寻找新的基点和有利于函数值下降的方向。然后,为了加快在探索性移动

Unity 字体创建时候容易导致字体文件不正确的一种情况

上面得到了两种字体格式,一种是TextMeshPro的,另一种是Unity UI系统中默认使用的字体资源。其原因是创建的位置不同导致的。 1.下面是TextMeshPro字体创建的位置 2:下面是Unity UI系统中默认使用的字体资源

Dubbo SPI之自适应扩展机制 @Adaptive

上一篇介绍了 Dubbo SPI 的基本实现,这篇就介绍下 Dubbo SPI 的自适应扩展机制,对应注解 @Adaptive。 介绍 @Adaptive 定义如下: public @interface Adaptive {/*** parameter names in URL*/String[] value() default {};} value 是个字符数组,通过该属性从 URL