This has been really helpful! I distilled it down to the simplest case I could, a single triangle that morphs, but I’m getting an error that I can’t understand caused by my slider usage in main_loop:
Assertion failed: !rows.is_inverse() at line 1498 of c:\buildslave\sdk-windows-amd64\build\panda\src\gobj\geomVertexData.cxx
Here’s the code:
from direct.showbase.ShowBase import ShowBase
from panda3d.core import GeomVertexFormat, GeomVertexArrayFormat, GeomVertexData
from panda3d.core import Geom, GeomNode, GeomTriangles, GeomVertexWriter, GeomEnums, GeomVertexAnimationSpec
from panda3d.core import UserVertexSlider, SliderTable, SparseArray
from direct.task.Task import Task
from direct.task.TaskManagerGlobal import taskMgr
# ---------------------------------------------------------------------------------------------------------------- #
# Create the primary configuration format:
base_format = GeomVertexArrayFormat()
base_format.add_column("vertex", 3,
GeomEnums.NT_float32, GeomEnums.C_point)
base_format.add_column("color", 4,
GeomEnums.NT_float32, GeomEnums.C_color)
# Create a second array for the morphs:
morph_format = GeomVertexArrayFormat()
morph_format.addColumn("vertex.morph.init_slider", 3, GeomEnums.NT_float32, GeomEnums.C_morph_delta)
# To morph other columns as needed, just change "vertex"
init_morph_format = GeomVertexFormat()
init_morph_format.addArray(base_format)
init_morph_format.addArray(morph_format)
# Indicate that this format should be animated by Panda.
ani_spec = GeomVertexAnimationSpec()
ani_spec.set_panda()
init_morph_format.set_animation(ani_spec)
init_morph_format = GeomVertexFormat.registerFormat(init_morph_format)
# Create a SliderTable holding a slider, affecting all vertex rows.
slider = UserVertexSlider("init_slider")
table = SliderTable()
table.addSlider(slider, SparseArray.allOn())
# ---------------------------------------------------------------------------------------------------------------- #
def make_demo_morph_triangle(vect_0, vect_1, vect_2,
vect_0_init, vect_1_init, vect_2_init):
vert_data = GeomVertexData('demo_triangle', init_morph_format, GeomEnums.UH_dynamic)
vertex = GeomVertexWriter(vert_data, 'vertex')
color = GeomVertexWriter(vert_data, 'color')
morph = GeomVertexWriter(vert_data, 'vertex.morph.init_slider')
for v_final, v_init in zip([vect_0, vect_1, vect_2],
[vect_0_init, vect_1_init, vect_2_init]):
vertex.add_data3(v_final[0], v_final[1], v_final[2])
morph.addData3(v_init[0] - v_final[0],
v_init[1] - v_final[1],
v_init[2] - v_final[2])
color.add_data4f(1.0, 0.0, 0.0, 1.0)
color.add_data4f(0.0, 1.0, 0.0, 1.0)
color.add_data4f(0.0, 0.0, 1.0, 1.0)
tris = GeomTriangles(GeomEnums.UHDynamic)
tris.add_vertices(0, 2, 1)
vert_data.setSliderTable(SliderTable.registerTable(table))
tri = Geom(vert_data)
tri.add_primitive(tris)
return tri
# ---------------------------------------------------------------------------------------------------------------- #
class TestMorphScene(ShowBase):
def __init__(self):
ShowBase.__init__(self)
self._active_slider = slider
def add_triangle(self,
v0, v1, v2,
v0_init, v1_init, v2_init):
tri_0 = make_demo_morph_triangle(v0, v1, v2,
v0_init, v1_init, v2_init)
tri_node = GeomNode('triangle')
tri_node.addGeom(tri_0)
self.render.attach_new_node(tri_node)
taskMgr.add(self.main_loop, 'loop_task')
def main_loop(self, task: Task):
self._active_slider.set_slider((task.time / 2) % 1)
return task.cont
# ---------------------------------------------------------------------------------------------------------------- #
if __name__ == "__main__":
pt_0 = (-2, 15, -2)
pt_1 = (-2, 15, 2)
pt_2 = (2, 15, -2)
pt_0_init = (-4, 5, -4)
pt_1_init = (-4, 5, 4)
pt_2_init = (4, 5, -4)
MyApp = TestMorphScene()
MyApp.add_triangle(pt_0, pt_1, pt_2,
pt_0_init, pt_1_init, pt_2_init)
MyApp.run()