diff --git a/src/mol-canvas3d/canvas3d.ts b/src/mol-canvas3d/canvas3d.ts index 7f525ab85908c6cf9779042aa3b6141bd67ae995..814503272e6f6c3da610e6a438bb32c977a343a6 100644 --- a/src/mol-canvas3d/canvas3d.ts +++ b/src/mol-canvas3d/canvas3d.ts @@ -21,13 +21,14 @@ import { Representation } from 'mol-repr/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, decodeIdRGB } from 'mol-geo/geometry/picking'; +import { PickingId } 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'; import { Camera } from './camera'; import { ParamDefinition as PD } from 'mol-util/param-definition'; import { BoundingSphereHelper, DebugHelperParams } from './helper/bounding-sphere-helper'; +import { decodeFloatRGB } from 'mol-util/float-packing'; export const Canvas3DParams = { // TODO: FPS cap? @@ -276,19 +277,19 @@ namespace Canvas3D { // TODO slow in Chrome, ok in FF; doesn't play well with gpu surface calc // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) - const objectId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + const objectId = decodeFloatRGB(buffer[0], buffer[1], buffer[2]) if (objectId === -1) { isIdentifying = false; return; } instancePickTarget.bind() // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) - const instanceId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + const instanceId = decodeFloatRGB(buffer[0], buffer[1], buffer[2]) if (instanceId === -1) { isIdentifying = false; return; } groupPickTarget.bind() // await webgl.readPixelsAsync(xp, yp, 1, 1, buffer) webgl.readPixels(xp, yp, 1, 1, buffer) - const groupId = decodeIdRGB(buffer[0], buffer[1], buffer[2]) + const groupId = decodeFloatRGB(buffer[0], buffer[1], buffer[2]) if (groupId === -1) { isIdentifying = false; return; } isIdentifying = false diff --git a/src/mol-geo/geometry/picking.ts b/src/mol-geo/geometry/picking.ts index a42ae76ee567993c03282a46a6fd7ed4237edd04..8ae9b751027a9b55470721ca58a0d665ff67bb26 100644 --- a/src/mol-geo/geometry/picking.ts +++ b/src/mol-geo/geometry/picking.ts @@ -4,17 +4,6 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -function decodeFloatRGBA(r: number, g: number, b: number) { - r = Math.floor(r) - g = Math.floor(g) - b = Math.floor(b) - return r * 256 * 256 + g * 256 + b -} - -export function decodeIdRGB(r: number, g: number, b: number) { - return decodeFloatRGBA(r, g, b) - 1 -} - export interface PickingId { objectId: number instanceId: number diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl b/src/mol-gl/shader/chunks/assign-color-varying.glsl index ad039eff1f54327427a3b9267b8b092ac095ba9a..e2e7e150af8b051086c3a1827e717e7a074588b4 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 = vec4(encodeIdRGB(float(uObjectId)), 1.0); + vColor = vec4(encodeFloatRGB(float(uObjectId)), 1.0); #elif defined(dColorType_instancePicking) - vColor = vec4(encodeIdRGB(aInstance), 1.0); + vColor = vec4(encodeFloatRGB(aInstance), 1.0); #elif defined(dColorType_groupPicking) - vColor = vec4(encodeIdRGB(aGroup), 1.0); + vColor = vec4(encodeFloatRGB(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 f34e13df4cd569f7de08fcb7daff7350bf97d8ee..abc149ebdcf64187d4989f048a7b3651639846e7 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: encodeIdRGB = require(../utils/encode-id-rgb.glsl) + #pragma glslify: encodeFloatRGB = require(../utils/encode-float-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 de8f74643629d2ba0c7a66e900580f5d9ae9789e..5728c6c41b3e1a0239a305f38024d3034775e604 100644 --- a/src/mol-gl/shader/direct-volume.frag +++ b/src/mol-gl/shader/direct-volume.frag @@ -47,8 +47,8 @@ uniform int uPickable; #pragma glslify: import('./chunks/common.glsl') #pragma glslify: readFromTexture = require(./utils/read-from-texture.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify -#pragma glslify: encodeIdRGB = require(./utils/encode-id-rgb.glsl) -#pragma glslify: decodeIdRGB = require(./utils/decode-id-rgb.glsl) +#pragma glslify: encodeFloatRGB = require(./utils/encode-float-rgb.glsl) +#pragma glslify: decodeFloatRGB = require(./utils/decode-float-rgb.glsl) #pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify #pragma glslify: texture3dFrom2dLinear = require(./utils/texture3d-from-2d-linear.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify @@ -135,12 +135,12 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) { #endif #if defined(dColorType_objectPicking) - return vec4(encodeIdRGB(float(uObjectId)), 1.0); + return vec4(encodeFloatRGB(float(uObjectId)), 1.0); #elif defined(dColorType_instancePicking) - return vec4(encodeIdRGB(instance), 1.0); + return vec4(encodeFloatRGB(instance), 1.0); #elif defined(dColorType_groupPicking) - float group = floor(decodeIdRGB(textureGroup(isoPos).rgb) + 0.5); - return vec4(encodeIdRGB(group), 1.0); + float group = floor(decodeFloatRGB(textureGroup(isoPos).rgb) + 0.5); + return vec4(encodeFloatRGB(group), 1.0); #else // compute gradient by central differences gradient.x = textureVal(isoPos - dx).a - textureVal(isoPos + dx).a; @@ -150,7 +150,7 @@ vec4 raymarch(vec3 startLoc, vec3 step, vec3 viewDir) { float d = float(dot(gradient, viewDir) > 0.0); gradient = (2.0 * d - 1.0) * gradient; - float group = floor(decodeIdRGB(textureGroup(isoPos).rgb) + 0.5); + float group = floor(decodeFloatRGB(textureGroup(isoPos).rgb) + 0.5); #if defined(dColorType_instance) color = readFromTexture(tColor, instance, uColorTexDim).rgb; diff --git a/src/mol-gl/shader/gaussian-density.frag b/src/mol-gl/shader/gaussian-density.frag index 137c2189100d4c1ba4c070e189cc10de0f0a5dbe..652e87891b45aa5e4a4bbafb8a5d654926acfe57 100644 --- a/src/mol-gl/shader/gaussian-density.frag +++ b/src/mol-gl/shader/gaussian-density.frag @@ -22,7 +22,9 @@ varying float vRadius; #endif #pragma glslify: import('./chunks/common.glsl') -#pragma glslify: encodeIdRGB = require(./utils/encode-id-rgb.glsl) +#pragma glslify: encodeFloatLog = require(./utils/encode-float-log.glsl) +#pragma glslify: decodeFloatLog = require(./utils/decode-float-log.glsl) +#pragma glslify: encodeFloatRGB = require(./utils/encode-float-rgb.glsl) #pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl, intMod=intMod, intDiv=intDiv, foo=foo) // foo=foo is a workaround for a bug in glslify uniform vec3 uBboxSize; @@ -46,12 +48,6 @@ uniform float uAlpha; #endif #endif -// encode distance logarithmically with given maxDistance -const float maxDistance = 10000.0; -const float distLogFactor = log(maxDistance + 1.0); -float encodeDistLog(float dist) { return log(dist + 1.0) / distLogFactor; } -float decodeDistLog(float logDist) { return exp(logDist * distLogFactor) - 1.0; } - void main() { vec2 v = gl_FragCoord.xy - vec2(uCurrentX, uCurrentY) - 0.5; vec3 fragPos = vec3(v.x, v.y, uCurrentSlice) / uGridDim; @@ -62,13 +58,13 @@ void main() { float density = exp(-uAlpha * ((dist * dist) / radiusSq)); gl_FragColor = vec4(density); #elif defined(dCalcType_minDistance) - gl_FragColor.a = 1.0 - encodeDistLog(dist); + gl_FragColor.a = 1.0 - encodeFloatLog(dist); #elif defined(dCalcType_groupId) - float minDistance = decodeDistLog(1.0 - textureMinDist(fragPos).a); + float minDistance = decodeFloatLog(1.0 - textureMinDist(fragPos).a); // TODO verify `length(uBboxSize / uGridDim) * 2.0` // on some machines `* 2.0` is needed while on others `* 0.5` works if (dist > minDistance + length(uBboxSize / uGridDim) * 0.5) discard; - gl_FragColor.rgb = encodeIdRGB(vGroup); + gl_FragColor.rgb = encodeFloatRGB(vGroup); #endif } \ No newline at end of file diff --git a/src/mol-gl/shader/utils/decode-float-log.glsl b/src/mol-gl/shader/utils/decode-float-log.glsl new file mode 100644 index 0000000000000000000000000000000000000000..eee87721cf8c76d953394ec02e9bfc340c1bc841 --- /dev/null +++ b/src/mol-gl/shader/utils/decode-float-log.glsl @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +const float maxFloat = 10000.0; // NOTE constant also set in in encodeFloatLog and in TypeScript +const float floatLogFactor = log(maxFloat + 1.0); +float decodeFloatLog(in float value) { return exp(value * floatLogFactor) - 1.0; } + +#pragma glslify: export(decodeFloatLog) \ 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 index 60a586e2865b11b21dd2857d5ddc3936975f2c3a..a0367ea32cc5ff4164b1e0282ad69978bafa0015 100644 --- a/src/mol-gl/shader/utils/decode-float-rgb.glsl +++ b/src/mol-gl/shader/utils/decode-float-rgb.glsl @@ -5,7 +5,7 @@ */ 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; + return (rgb.r * 256.0 * 256.0 * 255.0 + rgb.g * 256.0 * 255.0 + rgb.b * 255.0) - 1.0; } #pragma glslify: export(decodeFloatRGB) \ 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 deleted file mode 100644 index 1a4789e496505cf27c94d0086f1f928f6a58d1fd..0000000000000000000000000000000000000000 --- a/src/mol-gl/shader/utils/decode-id-rgb.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: 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-log.glsl b/src/mol-gl/shader/utils/encode-float-log.glsl new file mode 100644 index 0000000000000000000000000000000000000000..908efb7fbe3d536ed43b4f0aa0c584d04cc475bf --- /dev/null +++ b/src/mol-gl/shader/utils/encode-float-log.glsl @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +const float maxFloat = 10000.0; // NOTE constant also set in in decodeFloatLog and in TypeScript +const float floatLogFactor = log(maxFloat + 1.0); +float encodeFloatLog(in float value) { return log(value + 1.0) / floatLogFactor; } + +#pragma glslify: export(encodeFloatLog) \ 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 index 07183663150d825630e63e886432bb0d9f2993c1..69d500fe25216e69cb5d9551ce071cc020504253 100644 --- a/src/mol-gl/shader/utils/encode-float-rgb.glsl +++ b/src/mol-gl/shader/utils/encode-float-rgb.glsl @@ -5,7 +5,7 @@ */ vec3 encodeFloatRGB(in float value) { - value = clamp(value, 0.0, 16777216.0); + value = clamp(value, 0.0, 16777216.0 - 1.0) + 1.0; vec3 c = vec3(0.0); c.b = mod(value, 256.0); value = floor(value / 256.0); diff --git a/src/mol-gl/shader/utils/encode-id-rgb.glsl b/src/mol-gl/shader/utils/encode-id-rgb.glsl deleted file mode 100644 index 5dd156c096e8ebf1506c8764564a61d015ee74e2..0000000000000000000000000000000000000000 --- a/src/mol-gl/shader/utils/encode-id-rgb.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: 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-math/geometry/gaussian-density/gpu.ts b/src/mol-math/geometry/gaussian-density/gpu.ts index 0e2056c7a1bff3474d589199fb22caf3043b5458..fd087282e22a55608965bab8c3160d0914802728 100644 --- a/src/mol-math/geometry/gaussian-density/gpu.ts +++ b/src/mol-math/geometry/gaussian-density/gpu.ts @@ -18,7 +18,7 @@ import { createRenderable, createGaussianDensityRenderObject } from 'mol-gl/rend import { WebGLContext } from 'mol-gl/webgl/context'; import { createTexture, Texture } from 'mol-gl/webgl/texture'; import { GLRenderingContext } from 'mol-gl/webgl/compat'; -import { decodeIdRGB } from 'mol-geo/geometry/picking'; +import { decodeFloatRGB } from 'mol-util/float-packing'; /** name for shared framebuffer used for gpu gaussian surface operations */ const FramebufferName = 'gaussian-density-gpu' @@ -329,7 +329,7 @@ async function fieldFromTexture2d(ctx: WebGLContext, 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] = decodeIdRGB(image[idx], image[idx + 1], image[idx + 2]) + idData[j] = decodeFloatRGB(image[idx], image[idx + 1], image[idx + 2]) j++ } } diff --git a/src/mol-util/float-packing.ts b/src/mol-util/float-packing.ts new file mode 100644 index 0000000000000000000000000000000000000000..42087b10738d71adb4e1913c187cf5fd460b38cf --- /dev/null +++ b/src/mol-util/float-packing.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { clamp } from 'mol-math/interpolate'; + +const maxFloat = 10000.0; // NOTE same constant is set in shaders +const floatLogFactor = Math.log(maxFloat + 1.0); + +/** encode float logarithmically */ +export function encodeFloatLog(value: number) { return Math.log(value + 1.0) / floatLogFactor } + +/** decode logarithmically encoded float */ +export function decodeFloatLog(value: number) { return Math.exp(value * floatLogFactor) - 1.0 } + +/** encode float as rgb triplet */ +export function encodeFloatRGB(value: number) { + value = clamp(value, 0.0, 16777216.0 - 1.0) + 1.0 + const b = (value % 256) / 255.0 + value = Math.floor(value / 256.0) + const g = (value % 256) / 255.0 + value = Math.floor(value / 256.0) + const r = (value % 256) / 255.0 + return [r, g, b] +} + +/** decode float encoded as rgb triplet */ +export function decodeFloatRGB(r: number, g: number, b: number) { + return (Math.floor(r) * 256 * 256 + Math.floor(g) * 256 + Math.floor(b)) - 1 +} \ No newline at end of file