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