基于体素场景的摄像机穿模处理

2023-10-04 02:15

本文主要是介绍基于体素场景的摄像机穿模处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于上一篇一种基于体素的射线检测
使用射线处理第三人称摄像头穿模问题

基于体素的第三人称摄像机拉近简单处理

摄像机移动至碰撞点处

简单的从角色身上发射一条射线到摄像机,中途遇到碰撞就把摄像机移动至该碰撞点

    public void UpdateDistance(float defaultDistance){Vector3 from = player.position;Vector3 to = cameraRoot.position;Vector3 forward = (to - from).normalized;Debug.DrawLine(from, to, Color.red);if (BlockPhysics.Raycast(BlockWorld.CurWorld, from, forward, (to - from).magnitude, out hitInfo)){distance = cameraRoot.InverseTransformPoint(hitInfo.point).z;}else{distance = 0;}curDistance = Mathf.Lerp(curDistance, distance, speed * Time.fixedDeltaTime);curDistance = Mathf.Clamp(curDistance, 0, defaultDistance);transform.localPosition = Vector3.forward * curDistance;}

可以明显看到摄像机一半在外面,一半在墙里面体验感非常差
在这里插入图片描述
可以通过检测摄像机近裁剪面的4个顶点是否在方块或体素内
如果有一个顶点产生碰撞,那么就把摄像机向前移动

    float GetDistance(float distance){int i = 0;int loop = 666;virtualCamera.localPosition = Vector3.forward * distance;var wrold = BlockWorld.CurWorld;while (loop-- > 0){UpdateNearClipPlane();for (i = 0; i < 4; i++){if (wrold.HasBlockCollider(Vector3Int.RoundToInt(corners[i])) || wrold.HasVoxelCollider(corners[i])){break;}}if (i == 4)break;distance += 0.25f;virtualCamera.localPosition = Vector3.forward * distance;}return distance;}

通过前移规避穿模问题
在这里插入图片描述
当然如果夹角非常小或者在一个狭窄的通道内,并不推荐拉近摄像头。
在这里插入图片描述
因为拉近已经不能解决问题。这种情况下推荐摄像机观察中心直接固定在方块中心。
从方块中心出发就不用担心角色过于靠近墙壁导致的拉近修复无效

完整代码

using UnityEngine;public class CameraOffset : MonoBehaviour
{public float speed = 10;Transform cameraRoot;Transform player;float distance;float curDistance;RaycastHit hitInfo;Camera mainCamera;Transform virtualCamera;Vector3[] corners = new Vector3[4];float width;float height;private void Start(){cameraRoot = transform.parent;player = GameObject.FindGameObjectWithTag("Player").transform;player = player.transform.Find("cameraFollow");mainCamera = Camera.main;virtualCamera = new GameObject("virtualCamera").transform;virtualCamera.transform.SetParent(mainCamera.transform.parent);virtualCamera.localPosition = Vector3.zero;virtualCamera.localRotation = Quaternion.identity;virtualCamera.localScale = Vector3.zero;float halfFOV = (mainCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;float aspect = mainCamera.aspect;height = mainCamera.nearClipPlane * Mathf.Tan(halfFOV);width = height * aspect;}private void OnDrawGizmos(){Gizmos.color = Color.red;Gizmos.DrawWireSphere(hitInfo.point, 0.1f);}public void UpdateDistance(float defaultDistance){Vector3 from = player.position;Vector3 to = cameraRoot.position;Vector3 forward = (to - from).normalized;Debug.DrawLine(from, to, Color.red);if (BlockPhysics.Raycast(BlockWorld.CurWorld, from, forward, (to - from).magnitude, out hitInfo)){distance = GetDistance(cameraRoot.InverseTransformPoint(hitInfo.point).z);}else{distance = 0;}curDistance = Mathf.Lerp(curDistance, distance, speed * Time.fixedDeltaTime);curDistance = Mathf.Clamp(curDistance, 0, defaultDistance);transform.localPosition = Vector3.forward * curDistance;}float GetDistance(float distance){int i = 0;int loop = 666;virtualCamera.localPosition = Vector3.forward * distance;var wrold = BlockWorld.CurWorld;while (loop-- > 0){UpdateNearClipPlane();for (i = 0; i < 4; i++){if (wrold.HasBlockCollider(Vector3Int.RoundToInt(corners[i])) || wrold.HasVoxelCollider(corners[i])){break;}}if (i == 4)break;distance += 0.25f;virtualCamera.localPosition = Vector3.forward * distance;}return distance;}void UpdateNearClipPlane(){corners[0] = virtualCamera.position - (virtualCamera.right * width);corners[0] += virtualCamera.up * height;corners[0] += virtualCamera.forward * mainCamera.nearClipPlane;corners[1] = virtualCamera.position + (virtualCamera.right * width);corners[1] += virtualCamera.up * height;corners[1] += virtualCamera.forward * mainCamera.nearClipPlane;corners[2] = virtualCamera.position - (virtualCamera.right * width);corners[2] -= virtualCamera.up * height;corners[2] += virtualCamera.forward * mainCamera.nearClipPlane;corners[3] = virtualCamera.position + (virtualCamera.right * width);corners[3] -= virtualCamera.up * height;corners[3] += virtualCamera.forward * mainCamera.nearClipPlane;}
}

这篇关于基于体素场景的摄像机穿模处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

SpringBoot操作spark处理hdfs文件的操作方法

《SpringBoot操作spark处理hdfs文件的操作方法》本文介绍了如何使用SpringBoot操作Spark处理HDFS文件,包括导入依赖、配置Spark信息、编写Controller和Ser... 目录SpringBoot操作spark处理hdfs文件1、导入依赖2、配置spark信息3、cont

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

Python中异常类型ValueError使用方法与场景

《Python中异常类型ValueError使用方法与场景》:本文主要介绍Python中的ValueError异常类型,它在处理不合适的值时抛出,并提供如何有效使用ValueError的建议,文中... 目录前言什么是 ValueError?什么时候会用到 ValueError?场景 1: 转换数据类型场景

python中的与时间相关的模块应用场景分析

《python中的与时间相关的模块应用场景分析》本文介绍了Python中与时间相关的几个重要模块:`time`、`datetime`、`calendar`、`timeit`、`pytz`和`dateu... 目录1. time 模块2. datetime 模块3. calendar 模块4. timeit

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Python中处理NaN值的技巧分享

《Python中处理NaN值的技巧分享》在数据科学和数据分析领域,NaN(NotaNumber)是一个常见的概念,它表示一个缺失或未定义的数值,在Python中,尤其是在使用pandas库处理数据时,... 目录NaN 值的来源和影响使用 pandas 的 isna()和 isnull()函数直接比较 Na

详解Python中通用工具类与异常处理

《详解Python中通用工具类与异常处理》在Python开发中,编写可重用的工具类和通用的异常处理机制是提高代码质量和开发效率的关键,本文将介绍如何将特定的异常类改写为更通用的ValidationEx... 目录1. 通用异常类:ValidationException2. 通用工具类:Utils3. 示例文

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关