Zylann / godot_voxel

Voxel module for Godot Engine
MIT License
2.72k stars 251 forks source link

VoxelTool.do_* functions do not ignore VoxelModifier on terrain #665

Closed Piratux closed 5 months ago

Piratux commented 5 months ago

Describe the bug When trying to edit terrain with VoxelTool, the result depends on whether there was VoxelModifier in the area of edit. Effects of this can be noticed when stamping a shape with higher SDF scale.

To show an example:

To Reproduce Steps to reproduce the behavior:

  1. Just open up MRP, run the game and press space on keyboard (If this won't work I'll write more precise steps).

Expected behavior SDF values after an edit should be the same with or without VoxelModifier nodes in the edited area.

Environment

MRP Test VoxelMeshSDF stamp with VoxelModifierMesh.zip

Zylann commented 5 months ago

I think you're using the wrong SDF scale for your stamped SDF, and that's affecting the result. It's a unit sphere you scaled by 30, but you scaled its distance field by 500, which is 16 times too much. If you use the same scale 30, the issue is much less (if at all) noticeable:

image

Now I'm less sure about why the presence of a modifier affects it, but that might have to do with differences in gradient (one sphere is placed in an area that was already full of air so it's less prone to incorrect SDF, but the other one is placed in an area that has much closer distances so it matters more, especially since the added shape has zero-crossings in the same locations).

Here is how the SDF looks like initially (bright yellow=10, bright blue=-10): before0

When you use scale 500, you get this: after0 The right sphere doesnt end up looking bad because voxels above its surface can keep going with a "fast" gradients since there was no existing surface nearby (SDF keeps going beyond 10, the debug image doesn't show that). But the left sphere had one, so gradients go fast from the center of the sphere but suddenly have to "slow down" sharply above the surface since that's the closer values to the sphere that was originally there (the Add operation does a SDF union which uses the min operator). I suspect that discontinuity is causing the blockyness.

You'll even notice the same problem if you chain these two, without a modifier:

    voxel_tool.stamp_sdf(voxel_mesh_sdf, transform.translated(Vector3(50,0,0)), 0, 30)
    voxel_tool.stamp_sdf(voxel_mesh_sdf, transform.translated(Vector3(50,0,0)), 0, 500)

But if you use scale 30, you get this: after0 Which is pretty much the result you expected.

Piratux commented 5 months ago

Yes, I'm aware that I'm using different scales (there are reasons why I'm doing this, but it's a bit out of scope for this issue) and why the issue happens. Roughly speaking With sdf scale = 1 values are: A = [.., -2, -1, 0, 1, 2, ..]

With sdf scale = 1 values are: B = [.., -20, -10, 0, 10, 20, ..]

Thus, SDF_UNION(A, B) = MIN(A, B) = [.., -20, -10, 0, 1, 2, ..] Which causes unwanted blocky look.

My main point with this report, is that, presence of modifier should not affect the result (after all, it's intended to be non-destructive preview of the mesh).

Zylann commented 5 months ago

Unfortunately this cannot be "fixed", the problem is you're expecting that using wrong SDF alongside correct SDF to behave correctly, which can't happen.

stamp_sdf is a destructive operation, and you're using Add, so what was there earlier will affect the result. Modifiers act like "local generator extensions", therefore they are only applied in non-edited areas, before edits. Once the area becomes edited, they are frozen on it, with your destructive edit being done on top. Even if that order was somehow reversed and the modifier was applied on top of everything, it would not solve your issue because min(a, b) == min(b, a).

Piratux commented 5 months ago

I should have mentioned in an initial issue, that I expected the sphere on the left to be smooth again, after moving VoxelModifier away as I thought it was applied last.

However, now knowing that modifiers are to be treated as part of terrain this behavior is to be expected.

So this is not an issue.