AdamsLair / duality

a 2D Game Development Framework
https://adamslair.github.io/duality
MIT License
1.4k stars 289 forks source link

WIP: Add camera tilt support #750

Closed greyepoxy closed 4 years ago

greyepoxy commented 4 years ago

This is a work in progress

This is an initial PR for https://github.com/AdamsLair/duality/issues/747

The core of the functionality works for anyone that wants to play around with it. Add some things to the scene and change the camera transform angle and camera tilt values to see the world rotate around you.

TODOs:

  1. Source/Core/Duality/Utility/Log/VisualLogEntries/VisualLogTextEntry.cs does something with the transform Angle when drawing. Not familiar with this feature so will have to investigate if this is now broken and how to fix it if it is.
  2. Source/Plugins/Tilemaps/Core/Tilemaps/TilemapCulling.cs GetVisibleTileRect is probably broken with this change, need to investigate a fix.
  3. Write some samples that show a couple ways of doing orthographic/isometric rendering that take advantage of being able to set the camera tilt. a) A basic sample that renders the terrain as is and then uses "billboard rendering" to draw things that stand vertically in the scene. b) A sample using sprite stacking (stacking the sprites over the z axis). b) A sample using basic 3d models (a collection of rotated sprites) to create terrain. c) A Camera shake demo?

Things to discuss:

  1. I changed DrawDevice.ViewerAngle into DrawDevice.ViewerOrientation, should I leave ViewerAngle alone to make sure this is not a breaking change?
  2. Setting the Camera.Tilt in the editor over or under 360 does not wrap in the same way that the Transform.Angle does. Seems like there is some special editor logic in https://github.com/AdamsLair/duality/blob/master/Source/Plugins/EditorBase/PropertyEditors/Components/TransformPropertyEditor.cs#L220 that does that. Do we want that for this Tilt value as well?
  3. Currently storing the three camera tilt/orientation values as Euler angles and then applying them to the view matrix in a very specific order, rotation around Z axis first, then around Y, then X. Probably would be better to store the rotation as quaternions as that should reduce the cost of producing the rotation matrix. Not really sure if this is necessary at the moment since we do not expect a lot of camera rotations occurring during runtime, and if I remember my math correctly, the main advantage of quaternions is the speed/stability of combining rotations together. Is that something we want extended support for? What do people think? Should we convert to using quaternions internally?
  4. Related to the item above (as in we will probably want to do that if we want to do this item), there is a bunch of helper methods in the Transform object for performing angle changes, do we want to offer some similar methods for Camera tilt? If Camera shake is something we want first class support for, then this is probably a good idea.
  5. Additional test ideas?
ilexp commented 4 years ago

I changed DrawDevice.ViewerAngle into DrawDevice.ViewerOrientation, should I leave ViewerAngle alone to make sure this is not a breaking change?

We can't really make breaking changes unless we're doing a major version step, so the best we could do is add a new property in addition to ViewerAngle, like ViewerTilt. It's still breaking to add new interface members, but it's probably safe to say that the Duality core itself is currently the only implementer of that interface, we should be good.

Setting the Camera.Tilt in the editor over or under 360 does not wrap in the same way that the Transform.Angle does. Seems like there is some special editor logic in https://github.com/AdamsLair/duality/blob/master/Source/Plugins/EditorBase/PropertyEditors/Components/TransformPropertyEditor.cs#L220 that does that. Do we want that for this Tilt value as well?

Since we're dealing with the special case of a tilt away from a nominal angle, I'd suggest using a range of [-90, 90] and clamping the UI value to that range using a EditorHintRange attribute on the property. By limiting to 90° away, and not 180°, we're also confining the camera to one side of the focus plane, avoiding situations where it would look at the back sides of everything.

Currently storing the three camera tilt/orientation values as Euler angles and then applying them to the view matrix in a very specific order, rotation around Z axis first, then around Y, then X. Probably would be better to store the rotation as quaternions as that should reduce the cost of producing the rotation matrix.

I think euler angles are completely fine - we're not doing that much heavy math here, performance impact should be negligible and eulers are easier to deal with here. Adding to this, we only need a Vector2 here, since the Z axis is already defined by this.Transform.Angle.

Related to the item above (as in we will probably want to do that if we want to do this item), there is a bunch of helper methods in the Transform object for performing angle changes, do we want to offer some similar methods for Camera tilt? If Camera shake is something we want first class support for, then this is probably a good idea.

Which methods do you have in mind?

greyepoxy commented 4 years ago

Okay great! Thank you for your thoughts and feedback, I updated the change to keep tilt separate from angle in both the camera and drawDevice public interfaces. So only adding to the interface now.

I have mixed feelings on limiting the rotation to [-90, 90] while I believe you are completely correct that it would cover the scenarios I had in mind. I think there are a couple cases you would want to go outside of this. For example if you wanted to flip the world on its head, an easy way to do that would be to flip the camera 180 degrees along its viewing plane. If we limit to [-90, 90] then that would not be possible. Not sure if this is compelling enough to allow it though.

Here were the additional functions that I was considering for the Camera object,

  1. RotateBy(Plane alongPlane, float angle)
  2. RotateToFace(Vector3 lookAtPoint, Vector3 cameraUp)
  3. RotateRight(float angle)
  4. RotateLeft(float angle)
  5. RotateUp(float angle)
  6. RotateDown(float angle)
  7. RollLeft(float angle)
  8. RollRight(float angle) Where Plane is defined by two unit vectors. Not sure how they would work with the clamping as well, assuming we would just clamp the x or y axis rotations to [-90, 90] after they are updated.

This might look to much like 3d, so would be happy to start with something simpler if desired

ilexp commented 4 years ago

Sorry for not responding earlier - for time reasons, I wasn't able to continue looking into this as needed.

@Barsonax @SirePi Can you guys pick up this PR? Feel free to ping me if needed down the line.

SirePi commented 4 years ago

Just my personal preference maybe, but I think that instead of having 6 methods

  • RotateRight(float angle)
  • RotateLeft(float angle)
  • RotateUp(float angle)
  • RotateDown(float angle)
  • RollLeft(float angle)
  • RollRight(float angle)

with kind of "unreferenced" names like left/right/up/down, and with the potential headache of having to consider that RotateRight(-5) is equal to RotateLeft(5), maybe it would be better and easier (to understand and maintain) to have

Barsonax commented 4 years ago

@greyepoxy There have been quite a bit of changes in master recently. Can you rebase your branch on master so its up to date again? The changes are mostly in the csproj files so theres a good chance you won't have conflicts.

greyepoxy commented 4 years ago

Hey all thanks for your replies, unfortunately due to some changes in my available time and priorities I won't be able to continue working on this. Feel free to build off of my work if you would like but I totally understand if its not a priority for Duality at the moment.

Again I really appreciate everyone's time and what you all are building here

Barsonax commented 4 years ago

Ok thanks for letting us know and thanks for the effort you put in.

I pulled your branch into this repo and we will handle things further from now once we find some time.