0
\$\begingroup\$

I am attempting to add VR compatibility to my game, please could you help me figure out how to better control the multiple cameras in my scene regarding the head tracking and movement from VR devices?

I’m using Unity v2019.4, and not using the new VR Plugin system. In my XR Settings I have Virtual Reality Supported ticked and have the Oculus and OpenVR virtual reality SDKs.

I have three cameras in my scene, at the following Depth levels:

2 = Main Camera (Depth only) which shows everything except my sun and skybox

1 = A Sun Camera (Depth only) showing only my sun layer

0 = A Background Camera (SkyBox) showing my custom skybox

The reason I render the sun on a separate camera is to give the effect of a very distant object. The sun camera is sat close to the sun, but when I move in the scene the sun never gets any closer giving the illusion of it being far out there in space. This works great in non-VR, but in VR if I move my head forward or to the side, the sun camera also moves and so breaks the illusion of the distant sun.

I have tried playing around with settings and done a lot of searching, but I cannot figure out how to stop the "local" movement in my sun camera. Any ideas?

\$\endgroup\$
7
  • \$\begingroup\$ Have you considered solving the distant sun problem in the vertex shader instead? You can render it with the same camera, but modify the vertex transformation to ignore/replace the camera's translation, treating the camera as though it were static, even though it's still the same moving camera that renders the rest of your scene. \$\endgroup\$
    – DMGregory
    Commented Oct 9, 2020 at 14:51
  • \$\begingroup\$ Sounds interesting. I don't have much experience with shaders beyond utilising the Unity Standard Shader, so its no small task to try do what your suggesting. I guess I could visit this as an option if I can't get it working with the standard camera approach. Cheers \$\endgroup\$
    – GenericJoe
    Commented Oct 9, 2020 at 16:47
  • \$\begingroup\$ Want to edit your question to "How to make my sun appear far away in VR"? That way answers that show you how to either 1) separate your camera or 2) neutralize camera movement in the vertex shader would both be admissible. Right now I can't post an answer about the vertex trick because it doesn't answer the question "Control which camera..." \$\endgroup\$
    – DMGregory
    Commented Oct 9, 2020 at 17:08
  • \$\begingroup\$ Ok fair enough, I have done as you suggested, thanks for the input so far. By the way, the sun I am using is not just a geometric sphere, it is complex with animated textures and separate shader effects. Just in case that has any bearing on what you are suggesting with using another vertex shader, which currently I don't understand enough about to see how this will work. \$\endgroup\$
    – GenericJoe
    Commented Oct 10, 2020 at 11:50
  • \$\begingroup\$ Can you show us a sample of that effect or the shader code it's using? That can help us suggest answers that work with that. \$\endgroup\$
    – DMGregory
    Commented Oct 10, 2020 at 11:51

1 Answer 1

0
\$\begingroup\$

If you can modify the shaders used by your sun, you can neutralize the parallax of your camera in the vertex shader.

Here's the default vertex shader you get from Unity when making a new unlit effect (I presume the sun is unlit since it's a source of light, not something that reflects light significantly):

v2f vert (appdata v)
{
    v2f o;

    // This line combines the object's transform, the camera's viewpoint,
    // and the perspective projection into one step.
    o.vertex = UnityObjectToClipPos(v.vertex);
    // That's the only part we're going to change.

    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}

We can change that to this:

v2f vert (appdata v)
{
    v2f o;

    // First, apply the object's transformation in the world.
    float4 pos = mul(unity_ObjectToWorld, v.vertex);

    // Zero out the w component, so we're not affected by the camera position
    // in the next step - we behave as though the camera is always at (0, 0, 0).
    pos.w = 0;
    // Then apply the camera's rotation.
    pos = mul(UNITY_MATRIX_V, pos);

    // Restore the w component so we project correctly...
    pos.w = 1;
    // ...and apply the perspective projection.
    o.vertex = mul(UNITY_MATRIX_P, pos);
    
    // The rest of the shader can remain unchanged.
    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    UNITY_TRANSFER_FOG(o,o.vertex);
    return o;
}
\$\endgroup\$
8
  • \$\begingroup\$ Wow! Thank you DMGregory, I nearly have it I think, here's what it looks like now: manualintervention.com/Sun.PNG The body of the sun does not move, but is in the correct place! So if I can somehow apply the same to the Sun's particel systems, it might just work. By the way, the original shader code was slightly different: ` //o.normal = v.normal; //o.pos = UnityObjectToClipPos (v.vertex); //o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);` \$\endgroup\$
    – GenericJoe
    Commented Oct 15, 2020 at 16:00
  • \$\begingroup\$ Sounds like you need to apply this change to your particle shader too then. \$\endgroup\$
    – DMGregory
    Commented Oct 15, 2020 at 16:01
  • \$\begingroup\$ This works! I'm in shock - I've been fiddling with this for weeks! Thank you @DMGregory \$\endgroup\$
    – GenericJoe
    Commented Oct 15, 2020 at 18:23
  • \$\begingroup\$ Just a note for future readers. This trick works well, but does mean you will have issues with camera frustrum culling - not an easy one to solve in Unity, especially if there are particle systems involved. \$\endgroup\$
    – GenericJoe
    Commented Oct 20, 2020 at 19:13
  • \$\begingroup\$ We usually solve that by overriding the bounds on the renderer to always overlap the frustum. \$\endgroup\$
    – DMGregory
    Commented Oct 20, 2020 at 19:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .