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

Terrain random flashs #469

Open
wizardCyb opened this issue Nov 24, 2024 · 11 comments
Open

Terrain random flashs #469

wizardCyb opened this issue Nov 24, 2024 · 11 comments

Comments

@wizardCyb
Copy link

When moving the camera around the terrain, I occasionally see random flashes. They occur on average about every five minutes during gameplay. The flashes of light usually appear around a black dot.

5

Environment

  • OS: Windows 10
  • Graphics card: NVIDIA GeForce GTX 1060 6GB
  • Godot version: v4.3.stable.official
  • Plugin version: Heightmap terrain 1.7.3 (dev) - commit 8c1b660
  • Renderer used: Vulkan 1.3.280 - Forward+
@Zylann
Copy link
Owner

Zylann commented Nov 24, 2024

Sorry but I don't know how to investigate that. I would need a minimal test project that shows this happening (and therefore allowing to change things confirming whether or not it fixes it). I haven't experienced this lately. Is that black dot present all the time or is it flickering or moving? Does this happen with a specific shader? With specific things present? How big and how bright are the flashes?

The only supposition I have is that maybe, in your particular setup, something causes a value in shader to become NaN or very high, outputting that black pixel and then cause a "flash" if you have a post-processing effect such as bloom or glow enabled because that tends to spread the bogus pixel around (but why every 5 minutes, mystery; and that's assuming Godot features you're using are bug-free). But without any way of reproducing this I can't investigate.

@wizardCyb
Copy link
Author

The black dot and glow around appears in a frame then the next one if the camera moves it is not there anymore. The glow is particularly noticeable because it flashes strongly, with an approximate radius of 50 pixels.

I'm using the Classic4 shader, but the issue persists when switching to Classic4Lite. I have the glow effect enabled, and it seems related to the issue. Disabling the glow prevents the problem, while adjusting the glow parameters increases or decreases the intensity of the effect.

Side note, turning on fog makes the issue disappear, though I'm not sure if this applies to all situations or fog distances.

The 5 minutes I mentioned was just to illustrate how rare the event is. It doesn’t mean it happens every 5 minutes. I might notice it 3 times in 10 minutes or not at all.

At the moment, I don’t have a minimal test project to share, and I haven’t tested the issue on a different computer. I can probably test it later.

Not sure if is related, but sometimes I got white or black dots, even sometimes are small lines. Like this:

8

Thank you.

@Zylann
Copy link
Owner

Zylann commented Nov 24, 2024

Hmm I haven't seen lines like this either. I opened a few test scenes I had around and could not find anything. So I'm not going to be able to do further investigation without a way to confirm this, or you have to try changing things in the shader in your project.

If you have detail layers, try turning them off just in case.

An example of tests you could do, at the end of the terrain's fragment shader:

	// Attempts at sanitizing outputs to prevent NaNs/Infs/Illegal values
	ALBEDO = clamp(ALBEDO, vec3(0.0), vec3(1.0));
	ROUGHNESS = clamp(ROUGHNESS, 0.0, 1.0);
	NORMAL = clamp(NORMAL, vec3(-1.0), vec3(1.0));
	if (length(NORMAL) < 0.2) {
		NORMAL = vec3(0.0, 1.0, 0.0);
	} else {
		NORMAL = normalize(NORMAL);
	}

You could also try adding this one at the end of the vertex shader:

	NORMAL = clamp(NORMAL, vec3(-1.0), vec3(1.0));
	if (length(NORMAL) < 0.2) {
		NORMAL = vec3(0.0, 1.0, 0.0);
	} else {
		NORMAL = normalize(NORMAL);
	}

If that fixes it, remove them until you can identify which one causes it.
If it doesn't, then it would be something else, but I don't know what (considering these are the only variables the shader passes over to Godot).

@wizardCyb
Copy link
Author

wizardCyb commented Nov 28, 2024

ALBEDO = clamp(ALBEDO, vec3(0.0), vec3(1.0)

At least in the quick test I’ve done, this line seems to fix the issue of the white dots. Not sure about the glows, I have not tested yet.

I’ve attached a very basic project if you want to test it. There’s a small white dot in the top middle, and commenting out that line in the shader makes it disappear.

My screen is Full HD (1920 x 1080), the bug probably requires the same resolution to occur.

I’ve only added the terrain, no textures, no light, etc.. just enough to reproduce the bug.

bug_terrain.zip

@MGilleronFJ
Copy link

MGilleronFJ commented Nov 29, 2024

First thing I notice is that your splatmap (splat.png) is totally white, which is incorrect for a splatmap. I don't know how you got it in that state, but usually a splatmap's color components should mostly add up to 1 (with eventual precision fluctuations). But yours pretty much looks as if all pixels of the terrain have all 4 textures active at once which makes no sense.

If I run your test scene, this is what I see:
image
Is this the dot you're referring to?
image

That pixel has a component just about higher than 3.30715 (as far as I could measure in shader), which is weird because I dont think any HDR texture is supposedly used here.
What's even more incomprehensible is that the pixel still occurs if I litterally write this in the fragment shader:

ALBEDO = v_tint0;

Which is litterally the interpolation from this code in the vertex shader:

vec4 tint = texture(u_terrain_colormap, UV);
v_tint0 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.x);

