Options
All
  • Public
  • Public/Protected
  • All
Menu

Class WgCollisionAlgorithm

Implements the collision algorithm. This class is responsible for the following:

  • Initialization of buffers and data structures necessary for the collision detection (based on provided Components)
  • Keeping track of buffers and using them in GPU operations
  • Update of the matrix of a component
  • Update of collision detection parameters
  • Update of rendering parameters
  • Reading the collision detection results from the GPU to the CPU (slow)
  • Keeping track of the error/imprecision of the collision detection calculations

The first step of the algorithm is defining a uniform grid that will contain all the atoms. This allows us to compare an atom only with its neighbors, and not with all other atoms. We try to have each cell of the grid have the size of the smallest atom radius. If the grid is too large and there are too many cells, we increase the size of the cells until there aren't too many cells.

The algorithm consists of the following passes:

  • ASSIGN passes (assigns the atoms to a cell in a grid)

    • FILL per grid cell: set all elements of perBin_elemCount to ZERO
    • FILL per atom: set all elements of perElem_bonds_sorted
    • GRID ASSIGN per atom: update the matrix of a specific component (if requested)
                        and, most importantly, assign each atom to a grid cell
      
  • SORT passes (sorts the atoms by their cell - improves caching coherence - counting sort)

    • SCAN passes (multiple) per grid cell: performs a scan/prefix-sum on perBin_elemCountScan
    • FILL per atom: sets all elements of perElem_elemId_sorted to 0xffffffff (U32 max)
    • SORT per atom: calculates the new indexes for every atom, from perElem_binId
    • MAP XYZ per atom: based on the new indices from SORT, map/rearrange all other
                                        atom data (positions, etc.)
      
  • COLLIDE GLOBAL passes (actually only one pass... performs the collision detection!)

    • COLLIDE GLOBAL per atom: see WgCompCollisionGlobalShader for more details
  • RENDER passes (optional - again, only one pass)

    • RENDER pet atom: Based on atom positions and the result of the collision detection,
                   render the atoms that do collide
      

Hierarchy

Index

Constructors

constructor

Properties

Private Readonly assignPasses

assignPasses: WgPass[] = []

Private assignShader

Private Readonly buffers

buffers: { bin_maxElemCount: WgBuffer<Uint32Array>; perBin_elemCountScan: WgBuffer<Uint32Array>; perElem_binId: WgBuffer<Uint32Array>; perElem_bonds: WgBuffer<Uint32Array>; perElem_bonds_sorted: WgBuffer<Uint32Array>; perElem_collision: WgBuffer<Uint32Array>; perElem_collision_output: WgBuffer<Uint32Array>; perElem_collision_unsorted: WgBuffer<Uint32Array>; perElem_elemData: WgBuffer<Float32Array>; perElem_elemData_sorted: WgBuffer<Float32Array>; perElem_elemId_sorted: WgBuffer<Uint32Array> }

Type declaration

  • bin_maxElemCount: WgBuffer<Uint32Array>
  • perBin_elemCountScan: WgBuffer<Uint32Array>
  • perElem_binId: WgBuffer<Uint32Array>
  • perElem_bonds: WgBuffer<Uint32Array>
  • perElem_bonds_sorted: WgBuffer<Uint32Array>
  • perElem_collision: WgBuffer<Uint32Array>
  • perElem_collision_output: WgBuffer<Uint32Array>
  • perElem_collision_unsorted: WgBuffer<Uint32Array>
  • perElem_elemData: WgBuffer<Float32Array>
  • perElem_elemData_sorted: WgBuffer<Float32Array>
  • perElem_elemId_sorted: WgBuffer<Uint32Array>

Private Readonly collideGlobalPasses

collideGlobalPasses: WgPass[] = []

Private collisionShader

Private Readonly componentData

componentData: Map<AtomicComponent, ComponentData>

Protected Readonly context

context: WgContext

