Created
April 25, 2022 22:44
-
-
Save darrenwiens/4296f697eed1e739ad4c403e33d2fc6a to your computer and use it in GitHub Desktop.
Blender AWS Terrain tiles add-on
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
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