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

Z fighting with voxel rendering #79081

Open
elvisish opened this issue Jul 5, 2023 · 47 comments
Open

Z fighting with voxel rendering #79081

elvisish opened this issue Jul 5, 2023 · 47 comments

Comments

@elvisish
Copy link

elvisish commented Jul 5, 2023


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

  • Add a box with a texture that has a lighter side than the facing side.
  • Move the camera around to observe the flickering.
2023-07-05.22-39-42.mp4

Minimal reproduction project

broken_seams.zip

@elvisish
Copy link
Author

elvisish commented Jul 5, 2023

Some related issues:
#16337
#67673
godotengine/godot-proposals#651
#27837
#35067
Zylann/godot_voxel#510
Zylann/godot_voxel#96

@lawnjelly
Copy link
Member

lawnjelly commented Jul 6, 2023

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:

  • Geometric gaps
  • Texture sampling

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.

@lawnjelly
Copy link
Member

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.

@elvisish
Copy link
Author

elvisish commented Jul 6, 2023

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.

Here's a version using a texture for a single face and a shader that darkens each wall depending on it's facing direction:
broken_seams_shader.zip

It's also exhibits the same issue:

2023-07-06.08-41-27-00.00.01.543-00.00.07.424.mp4

The 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?

@lawnjelly
Copy link
Member

lawnjelly commented Jul 6, 2023

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:
This is quite a weird one, and I suspect it is GPU precision issue. What I think is happening is your shader has abrupt shading depending on the normal, in your second project (above post) most of the blocks are near 0 lightness, but occasionally you are getting lines of near 1 lightness appearing. I'm suspecting that the "left / right" faces are occasionally poking through due to numerical error and you are seeing their pixels overwrite the pixels from the front facing ones.

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:
Yes you can also get sparklies in the editor by setting the editor viewport to:
View Z near 0.01
View Z far 50000

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.

sparklies

sparklies

The term often used for this is "z fighting". Some ideas to help alleviate it:

  • Modify your camera near and far to make best use of the z range
  • Merge and remove internal walls in your geometry

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.

@elvisish
Copy link
Author

elvisish commented Jul 6, 2023

Modify your camera near and far to make best use of the z range

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.

Merge and remove internal walls in your geometry

I'm using gridmaps so this is impossible, unfortunately.

@lawnjelly
Copy link
Member

You might also be able to use some hackery to get around this. Some ideas:

  • Make the cube in blender, and contract the faces just a tad so they almost match up. This may help z fighting, but in exchange you might get gaps.
  • Modify the vertex shader .. if the normal of the vertex in camera space is to the side of the camera (rather than front on), then push the vertex slightly away from the camera.

@elvisish
Copy link
Author

elvisish commented Jul 6, 2023

  • Modify the vertex shader .. if the normal of the vertex in camera space is to the side of the camera (rather than front on), then push the vertex slightly away from the camera.

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).

@lawnjelly lawnjelly changed the title Mesh edge rendering seam flashes line of edge texture Z fighting with voxel rendering Jul 6, 2023
@fracteed
Copy link

fracteed commented Jul 7, 2023

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.
https://www.blendermarket.com/products/vox-importer

@elvisish
Copy link
Author

elvisish commented Jul 7, 2023

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. https://www.blendermarket.com/products/vox-importer

They're not voxels, I'm not sure why the title was changed, I'm just using MeshInstance cubes.

@fracteed
Copy link

fracteed commented Jul 7, 2023

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.

@elvisish
Copy link
Author

elvisish commented Jul 7, 2023

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.

@fracteed
Copy link

fracteed commented Jul 7, 2023

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?

@elvisish
Copy link
Author

elvisish commented Jul 7, 2023

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).

scaled to 0.99

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.

@elvisish
Copy link
Author

elvisish commented Jul 8, 2023

  • Make the cube in blender, and contract the faces just a tad so they almost match up. This may help z fighting, but in exchange you might get gaps.

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).

@Calinou
Copy link
Member

Calinou commented Jul 8, 2023

Is there no way of increasing the precision of the engine somehow?

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 (0.05) – most other engines use something that would be akin to 0.1.

@elvisish
Copy link
Author

elvisish commented Jul 8, 2023

Is there no way of increasing the precision of the engine somehow?

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 (0.05) – most other engines use something that would be akin to 0.1.

I have tried adjusting that and it still doesn't fix it, unfortunately.

@M0liusX
Copy link

M0liusX commented Jul 8, 2023

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.

@clayjohn
Copy link
Member

clayjohn commented Jul 9, 2023

I have a feeling this comes from the fact that we don't use invariant positions in the vertex shader. We had to disable it to work around a MESA bug.

It would be helpful if someone facing this issue could try testing with a version of the engine with the following line uncommented:

//invariant gl_Position;

@M0liusX
Copy link

M0liusX commented Jul 9, 2023

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.

@M0liusX
Copy link

M0liusX commented Jul 9, 2023

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.

@Calinou
Copy link
Member

Calinou commented Jul 9, 2023

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.

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.

@M0liusX
Copy link

M0liusX commented Jul 9, 2023

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.

@elvisish
Copy link
Author

elvisish commented Jul 9, 2023

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.

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.

@M0liusX
Copy link

M0liusX commented Jul 9, 2023

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.

@elvisish
Copy link
Author

elvisish commented Jul 9, 2023

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!

@knil79
Copy link

knil79 commented Nov 6, 2023

I can confirm that this is still a problem as of godot 4.2-beta4

Fireflies seems to happen on some edges but not others, I dont understand why, all the edges are the same mesh all vertices are connected, normals are normal. It does not show up in blender.

No shader used just a normal BaseMaterial3D

image

@Calinou
Copy link
Member

Calinou commented Nov 7, 2023

As a workaround, add a plane with an unshaded black material behind the area that exhibits fireflies.

@elvisish
Copy link
Author

elvisish commented Nov 7, 2023

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)?

@Calinou
Copy link
Member

Calinou commented Nov 7, 2023

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.

@elvisish
Copy link
Author

elvisish commented Nov 7, 2023

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.

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?

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.

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.

@Calinou
Copy link
Member

Calinou commented Nov 7, 2023

Is it an issue with the background showing through or is it the other face of the "voxel"?

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).

@knil79
Copy link

knil79 commented Nov 8, 2023

As a workaround, add a plane with an unshaded black material behind the area that exhibits fireflies.

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.

@Calinou
Copy link
Member

Calinou commented Nov 8, 2023

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.

@knil79
Copy link

knil79 commented Nov 8, 2023

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!

image

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)

@Calinou
Copy link
Member

Calinou commented Nov 8, 2023

I suggest testing this change by recompiling the engine: #79081 (comment)

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)

Please upload the .blend file somewhere so we can have a look (you don't need to include textures/materials).

@knil79
Copy link

knil79 commented Nov 8, 2023

I suggest testing this change by recompiling the engine: #79081 (comment)

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)

Please upload the .blend file somewhere so we can have a look (you don't need to include textures/materials).

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

image
image

Here is the blender file (it is saved so the camera is pointed directly on to the issue area)
island_tile_start.zip

@Calinou
Copy link
Member

Calinou commented Nov 8, 2023

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!

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.

@knil79
Copy link

knil79 commented Nov 8, 2023

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!

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.

still looks like this
image

@jdies
Copy link

jdies commented Nov 9, 2023

Godot 4.1.1
Win 10
Vulkan

Camera near plane 1.0m
Camera far plane 100.0m
Grid map cell size: 1x1x1
Cube mesh size: 1x1x1

Z fighting happens with box meshes from the engine

Flicker.mp4

Replacing the gridmap with multiple box mesh instances has the same issue

Changing the box mesh to a plane mesh removes the issue

@RobTheFiveNine
Copy link
Contributor

RobTheFiveNine commented Nov 17, 2023

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.mp4

I 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.mp4

And 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

@chutchinson
Copy link
Contributor

chutchinson commented Dec 13, 2023

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:

  • Texture atlas size is 256x256
  • Meshes are composed of exactly one surface
  • Mesh UVs are composed of quads (2 triangles per face, 6 vertices total)
  • Mesh UVs are snapped to pixels
  • Mesh resources are saved to individual files (not using inherited scene)

@elvisish
Copy link
Author

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:

  • Texture atlas size is 256x256
  • Meshes are composed of exactly one surface
  • Mesh UVs are composed of quads (2 triangles per face, 6 vertices total)
  • Mesh UVs are snapped to pixels
  • Mesh resources are saved to individual files (not using inherited scene)

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?

@eben-vranken

This comment was marked as off-topic.

@Calinou
Copy link
Member

Calinou commented Apr 22, 2024

@eben-vranken Please don't bump issues without contributing significant new information. Use the 👍 reaction button on the first post instead.

@Calinou Calinou changed the title Z fighting with voxel rendering Visible seams/sparkly dots between meshes placed next to each other Apr 22, 2024
@Calinou Calinou changed the title Visible seams/sparkly dots between meshes placed next to each other Z fighting with voxel rendering Apr 22, 2024
@Kurpotato
Copy link

I was searching for solutions to this problem, and found that yesterday there was an article posted about "reverse Z" coming to 4.3:
https://godotengine.org/article/introducing-reverse-z/

The technical information goes over my head, but do I understand correctly that this would fix the issue with seams/fireflies?

@Calinou
Copy link
Member

Calinou commented Apr 30, 2024

I was searching for solutions to this problem, and found that yesterday there was an article posted about "reverse Z" coming to 4.3:

It might help a little (particularly at long distances), but it won't resolve the issue entirely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: For team assessment
Development

No branches or pull requests