UNPKG

molstar

Version:

A comprehensive macromolecular library.

167 lines 8.41 kB
/** * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ import { createTextureImage } from '../../../mol-gl/renderable/util'; import { Box3D } from '../../../mol-math/geometry'; import { Vec2, Vec3, Vec4 } from '../../../mol-math/linear-algebra'; import { getVolumeTexture2dLayout } from '../../../mol-repr/volume/util'; import { Color } from '../../../mol-util/color'; export function calcMeshColorSmoothing(input, resolution, stride, webgl, texture) { var colorType = input.colorType, vertexCount = input.vertexCount, groupCount = input.groupCount, positionBuffer = input.positionBuffer, transformBuffer = input.transformBuffer, groupBuffer = input.groupBuffer; var isInstanceType = colorType.endsWith('Instance'); var box = Box3D.fromSphere3D(Box3D(), isInstanceType ? input.boundingSphere : input.invariantBoundingSphere); var scaleFactor = 1 / resolution; var scaledBox = Box3D.scale(Box3D(), box, scaleFactor); var gridDim = Box3D.size(Vec3(), scaledBox); Vec3.ceil(gridDim, gridDim); Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2)); var min = box.min; var xn = gridDim[0], yn = gridDim[1]; var _a = getVolumeTexture2dLayout(gridDim), width = _a.width, height = _a.height; // console.log({ width, height, dim }); var itemSize = 3; var data = new Float32Array(width * height * itemSize); var count = new Float32Array(width * height); var grid = new Uint8Array(width * height * itemSize); var textureImage = { array: grid, width: width, height: height, filter: 'linear' }; var instanceCount = isInstanceType ? input.instanceCount : 1; var colors = input.colorData.array; function getIndex(x, y, z) { var column = Math.floor(((z * xn) % width) / xn); var row = Math.floor((z * xn) / width); var px = column * xn + x; return itemSize * ((row * yn * width) + (y * width) + px); } var p = 2; var dimX = gridDim[0], dimY = gridDim[1], dimZ = gridDim[2]; var v = Vec3(); for (var i = 0; i < instanceCount; ++i) { for (var j = 0; j < vertexCount; j += stride) { Vec3.fromArray(v, positionBuffer, j * 3); if (isInstanceType) Vec3.transformMat4Offset(v, v, transformBuffer, 0, 0, i * 16); Vec3.sub(v, v, min); Vec3.scale(v, v, scaleFactor); var vx = v[0], vy = v[1], vz = v[2]; // vertex mapped to grid var x = Math.floor(vx); var y = Math.floor(vy); var z = Math.floor(vz); // group colors var ci = i * groupCount + groupBuffer[j]; var r = colors[ci * 3]; var g = colors[ci * 3 + 1]; var b = colors[ci * 3 + 2]; // Extents of grid to consider for this atom var begX = Math.max(0, x - p); var begY = Math.max(0, y - p); var begZ = Math.max(0, z - p); // Add two to these points: // - x, y, z are floor'd values so this ensures coverage // - these are loop limits (exclusive) var endX = Math.min(dimX, x + p + 2); var endY = Math.min(dimY, y + p + 2); var endZ = Math.min(dimZ, z + p + 2); for (var xi = begX; xi < endX; ++xi) { var dx = xi - vx; for (var yi = begY; yi < endY; ++yi) { var dy = yi - vy; for (var zi = begZ; zi < endZ; ++zi) { var dz = zi - vz; var d = Math.sqrt(dx * dx + dy * dy + dz * dz); if (d > p) continue; var s = p - d; var index = getIndex(xi, yi, zi); data[index] += r * s; data[index + 1] += g * s; data[index + 2] += b * s; count[index / 3] += s; } } } } } for (var i = 0, il = count.length; i < il; ++i) { var i3 = i * 3; var c = count[i]; grid[i3] = Math.round(data[i3] / c); grid[i3 + 1] = Math.round(data[i3 + 1] / c); grid[i3 + 2] = Math.round(data[i3 + 2] / c); } var gridTexDim = Vec2.create(width, height); var gridTransform = Vec4.create(min[0], min[1], min[2], scaleFactor); var type = isInstanceType ? 'volumeInstance' : 'volume'; if (webgl) { if (!texture) texture = webgl.resources.texture('image-uint8', 'rgb', 'ubyte', 'linear'); texture.load(textureImage); return { kind: 'volume', texture: texture, gridTexDim: gridTexDim, gridDim: gridDim, gridTransform: gridTransform, type: type }; } else { var interpolated = getTrilinearlyInterpolated({ vertexCount: vertexCount, instanceCount: instanceCount, transformBuffer: transformBuffer, positionBuffer: positionBuffer, colorType: type, grid: grid, gridDim: gridDim, gridTexDim: gridTexDim, gridTransform: gridTransform, vertexStride: 3, colorStride: 3 }); return { kind: 'vertex', texture: interpolated, texDim: Vec2.create(interpolated.width, interpolated.height), type: isInstanceType ? 'vertexInstance' : 'vertex' }; } } export function getTrilinearlyInterpolated(input) { var vertexCount = input.vertexCount, positionBuffer = input.positionBuffer, transformBuffer = input.transformBuffer, grid = input.grid, gridDim = input.gridDim, gridTexDim = input.gridTexDim, gridTransform = input.gridTransform, vertexStride = input.vertexStride, colorStride = input.colorStride; var isInstanceType = input.colorType.endsWith('Instance'); var instanceCount = isInstanceType ? input.instanceCount : 1; var image = createTextureImage(Math.max(1, instanceCount * vertexCount), 3, Uint8Array); var array = image.array; var xn = gridDim[0], yn = gridDim[1]; var width = gridTexDim[0]; var min = Vec3.fromArray(Vec3(), gridTransform, 0); var scaleFactor = gridTransform[3]; function getIndex(x, y, z) { var column = Math.floor(((z * xn) % width) / xn); var row = Math.floor((z * xn) / width); var px = column * xn + x; return colorStride * ((row * yn * width) + (y * width) + px); } var v = Vec3(); var v0 = Vec3(); var v1 = Vec3(); var vd = Vec3(); for (var i = 0; i < instanceCount; ++i) { for (var j = 0; j < vertexCount; ++j) { Vec3.fromArray(v, positionBuffer, j * vertexStride); if (isInstanceType) Vec3.transformMat4Offset(v, v, transformBuffer, 0, 0, i * 16); Vec3.sub(v, v, min); Vec3.scale(v, v, scaleFactor); Vec3.floor(v0, v); Vec3.ceil(v1, v); Vec3.sub(vd, v, v0); Vec3.sub(v, v1, v0); Vec3.div(vd, vd, v); var x0 = v0[0], y0 = v0[1], z0 = v0[2]; var x1 = v1[0], y1 = v1[1], z1 = v1[2]; var xd = vd[0], yd = vd[1], zd = vd[2]; var s000 = Color.fromArray(grid, getIndex(x0, y0, z0)); var s100 = Color.fromArray(grid, getIndex(x1, y0, z0)); var s001 = Color.fromArray(grid, getIndex(x0, y0, z1)); var s101 = Color.fromArray(grid, getIndex(x1, y0, z1)); var s010 = Color.fromArray(grid, getIndex(x0, y1, z0)); var s110 = Color.fromArray(grid, getIndex(x1, y1, z0)); var s011 = Color.fromArray(grid, getIndex(x0, y1, z1)); var s111 = Color.fromArray(grid, getIndex(x1, y1, z1)); var s00 = Color.interpolate(s000, s100, xd); var s01 = Color.interpolate(s001, s101, xd); var s10 = Color.interpolate(s010, s110, xd); var s11 = Color.interpolate(s011, s111, xd); var s0 = Color.interpolate(s00, s10, yd); var s1 = Color.interpolate(s01, s11, yd); Color.toArray(Color.interpolate(s0, s1, zd), array, (i * vertexCount + j) * 3); } } return image; } //# sourceMappingURL=color-smoothing.js.map