Trying to do it directly through the Roblox API is basically impossible (or just way too hard) because the API sends image files and Roblox scripts can’t read pixel data from images.
The best method I found was to download the specific crop you want from the site, and then use a Python script to convert that data into a text format that Roblox can read. I actually had Gemini 3 Pro generate this Python script for me and it does work. It keeps the terrain at an almost 1:1 scale with the real world.
Go onto the site you provided and crop a part of the land and export the zip file.
Make sure to create a folder and add it to an editor like VS Code or something similar. Grab the .tif file from the zip file and place it into the newly created folder. Then create a file under the folder name.py and paste this in:
import rasterio
import numpy as np
import os
# --- SETTINGS ---
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_FILE = os.path.join(SCRIPT_DIR, "CB11.tif") # Make sure this matches your file
OUTPUT_FILE = os.path.join(SCRIPT_DIR, "TerrainData.lua")
# 1 = reads every single pixel (Maximum Detail)
# Increase number to downgrade the detail
STEP = 1
# Do not change this if you want accuracy.
HEIGHT_SCALE = 1.0
def export_to_lua():
print(f"--- Processing {INPUT_FILE} in High Definition ---")
if not os.path.exists(INPUT_FILE):
print("Error: File not found!")
return
with rasterio.open(INPUT_FILE) as src:
elevation = src.read(1)
elevation[elevation < -500] = -9999
valid_data = elevation[elevation > -9999]
if valid_data.size == 0:
print("Error: File is empty.")
return
min_height = np.min(valid_data)
max_height = np.max(valid_data)
print(f"Real World Height Range: {min_height}m to {max_height}m")
print(f"Total Elevation Change: {max_height - min_height}m")
elevation = np.where(elevation > -9999, elevation - min_height + 5, 0)
height, width = elevation.shape
print(f"Grid Size: {width}x{height} pixels (1 pixel = 1 meter)")
with open(OUTPUT_FILE, "w") as f:
f.write("return {\n")
for y in range(0, height, STEP):
row_data = []
for x in range(0, width, STEP):
val = elevation[y, x]
h = round(val * HEIGHT_SCALE, 2)
row_data.append(str(h))
f.write("\t{" + ",".join(row_data) + "},\n")
f.write("}")
print(f"SUCCESS! Saved to {OUTPUT_FILE}")
if __name__ == "__main__":
export_to_lua()
You can run this python script by pressing play on the editor or through the terminal. It should then generate the new file inside the folder. If you encounter any errors, here are some fixes.
- Wrong python version, although I doubt it would matter (I’m using 3.12.8)
- Make sure all libraries are downloaded (Probably look up some tutorials)
Next Step:
- In Roblox Studio create a ModuleScript and this module is where you will paste the TerrainData.
- Create a normal script in ServerScriptService or just paste this code into the command prompt to generate the terrain.
local Terrain = workspace.Terrain
-- Make sure this matches the location of the module
local TerrainData = require(game.ServerScriptService.TerrainData)
-- We are reading every pixel, so 1 Data Point = 1 Meter
local SCALE = 4
function Generate()
Terrain:Clear()
for x, row in ipairs(TerrainData) do
for z, heightMeters in ipairs(row) do
if heightMeters > 0 then
local finalHeight = heightMeters * SCALE
local worldX = x * SCALE
local worldZ = z * SCALE
Terrain:FillBlock(
CFrame.new(worldX, finalHeight / 2, worldZ),
Vector3.new(SCALE, finalHeight, SCALE),
Enum.Material.Grass
)
end
end
if x % 20 == 0 then task.wait() end
end
print("Done!")
end
Generate()
My Result:
This image is where I cropped and downloaded land that includes some steep cliff and a river, in total this crop was only about 1Mb for the zip file.
This was my result after following my method. This is just another way to recreate the terrain in roblox without going through blender. I never tried any bigger terrain and I do not know how well it will handle. You can try to edit my script by maybe figuring out adding the river or changing the terrain type depending on the height or something. Ive got no clue if this is any faster or a more efficient method than blender. I hope this can become helpful towards you or provide you with some insight or ideas.