when i click where the green dot is here you can see where the terrain is raised to the right. its only the first two rows from the bottom that cause this bug. everywhere else the tool works as intended
all the other vertices outside the red circle raise when i click them. and all the ones in the red circle act like the one in the first picture.
i know my raytracing works. as it tells me its location as well as the global and local positions of where i click and they are right . even in the code it says its raising the vertices at the right global and local position but when i click on one of the vertices in the circle it raises a different one. i would add my sculpting function but its really long. maybe its the extra floating point numbers after global and local positions that are messing it up. ill test that right now.
this is the code i am using for raising height. its actually a lot longer i just got the relevant parts.
for chunk in affected_chunks:
var mesh: Mesh = chunk.mesh
var arrays: Array = mesh.surface_get_arrays(0)
var vertices: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
for z in range(vertex_count):
for x in range(vertex_count):
var local_x: float = x * resolution
var local_z: float = z * resolution
var index: int = x + z * vertex_count
var global_vertex_pos: Vector3 = chunk.to_global(Vector3(local_x, vertices[index].y, local_z))
var vertex_pos: Vector2 = Vector2(global_vertex_pos.x, global_vertex_pos.z)
var dist: float = vertex_pos.distance_to(global_brush_center)
var snapped_dist: float = Vector2(snapped_pos.x, snapped_pos.z).distance_to(Vector2(local_x, local_z))
var is_boundary: bool = x == 0 or x == vertex_count - 1 or z == 0 or z == vertex_count - 1
var row: int = z
var col: int = x
if dist < min_dist:
min_dist = dist
closest_index = index
if dist <= brush_radius:
var height_change: float = intensity * (1.0 if raise else -1.0) * get_process_delta_time()
var new_height: float = clamp(vertices[index].y + height_change, -height_scale, height_scale)
var global_key := Vector2(global_vertex_pos.x, global_vertex_pos.z)
vertex_updates[global_key] = new_height
# Apply vertex updates
if vertex_updates.size() > 0 and current_time - last_mesh_update >= MESH_UPDATE_INTERVAL:
for chunk in affected_chunks:
var mesh: Mesh = chunk.mesh
var arrays: Array = mesh.surface_get_arrays(0)
var vertices: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX]
var uvs: PackedVector2Array = arrays[Mesh.ARRAY_TEX_UV]
var chunk_modified: bool = false
for z in range(vertex_count):
for x in range(vertex_count):
var local_x: float = x * resolution
var local_z: float = z * resolution
var index: int = x + z * vertex_count
var global_vertex_pos: Vector3 = chunk.to_global(Vector3(local_x, vertices[index].y, local_z))
var global_key: Vector2 = Vector2(global_vertex_pos.x, global_vertex_pos.z)
var closest_key: Vector2 = global_key
var min_key_dist: float = INF
for key in vertex_updates:
var dist: float = global_key.distance_to(key)
if dist < min_key_dist and dist < 0.1:
min_key_dist = dist
closest_key = key
if vertex_updates.has(closest_key):
var new_height: float = vertex_updates[closest_key]
if abs(vertices[index].y - new_height) > 0.001:
vertices[index].y = new_height
chunk_modified = true
var is_boundary: bool = x == 0 or x == vertex_count - 1 or z == 0 or z == vertex_count - 1
var row: int = z
var col: int = x
You could probably simplify that a lot if you wanted to, and probably optimize a bunch as well.
For example, when you’re doing “which is closest” with distance checks, you can use distance_squared; it’ll eliminate a square root per vertex but produce the same result.
You can also do:
var index: int = 0
var local_x: float = 0.0
var local_z: float = 0.0
for z: int in vertex_count:
for x: int in vertex_count:
# Do your stuff here; x, z, local_x, local_z and index should all be
# correct, but not nearly as expensively calculated.
local_x += resolution
index += 1
local_x = 0.0
local_z += resolution
I think, though, you might want to experiment with snappedf() to calculate the vector offset without looping over the mesh.
As for the actual problem I’ve been ignoring, I’m wondering if it’s some bad interaction with whatever code is operating on is_boundary? I’m wondering if what’s happening is, the collision point is slightly off the mesh and “out of bounds”, and is getting corrected to the wrong place.
thank you for the helpful tips i will look into those changes I am still new to voxels. i probably should of started with something simpler. but i like learning the hard way . you were right it was an indexing problem. I was using “var index: int = x + z * vertex_count” as that is what i used to build the terrain to find the vertices but pulling the vertices directly from mesh using this “var vertices: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]” does not put them in the same order. that was the problem but adding this bit of code fixed it as it indexes based on vertices location
var vertex_index_map: Dictionary = {}
for index in range(vertices.size()):
var vertex_pos: Vector3 = vertices[index]
var local_x: float = round(vertex_pos.x / resolution) * resolution
var local_z: float = round(vertex_pos.z / resolution) * resolution
vertex_index_map[Vector2(local_x, local_z)] = index