0
\$\begingroup\$

I've found this article on Gamasutra on a custom camera projection to make 3D look more 2D and decided to implement it to make some gameplay tests.

I had to make some changes to make it work on URP(on unity 2019.3.6f1) but it "worked" with the following code:

using UnityEngine;
using System.Collections;
using UnityEngine.Rendering;
 
// This script is meant to be attached to your main camera.
// If you want to use it on more than one camera at a time, it will require
// modifcations due to the Camera.on* delegates in OnEnable()/OnDisable().
 
[ExecuteInEditMode]
public class CustomProjectionTest : MonoBehaviour {
    private void OnEnable(){
        RenderPipelineManager.beginFrameRendering += ScenePreCull;
        RenderPipelineManager.endFrameRendering += ScenePostRender;
        //Camera.onPreCull += ScenePreCull;
    }
 
    private void OnDisable(){
        RenderPipelineManager.beginFrameRendering -= ScenePreCull;
        RenderPipelineManager.endFrameRendering -= ScenePostRender;
 
        GetComponent<Camera>().ResetWorldToCameraMatrix();
    }
 
    private void ScenePreCull(ScriptableRenderContext context, Camera[] cam){
        // If the camera is the scene view camera, call our OnPreCull() event method for it.
        OnPreCull();
    }
 
    private void ScenePostRender(ScriptableRenderContext context, Camera[] cam){
        // Unity's gizmos don't like it when you change the worldToCameraMatrix.
        // The workaround is to reset it after rendering.
        
        foreach(var camm in cam)
            camm.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;
    }
 
    public Vector4 up = new Vector4(0, 1, 0, 0);
 
    // This is a Unity callback and is the ideal place to set the worldToCameraMatrix.
    private void OnPreCull(){
        var cam = !Application.isPlaying? Camera.current : _cam;
 
        // 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) - up);
 
        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);
    }
 
    private void Update(){
        if(Input.GetMouseButtonUp(0)){
            Debug.Log(ScreenToWorldPoint(Input.mousePosition));
        }
    }
}

Well, kinda. For some reason, it only works in the scene editor, but not in the game. I just have no clue why

With Scene Editor:

With Scene Editor

In Game

In Game

\$\endgroup\$
3
  • \$\begingroup\$ What happens when you move the camera around? Have you tried it at different angles? What is the blue block on the left half of the image? \$\endgroup\$ Commented Aug 22, 2020 at 0:51
  • \$\begingroup\$ It stays pretty much the same. The problem seems like in the game editor everything gets squished to the horizon line as hard as it can. Also, this problem seem to happen only on this version of unity, 2019.6.f1. Tried it on 2018.4 and 2020.1 and it worked fine(altough those were empty projects and the bugged one was not). \$\endgroup\$ Commented Aug 22, 2020 at 1:54
  • \$\begingroup\$ Why are you using 2019.3.6f1? The latest version is 2019.4.8f1 \$\endgroup\$ Commented Aug 22, 2020 at 18:25

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.