Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Objects flicker in brightness between time 6125 and 6375 (and at sunset) (basic shaders on) #8416

Closed
paramat opened this issue Mar 22, 2019 · 6 comments · Fixed by #8417
Closed
Assignees
Labels
Bug Issues that were confirmed to be a bug @ Client / Audiovisuals

Comments

@paramat
Copy link
Contributor

paramat commented Mar 22, 2019

Noticed this while when working on something else.

I added printf() lines to src/daynightratio.h.
When basic shaders are on, the smooth bool is true so the loop at the end of the function is used.

inline u32 time_to_daynight_ratio(float time_of_day, bool smooth)
{
	float t = time_of_day;
	if(t < 0)
		t += ((int)(-t)/24000)*24000;
	if(t >= 24000)
		t -= ((int)(t)/24000)*24000;
	if(t > 12000)
		t = 24000 - t;
	float values[][2] = {
		{4250+125, 150},
		{4500+125, 150},
		{4750+125, 250},
		{5000+125, 350},
		{5250+125, 500},
		{5500+125, 675},
		{5750+125, 875},
		{6000+125, 1000},
		{6250+125, 1000},
	};
	if(!smooth){
		float lastt = values[0][0];
		for(u32 i=1; i<sizeof(values)/sizeof(*values); i++){
			float t0 = values[i][0];
			float switch_t = (t0 + lastt) / 2;
			lastt = t0;
			if(switch_t <= t)
				continue;
			return values[i][1];
		}
		return 1000;
	}

	for (u32 i=0; i < sizeof(values) / sizeof(*values); i++) {
			if (values[i][0] <= t)
				continue;
			if (i == 0)
				return values[i][1];
			float td0 = values[i][0] - values[i-1][0];
			float f = (t - values[i-1][0]) / td0;
			printf(" t %f", t);
			printf(" f %f", f);
			printf(" dnr %f\n", f * values[i][1] + (1.0 - f) * values[i-1][1]);
			return f * values[i][1] + (1.0 - f) * values[i-1][1];
		}
		printf(" dnr %f\n", 1000.0);
		return 1000;
}

Also to src/light.h.

inline u8 blend_light(u32 daylight_factor, u8 lightday, u8 lightnight)
{
	u32 c = 1000;
	u32 l = ((daylight_factor * lightday + (c - daylight_factor) * lightnight)) / c;
	printf(" bl %d", l);
	if (l > LIGHT_SUN)
		l = LIGHT_SUN;
	return l;
}

to print:

  • time (t)
  • the internal interpolated daynightratio float value (dnr)
  • calculated light level for objects (bl)

I discovered that time_to_daynight_ratio() behaves like this:

During sunrise until time 6125, day night ratio smoothly increases towards 1000 (full brightness) as it interpolates between the value pairs in the table.

Between time 6125 and 6375 it is interpolating between two 1000 values, but tiny float errors cause the result of the interpolation to jump back and forth between, for example, 999.999995 and 1000.000006. Because the function returns an integer the returned value switches between 999 and 1000.
Printing the light level calculated by blend_light() shows that these tiny changes cause the lightlevel to jump back and forth between 14 and 15, causing objects to flicker.
This is only noticeable recently because the visual brightness of light levels 14 and 15 were identical until recently, now they differ.

After time 6375 the function returns 1000 all the time, the calculated light level is always 15 and object brightness stops flickering.

Printed data in terminal:
During flicker:

 t 6182.919434 f 0.231678 dnr 999.999994
 t 6182.919434 f 0.231678 dnr 999.999994
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14 bl 14
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6183.259277 f 0.233037 dnr 999.999995
 t 6184.917969 f 0.239672 dnr 1000.000004
 t 6184.917969 f 0.239672 dnr 1000.000004
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006
 t 6185.257812 f 0.241031 dnr 1000.000006

After time 6375:

 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15 bl 15
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000
 dnr 1000.000000

I will fix this soon.
A similar problem may possibly occur when time is between 4375 and 4625, as the interpolation is between 2 identical values.

@paramat paramat added Bug Issues that were confirmed to be a bug @ Client / Audiovisuals labels Mar 22, 2019
@paramat paramat self-assigned this Mar 22, 2019
@paramat
Copy link
Contributor Author

paramat commented Mar 22, 2019

 t 4444.366211 f 0.277465 dnr 149.999999
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 bl 2 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4444.706543 f 0.278826 dnr 149.999998
 t 4446.046875 f 0.284187 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 bl 2 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000
 t 4446.366699 f 0.285467 dnr 150.000000

Same interpolation jumpiness, so returned value will jump between 149 and 150, but this time both light levels are 2 for the default light curve. This should be fixed too.

My fix will be to only return 150, 1000, or smoothly varying values between.

@paramat
Copy link
Contributor Author

paramat commented Mar 22, 2019

Confirmed by printf() the value returned by time_to_daynight_ratio() jumps back and forth between 149 and 150, and between 999 and 1000 at the time periods described.

With shaders off, smooth bool false, returned daynightratio values behave correctly.

@paramat
Copy link
Contributor Author

paramat commented Mar 22, 2019

This code can also be much optimised, the table should be 'static', and codestyle needs work, i'll do this in a follow-up PR.

@paramat
Copy link
Contributor Author

paramat commented Mar 22, 2019

PR #8417

@lhofhansl
Copy link
Contributor

Nice find. I had observed the same... But never actually looked at why this would be happening.

@paramat
Copy link
Contributor Author

paramat commented Mar 25, 2019

Folow up PR could consider a better interpolation method, see IRC http://irc.minetest.net/minetest-dev/2019-03-25#i_5517930

01:40 p_gimeno The instability probably comes from the formula for linear interpolation. That formula is not monotonic and has problems. I suggest an alternate formula here: http://math.stackexchange.com/questions/907327/accurate-floating-point-linear-interpolation
...
01:57 p_gimeno ah no I haven't, but it's not td0, it's like this: return f < 0.5f ? values[i-1][1] + f * (values[i][1] - values[i-1][1]) : values[i][1] - (1.0f - f) * (values[i][1] - values[i-1][1]);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Issues that were confirmed to be a bug @ Client / Audiovisuals
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants