Compare commits

..

3 Commits

Author SHA1 Message Date
Alexander Rose
fa2b8542bf 2.0.0-dev.2 2021-02-18 21:20:14 -08:00
Alexander Rose
901522f500 added atom-id and entity-id color theme 2021-02-18 21:16:46 -08:00
dsehnal
62b63c1aa5 apply magic to solve GPU MC rendering issue 2021-02-18 19:05:07 +01:00
8 changed files with 213 additions and 10 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "2.0.0-dev.1",
"version": "2.0.0-dev.2",
"lockfileVersion": 2,
"requires": true,
"packages": {

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "2.0.0-dev.1",
"version": "2.0.0-dev.2",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {

View File

@@ -19,6 +19,7 @@ import { quad_vert } from '../../../mol-gl/shader/quad.vert';
import { isosurface_frag } from '../../../mol-gl/shader/marching-cubes/isosurface.frag';
import { calcActiveVoxels } from './active-voxels';
import { isWebGL2 } from '../../webgl/compat';
import { Scheduler } from '../../../mol-task';
const IsosurfaceSchema = {
...QuadSchema,
@@ -185,26 +186,36 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
gl.clear(gl.COLOR_BUFFER_BIT);
renderable.render();
gl.flush();
gl.finish();
return { vertexTexture, groupTexture, normalTexture, vertexCount: count };
}
//
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
function delay() {
return new Promise(r => Scheduler.setImmediate(r));
}
export async function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('calcActiveVoxels');
// apply advanced magic to solve incomplete buffer rendering issue
await delay();
// console.time('createHistogramPyramid');
const compacted = createHistogramPyramid(ctx, activeVoxelsTex, gridTexScale, gridTexDim);
// apply advanced magic to solve incomplete buffer rendering issue
await delay();
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createHistogramPyramid');
// console.time('createIsosurfaceBuffers');
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, packedGroup, vertexTexture, groupTexture, normalTexture);
// apply advanced magic to solve incomplete buffer rendering issue
await delay();
// ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers');

View File

@@ -181,7 +181,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
@@ -238,7 +238,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const gv = await extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);

View File

@@ -175,7 +175,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const gv = await extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, textureMesh?.vertexTexture.ref.value, textureMesh?.groupTexture.ref.value, textureMesh?.normalTexture.ref.value);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);

View File

