理解htcvive更新——控制相机旋转和位移

cartzhang cartzhang     2022-08-31     796

关键词:


本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/72188658
作者:cartzhang

一、写在前面


在HTC的vive 头盔中,
一旦Vive头盔连接都unity游戏中,就会控制所有Camera的旋转和位置。

这对于有需要的控制非头盔相机带来了烦恼。

比方说,上篇博客中,在VR中,对某个特点位置截图,就会由于头盔控制所有相机的旋转,
造成截图不精确和出现偏移。

地址:
http://blog.csdn.net/cartzhang/article/details/71136498


现在,经过测试发现,其实是可以控制的。

在Win10系统下测试,unity版本为5.4.4f1,Steam VR 版本v1.1.1。

二、怎么控制

这里写图片描述
图0

头盔在正常情况下,被头盔具体位置和旋转赋值控制。

这里写图片描述
图1

同时头盔的参数也控制其他,比如UI相机的位置和旋转。


加上我们的脚本:

这里写图片描述
图2

游戏编辑器下运行,头盔给Ui相机的赋值,被强制给变成了零。

三、控制脚本代码


接下来看看脚本代码:

//@cartzhang
using UnityEngine;
using System.Collections;

public class StickRotate : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }


    // NO ,不行。
    //private void FixedUpdate()
    //{
    //    transform.rotation = Quaternion.identity;
    //}


    // yes ,可以限定。
    //private void OnPreCull()
    //{
    //    transform.rotation = Quaternion.identity;
    //}

    // Update is called once per frame
    void OnPostRender ()
    {
        transform.rotation = Quaternion.identity;
        transform.position = Vector3.zero;
    }
}


经过测试,发现在Update和fixedUpdate中处理上不可行的。
在OnPreCull和OnPostRender进行重新赋值都可以的。

四、重点来了,都是幻觉

1. 没有那么简单


当时第六感就怀疑,应该没有这么简单。要不就不会有成群结队的人要求unity和steamVR插件做接口和选项了,让可以控制旋转和移动了。

当时是这样想的:
结果我还是有一定的怀疑的。是不是由于脚本执行顺序不同,在不同的电脑和不同时候结果也不一样的。
若有的话,试试看通过调整脚本执行顺序看能不能解决问题。

2.转折了


结果,出去遛一圈回来,就不行了。郁闷啊!!
截图都在,电脑不认了。
都是幻觉啊!!

这里写图片描述
图3

找到了方法
https://steamcommunity.com/app/358720/discussions/0/365163686052028359/
说在5.3 可用,5.4不可用。天啊…

(说明下,之前想的调整渲染顺序,然并卵。理想与现实的差距啊…)

3. 然而,并不气


气也没有用。考虑对策,

第一,我试图把VR5.3的VR插件直接拷贝到我的5.4.4f1版本里来做替换,结果可想而知,失败,替换后根本就没有了VR效果,因为VR的插件相当于没有加载。

第二、使用相对旋转和相对位置实时做矫正。


也参看来其他的只需要旋转的一个问题。有需要的可以参考:

http://answers.unity3d.com/questions/1209337/vrvive-allow-rotation-only.html

这个方案与我之前的小场地扩展到大场地的策略类似,可以参考:
HTC Vive小场地与大场景空间的解决方案————
http://blog.csdn.net/cartzhang/article/details/52780621

这个结果是成功了。

这里写图片描述
图4

4. 给出代码

using UnityEngine;
using System.Collections;

public class StickRotate : MonoBehaviour
{   
    private Vector3 InitialPos;
    private Vector3 hmdPos;
    public GameObject HMD;
    private Transform CameraPos;

    void Start()
    {
        CameraPos = transform;
        InitialPos = transform.position;
    }

    // Update is called once per frame
    void LateUpdate()
    {
        hmdPos = HMD.transform.localPosition;
        transform.position = CameraPos.position - hmdPos;
        transform.rotation = Quaternion.Euler(CameraPos.rotation.eulerAngles - HMD.transform.rotation.eulerAngles);
    }

