Issues with rewriting old voxel terrain generator

Hello Devforum, I haven’t made a scripting support post in a while but I decided to rewrite my voxel terrain generator but I’m having some issues currently.

I have never used region3 before and Terrain:WriteVoxels() and I’m running in some issues.

I am running command
require(game.ReplicatedStorage.rubysvoxelworldgen.chunkmod).loadchunk(workspace.CurrentCamera.CFrame.Position)
in the command bar to test a chunk loading function,
but I keep getting this error.

(screenshot: https://gyazo.com/859aec268e7e919207fbb53a5742667e)

> require(game.ReplicatedStorage.rubysvoxelworldgen.chunkmod).loadchunk(workspace.CurrentCamera.CFrame.Position)

[Chunk load time: 0.095962285995483]

[23:17:28.545 - Region cannot be empty]

23:17:28.545 - Stack Begin

[23:17:28.546 - Script 'ReplicatedStorage.rubysvoxelworldgen.chunkmod', Line 68]

23:17:28.546 - Script 'require(game.ReplicatedStorage.rubysvoxelworldgen.chunkmod).loadchunk(workspace.CurrentCamera.CFrame.Position)', Line 1

23:17:28.546 - Stack End
local wdat = require(script.Parent.worlddata) --The mod with all data.
local genmod = require(script.worldgenmod) --The mod used for the noise function, etc.
local chunkdat = wdat.chunkdata
local matdat = wdat.chunkmatdat

local terrain = workspace.Terrain
local runservice = game:GetService("RunService")

--Advanced world configuration
local chunkres = 6
local chunkresy = 10
local voxelres = 4

local mod = {}

local v3 = Vector3.new
local reg3 = Region3.new
local floor = math.floor

local function chunksnap(pos)
	return v3(
		floor((pos.x / chunkres) + 0.5) * chunkres,
		floor((pos.y / chunkresy) + 0.5) * chunkresy,
		floor((pos.z / chunkres) + 0.5) * chunkres
	) + v3(voxelres /2, voxelres / 2, voxelres / 2)
end

local function newreg(pos)
	pos = chunksnap(pos)
	local offset = v3(-(chunkres / 2) * voxelres, (chunkresy / 2) * voxelres, -(chunkres / 2) * voxelres)
	--Return a region3 along with a start position for writing chunks.
	return reg3(pos + offset, pos - offset):ExpandToGrid(voxelres), pos - offset
end

local noise = genmod.noise
mod.loadchunk = function(pos)
	local starttick = tick()
	local space, startpos = newreg(pos)
	
	local voxtab = {}
	local mattab = {}
	
	for x = 1, chunkres do --x
		for y = 1, chunkresy do --y
			for z = 1, chunkres do --z
				--Loop start
				local voxelpos = startpos + v3(x * voxelres, y * voxelres, z * voxelres)
				voxtab[x] = {}
				voxtab[x][y] = {}
				voxtab[x][y][z] = noise(voxelpos)
				
				mattab[x] = {}
				mattab[x][y] = {}
				mattab[x][y][z] = Enum.Material.Grass
				
				--Loop end
				--print("Repeated")
			end --z
		end --y
		runservice.Heartbeat:Wait()
	end --x --Ends of all x, y, z loops
	print("Chunk load time:", tick() - starttick)
	terrain:WriteVoxels(space, voxelres, mattab, voxtab)
end

return mod

It keeps telling me regions can’t be empty and such but I am pretty sure they aren’t empty, first time using region3 tbh so I’m uncertain, but I also don’t know where the issue is at.

I feel like maybe at where I am trying to set the start position offset or so for the chunk to load (this is so when you load a chunk the “center” of the chunk isn’t at the corner), but again I am very unsure about that.

My previous terrain generator just spams the FillBlock() function of terrain and I want a terrain generator that generates more beautiful and costs less performance, figured out I had to use WriteVoxels() for that assuming that’s faster than just spamming the FillBlock() function in a loop, it also has the advantage of being able to generate caves and more impressive mountains, overhangs, etc, it made my script spike to 90% activity and heats up my computer since it’s supposed to generate a infinite world in run time so you can explore for yourself.

1 Like

Do you have proof of that?

You have a flaw in your code, that I would like you to attempt discover yourself, so you can learn how to examine and understand what your code actually do - and not what you think it does.

Some hints, that you should use to discover the flaw:

  • Before calling WriteVoxels (the statement that errors) make sure you are actually providing it with the proper arguments. Do this by printing them to the Output-panel, so you yourself actually see what those arguments contain of values, to understand why “that function” writes an error like it does.
    Also remember to print out items within arrays (and those arrays’ items, etc.)

  • Remember that a computer will execute code statements literally in the sequence that you have written them in.
    So a good exercise would be, to mentally “execute” or “run” code statements line-by-line using your mind (possibly with help of notes on paper), while keeping track of which variables and arrays are being assigned new values at what time and such.

  • A 1-dimensional array is easy to understand how to use. But when working with 2-dimensional or higher array structures - in a language that has no easy ‘multidimensional indexing operator’ - be extra cautious that your code use/assign the items at the proper time.

  • Error is (likely) not related Region3, but has to do with your looping and variable assignments, before calling WriteVoxels.

  • Study the ‘WriteVoxels’ code sample (reading and writing voxels).

1 Like

Alright, thank you, I have now actually found out what the issue was.

None of the issues was with the looping or regions, it was perfect, the issue was with my snapping functions causing the grid to always be a little off, sometimes it would write the voxels but when the grid was about 2 studs off it would error due the grid not being correctly positioned,
but now I am basically running into the next issue, the next issue being that my chunks are now always positioned a bit off, the starting position has to be precise, otherwise chunks won’t connect/align up with each other correctly or are a bit off-center.
I am currently still figuring this out, if unable to fix I’ll post some screenshots and the updated code, terrain generation is quite complicated but I enjoy keeping myself busy with it and making some interesting stuff with it.

For so far I got everything working they way I wanted it to but the issue that I am now running into is terrain being extremely blocky and rough,
I actually want to smooth out the terrain a bit but I am unsure on how to do that and I feel like that due float point number imprecision that the voxel fullness might not be correct.

Is there a way for me to smooth out the voxels a bit more to make it look more like sculpted terrain while also still keeping it performant?

Edit: So far, i tried checking neighbor voxels to smooth it out a bit but I am unsure on how to do that so I did this.

local seed = 123.45

local amp = 100
local steepness = 100.827

local amp1 = 319.482
local steepness2 = 442.4826

local amp2 = 387.8

local cavetightness = 0.5


local terrainheight = 5


local noise = math.noise
local clamp = math.clamp
local floor = math.floor
local v3 = Vector3.new

local nbvoxels = {
	[1] = v3(0,0,4);
	[2] = v3(0,0,-4);
	[3] = v3(-4,0,0);
	[4] = v3(4,0,0);
	[5] = v3(0,4,0);
	[6] = v3(0,-4,0);
}

--local function lerp(a, b, c)
--	return a + (b - a ) * c
--end

local function noise3d(pos)
	return noise(
		(seed + pos.x) / amp1,
		(seed + pos.y) / amp1,
		(seed + pos.z) / amp1
	) + cavetightness
end

mod.terrainnoise = function(pos)
	pos = pos - v3(0, terrainheight, 0)
	
	local n3 = floor(noise3d(pos) + 0.49)
	for i = 1, 4 do
		if noise3d(pos + nbvoxels[i]) < 0.5 then
			n3 = n3 - 0.1
		else
				n3 = n3 + 0.1
		end
	end
	
	
	local n2 = noise(-(seed + pos.z) / steepness, seed, -(seed + pos.x) / steepness) * amp
	n2 = n2 * noise((seed + -pos.z) / steepness2, -seed, (seed + -pos.x) / steepness2)
	
	if (pos.y - terrainheight) > n2 then
		return 0, Enum.Material.Air
	end
	
	return n3, Enum.Material.Grass
end






return mod

Resulting in this.

1 Like