Simple Deferred Lighting Fix
Now that I have my dev kit, I was able to do some real testing on the deferred lighting issue. As I mentioned in other threads, the problem is that constructing your own perspective matrix can prevent Unity from doing transforms back from screen space to world space. The reason this is an issue here is that the Oculus SDK uses Direct3D clip space conventions in its matrix construction, while Unity expects OpenGL conventions.
The fix is easy, just use Unity's built in perspective matrix. Find this method at the bottom of OVRCamera.cs:
And replace it with this:
I have confirmed through testing (switching between those two functions quickly) that the projection is exactly the same visually. The absolute difference between the values in the matrices is also infinitesimal, except for the term where Direct3D and OpenGL differ:
The only thing this term affects is the Z position of vertices in clip space, so it has zero effect on the pixel position of a vertex, and therefore only influences the near and far clip plane distances.
Deferred lighting is also fixed if you simply change that line like so to match the OpenGL standard:
But its still better to use Unity's projection, because there is the possibility that it might change on other platforms, and Unity may expect it to be a certain way. Other subtle bugs may be present in the current implementation, at least the near plane probably does not accurately reflect what you set in Unity.
The fix is easy, just use Unity's built in perspective matrix. Find this method at the bottom of OVRCamera.cs:
public void SetPerspectiveOffset(ref Vector3 offset)
{
// NOTE: Unity skyboxes do not currently use the projection matrix, so
// if one wants to use a skybox with the Rift it must be implemented
// manually
gameObject.camera.ResetProjectionMatrix();
Matrix4x4 m = Matrix4x4.identity;// = gameObject.camera.projectionMatrix;
CreatePerspectiveMatrix(ref m);
Matrix4x4 tm = Matrix4x4.identity;
tm.SetColumn (3, new Vector4 (offset.x, offset.y, 0.0f, 1));
gameObject.camera.projectionMatrix = tm * m;
}
And replace it with this:
public void SetPerspectiveOffset(ref Vector3 offset)
{
// NOTE: Unity skyboxes do not currently use the projection matrix, so
// if one wants to use a skybox with the Rift it must be implemented
// manually
gameObject.camera.ResetProjectionMatrix();
Matrix4x4 tm = Matrix4x4.identity;
tm.SetColumn (3, new Vector4 (offset.x, offset.y, 0.0f, 1));
gameObject.camera.projectionMatrix = tm * gameObject.camera.projectionMatrix;
}
I have confirmed through testing (switching between those two functions quickly) that the projection is exactly the same visually. The absolute difference between the values in the matrices is also infinitesimal, except for the term where Direct3D and OpenGL differ:
m.m23 = (farClip * nearClip) / (nearClip - farClip);
The only thing this term affects is the Z position of vertices in clip space, so it has zero effect on the pixel position of a vertex, and therefore only influences the near and far clip plane distances.
Deferred lighting is also fixed if you simply change that line like so to match the OpenGL standard:
m.m23 = 2*(farClip * nearClip) / (nearClip - farClip);
But its still better to use Unity's projection, because there is the possibility that it might change on other platforms, and Unity may expect it to be a certain way. Other subtle bugs may be present in the current implementation, at least the near plane probably does not accurately reflect what you set in Unity.