    // NO ,不行。
    //private void FixedUpdate()
    //{
    //    transform.rotation = Quaternion.identity;
    //}


    // NO ,不能限制旋转。
    //private void Update()
    //{
    //    transform.rotation = Quaternion.identity;
    //}

    // yes ,可以限定。这个原来是可以的,后来莫名就不行了。
 //   private void OnPreCull()
 //   {
 //       transform.rotation = Quaternion.identity;
 //   }

 //   // 这个跟上面一下,当时还有点沾沾自喜...
 //   void OnPostRender ()
 //   {
 //       transform.rotation = Quaternion.identity;
 //       transform.position = Vector3.zero;
    //}

}

五、试着了解 Vive头盔的更新

1. 头盔的渲染更新是在SteamVR_Render中进行的。

// 注释 @cartzhang
void Update()
    {
#if !(UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
        // 添加PoseUpdate。在SteamVR_UpdatePoses中实现了位置更新。
        // 
        if (poseUpdater == null)
        {
            var go = new GameObject("poseUpdater");
            go.transform.parent = transform;
            poseUpdater = go.AddComponent<SteamVR_UpdatePoses>();
        }
#else
        if (cameras.Length == 0)
        {
            enabled = false;
            return;
        }

        // If our FixedUpdate rate doesn't match our render framerate, then catch the handoff here.
        SteamVR_Utils.QueueEventOnRenderThread(SteamVR.Unity.k_nRenderEventID_PostPresentHandoff);
#endif
        // Force controller update in case no one else called this frame to ensure prevState gets updated.
        // 强制调用手柄更新,以防止本帧没有调用。
        SteamVR_Controller.Update();

        // Dispatch any OpenVR events.
        // 事件分发。
        var system = OpenVR.System;
        if (system != null)
        {
            var vrEvent = new VREvent_t();
            var size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(VREvent_t));
            for (int i = 0; i < 64; i++)
            {
                if (!system.PollNextEvent(ref vrEvent, size))
                    break;

                switch ((EVREventType)vrEvent.eventType)
                {
                    case EVREventType.VREvent_InputFocusCaptured: // another app has taken focus (likely dashboard)
                        if (vrEvent.data.process.oldPid == 0)
                        {
                            SteamVR_Utils.Event.Send("input_focus", false);
                        }
                        break;
                    case EVREventType.VREvent_InputFocusReleased: // that app has released input focus
                        if (vrEvent.data.process.pid == 0)
                        {
                            SteamVR_Utils.Event.Send("input_focus", true);
                        }
                        break;
                    case EVREventType.VREvent_ShowRenderModels:
                        SteamVR_Utils.Event.Send("hide_render_models", false);
                        break;
                    case EVREventType.VREvent_HideRenderModels:
                        SteamVR_Utils.Event.Send("hide_render_models", true);
                        break;
                    default:
                        var name = System.Enum.GetName(typeof(EVREventType), vrEvent.eventType);
                        if (name != null)
                            SteamVR_Utils.Event.Send(name.Substring(8) /*strip VREvent_*/, vrEvent);
                        break;
                }
            }
        }

        // Ensure various settings to minimize latency.
        // 不限制最高帧率
        Application.targetFrameRate = -1;
        // 可以在后台运行,不需要强制窗口焦点。
        Application.runInBackground = true; // don't require companion window focus
        // 不限制驱动程序的最大队列值。这个只有DX有,OpenGL中被忽略。
        QualitySettings.maxQueuedFrames = -1;
        // 关闭垂直同步。
        QualitySettings.vSyncCount = 0; // this applies to the companion window

        // 是否锁定刷新速率与物理同步。
        if (lockPhysicsUpdateRateToRenderFrequency && Time.timeScale > 0.0f)
        {
            var vr = SteamVR.instance;
            if (vr != null)
            {
                var timing = new Compositor_FrameTiming();
                timing.m_nSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(Compositor_FrameTiming));
                vr.compositor.GetFrameTiming(ref timing, 0);
                // 设置新的物理更新间隔。
                Time.fixedDeltaTime = Time.timeScale / vr.hmd_DisplayFrequency;
            }
        }
    }


