Просмотр исходного кода

wip, added renderer, removed regl dep from geo

Alexander Rose 7 лет назад
Родитель
Сommit
452f2d8f13

+ 28 - 157
src/apps/render-test/state.ts

@@ -4,23 +4,18 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import REGL = require('regl');
 import { ValueBox } from 'mol-util/value-cell'
-import * as glContext from 'mol-gl/context'
-import { Camera } from 'mol-gl/camera'
+
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
-import { PointRenderable, MeshRenderable } from 'mol-gl/renderable'
-import Model from 'mol-gl/model';
-import { calculateTextureInfo } from 'mol-gl/util';
+import { createRenderer, createRenderObject, RenderObject } 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 Spacefill from 'mol-geo/representation/structure/spacefill'
 
 import CIF from 'mol-io/reader/cif'
 import { Run } from 'mol-task'
-// import Computation from 'mol-util/computation'
 import { AtomSet, Structure } from 'mol-model/structure'
-import { UnitRepresentation } from 'mol-geo/representation/structure';
 
 async function parseCif(data: string|Uint8Array) {
     const comp = CIF.parse(data)
@@ -39,35 +34,12 @@ async function getPdb(pdb: string) {
 import mcubes from './mcubes'
 
 export default class State {
-    regl: REGL.Regl
-
-    async initRegl (container: HTMLDivElement) {
-        const regl = glContext.create({
-            container,
-            extensions: [
-                'OES_texture_float',
-                'OES_texture_float_linear',
-                'OES_element_index_uint',
-                // 'EXT_disjoint_timer_query',
-                'EXT_blend_minmax',
-                'ANGLE_instanced_arrays'
-            ],
-            // profile: true
-        })
-
-        const camera = Camera.create(regl, container, {
-            center: Vec3.create(0, 0, 0),
-            near: 0.01,
-            far: 1000
-        })
+    async initRenderer (container: HTMLDivElement) {
+        const renderer = createRenderer(container)
 
         const p1 = Vec3.create(0, 4, 0)
         const p2 = Vec3.create(-3, 0, 0)
 
-        const model1 = Model(regl)
-        const model2 = Model(regl, { position: p1 })
-        const model3 = Model(regl, { position: p2 })
-
         const position = ValueBox(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0]))
         const normal = ValueBox(new Float32Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))
 
@@ -81,43 +53,23 @@ export default class State {
         Mat4.setTranslation(m4, p2)
         Mat4.toArray(m4, transformArray2.value, 32)
 
-        const colorTexInfo = calculateTextureInfo(3, 3)
-        const color = new Uint8Array(colorTexInfo.length)
-        color.set([
+        const color = ValueBox(createColorTexture(3))
+        color.value.set([
             0, 0, 255,
             0, 255, 0,
             255, 0, 0
         ])
-        console.log(color, colorTexInfo)
-        const colorTex = regl.texture({
-            width: colorTexInfo.width,
-            height: colorTexInfo.height,
-            format: 'rgb',
-            type: 'uint8',
-            wrapS: 'clamp',
-            wrapT: 'clamp',
-            data: color
-        })
-
-        // position.update((array: Float32Array) => {
-        //     positionFromModel({}, array, 0)
-        // })
 
-        const points = PointRenderable.create(regl, {
+        const points = createRenderObject('point', {
             position,
             transform: transformArray1
         })
-        const mesh = MeshRenderable.create(regl,
-            {
-                position,
-                normal,
-                transform: transformArray2
-            },
-            {
-                colorTex,
-                colorTexSize: [ colorTexInfo.width, colorTexInfo.height ]
-            }
-        )
+        const mesh = createRenderObject('mesh', {
+            position,
+            normal,
+            color,
+            transform: transformArray2
+        })
 
         const sphere = Icosahedron(1, 1)
         console.log(sphere)
@@ -125,7 +77,7 @@ export default class State {
         const box = Box(1, 1, 1, 1, 1, 1)
         console.log(box)
 
-        const points2 = PointRenderable.create(regl, {
+        const points2 = createRenderObject('point', {
             position: ValueBox(new Float32Array(box.vertices)),
             transform: transformArray1
         })
@@ -133,61 +85,21 @@ export default class State {
         let rr = 1;
         function cubesF(x: number, y: number, z: number) {
             return x * x + y * y + z * z - rr * rr;
-            // const a = ca;
-            // const t = (x + y + z + a);
-            // return x * x * x + y * y * y + z * z * z + a * a * a - t * t * t;
         }
 
         let cubes = await mcubes(cubesF);
 
-        const makeCubesMesh = () => MeshRenderable.create(regl,
-            {
-                position: cubes.surface.vertexBuffer,
-                normal: cubes.surface.normalBuffer as any,
-                transform: transformArray1
-            },
-            {
-                colorTex,
-                colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
-                'light.position': Vec3.create(0, 0, -100),
-                'light.color': Vec3.create(1.0, 1.0, 1.0),
-                'light.ambient': Vec3.create(0.5, 0.5, 0.5),
-                'light.falloff': 0,
-                'light.radius': 500
-            },
-            cubes.surface.indexBuffer.value
-        );
-
-        let mesh2 = makeCubesMesh();
-
-        // const makeCubes = async () => {
-        //     rr = Math.random();
-        //     cubes = await mcubes(cubesF, cubes);
-        //     mesh2 = makeCubesMesh();
-        //     setTimeout(makeCubes, 1000 / 15);
-        // };
-        // makeCubes();
-
-        // const mesh2 = MeshRenderable.create(regl,
-        //     {
-        //         position: Attribute.create(regl, new Float32Array(box.vertices), { size: 3 }),
-        //         normal: Attribute.create(regl, new Float32Array(box.normals), { size: 3 }),
-        //         ...createTransformAttributes(regl, transformArray1)
-        //     },
-        //     {
-        //         colorTex,
-        //         colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
-        //         'light.position': Vec3.create(0, 0, -20),
-        //         'light.color': Vec3.create(1.0, 1.0, 1.0),
-        //         'light.ambient': Vec3.create(0.5, 0.5, 0.5),
-        //         'light.falloff': 0,
-        //         'light.radius': 500
-        //     },
-        //     box.indices
-        // )
+        const makeCubesMesh = () => createRenderObject('mesh', {
+            position: cubes.surface.vertexBuffer,
+            normal: cubes.surface.normalBuffer as any,
+            color,
+            transform: transformArray1,
+        }, cubes.surface.indexBuffer.value);
+        const mesh2 = makeCubesMesh();
+        renderer.add(mesh2)
 
         function createSpacefills (structure: Structure) {
-            const spacefills: UnitRepresentation[] = []
+            const spacefills: RenderObject[] = []
             const { atoms, units } = structure;
             const unitIds = AtomSet.unitIds(atoms);
             for (let i = 0, _i = unitIds.length; i < _i; i++) {
@@ -195,57 +107,16 @@ export default class State {
                 const unit = units[unitId];
                 const atomGroup = AtomSet.unitGetByIndex(atoms, i);
 
-                const spacefill = Spacefill(regl)
-                spacefill.create(unit, atomGroup, {})
-                console.log('spacefill', spacefill)
-                spacefills.push(spacefill)
+                const spacefill = Spacefill()
+                spacefills.push(...spacefill.create(unit, atomGroup, {}))
             }
             return spacefills
         }
-
         const structures = await getPdb('1crn')
         const spacefills = createSpacefills(structures[0])
+        spacefills.forEach(renderer.add)
 
-        structures[0]
-
-        const baseContext = regl({
-            context: {
-                model: Mat4.identity(),
-                transform: Mat4.setTranslation(Mat4.identity(), Vec3.create(6, 0, 0))
-            },
-            uniforms: {
-                model: regl.context('model' as any),
-                transform: regl.context('transform' as any),
-            }
-        })
-
-        regl.frame((ctx) => {
-            camera.update((state: any) => {
-                if (!camera.isDirty()) return
-                baseContext(() => {
-                    // console.log(ctx)
-                    regl.clear({color: [0, 0, 0, 1]})
-                    spacefills.forEach(r => r.draw())
-                    // position.update(array => { array[0] = Math.random() })
-                    // points.update(a => { a.position[0] = Math.random() })
-                    // mesh.draw()
-                    // points.draw()
-                    mesh2.draw()
-                    // points2.draw()
-                    // model1({}, ({ transform }) => {
-                    //     points.draw()
-                    // })
-                    // model2({}, ({ transform }) => {
-                    //     points.draw()
-                    //     model3({ transform }, () => {
-                    //         points.draw()
-                    //     })
-                    // })
-                })
-            }, undefined)
-        })
-
-        this.regl = regl
+        renderer.frame()
     }
 
     constructor() {

+ 1 - 1
src/apps/render-test/ui.tsx

@@ -12,7 +12,7 @@ export default class Root extends React.Component<{ state: State }, { initialize
     state = { initialized: false }
 
     componentDidMount() {
-        if (this.canvasContainer) this.props.state.initRegl(this.canvasContainer).then(() => this.setState({ initialized: true }))
+        if (this.canvasContainer) this.props.state.initRenderer(this.canvasContainer).then(() => this.setState({ initialized: true }))
     }
 
     render() {

+ 2 - 2
src/mol-geo/representation/structure/index.ts

@@ -5,15 +5,15 @@
  */
 
 import { AtomGroup, AtomSet, Structure, Unit } from 'mol-model/structure';
+import { RenderObject } from 'mol-gl/renderer';
 
 export interface RepresentationProps {
 
 }
 
 export interface UnitRepresentation {
-    create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => boolean,
+    create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => RenderObject[],
     update: (props: RepresentationProps) => boolean,
-    draw: () => void
 }
 
 // export interface StructureRepresentation {

+ 13 - 37
src/mol-geo/representation/structure/spacefill.ts

@@ -4,11 +4,10 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import REGL = require('regl');
 import { ValueBox } from 'mol-util/value-cell'
 
-import { MeshRenderable, Renderable } from 'mol-gl/renderable'
-import { calculateTextureInfo } from 'mol-gl/util';
+import { createRenderObject, RenderObject } from 'mol-gl/renderer'
+import { createColorTexture } from 'mol-gl/util';
 import Icosahedron from 'mol-geo/primitive/icosahedron'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { OrderedSet } from 'mol-data/int'
@@ -16,11 +15,11 @@ import { Atom, AtomGroup, Unit } from 'mol-model/structure';
 import P from 'mol-model/structure/query/properties';
 import { RepresentationProps, UnitRepresentation } from './index';
 
-export default function Spacefill(regl: REGL.Regl): UnitRepresentation {
+export default function Spacefill(): UnitRepresentation {
     let vertices: Float32Array
     let normals: Float32Array
 
-    const renderables: Renderable<any>[] = []
+    const renderObjects: RenderObject[] = []
 
     return {
         create: (unit: Unit, atomGroup: AtomGroup, props: RepresentationProps) => {
@@ -59,48 +58,25 @@ export default function Spacefill(regl: REGL.Regl): UnitRepresentation {
             const m4 = Mat4.identity()
             Mat4.toArray(m4, transformArray, 0)
 
-            const colorTexInfo = calculateTextureInfo(3, 3)
-            const color = new Uint8Array(colorTexInfo.length)
-            color.set([
-                0, 0, 255,
-                0, 255, 0,
-                255, 0, 0
-            ])
-            // console.log(color, colorTexInfo)
-            const colorTex = regl.texture({
-                width: colorTexInfo.width,
-                height: colorTexInfo.height,
-                format: 'rgb',
-                type: 'uint8',
-                wrapS: 'clamp',
-                wrapT: 'clamp',
-                data: color
-            })
-
-            const spheres = MeshRenderable.create(regl,
+            const color = ValueBox(createColorTexture(1))
+            color.value.set([ 0, 0, 255 ])
+
+            const spheres = createRenderObject(
+                'mesh',
                 {
                     position: ValueBox(new Float32Array(vertices)),
                     normal: ValueBox(new Float32Array(normals)),
+                    color,
                     transform: ValueBox(transformArray)
-                },
-                {
-                    colorTex,
-                    colorTexSize: [ colorTexInfo.width, colorTexInfo.height ],
-                    'light.position': Vec3.create(0, 0, -100),
-                    'light.color': Vec3.create(1.0, 1.0, 1.0),
-                    'light.ambient': Vec3.create(0.5, 0.5, 0.5),
-                    'light.falloff': 0,
-                    'light.radius': 500
                 }
             )
 
             // console.log({ vertices, normals, vertexCount, atomCount })
 
-            renderables.push(spheres)
+            renderObjects.push(spheres)
 
-            return true
+            return renderObjects
         },
-        update: (props: RepresentationProps) => false,
-        draw: () => renderables.forEach(r => r.draw())
+        update: (props: RepresentationProps) => false
     }
 }

+ 1 - 1
src/mol-gl/camera.ts

@@ -82,7 +82,7 @@ export namespace Camera {
         const right = Vec3.create(1, 0, 0)
         const front = Vec3.create(0, 0, 1)
 
-        let dirty = false
+        let dirty = true
         let ddistance = 0
 
         let prevX = 0

+ 3 - 0
src/mol-gl/renderable.ts

@@ -16,6 +16,9 @@ export type AttributesBuffers<T extends AttributesData> = { [K in keyof T]: REGL
 
 export interface Renderable<T extends AttributesData> {
     draw(): void
+    // isPicking: () => boolean
+    // isVisible: () => boolean
+    // isTransparent: () => boolean
 }
 
 export { PointRenderable, MeshRenderable }

+ 4 - 1
src/mol-gl/renderable/mesh.ts

@@ -8,7 +8,8 @@ import REGL = require('regl');
 import { ValueBox } from 'mol-util/value-cell'
 
 import { Renderable } from '../renderable'
-import { getBuffers, createTransformAttributes, fillSerial } from './util'
+import { ColorTexture } from '../util'
+import { getBuffers, createTransformAttributes, fillSerial, createColorUniforms } from './util'
 import Attribute from '../attribute';
 import { MeshShaders } from '../shaders'
 
@@ -21,6 +22,7 @@ namespace Mesh {
         position: { type: Float32Array, itemSize: 3 }
         normal: { type: Float32Array, itemSize: 3 }
         transform: { type: Float32Array, itemSize: 16 }
+        color: { type: ColorTexture, itemSize: 16 }
     }
     export type Data = { [K in keyof DataType]: DataType[K]['type'] }
     export type BoxedData = { [K in keyof Data]: ValueBox<Data[K]> }
@@ -40,6 +42,7 @@ namespace Mesh {
             uniforms: {
                 objectId: uniforms.objectId || 0,
                 instanceCount,
+                ...createColorUniforms(regl, data.color),
                 ...uniforms
             },
             attributes: getBuffers({

+ 17 - 0
src/mol-gl/renderable/util.ts

@@ -7,6 +7,7 @@
 import REGL = require('regl');
 import { ValueBox } from 'mol-util/value-cell'
 
+import { ColorTexture } from '../util';
 import { Attributes, AttributesData, AttributesBuffers } from '../renderable'
 import Attribute from '../attribute'
 
@@ -23,6 +24,22 @@ export function createTransformAttributes (regl: REGL.Regl, transform: ValueBox<
     }
 }
 
+export function createColorUniforms (regl: REGL.Regl, color: ValueBox<ColorTexture>) {
+    const colorTex = regl.texture({
+        width: color.value.width,
+        height: color.value.height,
+        format: 'rgb',
+        type: 'uint8',
+        wrapS: 'clamp',
+        wrapT: 'clamp',
+        data: color.value
+    })
+    return {
+        colorTex,
+        colorTexSize: [ color.value.width, color.value.height ]
+    }
+}
+
 export function getBuffers<T extends AttributesData>(attributes: Attributes<T>): AttributesBuffers<T> {
     const buffers: AttributesBuffers<any> = {}
     for (const k of Object.keys(attributes)) {

+ 116 - 0
src/mol-gl/renderer.ts

@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import REGL = require('regl');
+import * as glContext from './context'
+import { Camera } from './camera'
+import { PointRenderable, MeshRenderable, Renderable } from './renderable'
+
+import { Vec3, Mat4 } from 'mol-math/linear-algebra'
+
+let _renderObjectId = 0;
+function getNextId() {
+    return _renderObjectId++ % 0x7FFFFFFF;
+}
+
+export interface RenderObject {
+    id: number
+    type: 'mesh' | 'point'
+    data: any
+    elements: any
+    uniforms: any
+}
+
+export function createRenderObject(type: 'mesh' | 'point', data: any, elements?: any, uniforms?: any) {
+    return { id: getNextId(), type, data, elements, uniforms }
+}
+
+export interface Renderer {
+    add: (o: RenderObject) => void
+    remove: (o: RenderObject) => void
+    draw: () => void
+    frame: () => void
+}
+
+export function createRenderable(regl: REGL.Regl, o: RenderObject) {
+    switch (o.type) {
+        case 'mesh': return MeshRenderable.create(regl, o.data, o.uniforms || {}, o.elements)
+        case 'point': return PointRenderable.create(regl, o.data)
+    }
+}
+
+export function createRenderer(container: HTMLDivElement): Renderer {
+    const renderableList: Renderable<any>[] = []
+    const objectIdRenderableMap: { [k: number]: Renderable<any> } = {}
+
+    const regl = glContext.create({
+        container,
+        extensions: [
+            'OES_texture_float',
+            'OES_texture_float_linear',
+            'OES_element_index_uint',
+            // 'EXT_disjoint_timer_query',
+            'EXT_blend_minmax',
+            'ANGLE_instanced_arrays'
+        ],
+        // profile: true
+    })
+
+    const camera = Camera.create(regl, container, {
+        center: Vec3.create(0, 0, 0),
+        near: 0.01,
+        far: 1000
+    })
+
+    const baseContext = regl({
+        context: {
+            model: Mat4.identity(),
+            transform: Mat4.setTranslation(Mat4.identity(), Vec3.create(6, 0, 0))
+        },
+        uniforms: {
+            model: regl.context('model' as any),
+            transform: regl.context('transform' as any),
+            'light.position': Vec3.create(0, 0, -100),
+            'light.color': Vec3.create(1.0, 1.0, 1.0),
+            'light.ambient': Vec3.create(0.5, 0.5, 0.5),
+            'light.falloff': 0,
+            'light.radius': 500
+        }
+    })
+
+    const draw = () => {
+        camera.update((state: any) => {
+            if (!camera.isDirty()) return;
+            baseContext(() => {
+                // console.log(ctx)
+                regl.clear({color: [0, 0, 0, 1]})
+                // TODO painters sort, filter visible, filter picking, visibility culling?
+                renderableList.forEach(r => {
+                    r.draw()
+                })
+            })
+        }, undefined)
+    }
+
+    return {
+        add: (o: RenderObject) => {
+            const renderable = createRenderable(regl, o)
+            renderableList.push(renderable)
+            objectIdRenderableMap[o.id] = renderable
+        },
+        remove: (o: RenderObject) => {
+            if (o.id in objectIdRenderableMap) {
+                // TODO
+                // objectIdRenderableMap[o.id].destroy()
+                delete objectIdRenderableMap[o.id]
+            }
+        },
+        draw,
+        frame: () => {
+            regl.frame((ctx) => draw())
+        }
+    }
+}

+ 14 - 0
src/mol-gl/util.ts

@@ -10,4 +10,18 @@ export function calculateTextureInfo (n: number, itemSize: number) {
     width = width + (itemSize - (width % itemSize)) % itemSize
     const height = width > 0 ? Math.ceil(n * itemSize / width) : 0
     return { width, height, length: width * height * itemSize }
+}
+
+export interface ColorTexture extends Uint8Array {
+    width: number,
+    height: number
+}
+
+export function createColorTexture (n: number): ColorTexture {
+    const colorTexInfo = calculateTextureInfo(n, 3)
+    const colorTexture = new Uint8Array(colorTexInfo.length)
+    return Object.assign(colorTexture, {
+        width: colorTexInfo.width,
+        height: colorTexInfo.height
+    })
 }