Bladeren bron

wip, mol-gl

Alexander Rose 7 jaren geleden
bovenliggende
commit
b0240b3579

+ 6 - 2
src/apps/render-test/state.ts

@@ -40,7 +40,7 @@ export type ColorTheme = keyof typeof ColorTheme
 
 export default class State {
     viewer: Viewer
-    pdbId = ''
+    pdbId = '1crn'
     // pdbId = '5ire'
     emdId = '8116'
     // pdbId = '6G1K'
@@ -77,6 +77,7 @@ export default class State {
     getSpacefillProps (): SpacefillProps {
         const colorThemeName = this.colorTheme.getValue()
         return {
+            doubleSided: true,
             detail: this.sphereDetail.getValue(),
             colorTheme: colorThemeName === 'uniform' ?
                 { name: colorThemeName, value: this.colorValue.getValue() } :
@@ -161,7 +162,10 @@ export default class State {
         this.surfaceRepr = VolumeRepresentation(Surface)
         await Run(this.surfaceRepr.create(v.volume, {
             isoValue: VolumeIsoValue.relative(v.volume.dataStats, 3.0),
-            alpha: 1.0
+            alpha: 0.5,
+            flatShaded: false,
+            flipSided: true,
+            doubleSided: true
         }), log, 500)
         viewer.add(this.surfaceRepr)
 

+ 4 - 2
src/mol-geo/representation/structure/point.ts

@@ -20,7 +20,8 @@ import { deepEqual } from 'mol-util';
 export const DefaultPointProps = {
     colorTheme: { name: 'instance-index' } as ColorTheme,
     sizeTheme: { name: 'vdw' } as SizeTheme,
-    alpha: 1
+    alpha: 1,
+    visible: true
 }
 export type PointProps = Partial<typeof DefaultPointProps>
 
@@ -60,7 +61,7 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 _units = units
                 _elementGroup = elementGroup
 
-                const { colorTheme, sizeTheme, alpha } = curProps
+                const { colorTheme, sizeTheme, alpha, visible } = curProps
                 const elementCount = OrderedSet.size(elementGroup.elements)
                 const unitCount = units.length
 
@@ -86,6 +87,7 @@ export default function Point(): UnitsRepresentation<PointProps> {
                 points = createPointRenderObject({
                     objectId: 0,
                     alpha,
+                    visible,
 
                     position: ValueCell.create(vertices),
                     id: ValueCell.create(fillSerial(new Float32Array(elementCount))),

+ 6 - 2
src/mol-geo/representation/structure/spacefill.ts

@@ -23,7 +23,9 @@ import { icosahedronVertexCount } from '../../primitive/icosahedron';
 export const DefaultSpacefillProps = {
     detail: 0,
     colorTheme: { name: 'instance-index' } as ColorTheme,
-    alpha: 1
+    alpha: 1,
+    visible: true,
+    doubleSided: false
 }
 export type SpacefillProps = Partial<typeof DefaultSpacefillProps>
 
@@ -79,7 +81,7 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
             return Task.create('Spacefill.create', async ctx => {
                 renderObjects.length = 0 // clear
 
-                const { detail, colorTheme, alpha } = { ...DefaultSpacefillProps, ...props }
+                const { detail, colorTheme, alpha, visible, doubleSided } = { ...DefaultSpacefillProps, ...props }
 
                 await ctx.update('Computing spacefill mesh');
                 const mesh = await ctx.runChild(createSpacefillMesh(units[0], elementGroup, detail))
@@ -96,6 +98,8 @@ export default function Spacefill(): UnitsRepresentation<SpacefillProps> {
                 spheres = createMeshRenderObject({
                     objectId: 0,
                     alpha,
+                    visible,
+                    doubleSided,
 
                     position: mesh.vertexBuffer,
                     normal: mesh.normalBuffer as ValueCell<Float32Array>,

+ 6 - 1
src/mol-geo/representation/volume/surface.ts

@@ -36,6 +36,7 @@ export function computeVolumeSurface(volume: VolumeData, isoValue: VolumeIsoValu
 export const DefaultSurfaceProps = {
     isoValue: VolumeIsoValue.relative({ min: 0, max: 0, mean: 0, sigma: 0 }, 0),
     alpha: 0.5,
+    visible: true,
     flatShaded: true,
     flipSided: true,
     doubleSided: true
@@ -53,13 +54,17 @@ export default function Surface(): VolumeElementRepresentation<SurfaceProps> {
             return Task.create('Point.create', async ctx => {
                 renderObjects.length = 0 // clear
                 curProps = { ...DefaultSurfaceProps, ...props }
-                const { alpha, flatShaded, flipSided, doubleSided } = curProps
+                const { alpha, visible, flatShaded, flipSided, doubleSided } = curProps
 
                 const mesh = await ctx.runChild(computeVolumeSurface(volume, curProps.isoValue))
+                if (!flatShaded) {
+                    Mesh.computeNormalsImmediate(mesh)
+                }
 
                 surface = createMeshRenderObject({
                     objectId: 0,
                     alpha,
+                    visible,
 
                     position: mesh.vertexBuffer,
                     normal: mesh.normalBuffer,

+ 7 - 2
src/mol-geo/shape/mesh.ts

@@ -8,7 +8,7 @@ import { Task } from 'mol-task'
 import { ValueCell } from 'mol-util'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Sphere3D } from 'mol-math/geometry'
-import { transformPositionArray } from '../util';
+import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../util';
 
 export interface Mesh {
     /** Number of vertices in the mesh */
@@ -86,7 +86,12 @@ export namespace Mesh {
 
     export function transformRangeImmediate(mesh: Mesh, t: Mat4, offset: number, count: number) {
         transformPositionArray(t, mesh.vertexBuffer.ref.value, offset, count)
-        // transformDirectionArray(n, mesh.normalBuffer.ref.value, offset, count)  // TODO
+        // TODO normals transformation does not work for an unknown reason, ASR
+        // if (mesh.normalBuffer.ref.value) {
+        //     const n = getNormalMatrix(Mat3.zero(), t)
+        //     transformDirectionArray(n, mesh.normalBuffer.ref.value, offset, count)
+        //     mesh.normalsComputed = true;
+        // }
         mesh.normalsComputed = false;
         // mesh.boundingSphere = void 0;
     }

+ 14 - 7
src/mol-geo/util.ts

@@ -19,21 +19,28 @@ export function normalizeVec3Array<T extends Helpers.NumberArray> (a: T) {
     }
 }
 
-const tmpV = Vec3.zero()
+export function getNormalMatrix(out: Mat3, t: Mat4) {
+    Mat3.fromMat4(out, t)
+    Mat3.invert(out, out)
+    Mat3.transpose(out, out)
+    return out
+}
+
+const tmpV3 = Vec3.zero()
 
 export function transformPositionArray (t: Mat4, array: Helpers.NumberArray, offset: number, count: number) {
     for (let i = 0, il = count * 3; i < il; i += 3) {
-        Vec3.fromArray(tmpV, array, offset + i)
-        Vec3.transformMat4(tmpV, tmpV, t)
-        Vec3.toArray(tmpV, array, offset + i)
+        Vec3.fromArray(tmpV3, array, offset + i)
+        Vec3.transformMat4(tmpV3, tmpV3, t)
+        Vec3.toArray(tmpV3, array, offset + i)
     }
 }
 
 export function transformDirectionArray (n: Mat3, array: Helpers.NumberArray, offset: number, count: number) {
     for (let i = 0, il = count * 3; i < il; i += 3) {
-        Vec3.fromArray(tmpV, array, offset + i)
-        Vec3.transformMat3(tmpV, tmpV, n)
-        Vec3.toArray(tmpV, array, offset + i)
+        Vec3.fromArray(tmpV3, array, offset + i)
+        Vec3.transformMat3(tmpV3, tmpV3, n)
+        Vec3.toArray(tmpV3, array, offset + i)
     }
 }
 

+ 1 - 0
src/mol-gl/_spec/renderer.spec.ts

@@ -51,6 +51,7 @@ function createPoints() {
     return createPointRenderObject({
         objectId: 0,
         alpha: 1.0,
+        visible: true,
 
         position,
         id,

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

@@ -8,6 +8,16 @@ import PointRenderable from './renderable/point'
 import MeshRenderable from './renderable/mesh'
 import { Program } from './webgl/program';
 
+export type BaseProps = {
+    objectId: number
+    alpha: number
+    visible: boolean
+
+    flatShaded?: boolean
+    doubleSided?: boolean
+    flipSided?: boolean
+}
+
 export interface Renderable<T> {
     draw: () => void
     name: string

+ 2 - 9
src/mol-gl/renderable/mesh.ts

@@ -7,7 +7,7 @@
 import { ValueCell } from 'mol-util/value-cell'
 import { ColorData } from 'mol-geo/util/color-data';
 
-import { Renderable } from '../renderable'
+import { Renderable, BaseProps } from '../renderable'
 import { getBaseDefs, getBaseValues, getBaseDefines } from './util'
 import { MeshShaderCode, addShaderDefines } from '../shader-code'
 import { Context } from '../webgl/context';
@@ -17,9 +17,6 @@ type Mesh = 'mesh'
 
 namespace Mesh {
     export type Props = {
-        objectId: number
-        alpha: number
-
         position: ValueCell<Float32Array>
         normal: ValueCell<Float32Array | undefined>
         id: ValueCell<Float32Array>
@@ -32,11 +29,7 @@ namespace Mesh {
         instanceCount: number
         elementCount: number
         positionCount: number
-
-        flatShaded?: boolean
-        doubleSided?: boolean
-        flipSided?: boolean
-    }
+    } & BaseProps
 
     export function create(ctx: Context, props: Props): Renderable<Props> {
         const defines = getBaseDefines(props)

+ 2 - 5
src/mol-gl/renderable/point.ts

@@ -6,7 +6,7 @@
 
 import { ValueCell } from 'mol-util/value-cell'
 
-import { Renderable } from '../renderable'
+import { Renderable, BaseProps } from '../renderable'
 import { getBaseValues, getBaseDefs, getBaseDefines } from './util'
 import { PointShaderCode, addShaderDefines } from '../shader-code'
 import { ColorData } from 'mol-geo/util/color-data';
@@ -18,9 +18,6 @@ type Point = 'point'
 
 namespace Point {
     export type Props = {
-        objectId: number
-        alpha: number
-
         position: ValueCell<Float32Array>
         id: ValueCell<Float32Array>
 
@@ -33,7 +30,7 @@ namespace Point {
         positionCount: number,
 
         usePointSizeAttenuation?: boolean
-    }
+    } & BaseProps
 
     export function create<T = Props>(ctx: Context, props: Props): Renderable<Props> {
         const defines = getBaseDefines(props)

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

@@ -69,8 +69,22 @@ namespace Renderer {
 
         let currentProgramId = -1
         const drawObject = (r: Renderable<any>, o: RenderObject) => {
-            if (o.visible) {
+            if (o.props.visible) {
                 if (currentProgramId !== r.program.id) {
+                    if (o.props.doubleSided) {
+                        gl.disable(gl.CULL_FACE)
+                    } else {
+                        gl.enable(gl.CULL_FACE)
+                    }
+
+                    if (o.props.flipSided) {
+                        gl.frontFace(gl.CW)
+                        gl.cullFace(gl.FRONT)
+                    } else {
+                        gl.frontFace(gl.CCW)
+                        gl.cullFace(gl.BACK)
+                    }
+
                     r.program.use()
                     r.program.setUniforms({
                         model,

+ 5 - 5
src/mol-gl/scene.ts

@@ -16,16 +16,16 @@ function getNextId() {
 
 export type RenderData = { [k: string]: ValueCell<Helpers.TypedArray> }
 
-export interface BaseRenderObject { id: number, type: string, props: {}, visible: boolean, transparent: boolean }
+export interface BaseRenderObject { id: number, type: string, props: {} }
 export interface MeshRenderObject extends BaseRenderObject { type: 'mesh', props: MeshRenderable.Props }
 export interface PointRenderObject extends BaseRenderObject { type: 'point', props: PointRenderable.Props }
 export type RenderObject = MeshRenderObject | PointRenderObject
 
 export function createMeshRenderObject(props: MeshRenderable.Props): MeshRenderObject {
-    return { id: getNextId(), type: 'mesh', props, visible: true, transparent: props.alpha < 1 }
+    return { id: getNextId(), type: 'mesh', props }
 }
 export function createPointRenderObject(props: PointRenderable.Props): PointRenderObject {
-    return { id: getNextId(), type: 'point', props, visible: true, transparent: props.alpha < 1 }
+    return { id: getNextId(), type: 'point', props }
 }
 
 export function createRenderable(ctx: Context, o: RenderObject) {
@@ -73,12 +73,12 @@ namespace Scene {
             },
             eachOpaque: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
                 renderableMap.forEach((r, o) => {
-                    if (!o.transparent) callbackFn(r, o)
+                    if (o.props.alpha === 1) callbackFn(r, o)
                 })
             },
             eachTransparent: (callbackFn: (value: Renderable<any>, key: RenderObject) => void) => {
                 renderableMap.forEach((r, o) => {
-                    if (o.transparent) callbackFn(r, o)
+                    if (o.props.alpha < 1) callbackFn(r, o)
                 })
             },
             get count() {

+ 1 - 4
src/mol-gl/shader/mesh.frag

@@ -48,10 +48,7 @@ void main() {
     #ifdef FLAT_SHADED
         vec3 fdx = dFdx(vViewPosition);
         vec3 fdy = dFdy(vViewPosition);
-        vec3 N = normalize(cross(fdx, fdy));
-        #ifdef FLIP_SIDED
-            N = -N;
-        #endif
+        vec3 N = -normalize(cross(fdx, fdy));
     #else
         vec3 N = -normalize(vNormal);
         #ifdef DOUBLE_SIDED

+ 2 - 2
src/mol-gl/shader/mesh.vert

@@ -39,8 +39,8 @@ void main(){
 
     #ifndef FLAT_SHADED
         mat3 normalMatrix = transpose(inverse(mat3(modelView)));
-        vec3 transformedNormal = normalize(normalMatrix * normal);
-        #ifdef FLIP_SIDED
+        vec3 transformedNormal = normalize(normalMatrix * normalize(normal));
+        #if defined(FLIP_SIDED) && !defined(DOUBLE_SIDED) // TODO checking DOUBLE_SIDED should not be required, ASR
             transformedNormal = -transformedNormal;
         #endif
         vNormal = transformedNormal;

+ 13 - 0
src/mol-math/linear-algebra/3d/mat3.ts

@@ -179,6 +179,19 @@ namespace Mat3 {
         out[8] = (a11 * a00 - a01 * a10) * det;
         return out;
     }
+
+    export function determinant(a: Mat3) {
+        const a00 = a[0], a01 = a[1], a02 = a[2];
+        const a10 = a[3], a11 = a[4], a12 = a[5];
+        const a20 = a[6], a21 = a[7], a22 = a[8];
+
+        const b01 = a22 * a11 - a12 * a21;
+        const b11 = -a22 * a10 + a12 * a20;
+        const b21 = a21 * a10 - a11 * a20;
+
+        // Calculate the determinant
+        return a00 * b01 + a01 * b11 + a02 * b21;
+    }
 }
 
 export default Mat3

+ 14 - 0
src/mol-math/linear-algebra/3d/vec4.ts

@@ -62,6 +62,20 @@ namespace Vec4 {
         return a
     }
 
+    export function toVec3Array(a: Vec4, out: Helpers.NumberArray, offset: number) {
+        out[offset + 0] = a[0];
+        out[offset + 1] = a[1];
+        out[offset + 2] = a[2];
+    }
+
+    export function fromVec3Array(a: Vec4, array: Helpers.NumberArray, offset: number) {
+        a[0] = array[offset + 0]
+        a[1] = array[offset + 1]
+        a[2] = array[offset + 2]
+        a[3] = 0
+        return a
+    }
+
     export function copy(out: Vec4, a: Vec4) {
         out[0] = a[0];
         out[1] = a[1];

+ 2 - 2
src/mol-view/viewer.ts

@@ -106,11 +106,11 @@ namespace Viewer {
         return {
             hide: (repr: Representation<any>) => {
                 const renderObjectSet = reprMap.get(repr)
-                if (renderObjectSet) renderObjectSet.forEach(o => o.visible = false)
+                if (renderObjectSet) renderObjectSet.forEach(o => o.props.visible = false)
             },
             show: (repr: Representation<any>) => {
                 const renderObjectSet = reprMap.get(repr)
-                if (renderObjectSet) renderObjectSet.forEach(o => o.visible = true)
+                if (renderObjectSet) renderObjectSet.forEach(o => o.props.visible = true)
             },
 
             add: (repr: Representation<any>) => {