在代码中加了中文注释。
在编辑器模式下运行过程中,关闭与steamVR 相关脚本并不会影响头盔的旋转和位置。

我理解的的是,这是Unity在VR的底层代码进行的处理。或者在OnEnable或Awake中进行了绑定,所有以后是否运行脚本都没有关系了。

2. SteamVR_UpdatePoses姿态更新


单独说下这个更新,是由于若在Vive相机上直接对相机下的模型贴上UI会造成在编辑器下正常,在游戏中UI的煽动,也就是在移动过程中,并不是实时的更随物体移动,而是有类似于弹簧似的移动,就像是使用了DoTween。

解决方法就在这里。

//void OnPreCull() 
    //fixed change for ui follow controller at leaset one frame delay.@zpj
    void LateUpdate()


把原来的OnPreCull修改为LateUpdate,目前是解决了问题,暂时没有发现副作用。

若有问题,还请多多指教!!

这一篇,真是不容易,过山车一般。把思路和走过的错误道路记录下来,希望大家别在走弯路。


希望你能点赞支持,手留余香!!

六、参考

【1】 http://www.ceeger.com/Script/QualitySettings/QualitySettings.html

【2】 http://answers.unity3d.com/questions/1209337/vrvive-allow-rotation-only.html

【3】 http://blog.csdn.net/cartzhang/article/details/71136498

【4】 https://steamcommunity.com/app/358720/discussions/0/365163686052028359/

如何使用zbrush中的位移、旋转和缩放功能

...色的圈移动会作用给当前模型,如图所示。移动上下两个控制圈会产生另一种结果,如图所示。以图中行动线为例,在缩放模式下,作用顶部圆圈和中间圆圈的效果对比如图所示。在旋转工具下,作用底部和中间圆圈的效果对比... 查看详情

在 three.js 中移动相机、lookAt 和旋转

...ree.js【发布时间】:2012-12-2515:38:55【问题描述】:我无法理解lookAt和相机的旋转。我在x-y平面上的[0,0,0]周围有一圈小球。摄像头放置在[0,0,30]处,经过一看,摄像头的旋转是[0,0,0]。圆圈看起来好像从上方看(如预期的那样)。... 查看详情

unity获取相机高度

