-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Z fighting with voxel rendering #79081
Comments
Some related issues: |
I had a look, the problem is as described in some of the topics you linked. There are two issues that typically cause this kind of thing:
In your project, I replaced the texture with a blank unshaded material and the cracks disappeared to me, which suggested texture filtering. You appear to be using an atlas texture. Texture sampling in GPUs is subject to numerical error, which can cause crossing boundaries from where you expect (which can be compounded with mipmapping). The solution with a texture atlas is to apply padding around the zone you intend to use, where the colors at the boundary are replicated. https://www.google.com/search?q=texture+atlas+padding&oq=texture+atlas+padding This same problem occurs in 2D. This is the reason we have UV contract in batching to try and counteract this, but the best recommendation is for users to apply padding in texture atlases. Godot 4 I believe natively supports auto-padding for 2D atlases. The problem also occurs with skinned mesh textures, which is why textures for skinned meshes also need padding applied, and a gap between UV islands. This is really a consequence of how GPUs work. There's no easy (and efficient) way of fixing this with atlases except using padding, which is why you will see this same recommendation for other engines. |
While I'm not sure this is actionable from a code perspective (a contributor might get around to padding grid atlases, or 2D only as in master), it might be good to add something in the docs as this seems to come around fairly regularly. |
Here's a version using a texture for a single face and a shader that darkens each wall depending on it's facing direction: It's also exhibits the same issue: 2023-07-06.08-41-27-00.00.01.543-00.00.07.424.mp4The texture I used is just an imported png applied to an albedo (in both cases) and I'm not sure entirely how I'd go about padding it? |
Actually, correction, on looking at this case, there does seem to be some interaction with the shader, rather than texture padding. I'm not sure yet, will get back. Yes it does seem likely there's something going on in the shader. UPDATE: I'm not absolutely sure on this yet, as float comparisons in shaders can sometimes give borderline quirk results. But outputting the normal as color suggests it is pretty stable. EDIT: I believe this is the same problem, the z values for the side faces are making them occasionally be drawn in front of the front facing faces. The term often used for this is "z fighting". Some ideas to help alleviate it:
I'm not sure offhand what z mode we use for OpenGL (or whether user can change this), just in case it is causing more fighting than necessary, but I have limited time available to look at this today. |
I've been playing with that, but I'm using a frustum camera and it's difficult to get the fov correct while adjusting the near/far, also the far is retro-styled (short draw distance) and near is close as I don't want to clip through walls, and I couldn't find any good setting that worked for those.
I'm using gridmaps so this is impossible, unfortunately. |
You might also be able to use some hackery to get around this. Some ideas:
|
This might be the easiest to do, since I'm using this shader on all of my walls in the gridmap. I'm not entirely sure how to do this though (I tried some of the other vertex solutions in the threads I linked, but none of them worked, I imagine this would work differently though). |
I am not sure what workflow you are using, but the best way to get MagicaVoxel meshes into a game engine is to optimise them so that they are "watertight". You then won't get z fighting issues as it is contiguous mesh. There is a blender addon to do this conversion. You will also have a much more performant mesh if you are using lots of voxel meshes. |
They're not voxels, I'm not sure why the title was changed, I'm just using MeshInstance cubes. |
Ah, no worries. I have had similar issues in the past and just ended having the cubes scale slightly below 1 at 0.99 or so. This solved my z fighting, but not the most elegant solution to be sure. |
I did try that, along with using the Scale setting in gridmaps, but nothing has so far fixed it, the rendering just seems determined no matter what to flash the side of the cube through. |
Have you tried recreating the same scene without gridmaps, as a test, to see if it has the same issue. I am using a lot of grid snapped cubic structures in my game for a procedural city. I just use standard instancing, not gridmap and have not seen any z fighting if they are scaled to 0.99. It may be something specific to gridmap rendering? |
Yeah, this example I posted is actually just the meshes stacked, I recreated without gridmaps to see if it was gridmap causing the problem (it wasn't, it behaves identically).
I actually haven't tried scaling down, only up (1.001, 1.01, etc), I'll try and see if it helps, thanks... EDIT: just tried, 0.999 makes it even worse. |
I think the problem with this would be the orientation of the cube, it wouldn't work depending on which side it's rotated, and I got even worse flickering with the gridmap cells scaled to 0.999, so I imagine that would be much the same. A vertex shader seems to be the only solution, but it's surely overkill for what is a rendering fault? Is there no way of increasing the precision of the engine somehow? If not, I'll gladly try a vertex shader if anyone has any sugestions (I'm really beginner with shaders myself so I wouldn't know how to write this). |
No, other than increasing the distance of the camera's near plane (which means objects very close to the camera may be culled). The default value is set quite low ( |
I have tried adjusting that and it still doesn't fix it, unfortunately. |
Does anybody know what format Godot uses for the depth buffer? Is it an 8bit UNORM/FLOAT? And I am guessing Godot doesn't store reverse depth? I am thinking this could be fixed for the majority of the screen by converting to depth to reverse floating point depth. But I am not too sure on godot's depth buffer implementation. |
I have a feeling this comes from the fact that we don't use It would be helpful if someone facing this issue could try testing with a version of the engine with the following line uncommented: godot/drivers/gles3/shaders/scene.glsl Line 361 in ac5d7dc
|
Again, not too familiar with the internals of Godot, but invariant tries to prevent variance in functional expression across different shaders. But since this is the same object instance z fighting with another object of the same instance, I don't see how adding invariant will fix the issue in this particular example. |
The only thing I can see where adding invariant works here is because Z prepass is a different shader than just the vertex shader of the object. In that case removing Z prepass from the options should also fix it, as a proof of concept. |
Godot uses a 24-bit depth buffer with standard ordering (see discussion in godotengine/godot-proposals#3539). Some GPUs fall back to a 32-bit depth buffer if they don't support 24-bit depth buffers, such as AMD GPUs on Vulkan. Reverse floating-point has many caveats for user-provided shaders that we may not want to impose on users, so I'm not sure if it's the way to go. |
Thanks! Yeah, there is never one perfect solution. The bane with game engines. The easiest solution I see here is for the user to have grid entries without the certain side walls depending on orientation so there wouldn't be any primitives even there to cause z fighting. Though as far as Godot is involved with fixing issues like this, I do think having different options available for users on depth buffer techniques is ideal. However, I won't hand wave the enormous work it would take to get all the advanced features that depend on reading depth values to work with the different techniques. |
If you mean having separate mesh entries for each wall, this is actually the least easy solution I would say, it would require at least two versions of every cell which would be an organisation nightmare, along with needing to ensure they were orientated correctly. In fact there might need to be three or four versions for corner walls in both directions (should rotating upside-down cause any texture issues visually). If you mean a shader, that would be fine but I don't think there'd be any way of knowing if a cell is occluded by another and have the shader hide the face. |
You don't need a mesh for each wall just a mesh for each cube with certain walls missing. But you wouldn't even need to place them yourself. You could just place the default cube like you already have it done. Then through a script, find all adjacent cubes to every cube, and replace the grid entry with the cube that doesn't have the unnecessary walls. |
At least six meshes for each cube (top face only, side left face only, side left and right face only, side left, side right and bottom face only, etc) and a custom script to manually figure out which walls are adjacent on which axis to fix a floating point precision rendering bug with the engine is definitely not the easiest solution? I don't even know if I'd be able to write a script that would make that work, it's almost like auto-tiling in 3 dimension! |
As a workaround, add a plane with an unshaded black material behind the area that exhibits fireflies. |
I don't think this is easily possible with gridmaps (or very performant)? |
Depending on how your GridMap is laid out, it may be possible to do so. You could make this black plane part of a GridMap cell itself or add a single large plane below the level. Performance-wise, rendering unshaded materials is fast. For indoor scenes, you can also change the background color to black. For hybrid indoor/outdoor scenes, you could use an Area3D node that detects when the player is deep enough into an interior and turn the background black while also disabling the DirectionalLight3D for added performance. |
If the gridmap cubes (which I'm using for example) are rotated it could cause problems, or the cubes themselves might have to be rotated so the plane appears on the correct side?
Is it an issue with the background showing through or is it the other face of the "voxel"? It seems so inconsistent I can't really figure out what it actually is. |
If your material has its cull mode set to Back (the default for materials created in the editor), it's the background showing through. If it's set to Disabled (the default for materials from imported glTF scenes as per its specification), it may be a backface showing through (but not always). |
Is there another workaround for this? I have a large outdoor cave with interior and it is very noticable when looking on the walls inside the cave, and trying to plug the holes with planes would require hundreds and hundreds of planes. |
Yes, change the background color dynamically as I mentioned in #79081 (comment). If you notice the color suddenly popping, smooth out the transition over time so that it's not too jarring. Many games like Minetest do that. |
I'm not sure I understand, you can see the sky from inside my cave and I have night and day cycle, changing the color of the sky would not be great. It is extra frustrating that it just seems to be some triangles that it happens to, many of them are solid as rocks! Another question I have is have I done something wrong when I see these fireflies? Or is this a bug? I don't see them inside blender when I create the mesh, I only see them inside Godot or in game (which also godot ofc) |
I suggest testing this change by recompiling the engine: #79081 (comment)
Please upload the |
I don't know how to compile myself, if someone can do it for me I will be more than willing to try it out! My blender file HAS some holes left over inside the cave from a conversion from trenchbroom, BUT I have this position where the I get issues without a doubt, it can be a bit hard to see in inside godot, but it is very clear in game Here is the blender file (it is saved so the camera is pointed directly on to the issue area) |
Which OS are you on? You can find instructions for compiling here. Godot is much easier to build than the average C++ project, since it includes all the required libraries in its source tree. |
I am on windows 11. I am compiling now, but according to git(hub) that line has been uncommented a year ago... at least in the master branch https://github.com/godotengine/godot/blame/master/drivers/gles3/shaders/scene.glsl#L299 EDIT: I have compiled from master, double checked that "invariant gl_Position;" was uncommented, which it was. |
Godot 4.1.1 Camera near plane 1.0m Z fighting happens with box meshes from the engine Flicker.mp4Replacing the gridmap with multiple box mesh instances has the same issue Changing the box mesh to a plane mesh removes the issue |
As per @jdies last post, I have been experiencing this when using the GridMap with cube tiles, including Godot box meshes with no texture applied. I've noticed it being much more noticeable than in the previous examples provided though. example.no_aa.mp4I have experienced it in 4.1.1, 4.1.2 and 4.1.3, only tested so far on Ubuntu 23.10. Something I have found to notably reduce the effect is anti-aliasing. Specifically, enabling a combination of TA and MSAA x4 almost eliminates it. There is still some flickering if you look closely, but nowhere near as noticeable as without any (see video below for example with TA enabled and MSAA x4): example.msaa4x.ta.mp4And as per @jdies last post - this doesn't seem to happen when using a plane mesh. I have uploaded a sample project here that the above videos were created from: https://github.com/RobTheFiveNine/godot-gridmap-flicker-demo |
For those using a texture atlas ("trim sheet"), I solved this problem in my project by contracting UVs by a half-pixel. I did this by attaching a custom script to my GLTF scene(s) that iterates through all mesh resources, modifies the UVs, and overwrites the mesh resources. I do not need antialiasing or multisampling in my project, but even with MSAA enabled there are no seams. @tool
extends EditorScenePostImport
const TEXTURE_SIZE := 256.0
const TEXEL := 1.0 / TEXTURE_SIZE
func _post_import(scene):
var mesh_tool = MeshDataTool.new()
_iterate(mesh_tool, scene)
return scene
func _iterate(mesh_tool: MeshDataTool, node):
if node is MeshInstance3D:
_process_mesh(mesh_tool, node.mesh)
for child in node.get_children():
_iterate(mesh_tool, child)
func _process_mesh(mesh_tool: MeshDataTool, mesh: ArrayMesh):
mesh_tool.create_from_surface(mesh, 0)
# iterate over faces one quad at a time
for face in range(0, mesh_tool.get_face_count() - 1, 2):
_contract_quad(mesh_tool, face)
# modify mesh
mesh.clear_surfaces()
mesh_tool.commit_to_surface(mesh, 0)
# overwrite existing mesh resource
ResourceSaver.save(mesh, mesh.resource_path, ResourceSaver.FLAG_COMPRESS)
func _contract_quad(mesh: MeshDataTool, face: int):
var uvs = {}
var center = Vector2(0.0, 0.0)
# iterate over all face (quad) vertices
for idx in range(6):
var fidx = wrapi(idx / 3, 0, 2)
var vidx = wrapi(idx, 0, 3)
var vertex = mesh.get_face_vertex(face + fidx, vidx)
var uv = mesh.get_vertex_uv(vertex)
center += uv * (1.0 / 6.0)
uvs[vertex] = uv
# compute half-pixel scaling factor
const factor = 1.0 - (TEXEL * 0.5)
# scale each UV towards the center (contraction)
for key in uvs:
mesh.set_vertex_uv(key, (uvs[key] - center) * factor + center) This script assumes:
|
This looks promising, I'm using a single texture applied to simple MeshInstances in the example, might it be possible this could work using separate textures or must they be atlases? |
This comment was marked as off-topic.
This comment was marked as off-topic.
@eben-vranken Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead. |
I was searching for solutions to this problem, and found that yesterday there was an article posted about "reverse Z" coming to 4.3: The technical information goes over my head, but do I understand correctly that this would fix the issue with seams/fireflies? |
It might help a little (particularly at long distances), but it won't resolve the issue entirely. |
Bugsquad note: This issue has been confirmed several times already. No need to confirm it further.
Godot version
3.5.2 RC2
System information
Windows 10, Vulkan, RTX 3060 (466.81)
Issue description
When moving the camera around meshes that are stacked, flashes that appear in strips of the side edge will show.
Steps to reproduce
2023-07-05.22-39-42.mp4
Minimal reproduction project
broken_seams.zip
The text was updated successfully, but these errors were encountered: