Explorar el Código

wip, repr instancing support

Alexander Rose hace 7 años
padre
commit
01bdf118ed

+ 13 - 12
src/apps/render-test/state.ts

@@ -7,16 +7,16 @@
 import { ValueCell } from 'mol-util/value-cell'
 
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
-import { createRenderer, createRenderObject, RenderObject } from 'mol-gl/renderer'
+import { createRenderer, createRenderObject } from 'mol-gl/renderer'
 import { createColorTexture } from 'mol-gl/util';
-import Icosahedron from 'mol-geo/primitive/icosahedron'
-import Box from 'mol-geo/primitive/box'
+// import Icosahedron from 'mol-geo/primitive/icosahedron'
+// import Box from 'mol-geo/primitive/box'
 import Spacefill from 'mol-geo/representation/structure/spacefill'
 import Point from 'mol-geo/representation/structure/point'
 
 import CIF from 'mol-io/reader/cif'
 import { Run, Progress } from 'mol-task'
-import { Structure } from 'mol-model/structure'
+import { Structure, Symmetry } from 'mol-model/structure'
 
 function log(progress: Progress) {
     const p = progress.root.progress
@@ -38,6 +38,7 @@ async function getPdb(pdb: string) {
 }
 
 import mcubes from './mcubes'
+import { StructureRepresentation } from 'mol-geo/representation/structure';
 // import Cylinder from 'mol-geo/primitive/cylinder';
 
 export default class State {
@@ -123,16 +124,16 @@ export default class State {
         const mesh2 = makeCubesMesh();
         renderer.add(mesh2)
 
-        const structures = await getPdb('4v99')
-        const { elements, units } = structures[0];
+        const structures = await getPdb('1rb8')
+        const struct = Symmetry.buildAssembly(structures[0], '1')
 
-        // const spacefill = Spacefill()
-        // const spacefills = await Run(spacefill.create(units, elements), log, 100)
-        // spacefills.forEach(renderer.add)
+        const structPointRepr = StructureRepresentation(Point)
+        await Run(structPointRepr.create(struct))
+        structPointRepr.renderObjects.forEach(renderer.add)
 
-        const point = Point()
-        const points = await Run(point.create(units, elements), log, 100)
-        points.forEach(renderer.add)
+        const structSpacefillRepr = StructureRepresentation(Spacefill)
+        await Run(structSpacefillRepr.create(struct))
+        structSpacefillRepr.renderObjects.forEach(renderer.add)
 
         renderer.frame()
     }

+ 62 - 32
src/mol-geo/representation/structure/index.ts

@@ -5,55 +5,85 @@
  */
 
 import { ElementGroup, ElementSet, Structure, Unit } from 'mol-model/structure';
-import { RenderObject } from 'mol-gl/renderer';
 import { EquivalenceClasses } from 'mol-data/util';
 import { OrderedSet } from 'mol-data/int'
 import { Task } from 'mol-task'
+import { RenderObject } from 'mol-gl/renderer';
 
 export interface RepresentationProps {
 
 }
 
-export interface UnitRepresentation {
-    create: (units: ReadonlyArray<Unit>, elements: ElementSet, props?: Partial<RepresentationProps>) => Task<RenderObject[]>,
+export interface UnitsRepresentation<Props> {
+    renderObjects: ReadonlyArray<RenderObject>,
+    create: (units: ReadonlyArray<Unit>, elementGroup: ElementGroup, props: Props) => Task<void>,
     update: (props: RepresentationProps) => boolean,
 }
 
-// export interface StructureRepresentation {
-//     create: (structure: Structure, props: RepresentationProps) => boolean,
-//     update: (props: RepresentationProps) => boolean
-// }
-
-export class StructureRepresentation {
-    constructor(private repr: UnitRepresentation) {
+export interface StructureRepresentation<Props> {
+    renderObjects: ReadonlyArray<RenderObject>,
+    create: (structure: Structure, props?: Props) => Task<void>,
+    update: (elements: ElementSet, props: Props) => boolean
+}
 
-    }
-    create(structure: Structure) {
-        return Task.create('S. repr.', async ctx => {
+export function StructureRepresentation<Props>(reprCtor: () => UnitsRepresentation<Props>): StructureRepresentation<Props> {
+    const renderObjects: RenderObject[] = []
+    const unitReprs: UnitsRepresentation<Props>[] = []
 
-            const { elements, units } = structure;
-            const uniqueGroups = EquivalenceClasses<number, ElementGroup>(
-                ElementGroup.hashCode,
-                (a, b) => units[a.id].model.id === units[b.id].model.id && OrderedSet.areEqual(a.elements, b.elements));
+    return {
+        renderObjects,
+        create(structure: Structure, props: Props = {} as Props) {
+            return Task.create('StructureRepresentation', async ctx => {
+                const { elements, units } = structure;
+                const uniqueGroups = EquivalenceClasses<number, ElementGroup>(
+                    ElementGroup.hashCode,
+                    (a, b) => units[a.id].model.id === units[b.id].model.id &&
+                        OrderedSet.areEqual(a.elements, b.elements)
+                );
+                // TODO
+                // const uniqueOperators = EquivalenceClasses<number, ElementGroup>(
+                //     ElementGroup.hashCode,
+                //     (a, b) => units[a.id].model.id === units[b.id].model.id &&
+                //         OrderedSet.areEqual(a.elements, b.elements)
+                // );
 
-            for (let i = 0, _i = ElementSet.unitCount(elements); i < _i; i++) {
-                const group = ElementSet.unitGetByIndex(elements, i);
-                uniqueGroups.add(group.id, group);
+                for (let i = 0, _i = ElementSet.unitCount(elements); i < _i; i++) {
+                    const group = ElementSet.unitGetByIndex(elements, i);
+                    uniqueGroups.add(i, group);
+                    // console.log(i, group)
+                }
 
-            }
+                for (let i = 0, _i = uniqueGroups.groups.length; i < _i; i++) {
+                    const groupUnits: Unit[] = []
+                    const group = uniqueGroups.groups[i]
+                    // console.log('group', i)
+                    for (let j = 0, _j = group.length; j < _j; j++) {
+                        groupUnits.push(units[group[j]])
+                        // console.log(units[group[j]].operator.matrix)
+                    }
+                    const elementGroup = ElementSet.unitGetByIndex(elements, group[0])
+                    const repr = reprCtor()
+                    unitReprs.push(repr)
+                    await ctx.update({ message: 'Building units...', current: i, max: _i });
+                    await ctx.runChild(repr.create(groupUnits, elementGroup, props));
+                    renderObjects.push(...repr.renderObjects)
+                }
 
-            const u = this.repr.create(units, 0 as any, 0 as any);
-            await ctx.update('Building units...');
-            await ctx.runChild(u);
+                // console.log(ElementSet.unitCount(elements))
+                // console.log(uniqueGroups)
 
-            //ctx.runChild(...)
-            //uniqueGroups.groups
+                // console.log({ elements, units })
 
-            return true
-        });
-    }
-    update(elements: ElementSet, props: RepresentationProps) {
-        // TODO check model.id, conformation.id, unit.id, elementGroup(.hashCode/.areEqual)
-        return false
+                // const repr = reprCtor()
+                // unitReprs.push(repr)
+                // await ctx.update('Building units...');
+                // await ctx.runChild(repr.create(units, elements, props));
+                // renderObjects.push(...repr.renderObjects)
+            });
+        },
+        update(elements: ElementSet, props: RepresentationProps) {
+            // TODO check model.id, conformation.id, unit.id, elementGroup(.hashCode/.areEqual)
+            return false
+        }
     }
 }

+ 23 - 26
src/mol-geo/representation/structure/point.ts

@@ -11,43 +11,42 @@ import { createColorTexture } from 'mol-gl/util';
 import { Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
 import { ChunkedArray } from 'mol-data/util';
-import { Element, Unit, ElementSet } from 'mol-model/structure';
-import P from 'mol-model/structure/query/properties';
-import { RepresentationProps, UnitRepresentation } from './index';
+import { Unit, ElementGroup } from 'mol-model/structure';
+import { RepresentationProps, UnitsRepresentation } from './index';
 import { Task } from 'mol-task'
 
+export const DefaultPointProps = {
 
-export default function Point(): UnitRepresentation {
+}
+export type PointProps = Partial<typeof DefaultPointProps>
+
+export default function Point(): UnitsRepresentation<PointProps> {
     const renderObjects: RenderObject[] = []
     const vertices = ChunkedArray.create(Float32Array, 3, 1024, 2048);
 
     return {
-        create: (units: ReadonlyArray<Unit>, elements: ElementSet, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
-            const l = Element.Location();
-
-            const unitIds = ElementSet.unitIds(elements);
-            for (let i = 0, _i = unitIds.length; i < _i; i++) {
-                const unitId = unitIds[i];
-                const unit = units[unitId];
-                const elementGroup = ElementSet.unitGetByIndex(elements, i);
-                const elementCount = OrderedSet.size(elementGroup.elements)
-                l.unit = unit;
+        renderObjects,
+        create: (units: ReadonlyArray<Unit>, elementGroup: ElementGroup, props: PointProps = {}) => Task.create('Spacefill', async ctx => {
+            // const l = Element.Location();
 
-                for (let i = 0; i < elementCount; i++) {
-                    l.element = OrderedSet.getAt(elementGroup.elements, i)
-                    ChunkedArray.add3(vertices, P.atom.x(l), P.atom.y(l), P.atom.z(l))
-                }
+            const { x, y, z } = units[0].model.conformation
+            const elementCount = OrderedSet.size(elementGroup.elements)
+            for (let i = 0; i < elementCount; i++) {
+                const e = OrderedSet.getAt(elementGroup.elements, i)
+                ChunkedArray.add3(vertices, x[e], y[e], z[e])
 
                 if (i % 10 === 0 && ctx.shouldUpdate) {
-                    await ctx.update({ message: 'Point', current: i, max: _i });
+                    await ctx.update({ message: 'Point', current: i, max: elementCount });
                 }
             }
 
-            const transformArray = new Float32Array(32)
-            const m4 = Mat4.identity()
-            Mat4.toArray(m4, transformArray, 0)
+            const unitsCount = units.length
+            const transformArray = new Float32Array(unitsCount * 16)
+            for (let i = 0; i < unitsCount; i++) {
+                Mat4.toArray(units[i].operator.matrix, transformArray, i * 16)
+            }
 
-            const color = ValueCell.create(createColorTexture(1))
+            const color = ValueCell.create(createColorTexture(unitsCount))
             color.ref.value.set([ 0, 0, 255 ])
 
             const points = createRenderObject('point', {
@@ -55,12 +54,10 @@ export default function Point(): UnitRepresentation {
                 color,
                 transform: ValueCell.create(transformArray),
 
-                instanceCount: transformArray.length / 16,
+                instanceCount: unitsCount,
                 positionCount: vertices.elementCount
             }, {})
             renderObjects.push(points)
-
-            return renderObjects
         }),
         update: (props: RepresentationProps) => false
     }

+ 31 - 39
src/mol-geo/representation/structure/spacefill.ts

@@ -10,62 +10,56 @@ import { createRenderObject, RenderObject } from 'mol-gl/renderer'
 import { createColorTexture } from 'mol-gl/util';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
-import { Element, Unit, ElementSet } from 'mol-model/structure';
-import P from 'mol-model/structure/query/properties';
-import { RepresentationProps, UnitRepresentation } from './index';
+import { Unit, ElementGroup } from 'mol-model/structure';
+import { RepresentationProps, UnitsRepresentation } from './index';
 import { Task } from 'mol-task'
 import { MeshBuilder } from '../../shape/mesh-builder';
+import { VdwRadius } from 'mol-model/structure/model/properties/atomic';
 
-export default function Spacefill(): UnitRepresentation {
-    const renderObjects: RenderObject[] = []
+export const DefaultSpacefillProps = {
+
+}
+export type SpacefillProps = Partial<typeof DefaultSpacefillProps>
 
-    // unit: Unit, atomGroup: AtomGroup
+export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
+    const renderObjects: RenderObject[] = []
 
     return {
-        create: (units: ReadonlyArray<Unit>, elements: ElementSet, props: Partial<RepresentationProps> = {}) => Task.create('Spacefill', async ctx => {
-            const l = Element.Location();
+        renderObjects,
+        create: (units: ReadonlyArray<Unit>, elementGroup: ElementGroup, props: SpacefillProps = {}) => Task.create('Spacefill', async ctx => {
             const meshBuilder = MeshBuilder.create()
 
-            const unitIds = ElementSet.unitIds(elements);
-            for (let i = 0, _i = unitIds.length; i < _i; i++) {
-                const unitId = unitIds[i];
-                const unit = units[unitId];
-                const elementGroup = ElementSet.unitGetByIndex(elements, i);
-
-                const elementCount = OrderedSet.size(elementGroup.elements)
-
-                l.unit = unit;
+            const v = Vec3.zero()
+            const m = Mat4.identity()
 
-                const v = Vec3.zero()
-                const m = Mat4.identity()
+            const { x, y, z } = units[0].model.conformation
+            const { type_symbol } = units[0].model.hierarchy.atoms
+            const elementCount = OrderedSet.size(elementGroup.elements)
+            for (let i = 0; i < elementCount; i++) {
+                const e = OrderedSet.getAt(elementGroup.elements, i)
+                v[0] = x[e]
+                v[1] = y[e]
+                v[2] = z[e]
+                Mat4.setTranslation(m, v)
 
-                for (let i = 0; i < elementCount; i++) {
-                    l.element = OrderedSet.getAt(elementGroup.elements, i)
-
-                    v[0] = P.atom.x(l)
-                    v[1] = P.atom.y(l)
-                    v[2] = P.atom.z(l)
-                    Mat4.setTranslation(m, v)
-
-                    meshBuilder.addIcosahedron(m, { radius: P.atom.vdw(l), detail: 1 })
-                }
+                meshBuilder.addIcosahedron(m, { radius: VdwRadius(type_symbol.value(e)), detail: 0 })
 
                 if (i % 10 === 0 && ctx.shouldUpdate) {
-                    await ctx.update({ message: 'Spacefill', current: i, max: _i });
+                    await ctx.update({ message: 'Spacefill', current: i, max: elementCount });
                 }
             }
 
-            const transformArray = new Float32Array(32)
-            const m4 = Mat4.identity()
-            Mat4.toArray(m4, transformArray, 0)
+            const unitsCount = units.length
+            const transformArray = new Float32Array(unitsCount * 16)
+            for (let i = 0; i < unitsCount; i++) {
+                Mat4.toArray(units[i].operator.matrix, transformArray, i * 16)
+            }
 
-            const color = ValueCell.create(createColorTexture(1))
+            const color = ValueCell.create(createColorTexture(unitsCount))
             color.ref.value.set([ 0, 0, 255 ])
 
             const mesh = meshBuilder.getMesh()
 
-            // console.log(mesh)
-
             const spheres = createRenderObject('mesh', {
                 position: mesh.vertexBuffer,
                 normal: mesh.normalBuffer,
@@ -73,13 +67,11 @@ export default function Spacefill(): UnitRepresentation {
                 transform: ValueCell.create(transformArray),
                 elements: mesh.indexBuffer,
 
-                instanceCount: transformArray.length / 16,
+                instanceCount: unitsCount,
                 elementCount: mesh.triangleCount,
                 positionCount: mesh.vertexCount
             }, {})
             renderObjects.push(spheres)
-
-            return renderObjects
         }),
         update: (props: RepresentationProps) => false
     }

+ 1 - 0
src/mol-gl/renderable/point.ts

@@ -24,6 +24,7 @@ namespace Point {
     }
 
     export function create(regl: REGL.Regl, data: Data): Renderable {
+        console.log(data)
         const instanceId = ValueCell.create(fillSerial(new Float32Array(data.instanceCount)))
         const command = regl({
             ...PointShaders,

+ 3 - 1
src/mol-gl/renderer.ts

@@ -70,7 +70,9 @@ export function createRenderer(container: HTMLDivElement): Renderer {
     const camera = Camera.create(regl, container, {
         center: Vec3.create(0, 0, 0),
         near: 0.01,
-        far: 1000
+        far: 10000,
+        minDistance: 0.01,
+        maxDistance: 10000
     })
 
     const baseContext = regl({

+ 1 - 1
src/mol-gl/shader/point.vert

@@ -21,6 +21,6 @@ attribute vec4 transformColumn0, transformColumn1, transformColumn2, transformCo
 void main(){
     mat4 transform = mat4(transformColumn0, transformColumn1, transformColumn2, transformColumn3);
     // vColor = color;
-    gl_PointSize = 5.0;
+    gl_PointSize = 1.0;
     gl_Position = projection * view * model * transform * vec4(position, 1.0);
 }