OpenArena / engine

OpenArena modifications to the ioquake3 engine
http://openarena.ws
GNU General Public License v2.0
211 stars 50 forks source link

About setting widescreen fov parameter [question] #49

Open suijingfeng opened 6 years ago

suijingfeng commented 6 years ago

This thread is more about question than issue. The following code is extracted from RE_RenderScene in tr_scene.c

parms.fovX = tr.refdef.fov_x;
parms.fovY = tr.refdef.fov_y;

if (!( fd->rdflags & RDF_NOWORLDMODEL ) ) // don't affect interface refdefs
{
    float zoomfov = tr.refdef.fov_x / 90;   
    int thisisit;
    float erspact = tr.refdef.width / tr.refdef.height;
    float aspact = glConfig.vidWidth / glConfig.vidHeight;
    if (erspact == aspact) thisisit = 1;
    if (((tr.refdef.fov_x /  tr.refdef.fov_y) > 1.3) && (thisisit))
        {
                // undo vert-
                parms.fovY = parms.fovY * (73.739792 / tr.refdef.fov_y) * zoomfov;
                // recalculate the fov
                parms.fovX = (atan (glConfig.vidWidth / (glConfig.vidHeight / tan ((parms.fovY * M_PI) / 360.0f))) * 360.0f) / M_PI;
                parms.fovY = (atan (glConfig.vidHeight / (glConfig.vidWidth / tan ((parms.fovX * M_PI) / 360.0f))) * 360.0f) / M_PI;
        }
}

It boil down to

parms.fovX = tr.refdef.fov_x;
parms.fovY = tr.refdef.fov_y;
if (!( fd->rdflags & RDF_NOWORLDMODEL ) ) // don't affect interface refdefs
{
    if ((parms.fovX > parms.fovY * 1.3f) && (tr.refdef.width * glConfig.vidHeight == glConfig.vidWidth * tr.refdef.height ))
    {
        // undo vert-
        parms.fovY = parms.fovX * (73.739792 / 90.0);
        // recalculate the fov_x
        parms.fovX = atan( tan(parms.fovY*(M_PI/360.0)) * glConfig.windowAspect ) * (360.0 / M_PI);
    }
}

because:

1) glConfig.windowAspect = glConfig.vidWidth / glConfig.vidHeight is already computed previously, don't compute it every time in the main loop.

2) parms.fovX = (atan (glConfig.vidWidth / (glConfig.vidHeight / tan ((parms.fovY * M_PI) / 360.0f))) * 360.0f) / M_PI are equivalent to parms.fovY = (atan (glConfig.vidHeight / (glConfig.vidWidth / tan ((parms.fovX * M_PI) / 360.0f))) * 360.0f) / M_PI; because:

glConfig.vidWidth / glConfig.vidHeight = tan( parms.fovX M_PI / 360) / tan( parms.fovY M_PI / 360) there no need to compute parms.fovY again, right?

3) what i am doing is trying to avoid float divided, it seems that adding this code code snippet to my rendergl2 module make sarge run faster. it may somewhere which OA different from ioq3.

I don't know how 1.3f and 73.739792 this two parameters comes from. Can someone tell something about that?

The-Gig commented 6 years ago

While waiting for someone capable of answering to you, maybe you may take a look to this: https://github.com/OpenArena/engine/pull/37 (a different way to compute widescreen fov, which should not have a small problem that current implementation has got in case of cg_fov <>90).

leilei- commented 6 years ago

1.3f comes from wanting to check if the refdef has an aspect of 4:3 or wider (comes from 320 / 240, and to exclude widescreen processing a vert+ 5:4 mode like 1280x1024, which would be 1.25)

As for the other, I think 73.739792 was from calculating against the cgame's assumed vertical FOV and that I couldn't get a divide working properly.

A lot of it was trial and error on adapting older engoo code (which is either adapted from mh or quakespasm code) and attempting to apply that renderer-side for compatibility so it shouldn't affect gameplay. Also all the refdefs (viewports, etc) in the game go through that function and I had tried to make sure the widescreen fov only applies to the player view. A lot of my code is this messy as I've rarely had a second opinion whenever I commit stuff, especially back in 2014.

Also, i'm not the best at math, and i'd like to learn how to do this better. This issue is better than that one pull request wrongfully implying i didn't have hor+ in the first place. This issue marks the first time i've had proper insightful feedback and critique on my now-4-years-old widescreen implementation code.

suijingfeng commented 6 years ago

Thanks for replies, it is very helpful. By print the results the above code, i learned that 73.739792 = (360.0 / M_PI) * atan( tan( (M_PI/360.0) * 90) * 0.75f ) = (360.0 / M_PI) * atan(0.75)