Private Optional Readonly debug

debug: undefined | string

Private Readonly grid

grid: Grid

Private Readonly numElems

numElems: number

Private ranOnce

ranOnce: boolean = false

Private Readonly renderPasses

renderPasses: WgPass[] = []

Private renderShader

renderShader: null | WgRendCollisionShader = null

Private renderTarget

renderTarget: null | WgRenderTarget = null

Private rf

Private Readonly sortPasses

sortPasses: WgPass[] = []

Static Private Readonly MAX_BINDING_SIZE

MAX_BINDING_SIZE: 134217728 = 134217728

Static Readonly MAX_BINS

MAX_BINS: number = Math.min(WgCollisionAlgorithm.MAX_BINDING_SIZE / 4, WgCollisionAlgorithm.MAX_SIZE)

Static Readonly MAX_COMPONENTS

MAX_COMPONENTS: 256 = 256

Static Private Readonly MAX_DISPATCH_SIZE

MAX_DISPATCH_SIZE: 65535 = 65535

Static Readonly MAX_ELEMENTS

MAX_ELEMENTS: number = Math.min(WgCollisionAlgorithm.MAX_BINDING_SIZE / (4 * 4), WgCollisionAlgorithm.MAX_SIZE, 16777215)

Static Private Readonly MAX_SIZE

MAX_SIZE: number = WgCollisionAlgorithm.MAX_DISPATCH_SIZE * WgCollisionAlgorithm.WORKGROUP_SIZE

Static Private Readonly WORKGROUP_SIZE

WORKGROUP_SIZE: 256 = 256

Accessors

gridBox

  • get gridBox(): Box3

Methods

Private _resetComponent

  • _resetComponent(c: ComponentObject, elemData: Float32Array, bonds: Uint32Array, offset: number): number

Protected _run

  • _run(passes: WgPass[], debug?: undefined | string): Promise<void>

activateRendering

Private createAssignPasses

  • createAssignPasses(): WgPass[]

Private createCollideGlobalPasses

Private createSortPasses

  • createSortPasses(): WgPass[]

deactivateRendering

  • deactivateRendering(): void

dispose

  • dispose(): void

draw

  • draw(): Promise<void>

getError

  • Gets the error/imprecision of the collision detection calculations for a specific component

    Explanation: The precise way to update the positions of the atoms of a Component when its matrix changes would be (1) get the initial positions of the atoms (2) transform these positions by the new matrix. However, we do not have the initial atom positions on the GPU! So instead, we (1) get the current positions of the atoms (2) transform these positions by the (newMatrix * inverse(oldMatrix)). However, this comes with a cost: the result of this operation is imprecise. It is not the same as the first method. The imprecision is the sum of all elements of the absolute element-wise difference of newMatrix and ( (newMatrix * inverse(oldMatrix)) * oldMatrix ), or, perhaps more concise:

    trans = new * inv(old);                      <- Matrix to go from old to new position
    error = sum( abs( (trans * old) - new ) );   <- abs() is elementwise
                                                    sum() sums the individual matrix elements
    

    Parameters

    • c: AtomicComponent

      The component to get the collision detection error/imprecision of

    Returns null | number

read

  • read(): Promise<Uint32Array>

readAsBitArray

resetComponent

Private run

  • WARNING: Make sure you run start() once before running this function Runs the entire collision detection pipeline, including rendering

    Parameters

    • Optional td: TransformData

      The data necessary to apply a transformation to one component in the next collision detection algorithm. If nothing/undefined is provided, no transformation will occur

    Returns Promise<void>

setCollisionUniforms

  • setCollisionUniforms(uniforms: { lenience: number }): void

setRenderUniforms

setSize

  • setSize(width: number, height: number): Promise<void>

start

  • start(): Promise<void>

updateComponent

  • updateComponent(c: AtomicComponent, matrix?: Matrix4): Promise<void | this>

Generated using TypeDoc