Skip to content

Instantly share code, notes, and snippets.

@darrenwiens
Created April 25, 2022 22:44
Show Gist options
  • Save darrenwiens/4296f697eed1e739ad4c403e33d2fc6a to your computer and use it in GitHub Desktop.
Save darrenwiens/4296f697eed1e739ad4c403e33d2fc6a to your computer and use it in GitHub Desktop.
Blender AWS Terrain tiles add-on
import bpy
import morecantile
import os
import requests
url = "https://elevation-tiles-prod.s3.amazonaws.com/v2/geotiff"
def get_tile(x, y, z):
src_path = f"{url}/{z}/{x}/{y}.tif"
dst_path = f'/tmp/{z}_{x}_{y}.tif'
r = requests.get(src_path, stream=True)
if r.status_code == 200:
with open(dst_path, 'wb') as f:
for chunk in r.iter_content(1024):
f.write(chunk)
return dst_path
def create_grid():
bpy.ops.mesh.primitive_grid_add(
x_subdivisions=257,
y_subdivisions=257,
size=1.0,
calc_uvs=True,
enter_editmode=False,
align='WORLD',
location=(0.0, 0.0, 25.0),
rotation=(0.0, 0.0, 0.0),
scale=(0.0, 0.0, 0.0)
)
def create_texture(img_path):
bpy_image = bpy.data.images.new(
"new_img",
width=256,
height=256
)
tex_name = os.path.splitext(os.path.basename(img_path))[0]
tex_image = bpy.data.textures.new(tex_name, 'IMAGE')
tex_image.image = bpy.data.images.load(img_path)
return tex_name
def create_displace_modifier(tex_name):
grid = bpy.data.objects['Grid']
bpy.ops.object.modifier_add(type='DISPLACE')
bpy.ops.object.modifier_apply(modifier='DISPLACE')
texture = bpy.data.textures[tex_name]
modifier = bpy.context.active_object.modifiers[-1]
modifier.texture = texture
modifier.strength = 50
def add_material(img_path, tex_name):
mat = bpy.data.materials.get(tex_name) or bpy.data.materials.new(tex_name)
mat.use_nodes = True
node_tree = mat.node_tree
nodes = node_tree.nodes
links = node_tree.links
bsdf = nodes.get("Principled BSDF")
bsdf.inputs["Roughness"].default_value = 1
bsdf.inputs["Sheen"].default_value = 1
tex_image = mat.node_tree.nodes.new("ShaderNodeTexImage")
tex_image.image = bpy.data.images.load(img_path)
links.new(tex_image.outputs["Color"], bsdf.inputs[0])
ob = bpy.context.scene.objects["Grid"]
if ob.data.materials:
ob.data.materials[0] = mat
else:
ob.data.materials.append(mat)
class CoordSettings(bpy.types.PropertyGroup):
x_tile: bpy.props.IntProperty(name="X: ", min=0, max=16383)
y_tile: bpy.props.IntProperty(name="Y: ", min=0, max=16383)
z_tile: bpy.props.IntProperty(name="Z: ", min=0, max=14)
x_geo: bpy.props.FloatProperty(name="Lng: ", min=-180, max=180)
y_geo: bpy.props.FloatProperty(name="Lat: ", min=-90, max=90)
class GeoOperator(bpy.types.Operator):
bl_idname = "wm.geo_op"
bl_label = "Geo Operator"
def execute(self, context):
layout = self.layout
scene = context.scene
tile_settings = scene.coord_settings
tms = morecantile.tms.get("WebMercatorQuad")
tile = tms.tile(tile_settings.x_geo, tile_settings.y_geo, tile_settings.z_tile)
x_tile = tile.x
y_tile = tile.y
z_tile = tile.z
img_path = get_tile(x_tile, y_tile, z_tile)
create_grid()
tex_name = create_texture(img_path)
create_displace_modifier(tex_name)
add_material(img_path, tex_name)
return {'FINISHED'}
class TileOperator(bpy.types.Operator):
bl_idname = "wm.tile_op"
bl_label = "Tile Operator"
def execute(self, context):
layout = self.layout
scene = context.scene
tile_settings = scene.coord_settings
img_path = get_tile(tile_settings.x_tile, tile_settings.y_tile, tile_settings.z_tile)
create_grid()
tex_name = create_texture(img_path)
create_displace_modifier(tex_name)
add_material(img_path, tex_name)
return {'FINISHED'}
class ToolPanel:
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tools"
bl_options = {"DEFAULT_CLOSED"}
class TERRAIN_PT_Main(ToolPanel, bpy.types.Panel):
bl_idname = "TERRAIN_PT_Main"
bl_label = "AWS Terrain Tiles"
def draw(self, context):
layout = self.layout
layout.label(text="Enter geographic or tile coordinates below.")
class GEO_PT_Coords(ToolPanel, bpy.types.Panel):
bl_parent_id = "TERRAIN_PT_Main"
bl_label = "Geographic Coordinates"
def draw(self, context):
layout = self.layout
scene = context.scene
coord_settings = scene.coord_settings
row = layout.row()
row.prop(coord_settings, 'x_geo')
row.prop(coord_settings, 'y_geo')
row.prop(coord_settings, 'z_tile')
layout.operator(GeoOperator.bl_idname, text="Get tile")
class TILE_PT_Coords(ToolPanel, bpy.types.Panel):
bl_parent_id = "TERRAIN_PT_Main"
bl_label = "Tile Coordinates"
def draw(self, context):
layout = self.layout
scene = context.scene
coord_settings = scene.coord_settings
row = layout.row()
row.prop(coord_settings, 'x_tile')
row.prop(coord_settings, 'y_tile')
row.prop(coord_settings, 'z_tile')
layout.operator(TileOperator.bl_idname, text="Get tile")
classes = (
TERRAIN_PT_Main,
GEO_PT_Coords,
TILE_PT_Coords,
CoordSettings,
GeoOperator,
TileOperator
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.coord_settings = bpy.props.PointerProperty(type=CoordSettings)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment