1

I want to animate a landscapes that "grows" up, using a grid. The landscape sits in a numpy matrix. After I update the Z values in the grid, the shape keys don't capture this.

Below is my current code. At line 49, just below the text "### Below here', the data can be set. If you fill in "False", the grid values get replaced by a random vertex transform, and this works fine, creating a changing grid between frame 1 and 100.

If "True" is filled in, the numpy matrix data is used (here a funny sine wave for testing) and this sets the Z coordinates directly, to adjust the mesh. The problem is: the shape-keys/keyframes don't capture this, just showing the landscape that I set for the entire animation.

What am I doing wrong?

import bpy, bmesh
from math import pi
import numpy as np

O = bpy.data.objects

--- Cleaning previous iterations --------------------------------------

for o in O: if o.name[0:4]=='Land': O.remove(o)

--- Function setting the mesh -----------------------------------------

def SetMesh(me, V):

# Get a BMesh representation
bm = bmesh.new()   # create an empty BMesh
bm.from_mesh(me)   # fill it in from a Mesh
bm.verts.ensure_lookup_table()

# Modify the BMesh, can do anything here...
for i in range(len(bm.verts)):
    bm.verts[i].co.z =V[i]

# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
bm.free()
me.update()

--- Generating data (wavy landscape) ---------------------------------

GridDim = 20 R=np.linspace(0,pi,GridDim) X,Y=np.meshgrid(R,R) D=np.sin(XY) D=D.flatten()0.1

bpy.context.scene.frame_current = 1 bpy.ops.mesh.primitive_grid_add( x_subdivisions=GridDim, y_subdivisions=GridDim, size=2, location=(0, 0, 0)) bpy.context.object.name = "Landscape"

bpy.ops.object.shape_key_add(from_mix=False) # The basis shape_key bpy.ops.object.shape_key_add(from_mix=False) # The "Key 1" shape_key

Below here, the data can be set

if True: SetMesh(Landscape.data, D) else: bpy.ops.object.editmode_toggle() bpy.ops.transform.vertex_random(offset=0.2) bpy.ops.object.editmode_toggle()

bpy.context.object.data.shape_keys.key_blocks["Key 1"].value = 1 bpy.context.object.data.shape_keys.key_blocks["Key 1"].keyframe_insert(data_path='value', frame=1)

Setting keyframes for animation

sk1 = bpy.context.object.data.shape_keys.key_blocks["Key 1"] sk1.value = 0.0 sk1.keyframe_insert(data_path='value', frame=1) sk1.value = 1.0 sk1.keyframe_insert(data_path='value', frame=100)

  • See for example https://blender.stackexchange.com/a/93180/15543 ditch using the operator to create shapekeys. Also recommend using variables eg mesh instead of bpy.context.object.data – batFINGER Aug 19 '20 at 11:35
  • That example doesn't work with me (maybe because I use version 2.83). Why using variables? I wouldn't mind, but I am unsure what would be the benefit? – Johan vd Koppel Aug 19 '20 at 12:01
  • Needed the most minor of edits to upgrade from 2.80. (btw feel free to edit answers if you find and can fix) Concept is same. Readability for example usage of sk1 above, (possibly three lines prior.) Reading full addresses to variables feels like hearing somebody's title, full name, address, everytime they are addressed. Edit ability. Portability. eg using a variable named context in test scripts can then be pasted into (eg) operator method code where it is an argument. – batFINGER Aug 19 '20 at 13:41

0 Answers0