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

news2025/1/13 10:26:31

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

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

摄像机移动至碰撞点处

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

    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.coloradmin.cn/o/1058075.html

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

相关文章

机器学习(监督学习)笔记

笔记内容 代码部分 # 实验2-1 # 批梯度下降 import pandas as pd import numpy as np import random as rd import matplotlib.pyplot as plt # load dataset df pd.read_csv(temperature_dataset.csv) data np.array(df) y0 np.array([i[0] for i in data]) # 第一列作为…

Docker项目部署

目录 一、前端项目部署 1、上传文件 2、开启容器 3、测试 二、后端项目部署 1、打包java项目 2、将jar包和Dockerfile文件长传到Linux系统 3、构建镜像 4、开启容器 5、测试 一、前端项目部署 1、上传文件 里面包括页面和配置文件 worker_processes 1;events {worker…

云畅科技TMS解决方案助力华菱线缆实现智能货运管理

9月26日下午&#xff0c;湖南华菱线缆股份有限公司TMS物流系统上线启动会成功举办&#xff0c;由云畅科技倾力打造的华菱线缆TMS物流系统正式上线运行&#xff0c;标志着湖南华菱线缆股份有限公司在智能化物流货运管理领域的一次重大突破。 湖南华菱线缆股份有限公司董事兼总经…

C#捕捉全局异常

1.运行图片 2.源码 using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms;namespace 捕捉全局异常 {internal static class Program{/// <summary>/// 应用程序的主入口点。/// </summary…

竞赛选题 机器视觉opencv答题卡识别系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 答题卡识别系统 - opencv python 图像识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分…

【Spring】更简单的读取和存储对象

更简单的读取和存储对象 一. 存储 Bean 对象1. 前置工作&#xff1a;配置扫描路径2. 添加注解存储 Bean 对象Controller&#xff08;控制器存储&#xff09;Service&#xff08;服务存储&#xff09;Repository&#xff08;仓库存储&#xff09;Component&#xff08;组件存储&…

基于transformer的心脑血管心脏病疾病预测

视频讲解:基于transformer的心脑血管疾病预测 完整数据代码分享_哔哩哔哩_bilibili 数据展示: 完整代码: # pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple/ # pip install optuna -i https://pypi.tuna.tsinghua.edu.cn/simple/ import numpy as np …

C++ - 位图 - bitset 容器介绍

前言 之前的两篇博客已经完成 闭散列的开放地址法的哈希表 和 哈希桶基本实现&#xff0c;和对 unordered_set 和 unordered_map 的封装 &#xff1a;C - 封装 unordered_set 和 unordered_map - 哈希桶的迭代器实现_chihiro1122的博客-CSDN博客C - 开散列的拉链法&#xff08…

【JVM】运行时数据区(内存区域划分)详解

文章目录 前言一、JVM 运行时数据区1, 堆2, Java 虚拟机栈3, 本地方法栈4, 程序计数器5, 元数据区 / 方法区 二、内存异常问题1, 栈溢出2, 内存溢出3, 内存泄露 总结 前言 &#x1f4d5;各位读者好, 我是小陈, 这是我的个人主页 &#x1f4d7;小陈还在持续努力学习编程, 努力通…

【重拾C语言】三、分支程序设计(双分支和单分支程序设计、逻辑判断、多分支程序设计、枚举类型表示;典型例题:判断闰年和求一元二次方程根)

目录 前言 三、分支程序设计 3.1 判断成绩是否及格——双分支程序设计 3.2 成绩加上获奖信息—单分支程序设计 3.3 逻辑判断——布尔类型 3.4 获奖分等级——多分支程序设计 3.5 表示汽车种类——枚举类型 3.6 例题 3.6.1 例题——判断某个年份是否闰年 3.6.2 例题—…

SG Former论文学习笔记

超越SWin和CSWin Transformer的新模型 代码地址&#xff1a;https://github.com/OliverRensu/SG-Former 论文地址&#xff1a;https://arxiv.org/pdf/2308.12216.pdf ViT在各种视觉任务中虽然成功&#xff0c;但它的计算成本随着Token序列长度的增加呈二次增长&#xff0c;这在…

前端系列-1 HTML+JS+CSS基础

背景&#xff1a; 前端系列会收集碎片化的前端知识点&#xff0c;作为自己工作和学习时的字典&#xff0c;欢迎读者收藏和使用。 笔者是后端开发&#x1f636;前端涉猎不深&#xff0c;因此文章重在广度和实用&#xff0c;对原理和性能不会过多深究。 1.html 1.1 html5网页结…

软考中级—— 操作系统知识

进程管理 操作系统概述 操作系统的作用&#xff1a;通过资源管理提高计算机系统的效率&#xff1b;改善人机界面向用户提供友好的工作环境。 操作系统的特征&#xff1a;并发性、共享性、虚拟性、不确定性。 操作系统的功能&#xff1a;进程管理、存储管理、文件管理、设备…

654.最大二叉树

力扣题目地址(opens new window) 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给…

BIT-7文件操作和程序环境(16000字详解)

一&#xff1a;文件 1.1 文件指针 每个被使用的文件都在内存中开辟了一个相应的文件信息区&#xff0c;用来存放文件的相关信息&#xff08;如文件的名字&#xff0c;文件状态及文件当前的位置等&#xff09;。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明…

uniapp实现微信小程序隐私协议组件封装

uniapp实现微信小程序隐私协议组件封装。 <template><view class"diygw-modal basic" v-if"showPrivacy" :class"showPrivacy?show:" style"z-index: 1000000"><view class"diygw-dialog diygw-dialog-modal bas…

边缘计算网关

一、项目整体框架图 二、项目整体描述 边缘计算网关项目主要实现了智能家居场景和工业物联网场景下设备的数据采集和控制。 整个项目分为三大层&#xff1a;用户接口层、网关层、设备层。 其中用户层通过QT客户端、WEB界面及阿里云提供数据展示和用户接口。 网关使用虚拟机代替…

【网络安全-sqlmap】sqlmap以及几款自动化sql注入工具的详细使用过程,超详细,SQL注入【5】

一&#xff0c;sqlmap 工具的详细使用 kali系统自带这个工具&#xff0c;无需安装直接sqlmap 后面接参数使用 Windows上参照以下方法安装即可 1-1 工具下载 1-1-1 sqlmap下载 sqlmap 工具下载地址&#xff1a; GitHub - sqlmapproject/sqlmap: Automatic SQL injection a…

多线程基础篇(多线程案例)

文章目录 多线程案例1、单例模式1&#xff09;饿汉模式2&#xff09;懒汉模式3&#xff09;线程安全吗&#xff1f;&#xff1f;4&#xff09;解决懒汉模式线程安全问题5&#xff09;解决懒汉模式内存可见性问题 2、阻塞队列1) 阻塞队列是什么&#xff1f;2) 生产者消费者模型1…

大屏自适应容器组件-Vue3+TS

1.引言 在做数字大屏时&#xff0c;图表能跟着浏览器的尺寸自动变化&#xff0c;本文采用Vue3前端框架&#xff0c;采用TypeScript语言&#xff0c;封装了一个大屏自适应组件&#xff0c;将需要显示的图表放入组件的插槽中&#xff0c;就能实现自适应屏幕大小的效果。 2.实际…