From 15ebfd611e24744f97c1222283d6d9eb2c74cded Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Fri, 19 Oct 2018 18:28:16 -0700 Subject: [PATCH] wip, color support for direct volume isosurface --- .../geometry/direct-volume/direct-volume.ts | 43 ++++--- src/mol-geo/geometry/picking.ts | 2 +- .../representation/structure/units-visual.ts | 22 ++-- .../structure/visual/gaussian-surface-mesh.ts | 46 +------ .../structure/visual/util/common.ts | 7 +- .../representation/volume/direct-volume.ts | 9 +- src/mol-gl/renderable/direct-volume.ts | 15 +++ src/mol-gl/renderable/schema.ts | 2 +- .../shader/chunks/assign-color-varying.glsl | 6 +- .../shader/chunks/color-vert-params.glsl | 2 +- src/mol-gl/shader/direct-volume.frag | 118 +++++++++++------- src/mol-gl/shader/direct-volume.vert | 4 + src/mol-gl/shader/gaussian-density.frag | 4 +- src/mol-gl/shader/utils/decode-float-rgb.glsl | 11 ++ .../shader/utils/decode-float-rgba.glsl | 5 - src/mol-gl/shader/utils/decode-id-rgb.glsl | 13 ++ src/mol-gl/shader/utils/encode-float-rgb.glsl | 20 +++ .../shader/utils/encode-float-rgba.glsl | 12 -- src/mol-gl/shader/utils/encode-id-rgb.glsl | 13 ++ src/mol-gl/shader/utils/encode-id-rgba.glsl | 13 -- src/mol-gl/shader/utils/my-div.glsl | 13 -- src/mol-gl/shader/utils/my-mod.glsl | 13 -- .../utils/texture3d-from-2d-linear.glsl | 5 +- .../utils/texture3d-from-2d-nearest.glsl | 5 +- src/mol-math/geometry/gaussian-density/gpu.ts | 6 +- src/mol-view/viewer.ts | 8 +- 26 files changed, 216 insertions(+), 201 deletions(-) create mode 100644 src/mol-gl/shader/utils/decode-float-rgb.glsl delete mode 100644 src/mol-gl/shader/utils/decode-float-rgba.glsl create mode 100644 src/mol-gl/shader/utils/decode-id-rgb.glsl create mode 100644 src/mol-gl/shader/utils/encode-float-rgb.glsl delete mode 100644 src/mol-gl/shader/utils/encode-float-rgba.glsl create mode 100644 src/mol-gl/shader/utils/encode-id-rgb.glsl delete mode 100644 src/mol-gl/shader/utils/encode-id-rgba.glsl delete mode 100644 src/mol-gl/shader/utils/my-div.glsl delete mode 100644 src/mol-gl/shader/utils/my-mod.glsl diff --git a/src/mol-geo/geometry/direct-volume/direct-volume.ts b/src/mol-geo/geometry/direct-volume/direct-volume.ts index cdfdccc30..5d175ea1f 100644 --- a/src/mol-geo/geometry/direct-volume/direct-volume.ts +++ b/src/mol-geo/geometry/direct-volume/direct-volume.ts @@ -7,12 +7,17 @@ import { RuntimeContext } from 'mol-task' import { ValueCell } from 'mol-util' import { Sphere3D, Box3D } from 'mol-math/geometry' -import { paramDefaultValues, RangeParam, BooleanParam, SelectParam, TextParam } from 'mol-view/parameter'; +import { paramDefaultValues, RangeParam, SelectParam, TextParam } from 'mol-view/parameter'; import { DirectVolume2dValues, DirectVolumeBaseValues, DirectVolume3dValues } from 'mol-gl/renderable/direct-volume'; import { Vec3, Vec2, Mat4 } from 'mol-math/linear-algebra'; import { Box } from '../../primitive/box'; import { getControlPointsFromString, createTransferFunctionTexture } from './transfer-function'; import { Texture } from 'mol-gl/webgl/texture'; +import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { TransformData } from '../transform-data'; +import { createColors } from '../color-data'; +import { createMarkers } from '../marker-data'; +import { Geometry } from '../geometry'; const VolumeBox = Box() const RenderModeOptions = [['isosurface', 'Isosurface'], ['volume', 'Volume']] as [string, string][] @@ -29,10 +34,7 @@ interface DirectVolumeBase { } const BaseParams = { - alpha: RangeParam('Opacity', '', 1, 0, 1, 0.01), - visible: BooleanParam('Visible', '', true), - depthMask: BooleanParam('Depth Mask', '', true), - useFog: BooleanParam('Use Fog', '', false), + ...Geometry.Params, isoValueAbsolute: RangeParam('Iso Value Absolute', '', 0.22, -1, 1, 0.01), isoValueRelative: RangeParam('Iso Value Relative', '', 2, -10, 10, 0.1), renderMode: SelectParam('Render Mode', '', 'volume', RenderModeOptions), @@ -41,31 +43,35 @@ const BaseParams = { const DefaultBaseProps = paramDefaultValues(BaseParams) type BaseProps = typeof DefaultBaseProps -async function createBaseValues(ctx: RuntimeContext, directVolume: DirectVolumeBase, props: BaseProps): Promise<DirectVolumeBaseValues> { - const { bboxSize, bboxMin, bboxMax, gridDimension, transform } = directVolume +async function createBaseValues(ctx: RuntimeContext, directVolume: DirectVolumeBase, transform: TransformData, locationIt: LocationIterator, props: BaseProps): Promise<DirectVolumeBaseValues> { + const { instanceCount, groupCount } = locationIt + const color = await createColors(ctx, locationIt, props) + const marker = createMarkers(instanceCount * groupCount) + + const counts = { drawCount: VolumeBox.indices.length, groupCount, instanceCount } + + const { bboxSize, bboxMin, bboxMax, gridDimension, transform: gridTransform } = directVolume const controlPoints = getControlPointsFromString(props.controlPoints) const transferTex = createTransferFunctionTexture(controlPoints) const maxSteps = Math.ceil(Vec3.magnitude(gridDimension.ref.value)) * 2 - console.log('maxSteps', maxSteps) return { - drawCount: ValueCell.create(VolumeBox.indices.length), - instanceCount: ValueCell.create(1), + ...color, + ...marker, + ...transform, + ...Geometry.createValues(props, counts), aPosition: ValueCell.create(VolumeBox.vertices as Float32Array), elements: ValueCell.create(VolumeBox.indices as Uint32Array), - uAlpha: ValueCell.create(props.alpha), - dUseFog: ValueCell.create(props.useFog), - uIsoValue: ValueCell.create(props.isoValueAbsolute), uBboxMin: bboxMin, uBboxMax: bboxMax, uBboxSize: bboxSize, dMaxSteps: ValueCell.create(maxSteps), - uTransform: transform, + uTransform: gridTransform, uGridDim: gridDimension, dRenderMode: ValueCell.create(props.renderMode), tTransferTex: transferTex, @@ -73,7 +79,6 @@ async function createBaseValues(ctx: RuntimeContext, directVolume: DirectVolumeB } function updateBaseValues(values: DirectVolumeBaseValues, props: BaseProps) { - console.log('DirectVolumeBaseValues', props, values) ValueCell.updateIfChanged(values.uIsoValue, props.isoValueAbsolute) ValueCell.updateIfChanged(values.uAlpha, props.alpha) ValueCell.updateIfChanged(values.dUseFog, props.useFog) @@ -123,11 +128,11 @@ export namespace DirectVolume2d { export const DefaultProps = paramDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume2d, props: Props): Promise<DirectVolume2dValues> { + export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume2d, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<DirectVolume2dValues> { const { gridTexture, gridTextureDim } = directVolume return { - ...await createBaseValues(ctx, directVolume, props), + ...await createBaseValues(ctx, directVolume, transform, locationIt, props), dGridTexType: ValueCell.create('2d'), uGridTexDim: gridTextureDim, tGridTex: gridTexture, @@ -176,11 +181,11 @@ export namespace DirectVolume3d { export const DefaultProps = paramDefaultValues(Params) export type Props = typeof DefaultProps - export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume3d, props: Props): Promise<DirectVolume3dValues> { + export async function createValues(ctx: RuntimeContext, directVolume: DirectVolume3d, transform: TransformData, locationIt: LocationIterator, props: Props): Promise<DirectVolume3dValues> { const { gridTexture } = directVolume return { - ...await createBaseValues(ctx, directVolume, props), + ...await createBaseValues(ctx, directVolume, transform, locationIt, props), dGridTexType: ValueCell.create('3d'), tGridTex: gridTexture, } diff --git a/src/mol-geo/geometry/picking.ts b/src/mol-geo/geometry/picking.ts index 07f2bf743..ac145f4b1 100644 --- a/src/mol-geo/geometry/picking.ts +++ b/src/mol-geo/geometry/picking.ts @@ -11,7 +11,7 @@ function decodeFloatRGBA(r: number, g: number, b: number) { return r * 256 * 256 + g * 256 + b } -export function decodeIdRGBA(r: number, g: number, b: number) { +export function decodeIdRGB(r: number, g: number, b: number) { return decodeFloatRGBA(r, g, b) - 1 } diff --git a/src/mol-geo/representation/structure/units-visual.ts b/src/mol-geo/representation/structure/units-visual.ts index 353404ea7..50de4ef0f 100644 --- a/src/mol-geo/representation/structure/units-visual.ts +++ b/src/mol-geo/representation/structure/units-visual.ts @@ -555,8 +555,6 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builde DirectVolume2d.createEmpty(directVolume as DirectVolume2d) : DirectVolume3d.createEmpty(directVolume as DirectVolume3d)) - console.log('directVolume', directVolume) - // TODO create empty location iterator when not in unitKinds locationIt = createLocationIterator(group) renderObject = await createUnitsDirectVolumeRenderObject(ctx, group, directVolume, locationIt, currentProps) @@ -589,13 +587,13 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builde // - // if (updateState.updateTransform) { - // locationIt = createLocationIterator(currentGroup) - // const { instanceCount, groupCount } = locationIt - // createUnitsTransform(currentGroup, renderObject.values) - // createMarkers(instanceCount * groupCount, renderObject.values) - // updateState.updateColor = true - // } + if (updateState.updateTransform) { + locationIt = createLocationIterator(currentGroup) + const { instanceCount, groupCount } = locationIt + createUnitsTransform(currentGroup, renderObject.values) + createMarkers(instanceCount * groupCount, renderObject.values) + updateState.updateColor = true + } if (updateState.createGeometry) { directVolume = includesUnitKind(newProps.unitKinds, unit) @@ -606,9 +604,9 @@ export function UnitsDirectVolumeVisual<P extends UnitsDirectVolumeProps>(builde updateState.updateColor = true } - // if (updateState.updateColor) { - // await createColors(ctx, locationIt, newProps, renderObject.values) - // } + if (updateState.updateColor) { + await createColors(ctx, locationIt, newProps, renderObject.values) + } if (renderObject.type === 'direct-volume-2d') { DirectVolume2d.updateValues(renderObject.values, newProps) diff --git a/src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts b/src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts index 6d36997bb..043f8dc93 100644 --- a/src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts +++ b/src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts @@ -4,7 +4,7 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { Unit, Structure, StructureElement, ElementIndex } from 'mol-model/structure'; +import { Unit, Structure } from 'mol-model/structure'; import { UnitsVisual, VisualUpdateState } from '..'; import { RuntimeContext } from 'mol-task' import { Mesh } from '../../../geometry/mesh/mesh'; @@ -13,11 +13,9 @@ import { StructureElementIterator, getElementLoci, markElement } from './util/el import { computeMarchingCubesMesh } from '../../../util/marching-cubes/algorithm'; import { GaussianDensityProps, GaussianDensityParams } from 'mol-model/structure/structure/unit/gaussian-density'; import { paramDefaultValues } from 'mol-view/parameter'; -import { SizeTheme } from 'mol-view/theme/size'; -import { OrderedSet } from 'mol-data/int'; async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, mesh?: Mesh): Promise<Mesh> { - const { smoothness, radiusOffset } = props + const { smoothness } = props const { transform, field, idField } = await unit.computeGaussianDensity(props, ctx) const params = { @@ -28,46 +26,6 @@ async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, struct const surface = await computeMarchingCubesMesh(params, mesh).runAsChild(ctx) Mesh.transformImmediate(surface, transform) - - // if (props.useGpu) { - // console.time('find max element radius') - // const { elements } = unit - // const n = OrderedSet.size(elements) - // const l = StructureElement.create(unit) - // const sizeTheme = SizeTheme({ name: 'physical' }) - // const radius = (index: number) => { - // l.element = index as ElementIndex - // return sizeTheme.size(l) - // } - // let maxRadius = 0 - // for (let i = 0; i < n; ++i) { - // const r = radius(OrderedSet.getAt(elements, i)) + radiusOffset - // if (maxRadius < r) maxRadius = r - // } - // console.timeEnd('find max element radius') - - // console.time('find closest element for vertices') - // const { lookup3d } = unit - - // const { vertexCount, vertexBuffer, groupBuffer } = surface - // const vertices = vertexBuffer.ref.value - // const groups = groupBuffer.ref.value - // for (let i = 0; i < vertexCount; ++i) { - // const r = lookup3d.find(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2], maxRadius * 2) - // let minDsq = Infinity - // let group = 0 - // for (let j = 0, jl = r.count; j < jl; ++j) { - // const dSq = r.squaredDistances[j] - // if (dSq < minDsq) { - // minDsq = dSq - // group = r.indices[j] - // } - // } - // groups[i] = group - // } - // console.timeEnd('find closest element for vertices') - // } - Mesh.computeNormalsImmediate(surface) Mesh.uniformTriangleGroup(surface) diff --git a/src/mol-geo/representation/structure/visual/util/common.ts b/src/mol-geo/representation/structure/visual/util/common.ts index ef59fe0f3..f4784ed42 100644 --- a/src/mol-geo/representation/structure/visual/util/common.ts +++ b/src/mol-geo/representation/structure/visual/util/common.ts @@ -73,10 +73,9 @@ export async function createUnitsLinesRenderObject(ctx: RuntimeContext, group: U type StructureDirectVolumeProps = DirectVolume2d.Props & DirectVolume3d.Props & StructureProps export async function createUnitsDirectVolumeRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, directVolume: DirectVolume2d | DirectVolume3d, locationIt: LocationIterator, props: StructureDirectVolumeProps) { - // TODO transform support - // const transform = createUnitsTransform(group) + const transform = createUnitsTransform(group) const state = createRenderableState(props) return directVolume.kind === 'direct-volume-2d' ? - createDirectVolume2dRenderObject(await DirectVolume2d.createValues(ctx, directVolume, props), state) : - createDirectVolume3dRenderObject(await DirectVolume3d.createValues(ctx, directVolume, props), state) + createDirectVolume2dRenderObject(await DirectVolume2d.createValues(ctx, directVolume, transform, locationIt, props), state) : + createDirectVolume3dRenderObject(await DirectVolume3d.createValues(ctx, directVolume, transform, locationIt, props), state) } \ No newline at end of file diff --git a/src/mol-geo/representation/volume/direct-volume.ts b/src/mol-geo/representation/volume/direct-volume.ts index 8e5eaecdf..2a70a4ba9 100644 --- a/src/mol-geo/representation/volume/direct-volume.ts +++ b/src/mol-geo/representation/volume/direct-volume.ts @@ -19,6 +19,9 @@ import { Box3D } from 'mol-math/geometry'; import { Context } from 'mol-gl/webgl/context'; import { DirectVolume3dValues, DirectVolume2dValues } from 'mol-gl/renderable/direct-volume'; import { createTexture } from 'mol-gl/webgl/texture'; +import { LocationIterator } from 'mol-geo/util/location-iterator'; +import { NullLocation } from 'mol-model/location'; +import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; function getBoundingBox(gridDimension: Vec3, transform: Mat4) { const bbox = Box3D.empty() @@ -160,15 +163,17 @@ export function DirectVolumeVisual(): VolumeVisual<DirectVolumeProps> { } const state = createRenderableState(currentProps) + const locationIt = LocationIterator(1, 1, () => NullLocation) + const transform = createIdentityTransform() if (webgl.isWebGL2) { console.log('creating 3d volume') directVolume = await createDirectVolume3d(ctx, webgl, volume, directVolume as DirectVolume3d) - const values = await DirectVolume3d.createValues(ctx, directVolume as DirectVolume3d, currentProps) + const values = await DirectVolume3d.createValues(ctx, directVolume as DirectVolume3d, transform, locationIt, currentProps) renderObject = createDirectVolume3dRenderObject(values, state) } else { directVolume = await createDirectVolume2d(ctx, webgl, volume, directVolume as DirectVolume2d) - const values = await DirectVolume2d.createValues(ctx, directVolume as DirectVolume2d, currentProps) + const values = await DirectVolume2d.createValues(ctx, directVolume as DirectVolume2d, transform, locationIt, currentProps) renderObject = createDirectVolume2dRenderObject(values, state) } } diff --git a/src/mol-gl/renderable/direct-volume.ts b/src/mol-gl/renderable/direct-volume.ts index 356ad888e..2f043942b 100644 --- a/src/mol-gl/renderable/direct-volume.ts +++ b/src/mol-gl/renderable/direct-volume.ts @@ -12,6 +12,21 @@ import { DirectVolumeShaderCode } from '../shader-code'; import { ValueCell } from 'mol-util'; export const DirectVolumeBaseSchema = { + aColor: AttributeSpec('float32', 3, 0), // TODO not used, just for type checking + uColor: UniformSpec('v3'), + uColorTexDim: UniformSpec('v2'), + tColor: TextureSpec('image-uint8', 'rgb', 'ubyte', 'nearest'), + dColorType: DefineSpec('string', ['uniform', 'instance', 'group', 'group_instance']), + + uMarkerTexDim: UniformSpec('v2'), + tMarker: TextureSpec('image-uint8', 'alpha', 'ubyte', 'nearest'), + + uInstanceCount: UniformSpec('i'), + uGroupCount: UniformSpec('i'), + + aInstance: AttributeSpec('float32', 1, 1), + aTransform: AttributeSpec('float32', 16, 1), + drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index 1c25d2ab4..42a09454e 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -59,7 +59,7 @@ export function splitValues(schema: RenderableSchema, values: RenderableValues) const defineValues: DefineValues = {} const textureValues: TextureValues = {} const uniformValues: UniformValues = {} - Object.keys(values).forEach(k => { + Object.keys(schema).forEach(k => { if (schema[k].type === 'attribute') attributeValues[k] = values[k] if (schema[k].type === 'define') defineValues[k] = values[k] if (schema[k].type === 'texture') textureValues[k] = values[k] diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl b/src/mol-gl/shader/chunks/assign-color-varying.glsl index b946c1025..ad039eff1 100644 --- a/src/mol-gl/shader/chunks/assign-color-varying.glsl +++ b/src/mol-gl/shader/chunks/assign-color-varying.glsl @@ -7,9 +7,9 @@ #elif defined(dColorType_groupInstance) vColor.rgb = readFromTexture(tColor, aInstance * float(uGroupCount) + aGroup, uColorTexDim).rgb; #elif defined(dColorType_objectPicking) - vColor = encodeIdRGBA(float(uObjectId)); + vColor = vec4(encodeIdRGB(float(uObjectId)), 1.0); #elif defined(dColorType_instancePicking) - vColor = encodeIdRGBA(aInstance); + vColor = vec4(encodeIdRGB(aInstance), 1.0); #elif defined(dColorType_groupPicking) - vColor = encodeIdRGBA(aGroup); + vColor = vec4(encodeIdRGB(aGroup), 1.0); #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl b/src/mol-gl/shader/chunks/color-vert-params.glsl index 63318ea3c..f34e13df4 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl @@ -9,5 +9,5 @@ uniform sampler2D tColor; #elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) varying vec4 vColor; - #pragma glslify: encodeIdRGBA = require(../utils/encode-id-rgba.glsl) + #pragma glslify: encodeIdRGB = require(../utils/encode-id-rgb.glsl) #endif \ No newline at end of file diff --git a/src/mol-gl/shader/direct-volume.frag b/src/mol-gl/shader/direct-volume.frag index 96df2263e..eac50188c 100644 --- a/src/mol-gl/shader/direct-volume.frag +++ b/src/mol-gl/shader/direct-volume.frag @@ -9,6 +9,7 @@ precision highp float; varying vec3 unitCoord; varying vec3 origPos; +varying float instance; uniform float uAlpha; uniform mat4 uInvView; @@ -16,6 +17,15 @@ uniform float uIsoValue; uniform vec3 uGridDim; uniform sampler2D tTransferTex; +uniform int uObjectId; +uniform int uInstanceCount; +uniform int uGroupCount; + +uniform vec3 uHighlightColor; +uniform vec3 uSelectColor; +uniform vec2 uMarkerTexDim; +uniform sampler2D tMarker; + #if defined(dGridTexType_2d) precision mediump sampler2D; uniform sampler2D tGridTex; @@ -25,35 +35,34 @@ uniform sampler2D tTransferTex; uniform sampler3D tGridTex; #endif -#if defined(dGridTexType_2d) - // TODO workaround due to some kind of GPU bug - float myMod(float a, float b) { - return a - b * float(int(a) / int(b)); - } - float myDiv(float a, float b) { - return float(int(a) / int(b)); - } +#if defined(dColorType_uniform) + uniform vec3 uColor; +#elif defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) + uniform vec2 uColorTexDim; + uniform sampler2D tColor; +#endif + +#pragma glslify: readFromTexture = require(./utils/read-from-texture.glsl) +#pragma glslify: encodeIdRGB = require(./utils/encode-id-rgb.glsl) +#pragma glslify: decodeIdRGB = require(./utils/decode-id-rgb.glsl) +#pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl) +#pragma glslify: texture3dFrom2dLinear = require(./utils/texture3d-from-2d-linear.glsl) +#if defined(dGridTexType_2d) vec4 textureVal(vec3 pos) { - float zSlice0 = floor(pos.z * uGridDim.z); - float column0 = myMod(zSlice0 * uGridDim.x, uGridTexDim.x) / uGridDim.x; - float row0 = floor(myDiv(zSlice0 * uGridDim.x, uGridTexDim.x)); - vec2 coord0 = (vec2(column0 * uGridDim.x, row0 * uGridDim.y) + (pos.xy * uGridDim.xy)) / uGridTexDim; - vec4 color0 = texture2D(tGridTex, coord0); - - float zSlice1 = zSlice0 + 1.0; - float column1 = myMod(zSlice1 * uGridDim.x, uGridTexDim.x) / uGridDim.x; - float row1 = floor(myDiv(zSlice1 * uGridDim.x, uGridTexDim.x)); - vec2 coord1 = (vec2(column1 * uGridDim.x, row1 * uGridDim.y) + (pos.xy * uGridDim.xy)) / uGridTexDim; - vec4 color1 = texture2D(tGridTex, coord1); - - float delta0 = abs((pos.z * uGridDim.z) - zSlice0); - return mix(color0, color1, delta0); + return texture3dFrom2dLinear(tGridTex, pos, uGridDim, uGridTexDim); + } + vec4 textureGroup(vec3 pos) { + vec3 nearestPos = floor(pos * uGridDim + 0.5) / uGridDim + 0.5 / uGridDim; + return texture3dFrom2dNearest(tGridTex, nearestPos, uGridDim, uGridTexDim); } #elif defined(dGridTexType_3d) vec4 textureVal(vec3 pos) { return texture(tGridTex, pos); } + vec4 textureGroup(vec3 pos) { + return texelFetch(tGridTex, ivec3(pos * uGridDim), 0); + } #endif vec4 transferFunction(float value) { @@ -61,7 +70,6 @@ vec4 transferFunction(float value) { } const float gradOffset = 0.5; -const vec3 color = vec3(0.45, 0.55, 0.8); vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) { vec3 scaleVol = vec3(1.0) / uGridDim; @@ -75,6 +83,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) { vec3 isoPos; float tmp; + vec3 color = vec3(0.45, 0.55, 0.8); vec3 gradient = vec3(1.0); vec3 dx = vec3(gradOffset * scaleVol.x, 0.0, 0.0); vec3 dy = vec3(0.0, gradOffset * scaleVol.y, 0.0); @@ -100,28 +109,47 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) { tmp = ((prevValue - uIsoValue) / ((prevValue - uIsoValue) - (value - uIsoValue))); isoPos = mix(pos - step, pos, tmp); - // compute gradient by central differences - gradient.x = textureVal(isoPos - dx).a - textureVal(isoPos + dx).a; - gradient.y = textureVal(isoPos - dy).a - textureVal(isoPos + dy).a; - gradient.z = textureVal(isoPos - dz).a - textureVal(isoPos + dz).a; - gradient = normalize(gradient); - - float d = float(dot(gradient, viewDir) > 0.0); - gradient = (2.0 * d - 1.0) * gradient; - - src.rgb = color.rgb * abs(dot(gradient, viewDir)); - src.a = uAlpha; - - // draw interior darker - if( (prevValue - uIsoValue) > 0.0 ) { - src.rgb *= 0.5; - } - - src.rgb *= src.a; - dst = (1.0 - dst.a) * src + dst; // standard blending - if(dst.a >= 1.0) { - break; - } + #if defined(dColorType_objectPicking) + return vec4(encodeIdRGB(float(uObjectId)), 1.0); + #elif defined(dColorType_instancePicking) + return vec4(encodeIdRGB(instance), 1.0); + #elif defined(dColorType_groupPicking) + float group = floor(decodeIdRGB(textureGroup(isoPos).rgb) + 0.5); + return vec4(encodeIdRGB(group), 1.0); + #else + // compute gradient by central differences + gradient.x = textureVal(isoPos - dx).a - textureVal(isoPos + dx).a; + gradient.y = textureVal(isoPos - dy).a - textureVal(isoPos + dy).a; + gradient.z = textureVal(isoPos - dz).a - textureVal(isoPos + dz).a; + gradient = normalize(gradient); + + float d = float(dot(gradient, viewDir) > 0.0); + gradient = (2.0 * d - 1.0) * gradient; + + #if defined(dColorType_instance) + color = readFromTexture(tColor, instance, uColorTexDim).rgb; + #elif defined(dColorType_group) + float group = floor(decodeIdRGB(textureGroup(isoPos).rgb) + 0.5); + color = readFromTexture(tColor, group, uColorTexDim).rgb; + #elif defined(dColorType_groupInstance) + float group = floor(decodeIdRGB(textureGroup(isoPos).rgb) + 0.5); + color = readFromTexture(tColor, instance * float(uGroupCount) + group, uColorTexDim).rgb; + #endif + + src.rgb = color * abs(dot(gradient, viewDir)); + src.a = uAlpha; + + // draw interior darker + if( (prevValue - uIsoValue) > 0.0 ) { + src.rgb *= 0.5; + } + + src.rgb *= src.a; + dst = (1.0 - dst.a) * src + dst; // standard blending + if(dst.a >= 1.0) { + break; + } + #endif } prevValue = value; #endif diff --git a/src/mol-gl/shader/direct-volume.vert b/src/mol-gl/shader/direct-volume.vert index 7ab9edae8..248ddcaeb 100644 --- a/src/mol-gl/shader/direct-volume.vert +++ b/src/mol-gl/shader/direct-volume.vert @@ -8,9 +8,12 @@ precision highp float; attribute vec3 aPosition; +attribute mat4 aTransform; +attribute float aInstance; varying vec3 unitCoord; varying vec3 origPos; +varying float instance; uniform vec3 uBboxSize; uniform vec3 uBboxMin; @@ -23,5 +26,6 @@ void main() { unitCoord = aPosition + vec3(0.5); vec4 mvPosition = uModelView * vec4(unitCoord * uBboxSize + uBboxMin, 1.0); origPos = unitCoord * uBboxSize + uBboxMin; + instance = aInstance; gl_Position = uProjection * mvPosition; } \ No newline at end of file diff --git a/src/mol-gl/shader/gaussian-density.frag b/src/mol-gl/shader/gaussian-density.frag index dbb5e67b1..acb34cd16 100644 --- a/src/mol-gl/shader/gaussian-density.frag +++ b/src/mol-gl/shader/gaussian-density.frag @@ -21,7 +21,7 @@ varying float vRadius; varying float vGroup; #endif -#pragma glslify: encodeIdRGBA = require(./utils/encode-id-rgba.glsl) +#pragma glslify: encodeIdRGB = require(./utils/encode-id-rgb.glsl) #pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl) uniform vec3 uBboxSize; @@ -66,6 +66,6 @@ void main() { float minDistance = decodeDistLog(1.0 - textureMinDist(fragPos).a); if (dist > minDistance + length(uBboxSize / uGridDim) / 1.5) discard; - gl_FragColor = encodeIdRGBA(vGroup); + gl_FragColor.rgb = encodeIdRGB(vGroup); #endif } \ No newline at end of file diff --git a/src/mol-gl/shader/utils/decode-float-rgb.glsl b/src/mol-gl/shader/utils/decode-float-rgb.glsl new file mode 100644 index 000000000..60a586e28 --- /dev/null +++ b/src/mol-gl/shader/utils/decode-float-rgb.glsl @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +float decodeFloatRGB(const in vec3 rgb) { + return rgb.r * 256.0 * 256.0 * 255.0 + rgb.g * 256.0 * 255.0 + rgb.b * 255.0; +} + +#pragma glslify: export(decodeFloatRGB) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/decode-float-rgba.glsl b/src/mol-gl/shader/utils/decode-float-rgba.glsl deleted file mode 100644 index 9948ffcfe..000000000 --- a/src/mol-gl/shader/utils/decode-float-rgba.glsl +++ /dev/null @@ -1,5 +0,0 @@ -float decodeFloatRGBA(const in vec4 rgba) { - return dot(rgba, vec4(1.0, 1.0/255.0, 1.0/65025.0, 1.0/16581375.0)); -} - -#pragma glslify: export(decodeFloatRGBA) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/decode-id-rgb.glsl b/src/mol-gl/shader/utils/decode-id-rgb.glsl new file mode 100644 index 000000000..1a4789e49 --- /dev/null +++ b/src/mol-gl/shader/utils/decode-id-rgb.glsl @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +#pragma glslify: decodeFloatRGB = require(../utils/decode-float-rgb.glsl) + +float decodeIdRGB(const in vec3 v) { + return decodeFloatRGB(v) - 1.0; +} + +#pragma glslify: export(decodeIdRGB) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/encode-float-rgb.glsl b/src/mol-gl/shader/utils/encode-float-rgb.glsl new file mode 100644 index 000000000..1cecbf759 --- /dev/null +++ b/src/mol-gl/shader/utils/encode-float-rgb.glsl @@ -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> + */ + +// TODO use myMod and myDiv to fix issues with picking? + +vec3 encodeFloatRGB(in float value) { + value = clamp(value, 0.0, 16777216.0); + vec3 c = vec3(0.0); + c.b = mod(value, 256.0); + value = floor(value / 256.0); + c.g = mod(value, 256.0); + value = floor(value / 256.0); + c.r = mod(value, 256.0); + return c / 255.0; +} + +#pragma glslify: export(encodeFloatRGB) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/encode-float-rgba.glsl b/src/mol-gl/shader/utils/encode-float-rgba.glsl deleted file mode 100644 index fe67ca0d8..000000000 --- a/src/mol-gl/shader/utils/encode-float-rgba.glsl +++ /dev/null @@ -1,12 +0,0 @@ -vec4 encodeFloatRGBA(in float value) { - value = clamp(value, 0., 16777216.); - vec3 c = vec3(0.); - c.b = mod(value, 256.); - value = floor(value/256.); - c.g = mod(value, 256.); - value = floor(value/256.); - c.r = mod(value, 256.); - return vec4(c/255., 1.); -} - -#pragma glslify: export(encodeFloatRGBA) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/encode-id-rgb.glsl b/src/mol-gl/shader/utils/encode-id-rgb.glsl new file mode 100644 index 000000000..5dd156c09 --- /dev/null +++ b/src/mol-gl/shader/utils/encode-id-rgb.glsl @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +#pragma glslify: encodeFloatRGB = require(../utils/encode-float-rgb.glsl) + +vec3 encodeIdRGB(const in float v) { + return encodeFloatRGB(v + 1.0); +} + +#pragma glslify: export(encodeIdRGB) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/encode-id-rgba.glsl b/src/mol-gl/shader/utils/encode-id-rgba.glsl deleted file mode 100644 index b487be72f..000000000 --- a/src/mol-gl/shader/utils/encode-id-rgba.glsl +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -#pragma glslify: encodeFloatRGBA = require(../utils/encode-float-rgba.glsl) - -vec4 encodeIdRGBA(const in float v) { - return encodeFloatRGBA(v + 1.0); -} - -#pragma glslify: export(encodeIdRGBA) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/my-div.glsl b/src/mol-gl/shader/utils/my-div.glsl deleted file mode 100644 index 49c461894..000000000 --- a/src/mol-gl/shader/utils/my-div.glsl +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - * @author Michael Krone <michael.krone@uni-tuebingen.de> - */ - -// TODO workaround due to some kind of GPU quirk -float myDiv(float a, float b) { - return float(int(a) / int(b)); -} - -#pragma glslify: export(myDiv) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/my-mod.glsl b/src/mol-gl/shader/utils/my-mod.glsl deleted file mode 100644 index 3030ff3f1..000000000 --- a/src/mol-gl/shader/utils/my-mod.glsl +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2017-2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - * @author Michael Krone <michael.krone@uni-tuebingen.de> - */ - -// TODO workaround due to some kind of GPU quirk -float myMod(float a, float b) { - return a - b * float(int(a) / int(b)); -} - -#pragma glslify: export(myMod) \ No newline at end of file diff --git a/src/mol-gl/shader/utils/texture3d-from-2d-linear.glsl b/src/mol-gl/shader/utils/texture3d-from-2d-linear.glsl index 5b8fca4f0..af7893849 100644 --- a/src/mol-gl/shader/utils/texture3d-from-2d-linear.glsl +++ b/src/mol-gl/shader/utils/texture3d-from-2d-linear.glsl @@ -5,8 +5,9 @@ * @author Michael Krone <michael.krone@uni-tuebingen.de> */ -#pragma glslify: myMod = require(./my-mod.glsl) -#pragma glslify: myDiv = require(./my-div.glsl) +// TODO workaround due to some kind of GPU quirk +float myMod(float a, float b) { return a - b * float(int(a) / int(b)); } +float myDiv(float a, float b) { return float(int(a) / int(b)); } vec4 texture3dFrom2dLinear(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim) { float zSlice0 = floor(pos.z * gridDim.z); diff --git a/src/mol-gl/shader/utils/texture3d-from-2d-nearest.glsl b/src/mol-gl/shader/utils/texture3d-from-2d-nearest.glsl index 9cf714cd6..305312cd1 100644 --- a/src/mol-gl/shader/utils/texture3d-from-2d-nearest.glsl +++ b/src/mol-gl/shader/utils/texture3d-from-2d-nearest.glsl @@ -5,8 +5,9 @@ * @author Michael Krone <michael.krone@uni-tuebingen.de> */ -#pragma glslify: myMod = require(./my-mod.glsl) -#pragma glslify: myDiv = require(./my-div.glsl) +// TODO workaround due to some kind of GPU quirk +float myMod(float a, float b) { return a - b * float(int(a) / int(b)); } +float myDiv(float a, float b) { return float(int(a) / int(b)); } vec4 texture3dFrom2dNearest(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim) { float zSlice = floor(pos.z * gridDim.z + 0.5); // round to nearest z-slice diff --git a/src/mol-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 233ce9aa6..682699cb2 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -19,7 +19,7 @@ import { Context, createContext, getGLContext } from 'mol-gl/webgl/context'; import { createFramebuffer } from 'mol-gl/webgl/framebuffer'; import { createTexture, Texture } from 'mol-gl/webgl/texture'; import { GLRenderingContext } from 'mol-gl/webgl/compat'; -import { decodeIdRGBA } from 'mol-geo/geometry/picking'; +import { decodeIdRGB } from 'mol-geo/geometry/picking'; export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> { const webgl = defaults(props.webgl, getWebGLContext()) @@ -344,7 +344,7 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { for (let ix = 0; ix < dx; ++ix) { const idx = 4 * (tmpCol * dx + (iy + tmpRow) * width + ix) data[j] = image[idx + 3] / 255 - idData[j] = decodeIdRGBA(image[idx], image[idx + 1], image[idx + 2]) + idData[j] = decodeIdRGB(image[idx], image[idx + 1], image[idx + 2]) j++ } } @@ -381,7 +381,7 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { // for (let ix = 0; ix < width; ++ix) { // const idx = 4 * (iy * width + ix) // data[j] = slice[idx + 3] / 255 -// idData[j] = decodeIdRGBA(slice[idx], slice[idx + 1], slice[idx + 2]) +// idData[j] = decodeIdRGB(slice[idx], slice[idx + 1], slice[idx + 2]) // ++j // } // } diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index 7d092a837..aab76b56f 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -21,7 +21,7 @@ import { Representation } from 'mol-geo/representation'; import { createRenderTarget } from 'mol-gl/webgl/render-target'; import Scene from 'mol-gl/scene'; import { RenderVariant } from 'mol-gl/webgl/render-item'; -import { PickingId, decodeIdRGBA } from 'mol-geo/geometry/picking'; +import { PickingId, decodeIdRGB } from 'mol-geo/geometry/picking'; import { MarkerAction } from 'mol-geo/geometry/marker-data'; import { Loci, EmptyLoci, isEmptyLoci } from 'mol-model/loci'; import { Color } from 'mol-util/color'; @@ -231,15 +231,15 @@ namespace Viewer { objectPickTarget.bind() ctx.readPixels(xp, yp, 1, 1, buffer) - const objectId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) + const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) instancePickTarget.bind() ctx.readPixels(xp, yp, 1, 1, buffer) - const instanceId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) + const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) groupPickTarget.bind() ctx.readPixels(xp, yp, 1, 1, buffer) - const groupId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) + const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) isPicking = false -- GitLab