-->

分類

2017年1月23日 星期一

fixed Unity standard asset water reflection in VR environmemt(SteamVR only)

[DOWNLOAD the unity package] (note: need to import Unity SteamVR plugin first, tested with SteamVR plugin 1.1.1 and SteamVR plugin 1.2. Unity may show compilation error if the SteamVR plugin is not compatible with the script for the water, you can fix the script by following the instructions at the line where compilation error occurs)
The water module  from Unity standard asset has problem with reflection under VR environment.
This link has the solution to reflection under VR environment in Unity.
https://forum.unity3d.com/threads/5-4-beta15-reflection-rendering-wrong-in-openvr-htc-vive.398756/

Simply apply this solution to the water module's source code then the problem is solved.

02/10/2017 update(package is also updated for the download link):
Fixed the missing prefab problem from previous unity package. Added instructions to fix SteamVR plugin incompatible problem.

02/03/2017 update(package is also updated for the download link):
some modifications for single pass stereo rendering, removed the discontinuous texture sampling artifacts when single pass stereo rendering turned on.

Some notes:
The reflection use a camera for reflection. The reflection camera is at the reflection pose of the main camera by the reflection surface.

The reflection camera makes a render texture for the reflection surface plane.

The reflection camera modified it's projection matrix so that its clip plane will be the reflection plane(so that object between reflection camera and the reflection surface will not be rendered). It transforms it's view frustum to be oblique view frustum.
Oblique view frustum derivation
view frustum culling(the relationship between view frustum plane and projection matrix)
reflection matrix
oblique view frustum transform implemented by C#

The reflection camera has different pose for left eye and right eye in VR enivronment:
Vector3 eyePos = cam.transform.TransformPoint(SteamVR.instance.eyes[0].pos);
Quaternion eyeRot = cam.transform.rotation * SteamVR.instance.eyes[0].rot;
Matrix4x4 projectionMatrix = GetSteamVRProjectionMatrix(cam, Valve.VR.EVREye.Eye_Left);

 Vector3 eyePos = cam.transform.TransformPoint(SteamVR.instance.eyes[1].pos);
 Quaternion eyeRot = cam.transform.rotation * SteamVR.instance.eyes[1].rot;
 Matrix4x4 projectionMatrix = GetSteamVRProjectionMatrix(cam, Valve.VR.EVREye.Eye_Right);

The reflection camera has different render textures for left and right eye:
render the render texture for left and right eye on the same texture by specifying the range where the texture of each eye should be drawn:
    private static readonly Rect LeftEyeRect = new Rect(0.0f, 0.0f, 0.5f, 1.0f);
    private static readonly Rect RightEyeRect = new Rect(0.5f, 0.0f, 0.5f, 1.0f);
    ...
    m_ReflectionCamera.rect = camViewport;//camViewport is LeftEyeRect or RightEyeRect
So the reflection render texture's left half part is for left eye, right half part is for right eye.
And when sampling the reflection render texture, the uv coordinates need to be modified according to which eye is being used:
vert shader
o.screenPos = ComputeScreenPos(o.pos);
frag shader
half4 screenWithOffset = i.screenPos;
#ifndef UNITY_SINGLE_PASS_STEREO
if (unity_CameraProjection[0][2] < 0)
{
screenWithOffset.x = (screenWithOffset.x * 0.5f);//make x as 0 ~ 0.5
}
else if (unity_CameraProjection[0][2] > 0)
{
screenWithOffset.x = (screenWithOffset.x * 0.5f) + (screenWithOffset.w * 0.5f);//0.5~1
}
#endif

for Single Pass Stereo Rendering case, the "screenWithOffset" will be handled automatically since single pass stereo rendering treats the texture as a combined texture for left and right eye. It will use left half texture for left eye, right half texture for right eye, we don't need to modify the screenWithOffset.x as the case of non single pass stereo rendering