Some camera tricks with the camera projectionMatrix in Unity
This file contains 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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class OnePointPerspective : MonoBehaviour { | |
[SerializeField] | |
private Camera camcam; | |
//Where you want the vanishing point to be instead of the centre. | |
[SerializeField] | |
private Vector2 offsetVanishingPoint = Vector2.zero; | |
/// <summary> | |
/// Centre the camera should rotate z axis around, in case it shouldn't really be the centre | |
/// </summary> | |
[SerializeField] | |
private Vector2 rotationCentre = Vector2.zero; | |
//presumed distance of camera from subject, used to compensate | |
[SerializeField] | |
private float presumedDistance = 10f; | |
//scales the z to compensate for things looking too tall / long | |
[SerializeField] | |
private float zscale = 1f; | |
void Update () { | |
SetCameraMatrix(); | |
} | |
public void SetCameraMatrix () | |
{ | |
if (camcam != null) | |
{ | |
camcam.ResetProjectionMatrix(); | |
var fov = camcam.fieldOfView; //fov seems to be calculated based on vertical | |
var aspect = camcam.aspect; //post offset needs to account for aspect ratio | |
var combinedOffset = offsetVanishingPoint - rotationCentre; //combine offset and rotationCentre | |
//convert fov angle into slope and multiply by presumedDistance to get a compensating offset | |
var slope = Mathf.Tan(Mathf.Deg2Rad * fov / 2f); | |
var preOffset = new Vector2(combinedOffset.x * aspect, combinedOffset.y) * -slope * presumedDistance; | |
var projectionMatrixBefore = camcam.projectionMatrix; //get starting point from camera | |
//scales Z relative to the presumed distance and offsets X & Y according to preOffset | |
var preTransform = Matrix4x4.Translate(Vector3.forward * -presumedDistance) * Matrix4x4.Scale(new Vector3(1, 1, zscale)) * Matrix4x4.Translate(new Vector3(preOffset.x, preOffset.y, presumedDistance)); | |
//shifts vanishing point | |
var postTransform = Matrix4x4.Translate(offsetVanishingPoint); | |
//applies everything to get the new projectionMatrix | |
var projectionMatrixAfter = postTransform * projectionMatrixBefore * preTransform; | |
camcam.projectionMatrix = projectionMatrixAfter; | |
} | |
} | |
} |
This file contains 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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class ProjectionMatrixExperiments : MonoBehaviour { | |
[SerializeField] | |
private Camera camcam; | |
[SerializeField] | |
private Matrix4x4 projectionMatrixBefore; | |
[SerializeField] | |
private Matrix4x4 transformMatrix; | |
[SerializeField] | |
private Matrix4x4 projectionMatrixAfter; | |
[SerializeField] | |
private Vector3 rotate = Vector3.zero; | |
[SerializeField] | |
private Vector3 pos = Vector3.zero; | |
[SerializeField] | |
private Vector3 scale = Vector3.one; | |
public enum TransformationMethod | |
{ | |
TRSTimesOriginal, OriginalTimesTRS, Replace | |
} | |
[SerializeField] | |
TransformationMethod transformationMethod; | |
void Update () { | |
if (camcam!=null) | |
{ | |
camcam.ResetProjectionMatrix(); | |
projectionMatrixBefore = camcam.projectionMatrix; | |
transformMatrix = Matrix4x4.TRS(pos, Quaternion.Euler(rotate), scale); | |
switch (transformationMethod) | |
{ | |
case TransformationMethod.OriginalTimesTRS: | |
projectionMatrixAfter = projectionMatrixBefore * transformMatrix; | |
break; | |
case TransformationMethod.TRSTimesOriginal: | |
projectionMatrixAfter = transformMatrix * projectionMatrixBefore; | |
break; | |
case TransformationMethod.Replace: | |
projectionMatrixAfter = transformMatrix; | |
break; | |
} | |
camcam.projectionMatrix = projectionMatrixAfter; | |
} | |
} | |
} |
This file contains 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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class ProjectionReplace : MonoBehaviour { | |
[SerializeField] | |
private Camera camcam; | |
[SerializeField] | |
private Matrix4x4 newProjectionMatrix; | |
[SerializeField] | |
private bool resetCamera = false; | |
[SerializeField] | |
private Vector3 rotate = Vector3.zero; | |
[SerializeField] | |
private Vector3 pos = Vector3.zero; | |
[SerializeField] | |
private Vector3 scale = Vector3.one; | |
[SerializeField] | |
private bool applyTRS = false; | |
void Update () { | |
if (camcam!=null) | |
{ | |
if (resetCamera) | |
{ | |
camcam.ResetProjectionMatrix(); | |
newProjectionMatrix = camcam.projectionMatrix; | |
resetCamera = false; | |
} | |
else | |
{ | |
if (applyTRS) | |
{ | |
Matrix4x4 transformMatrix = Matrix4x4.TRS(pos, Quaternion.Euler(rotate), scale); | |
newProjectionMatrix = transformMatrix * newProjectionMatrix; | |
applyTRS = false; | |
} | |
camcam.projectionMatrix = newProjectionMatrix; | |
} | |
} | |
} | |
} |
This file contains 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 System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
[ExecuteInEditMode] | |
public class ZoomInOffset : MonoBehaviour { | |
[SerializeField] | |
private Camera camcam; | |
//Where you want to zoom towards | |
[SerializeField] | |
private Vector2 zoomCentre = Vector2.zero; | |
//Number of times to magnify the view | |
[SerializeField] | |
private float zoomTotal = 1f; | |
//Lerp from unzoomed to zoomed | |
[SerializeField] | |
[Range (0f, 1f)] | |
private float zoomLerp = 0f; | |
void Update () { | |
if (camcam!=null) | |
{ | |
camcam.ResetProjectionMatrix(); | |
var projectionMatrixBefore = camcam.projectionMatrix; //get starting point from camera | |
//shifts vanishing point and scales | |
var translation = Matrix4x4.Translate(Vector2.Lerp(Vector2.zero, zoomCentre, zoomLerp)); | |
var zoomAmount = 1 / Mathf.Lerp(1, 1 / zoomTotal, zoomLerp); //use inverse to make it lerp correctly to match the linear translation | |
var scale = Matrix4x4.Scale(new Vector3(zoomAmount, zoomAmount, 1)); | |
//applies everything to get the new projectionMatrix | |
var projectionMatrixAfter = scale * translation * projectionMatrixBefore; | |
camcam.projectionMatrix = projectionMatrixAfter; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment