diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts index 912f0090b51a7fb923cf333355235034a77598c7..36865663af9be4f3e8a1190cd3648f8d29a56c0d 100644 --- a/src/apps/canvas/structure-view.ts +++ b/src/apps/canvas/structure-view.ts @@ -10,7 +10,7 @@ import { BallAndStickRepresentation } from 'mol-geo/representation/structure/rep import { getStructureFromModel } from './util'; import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry'; import { ShapeRepresentation, ShapeProps } from 'mol-geo/representation/shape'; -import { getAxesShape } from './assembly-symmetry'; +import { getAxesShape, getClusterColorTheme } from './assembly-symmetry'; import Viewer from 'mol-view/viewer'; import { CarbohydrateRepresentation } from 'mol-geo/representation/structure/representation/carbohydrate'; import { MeshBuilder } from 'mol-geo/mesh/mesh-builder'; @@ -19,6 +19,7 @@ import { Shape } from 'mol-model/shape'; import { Color } from 'mol-util/color'; import { computeUnitBoundary } from 'mol-model/structure/structure/util/boundary'; import { addBoundingBox } from 'mol-geo/mesh/builder/bounding-box'; +import { PointRepresentation } from 'mol-geo/representation/structure/representation/point'; export interface StructureView { readonly label: string @@ -52,6 +53,7 @@ interface StructureViewProps { export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> { const cartoon = CartoonRepresentation() + const point = PointRepresentation() const ballAndStick = BallAndStickRepresentation() const carbohydrate = CarbohydrateRepresentation() const symmetryAxes = ShapeRepresentation() @@ -154,55 +156,63 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model> async function createStructureRepr() { if (structure) { console.log('createStructureRepr') - await cartoon.createOrUpdate({ - colorTheme: { name: 'chain-id' }, + // await cartoon.createOrUpdate({ + // colorTheme: { name: 'unit-index' }, + // sizeTheme: { name: 'uniform', value: 0.2 }, + // useFog: false // TODO fog not working properly + // }, structure).run() + + await point.createOrUpdate({ + colorTheme: { name: 'unit-index' }, sizeTheme: { name: 'uniform', value: 0.2 }, useFog: false // TODO fog not working properly }, structure).run() - await ballAndStick.createOrUpdate({ - colorTheme: { name: 'element-symbol' }, - sizeTheme: { name: 'uniform', value: 0.1 }, - useFog: false // TODO fog not working properly - }, structure).run() + // await ballAndStick.createOrUpdate({ + // colorTheme: { name: 'unit-index' }, + // sizeTheme: { name: 'uniform', value: 0.1 }, + // useFog: false // TODO fog not working properly + // }, structure).run() - await carbohydrate.createOrUpdate({ - colorTheme: { name: 'carbohydrate-symbol' }, - sizeTheme: { name: 'uniform', value: 1, factor: 1 }, - useFog: false // TODO fog not working properly - }, structure).run() + // await carbohydrate.createOrUpdate({ + // colorTheme: { name: 'carbohydrate-symbol' }, + // sizeTheme: { name: 'uniform', value: 1, factor: 1 }, + // useFog: false // TODO fog not working properly + // }, structure).run() viewer.center(structure.boundary.sphere.center) - const mb = MeshBuilder.create() - mb.setGroup(0) - addSphere(mb, structure.boundary.sphere.center, structure.boundary.sphere.radius, 3) - addBoundingBox(mb, structure.boundary.box, 1, 2, 8) - for (let i = 0, il = structure.units.length; i < il; ++i) { - mb.setGroup(1) - const u = structure.units[i] - const ci = u.model.atomicHierarchy.chainAtomSegments.index[u.elements[0]] - const ek = u.model.atomicHierarchy.getEntityKey(ci) - if (u.model.entities.data.type.value(ek) === 'water') continue - const boundary = computeUnitBoundary(u) - addSphere(mb, boundary.sphere.center, boundary.sphere.radius, 3) - addBoundingBox(mb, boundary.box, 0.5, 2, 8) - } - const shape = Shape.create('boundary', mb.getMesh(), [Color(0xCC6633), Color(0x3366CC)], ['sphere boundary']) - await polymerSphere.createOrUpdate({ - alpha: 0.5, - doubleSided: false, - depthMask: false, - useFog: false // TODO fog not working properly - }, shape).run() + // const mb = MeshBuilder.create() + // mb.setGroup(0) + // addSphere(mb, structure.boundary.sphere.center, structure.boundary.sphere.radius, 3) + // addBoundingBox(mb, structure.boundary.box, 1, 2, 8) + // for (let i = 0, il = structure.units.length; i < il; ++i) { + // mb.setGroup(1) + // const u = structure.units[i] + // const ci = u.model.atomicHierarchy.chainAtomSegments.index[u.elements[0]] + // const ek = u.model.atomicHierarchy.getEntityKey(ci) + // if (u.model.entities.data.type.value(ek) === 'water') continue + // const boundary = computeUnitBoundary(u) + // addSphere(mb, boundary.sphere.center, boundary.sphere.radius, 3) + // addBoundingBox(mb, boundary.box, 0.5, 2, 8) + // } + // const shape = Shape.create('boundary', mb.getMesh(), [Color(0xCC6633), Color(0x3366CC)], ['sphere boundary']) + // await polymerSphere.createOrUpdate({ + // alpha: 0.5, + // doubleSided: false, + // depthMask: false, + // useFog: false // TODO fog not working properly + // }, shape).run() } else { cartoon.destroy() + point.destroy() ballAndStick.destroy() carbohydrate.destroy() polymerSphere.destroy() } viewer.add(cartoon) + viewer.add(point) viewer.add(ballAndStick) viewer.add(carbohydrate) viewer.add(polymerSphere) @@ -214,9 +224,19 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model> if (features._rowCount) { const axesShape = getAxesShape(symmetryFeatureId, assemblySymmetry) if (axesShape) { - // getClusterColorTheme(symmetryFeatureId, assemblySymmetry) + const colorTheme = getClusterColorTheme(symmetryFeatureId, assemblySymmetry) + // await cartoon.createOrUpdate({ + // colorTheme: { name: 'custom', ...colorTheme }, + // sizeTheme: { name: 'uniform', value: 0.2 }, + // useFog: false // TODO fog not working properly + // }).run() + // await ballAndStick.createOrUpdate({ + // colorTheme: { name: 'custom', ...colorTheme }, + // sizeTheme: { name: 'uniform', value: 0.1 }, + // useFog: false // TODO fog not working properly + // }).run() await symmetryAxes.createOrUpdate({ - colorTheme: { name: 'shape-group' }, + colorTheme: { name: 'shape-group', ...colorTheme }, // colorTheme: { name: 'uniform', value: Color(0xFFCC22) }, useFog: false // TODO fog not working properly }, axesShape).run() diff --git a/src/mol-geo/representation/structure/representation/point.ts b/src/mol-geo/representation/structure/representation/point.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d15e6555eb40a1001956e6c414b9831ac1f0d81 --- /dev/null +++ b/src/mol-geo/representation/structure/representation/point.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { UnitsRepresentation } from '..'; +import { ElementPointVisual, DefaultElementPointProps } from '../visual/element-point'; +import { StructureRepresentation } from '../units-representation'; + +export const DefaultSpacefillProps = { + ...DefaultElementPointProps +} +export type PointProps = typeof DefaultElementPointProps + +export type PointRepresentation = StructureRepresentation<PointProps> + +export function PointRepresentation(): PointRepresentation { + return UnitsRepresentation(ElementPointVisual) +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/units-visual.ts b/src/mol-geo/representation/structure/units-visual.ts index d85859826d8c5d66deb4084830416c89ec4b2067..d1d9a8f5517a477ad175b5eccc5fdfbc6560e2aa 100644 --- a/src/mol-geo/representation/structure/units-visual.ts +++ b/src/mol-geo/representation/structure/units-visual.ts @@ -94,7 +94,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu createTransforms(currentGroup, renderObject.values) createMarkers(instanceCount * groupCount, renderObject.values) ValueCell.update(renderObject.values.instanceCount, instanceCount) - ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO + ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO reuse array updateState.updateColor = true } diff --git a/src/mol-geo/representation/structure/visual/element-point.ts b/src/mol-geo/representation/structure/visual/element-point.ts index d717deb4d3663a42e87749feb603c8691fc76196..0765138ae8ca01645fc13cfc2d482e754d683035 100644 --- a/src/mol-geo/representation/structure/visual/element-point.ts +++ b/src/mol-geo/representation/structure/visual/element-point.ts @@ -24,33 +24,33 @@ import { fillSerial } from 'mol-util/array'; import { SizeThemeProps } from 'mol-view/theme/size'; import { LocationIterator } from '../../../util/location-iterator'; -export const DefaultPointProps = { +export const DefaultElementPointProps = { ...DefaultStructureProps, sizeTheme: { name: 'physical' } as SizeThemeProps } -export type PointProps = Partial<typeof DefaultPointProps> +export type ElementPointProps = Partial<typeof DefaultElementPointProps> -export function createPointVertices(unit: Unit) { +// TODO make async +export function createElementPointVertices(unit: Unit, vertices?: ValueCell<Float32Array>) { const elements = unit.elements - const elementCount = elements.length - const vertices = new Float32Array(elementCount * 3) + const n = elements.length * 3 + const array = vertices && vertices.ref.value.length >= n ? vertices.ref.value : new Float32Array(n) const pos = unit.conformation.invariantPosition const p = Vec3.zero() - for (let i = 0; i < elementCount; i++) { - const i3 = i * 3 - pos(elements[i], p) - vertices[i3] = p[0] - vertices[i3 + 1] = p[1] - vertices[i3 + 2] = p[2] + for (let i = 0; i < n; i += 3) { + pos(elements[i / 3], p) + array[i] = p[0] + array[i + 1] = p[1] + array[i + 2] = p[2] } - return vertices + return vertices ? ValueCell.update(vertices, array) : ValueCell.create(array) } -export default function PointVisual(): UnitsVisual<PointProps> { +export function ElementPointVisual(): UnitsVisual<ElementPointProps> { let renderObject: PointRenderObject | undefined - let currentProps = DefaultPointProps + let currentProps = DefaultElementPointProps let currentGroup: Unit.SymmetryGroup let locationIt: LocationIterator @@ -59,11 +59,11 @@ export default function PointVisual(): UnitsVisual<PointProps> { return { get renderObject () { return renderObject }, - async createOrUpdate(ctx: RuntimeContext, props: PointProps = {}, group?: Unit.SymmetryGroup) { + async createOrUpdate(ctx: RuntimeContext, props: ElementPointProps = {}, group?: Unit.SymmetryGroup) { if (!group && !currentGroup) { throw new Error('missing group') } else if (group && !currentGroup) { - currentProps = Object.assign({}, DefaultPointProps, props) + currentProps = Object.assign({}, DefaultElementPointProps, props) currentGroup = group locationIt = StructureElementIterator.fromGroup(group) @@ -74,14 +74,16 @@ export default function PointVisual(): UnitsVisual<PointProps> { const elementCount = _elements.length const instanceCount = group.units.length - const vertices = createPointVertices(_units[0]) + const vertices = createElementPointVertices(_units[0]) const transform = createTransforms(group) + // console.time('createColors point') const color = await createColors(ctx, locationIt, colorTheme) + // console.timeEnd('createColors point') const size = createSizes(locationIt, sizeTheme) const marker = createMarkers(instanceCount * elementCount) const values: PointValues = { - aPosition: ValueCell.create(vertices), + aPosition: vertices, aGroup: ValueCell.create(fillSerial(new Float32Array(elementCount))), aInstance: ValueCell.create(fillSerial(new Float32Array(instanceCount))), ...transform, @@ -93,7 +95,7 @@ export default function PointVisual(): UnitsVisual<PointProps> { uInstanceCount: ValueCell.create(instanceCount), uGroupCount: ValueCell.create(group.elements.length), - drawCount: ValueCell.create(vertices.length / 3), + drawCount: ValueCell.create(group.elements.length), instanceCount: ValueCell.create(instanceCount), dPointSizeAttenuation: ValueCell.create(true), @@ -106,13 +108,44 @@ export default function PointVisual(): UnitsVisual<PointProps> { renderObject = createPointRenderObject(values, state) } else if (renderObject) { + if (group) currentGroup = group + const newProps = { ...currentProps, ...props } - if (!deepEqual(currentProps.colorTheme, newProps.colorTheme)) { + let updateTransform = false + let createVertices = false + let updateColor = false + let updateSize = false + + if (currentGroup.units.length !== locationIt.instanceCount) updateTransform = true + if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) createVertices = true + if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateColor = true + if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateSize = true + + if (updateTransform) { + locationIt = StructureElementIterator.fromGroup(currentGroup) + const { instanceCount, groupCount } = locationIt + createTransforms(currentGroup, renderObject.values) + createMarkers(instanceCount * groupCount, renderObject.values) + ValueCell.update(renderObject.values.instanceCount, instanceCount) + ValueCell.update(renderObject.values.aInstance, fillSerial(new Float32Array(instanceCount))) // TODO reuse array + updateColor = true + updateSize = true + } + + if (createVertices) { + createElementPointVertices(currentGroup.units[0], renderObject.values.aPosition) + ValueCell.update(renderObject.values.aGroup, fillSerial(new Float32Array(locationIt.groupCount))) // TODO reuse array + ValueCell.update(renderObject.values.drawCount, currentGroup.elements.length) + updateColor = true + updateSize = true + } + + if (updateColor) { await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values) } - if (!deepEqual(currentProps.sizeTheme, newProps.sizeTheme)) { + if (updateSize) { createSizes(locationIt, newProps.sizeTheme, renderObject.values) } diff --git a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts index e3b1b00ae8c4923e157908bd9ecd404e10285b79..8c848a8cb0fa7107fcfab1fa0762eee089207552 100644 --- a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts @@ -73,6 +73,7 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> { return UnitsMeshVisual<PolymerBackboneProps>({ defaultProps: DefaultPolymerBackboneProps, createMesh: createPolymerBackboneCylinderMesh, + // TODO create a specialized location iterator createLocationIterator: StructureElementIterator.fromGroup, getLoci: getElementLoci, mark: markElement, diff --git a/src/mol-geo/representation/structure/visual/util/common.ts b/src/mol-geo/representation/structure/visual/util/common.ts index 55b05b08c6801b8e68712dd53b2e76b3b6b770c3..b55c3f265d302172a4b8cd82b8fe007e8ef6f175 100644 --- a/src/mol-geo/representation/structure/visual/util/common.ts +++ b/src/mol-geo/representation/structure/visual/util/common.ts @@ -62,9 +62,9 @@ type StructureMeshProps = Required<MeshProps & StructureProps> async function _createMeshValues(ctx: RuntimeContext, transforms: TransformData, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): Promise<MeshValues> { const { instanceCount, groupCount } = locationIt - console.time('createColors1') + console.time('createColors mesh') const color = await createColors(ctx, locationIt, props.colorTheme) - console.timeEnd('createColors1') + console.timeEnd('createColors mesh') const marker = createMarkers(instanceCount * groupCount) const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount } diff --git a/src/mol-gl/renderer.ts b/src/mol-gl/renderer.ts index 22e64a84405ff4e48940befa7e46dcd04113dd8b..45e6d11f24ba1fcb719467e72ab6cf20b6706bb7 100644 --- a/src/mol-gl/renderer.ts +++ b/src/mol-gl/renderer.ts @@ -92,16 +92,28 @@ namespace Renderer { program.setUniforms(globalUniforms) currentProgramId = program.id } - if (r.values.dDoubleSided.ref.value) { - gl.disable(gl.CULL_FACE) + + if (r.values.dDoubleSided) { + if (r.values.dDoubleSided.ref.value) { + gl.disable(gl.CULL_FACE) + } else { + gl.enable(gl.CULL_FACE) + } } else { - gl.enable(gl.CULL_FACE) + // webgl default + gl.disable(gl.CULL_FACE) } - if (r.values.dFlipSided.ref.value) { - gl.frontFace(gl.CW) - gl.cullFace(gl.FRONT) + if (r.values.dFlipSided) { + if (r.values.dFlipSided.ref.value) { + gl.frontFace(gl.CW) + gl.cullFace(gl.FRONT) + } else { + gl.frontFace(gl.CCW) + gl.cullFace(gl.BACK) + } } else { + // webgl default gl.frontFace(gl.CCW) gl.cullFace(gl.BACK) } diff --git a/src/mol-gl/shader/chunks/assign-material-color.glsl b/src/mol-gl/shader/chunks/assign-material-color.glsl index 5969c88c34b534a0556d2da9f30e6b22f41a557e..11b1779411269ab223e03cbbc42a90865a286d69 100644 --- a/src/mol-gl/shader/chunks/assign-material-color.glsl +++ b/src/mol-gl/shader/chunks/assign-material-color.glsl @@ -1,5 +1,5 @@ #if defined(dColorType_uniform) - vec4 material = vec4(uColor, 1.0); + vec4 material = vec4(uColor, uAlpha); #elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) vec4 material = vColor; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl b/src/mol-gl/shader/chunks/common-frag-params.glsl index a1b1b64d8eb9b2a560e4de1b101bb5cc331748ab..c757d1b2f5afa54efad4236d533b9f4535bc64da 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl +++ b/src/mol-gl/shader/chunks/common-frag-params.glsl @@ -6,6 +6,10 @@ uniform vec3 uHighlightColor; uniform vec3 uSelectColor; varying float vMarker; +varying vec3 vViewPosition; + uniform float uFogNear; uniform float uFogFar; -uniform vec3 uFogColor; \ No newline at end of file +uniform vec3 uFogColor; + +uniform float uAlpha; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-vert-params.glsl b/src/mol-gl/shader/chunks/common-vert-params.glsl index 30bc2caea18865056975654eeccac9b43348ba66..5028d0abb23450b2c7126a1ed256a6ebfeff95d6 100644 --- a/src/mol-gl/shader/chunks/common-vert-params.glsl +++ b/src/mol-gl/shader/chunks/common-vert-params.glsl @@ -7,4 +7,7 @@ uniform int uGroupCount; uniform vec2 uMarkerTexDim; uniform sampler2D tMarker; varying float vMarker; + +varying vec3 vViewPosition; + #pragma glslify: readFromTexture = require(../utils/read-from-texture.glsl) \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag index ce282933ea1281f35e1699e3d0acc373ec3a814f..5b6a6e7218aa4d896bed9a19df9692d36bf9f366 100644 --- a/src/mol-gl/shader/mesh.frag +++ b/src/mol-gl/shader/mesh.frag @@ -18,12 +18,10 @@ precision highp int; uniform vec3 uLightColor; uniform vec3 uLightAmbient; uniform mat4 uView; -uniform float uAlpha; #ifndef dFlatShaded varying vec3 vNormal; #endif -varying vec3 vViewPosition; #pragma glslify: attenuation = require(./utils/attenuation.glsl) #pragma glslify: calculateSpecular = require(./utils/phong-specular.glsl) @@ -74,7 +72,7 @@ void main() { // gl_FragColor.a = 1.0; // gl_FragColor.rgb = vec3(1.0, 0.0, 0.0); gl_FragColor.rgb = finalColor; - gl_FragColor.a = uAlpha; + gl_FragColor.a = material.a; #pragma glslify: import('./chunks/apply-marker-color.glsl') #pragma glslify: import('./chunks/apply-fog.glsl') diff --git a/src/mol-gl/shader/mesh.vert b/src/mol-gl/shader/mesh.vert index af38be41e65a3be4d05412a1cadd618ce5d38438..b3f1a943085fda68654f05d072db68d6bc803577 100644 --- a/src/mol-gl/shader/mesh.vert +++ b/src/mol-gl/shader/mesh.vert @@ -20,8 +20,6 @@ attribute float aGroup; varying vec3 vNormal; #endif -varying vec3 vViewPosition; - #pragma glslify: inverse = require(./utils/inverse.glsl) #pragma glslify: transpose = require(./utils/transpose.glsl) diff --git a/src/mol-gl/shader/point.frag b/src/mol-gl/shader/point.frag index ae18b4a35f8ac2bf100ba5b52873c1bb5ab4d1e5..861bfef3fa6b59cf498fb9f57747fde9f2a1de94 100644 --- a/src/mol-gl/shader/point.frag +++ b/src/mol-gl/shader/point.frag @@ -10,12 +10,10 @@ precision highp int; #pragma glslify: import('./chunks/common-frag-params.glsl') #pragma glslify: import('./chunks/color-frag-params.glsl') -uniform float uAlpha; - void main(){ #pragma glslify: import('./chunks/assign-material-color.glsl') - - gl_FragColor = vec4(material, uAlpha); + + gl_FragColor = material; #pragma glslify: import('./chunks/apply-marker-color.glsl') #pragma glslify: import('./chunks/apply-fog.glsl') diff --git a/src/mol-view/theme/color/unit-index.ts b/src/mol-view/theme/color/unit-index.ts index 23411606cb1e5b2052a11ea0dca3c3e90cd3e528..4b55b16dd09622a931deac5da509d707ba594841 100644 --- a/src/mol-view/theme/color/unit-index.ts +++ b/src/mol-view/theme/color/unit-index.ts @@ -34,5 +34,5 @@ export function UnitIndexColorTheme(props: ColorThemeProps): ColorTheme { color = () => DefaultColor } - return { kind: 'groupInstance', color } + return { kind: 'instance', color } } \ No newline at end of file diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index 811fa40bd4663ea8650a870d703ba697f82a7cf3..7c4070cd107c4ceec5a209bfedca4e9d75f87635 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -104,7 +104,7 @@ namespace Viewer { // const renderer = Renderer.create(ctx, camera, { clearColor: 0xFFFFFF }) const renderer = Renderer.create(ctx, camera, { clearColor: Color(0x000000) }) - const pickScale = 1 / 4 + const pickScale = 1 const pickWidth = Math.round(canvas.width * pickScale) const pickHeight = Math.round(canvas.height * pickScale) const objectPickTarget = createRenderTarget(ctx, pickWidth, pickHeight)