# How do I create a heightmap from a python array of numbers?

I have a python numpy array similar to the following:

Array = ([[1, 2, 1, -1, -1, -3],
[3, 4, 2, 1, -2, -2],
[3, 4, 1, -1, -2, -2]])

I want to convert this to a heightmap in blender where a plane is subdivided into the equal number of rows and columns and each subdivision is displaced proportional to the numbers in the array.

Can this be done through a python script running in Blender? Are there any other methods of creating a heightmap from a python array?

Here's a script that generates a blender image from the array, and maps it to an image texture on a displacement modifier assigned to a Plane object.

import bpy, math
import numpy as np

a = np.array([
[1, 2, 1, -1, -1, -3],
[3, 4, 2, 1, -2, -2],
[3, 4, 1, -1, -2, -2]
])

# Normalize values
anorm = (a - a.min()) / (a.max() - a.min())

# Generate RGBA image from grayscale normalized array
pixels = np.dstack([anorm]*3+[np.ones(anorm.shape)])

# Generate or update image object in Blender
# Based on this answer: https://blender.stackexchange.com/a/105312/15861
height, width = anorm.shape
image_name = "dispmap.png"
if image_name not in bpy.data.images.keys():
bpy.data.images.new(image_name, width=width, height=height, alpha=True, float_buffer=False)

outputImg  = bpy.data.images[image_name]
input_res  = int(math.sqrt(outputImg.size[0]))
np_out_img = pixels.astype( np.float16 )
outputImg.pixels = np_out_img.ravel()

# Add or get displacement modifier
plane_obj = bpy.data.objects['Plane'] # Assumes the plane object is named "Plane"
if 'Disp' not in plane_obj.modifiers:
m = plane_obj.modifiers.new('Disp', 'DISPLACE')

m = plane_obj.modifiers["Disp"]

# Add or get displacement image texture
if not m.texture:
t = bpy.data.textures.new('DispTex', 'IMAGE')

t = bpy.data.textures['DispTex']

# Set image texture and image
t.image = outputImg
m.texture = t

Generated height (displacement) map and resulting mesh:

I use a grid (instead a plane, i hope that's ok). Then i just loop over the vertices and set the vertices height from the array.

Code:

import bpy
import bmesh

bpy.ops.object.mode_set(mode="EDIT")

Array = ([[1, 2, 1, -1, -1, -3],
[3, 4, 2, 1, -2, -2],
[3, 4, 1, -1, -2, -2]])

context = bpy.context

bm = bmesh.from_edit_mesh(context.edit_object.data)
# deselect all
for v in bm.verts:
v.select = False

bm.verts.ensure_lookup_table()

for x in range(6):
print("x",x)
for y in range(2):
print("y",y)
bm.verts[y * 6 + x].co.z = Array[y][x]

Result:

Array as vertex height

Similarly to @Chris's answer if the array values are interpreted as vertex z values

• Add a grid of same dimensions (unit size)
• Scale such that each xy grid is square
• Use foreach_get and foreach_set to quickly set the z offset without looping. (Or edit mode)

Test script.

import bpy
import numpy as np
from mathutils import Matrix

scale_factor = 2

a = np.array([
[1, 2, 1, -1, -1, -3],
[3, 4, 2, 1, -2, -2],
[3, 4, 1, -1, -2, -2]
])

rows, cols = a.shape
# make the grid rows x cols blender  units
S = Matrix.Diagonal((rows - 1, cols - 1, 1, 1))
# add a grid
size=1,
x_subdivisions=rows,
y_subdivisions=cols,
)

ob = bpy.context.object
me = ob.data
#scale it
me.transform(scale_factor * S)
# update z coord from data
coords = np.empty(rows * cols * 3)
me.vertices.foreach_get("co", coords)

x, y, z = coords.reshape(-1, 3).T

me.vertices.foreach_set(
"co",
np.array([x, y, a.T.ravel()]).T.ravel(),
)
• "co", RuntimeError: internal error setting the array. not sure why? Mar 20, 2022 at 7:12