Unity中的数字孪生项目:两种输入方式对观察物体的实现

在数字孪生项目中,精确的相机控制至关重要。相机不仅需要灵活地跟随目标,还要能够平滑地旋转和缩放,以便观察和分析物体的各个细节。今天,我将通过 TouchControlCameraCameraRotate 两个脚本,展示如何实现一个适用于数字孪生的相机控制系统。

1. TouchControlCamera 脚本(触摸一体机 安卓环境)

在数字孪生项目中,可能会涉及到移动端的交互式观察,用户通过触摸屏幕来操控相机,从而查看虚拟物体的各个视角。TouchControlCamera 脚本正是为此设计,它允许用户通过触摸操作来实现相机的旋转和缩放,特别适合移动设备上的数字孪生展示。

主要功能:
  • 触摸输入控制:通过手指在屏幕上的滑动或捏合手势,用户可以旋转相机或调整相机与目标物体的距离。
  • 直观的视角控制:无论是查看物体的细节,还是放大、缩小某个区域,触摸控制都能提供灵活的操作体验。
  • 平滑过渡:采用平滑算法来确保相机的旋转和缩放不会造成突兀感,用户体验更加自然。
代码实现:
cs 复制代码
using UnityEngine;

public class TouchControlCamera : MonoBehaviour
{
    public Transform target;  // 主相机要围绕其旋转的物体
    public float distance = 3.0f;  // 主相机与目标物体之间的距离

    [HideInInspector]
    public float eulerAngles_x;
    [HideInInspector]
    public float eulerAngles_y;

    public float distanceMax = 10;  // 主相机与目标物体之间的最大距离
    public float distanceMin = 1;   // 主相机与目标物体之间的最小距离
    public float xSpeed = 5.0f;     // 主相机水平方向旋转速度
    public float ySpeed = 5.0f;     // 主相机纵向旋转速度
    public int yMaxLimit = 80;      // 最大y(单位是角度)
    public int yMinLimit = -80;     // 最小y(单位是角度)

    public float dragAreaWidth = 200f;  // 屏幕中间允许拖拽的宽度

    private Vector2 oldPosition1 = new Vector2(0, 0);
    private Vector2 oldPosition2 = new Vector2(0, 0);

    private float XX, YY;

    private bool isDragging = false;  // 是否开始拖拽

    // 初始相机位置和旋转
    private Vector3 initialPosition;
    private Quaternion initialRotation;

    private Quaternion currentRotation;
    private Quaternion desiredRotation;

    void Start()
    {
        initialPosition = this.transform.position;
        initialRotation = this.transform.rotation;

        Vector3 eulerAngles = this.transform.eulerAngles;  // 当前物体的欧拉角
        this.eulerAngles_x = eulerAngles.y;
        this.eulerAngles_y = eulerAngles.x;

        currentRotation = this.transform.rotation;
        desiredRotation = this.transform.rotation;
    }

    void Update()
    {
        OneAndTwo();
    }

    /// <summary>
    /// 手指触屏判断
    /// </summary>
    public void OneAndTwo()
    {
        Vector3 eulerAngles = this.transform.eulerAngles;  // 当前物体的欧拉角
        this.eulerAngles_x = eulerAngles.y;
        this.eulerAngles_y = eulerAngles.x;

        // 一根手指触碰,旋转
        if (Input.touchCount == 1)
        {
            Touch touch = Input.GetTouch(0);

            if (touch.phase == TouchPhase.Began)
            {
                // 记录触摸的初始位置
                XX = touch.position.x;
                YY = touch.position.y;

                // 只有在触摸点在屏幕中间区域时才开始拖拽
                if (Mathf.Abs(touch.position.x - Screen.width / 2) <= dragAreaWidth)
                {
                    isDragging = true;
                }
                else
                {
                    isDragging = false;
                }
            }

            if (isDragging && touch.phase == TouchPhase.Moved)  // 只在拖拽时更新旋转
            {
                this.eulerAngles_x += (touch.position.x - XX) * Time.deltaTime * this.xSpeed;
                this.eulerAngles_y -= (touch.position.y - YY) * Time.deltaTime * this.ySpeed;
                this.eulerAngles_y = ClampAngle(this.eulerAngles_y, (float)this.yMinLimit, (float)this.yMaxLimit);

                XX = touch.position.x;
                YY = touch.position.y;

                // 使用平滑旋转效果
                desiredRotation = Quaternion.Euler(this.eulerAngles_y, this.eulerAngles_x, 0);
                currentRotation = this.transform.rotation;

                // 平滑过渡
                this.transform.rotation = Quaternion.Lerp(currentRotation, desiredRotation, 0.3f);
            }
        }

        // 确保相机保持在与目标物体之间的适当距离
        Vector3 vector = (this.transform.rotation * new Vector3(0, 0, -this.distance)) + this.target.position;

        // 更新相机的位置
        this.transform.position = vector;
    }

    // 将角度限制到给定范围内
    public float ClampAngle(float angle, float min, float max)
    {
        while (angle < -360)
        {
            angle += 360;
        }
        while (angle > 360)
        {
            angle -= 360;
        }

        return Mathf.Clamp(angle, min, max);
    }

    // 新增方法:重置相机位置和旋转
    public void ResetCamera()
    {
        this.transform.position = initialPosition;
        this.transform.rotation = initialRotation;
        this.eulerAngles_x = initialRotation.eulerAngles.y;
        this.eulerAngles_y = initialRotation.eulerAngles.x;
    }
}

