Blitz3D+ Command Reference

PhysicsDebugDraw world,camera[,flags]

Parameters

world - live physics-world handle.
camera - live camera entity used to project the overlay.
flags - combined bits from the table below; default 7 retains joints, contacts and bounds. Zero draws nothing. Negative values and unknown bits cause a runtime error.

BitLayer
1Native joint geometry, with available limits and extra geometry.
2Contact crosses, normals and signed separation labels in centimetres.
4Native fat shape AABBs, including broad-phase margin; not exact body bounds.
8Collider wire geometry: sphere circles, capsule rings/arcs, hull edges and solid mesh/terrain triangle edges.
16Dynamic-body centre-of-mass axes and mass labels in kilograms.
32Both joint attachment frames, including joints with shapeless or disabled bodies.
64Approximate native normal-force arrows and labels.
128Independent approximate native friction-force arrows and magnitude labels.
256Native hexadecimal contact feature labels; these are not Blitz handles.
512Native island bounds.
1024Contact crosses coloured by solver graph assignment.
4096Managed scene colliders, movement roles and body identities. Requires the shared world returned by GetWorldPhysics.

Description

Draws a world's diagnostics through renderer-owned 2D lines and text. Call after RenderWorld and before Flip. Add distinct flags or combine with Or; for example 24 shows collider geometry, centres of mass and mass labels. Default 7 does not include the new layers.

The overlay is not depth-tested. It respects camera viewport offsets, near/far clipping, perspective or orthographic projection, current 2D Viewport and buffer bounds. It ignores the current Origin while aligning to the camera, then restores Origin and Viewport and leaves Color white. A camera with projection mode 0 draws nothing. Text uses the current font; crowded or combined labels can overlap.

Shape, COM and island selection uses enabled native shape proxies. Sleeping enabled shapes remain visible; disabled shapes do not. Contact layers show awake solver pairs, including speculative contacts, rather than sensor overlaps or retained event history. Native joint geometry requires at least one participating body selected through a shape proxy. Flag 32 separately visits all public joints. Frame axes are red X, green Y and blue Z, each 0.3 metres long.

Force arrows are native solver estimates, not calibrated physical reaction-force measurements. The display uses half the stored impulse times the last step's inverse timestep. Normal estimates use totalNormalImpulse, which includes repeated bias/relaxation solver passes; friction uses the manifold friction impulse. Arrow length is 0.05 metres per displayed estimate unit. Do not treat changes between substep settings as physical force changes. Use the documented joint reaction getters for joint loads.

Drawing neither steps nor wakes bodies, consumes no events and records no mutations. Geometry replacement updates the next draw without another step. Sphere/capsule curves are sampled wire outlines; hull edges and mesh/terrain solid triangle edges use native cooked geometry, scale and transforms. Terrain holes are omitted.

For entity physics, keep the handle from GetWorldPhysics and use PhysicsDebugDraw world,camera,4096 after RenderWorld. This optional layer draws committed canonical geometry in the body's role colour: grey for static, blue for kinematic, green for free dynamic and purple for Collisions-controlled. Compatibility geometry uses short orange segments, leaving canonical edges visible when the shapes coincide. Each label shows the same body handle returned by EntityPhysicsBody, its movement role, and C/K counts for canonical/compatibility colliders. Counts describe actual colliders; they do not imply additional bodies or mass.

Layer 4096 includes sleeping enabled bodies and omits disabled bodies. It replaces layer 8 when both are selected; other diagnostic layers can be combined normally. It reads committed native geometry without applying pending entity edits, cooking colliders or stepping. Use UpdateWorld to apply edits, or GetWorldPhysics to explicitly reconcile without stepping. A previously obtained world handle can inspect the retained scene after a rejected edit. The layer is unavailable for standalone physics worlds or replay players. Bit 2048 remains unsupported by this command; PhysicsPlayerDebugDraw uses it for replayed queries.

Each world retains at most 262,144 lines and 8,192 labels (127 bytes per label). Exceeding either bound raises a runtime error before any primitives from that capture are drawn. Storage is reused until world teardown. Large scenes and many labels can be expensive; enable only the layers needed.

