Skip to content

Instantly share code, notes, and snippets.

@nightm4re94
Last active May 19, 2025 09:48
Show Gist options
  • Save nightm4re94/d024d3a534de0b8fc482436833b75c83 to your computer and use it in GitHub Desktop.
Save nightm4re94/d024d3a534de0b8fc482436833b75c83 to your computer and use it in GitHub Desktop.
A Blender script to import cities created with Watabou's Medieval Fantasy City Generator
import bpy
import json
import math
import random
from shapely.geometry import Polygon, Point
# Load JSON data
with open("D:/Downloads/nightfair.json", "r") as f:
city_data = json.load(f)
# Preset array of credible building colors for districts
building_colors = [
(0.8, 0.2, 0.1, 1), # Classic brick red
(0.6, 0.6, 0.6, 1), # Stone gray
(1.0, 1.0, 0.8, 1), # Ivory white
(0.85, 0.6, 0.2, 1), # Warm ochre
(0.2, 0.6, 0.2, 1), # Deep forest green
(0.5, 0.7, 1.0, 1), # Coastal blue
(0.2, 0.2, 0.2, 1), # Urban charcoal
(1.0, 0.4, 0.2, 1), # Sunset orange
(0.6, 0.4, 0.8, 1), # Dusty lavender
(0.5, 0.5, 0.8, 1), # Slate blue
(1.0, 0.7, 0.5, 1), # Soft peach
(0.5, 0.8, 0.5, 1), # Seafoam green
(0.76, 0.25, 0.13, 1), # Burnt sienna
(1.0, 1.0, 1.0, 1), # Crisp white
(0.1, 0.1, 0.1, 1), # Charcoal black
(1.0, 0.6, 0.2, 1), # Tangerine yellow
(0.6, 0.4, 0.2, 1), # Warm taupe
(0.5, 0.7, 0.9, 1), # Powder blue
(1.0, 0.85, 0.25, 1), # Goldenrod yellow
(0.5, 0.6, 0.2, 1), # Moss green
(0.72, 0.45, 0.2, 1), # Copper brown
(0.5, 0.0, 0.5, 1), # Royal purple
(0.94, 0.87, 0.7, 1), # Light almond
(1.0, 0.8, 0.0, 1), # Sunflower yellow
(0.27, 0.51, 0.71, 1), # Steel blue
(1.0, 0.8, 0.9, 1), # Cherry blossom pink
(0.94, 0.91, 0.55, 1), # Sandstone beige
(0.6, 0.3, 0.2, 1), # Auburn red
(0.0, 0.4, 0.2, 1), # Pine green
(0.0, 0.28, 0.67, 1), # Cobalt blue
(0.44, 0.5, 0.6, 1), # Slate gray
(0.6, 1.0, 0.2, 1), # Lime green
]
# Helper functions
def create_material(name, color):
mat = bpy.data.materials.new(name=name)
mat.use_nodes = True
bsdf = mat.node_tree.nodes["Principled BSDF"]
bsdf.inputs["Base Color"].default_value = color
return mat
def create_roof_material():
"""Create and return a roof material."""
# Create the material for the roof
roof_material = bpy.data.materials.new(name="Roof_Material")
roof_material.use_nodes = True
bsdf = roof_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a typical roof color (e.g., brownish red)
bsdf.inputs["Base Color"].default_value = (0.8, 0.2, 0.1, 1) # Red roof color
# Optionally set other properties like roughness and metallic
bsdf.inputs["Roughness"].default_value = 0.7 # Slightly rough roof
bsdf.inputs["Metallic"].default_value = 0.0 # Not metallic
return roof_material
def create_tree_material():
"""Create and return a green material for the trees."""
tree_material = bpy.data.materials.new(name="Tree_Material")
tree_material.use_nodes = True
bsdf = tree_material.node_tree.nodes["Principled BSDF"]
# Set the base color to green
bsdf.inputs["Base Color"].default_value = (0.1, 0.7, 0.1, 1) # A green color for the tree
# Optionally adjust other material properties, e.g., roughness for a natural look
bsdf.inputs["Roughness"].default_value = 0.5 # Adjust roughness if needed
bsdf.inputs["Metallic"].default_value = 0.3 # Adjust shine if needed
return tree_material
def create_water_material():
"""Create and return a blue material for the water."""
# Create the material for the water
water_material = bpy.data.materials.new(name="Water_Material")
water_material.use_nodes = True
bsdf = water_material.node_tree.nodes["Principled BSDF"]
# Set the base color to blue
bsdf.inputs["Base Color"].default_value = (0.2, 0.4, 1.0, 1) # Light blue color for water
# Optionally set other properties for water-like appearance
bsdf.inputs['Alpha'].default_value = 0.8 # Make it transparent like water
bsdf.inputs["Roughness"].default_value = 0.0 # Smooth surface for water
bsdf.inputs["Metallic"].default_value = 0.5 # Slightly reflective for water surface
return water_material
def create_earth_material():
"""Create and return an earth material (brownish, rocky texture)."""
# Create the material for the earth
earth_material = bpy.data.materials.new(name="Earth_Material")
earth_material.use_nodes = True
bsdf = earth_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a brownish, earthy tone
bsdf.inputs["Base Color"].default_value = (0.6, 0.4, 0.2, 1) # Brown color for earth
# Set roughness to simulate a natural, non-reflective surface
bsdf.inputs["Roughness"].default_value = 0.8 # Rough surface for earth
# Optionally adjust specular if needed (usually low for earthy textures)
bsdf.inputs["Metallic"].default_value = 0.2 # Low specular for natural material
return earth_material
def create_field_material():
"""Create and return a green material for the fields."""
# Create the material for the field
field_material = bpy.data.materials.new(name="Field_Material")
field_material.use_nodes = True
bsdf = field_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a grassy green
bsdf.inputs["Base Color"].default_value = (0.3, 0.7, 0.3, 1) # Grass green color
# Set roughness to simulate a natural, matte surface (not reflective)
bsdf.inputs["Roughness"].default_value = 0.6 # Rough surface for fields
# Optionally adjust specular to simulate a more natural surface
bsdf.inputs["Metallic"].default_value = 0.2 # Low specular for a grassy material
return field_material
def create_green_material():
"""Create and return a green material for greenspaces (like grass, plants, etc.)."""
# Create the material for the green
green_material = bpy.data.materials.new(name="Green_Material")
green_material.use_nodes = True
bsdf = green_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a lush, vibrant green
bsdf.inputs["Base Color"].default_value = (0.2, 0.8, 0.2, 1) # A vibrant green color
# Set roughness to simulate a natural, non-reflective surface (grass-like)
bsdf.inputs["Roughness"].default_value = 0.5 # Slight roughness for a natural finish
# Set specular value (grass often has some subtle reflection)
bsdf.inputs["Metallic"].default_value = 0.3 # Slightly reflective, but not too much
return green_material
def create_stone_material():
"""Create and return a stone-like material for squares."""
# Create the material for the stone
stone_material = bpy.data.materials.new(name="Stone_Material")
stone_material.use_nodes = True
bsdf = stone_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a natural stone gray
bsdf.inputs["Base Color"].default_value = (0.4, 0.4, 0.4, 1) # Neutral stone gray color
# Set roughness to simulate a rough stone surface (not reflective)
bsdf.inputs["Roughness"].default_value = 0.8 # Rough stone-like finish
# Set specular value to give it a bit of subtle reflection (like wet stones)
bsdf.inputs["Metallic"].default_value = 0.3 # Low specular for a stone material
# Optionally, add a bump map or a noise texture for more realistic stone texture
# You could use a texture or noise pattern here if desired
return stone_material
def create_plank_material():
"""Create and return a material for the planks."""
plank_material = bpy.data.materials.new(name="Plank_Material")
plank_material.use_nodes = True
bsdf = plank_material.node_tree.nodes["Principled BSDF"]
# Set the base color to a wood-like color (light brown)
bsdf.inputs["Base Color"].default_value = (0.6, 0.3, 0.1, 1) # Light brown for wood
# Set roughness to simulate a rough wooden texture
bsdf.inputs["Roughness"].default_value = 0.8 # Rough wood texture
# Set specular for a slightly matte appearance
bsdf.inputs["Metallic"].default_value = 0.4
return plank_material
def get_district_material(district_name):
"""Assign a material based on the district's name using a color palette."""
# Use a hash of the district name to cycle through the color palette
color_index = hash(district_name) % len(district_colors) # Ensure a consistent color
color = district_colors[color_index]
# Create the material using the selected color
return create_material(district_name, color)
def assign_material(obj, material):
if not obj.data.materials:
obj.data.materials.append(material)
else:
obj.data.materials[0] = material
def create_tree(location, depth=5, tree_collection=None):
# Adjust the z-coordinate to raise the tree by 0.5 * depth
x, y, z = location
z += 0.5 * depth # Raise the tree by half of its depth
# Create the cone (tree) at the adjusted location
bpy.ops.mesh.primitive_cone_add(vertices=8, radius1=1, depth=depth, location=(x, y, z))
tree_obj = bpy.context.object
tree_obj.name = "Tree"
assign_material(tree_obj, create_tree_material())
# Link tree object to the provided collection
if tree_collection:
tree_collection.objects.link(tree_obj)
bpy.context.collection.objects.unlink(tree_obj) # Unlink from the current collection (default collection)
return tree_obj
def calculate_height(area, min_height=5.0, max_height=20.0):
"""Calculate building height based on area, clamped to [min_height, max_height]."""
normalized_area = max(0, min(area, 1000)) / 1000 # Normalize area to [0, 1]
return min_height + normalized_area * (max_height - min_height)
def create_roof(coordinates, base_height, roof_height):
"""
Create a simple pyramid roof on top of a building.
:param coordinates: List of (x, y) tuples defining the building's base polygon.
:param base_height: The height of the building.
:param roof_height: The height of the roof above the building's top.
:return: The created roof object.
"""
# Calculate the centroid (center) of the building
centroid_x = sum(x for x, y in coordinates) / len(coordinates)
centroid_y = sum(y for x, y in coordinates) / len(coordinates)
# The apex of the pyramid (roof) is at the center of the base + roof height
apex = (centroid_x, centroid_y, base_height + roof_height)
# Create vertices for the roof: the base vertices and the apex
vertices = []
for x, y in coordinates:
vertices.append((x, y, base_height)) # Add the base vertices at building height
vertices.append(apex) # Add the apex at the top of the building
# Create faces for the pyramid: triangles connecting each base vertex to the apex
faces = []
num_vertices = len(coordinates)
for i in range(num_vertices):
# Each face connects the i-th vertex, the (i+1)-th vertex (with wrapping), and the apex
next_i = (i + 1) % num_vertices
faces.append([i, next_i, num_vertices]) # Each triangle
# Create the mesh for the roof
mesh = bpy.data.meshes.new("PyramidRoof")
mesh.from_pydata(vertices, [], faces)
roof_obj = bpy.data.objects.new("Roof", mesh)
# Link the roof object to the current collection
bpy.context.collection.objects.link(roof_obj)
# Apply roof material
assign_material(roof_obj, create_roof_material())
return roof_obj
def create_building(coordinates, parent_collection):
"""
Create a building with a roof and group them in a unique collection for the building.
:param coordinates: List of (x, y) tuples defining the building's base polygon.
:param material: Material to apply to the building.
:param parent_collection: The general collection to link the new collection to.
"""
# Calculate the building footprint area
polygon = Polygon(coordinates)
area = polygon.area
height = calculate_height(area)
# Create building base
vertices = [(x, y, 0) for x, y in coordinates] + [(x, y, height) for x, y in coordinates]
edges = []
faces = [
[i for i in range(len(coordinates))], # Bottom face
[i + len(coordinates) for i in range(len(coordinates))] # Top face
]
faces += [[i, (i + 1) % len(coordinates), (i + 1) % len(coordinates) + len(coordinates), i + len(coordinates)]
for i in range(len(coordinates))] # Side faces
mesh = bpy.data.meshes.new("Building")
mesh.from_pydata(vertices, edges, faces)
building_obj = bpy.data.objects.new("Building", mesh)
bpy.context.collection.objects.link(building_obj)
# Assign material
color = random.choice(building_colors)
material = create_material(building_obj.name, color)
assign_material(building_obj, material)
# Create a new collection for the building and its roof
building_collection = bpy.data.collections.new(f"Building_{building_obj.name}")
parent_collection.children.link(building_collection) # Link this new collection to the parent collection
# Always link the building to its new collection
building_collection.objects.link(building_obj)
# If the building has exactly 4 vertices (for rectangular buildings), add a roof.
if len(coordinates) == 4:
# Add a pointy roof if the building has 4 vertices
roof_obj = create_roof(coordinates, base_height=height, roof_height=height * 0.4)
# Link the roof to the same collection as the building
building_collection.objects.link(roof_obj)
bpy.context.collection.objects.unlink(building_obj) # Unlink from the default collection
bpy.context.collection.objects.unlink(roof_obj) # Unlink from the default collection
else:
# If not rectangular, just add the building to the collection
bpy.context.collection.objects.unlink(building_obj) # Unlink from the default collection
# Return the new collection for possible further use
return building_collection
def create_polygon(coordinates, height=0.1, name="Polygon", collection=None):
vertices = [(x, y, 0) for x, y in coordinates] + [(x, y, height) for x, y in coordinates]
edges = []
faces = [
[i for i in range(len(coordinates))],
[i + len(coordinates) for i in range(len(coordinates))]
]
faces += [[i, (i + 1) % len(coordinates), (i + 1) % len(coordinates) + len(coordinates), i + len(coordinates)]
for i in range(len(coordinates))]
mesh = bpy.data.meshes.new(name)
mesh.from_pydata(vertices, edges, faces)
obj = bpy.data.objects.new(name, mesh)
bpy.context.collection.objects.link(obj)
# Link the object to the provided collection
if collection:
collection.objects.link(obj)
bpy.context.collection.objects.unlink(obj) # Unlink from the default collection
return obj
def create_plank_line(coordinates, width, collection=None):
"""Create a 3D plank along a line with a given width."""
# Calculate the direction vector from the first and last point of the line
x1, y1 = coordinates[0]
x2, y2 = coordinates[-1]
# Vector between the two points
dx = x2 - x1
dy = y2 - y1
length = math.sqrt(dx**2 + dy**2)
# Normalize direction
direction_x = dx / length
direction_y = dy / length
# Create a plank (cube stretched along the line)
bpy.ops.mesh.primitive_cube_add(size=1, location=((x1 + x2) / 2, (y1 + y2) / 2, 0), enter_editmode=False)
plank = bpy.context.object
plank.scale = (length / 2, width / 2, width / 2)
# Rotate the plank so it matches the direction of the line
angle = math.atan2(dy, dx)
plank.rotation_euler[2] = angle
# Apply the material to the plank
plank_material = create_plank_material()
plank.data.materials.append(plank_material)
# Link the plank to the specified collection
if collection:
collection.objects.link(plank)
bpy.context.collection.objects.unlink(plank) # Unlink from the default collection
return plank
def create_curve(coordinates, width, collection, object_name="Curve"):
"""Create a curve (e.g., road or river) with given coordinates and width."""
# Create a NURBS path from the coordinates
bpy.ops.object.select_all(action='DESELECT') # Deselect all objects
curve_data = bpy.data.curves.new(object_name, type='CURVE')
curve_data.dimensions = '2D' # Ensure the curve is flat along the XY plane
# Create a path (nurbs curve)
spline = curve_data.splines.new('POLY')
spline.points.add(count=len(coordinates) - 1) # Add points based on the coordinates
# Set curve points
for i, (x, y) in enumerate(coordinates):
spline.points[i].co = (x, y, 0, 1) # Set points in 3D space (last value is the weight, which is 1)
# Create an object from the curve
curve_object = bpy.data.objects.new(object_name, curve_data)
bpy.context.collection.objects.link(curve_object) # Link to the current scene collection
# Set the bevel depth to define the width of the road/rivers (extrude the curve to give it width)
# curve_object.data.bevel_depth = width / 2 # Bevel depth defines the width of the curve
# curve_object.data.bevel_resolution = 8 # Resolution of bevel (smoothness)
# curve_object.data.extrude = 0 # Set extrusion to 0 to keep the curve flat (no vertical height)
# Link the curve object to the specified collection
collection.objects.link(curve_object)
bpy.context.collection.objects.unlink(curve_object) # Unlink from the current collection
return curve_object
def create_river_polygon(coordinates, width, collection=None):
"""Create a flat river polygon based on coordinates and width."""
vertices = []
faces = []
# Loop through the coordinates and create two vertices for each segment
for i in range(len(coordinates)):
x1, y1 = coordinates[i]
# For each coordinate, calculate the perpendicular direction and spawn two vertices
if i > 0:
x0, y0 = coordinates[i-1] # Previous point (for direction)
elif i < len(coordinates) - 1:
x0, y0 = coordinates[i + 1] # Next point (for direction)
else:
x0, y0 = coordinates[i] # Just use the current coordinate if it's the only one
# Calculate the direction vector from (x0, y0) to (x1, y1)
dx = x1 - x0
dy = y1 - y0
length = math.sqrt(dx**2 + dy**2)
# Normalize the direction vector to get the unit vector
direction_x = dx / length
direction_y = dy / length
# Perpendicular direction (rotate by 90 degrees)
perp_x = -direction_y
perp_y = direction_x
# Calculate the left and right offset points by half the width
offset_x1 = x1 + perp_x * (width / 2)
offset_y1 = y1 + perp_y * (width / 2)
offset_x2 = x1 - perp_x * (width / 2)
offset_y2 = y1 - perp_y * (width / 2)
# Add the two vertices to the list
vertices.append((offset_x1, offset_y1, 0)) # Left vertex
vertices.append((offset_x2, offset_y2, 0)) # Right vertex
# Loop through the coordinates to create faces between the left and right vertices
for i in range(0, len(vertices) - 2, 2):
faces.append([i, i + 1, i + 3, i + 2]) # Form faces between adjacent left and right vertices
# Create mesh for the river
river_mesh = bpy.data.meshes.new("River")
river_mesh.from_pydata(vertices, [], faces)
river_obj = bpy.data.objects.new("River", river_mesh)
bpy.context.collection.objects.link(river_obj)
# Link the river to the collection
if collection:
collection.objects.link(river_obj)
bpy.context.collection.objects.unlink(river_obj) # Unlink from the default collection
return river_obj
def create_tower(location, height=14, radius=10, collection=None):
"""Create a tower (cylinder) at the specified location."""
total_height = height * 1.2
if len(location) == 2:
location = (*location, total_height/2) # Set z to height/2 if the location is 2D (usually the cylinder is centered at z=0)
bpy.ops.mesh.primitive_cylinder_add(radius=radius, depth=total_height, location=location)
tower = bpy.context.object # The newly created tower object
tower_material = create_material("TowerMaterial", (0.3, 0.3, 0.3, 1))
assign_material(tower,tower_material)
# Add the tower to the specified collection
if collection:
collection.objects.link(tower)
bpy.context.collection.objects.unlink(tower) # Unlink from the default collection
return tower
def spawn_towers_at_wall_vertices(wall_coordinates, height, collection=None):
"""Spawn a tower at each vertex of a wall."""
for vertex in wall_coordinates:
# Spawn a tower at each vertex (x, y, z)
create_tower(vertex, height=height, radius=4, collection=collection)
def create_wall(coordinates, thickness=0.5, height=12.0, parent_collection=None):
wall_segments = []
spawn_towers_at_wall_vertices(coordinates, height=height, collection=parent_collection)
for start, end in zip(coordinates, coordinates[1:] + [coordinates[0]]): # Loop back to the start
x1, y1 = start
x2, y2 = end
# Calculate wall vertices
dx, dy = x2 - x1, y2 - y1
length = math.sqrt(dx**2 + dy**2)
nx, ny = dy / length * thickness / 2, -dx / length * thickness / 2 # Perpendicular vector for thickness
vertices = [
(x1 - nx, y1 - ny, 0), (x2 - nx, y2 - ny, 0), # Outer base
(x1 + nx, y1 + ny, 0), (x2 + nx, y2 + ny, 0), # Inner base
(x1 - nx, y1 - ny, height), (x2 - nx, y2 - ny, height), # Outer top
(x1 + nx, y1 + ny, height), (x2 + nx, y2 + ny, height) # Inner top
]
edges = []
faces = [
[0, 1, 5, 4], # Outer face
[2, 3, 7, 6], # Inner face
[0, 2, 6, 4], # Left face
[1, 3, 7, 5], # Right face
[4, 5, 7, 6], # Top face
[0, 1, 3, 2] # Bottom face
]
mesh = bpy.data.meshes.new("Wall")
mesh.from_pydata(vertices, edges, faces)
wall_obj = bpy.data.objects.new("Wall", mesh)
if parent_collection:
parent_collection.objects.link(wall_obj)
wall_segments.append(wall_obj)
return wall_segments
# Create Collections
walls_collection = bpy.data.collections.new("Walls")
bpy.context.scene.collection.children.link(walls_collection)
buildings_collection = bpy.data.collections.new("Buildings")
bpy.context.scene.collection.children.link(buildings_collection)
districts_collection = bpy.data.collections.new("Districts")
bpy.context.scene.collection.children.link(districts_collection)
roads_collection = bpy.data.collections.new("Roads")
bpy.context.scene.collection.children.link(roads_collection)
water_collection = bpy.data.collections.new("Water")
bpy.context.scene.collection.children.link(water_collection)
earth_collection = bpy.data.collections.new("Earth")
bpy.context.scene.collection.children.link(earth_collection)
rivers_collection = bpy.data.collections.new("Rivers")
bpy.context.scene.collection.children.link(rivers_collection)
prisms_collection = bpy.data.collections.new("Prisms")
bpy.context.scene.collection.children.link(prisms_collection)
trees_collection = bpy.data.collections.new("Trees")
bpy.context.scene.collection.children.link(trees_collection)
squares_collection = bpy.data.collections.new("Squares")
bpy.context.scene.collection.children.link(squares_collection)
greens_collection = bpy.data.collections.new("Greens")
bpy.context.scene.collection.children.link(greens_collection)
fields_collection = bpy.data.collections.new("Fields")
bpy.context.scene.collection.children.link(fields_collection)
planks_collection = bpy.data.collections.new("Planks")
bpy.context.scene.collection.children.link(planks_collection)
# Process features
for feature in city_data["features"]:
feature_type = feature["type"]
feature_id = feature.get("id", "")
if feature_id == "trees" and feature_type == "MultiPoint":
for x, y in feature["coordinates"]:
create_tree((x, y, 0), tree_collection=trees_collection)
elif feature_id == "districts" and feature_type == "GeometryCollection":
for district in feature["geometries"]:
if district["type"] == "Polygon":
district_name = district.get('name', 'Unnamed')
district_polygon = create_polygon(square[0], height=0.1, name="District", collection=districts_collection)
elif feature_id == "buildings" and feature_type == "MultiPolygon":
for building in feature["coordinates"]:
for coordinates in building:
building_collection = create_building(coordinates, buildings_collection)
# Processing the 'rivers' feature (now uses create_curve)
elif feature_id == "rivers" and feature_type == "GeometryCollection":
for river in feature["geometries"]:
if river["type"] == "LineString":
# create_curve(river["coordinates"], river["width"], river_collection, object_name="River")
river_polygon = create_river_polygon(river["coordinates"], river["width"], collection=rivers_collection)
assign_material(river_polygon, create_water_material())
# Processing the 'roads' feature (now uses create_curve)
elif feature_id == "roads" and feature_type == "GeometryCollection":
for road in feature["geometries"]:
if road["type"] == "LineString":
create_curve(road["coordinates"], road["width"], roads_collection, object_name="Road")
elif feature_id == "walls" and feature_type == "GeometryCollection":
for wall in feature["geometries"]:
if wall["type"] == "Polygon":
segments = create_wall(wall["coordinates"][0], thickness=0.5, height=12.0, parent_collection=walls_collection)
for wall_polygon in segments:
assign_material(wall_polygon, create_stone_material())
elif feature_id == "squares" and feature_type == "MultiPolygon":
for square in feature["coordinates"]:
square_polygon = create_polygon(square[0], height=0.6, name="Square", collection=squares_collection)
assign_material(square_polygon, create_stone_material())
elif feature_id == "greens" and feature_type == "MultiPolygon":
for green in feature["coordinates"]:
green_polygon = create_polygon(green[0], height=0.6, name="Green", collection=greens_collection)
assign_material(green_polygon, create_green_material())
elif feature_id == "fields" and feature_type == "MultiPolygon":
for field in feature["coordinates"]:
field_polygon = create_polygon(field[0], height=0.6, name="Field", collection=fields_collection)
assign_material(field_polygon, create_field_material())
elif feature_id == "earth" and feature_type == "Polygon":
earth_coordinates = feature["coordinates"][0]
earth_polygon = create_polygon(earth_coordinates, height=0.1, name="Earth", collection=earth_collection)
assign_material(earth_polygon, create_earth_material())
elif feature_id == "water" and feature_type == "MultiPolygon":
for water in feature["coordinates"]:
for coordinates in water:
water_polygon = create_polygon(coordinates, height=0.15, name="Water", collection=water_collection)
assign_material(water_polygon, create_water_material())
elif feature_id == "prisms" and feature_type == "MultiPolygon":
for prism in feature["coordinates"]:
for coordinates in prism:
prism_polygon = create_polygon(coordinates, height=5.0, name="Prism", collection=prisms_collection)
assign_material(prism_polygon, create_stone_material())
elif feature["id"] == "planks" and feature["type"] == "GeometryCollection":
for plank in feature["geometries"]:
if plank["type"] == "LineString":
# Get the coordinates and width of the plank
coordinates = plank["coordinates"]
width = plank["width"]
# Create the plank line in Blender
create_plank_line(coordinates, width, collection=planks_collection)
# Final adjustments
bpy.ops.object.select_all(action="DESELECT")
# Final adjustments
bpy.ops.object.select_all(action="DESELECT")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment