Tried this, unfortunately my laptop could not handle exporting the map from Gaea. It gets stuck on the erosion node. Too bad, this is quite amazing!
I found a better and less laggy way to do this, gaea unselect everything and click 2d, righth click the image and choose save as image now import it to roblox as a heightmap
It’s not a good practice, it’s working now, just super slow.
Thanks for the guidance, you helped me a lot
Just looking at these screenshots I thought you rendered it in Blender! I’ll definitely be trying this out for my project!
This is a great guide. Really nice work.
I have a suggestion that I feel would be of significant benefit:
Terrain:FillWedge suffers from artefacts and I see that you’ve worked around this somewhat by doing,
Vector3.new(thickness, part.Size.Y + 15, part.Size.Z + 15)
to increase overlap. (Though this still leaves a few artefacts and makes the terrain less smooth in some areas.)
Instead I recommend using my custom function which produces a much closer fit,
This should also work better in smaller spaces such as caves.
For reference, here’s an example of the better aesthetics achieved after switching to my method and removing your increase in wedge size to instead use the exact wedge size.
awesome stuff man, appreciate it.
I’ll take a look at this and consider switching to it after a few test runs! Thanks for your contribution.
I’ll give it a go as well, (I use this workflow everyday, has quite literally started my career,) and let you know of the results. Seems promising though.
Edit: @Quasiduck, it’s not exactly a viable option over the other one as it does not automatically paint materials based on height. That would be my recommended change. Other than that, it works like a charm.
I’d assume it’s still viable (I haven’t tried it myself yet), the only difference is that their code does not include my auto painting code. I’ll happily incorporate it once I get a chance… Life’s been busy lately!
Yeah, totally agree. It works well in the sense of creating the terrain, however due to the fact that it doesn’t auto paint, it’s just not an option for this type of workflow. I’ve actually got a few other suggestions myself, I’d be happy to share them via DMs.
I didn’t mean replace the entirety of @Vexture 's code with just my FillWedge.
I meant replace only the terrain:FillWedge part of his code with my custom function + use exact wedge size rather than adding on 15. That way you get the accurate fillwedge + the painting (based on steepness) that you desire. This is the code if I add in those edits:
local rate = .00001
local RunService = game:GetService("RunService")
local whitelist = workspace.Mesh:GetChildren()
local thickness = nil --No need to set this anymore. Terrain thickness will just depend on each wedgePart.Size.X.
local sea_level = .125 --From 0 to 1, where 0 is the lowest elevation of the map and 1 is the highest (gets denormalized in terms of the relative elevations of your map automatically)
local regionIncrement = 1024
function FillWedge(wedgeCFrame, wedgeSize, material) --Custom FillWedge with advantages over terrain:FillWedge
local terrain = workspace.Terrain
local Zlen, Ylen = wedgeSize.Z, wedgeSize.Y
local longerSide, shorterSide, isZlonger
if Zlen > Ylen then
longerSide, shorterSide, isZlonger = Zlen, Ylen, true
else
longerSide, shorterSide, isZlonger = Ylen, Zlen, false
end
local closestIntDivisor = math.max(1, math.floor(shorterSide/3))
local closestQuotient = shorterSide/closestIntDivisor
local scaledLength = closestQuotient*longerSide/shorterSide
local cornerPos = Vector3.new(0, -Ylen, Zlen)/2
for i = 1, closestIntDivisor - 1 do
local longest_baselen = (closestIntDivisor-i)*scaledLength
local size, cf = Vector3.new(math.max(3, wedgeSize.X), closestQuotient, longest_baselen)
if isZlonger then
cf = wedgeCFrame:toWorldSpace(CFrame.new(cornerPos) + Vector3.new(0, (i-0.5)*closestQuotient, -longest_baselen/2))
else
cf = wedgeCFrame:toWorldSpace(CFrame.Angles(math.pi/2, 0, 0) + cornerPos + Vector3.new(0, longest_baselen/2, -(i-0.5)*closestQuotient))
end
terrain:FillBlock(cf, size, material)
end
local diagSize = Vector3.new(math.max(3, wedgeSize.X), closestQuotient*scaledLength/math.sqrt(closestQuotient^2 + scaledLength^2), math.sqrt(Zlen^2 + Ylen^2)) --Vector3.new(3, 3, math.sqrt(Zlen^2 + Ylen^2))
local rv, bv = wedgeCFrame.RightVector, -(Zlen*wedgeCFrame.LookVector - Ylen*wedgeCFrame.UpVector).Unit
local uv = bv:Cross(rv).Unit
local diagPos = wedgeCFrame.p - uv*diagSize.Y/2
local diagCf = CFrame.fromMatrix(diagPos, rv, uv, bv)
terrain:FillBlock(diagCf, diagSize, material)
end
local function TimerWait(duration) --Framerate-dependent function that waits at the theoretically lowest possible step, Heartbeat:Wait(), until some time dt has passed.
local start = tick()
repeat RunService.Heartbeat:Wait() until tick() - start >= duration
return true
end
local function MinMaxAvg(data)
local min, max, average = data[1], data[#data], 0
for _, element in pairs(data) do
if element < min then
min = element
end
if element > max then
max = element
end
average = average + element
end
average = average / #data
return min, max, average
end
local function Normalize(Min, Max, Val)
local Normal = (Val - Min) / (Max - Min)
return Normal
end
local function Denormalize(Min, Max, Val)
local Denormal = (Val * (Max - Min)) + Min
return Denormal
end
local function ConvertTerrain()
local data = {}
for _, part in pairs(whitelist) do
table.insert(data, part.Position.Y)
if tick() % 5 > 4.5 then
TimerWait(rate)
end
end
local min, max, average = MinMaxAvg(data)
local orient, extents = workspace.Mesh:GetBoundingBox()
local MeshCenter, MeshSize = workspace.Mesh:GetModelCFrame().p, workspace.Mesh:GetExtentsSize()
local LowerBound = Vector3.new(MeshCenter.X - MeshSize.X/2, MeshCenter.Y - MeshSize.Y/2, MeshCenter.Z - MeshSize.Z/2)
local UpperBound = Vector3.new(MeshCenter.X + MeshSize.X/2, Denormalize(min, max, sea_level), MeshCenter.Z + MeshSize.Z/2)
--Enable for automatic sea level filling based on sea_level variable (VERY slow, recommend using Roblox's sea level method instead. My version of this functionality isn't complete.
--(It's also not guaranteed that it will be aligned with your map. That's why it's off by default.)
--[[for x = LowerBound.X, UpperBound.X, regionIncrement do
for z = LowerBound.Z, UpperBound.Z, regionIncrement do
if tick() % 5 > 4.5 then
TimerWait(rate)
end
for y = LowerBound.Y, UpperBound.Y, regionIncrement do
local Lower = Vector3.new(x, y, z)
local Upper = Vector3.new(x + regionIncrement, y + regionIncrement, z + regionIncrement)
local WaterRegion = Region3.new(Lower, Upper)
workspace.Terrain:FillRegion(WaterRegion:ExpandToGrid(4), 4, Enum.Material.Water)
end
end
end]]--
for _, part in pairs(whitelist) do
local Material
local cf, pos, size = part.CFrame, part.CFrame.p, part.Size --Vector3.new(thickness, part.Size.Y, part.Size.Z)
if math.abs(90 - math.abs(part.Orientation.Z)) > 35 or math.abs(0 - math.abs(part.Orientation.X)) > 35 then
Material = Enum.Material.Rock
else
Material = Enum.Material.Grass
end
if pos.Y < Denormalize(min, max, sea_level) + 6 then
if Material == Enum.Material.Grass then
Material = Enum.Material.Sand
elseif Material == Enum.Material.Rock then
Material = Enum.Material.Slate
end
end
FillWedge(cf, size, Material)
part:Destroy()
if tick() % 5 > 4.5 then
TimerWait(rate)
end
end
end
ConvertTerrain()
Here’s also a repo comparing the above edits to before:
(Disable new script and enable old script to compare the difference)
(You’ll notice the old version has a lot of holes & artefacts and appears a lot more jagged-looking. The new version is a lot smoother and preferable visually.)
CustomFillWedgeDemo.rbxl (340.8 KB)
I’ll give the new one a shot today, thank you!
Edit: Oops, autocorrect.
All I can say is WOW. Your method is amazing! I highly recommend using it over terrain:FillWedge
! Thank you so much!
Dang my PC only has an i3. Guess I’ll have to use someone else’s.
Very helpful guide, this is just what I was looking for.
I think it would work, my computer is a potato, and while it’s laggy and takes and hour or 2, it does work.
Alright, I’ll try it. Hope it works and my PC doesn’t blow up.
I just discovered the select all feature in Notepad while coyping the terrain.
Can Gaea run on lower end PCs? Gaea says I need this:
- Intel® i7 or similar
- 24GB RAM (32GB recommended)
- 10GB HDD space
- GPU with 1GB VRAM, Shader Model 3, DirectX 11 support
I have an i5 processer and 16 GB, can I still run it?
You should be fine. Gaea expects heavier workloads in general than what you’ll need for roblox.