ryvnf's request is actually can be optimized as follow:

        parms.fovX = tr.refdef.fov_x;
    parms.fovY = tr.refdef.fov_y;
    if (!( fd->rdflags & RDF_NOWORLDMODEL ) ){
        parms.fovY = (360.0 / M_PI) * atan( tan( (M_PI/360.0) * parms.fovX ) * 0.75f );
        parms.fovX = (360.0 / M_PI) * atan( tan( (M_PI/360.0) * parms.fovY ) * tr.refdef.width / tr.refdef.height ) ;
    }

1) ryvnf's method are actually roughly same with leilei's. they both compute parms.fovY use tr.refdef.fov_x(=fd->fov_x), then compute parms.fovX with parms.fovY. Both method preserve the window aspect ratio. ryvnf does't check (parms.fovX / parms.fovY > 1.3f) which may has a influence on 1280*1024.

2) Both method are not perfect, because players of OA can not set the horizon field of view accurately. For example, my display resolution is 1920*1080, if i want to set my HFOV to 140 by set cg_fov = 140, but i will get 140.363510 by using leilei's code, or 149.463058 by using ryvnf's code. I means the actual horizontal fov will not correspond to cg_fov value, and the user cannot know what it is exactly.

I hasty write a naive program to verify this.

if set cg_fov = 90, both leilei and ryvnf's method will get the same results.

width: 320, height: 240 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 400, height: 300 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 512, height: 384 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 640, height: 480 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 800, height: 600 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 960, height: 720 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 1024, height: 768 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 1152, height: 864 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 1280, height: 1024 leilei ------ fovX: 90.000000, fovY: 0.000000, aspect: inf ryvnf ------ fovX: 90.000000, fovY: 0.000000, aspect: inf

width: 1600, height: 1200 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 2048, height: 1536 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 856, height: 480 leilei ------ fovX: 106.431747, fovY: 73.739792, aspect: 1.783333 ryvnf ------ fovX: 106.431747, fovY: 73.739792, aspect: 1.783333

width: 1280, height: 720 leilei ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778 ryvnf ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778

width: 1280, height: 768 leilei ------ fovX: 102.680382, fovY: 73.739792, aspect: 1.666667 ryvnf ------ fovX: 102.680382, fovY: 73.739792, aspect: 1.666667

width: 1280, height: 800 leilei ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000 ryvnf ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000

width: 1280, height: 960 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 1360, height: 768 leilei ------ fovX: 106.044807, fovY: 73.739792, aspect: 1.770833 ryvnf ------ fovX: 106.044807, fovY: 73.739792, aspect: 1.770833

width: 1366, height: 768 leilei ------ fovX: 106.287048, fovY: 73.739792, aspect: 1.778646 ryvnf ------ fovX: 106.287048, fovY: 73.739792, aspect: 1.778646

width: 1360, height: 1024 leilei ------ fovX: 89.775749, fovY: 73.739792, aspect: 1.328125 ryvnf ------ fovX: 89.775749, fovY: 73.739792, aspect: 1.328125

width: 1400, height: 1050 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 1400, height: 900 leilei ------ fovX: 98.797409, fovY: 73.739792, aspect: 1.555556 ryvnf ------ fovX: 98.797409, fovY: 73.739792, aspect: 1.555556

width: 1600, height: 900 leilei ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778 ryvnf ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778

width: 1680, height: 1050 leilei ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000 ryvnf ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000

width: 1920, height: 1080 leilei ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778 ryvnf ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778

width: 1920, height: 1200 leilei ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000 ryvnf ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000

width: 1920, height: 1440 leilei ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333 ryvnf ------ fovX: 90.000000, fovY: 73.739792, aspect: 1.333333

width: 2560, height: 1600 leilei ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000 ryvnf ------ fovX: 100.388855, fovY: 73.739792, aspect: 1.600000

width: 3840, height: 2160 leilei ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778 ryvnf ------ fovX: 106.260201, fovY: 73.739792, aspect: 1.777778

But set cg_fov = 140

width: 320, height: 240 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 400, height: 300 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 512, height: 384 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 640, height: 480 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 800, height: 600 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 960, height: 720 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 1024, height: 768 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 1152, height: 864 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 1280, height: 1024 leilei ------ fovX: 140.000000, fovY: 0.000000, aspect: inf ryvnf ------ fovX: 140.000000, fovY: 0.000000, aspect: inf

width: 1600, height: 1200 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 2048, height: 1536 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 856, height: 480 leilei ------ fovX: 140.477417, fovY: 114.706345, aspect: 1.783333 ryvnf ------ fovX: 149.553772, fovY: 128.225998, aspect: 1.783333

