toydev / HC_VRTrial

MIT License
33 stars 1 forks source link

Head orientation improvements #9

Closed astelemon closed 4 months ago

astelemon commented 5 months ago

This PR makes 2 changes that should improve comfort:

  1. Base head rotation setup is modified so that X and Z components are ignored. These are responsible for tilt. I believe that ignoring them is a good choice, as VR environments should always have a level floor. Y component is kept as the "heading direction".

  2. In Update(), reset the XZ components of the camera parent. This resets the default camera tilt used in many scenes. The motivation behind this change is the same as previous. Unfortunately, this is not perfect - if panning the camera quickly (in H scenes), there will be one-frame delay before the rotation is reset. I believe this is because the game modifies the camera position after the patch overrides it. The better way would be to change script execution order, or use Application.onBeforeRender, but I believe this currently can't be done with IL2CPP.

With these 2 changes, the floor of the game world always matches with reality, which makes it a lot less nauseating to play. I have tested it for some time and I believe it works well. Please consider looking through my PR.

Thank you for your hard work on this!

toydev commented 4 months ago

Thanks, I'll check this weekend.

toydev commented 4 months ago

I have reviewed two changes.

I noticed a difference in how it's used, which inspired the design. I use it while lying on my bed, facing upwards. On the other hand, I also understand that if you use it while sitting in a chair, it can cause discomfort and make you feel sick.

I plan to merge the pull request, introduce it as an optional feature, and ensure it can be customized via configuration options before releasing it.

toydev commented 4 months ago

Thank you for your contribution with this pull request.

Regarding the first change, it has already been incorporated into the project. We've implemented the viewport customization feature to accommodate different user play styles, allowing for a selection of styles through customization. This enhancement enables users to optimize their VR experience according to their own preferences and conditions, making the game more enjoyable for a wider audience.


Regarding the second change, it has been cancelled.The reason for this cancellation is due to the undesired behavior observed.

While we succeeded in locking the camera's horizontal orientation, the camera's positional movement remained. This movement resulted in a sense of discomfort, which was not intended. I understand the rationale behind fixing the camera's horizontal orientation, but I do not believe the resulting movement was as intended.

For example, in the experimental VR plugin I developed while learning, named KKS_VROON, there's a case where I restricted vertical mouse movement. This effectively suppressed both vertical movement and rotation. I can understand such an approach.

    public class ActionSceneMouseEmulator : BasicMouseEmulator
        public override float? GetAxis(string axisName)
            // ...
            // Stop vertical movement of vision when walking.
            else if (Manager.Scene.NowSceneNames?.First() == SceneNames.ACTION && axisName == "Mouse Y")
            {
                return null;
            }

Unfortunately, the above approach, which involves using Harmony to intercept Unity's UnityEngine.Input.GetAxis method, has been tested and found not to work in the IL2CPP environment. Although it may not be possible to intercept mouse operations, considerations can be made during the implementation of VR controller operations.

This might fall into the realm of practical applications, and it may not be covered in this repository. However, it could be a viable idea for a practical application you might develop. There could be even better ideas out there. I am rooting for you.


Additionally, I would like to leave two related points of discussion regarding this request.

The first is about my policy of avoiding unnecessary intervention in the game's main camera as much as possible. Your implementation directly interfered with the game's main camera, which could potentially affect the game itself, something we would like to avoid if possible. This plugin separates the VR camera from the game's main camera, so it is possible to address this by operating the VR camera instead.

Here is an example of the implementation:

    public class VRCamera : MonoBehaviour
    {
        public void Hijack(Camera targetCamera, bool useCopyFrom = true, bool synchronization = true)
        {
            Setup();

            if (targetCamera != null)
            {
                CameraHijacker.Hijack(targetCamera, Normal, useCopyFrom, synchronization);

                // Set origin to the inverse position of the orientation pose from the target camera.
                // The origin of the VR camera is the center of the play area (Usually at the player's feet).
                VR.origin.rotation = GetParentRotation(targetCamera.transform.rotation) * Quaternion.Inverse(OrientationRotation);
                VR.origin.position = targetCamera.transform.position - VR.origin.rotation * OrientationPosition;
                VR.origin.SetParent(targetCamera.transform);
            }

            Normal.depth = Depth;
        }

        private static Quaternion GetParentRotation(Quaternion parentRotation)
        {
            // Remove X and Z components from the game main camera
            var parentRotationEulerAngles = parentRotation.eulerAngles;
            return Quaternion.Euler(parentRotationEulerAngles.x, 0, 0)
        }

While the above retains the original form of linking with the game's main camera, you are free to implement it more freely if you have a better idea for controlling the VR camera.

The second point is that while Application.onBeforeRender is not usable, alternatives can be found upon investigation. For example, in adapting SteamVR for IL2CPP, I replaced Application.onBeforeRender with RenderPipelineManager.beginContextRendering. Mod creation comes with its set of challenges, but alternative ideas can emerge with some thought. Please don't give up.