quads
quads copied to clipboard
quads - Geometry Tools
This package is a collection of quad geometry creation and manipulation tools. They can be used agnostic to any given library as they only operate on simple arrays and objects. Please note that this package is an early release, and the APIs may stabilize over time. More rigorous testing is also in the works.
Types
SimplicialComplex
This is a complicated math word that means an object with { positions, cells }. The
word mesh is used for convenience in this module, and normals are included with
this object.
// A single quad oriented facing up.
const mesh = {
positions: [[-1, 0, -1], [-1, 0, 1], [1, 0, 1], [1, 0, -1]],
normals: [[0, 1, 0], [0, 1, 0], [0, 1, 0], [0, 1, 0]],
cells: [[0, 1, 2, 3]]
}
Additional attributes may be added for one's own applications. For example:
mesh.colors = mesh.positions.map(p => [0, p.y, 0])
Type: Object
Properties
Position
An array of 3 values representing a position [x, y, z].
Type: Array
Cell
In a simplicial complex, a cell is an array of of indices that refer to a position or
some other attribute like normals. Quads have 4 indices, and this module uses the
convention of [a, b, c, d] with clockwise winding order.
b-------c
| |
| |
a-------d
Type: Array
Normal
An array of 3 values, [x, y, z] representing a surface normal. A valid normal has a length of 1. Normals are used for lighting calculation, and for knowing which way a surface is oriented in space. Many operation rely on valid normals.
Type: Array
API
averageNormalForPosition
Computes the average normal for a position given the connected cells.
Parameters
meshSimplicialComplexpositionIndexNumbertargetArray? = []normalCacheMap? A Map can be provided to cache intermediate normal computations.positionIndexToCellsMap? A Map where positionIndex is mapped to its cell, used primarily internally.
Returns Normal target
clone
Clones a cell. Returns the new cell.
Parameters
meshSimplicialComplexcellCell
Returns Cell cloned cell
computeCellCenter
Computes the center of a single cell.
Parameters
meshSimplicialComplexcellCell
Returns Position center
computeCenterPositions
Computes all of the centers of all the cells.
Parameters
meshSimplicialComplex
Returns Array<Position> centers
computeNormals
Updates all of the normals for all the positions using #averageNormalForPosition. If a normal doesn't exist, then it is created.
Parameters
meshSimplicialComplex
Returns SimplicialComplex
createBox
Creates a quad box of the given dimensions. This box will render as a
smoothed out box, as the normals are averaged. This is typically used for a
starting place for subdividing or extrusion operations. If the
optionalMesh object is passed, then the box will be created inside of
that simplicial complex, otherwise a new mesh simplicial complex will be
generated.
Parameters
Returns SimplicialComplex
createBoxDisjoint
Creates a quad box of the given dimensions, but with non-joined positions. This box renders as a flat shaded box. If the optionalMesh object is passed, then the box will be created inside of that simplicial complex, otherwise a new mesh simplicial complex will be generated.
Parameters
Returns SimplicialComplex
createQuad
Create a quad with options. If the optionalMesh object is passed, then the quad will be created inside of that simplicial complex, otherwise a new mesh simplicial complex will be generated. Both the mesh simplicial complex and the created cell are returned in an object.
Parameters
optionsObjectmeshSimplicialComplex?= {}
Examples
Usage:
const {mesh, cell} = createQuad({ positions: [[-1, 0, -1], [-1, 0, 1], [1, 0, 1], [1, 0, -1]] })
const {mesh, cell} = createQuad({ w: 1, h: 1 })
const {mesh, cell} = createQuad()
Returns Object {mesh, cell}
elementsFromQuads
Returns an elements array using the given ArrayType, which can be used by WebGL.
Parameters
meshSimplicialComplexdrawModeString?= 'triangles'ArrayTypetypeof?= Uint16Array
Returns Array Elements using the given ArrayType, which can be used by WebGL.
extrude
Given a target cell, first inset it, then move it along the cell's normal outwards by a given distance.
Parameters
meshSimplicialComplexcellCellinsetTNumber Value ranged from0to1, defaults to0extrudeNumber Distance to extrude, defaults to0
extrudeDisjoint
Given a target cell, first inset it, then move it along the cell's normal outwards by a given distance, but all new geometry generated will not share positions.
Parameters
meshSimplicialComplexcellCellinsetTNumber = 0, ranged from0(the edge) to1(the center).extrudeNumber = 0, the distance to extrude out.
flip
Flip a cell's normal to point the other way. Returns the cell.
Parameters
meshSimplicialComplexcellCell
Returns Cell The cell
getCellFromEdge
Find a cell given two position indices. Optionally provide a previousCell
that will not be matched against. Returns the first cell that matches.
Parameters
meshSimplicialComplexpositionIndexANumberpositionIndexBNumberpreviousCellCell? Optional will not be matched against
Returns Cell
getCellNormal
Compute a cell's normal regardless of it's neighboring cells.
Parameters
meshSimplicialComplexcellCelltargetNormal? = []
Returns Normal The target normal.
getCellsFromPositionIndex
Given a position index, find any cells that include it.
Parameters
Returns Array<Cell> The target cells.
getCenter
Computes the center of a cell.
Parameters
meshSimplicialComplexcellCelltargetPosition?= []
Returns Position center
getLoop
Gets a loop of cells. Given a single cell, start walking in both directions to select a loop. .
Parameters
meshSimplicialComplexcellCelltypeString can either be"cells","positions", or"normals".oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns Array an array according to the type.
getNewGeometry
Get all newly created geometry of the given type from whatever arbitrary operations were done on the mesh. This assumes new geometry was created and not destroyed.
Parameters
Examples
Usage:
const extrudedCells = quad.getNewGeometry(mesh, "cells", () => {
quad.extrude(mesh, tipCell, 0.5, 3)
});
Returns Array
inset
Inset a cell some value between 0 (its edges) and 1 (its center).
b----------c
|\ q1 /|
| \ / |
| f----g |
|q0| tC |q2| tc = targetCell
| e----h |
| / \ |
|/ q3 \|
a----------d
Parameters
meshSimplicialComplexcellCelltNumber Specifies where the split should be. Ranged from0to1, defaults to0.
Returns Array<Cell> cells [q0, q1, q2, q3, targetCell]
insetDisjoint
Inset a cell some value between 0 (its edges) and 1 (its center), but
keep the new cells disjoint so they do not share any positions.
bT----------cT
bL \ qT / cR
|\ \ / /|
| \ fT----gT / |
| fL fM----gM gR |
|qL| | tC | |qR| tC = targetCell
| eL eM----hM hR |
| / eB----hB \ |
|/ / \ \|
aL / qB \ dR
aB----------dB
Parameters
meshSimplicialComplexcellCelltNumber? value between 0 - 1 (optional, default0)
Returns Array<Cell> cells [qL, qT, qR, qB, targetCell].
insetLoop
Given a cell, walk a loop and inset the loop, where 0 is the inset being on the edge, and 1 the inset being in the enter. Setting opposite to true will make the cell walk the loop in the opposite direction, e.g. up/down rather than left/right.
*----*----*----*----*----*----*----*----*----*
| | | | | | | | | |
| | |<---|----|----|----|--->| | |
| | | | |cell| | | | |
| | |<---|----|----|----|--->| | |
| | | | | | | | | |
*----*----*----*----*----*----*----*----*----*
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns SimplicialComplex
mergePositions
Combine all positions together and recompute the normals.
Parameters
meshSimplicialComplex
Returns SimplicialComplex
mirror
Clone all existing geometry, and mirror it about the given axis.
Parameters
meshSimplicialComplexcellsCellaxisNumber is either0,1, or2, which represents thex,y, andzaxis respectively.
splitHorizontal
Split a cell horizontally.
b--------c
| |
ab------cd
| |
a--------d
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1targetCell
splitHorizontalDisjoint
Split a cell horizontally into two new disconnected cells.
b--------c
| |
ab1----cd1
ab2----cd2
| target |
a--------d
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1targetCell
splitLoop
Given a cell, walk along the mesh in both directions and split the cell.
*--------*--------*--------*--------*--------*--------*--------*
| | | | | | | |
* *<-------*--------*--cell--*--------*------->* *
| | | | | | | |
*--------*--------*--------*--------*--------*--------*--------*
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns SimplicialComplex
splitVertical
Split a cell horizontally.
b---bc---c
| | |
| | |
a---ad---d
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1, defaults to0.5.targetCell
splitVerticalDisjoint
Split a cell horizontally into two new disconnected cells.
b---bc1 bc2---c
| | | |
| | | |
a---ad1 ad2---d
Parameters
meshSimplicialComplexcellCelltNumber?= 0.5 Specifies where the split should be. Ranged from0to1, defaults to0.5.targetCell
subdivide
Use catmull clark subdivision to smooth out the geometry. All normals will be recomputed. Under the hood this is a convenience function for the module gl-catmull-clark.
Parameters
meshSimplicialComplexsubdivisionsNumberpositionsArray<Position>?= mesh.positionscellsCell?= mesh.cells
Returns SimplicialComplex
updateNormals
Updates all of the normals for all the positions using #averageNormalForPosition. If a normal doesn't exist, then it is created.
Parameters
meshSimplicialComplexcellCell
Returns SimplicialComplex
Three
splitVertical
Split a cell horizontally.
b---bc---c
| | |
| | |
a---ad---d
Parameters
$0Object quadtargetCellArraytNumber Specifies where the split should be. Ranged from0to1_ref
splitVerticalDisjoint
Split a cell horizontally into two new disconnected cells.
b---bc1 bc2---c
| | | |
| | | |
a---ad1 ad2---d
Parameters
splitHorizontal
Split a cell horizontally.
b--------c
| |
ab------cd
| |
a--------d
Parameters
$0.positionsArray$0.cellsArraytargetCellArraytNumber Specifies where the split should be. Ranged from0to1_ref2
splitHorizontalDisjoint
Split a cell horizontally into two new disconnected cells.
b--------c
| |
ab1----cd1
ab2----cd2
| target |
a--------d
Parameters
inset
Inset a cell some value between 0 (its edges) and 1 (its center).
b----------c
|\ q1 /|
| \ / |
| f----g |
|q0| tQ |q2|
| e----h |
| / \ |
|/ q3 \|
a----------d
Parameters
Returns Array cells [q0, q1, q2, q3, tC] where tC is the targetCell.
extrude
Given a target cell, first inset it, then move it along the cell's normal outwards by a given distance.
Parameters
averageNormalForPosition
Computes the average normal for a position given the connected cells.
Parameters
meshObjectpositionIndexNumbertargetArray? = []normalCacheMap? = new Map() can be provided to cache intermediate normal computations.positionIndexToCellsNumber
Returns any the targetNormal
insetDisjoint
Inset a cell some value between 0 (its edges) and 1 (its center), but
keep the new cells disjoint so they do not share any positions.
bT----------cT
bL \ qT / cR
|\ \ / /|
| \ fT----gT / |
| fL fM----gM gR |
|qL| | tC | |qR| tC = targetCell
| eL eM----hM hR |
| / eB----hB \ |
|/ / \ \|
aL / qB \ dR
aB----------dB
Parameters
Returns Array cells [q0, q1, q2, q3, tC] where tC is the targetCell.
extrudeDisjoint
Given a target cell, first inset it, then move it along the cell's normal outwards by a given distance, but all new geometry generated will not share positions.
Parameters
getCenter
Computes the center of a cell
Parameters
Returns Array the targetPosition
clone
Clones a cell. Returns the new cell.
Parameters
Returns Array a new cell
updateNormals
Updates all of the normals for all the positions using #averageNormalForPosition. If a normal doesn't exist, then it is created.
Parameters
Returns Object mesh
getCellNormal
Compute a cell's normal regardless of it's neighboring cells.
Parameters
Returns Array The target normal.
getCellsFromPositionIndex
Given a position index, find any cells that include it.
Parameters
Returns Array The target cells.
flip
Flip a cell's normal to point the other way. Returns the cell.
Parameters
Returns Array The cell
createQuad
Create a quad with options. If the optionalMesh object is passed, then the quad will be created inside of that simplicial complex, otherwise a new mesh simplicial complex will be generated. Both the mesh simplicial complex and the created cell are returned in an object.
Parameters
Examples
Usage:
const {mesh, cell} = createQuad({ positions: [[-1, 0, -1], [-1, 0, 1], [1, 0, 1], [1, 0, -1]] })
const {mesh, cell} = createQuad({ w: 1, h: 1 })
const {mesh, cell} = createQuad()
Returns Object {mesh, cell}
createBoxDisjoint
Creates a quad box of the given dimensions, but with non-joined positions. This box renders as a flat shaded box. If the optionalMesh object is passed, then the box will be created inside of that simplicial complex, otherwise a new mesh simplicial complex will be generated.
Parameters
Returns Object a simplicial complex
createBox
Creates a quad box of the given dimensions. This box will render as a
smoothed out box, as the normals are averaged. This is typically used for a
starting place for subdividing or extrusion operations. If the
optionalMesh object is passed, then the box will be created inside of
that simplicial complex, otherwise a new mesh simplicial complex will be
generated.
Parameters
Returns Object a simplicial complex
mergePositions
Combine all positions together and recompute the normals.
Parameters
meshObject
Returns Object mesh
elementsFromQuads
Returns an elements array using the given ArrayType, which can be used by WebGL.
Parameters
Returns Array Elements using the given ArrayType, which can be used by WebGL.
computeNormals
Updates all of the normals for all the positions using #averageNormalForPosition. If a normal doesn't exist, then it is created.
Parameters
meshObject
Returns Object The mesh
splitLoop
Given a cell, walk along the mesh in both directions and split the cell.
*--------*--------*--------*--------*--------*--------*--------*
| | | | | | | |
* *<-------*--------*--cell--*--------*------->* *
| | | | | | | |
*--------*--------*--------*--------*--------*--------*--------*
Parameters
meshObjectcellArraytNumber Specifies where the split should be. Ranged from0to1oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns Object mesh
getCellFromEdge
Find a cell given two position indices. Optionally provide a previousCell
that will not be matched against. Returns the first cell that matches.
Parameters
meshObjectpositionIndexANumberpositionIndexBNumberpreviousCellArray? Optional will not be matched against
Returns Array Elements using the given ArrayType, which can be used by WebGL.
getNewGeometry
Get all newly created geometry of the given type from whatever arbitrary operations were done on the mesh. This assumes new geometry was created and not destroyed.
Parameters
Examples
Usage:
const extrudedCells = quad.getNewGeometry(mesh, "cells", () => {
quad.extrude(mesh, tipCell, 0.5, 3)
});
Returns Array
subdivide
Use catmull clark subdivision to smooth out the geometry. All normals will be recomputed. Under the hood this is a convenience function for the module gl-catmull-clark.
Parameters
Returns Object mesh
computeCenterPositions
Computes all of the centers of all the cells.
Parameters
meshObject
Returns any A new array
computeCellCenter
Computes the center of a single cell.
Parameters
Returns any A new array
insetLoop
Given a cell, walk a loop and inset the loop, where 0 is the inset being on the edge, and 1 the inset being in the enter. Setting opposite to true will make the cell walk the loop in the opposite direction, e.g. up/down rather than left/right.
*----*----*----*----*----*----*----*----*----*
| | | | | | | | | |
| | |<---|----|----|----|--->| | |
| | | | |cell| | | | |
| | |<---|----|----|----|--->| | |
| | | | | | | | | |
*----*----*----*----*----*----*----*----*----*
Parameters
meshObjectcellArraytNumber Specifies where the split should be. Ranged from0to1oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns Object mesh
getLoop
Gets a loop of cells. Given a single cell, start walking in both directions to select a loop. .
Parameters
meshObjectcellArraytypeString can either be"cells","positions", or"normals".oppositeBoolean will walk in the opposite direction, e.g. up and down, versus left and right
Returns Array an array according to the type.
mirror
Clone all existing geometry, and mirror it about the given axis.
Parameters