storm-devs / storm-engine

Game engine behind Sea Dogs, Pirates of the Caribbean and Age of Pirates games.
https://storm-devs.github.io/storm-engine
GNU General Public License v3.0
845 stars 120 forks source link

Fixed perspective on ultrawide screens #492

Closed Reksotiv closed 1 year ago

Reksotiv commented 1 year ago

In the SetPerspective function, the variable perspective is the horizontal fov, which is set to the same value for all diagonals, and as the screen width increases, the image gets closer. For example, the horizontal fov is 90 and with an aspect ratio of 16:9 vertical fov = 59, and with an aspect ratio of 21:9 vertical fov = 47. https://themetalmuncher.github.io/fov-calc/ The perspective can be increased using the fov_multiplier variable in the engine.ini file, but after that the image looks distorted. Look at the screenshot with the barrel, without changes it is not round but oval. Instead of manually calculating perspective projection matrix, i used this function https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovlh

Without fix fov_multiplier = 1.0 default-1 0 With fix fov_multiplier = 1.0 moded-1 0

Without fix fov_multiplier = 1.5 default2-1 5 With fix fov_multiplier = 1.5 moded2-1 5

Without fix fov_multiplier = 1.5 default-1 5-circle With fix fov_multiplier = 1.5 moded-1 5-circle

Hammie commented 1 year ago

I think I understand the issue, and const float fov_vert = 2.0f * atanf(tanf(perspective * 0.5f * FovMultiplier) / fAspectRatio); is the actual part of the fix we need.

Let me double check the math.

Reksotiv commented 1 year ago

You are right, only fov_vert 2

Reksotiv commented 1 year ago

No, changing only fov_vert is not enough, sea camera not working properly. I made this change 3 months ago and forgot why i changed D3DMATRIX math. Only fov_vert 1

Hammie commented 1 year ago

What game/mod are you playing? I'm not seeing any issues when I set TEHO to a 21:9 aspect ratio.

Reksotiv commented 1 year ago

increase fov_multiplier in engine.ini, i use 1.35 for 3440x1440 resolution. Any game, screenshots above from beyond new horizons, but all tests were in a ship pack 2.3.0a. With the change played 50 hours without problems and 10 hours in TEHO. Without using the D3DXMatrixPerspectiveFovLH function, i remember changing something in the files deck_camera.cpp, free_camera.cpp, ship_camera.cpp. But why don't you want to use it? I don't know something or?

Hammie commented 1 year ago

But why don't you want to use it? I don't know something or?

We are trying to depend less on DirectX, for cross-platform compatibility. Adding new dependencies is something I would really like to avoid.

Reksotiv commented 1 year ago

I understand why the problem with the camera in the sea. image in my fix i removed that and applied the FovMultiplier without changing the perspective variable, which is stored in Fov variable here. image and when we move from land to sea, we get a double FovMultiplier

espkk commented 1 year ago

But why don't you want to use it? I don't know something or?

We are trying to depend less on DirectX, for cross-platform compatibility. Adding new dependencies is something I would really like to avoid.

Just to clarify, that's not about DirectX itself, but rather about D3DX support lib which is not present for our Linux build, so it simply won't compile unless we implement it ourselves (should be a few lines though)

I understand why the problem with the camera in the sea. image in my fix i removed that and applied the FovMultiplier without changing the perspective variable image and when we move from land to sea, we get a double FovMultiplier ship_camera.cpp

Yes indeed, IIRC it was my attempt to centralize FOV customization, but it ended up setting it through sea/camera only for compatibility. Also, it's probably still missing from the SKY entity. So fov_multiplier was an unfinished feature.

With fov_multiplier=1.0 it likely won't affect anything even if we merge it as is, but since we are touching this we probably want it to be complete. And this is a non-trivial task...

Reksotiv commented 1 year ago

this code works fine for me, without saving the changed perspective by fov_multiplier in Fov variable

const float near_plane = fNearClipPlane; // Distance to near clipping
const float far_plane = fFarClipPlane;   // Distance to far clipping
const float fov_horiz = perspective;     // Horizontal field of view  angle, in radians
if (fAspectRatio < 0)
{
    fAspectRatio = static_cast<float>(screen_size.y) / screen_size.x;
}
aspectRatio = fAspectRatio;
// Vertical field of view  angle, in radians
const float fov_vert = 2.f * atanf(tanf(perspective * 0.5f * FovMultiplier) * fAspectRatio);

const float w = 1.0f / tanf(fov_vert * 0.5f) * fAspectRatio;
const float h = 1.0f / tanf(fov_vert * 0.5f);
const float Q = far_plane / (far_plane - near_plane);

D3DMATRIX mtx{};

mtx._11 = w;
mtx._22 = h;
mtx._33 = Q;
mtx._43 = -Q * near_plane;
mtx._34 = 1.0f;
Reksotiv commented 1 year ago

Yes indeed, IIRC it was my attempt to centralize FOV customization, but it ended up setting it through sea/camera only for compatibility. Also, it's probably still missing from the SKY entity. So fov_multiplier was an unfinished feature.

ok i realized that with this fix we might get errors in other places.