Created
January 9, 2017 20:24
-
-
Save slembcke/b9edb74b854a0ee502a7b0b31bf9734b to your computer and use it in GitHub Desktop.
Custom projection support for Unity.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
[ExecuteInEditMode] | |
public class TreesCamera : MonoBehaviour { | |
private void OnEnable(){ | |
// Optional, only enable the callbacks when in the editor. | |
if(Application.isEditor){ | |
// These callbacks are invoked for all cameras including the scene view and camera previews. | |
Camera.onPreCull += ScenePreCull; | |
Camera.onPostRender += ScenePostRender; | |
} | |
} | |
private void OnDisable(){ | |
if(Application.isEditor){ | |
Camera.onPreCull -= ScenePreCull; | |
Camera.onPostRender -= ScenePostRender; | |
} | |
} | |
private void ScenePreCull(Camera cam){ | |
// If the camera is the scene view camera, call our OnPreCull() event method for it. | |
if(cam.cameraType == CameraType.SceneView) OnPreCull(); | |
} | |
private void ScenePostRender(Camera cam){ | |
// Unity's gizmos don't like it when you change the worldToCameraMatrix. | |
// The workaround is to reset it after rendering. | |
if(cam.cameraType == CameraType.SceneView) cam.ResetWorldToCameraMatrix(); | |
} | |
private Camera _cam; | |
private void Start(){ | |
_cam = GetComponent<Camera>(); | |
// Set the camera this script is attached to to use orthographic sorting order. | |
// Instead of using the euclidean distance from the camera, objects will be sorted based on their depth into the scene. | |
_cam.transparencySortMode = TransparencySortMode.Orthographic; | |
GetComponent<SFRenderer>().extents = Rect.MinMaxRect(-1, -2f, 1, 1); | |
} | |
// This is a Unity callback and is the ideal place to set the worldToCameraMatrix. | |
private void OnPreCull(){ | |
var cam = Camera.current; | |
// First calculate the regular worldToCameraMatrix. | |
// Start with transform.worldToLocalMatrix. | |
var m = cam.transform.worldToLocalMatrix; | |
// Then, since Unity uses OpenGL's view matrix conventions we have to flip the output z-value. | |
m.SetRow(2, -m.GetRow(2)); | |
// Now for the custom projection. | |
// Set the world's up vector to always align with the camera's up vector. | |
// Add a small amount of the original up vector to ensure the matrix will be invertible. | |
m.SetColumn(2, 1e-3f*m.GetColumn(2) - new Vector4(0, 1, 0, 0)); | |
cam.worldToCameraMatrix = m; | |
} | |
public static Matrix4x4 ScreenToWorldMatrix(Camera cam){ | |
// Make a matrix that converts from screen coordinates to clip coordinates. | |
var rect = cam.pixelRect; | |
var viewportMatrix = Matrix4x4.Ortho(rect.xMin, rect.xMax, rect.yMin, rect.yMax, -1, 1); | |
// The camera's view-projection matrix converts from world coordinates to clip coordinates. | |
var vpMatrix = cam.projectionMatrix*cam.worldToCameraMatrix; | |
// Setting column 2 (z-axis) to identity makes the matrix ignore the z-axis. | |
// Instead you get the value on the xy plane. | |
vpMatrix.SetColumn(2, new Vector4(0, 0, 1, 0)); | |
// Going from right to left: | |
// convert screen coords to clip coords, then clip coords to world coords. | |
return vpMatrix.inverse*viewportMatrix; | |
} | |
public Vector2 ScreenToWorldPoint(Vector2 point){ | |
return ScreenToWorldMatrix(_cam).MultiplyPoint(point); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment