Write & read terrain giving (slightly) incorrect info

I’m using the functions Terrain:ReadVoxels() and Terrain:WriteVoxels(). What I’m trying to do is read one area of terrain, and then copy that over somewhere else. While this does work, it isn’t perfect. You probably can’t tell from the image, but closer up it’s more obvious. I also checked to see if it was just me, by reading both pieces of terrain using the ReadVoxels function, and they were different.

Notes:

  • Both regions are the same size
  • Both regions are the same orientation
  • I’m never changing the “materials” or “occupancies” given by the ReadVoxels function
  • The code provided is the only piece of code in the whole game

Code
--// Services

local Terrain = workspace.Terrain


--// Variables

local region1Part = workspace.Region1
local region2Part = workspace.Region2


--// Constants

local RESOLUTION = 4


--// Functions

local function roundVector3(vector, toNearest)
	return Vector3.new(
		math.round(vector.X / toNearest) * toNearest,
		math.round(vector.Y / toNearest) * toNearest,
		math.round(vector.Z / toNearest) * toNearest
	)
end

local function roundSize(part, toNearest)
	part.Size = roundVector3(part.Size, RESOLUTION)
end


--// Main

roundSize(region1Part, RESOLUTION)
roundSize(region2Part, RESOLUTION)

local readPos1 = roundVector3(region1Part.Position - (region1Part.Size/2), RESOLUTION)
local readPos2 = roundVector3(region1Part.Position + (region1Part.Size/2), RESOLUTION)


local readRegion = Region3.new(readPos1, readPos2)
local materials, occupancies = workspace.Terrain:ReadVoxels(readRegion, RESOLUTION)



local writePos1 = roundVector3(region2Part.Position - (region2Part.Size/2), RESOLUTION)
local writePos2 = roundVector3(region2Part.Position + (region2Part.Size/2), RESOLUTION)

local writeRegion = Region3.new(writePos1, writePos2)
workspace.Terrain:WriteVoxels(writeRegion, RESOLUTION, materials, occupancies)


---------
task.wait(2)
local _materials, _occupancies = workspace.Terrain:ReadVoxels(writeRegion, RESOLUTION)
warn(materials == _materials, occupancies == _occupancies) -- prints false false

To be honest I don’t know if this is me or Roblox (because I’m not changing any values) but wanted to be sure before posting something in studio bugs (could also be some kind of limitations, I don’t know)

1 Like

Bump because no one replied

I am possibly not the best person to reply to this (I’ve not played around with terrain much) but from what I can tell this is either Roblox generating terrain using Terrain:WriteVoxels slightly differently from manually creating terrain using TerrainEditor, or something to do with using math.round (probably the latter).

Rounding the terrain to a certain number probably removes the tiny weird quirks in the terrain of using the manual editor, meaning the copied terrain would be different. Now I don’t know how you would work around it, but that’s just what I get from a first impression of what your issue could be

Hope this helps

2 Likes

I thought about that too, but I’m only rounding the region’s size and position, instead of the actual terrain info, so I don’t think that’s it, but honestly I’m not really sure

Probably an issue with Roblox then. I can’t spot anything else in your code that would cause the copied terrain to alter

Last time I’ll reply to this to see if anyone knows how to fix, or at least put something here:

  • Roblox bug
  • Roblox limitations
  • Incorrect code

0 voters

I’m interested in this problem. First off, you do have a bug in your code – you attempt to compare two tables using the == operator, but this won’t work, as tables only compare equal if they’re the exact same object (that is, occupy the same memory). You have to do an element-by-element comparison. In fact, since this is a 3D array, you’ll need to do a triple-nested element-by-element comparison.

Second, there’s a chance the terrain renders differently based on the unseen boundaries. Roblox’s engine probably processes terrain blocks on a chunk-by-chunk basis, and they probably picked a power of two for their chunks. Try doing this with:

region1 going from <0, 0, 0> to <64, 64, 64>
region2 going from <256, 0, 0> to <320, 64, 64>

If this fixes the problem, then you know… it’s a roblox limitation.