@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
@@ -33,6 +33,8 @@ import { OccupancyColorThemeProvider } from './color/occupancy';
import { OperatorNameColorThemeProvider } from './color/operator-name';
import { OperatorHklColorThemeProvider } from './color/operator-hkl';
import { PartialChargeColorThemeProvider } from './color/partial-charge';
import { AtomIdColorThemeProvider } from './color/atom-id';
import { EntityIdColorThemeProvider } from './color/entity-id';
export type LocationColor = (location: Location, isSecondary: boolean) => Color
@@ -80,10 +82,12 @@ namespace ColorTheme {
}
export const BuiltIn = {
'atom-id': AtomIdColorThemeProvider,
'carbohydrate-symbol': CarbohydrateSymbolColorThemeProvider,
'chain-id': ChainIdColorThemeProvider,
'element-index': ElementIndexColorThemeProvider,
'element-symbol': ElementSymbolColorThemeProvider,
'entity-id': EntityIdColorThemeProvider,
'entity-source': EntitySourceColorThemeProvider,
'hydrophobicity': HydrophobicityColorThemeProvider,
'illustrative': IllustrativeColorThemeProvider,

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { Location } from '../../mol-model/location';
import { ColorTheme, LocationColor } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { ThemeDataContext } from '../../mol-theme/theme';
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
const DefaultList = 'many-distinct';
const DefaultColor = Color(0xFAFAFA);
const Description = 'Gives every atom a color based on its `label_atom_id` value.';
export const AtomIdColorThemeParams = {
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
};
export type AtomIdColorThemeParams = typeof AtomIdColorThemeParams
export function getAtomIdColorThemeParams(ctx: ThemeDataContext) {
const params = PD.clone(AtomIdColorThemeParams);
return params;
}
function getAtomIdSerialMap(structure: Structure) {
const map = new Map<string, number>();
for (const m of structure.models) {
const { label_atom_id } = m.atomicHierarchy.atoms;
for (let i = 0, il = label_atom_id.rowCount; i < il; ++i) {
const id = label_atom_id.value(i);
if (!map.has(id)) map.set(id, map.size);
}
}
return map;
}
export function AtomIdColorTheme(ctx: ThemeDataContext, props: PD.Values<AtomIdColorThemeParams>): ColorTheme<AtomIdColorThemeParams> {
let color: LocationColor;
let legend: ScaleLegend | TableLegend | undefined;
if (ctx.structure) {
const l = StructureElement.Location.create(ctx.structure.root);
const atomIdSerialMap = getAtomIdSerialMap(ctx.structure.root);
const labelTable = Array.from(atomIdSerialMap.keys());
const valueLabel = (i: number) => labelTable[i];
const palette = getPalette(atomIdSerialMap.size, props, { valueLabel });
legend = palette.legend;
color = (location: Location): Color => {
let serial: number | undefined = undefined;
if (StructureElement.Location.is(location)) {
const id = StructureProperties.atom.label_atom_id(location);
serial = atomIdSerialMap.get(id);
} else if (Bond.isLocation(location)) {
l.unit = location.aUnit;
l.element = location.aUnit.elements[location.aIndex];
const id = StructureProperties.atom.label_atom_id(l);
serial = atomIdSerialMap.get(id);
}
return serial === undefined ? DefaultColor : palette.color(serial);
};
} else {
color = () => DefaultColor;
}
return {
factory: AtomIdColorTheme,
granularity: 'group',
color,
props,
description: Description,
legend
};
}
export const AtomIdColorThemeProvider: ColorTheme.Provider<AtomIdColorThemeParams, 'atom-id'> = {
name: 'atom-id',
label: 'Atom Id',
category: ColorTheme.Category.Atom,
factory: AtomIdColorTheme,
getParams: getAtomIdColorThemeParams,
defaultValues: PD.getDefaultValues(AtomIdColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
};

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { StructureProperties, StructureElement, Bond, Structure } from '../../mol-model/structure';
import { Color } from '../../mol-util/color';
import { Location } from '../../mol-model/location';
import { ColorTheme, LocationColor } from '../color';
import { ParamDefinition as PD } from '../../mol-util/param-definition';
import { ThemeDataContext } from '../../mol-theme/theme';
import { getPaletteParams, getPalette } from '../../mol-util/color/palette';
import { TableLegend, ScaleLegend } from '../../mol-util/legend';
const DefaultList = 'many-distinct';
const DefaultColor = Color(0xFAFAFA);
const Description = 'Gives every chain a color based on its `label_entity_id` value.';
export const EntityIdColorThemeParams = {
...getPaletteParams({ type: 'colors', colorList: DefaultList }),
};
export type EntityIdColorThemeParams = typeof EntityIdColorThemeParams
export function getEntityIdColorThemeParams(ctx: ThemeDataContext) {
const params = PD.clone(EntityIdColorThemeParams);
return params;
}
function key(entityId: string, modelIndex: number) {
return `${entityId}|${modelIndex}`;
}
function getEntityIdSerialMap(structure: Structure) {
const map = new Map<string, number>();
for (let i = 0, il = structure.models.length; i < il; ++i) {
const { label_entity_id } = structure.models[i].atomicHierarchy.chains;
for (let j = 0, jl = label_entity_id.rowCount; j < jl; ++j) {
const k = key(label_entity_id.value(j), i);
if (!map.has(k)) map.set(k, map.size);
}
}
return map;
}
export function EntityIdColorTheme(ctx: ThemeDataContext, props: PD.Values<EntityIdColorThemeParams>): ColorTheme<EntityIdColorThemeParams> {
let color: LocationColor;
let legend: ScaleLegend | TableLegend | undefined;
if (ctx.structure) {
const l = StructureElement.Location.create(ctx.structure.root);
const entityIdSerialMap = getEntityIdSerialMap(ctx.structure.root);
const labelTable = Array.from(entityIdSerialMap.keys());
const valueLabel = (i: number) => labelTable[i];
const palette = getPalette(entityIdSerialMap.size, props, { valueLabel });
legend = palette.legend;
color = (location: Location): Color => {
let serial: number | undefined = undefined;
if (StructureElement.Location.is(location)) {
const atomId = StructureProperties.chain.label_entity_id(location);
const modelIndex = location.structure.models.indexOf(location.unit.model);
const k = key(atomId, modelIndex);
serial = entityIdSerialMap.get(k);
} else if (Bond.isLocation(location)) {
l.unit = location.aUnit;
l.element = location.aUnit.elements[location.aIndex];
const atomId = StructureProperties.chain.label_entity_id(l);
const modelIndex = l.structure.models.indexOf(l.unit.model);
const k = key(atomId, modelIndex);
serial = entityIdSerialMap.get(k);
}
return serial === undefined ? DefaultColor : palette.color(serial);
};
} else {
color = () => DefaultColor;
}
return {
factory: EntityIdColorTheme,
granularity: 'group',
color,
props,
description: Description,
legend
};
}
export const EntityIdColorThemeProvider: ColorTheme.Provider<EntityIdColorThemeParams, 'entity-id'> = {
name: 'entity-id',
label: 'Entity Id',
category: ColorTheme.Category.Chain,
factory: EntityIdColorTheme,
getParams: getEntityIdColorThemeParams,
defaultValues: PD.getDefaultValues(EntityIdColorThemeParams),
isApplicable: (ctx: ThemeDataContext) => !!ctx.structure
};