width: 1280, height: 720 leilei ------ fovX: 140.363510, fovY: 114.706345, aspect: 1.777778 ryvnf ------ fovX: 149.463058, fovY: 128.225998, aspect: 1.777778

width: 1280, height: 768 leilei ------ fovX: 137.945755, fovY: 114.706345, aspect: 1.666667 ryvnf ------ fovX: 147.531403, fovY: 128.225998, aspect: 1.666667

width: 1280, height: 800 leilei ------ fovX: 136.355270, fovY: 114.706345, aspect: 1.600000 ryvnf ------ fovX: 146.254013, fovY: 128.225998, aspect: 1.600000

width: 1280, height: 960 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 1360, height: 768 leilei ------ fovX: 140.220245, fovY: 114.706345, aspect: 1.770833 ryvnf ------ fovX: 149.348923, fovY: 128.225998, aspect: 1.770833

width: 1366, height: 768 leilei ------ fovX: 140.381348, fovY: 114.706345, aspect: 1.778646 ryvnf ------ fovX: 149.477264, fovY: 128.225998, aspect: 1.778646

width: 1360, height: 1024 leilei ------ fovX: 128.495285, fovY: 114.706345, aspect: 1.328125 ryvnf ------ fovX: 139.855652, fovY: 128.225998, aspect: 1.328125

width: 1400, height: 1050 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 1400, height: 900 leilei ------ fovX: 135.229904, fovY: 114.706345, aspect: 1.555555 ryvnf ------ fovX: 145.346832, fovY: 128.225998, aspect: 1.555556

width: 1600, height: 900 leilei ------ fovX: 140.363510, fovY: 114.706345, aspect: 1.777778 ryvnf ------ fovX: 149.463058, fovY: 128.225998, aspect: 1.777778

width: 1680, height: 1050 leilei ------ fovX: 136.355270, fovY: 114.706345, aspect: 1.600000 ryvnf ------ fovX: 146.254013, fovY: 128.225998, aspect: 1.600000

width: 1920, height: 1080 leilei ------ fovX: 140.363510, fovY: 114.706345, aspect: 1.777778 ryvnf ------ fovX: 149.463058, fovY: 128.225998, aspect: 1.777778

width: 1920, height: 1200 leilei ------ fovX: 136.355270, fovY: 114.706345, aspect: 1.600000 ryvnf ------ fovX: 146.254013, fovY: 128.225998, aspect: 1.600000

width: 1920, height: 1440 leilei ------ fovX: 128.670578, fovY: 114.706345, aspect: 1.333333 ryvnf ------ fovX: 140.000000, fovY: 128.225998, aspect: 1.333333

width: 2560, height: 1600 leilei ------ fovX: 136.355270, fovY: 114.706345, aspect: 1.600000 ryvnf ------ fovX: 146.254013, fovY: 128.225998, aspect: 1.600000

width: 3840, height: 2160 leilei ------ fovX: 140.363510, fovY: 114.706345, aspect: 1.777778 ryvnf ------ fovX: 149.463058, fovY: 128.225998, aspect: 1.777778

The-Gig commented 6 years ago

Excuse me, what do you mean with this sentence?

"Both method are not perfect, because we can not set the horizon field of version accurately."

I suppose you meant "field of view" instead of "field of version", okay... But I still don't get what you mean...

Maybe do you mean that you would prefer to be able to set a cg_fov corresponding to the horizontal fov you actually want to obtain on your screen, instead of the one you would have at 4:3 ratio? Aw, I really did not explain myself well in the above sentence. Let's try again. With vert-, your cg_fov was always your actual horizontal fov value, right? With hor+, cg_fov refers to the horizontal fov you would have in case of a 4:3 ratio. In case your ratio is different, your actual horizontal fov will not correspond to cg_fov value, and the user cannot know what it is exacly. If cg_fov 90 gives fovX 106.260201 at FullHD, did you mean you wanted to have this info somewhere, or to directly enter 106 in cg_fov cvar? Or what else? I'm a bit lost... I have to admit I don't know how modern games deal with that. Like, maybe they assume the horizontal FOV you specify refers to 16:9, and silently adapt fovX for other ratios?

suijingfeng commented 6 years ago

@The-Gig , thanks for feedback and sorry for my poor English written skills. I revise my comment, wish you could understand it.

I am now doubt the necessary of the leilei's widescreen support code and ryvnf's widescreen support request. Because those patched code do not help the players get the best HFOV and VFOR parameter for a specific resolution. In other word, I think leilei's widescreen support code should be removed from the engine. The reasons are as follows.

As I puts it earlier, display aspect = winWidth / winHeight = tan( parms.fovX * M_PI / 360) / tan( parms.fovY * M_PI / 360). Either parms.fovX or parms.fovY are independent, If we know the width and height of the rendering windows. In other word, parms.fovY can be calculated from parms.fovX if we want preserve the display aspect. The game code fov_y = (360.0/M_PI) * atan2( tan( fov_x * (M_PI/360.0) ) * cg.refdef.height , cg.refdef.width); in CG_CalcFov is meant to preserve aspect, there no need to recalculate parms.fovX and parms.fovY again.

Both leilei and ryvnf's code are not useful with cg_fov = 90 setting by default, it does not help widescreen players get the best fov parameters for a specific display resolution. You have to turn cg_fov by youselves for best efficiency or for view effect.

The-Gig commented 6 years ago

Your rewording of the previous post confirmed I understood correctly about that specific sentence, thanks.

However, for me it's okay to just say "Cg_fov is the horizontal FOV with a 4:3 ratio. In case of widescreen, actual FOV will be larger". However, I don't know how modern games deal with this. I don't know if they automatically change your FOV setting in case you change your resolution to a different ratio or what else...

I'm sorry I get lost with the calculations, I'm not good with them.

Hor+ may give an advantage to widescreen users (compared to 4:3 users) with the same fov (more horizontal view), but vert- gives them a disadvantage (less vertical view). Considering today widescreen is the norm, I'm okay with hor+...

leilei- commented 6 years ago

My implementation is intended to be mod compatible and cgame should not be changed for widescreen support.

Here's an old gif of my implementation which had me feel certain about the hor+ FOV being correct

oawidescreen2

I'm not removing widescreen.

It should also be noted that John Carmack did consider widescreen hor+ in Q3 but decided against it because of the fov setting confusion that would possibly upset the "config enthusiast" playerbase

However, I don't know how modern games deal with this.

Letterboxing for non-wide.

The-Gig commented 6 years ago

About suijingfeng's note that players cannot control or know actual fov, here's a small idea (take it for what it is, just an idea): what about adding a new command to output effective fov info to console?

Your cg_fov is 90. Actual fovX: 102.680382, fovY: 73.739792 Your cg_zoomfov is 22.5. Actual zoomFovX: xxxxxxxxx, zoomFovY: yyyyyyyyyy

Or maybe the output may be more verbose, also recapping some other related infos:

Resolution/Field Of View settings: r_mode -1 (custom) r_customheight 1920 [to be shown in case of r_mode -1] r_customwidth 1080 [to be shown in case of r_mode -1] r_custompixelaspect 0 [somewhat related with r_mode -1, IIRC. Note, I don't know if this may have some relationship with the resulting FOV] r_fullscreen 0 Resolution: 1920x1080, ratio 1.33333 cg_fov 90. Actual fovX: 102.680382, fovY: 73.739792 cg_zoomfov 22.5. Actual zoomFovX: xxxxxxxxx, zoomFovY: yyyyyyyyyy

Well, at least players would have a way to know which is their actual FOV, while the reference cg_fov value would still refer to 4:3.

About the "1.3f" thing in leilei's implementation, have I understood correctly how it works? 1.33333 means 4:3 ratio, which is set as reference. Assuming "widescreen" meaning > 1.33333 and "narrowsreen" < 1.33333... In "hor+" using a narrowscreen would ed up in doing a "hor-" (actual fovX smaller than cg_fov). Leilei code in that case reverts to "vert-", ending up doing a "vert+" (actual fovX equal to cgfov). Did I understand correctly? Probably leilei's explanation from Aug 1 is clear enough about it... but I ask because suijingfeng's resolution/fov comparison examples above just list as "fovY 00000, ratio inf." the cases where ratio is smaller than 1.33333, so I'm not sure about actual results. That sounds a quite good solution, much better than letterboxing! ^^ Wondering what does ryvnf code do in case of narrowscreen (narrower than 4:3)...? Also, is 1.3f equal to 1.3 or 1.33333? I mean, rounding decimals may be a problem here?

Kezuz commented 5 years ago

@leilei- ryvnf claimed the implementation is flawed for cg_fov values not equal to 90. It appears you use cg_fov 90 in your GIF.

I tried to replicate your example with cg_fov 130 and it appears ryvnf was correct. See for yourself:

130

The vertical FOV changes between 640x480, 800x480 and 960x480 which it shouldn't in a correct implementation.

suijingfeng commented 5 years ago

@Kezuz @leilei- how to generate GIT like what your have done? I'm also want to generate one.

Kezuz commented 5 years ago

@suijingfeng I used the screenshotjpeg command after each change in cg_fov. Then open up the screenshots in GIMP and make a animated gif of them.