Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to calculate / set an oblique projection matrix for a 45 degree camera

Discussion in 'Cinemachine' started by ShervinM, Jan 28, 2020.

  1. ShervinM

    ShervinM

    Joined:
    Sep 16, 2017
    Posts:
    67
    Some Context:

    In my game I have the floor flat on the X/Z plane with walls/characters rotated +45 degrees about the X axis. The orthographic camera is pointing down also at 45 degrees about the x axis, parallel with my walls/characters:


    As a result, I dont see any distortion for players/characters since they face the camera directly on, while the ground however sees a distortion of sqrt(2) shorter. This makes sense considering how an orthographic camera works.

    My initial approach to fix this was to set up my Tilemap with a scaling of X: 1 Y: 1 Z: Sqrt(2) so that each tile is stretched on the Z axis by Sqrt(2) to compensate for this distortion.

    However, my one problem now is that I experience foreshortening with regards to movement: Forward and backwards movements of objects/characters along the z axis are perceived to be slower than movements left/right on the x axis in the game view. This makes sense because while each tile is perceived to be a square in the camera view thanks to scaling Z on the tilemap by sqrt(2), the real world tile is, well, sqrt(2) times longer along the z than its x/width, so obviously it takes longer to travel forwards / backwards than it does left/right.

    Honestly, I would also love to hear from others on how they have approached this issue (especially with a game like Enter the Gungeon), but from what I have learned in the past few weeks is that there are three approaches:
    1. Move everything locally / using local transformations (underneath a root scene object that is made sqrt(2) times longer, which in this case would be my tilemap).
    2. Adjust all movements of objects in the z-axis to be faster by a factor of sqrt(2).
    3. Use an oblique projection: https://gamedev.stackexchange.com/q...backward-movement-in-an-oblique-top-down-view

    I'm very hesitant regarding Approaches (1) and (2) as not only do I use rigidbody forces everywhere, but I'd also be concerned about fixing all my other systems (for instance usages of overlap spheres) to make sure they see an appropriate scaling as well.

    So now I'm left with option (3), which is the least I know anything about (specifically regarding projection matrices and oblique projections).

    My Question(s):

    - Is there a way to set oblique projections in Cinemachine?
    - How do I calculate the appropriate matrix given the environments I have set up? I.e. a camera pointing 45 degrees downwards at the floor.

    My attempts so far have been to use this package here:
    https://github.com/keijiro/unity-oblique-projection
    The package/component has three params to play with. Setting the Angle parameter to 0 (seems to rotate camera around the y axis, which I dont need), eyeballing the Z-Scale parameter, and arbitrarily moving the Z-Offset parameter so that the camera is centered where it was before, I can see the results I want: neither walls/character nor the floor see ANY distortion, and I dont have to scale anything at all.

    BUT, I want to figure out how to set the Z Scale and Z Offset precisely (based on calculations), and not just eyeballing it. Given an orthographic size and camera angle, how do I calculate what these parameters should be?

    Any help is greatly appreciated :) Thank you if you read the whole post!
     
  2. Gregoryl

    Gregoryl

    Unity Technologies

    Joined:
    Dec 22, 2016
    Posts:
    7,658
    I like your solution #3 too.
    unity-oblique-projection seems to be the way to go. Cinemachine is quite happy to live alongside it.
    Looks like Z offset has to exactly match the Framing Transposer's camera distance field.
    Ortho size seems to not affect the settings.
    The Z Scale is related to the X angle of the camera. Not sure of the exact mathematical relationship - you'll have to drill into ObliqueProjection.Apply() to figure it out.
     
  3. ShervinM

    ShervinM

    Joined:
    Sep 16, 2017
    Posts:
    67

    As always, thanks @Gregoryl for your prompt response. I spent some more time playing around with the component, and thinking a bit more about what's happening.

    Indeed, I think you're right about the Z offset matching the Framing Transposer's camera distance field. I'm still trying to calculate indeed why these two match, but visually I'm happy with lining up these values.

    For anyone else following, I'm happy to note that I did figure out some relationship of the Z Scale. I'm still very noobie at matrices, but I just tried to think about it more logically:

    Were I to be using a normal orthographic camera, as I've stated before (my previous solution), I would need to scale the floor by sqrt(2) so that the orthographic camera sees each tile as 1 by 1. Now that I'm not distorting the tiles (keeping them at 1 by 1) but rather instead skewing my projection matrix, I know that I need to distort the matrix in such a way so as to get the z axis to scale from 1 to sqrt(2).

    Now previously I was putting in sqrt(2) for the Z Scale, but it seems like what I really need to do is put in (sqrt(2) - 1), which is the difference between the distorted tile and the normal tile.

    Why exactly it makes sense to use this difference (sqrt(2) - 1) instead of the factor (sqrt(2)), I'm still not entirely sure, but I suppose I would need to fully understand the reasoning behind how the matrix is altered in the ObliqueProjection.Apply() method (as you mentioned) to get it.
     
    Last edited: Feb 21, 2020