Skip to content
Snippets Groups Projects
Commit 6828e78f authored by Alexander Rose's avatar Alexander Rose
Browse files

simplified primitive handling in mesh-builder

parent c53c5cc3
Branches
Tags
No related merge requests found
...@@ -8,9 +8,9 @@ import { ValueCell } from 'mol-util/value-cell' ...@@ -8,9 +8,9 @@ import { ValueCell } from 'mol-util/value-cell'
import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra'; import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra';
import { ChunkedArray } from 'mol-data/util'; import { ChunkedArray } from 'mol-data/util';
import { Plane, PlaneProps } from '../primitive/plane'; import { Plane } from '../primitive/plane';
import { Cylinder, CylinderProps } from '../primitive/cylinder'; import { Cylinder, CylinderProps } from '../primitive/cylinder';
import { Sphere, SphereProps } from '../primitive/sphere'; import { Sphere } from '../primitive/sphere';
import { Mesh } from './mesh'; import { Mesh } from './mesh';
import { getNormalMatrix } from '../util'; import { getNormalMatrix } from '../util';
import { addSheet } from './sheet'; import { addSheet } from './sheet';
...@@ -31,9 +31,11 @@ export interface MeshBuilderState { ...@@ -31,9 +31,11 @@ export interface MeshBuilderState {
export interface MeshBuilder { export interface MeshBuilder {
add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices?: ArrayLike<number>): void add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices?: ArrayLike<number>): void
addPrimitive(t: Mat4, primitive: Primitive): void,
addBox(t: Mat4): void addBox(t: Mat4): void
addPerforatedBox(t: Mat4): void addPerforatedBox(t: Mat4): void
addPlane(t: Mat4, props?: PlaneProps): void addPlane(t: Mat4): void
addWedge(t: Mat4): void addWedge(t: Mat4): void
addDiamondPrism(t: Mat4): void addDiamondPrism(t: Mat4): void
addPentagonalPrism(t: Mat4): void addPentagonalPrism(t: Mat4): void
...@@ -43,18 +45,21 @@ export interface MeshBuilder { ...@@ -43,18 +45,21 @@ export interface MeshBuilder {
addStar(t: Mat4, props?: StarProps): void addStar(t: Mat4, props?: StarProps): void
addOctahedron(t: Mat4): void addOctahedron(t: Mat4): void
addPerforatedOctahedron(t: Mat4): void addPerforatedOctahedron(t: Mat4): void
addCylinder(start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps): void addCylinder(start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps): void
addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void
addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void
addSphere(center: Vec3, radius: number, detail: number): void addSphere(center: Vec3, radius: number, detail: number): void
addTube(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean): void addTube(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean): void
addSheet(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean): void addSheet(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean): void
setGroup(id: number): void setGroup(id: number): void
getMesh(): Mesh getMesh(): Mesh
} }
const cylinderMap = new Map<string, Primitive>() const cylinderMap = new Map<string, Primitive>()
const sphereMap = new Map<string, Primitive>() const sphereMap = new Map<number, Primitive>()
const up = Vec3.create(0, 1, 0) const up = Vec3.create(0, 1, 0)
const tmpV = Vec3.zero() const tmpV = Vec3.zero()
...@@ -64,7 +69,6 @@ const tmpCylinderDir = Vec3.zero() ...@@ -64,7 +69,6 @@ const tmpCylinderDir = Vec3.zero()
const tmpCylinderMatDir = Vec3.zero() const tmpCylinderMatDir = Vec3.zero()
const tmpCylinderCenter = Vec3.zero() const tmpCylinderCenter = Vec3.zero()
const tmpCylinderMat = Mat4.zero() const tmpCylinderMat = Mat4.zero()
// const tmpCylinderMatTrans = Mat4.zero()
const tmpCylinderStart = Vec3.zero() const tmpCylinderStart = Vec3.zero()
const tmpUp = Vec3.zero() const tmpUp = Vec3.zero()
...@@ -91,22 +95,19 @@ function getCylinder(props: CylinderProps) { ...@@ -91,22 +95,19 @@ function getCylinder(props: CylinderProps) {
const tmpSphereMat = Mat4.identity() const tmpSphereMat = Mat4.identity()
function setSphereMat(m: Mat4, center: Vec3) { function setSphereMat(m: Mat4, center: Vec3, radius: number) {
return Mat4.setTranslation(m, center) return Mat4.scaleUniformly(m, Mat4.fromTranslation(m, center), radius)
} }
function getSphere(props: SphereProps) { function getSphere(detail: number) {
const key = JSON.stringify(props) let sphere = sphereMap.get(detail)
let sphere = sphereMap.get(key)
if (sphere === undefined) { if (sphere === undefined) {
sphere = Sphere(props) sphere = Sphere(detail)
sphereMap.set(key, sphere) sphereMap.set(detail, sphere)
} }
return sphere return sphere
} }
// TODO cache primitives based on props
export namespace MeshBuilder { export namespace MeshBuilder {
export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder { export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder {
const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount); const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount);
...@@ -118,97 +119,66 @@ export namespace MeshBuilder { ...@@ -118,97 +119,66 @@ export namespace MeshBuilder {
let currentGroup = -1 let currentGroup = -1
function add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices: ArrayLike<number>) { function add(t: Mat4, va: ArrayLike<number>, na: ArrayLike<number>, ia: ArrayLike<number>) {
const { elementCount } = vertices const offset = vertices.elementCount
const n = getNormalMatrix(tmpMat3, t) const n = getNormalMatrix(tmpMat3, t)
for (let i = 0, il = _vertices.length; i < il; i += 3) { for (let i = 0, il = va.length; i < il; i += 3) {
// position // position
Vec3.fromArray(tmpV, _vertices, i) Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, va, i), t)
Vec3.transformMat4(tmpV, tmpV, t)
ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]); ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]);
// normal // normal
Vec3.fromArray(tmpV, _normals, i) Vec3.transformMat3(tmpV, Vec3.fromArray(tmpV, na, i), n)
Vec3.transformMat3(tmpV, tmpV, n)
ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]); ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]);
// group // group
ChunkedArray.add(groups, currentGroup); ChunkedArray.add(groups, currentGroup);
} }
for (let i = 0, il = _indices.length; i < il; i += 3) { for (let i = 0, il = ia.length; i < il; i += 3) {
ChunkedArray.add3(indices, _indices[i] + elementCount, _indices[i + 1] + elementCount, _indices[i + 2] + elementCount); ChunkedArray.add3(indices, ia[i] + offset, ia[i + 1] + offset, ia[i + 2] + offset);
} }
} }
function addPrimitive(t: Mat4, primitive: Primitive) {
const { vertices, normals, indices } = primitive
add(t, vertices, normals, indices)
}
return { return {
add, add,
addBox: (t: Mat4) => { addPrimitive,
const { vertices, normals, indices } = Box()
add(t, vertices, normals, indices) addBox: (t: Mat4) => addPrimitive(t, Box()),
}, addPerforatedBox: (t: Mat4) => addPrimitive(t, PerforatedBox()),
addPerforatedBox: (t: Mat4) => { addPlane: (t: Mat4) => addPrimitive(t, Plane()),
const { vertices, normals, indices } = PerforatedBox() addWedge: (t: Mat4) => addPrimitive(t, Wedge()),
add(t, vertices, normals, indices) addDiamondPrism: (t: Mat4) => addPrimitive(t, DiamondPrism()),
}, addPentagonalPrism: (t: Mat4) => addPrimitive(t, PentagonalPrism()),
addPlane: (t: Mat4, props?: PlaneProps) => { addHexagonalPrism: (t: Mat4) => addPrimitive(t, HexagonalPrism()),
const { vertices, normals, indices } = Plane(props) addOctagonalPyramid: (t: Mat4) => addPrimitive(t, OctagonalPyramide()),
add(t, vertices, normals, indices) addPerforatedOctagonalPyramid: (t: Mat4) => addPrimitive(t, PerforatedOctagonalPyramid()),
}, addStar: (t: Mat4, props?: StarProps) => addPrimitive(t, Star(props)),
addWedge: (t: Mat4) => { addOctahedron: (t: Mat4) => addPrimitive(t, Octahedron()),
const { vertices, normals, indices } = Wedge() addPerforatedOctahedron: (t: Mat4) => addPrimitive(t, PerforatedOctahedron()),
add(t, vertices, normals, indices)
},
addDiamondPrism: (t: Mat4) => {
const { vertices, normals, indices } = DiamondPrism()
add(t, vertices, normals, indices)
},
addPentagonalPrism: (t: Mat4) => {
const { vertices, normals, indices } = PentagonalPrism()
add(t, vertices, normals, indices)
},
addHexagonalPrism: (t: Mat4) => {
const { vertices, normals, indices } = HexagonalPrism()
add(t, vertices, normals, indices)
},
addOctagonalPyramid: (t: Mat4) => {
const { vertices, normals, indices } = OctagonalPyramide()
add(t, vertices, normals, indices)
},
addPerforatedOctagonalPyramid: (t: Mat4) => {
const { vertices, normals, indices } = PerforatedOctagonalPyramid()
add(t, vertices, normals, indices)
},
addStar: (t: Mat4, props?: StarProps) => {
const { vertices, normals, indices } = Star(props)
add(t, vertices, normals, indices)
},
addOctahedron: (t: Mat4) => {
const { vertices, normals, indices } = Octahedron()
add(t, vertices, normals, indices)
},
addPerforatedOctahedron: (t: Mat4) => {
const { vertices, normals, indices } = PerforatedOctahedron()
add(t, vertices, normals, indices)
},
addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => { addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => {
const d = Vec3.distance(start, end) * lengthScale const d = Vec3.distance(start, end) * lengthScale
props.height = d props.height = d
const { vertices, normals, indices } = getCylinder(props)
Vec3.sub(tmpCylinderDir, end, start) Vec3.sub(tmpCylinderDir, end, start)
setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d) setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d)
add(tmpCylinderMat, vertices, normals, indices) addPrimitive(tmpCylinderMat, getCylinder(props))
}, },
addDoubleCylinder: (start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) => { addDoubleCylinder: (start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) => {
const d = Vec3.distance(start, end) * lengthScale const d = Vec3.distance(start, end) * lengthScale
props.height = d props.height = d
const { vertices, normals, indices } = getCylinder(props) const cylinder = getCylinder(props)
Vec3.sub(tmpCylinderDir, end, start) Vec3.sub(tmpCylinderDir, end, start)
// positivly shifted cylinder // positivly shifted cylinder
Vec3.add(tmpCylinderStart, start, shift) Vec3.add(tmpCylinderStart, start, shift)
setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d)
add(tmpCylinderMat, vertices, normals, indices) addPrimitive(tmpCylinderMat, cylinder)
// negativly shifted cylinder // negativly shifted cylinder
Vec3.sub(tmpCylinderStart, start, shift) Vec3.sub(tmpCylinderStart, start, shift)
setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d)
add(tmpCylinderMat, vertices, normals, indices) addPrimitive(tmpCylinderMat, cylinder)
}, },
addFixedCountDashedCylinder: (start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) => { addFixedCountDashedCylinder: (start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) => {
const s = Math.floor(segmentCount / 2) const s = Math.floor(segmentCount / 2)
...@@ -223,7 +193,7 @@ export namespace MeshBuilder { ...@@ -223,7 +193,7 @@ export namespace MeshBuilder {
const d = Vec3.distance(start, end) * lengthScale const d = Vec3.distance(start, end) * lengthScale
props.height = d * step props.height = d * step
const { vertices, normals, indices } = getCylinder(props) const cylinder = getCylinder(props)
Vec3.sub(tmpCylinderDir, end, start) Vec3.sub(tmpCylinderDir, end, start)
for (let j = 0; j < s; ++j) { for (let j = 0; j < s; ++j) {
...@@ -231,14 +201,13 @@ export namespace MeshBuilder { ...@@ -231,14 +201,13 @@ export namespace MeshBuilder {
Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f) Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f)
Vec3.add(tmpCylinderStart, start, tmpCylinderDir) Vec3.add(tmpCylinderStart, start, tmpCylinderDir)
setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step) setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step)
add(tmpCylinderMat, vertices, normals, indices) addPrimitive(tmpCylinderMat, cylinder)
} }
}, },
addSphere: (center: Vec3, radius: number, detail: number) => { addSphere: (center: Vec3, radius: number, detail: number) => {
const { vertices, normals, indices } = getSphere({ radius, detail }) addPrimitive(setSphereMat(tmpSphereMat, center, radius), getSphere(detail))
setSphereMat(tmpSphereMat, center)
add(tmpSphereMat, vertices, normals, indices)
}, },
addTube: (centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) => { addTube: (centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) => {
const addedVertexCount = addTube(centers, normals, binormals, linearSegments, radialSegments, width, height, waveFactor, startCap, endCap, state) const addedVertexCount = addTube(centers, normals, binormals, linearSegments, radialSegments, width, height, waveFactor, startCap, endCap, state)
for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup); for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup);
...@@ -247,6 +216,7 @@ export namespace MeshBuilder { ...@@ -247,6 +216,7 @@ export namespace MeshBuilder {
const addedVertexCount = addSheet(controls, normals, binormals, linearSegments, width, height, arrowHeight, startCap, endCap, state) const addedVertexCount = addSheet(controls, normals, binormals, linearSegments, width, height, arrowHeight, startCap, endCap, state)
for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup); for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup);
}, },
setGroup: (group: number) => { setGroup: (group: number) => {
currentGroup = group currentGroup = group
}, },
......
...@@ -6,31 +6,25 @@ import { Primitive } from './primitive'; ...@@ -6,31 +6,25 @@ import { Primitive } from './primitive';
* @author Alexander Rose <alexander.rose@weirdbyte.de> * @author Alexander Rose <alexander.rose@weirdbyte.de>
*/ */
export const DefaultPlaneProps = { const plane: Primitive = {
width: 1, vertices: new Float32Array([
height: 1 -0.5, 0.5, 0,
0.5, 0.5, 0,
-0.5, -0.5, 0,
0.5, -0.5, 0
]),
normals: new Float32Array([
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1
]),
indices: new Uint32Array([
0, 2, 1,
1, 2, 3
])
} }
export type PlaneProps = Partial<typeof DefaultPlaneProps>
export function Plane(props?: PlaneProps): Primitive { export function Plane(): Primitive {
const { width, height } = { ...DefaultPlaneProps, ...props } return plane
return {
vertices: new Float32Array([
-width / 2, height / 2, 0,
width / 2, height / 2, 0,
-width / 2, -height / 2, 0,
width / 2, -height / 2, 0
]),
normals: new Float32Array([
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1
]),
indices: new Uint32Array([
0, 2, 1,
1, 2, 3
])
}
} }
\ No newline at end of file
...@@ -15,13 +15,7 @@ export function sphereVertexCount(detail: number) { ...@@ -15,13 +15,7 @@ export function sphereVertexCount(detail: number) {
return 10 * Math.pow(Math.pow(2, detail), 2) + 2 return 10 * Math.pow(Math.pow(2, detail), 2) + 2
} }
export const DefaultSphereProps = {
radius: 1,
detail: 0
}
export type SphereProps = Partial<typeof DefaultSphereProps>
/** Create sphere by subdividing an icosahedron */ /** Create sphere by subdividing an icosahedron */
export function Sphere(props?: SphereProps): Primitive { export function Sphere(detail: number): Primitive {
return Polyhedron(vertices, indices, { ...DefaultSphereProps, ...props }) return Polyhedron(vertices, indices, { detail, radius: 1 })
} }
\ No newline at end of file
...@@ -50,13 +50,13 @@ namespace Vec3 { ...@@ -50,13 +50,13 @@ namespace Vec3 {
v[0] = array[offset + 0] v[0] = array[offset + 0]
v[1] = array[offset + 1] v[1] = array[offset + 1]
v[2] = array[offset + 2] v[2] = array[offset + 2]
return v
} }
export function toArray(v: Vec3, out: Helpers.NumberArray, offset: number) { export function toArray(v: Vec3, out: Helpers.NumberArray, offset: number) {
out[offset + 0] = v[0] out[offset + 0] = v[0]
out[offset + 1] = v[1] out[offset + 1] = v[1]
out[offset + 2] = v[2] out[offset + 2] = v[2]
return v
} }
export function create(x: number, y: number, z: number): Vec3 { export function create(x: number, y: number, z: number): Vec3 {
......
...@@ -91,7 +91,7 @@ export class Stage { ...@@ -91,7 +91,7 @@ export class Stage {
// this.loadPdbid('3pqr') // inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein // this.loadPdbid('3pqr') // inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein
// this.loadPdbid('4v5a') // ribosome // this.loadPdbid('4v5a') // ribosome
// this.loadPdbid('3j3q') // ... // this.loadPdbid('3j3q') // ...
this.loadPdbid('2np2') // dna // this.loadPdbid('2np2') // dna
// this.loadPdbid('1d66') // dna // this.loadPdbid('1d66') // dna
// this.loadPdbid('9dna') // A form dna // this.loadPdbid('9dna') // A form dna
// this.loadPdbid('1bna') // B form dna // this.loadPdbid('1bna') // B form dna
...@@ -107,7 +107,7 @@ export class Stage { ...@@ -107,7 +107,7 @@ export class Stage {
// this.loadPdbid('1sfi') // contains cyclic peptid // this.loadPdbid('1sfi') // contains cyclic peptid
// this.loadPdbid('3sn6') // discontinuous chains // this.loadPdbid('3sn6') // discontinuous chains
// this.loadPdbid('2zex') // contains carbohydrate polymer // this.loadPdbid('2zex') // contains carbohydrate polymer
// this.loadPdbid('3sgj') // contains carbohydrate polymer this.loadPdbid('3sgj') // contains carbohydrate polymer
// this.loadPdbid('3ina') // contains GlcN and IdoA // this.loadPdbid('3ina') // contains GlcN and IdoA
// this.loadPdbid('1umz') // contains Xyl (Xyloglucan) // this.loadPdbid('1umz') // contains Xyl (Xyloglucan)
// this.loadPdbid('1mfb') // contains Abe // this.loadPdbid('1mfb') // contains Abe
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment