Blitz3D+ Command Reference

RefreshPhysicsMesh shape,mesh[,x#][,y#][,z#][,pitch#][,yaw#][,roll#][,preserve_materials]

Parameters

shape - live physics-shape handle

mesh - live source mesh entity

x# (optional) - frame X offset in body-local metres; 0 (default)
y# (optional) - frame Y offset in body-local metres; 0 (default)
z# (optional) - frame Z offset in body-local metres; 0 (default)

pitch# (optional) - frame pitch in radians; 0 (default)
yaw# (optional) - frame yaw in radians; 0 (default)
roll# (optional) - frame roll in radians; 0 (default)

preserve_materials (optional) - True keeps per-triangle material assignments, which requires unchanged vertex count and numbering (default); False resets every face to slot 1

Description

Cooks a new static triangle collider from the supplied mesh entity and replaces the shape.

Every surface contributes vertices and triangles, concatenated in surface order. Source-local vertices are multiplied by source world scale; source world position/rotation are ignored. Apply the optional body-local frame after scale, with angles in radians. Winding is retained. The owning physics body must be static. This command can convert another collider kind to a mesh.

With preserve_materials=True, an existing mesh must retain the same vertex count and numbering. Material assignments follow oriented index triples, including cyclic permutations, rather than cooked triangle order or spatial position. Moving vertices and BVH reordering preserve those assignments. Newly introduced faces use slot 1; removed faces lose their assignments. Faces temporarily omitted by cooking as degenerate retain their preferred slot while present in the source topology. Duplicate oriented faces with conflicting slots are ambiguous and raise a runtime error.

Set preserve_materials=False to reset face assignments to slot 1 and allow new vertex numbering/count. The material table itself remains intact. Shrinking a table cannot remove a slot still assigned to a temporarily degenerate source face; reset assignments first if required. Cooked triangle indices may change after refresh. Old query triangle indices identify the historical result and must not be used as current face identifiers without running the query again.

The shape handle, body/world ownership, public enumeration order, application tag, density, filter, sensor/event settings and material table remain intact. Sphere, capsule and box setters and RefreshPhysicsHull require a one-slot material table; explicitly remap existing faces and shrink larger tables before converting to a convex shape. Triangle meshes and terrain remain restricted to static bodies.

Primitive diameters and box dimensions must be positive; all positions, dimensions and frame angles must be finite. Replacement data is validated and cooked before native mutation. Invalid inputs raise a runtime error and retain the previous collider. Supported source limits are 1,048,576 vertices and 1,048,576 triangles. Coordinates/bounds must fit the pinned Box3D coordinate range; mass and inertia must remain finite and representable. Native allocation failure follows the library's allocation policy; these limits are not a guarantee that every maximum-size mesh will fit memory.

Successful edits recalculate body mass from all shapes, replacing custom mass data. Moving the centre of mass preserves point velocity, including saved velocity on disabled bodies. Enabled bodies are woken; disabled bodies remain disabled. Geometry changes invalidate contacts and wake affected touching bodies. Replacing an identical shared hull can retain its native proxy/contact cache. Queries run afterward see the current collider; existing owned queries retain their historical numbers and still resolve this live public shape handle.

Visual geometry changes never refresh physics automatically. Refresh is an explicit authoring operation, not a dynamic deformable-mesh solver. Native mesh geometry is borrowed: the wrapper releases previous cooked storage only after native references are gone. Hull geometry is copied into the native world database. All replacement effects record/replay. Hull/mesh replacement uses added opcodes and requires the patched Blitz3D+ player; older opcodes retain their values. Wrapper frame/dimension metadata and editable visual assets are not restored by physics replay.

Requires Extended mode.

See also: PhysicsShapeSphere, PhysicsShapeCapsule, PhysicsShapeBox, RefreshPhysicsHull, PhysicsShapeRadius, PhysicsShapeLocalMinX.

Example

; RefreshPhysicsMesh Example
; --------------------------
; Requires Extended mode.

Graphics3D 640,480,0,2
SetBuffer BackBuffer()

Const PHYSICS_STATIC=0
Const PHYSICS_DYNAMIC=2

camera=CreateCamera()
PositionEntity camera,0,3,-7
RotateEntity camera,20,0,0

light=CreateLight()
RotateEntity light,45,-30,0
AmbientLight 60,60,60

; An independent Box3D world with standard gravity
world=CreatePhysicsWorld()

; Blue static floor
ground=CreateCube()
ScaleEntity ground,6,0.5,6
PositionEntity ground,0,-0.5,0
EntityColor ground,80,160,255
ground_body=CreatePhysicsBody(world,ground,PHYSICS_STATIC)
ground_shape=PhysicsBodyBox(ground_body,12,1,12)

; A static mesh ramp made of 8 strips, each strip two triangles
ramp=CreateMesh()
surface=CreateSurface(ramp)
For strip=0 To 7
    x#=strip-4
    AddVertex surface,x,1.6-strip*0.2,-1.5
    AddVertex surface,x,1.6-strip*0.2,1.5
    AddVertex surface,x+1,1.4-strip*0.2,-1.5
    AddVertex surface,x+1,1.4-strip*0.2,1.5
    AddTriangle surface,strip*4,strip*4+1,strip*4+3
    AddTriangle surface,strip*4,strip*4+3,strip*4+2
Next
UpdateNormals ramp
EntityFX ramp,2
ramp_body=CreatePhysicsBody(world,ramp,PHYSICS_STATIC)
ramp_shape=PhysicsBodyMesh(ramp_body,ramp)

; Slot 2 of the ramp's material table is ice, with no friction
PhysicsShapeMaterials ramp_shape,2
PhysicsShapeMaterialFriction ramp_shape,2,0

; Crates resting on the grippy ramp
Dim crate_bodies(3)
For i=0 To 3
    crate=CreateCube()
    ScaleEntity crate,0.3,0.3,0.3
    EntityColor crate,255,120,70
    crate_bodies(i)=CreatePhysicsBody(world,crate,PHYSICS_DYNAMIC)
    crate_shape=PhysicsBodyBox(crate_bodies(i),0.6,0.6,0.6)
    ResetPhysicsBody crate_bodies(i),-3.5+i*2,2-i*0.4,0,0,0,-0.2
Next
PaintStrips(ramp,painted)

While Not KeyDown(1)

    ; Space paints the next strip as ice, so the crates slide
    If KeyHit(57) And painted<8
        PhysicsMeshTriangleMaterial ramp_shape,painted*2,2,2
        painted=painted+1
        PaintStrips(ramp,painted)
    EndIf

    ; M steepens the mesh, then rebuilds its collider, keeping the painted slots
    If KeyHit(50)
        For v=0 To CountVertices(surface)-1
            VertexCoords surface,v,VertexX(surface,v),VertexY(surface,v)-VertexX(surface,v)*0.05,VertexZ(surface,v)
        Next
        UpdateNormals ramp
        RefreshPhysicsMesh ramp_shape,ramp,0,0,0,0,0,0,True
    EndIf
    StepPhysics world,1.0/60.0,4

    ; Arrow keys move the camera
    If KeyDown(200) Then MoveEntity camera,0,0,0.1
    If KeyDown(208) Then MoveEntity camera,0,0,-0.1
    If KeyDown(203) Then TurnEntity camera,0,1,0
    If KeyDown(205) Then TurnEntity camera,0,-1,0

    RenderWorld

    Text 0,0,"Arrow keys: move camera   Space: paint ice   M: steepen the ramp   Esc: exit"
    Text 0,20,"RefreshPhysicsMesh ramp_shape,ramp,0,0,0,0,0,0,True"
    Text 0,40,"The last True keeps each triangle's material slot"

    Flip

Wend

FreePhysicsWorld world
End

Function PaintStrips(ramp,painted)
    ; Ice strips are pale blue, grippy strips are green
    surface=GetSurface(ramp,1)
    For v=0 To CountVertices(surface)-1
        If v/4<painted
            VertexColor surface,v,200,230,255
        Else
            VertexColor surface,v,120,200,140
        EndIf
    Next
End Function

Index