Last active
November 19, 2021 00:10
-
-
Save Domiii/5b5ca24513314ef1c7f798c2d2d16493 to your computer and use it in GitHub Desktop.
Import real world terrain into Roblox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Steps: | |
1. Download heightmap Bitmap | |
e.g. from terrain.party: http://terrain.party/api/export?name=guarda&box=10.186055,46.850130,10.080975,46.778264) | |
e.g. from earthe | |
Data Sets: NASA LPDAAC Collections -> NASA SRTM (SRTM 3) Collections | |
2. Use this site to convert BMP to Lua: https://codepen.io/Domiii/pen/oMJvoJ?editors=0010 | |
3. Copy the final Lua code to workspace.TerrainPixels (ModuleScript) | |
4. Run this script! | |
]] | |
local MaxHeight = 1800 | |
local VoxelSize = 1 | |
local MaxPixelValue = 255 | |
local Resolution = 1 -- only use every 4th pixel | |
-- xLen = 100 | |
-- zLen = 100 | |
local VoxelVectorSize = Vector3.new(VoxelSize, VoxelSize, VoxelSize) | |
local origin = Vector3.new(0, 0, 0) | |
function GenerateMountain(origin, xLen, zLen, height) | |
for i = 1, xLen do | |
for j = 1, zLen do | |
local y = math.random() * height | |
--print(y) | |
for k = 1, y do | |
--local size = Vector3.new(Amount*Amount-(i*10),Y*(i*2),Amount*Amount-(i*10)) | |
--local pos = pos + Vector3.new(i * VoxelSize, k*VoxelSize, j*VoxelSize) | |
local pos = origin + Vector3.new(i*VoxelSize, k*VoxelSize, j*VoxelSize) | |
game.Workspace.Terrain:FillBlock(CFrame.new(pos), VoxelVectorSize, Enum.Material.Rock) | |
end | |
end | |
end | |
end | |
local cancelName = 'TerrainCancel' | |
local guiName = 'TerrainGenStatusGui' | |
local cancelledRef | |
local gui | |
local statusLabel | |
function Cleanup() | |
if game.StarterGui:FindFirstChild(guiName) then | |
game.StarterGui:FindFirstChild(guiName):Destroy() | |
end | |
if workspace:FindFirstChild(cancelName) then | |
workspace:FindFirstChild(cancelName):Destroy() | |
end | |
end | |
function GetProgressPercent(current, max) | |
return current / max * 100 | |
end | |
function UpdateStatus(current, max) | |
local progressPct = GetProgressPercent(current, max) | |
statusLabel.Text = tostring(math.floor(progressPct + 0.5)) .. '%' | |
end | |
function ShowTerrainGui() | |
gui = Instance.new('ScreenGui') | |
gui.Name = guiName | |
statusLabel = Instance.new('TextLabel') | |
statusLabel.Parent = gui | |
statusLabel.Size = UDim2.new(1, 0, 0, 30) | |
gui.Parent = game.StarterGui | |
cancelledRef = workspace:FindFirstChild(cancelName) | |
if not cancelledRef then | |
cancelledRef = Instance.new('BoolValue') | |
cancelledRef.Name = cancelName | |
cancelledRef.Parent = workspace | |
end | |
cancelledRef.Value = false | |
-- select the Cancel object | |
local select = { cancelledRef } | |
game.Selection:Set(select) | |
end | |
function CheckCancel() | |
if cancelledRef and cancelledRef.Value then | |
print('Terrain Generation Cancelled') | |
Cleanup() | |
return true | |
end | |
return false | |
end | |
function GetMaterial(yNormalized) | |
local material | |
if yNormalized < 0.4 then | |
material = Enum.Material.Grass | |
elseif yNormalized < 0.8 then | |
material = Enum.Material.Rock | |
else | |
material = Enum.Material.Snow | |
end | |
return material | |
end | |
function GenTerrainFromHeightmap(origin) | |
local pixels = require(workspace.TerrainPixels:Clone()) | |
local xLen = #pixels | |
local zLen = #pixels[1] | |
Cleanup() | |
ShowTerrainGui() | |
workspace.Terrain:Clear() | |
for i = 1, xLen, Resolution do | |
local row = pixels[i] | |
for j = 1, zLen, Resolution do | |
local px = row[j] | |
local yNormalized = px / MaxPixelValue | |
local material = GetMaterial(yNormalized) | |
y = yNormalized * MaxHeight | |
--for k = 1, y do | |
local pos = origin + Vector3.new(i*VoxelSize, 0, j*VoxelSize) | |
local size = Vector3.new(VoxelSize, y * VoxelSize, VoxelSize) | |
game.Workspace.Terrain:FillBlock(CFrame.new(pos), size, material) | |
--end | |
end | |
if CheckCancel() then return end | |
UpdateStatus(i, xLen) | |
wait() | |
end | |
print('Terrain Generation Finished!') | |
Cleanup() | |
end | |
--GenTerrainFromHeightmap(origin, pixels) | |
--GenerateMountain(origin, xLen, zLen, height) | |
function GenTerrainBetweenParts(basePart) | |
Cleanup() | |
ShowTerrainGui() | |
workspace.Terrain:Clear() | |
local material = Enum.Material.Grass | |
local size = basePart.Size | |
local pos1 = basePart.Position - size / 2 | |
local pos2 = pos1 + size | |
local y = basePart.Position.Y + size.Y | |
--local y = (pos1.Y + pos2.Y) / 2 | |
local up = Vector3.new(0, 1, 0) | |
for z = pos1.Z, pos2.Z do | |
for x = pos1.X, pos2.X do | |
local origin = Vector3.new(x, y, z) | |
local ray = Ray.new(origin, origin + up * 100000) | |
local terrainCellsAreCubes = false | |
local ignoreWater = true | |
local part, pos, normal, material2 = workspace:FindPartOnRay ( | |
ray, | |
basePart, | |
terrainCellsAreCubes, | |
ignoreWater | |
) | |
--print(x,y,z, part, pos, normal, material2) | |
-- local p = Instance.new('Part') | |
-- p.Shape = Enum.PartType.Ball | |
-- p.Position = origin | |
-- p.Parent = workspace.Tmp | |
--if part then | |
local blockSize = Vector3.new(1, (pos - origin).Y, 1) | |
-- NOTE: basePos is the center of the block! | |
local basePos = origin + blockSize/2 | |
game.Workspace.Terrain:FillBlock(CFrame.new(basePos), blockSize, material) | |
--end | |
end | |
if CheckCancel() then return end | |
UpdateStatus(z-pos1.Z, pos2.Z-pos1.Z) | |
wait() | |
end | |
print('Terrain Generation Finished!') | |
Cleanup() | |
end | |
GenTerrainBetweenParts(workspace.Baseplate) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It says
The current identity (2) cannot Set (lacking permission 1)
What is wrong?