Optional native logging: set environment variable B3D_BOX3D_LOG to 1, including with SetEnv. Native messages then enter the existing bounded diagnostics store at Information level, category physics, source Box3D. Unset or other values preserve console logging. Ordinary steps may emit no messages. This is process-wide, thread-safe diagnostic routing; native workers never call Blitz functions. Native assertions retain their existing handler and fail-fast behaviour.

Requires Extended mode.

See also: StepPhysics, PhysicsBodyCenterX, PhysicsJointForceX, CapturePhysicsProfile, CountDiagnostics, DiagnosticMessage, ClearDiagnostics.

Example

; Native physics overlays. Requires Extended mode.
Graphics3D 1120,820,0,2
SetBuffer BackBuffer()
AppTitle "Blitz3D+ - physics debug layers"
Global world=CreatePhysicsWorld(),flags=8,overlay=True,paused=False,show_meshes=True,ortho=False
Global ball=CreateSphere(20),ball_body,ball_shape,ball_size#=1
Global block=CreateCube(),block_body,hinge,enabled=True
Dim layer_bits(11): Dim layer_keys(11): Dim layer_names$(11)
For i=1 To 11: layer_bits(i)=1 Shl (i-1): layer_keys(i)=i+1: Next
layer_keys(11)=34
layer_names(1)="1  Joint geometry / limits"
layer_names(2)="2  Contact points / normals"
layer_names(3)="3  Fat shape bounds"
layer_names(4)="4  Collider wire geometry"
layer_names(5)="5  Dynamic COM / mass"
layer_names(6)="6  Joint attachment frames"
layer_names(7)="7  Approx. normal forces"
layer_names(8)="8  Approx. friction forces"
layer_names(9)="9  Contact feature labels"
layer_names(10)="0  Island bounds"
layer_names(11)="G  Solver graph colours"
camera=CreateCamera(): CameraViewport camera,340,130,760,660
CameraClsColor camera,16,23,36: PositionEntity camera,13,13,-20: CameraZoom camera,2.8
target=CreatePivot(): PositionEntity target,0,1,0: PointEntity camera,target
light=CreateLight(): RotateEntity light,45,-30,0: AmbientLight 110,120,140
floor=CreateCube(): ScaleEntity floor,5,.25,4: PositionEntity floor,0,-.25,0: EntityColor floor,45,55,70
floor_body=CreatePhysicsBody(world,floor,0): fs=PhysicsBodyBox(floor_body,10,.5,8)
ScaleEntity ball,.5,.5,.5: EntityColor ball,240,155,65
ball_body=CreatePhysicsBody(world,ball,2): ball_shape=PhysicsBodySphere(ball_body,1): PhysicsShapeRestitution ball_shape,.5
PhysicsBodySleeping ball_body,False: PhysicsBodyDamping ball_body,.3,.2
ScaleEntity block,1,.3,.6: EntityColor block,70,175,235
block_body=CreatePhysicsBody(world,block,2): bs=PhysicsBodyBox(block_body,2,.6,1.2)
; A shaped fixed anchor keeps native joint geometry visible.
anchor=CreatePivot(): PositionEntity anchor,1,2,0
anchor_body=CreatePhysicsBody(world,anchor,0): aps=PhysicsBodySphere(anchor_body,.15,0)
ResetPhysicsBody block_body,2,2,0,0,0,0
hinge=CreatePhysicsHingeJoint(anchor_body,block_body,1,2,0,0,0,1)
PhysicsJointLimits hinge,True,-.7,.7
PhysicsJointMotor hinge,True,1.2,20
capsule=CreatePivot(): PositionEntity capsule,-3,1.25,2
cap_body=CreatePhysicsBody(world,capsule,0): cs=PhysicsBodyCapsule(cap_body,1,2.5)
cap_mid=CreateCylinder(20,True,capsule): ScaleEntity cap_mid,.5,.75,.5: EntityColor cap_mid,100,210,150
For side=-1 To 1 Step 2
    cap_end=CreateSphere(16,capsule): ScaleEntity cap_end,.5,.5,.5: PositionEntity cap_end,0,.75*side,0: EntityColor cap_end,100,210,150