Still happens when I simplify it to:

vec4 tint = texture(u_terrain_colormap, UV);
v_tint0 = tint.rgb;

But if I do:

v_tint0 = vec3(1.0, 0.0, 0.0);

Then I see no dot.

Also it actually doesn't have to be super specific angles, it just needs to be very shallow. When looking at the horizon, this happens:
image
And again, it does as long as the texture is sampled.
Now your terrain doesn't have any textures setup so I don't know if this is specifically caused by the colormap, but I'm not sure what's going on here. Broken mipmaps? Weird sampling behavior?

Curiously it happens less if I properly splat-paint some regions, but black pixels still tend to show up a bit, while more occur with also flashes in regions where splats are all 1. Also hardcoding colormap tint to white seems to get rid of the issue, but why?? I tried to change import settings of that texture and nothing seemed to make a difference.

@wizardCyb
Copy link
Author

wizardCyb commented Nov 29, 2024

That’s the bug I encountered. When the glow is active, those dots sometimes cause a glow effect there.

I manually cleaned the splatmap, I didn’t notice that it wasn’t the correct color.

I was in a bit of a hurry and I thought it might be enough without textures, but I can try again later when I have the opportunity to provide some example with textures. Thank you for looking into it.

@wizardCyb
Copy link
Author

wizardCyb commented Nov 29, 2024

Here is the same scene. I have added a texture, and also a Environment light.

bug_terrain2.zip

You can probably apply any texture, and the bug persists. At least with the two I tried, it was still present.

@MGilleronFJ
Copy link

MGilleronFJ commented Nov 29, 2024

See my last notes from above.

I wonder if the fact that tint is sampled per vertex has something to do with this. If I move all sampling to the fragment part, the problem seems to go away. It's like whatever interpolates the varying makes it go beyond the values being interpolated in the first place (which is still partially unexplained because the issue doesn't happen if I set this to a hardcoded color in the vertex shader).
I was also unable to reproduce this in any simple test project (without the bulk of the plugin, just a simple shader and a subdivided plane), so it's still difficult to prove what's really going on. Because it's hard to ask around for advice if the only way to reproduce this is a big addon.

It's annoying because moving it all to fragment brings a different problem: 2 more texture samples and extra calculations done per pixel, for something that varies only per vertex, so it may be more expensive. Also there are already a lot of other samples in terrain fragment shaders (which some low-end graphics cards just nope at) so I don't know what else to do about it, or how I could keep it per-vertex while avoiding this frustrating issue (which, oddly enough, hasn't been noticed in years of existence of this shader).

@wizardCyb
Copy link
Author

I don’t know much about shaders (it’s something I want to learn later), so unfortunately, I can’t be of much help with this. I just wanted to report the issue in the hope that it can be found and fixed.
Thank you for your time.

@Zylann
Copy link
Owner

Zylann commented Nov 29, 2024

If you need a quick fix for now, you may keep the clamp, or move this part to the beginning of fragment():

// Putting this in vertex saves 2 fetches from the fragment shader,
// which is good for performance at a negligible quality cost,
// provided that geometry is a regular grid that decimates with LOD.
// (downside is LOD will also decimate tint and splat, but it's not bad overall)
vec4 tint = texture(u_terrain_colormap, UV);
v_hole = tint.a;
v_tint0 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.x);
v_tint1 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.y);
v_tint2 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.z);
v_tint3 = mix(vec3(1.0), tint.rgb, u_colormap_opacity_per_texture.w);
v_splat = texture(u_terrain_splatmap, UV);

For now I only suspect the issue comes from how the graphics driver is interpolating varying v_tint in such situations. Maybe it's using less precision than it should. I tried adding highp but that didnt change anything. Maybe it's a driver bug or quirk, and would require much heavier investigating to find for example if gl_Position.w becomes wrong or something, but at this point I'm not sure how to do that and I don't have much time.

So unfortunately the "fix" for now will be to move these samplings to the fragment shader, because it seems to just work, despite the small extra cost...

If someone wants the shader to do it per-vertex again, or wants to investigate this, I'll do it using #define so it can be toggled back.

Zylann added a commit that referenced this issue Nov 29, 2024
This is to workaround an unexpected blow-up of interpolated values when
they were sampled in the vertex shader and used in the fragment shader.
The assumption is that interpolation somehow runs out of precision or
incorrectly calculates varying values, causing them to become higher than
1, which in turn causes flashes to occur when bloom is enabled.
I think this is still unexpected and needs more investigation,
but I'm not sure what else to try (that I know how to do)
and I don't have much time.
See #469
@Zylann
Copy link
Owner

Zylann commented Nov 29, 2024

Workaround in 659da22

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants