Page 1 of 3

r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 8:53
by Rachael
https://github.com/raa-eruanna/qzdoom/pull/3

Creating a pull request because I am not sure how you want this handled.

Two issues:

1) This is faked based on viewpitch. Look up and down, it simply fudges it towards 1.0. Barely noticeable to the user. When someone tries to use a negative pixel ratio, though, this will create issues. As far as I know, negative pixel ratios are not officially supported in GZDoom, anyway.
2) I do not know how to initialize GZDoom's mapinfo. As you can see in the submission, I tried, but it created compile errors. For now, due to this, it simply defaults to 1.2. This also gives it built-in divide by zero protection. [Solved] - I prototyped GZDoom's initializer function.

All I can say is - for what it does, it works, but it doesn't yet support GZDoom's pixelratio and it should.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 10:37
by dpJudas
What does the pixelstretch setting do?

In the PR you are using it to alter the field of view. If the purpose is to squish or stretch the pixels, it might work better to update the scale matrix that code is already using. The YaspectMul variable might be the software equivalent of what you are adding. For some reason I had to add such an Y scale to get it match 100% with how it looks in the original renderer.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 11:06
by Rachael
Pixelstretch is GZDoom's internal name for it.

YaspectMul is used elsewhere in the code. I would rather not modify that variable directly.

Unless you mean something else by scale matrix?

The way GZDoom does it is it just changes the Z geometry before the verteces hit the GPU.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 11:34
by dpJudas
What I meant is that maybe you could replace YaspectMul with that pixelstretch variable in the line where it applies it to the matrix. In any case, I am fine with whichever solution is used as long as toggling r_newrenderer on and off in Doom and Doom 2 looks exactly the same when looking straight ahead.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 12:07
by Rachael
Well if that still works I would be happy with that solution. I am going to play with it some more, anyway, I am not happy with how it handles extreme aspect ratios (4.0, 0.2).

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 12:09
by dpJudas
Okay, finally at my (dev) computer. :) Hooked up the debugger and I can see that YaspectMul evaluates to 1.2, which matches the default fallback of the code in the PR.

So I think it can be simplified to look like this:

Code: Select all

	static bool bDidSetup = false;
	if (!bDidSetup)
	{
		InitGLRMapinfoData();
		bDidSetup = true;
	}
	float pixelstretch = (glset.pixelstretch) ? glset.pixelstretch : 1.2;
	
	float ratio = WidescreenRatio;
	float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
	float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
	TriMatrix worldToView =
		TriMatrix::scale(1.0f, pixelstretch, 1.0f) *
		TriMatrix::rotate((float)ViewPitch.Radians(), 1.0f, 0.0f, 0.0f) *
		TriMatrix::rotate((float)(ViewAngle - 90).Radians(), 0.0f, -1.0f, 0.0f) *
		TriMatrix::swapYZ() *
		TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
	WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
Not relying on YaspectMul at all will be perfect, because eventually the few remaining globals shared with the Carmack software renderer needs to be removed.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 12:47
by dpJudas
Eruanna wrote:I am not happy with how it handles extreme aspect ratios (4.0, 0.2).
Missed this part. Extreme aspect ratios are probably not working very well right now due to the way it culls segments.

When it renders the scene it walks the BSP nodes in a front to back manner, but to avoid processing more than absolutely needed it keeps a list of SolidSegments (in PolyCull) that marks which X screen pixel ranges have been blocked. It does this by projecting each line to the screen in 2D (not taking ViewPitch into account) and then scaling it up to a -3000 to 3000 range. The code doing this projection can be found at the bottom of PolyCull::GetSegmentRangeForLine.

Now, the problem is that this code doesn't really factor in the active aspect ratio. Instead, I chose to just assume that the range is "reasonable" in the 1.0 to 3.0 range. If the aspect ratio is too low, the resolution of -3000 to 3000 is never fully used, and if its too big the edges of the screen go beyond 3000.

This can be fixed, of course, but what are the use cases for such extreme aspect ratios?

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 12:56
by Rachael
The culling isn't the problem. What was the issue, for me, was going for those high ratios, and looking at odd angles like 45 up or down, it looked a bit wonky.

I discovered that changing the tween formula to sin instead of cos fixed that - but now I am having another problem because looking up causes the tween multiplier to go out of range. (Long story short: I failed at math. Again.)

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 13:26
by dpJudas
Hehe, join the club. I always have to spend hours debugging my math code before finally getting it to work. At least I'm not the only one cursed that way. :D

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 13:30
by Rachael
My OCD will be the death of me. I'm still not 100% happy with it but it's definitely better than it was, and it doesn't look too bad for faking geometry stretching.

I now consider this mergeable but you should probably review the code again and make sure everything looks okay. If you think anything further needs to be simplified - it's all your's. :) I'll be back in a few hours.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 14:53
by dpJudas
To be honest I'm still not sure what YaspectMul was doing, or what pixelstretch is all about. Feel free to merge it in (or commit directly to master) when you feel like it. But since it sounds like you're trying to make it do exactly what GZDoom is doing, I believe the code there does this:

Code: Select all

// We have to scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
double radPitch = ViewPitch.Normalized180().Radians();
double angx = cos(radPitch);
double angy = sin(radPitch) * glset.pixelstretch;
double alen = sqrt(angx*angx + angy*angy);

DAngle anglesPitch = (float)RAD2DEG(asin(angy / alen));
DAngle anglesRoll = ViewRoll;
DAngle anglesYaw = float(270.0-ViewAngle.Degrees);

bool mirror = false; // Set to true in the future when rendering from mirror
bool planemirror = false; // Ditto, although I'm not sure when this one might be true

float mult = mirror? -1:1;
float planemult = planemirror? -glset.pixelstretch : glset.pixelstretch;

float vx = (float)ViewPos.X;
float vy = (float)ViewPos.Y;
float vz = (float)ViewPos.Z;

TriMatrix worldToView =
	TriMatrix::rotate(anglesRoll.Radians(),  0.0f, 0.0f, 1.0f) *
	TriMatrix::rotate(anglesPitch.Radians(), 1.0f, 0.0f, 0.0f) *
	TriMatrix::rotate(anglesYaw.Radians(), 0.0f, mult, 0.0f) *
	TriMatrix::translate(vx * mult, -vz * planemult , -vy) *
	TriMatrix::scale(-mult, planemult, 1);
	
float ratio = WidescreenRatio;
float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
Shamelessly looted from FGLRenderer::SetupView, FGLRenderer::SetViewMatrix, FGLRenderer::SetViewAngle and FGLRenderer::RenderViewpoint.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 18:24
by Rachael
I don't know what the sample you pasted is actually doing, but somehow I think it's neglecting the extra *1.2f that YaspectMul was doing. Change that to a simple constant, and it seems to work better.

That being said, I managed to make it work even closer to what GZDoom was doing. It executes two scalings - one is before the rotation one is after, and with the one before the rotation being customizable I've found that I was able to input any non-negative value and it worked.

If you are planning to implement mirrors though you're going to have to turn off backface culling.

I've simplified the code down to this:

Code: Select all

	static bool bDidSetup = false;

	if (!bDidSetup)
	{
		InitGLRMapinfoData();
		bDidSetup = true;
	}

	float pixelstretch = (glset.pixelstretch) ? glset.pixelstretch : 1.2;

	float ratio = WidescreenRatio;
	float fovratio = (WidescreenRatio >= 1.3f) ? 1.333333f : ratio;
	float fovy = (float)(2 * DAngle::ToDegrees(atan(tan(FieldOfView.Radians() / 2) / fovratio)).Degrees);
	TriMatrix worldToView =
		TriMatrix::scale(1.0f, 1.2f, 1.0f) *
		TriMatrix::rotate((float)ViewPitch.Radians(), 1.0f, 0.0f, 0.0f) *
		TriMatrix::rotate((float)(ViewAngle - 90).Radians(), 0.0f, -1.0f, 0.0f) *
		TriMatrix::scale(1.0f, pixelstretch, 1.0f) *
		TriMatrix::swapYZ() *
		TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
	WorldToClip = TriMatrix::perspective(fovy, ratio, 5.0f, 65535.0f) * worldToView;
Though it still needs testing before a merge. So far, it works, though.

Also, the GLData setup should probably be done elsewhere in the code, as well.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 19:52
by Rachael
This is now merged in as a single commit.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 20:15
by Rachael
bool planemirror = false; // Ditto, although I'm not sure when this one might be true
By the way - this - in GZDoom there are plane reflections. See sapphire.wad

Code: Select all

map map01
warp -2100 2100
It used to be used a lot more than it is used nowadays, but people mostly use it now for rain effects and water puddles.

Re: r_newrenderer pixel ratio support - partial implementation (for now)

Posted: Thu Nov 17, 2016 20:28
by dpJudas
I'm afraid the new perspective code doesn't really work. On my computer it looks like this:
Image

As you can see, ZDoom and GZDoom agrees on the vertical scale, while the new perspective code does not. Before the change ZDoom and Poly were identical.

I can make it identical again by changing the code to look like this:

Code: Select all

	TriMatrix worldToView =
		TriMatrix::scale(1.0f, glset.pixelstretch, 1.0f) *
		TriMatrix::rotate((float)ViewPitch.Radians(), 1.0f, 0.0f, 0.0f) *
		TriMatrix::rotate((float)(ViewAngle - 90).Radians(), 0.0f, -1.0f, 0.0f) *
		TriMatrix::swapYZ() *
		TriMatrix::translate((float)-ViewPos.X, (float)-ViewPos.Y, (float)-ViewPos.Z);
But I'm not sure I really understand what is looking wrong on your computer that prompted you to change all this.