Next
; A cooked hull and a triangle ramp expose their actual edges.
hull=CreateCone(8): ScaleEntity hull,.8,1,.8: PositionEntity hull,3,1,2: EntityColor hull,180,120,225
hull_body=CreatePhysicsBody(world,hull,0): hs=PhysicsBodyHull(hull_body,hull)
ramp=CreateMesh(): surf=CreateSurface(ramp)
AddVertex surf,-1,0,-1: AddVertex surf,1,0,-1: AddVertex surf,1,.8,1: AddVertex surf,-1,.8,1
AddTriangle surf,0,2,1: AddTriangle surf,0,3,2: UpdateNormals ramp
PositionEntity ramp,-1,0,2: EntityColor ramp,200,190,100: EntityFX ramp,16
ramp_body=CreatePhysicsBody(world,ramp,0): rs=PhysicsBodyMesh(ramp_body,ramp)
ResetDebugLoads()
timer=CreateTimer(60)
While Not KeyDown(1)
    For i=1 To 11
        If KeyHit(layer_keys(i)) Then flags=flags Xor layer_bits(i)
    Next
    If KeyHit(57) Then overlay=Not overlay
    If KeyHit(25) Then paused=Not paused
    If KeyHit(50)
        show_meshes=Not show_meshes
        If show_meshes
            ShowEntity ball: ShowEntity block: ShowEntity capsule: ShowEntity hull: ShowEntity ramp: ShowEntity floor
        Else
            HideEntity ball: HideEntity block: HideEntity capsule: HideEntity hull: HideEntity ramp: HideEntity floor
        EndIf
    EndIf
    If KeyHit(24)
        ortho=Not ortho
        If ortho Then CameraProjMode camera,2: CameraZoom camera,.09 Else CameraProjMode camera,1: CameraZoom camera,2.8
    EndIf
    If KeyHit(18) Then enabled=Not enabled: PhysicsBodyActive ball_body,enabled
    If KeyHit(44)
        ball_size=2.5-ball_size
        PhysicsShapeSphere ball_shape,ball_size,0,0,0
        ScaleEntity ball,ball_size/2,ball_size/2,ball_size/2
    EndIf
    If KeyHit(19) Then ResetDebugLoads()
    ticks=WaitTimer(timer): If ticks>6 Then ticks=6
    If paused=False
        For tick=1 To ticks
            If enabled Then PhysicsBodyForce ball_body,.5,0,0
            StepPhysics world,1.0/60,4
        Next
        If EntityY(ball)<-4 Then ResetPhysicsBody ball_body,-2,4,-1,0,0,0
    EndIf
    RenderWorld
    If overlay Then PhysicsDebugDraw world,camera,flags
    Color 235,240,250
    Text 18,18,"PHYSICS DEBUG LAYERS"
    Text 18,49,"Native collider geometry, contacts and constraints"
    Text 18,82,"Space: overlay   P: pause   M: meshes   O: projection   E: enable ball   Z: resize ball   R: reset   Esc: exit"
    For i=1 To 11
        Color 115,130,150: state$="off"
        If flags And layer_bits(i) Then Color 115,230,170: state="ON"
        Text 18,146+(i-1)*29,layer_names(i)
        Text 298,146+(i-1)*29,state
    Next
    Color 235,240,250
    Text 18,488,"Flags: "+flags+"   Overlay: "+overlay
    Text 18,514,"Paused: "+paused+"   Meshes: "+show_meshes
    Text 18,540,"Ortho: "+ortho+"   Ball active: "+PhysicsBodyIsEnabled(ball_body)
    Text 18,566,"Ball diameter: "+ball_size+" m"
    Text 18,610,"Frames: red X / green Y / blue Z"
    Text 18,636,"Mass labels: kilograms"
    Text 18,662,"Forces: native diagnostic estimates"
    Text 18,688,"Contact layers show awake pairs."
    Text 18,714,"Combine layers; crowded labels overlap."
    Text 18,750,"M hides meshes so wire edges stand out."
    Text 18,776,"R resets poses; layer choices stay set."
    Flip
Wend
FreeTimer timer
FreePhysicsWorld world
ClearWorld
End

Function ResetDebugLoads()
    ResetPhysicsBody ball_body,-2,4,-1,0,0,0
    ResetPhysicsBody block_body,2,2,0,0,0,0
    PhysicsBodyAwake block_body,True
End Function

Index