参考技术Aunity获取相机高度首先设置相机与物体之间的距离distance,相机与xz平面的角度为roll所以根据三角关系可以求得映射在xz平面的距离d为distancecos(rool),相机高度为distancesin(roll)。在xz平面中,设相机与物体的距离为d(就是... 查看详情

slam中的变换(旋转与位移)表示方法

...e‘坐标系下到e坐标系下的坐标变换。在SLAM中一般a‘为相机坐标系下坐标 查看详情

Unity C#:第三人称相机控制器:向相机方向旋转时捕捉

】UnityC#:第三人称相机控制器:向相机方向旋转时捕捉【英文标题】:UnityC#:ThirdPersonCameraController:Snapswhenrotatingtowardcameradirection【发布时间】:2021-05-2505:54:21【问题描述】:我正在尝试在Unity中重新创建“GTA风格”第三人称相机... 查看详情

怎样用鼠标控制摄像机的移动旋转

...,在里面设置相机跟随鼠标旋转、物体与相机同步旋转、更新相机位置。floaty=Input.GetAxis("MouseX");floatx=Input.GetAxis("MouseY");camAng.x-=x;camAng.y+=y;camTrans.eulerAngles=camAng;camTrans.position=newVector 查看详情

特定阈值后相机旋转抖动(视频)

...旋转被限制在Y轴上。只能左右旋转-75到75度,旋转由鼠标控制。玩家身体可以围绕它的Y轴旋转,并且它的Y旋转值被添加到-75和75度的相机夹子中,以保持玩家身体前方的相机旋转空间。示例:如果玩家在Y轴上旋转9 查看详情

对相机的理解及使用多相机绘制只旋转的坐标系

1. 对相机的理解1.1. 点是怎么转到屏幕上假设一个A点在世界坐标系内的坐标是A(x,y,z),视口矩阵,投影矩阵,模型视图矩阵为M,N,P,则 M*N*P *A=A1, A1就是点A在屏幕上的坐标。有此可见,在这个过程中只有三个矩阵M... 查看详情

htcvive的手柄怎么和unity

...igger。参考技术A你这个问题说的太含糊了,如果你是想问HTCvive手柄是怎么样更新的话,建议你用USB数据线吧把手柄和电脑主机连接起来,电脑会自动弹出更新提示信息的。本回答被提问者采纳 查看详情

在 FPS 场景中理解 gluLookAt xyz 旋转的问题

】在FPS场景中理解gluLookAtxyz旋转的问题【英文标题】:ProblemsunderstandinggluLookAtxyzrotationinFPSscenario【发布时间】:2014-04-3017:46:18【问题描述】:我在使用gluLookAt时遇到问题。我的相机可以通过管道在相对鼠标运动事件中沿X和Y轴旋... 查看详情

在opengl中翻译相机有问题

...opengl【发布时间】:2019-10-0706:08:39【问题描述】:我无法理解翻译相机。我已经可以成功旋转相机,但我仍然对平移相机感到困惑。我包含有关如何旋转相机的代码,因为平移和旋转需要使用lookat功能。作业说平移相机意味着眼... 查看详情

在 Forge 查看器中控制相机

】在Forge查看器中控制相机【英文标题】:ControllingcamerainForgeviewer【发布时间】:2017-07-1115:06:48【问题描述】:我正在尝试在AutodeskForgeViewer中控制相机。设置目标和位置似乎工作正常,但如果我尝试设置旋转或四元数它没有任何... 查看详情

css33d位移和旋转(代码片段)

    transform-style:preserve-3d  设定父元素为一个3d空间   小例子: <!DOCTYPEhtml><html> <head> <metacharset="utf-8"> <title></title> <styletype 查看详情

04canvas——位移画布和旋转缩放

4.1缩放scale()方法缩放当前绘图,更大或更小语法:context.scale(scalewidth,scaleheight)scalewidth:缩放当前绘图的宽度(1=100%,0.5=50%,2=200%,依次类推)scaleheight:缩放当前绘图的高度(1=100%,0.5=50%,2=200%,etc.)注意:缩放的是整个画布,缩放后,继续... 查看详情

androidcamera旋转角度(代码片段)

首先理解一下info.orientation官方解释官方定义:orientation表示相机图像的方向。它的值是相机图像顺时针旋转到设备自然方向一致时的角度。例如假设设备是竖屏的。后置相机传感器是横屏安装的。当你面向屏幕时,如果... 查看详情

鼠标在屏幕上的移动来控制相机水平,垂直旋转

usingUnityEngine;usingSystem.Collections;publicclassCameraController:MonoBehaviour{publicfloatdistance_v;publicfloatdistance_h;publicfloatrotation_H_speed=1;publicfloatrotation_V_speed=1;publicfloatma 查看详情

cesium设置和移动camera相机(工具篇)

...数计算,然后根据四元数求得旋转矩阵,再根据旋转矩阵更新direction,up,right方向相机向左看:.lookLeft(amount) amount弧度相机向右看:.lookRight(amount) amount弧度 查看详情

请教directx龙书中一个灵活的camera类应用于物体的前进旋转前进可以但是旋转只是绕固定轴旋转呢

...,运动方向,运动速度),然后在update(floatdt)这种类似的更新函数去改变这些属性,利用dx的api计算出世界转换矩阵;同时,相机这东西也要看情况,而如何更新则取决个人的期望了。 查看详情