2. CameraRotate 脚本 (纯PC环境 鼠标输入)

CameraRotate 脚本适用于桌面端或VR设备,可以实现相机围绕一个目标物体的旋转。对于数字孪生中的静态或动态物体观察,这种控制方式尤为重要。它能够让用户精准地控制相机角度,确保可以从不同的视角查看虚拟物体。

主要功能:
  • 目标物体观察:相机始终围绕指定的目标物体旋转,适合需要360度查看物体细节的场景。
  • 精细的角度控制:用户可以通过鼠标控制相机在水平和垂直方向上的旋转角度,提供高精度的观察视角。
  • 角度限制:为了避免相机的旋转过度(如倒立),垂直角度旋转被限制在一定范围内。
代码实现:
cs 复制代码
using UnityEngine;

/// <summary>
/// 相机围绕物体观察的简化版本
/// 可以旋转自主控制观察角度
/// </summary>
public class CameraRotate : MonoBehaviour
{
    [Header("相机观察的目标物体")]
    public Transform targetObject;
    public Vector3 targetOffset;
    public float averageDistance = 5.0f;
    public float maxDistance = 20;
    public float minDistance = .6f;
    public float xSpeed = 200.0f;
    public float ySpeed = 200.0f;
    [Header("相机y轴视野范围")]
    public int yMinLimit = -80;
    public int yMaxLimit = 80;

    private float xDeg = 0.0f;
    private float yDeg = 0.0f;
    private float currentDistance;
    private Quaternion currentRotation;
    private Quaternion desiredRotation;
    private Quaternion rotation;
    private Vector3 position;

    void Start() { Init(); }
    void OnEnable() { Init(); }

    public void Init()
    {
        // 如果目标物体为空,则在相机正前方创建一个观察目标
        if (!targetObject)
        {
            GameObject go = new GameObject("Cam Target");
            go.transform.position = transform.position + (transform.forward * averageDistance);
            targetObject = go.transform;
        }

        currentDistance = averageDistance;
        position = transform.position;
        rotation = transform.rotation;
        currentRotation = transform.rotation;
        desiredRotation = transform.rotation;
        xDeg = Vector3.Angle(Vector3.right, transform.right);
        yDeg = Vector3.Angle(Vector3.up, transform.up);

        // 相机位置 = 目标物体位置 - 目标与相机在三维下的位置差值
        position = targetObject.position - (rotation * Vector3.forward * currentDistance + targetOffset);
    }

    void LateUpdate()
    {
        // 按住鼠标左键时旋转相机
        if (Input.GetMouseButton(0))
        {
            xDeg += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
            yDeg -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
            yDeg = ClampAngle(yDeg, yMinLimit, yMaxLimit);  // 限制y轴旋转角度

            desiredRotation = Quaternion.Euler(yDeg, xDeg, 0);
            currentRotation = transform.rotation;

            // 平滑旋转
            rotation = Quaternion.Lerp(currentRotation, desiredRotation, 0.02f);
            transform.rotation = rotation;
        }

        // 更新相机位置
        position = targetObject.position - (rotation * Vector3.forward * currentDistance + targetOffset);
        transform.position = position;
    }

    /// <summary>
    /// 限制角度angle的大小在一个范围内
    /// </summary>
    private static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360)
            angle += 360;
        if (angle > 360)
            angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }
}

数字孪生项目中的应用

通过这两个脚本的结合,你可以实现更高效的视角控制,提升数字孪生的沉浸感和交互性。

例如,在虚拟工厂环境中,用户可以通过触摸操作放大、缩小并旋转相机,查看机器设备的各个细节。而在虚拟建筑物的模型中,用户可以通过 CameraRotate 旋转相机,从多个角度观察建筑物的外观和结构,获得更加全面的视角。

相关推荐
徐子竣3 小时前
[学习记录]Unity-Shader-几何着色器
unity·游戏引擎·着色器
EQ-雪梨蛋花汤9 小时前
【Part 3 Unity VR眼镜端播放器开发与优化】第四节|高分辨率VR全景视频播放性能优化
unity·音视频·vr
kyle~11 小时前
计算机视觉---RealSense深度相机技术
人工智能·数码相机·计算机视觉·机器人·嵌入式·ros·传感器
双翌视觉13 小时前
机器视觉对位中的常见模型与技术原理
数码相机·计算机视觉·机器视觉
与火星的孩子对话13 小时前
Unity进阶课程【六】Android、ios、Pad 终端设备打包局域网IP调试、USB调试、性能检测、控制台打印日志等、C#
android·unity·ios·c#·ip
幻世界14 小时前
【Unity智能模型系列】Unity + MediaPipe + Sentis + ArcFace模型:构建高效人脸识别比对系统
unity·游戏引擎
漫游者Nova1 天前
虚幻引擎Unreal Engine5恐怖游戏设计制作教程,从入门到精通从零开始完整项目开发实战详细讲解中英字幕
ue5·游戏引擎·虚幻·游戏开发完整教程·恐怖游戏开发
死也不注释1 天前
【Unity 编辑器工具开发:GUILayout 与 EditorGUILayout 对比分析】
unity·编辑器·游戏引擎
lingling0091 天前
结构光相机:重塑工业自动化的“智慧之眼”,驱动智能制造新未来
数码相机
小赖同学啊2 天前
物联网中的Unity/Unreal引擎集成:数字孪生与可视化控制
物联网·unity·游戏引擎