Skip to content
Snippets Groups Projects
Commit d6ffbae8 authored by Alexander Rose's avatar Alexander Rose
Browse files

gaussian density groupid calc for via 2d textures

parent 2f6b2989
No related branches found
No related tags found
No related merge requests found
...@@ -25,9 +25,11 @@ export const GaussianDensitySchema = { ...@@ -25,9 +25,11 @@ export const GaussianDensitySchema = {
uBboxMax: UniformSpec('v3'), uBboxMax: UniformSpec('v3'),
uBboxSize: UniformSpec('v3'), uBboxSize: UniformSpec('v3'),
uGridDim: UniformSpec('v3'), uGridDim: UniformSpec('v3'),
uGridTexDim: UniformSpec('v2'),
uAlpha: UniformSpec('f'), uAlpha: UniformSpec('f'),
tMinDistanceTex: TextureSpec('texture2d', 'rgba', 'ubyte', 'nearest'), tMinDistanceTex: TextureSpec('texture3d', 'rgba', 'ubyte', 'nearest'),
dGridTexType: DefineSpec('string', ['2d', '3d']),
dCalcType: DefineSpec('string', ['density', 'minDistance', 'groupId']), dCalcType: DefineSpec('string', ['density', 'minDistance', 'groupId']),
} }
export type GaussianDensitySchema = typeof GaussianDensitySchema export type GaussianDensitySchema = typeof GaussianDensitySchema
......
...@@ -5,11 +5,6 @@ ...@@ -5,11 +5,6 @@
* @author Michael Krone <michael.krone@uni-tuebingen.de> * @author Michael Krone <michael.krone@uni-tuebingen.de>
*/ */
#if defined(dGridTexType_2d)
precision mediump sampler2D;
#elif defined(dGridTexType_3d)
precision mediump sampler3D;
#endif
precision highp float; precision highp float;
varying vec3 unitCoord; varying vec3 unitCoord;
...@@ -22,9 +17,11 @@ uniform vec3 uGridDim; ...@@ -22,9 +17,11 @@ uniform vec3 uGridDim;
uniform sampler2D tTransferTex; uniform sampler2D tTransferTex;
#if defined(dGridTexType_2d) #if defined(dGridTexType_2d)
precision mediump sampler2D;
uniform sampler2D tGridTex; uniform sampler2D tGridTex;
uniform vec2 uGridTexDim; uniform vec2 uGridTexDim;
#elif defined(dGridTexType_3d) #elif defined(dGridTexType_3d)
precision mediump sampler3D;
uniform sampler3D tGridTex; uniform sampler3D tGridTex;
#endif #endif
......
...@@ -10,12 +10,19 @@ precision highp float; ...@@ -10,12 +10,19 @@ precision highp float;
varying vec3 vPosition; varying vec3 vPosition;
varying float vRadius; varying float vRadius;
#if defined(dCalcType_groupId) #if defined(dCalcType_groupId)
precision highp sampler3D; #if defined(dGridTexType_2d)
uniform sampler3D tMinDistanceTex; precision mediump sampler2D;
uniform sampler2D tMinDistanceTex;
uniform vec2 uGridTexDim;
#elif defined(dGridTexType_3d)
precision highp sampler3D;
uniform sampler3D tMinDistanceTex;
#endif
varying float vGroup; varying float vGroup;
#endif #endif
#pragma glslify: encodeIdRGBA = require(./utils/encode-id-rgba.glsl) #pragma glslify: encodeIdRGBA = require(./utils/encode-id-rgba.glsl)
#pragma glslify: texture3dFrom2dNearest = require(./utils/texture3d-from-2d-nearest.glsl)
uniform vec3 uBboxSize; uniform vec3 uBboxSize;
uniform vec3 uBboxMin; uniform vec3 uBboxMin;
...@@ -26,6 +33,18 @@ uniform float uCurrentX; ...@@ -26,6 +33,18 @@ uniform float uCurrentX;
uniform float uCurrentY; uniform float uCurrentY;
uniform float uAlpha; uniform float uAlpha;
#if defined(dCalcType_groupId)
#if defined(dGridTexType_2d)
vec4 textureMinDist(vec3 pos) {
return texture3dFrom2dNearest(tMinDistanceTex, pos, uGridDim, uGridTexDim);
}
#elif defined(dGridTexType_3d)
vec4 textureMinDist(vec3 pos) {
return texture(tMinDistanceTex, pos);
}
#endif
#endif
// encode distance logarithmically with given maxDistance // encode distance logarithmically with given maxDistance
const float maxDistance = 10000.0; const float maxDistance = 10000.0;
const float distLogFactor = log(maxDistance + 1.0); const float distLogFactor = log(maxDistance + 1.0);
...@@ -42,10 +61,10 @@ void main() { ...@@ -42,10 +61,10 @@ void main() {
float density = exp(-uAlpha * ((dist * dist) / radiusSq)); float density = exp(-uAlpha * ((dist * dist) / radiusSq));
gl_FragColor = vec4(density); gl_FragColor = vec4(density);
#elif defined(dCalcType_minDistance) #elif defined(dCalcType_minDistance)
gl_FragColor.r = 1.0 - encodeDistLog(dist); gl_FragColor.a = 1.0 - encodeDistLog(dist);
#elif defined(dCalcType_groupId) #elif defined(dCalcType_groupId)
float minDistance = decodeDistLog(1.0 - texture(tMinDistanceTex, fragPos).r); float minDistance = decodeDistLog(1.0 - textureMinDist(fragPos).a);
if (dist > minDistance + log(minDistance) / 2.0) if (dist > minDistance + length(uBboxSize / uGridDim) / 1.5)
discard; discard;
gl_FragColor = encodeIdRGBA(vGroup); gl_FragColor = encodeIdRGBA(vGroup);
#endif #endif
......
/**
* 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) #pragma glslify: encodeFloatRGBA = require(../utils/encode-float-rgba.glsl)
vec4 encodeIdRGBA(const in float v) { vec4 encodeIdRGBA(const in float v) {
......
/**
* 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
/**
* 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
/**
* 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>
*/
#pragma glslify: myMod = require(./my-mod.glsl)
#pragma glslify: myDiv = require(./my-div.glsl)
vec4 texture3dFrom2dLinear(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim) {
float zSlice0 = floor(pos.z * gridDim.z);
float column0 = myMod(zSlice0 * gridDim.x, texDim.x) / gridDim.x;
float row0 = floor(myDiv(zSlice0 * gridDim.x, texDim.x));
vec2 coord0 = (vec2(column0 * gridDim.x, row0 * gridDim.y) + (pos.xy * gridDim.xy)) / texDim;
vec4 color0 = texture2D(tex, coord0);
float zSlice1 = zSlice0 + 1.0;
float column1 = myMod(zSlice1 * gridDim.x, texDim.x) / gridDim.x;
float row1 = floor(myDiv(zSlice1 * gridDim.x, texDim.x));
vec2 coord1 = (vec2(column1 * gridDim.x, row1 * gridDim.y) + (pos.xy * gridDim.xy)) / texDim;
vec4 color1 = texture2D(tex, coord1);
float delta0 = abs((pos.z * gridDim.z) - zSlice0);
return mix(color0, color1, delta0);
}
#pragma glslify: export(texture3dFrom2dLinear)
\ No newline at end of file
/**
* 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>
*/
#pragma glslify: myMod = require(./my-mod.glsl)
#pragma glslify: myDiv = require(./my-div.glsl)
vec4 texture3dFrom2dNearest(sampler2D tex, vec3 pos, vec3 gridDim, vec2 texDim) {
float zSlice = floor(pos.z * gridDim.z + 0.5); // round to nearest z-slice
float column = myMod(zSlice * gridDim.x, texDim.x) / gridDim.x;
float row = floor(myDiv(zSlice * gridDim.x, texDim.x));
vec2 coord = (vec2(column * gridDim.x, row * gridDim.y) + (pos.xy * gridDim.xy)) / texDim;
return texture2D(tex, coord);
}
#pragma glslify: export(texture3dFrom2dNearest)
\ No newline at end of file
...@@ -106,4 +106,19 @@ export interface COMPAT_texture_float_linear { ...@@ -106,4 +106,19 @@ export interface COMPAT_texture_float_linear {
export function getTextureFloatLinear(gl: GLRenderingContext): COMPAT_texture_float_linear | null { export function getTextureFloatLinear(gl: GLRenderingContext): COMPAT_texture_float_linear | null {
return gl.getExtension('OES_texture_float_linear') return gl.getExtension('OES_texture_float_linear')
}
export interface COMPAT_blend_minmax {
readonly MIN: number
readonly MAX: number
}
export function getBlendMinMax(gl: GLRenderingContext): COMPAT_blend_minmax | null {
if (isWebGL2(gl)) {
return { MIN: gl.MIN, MAX: gl.MAX }
} else {
const ext = gl.getExtension('EXT_blend_minmax')
if (ext === null) return null
return { MIN: ext.MIN_EXT, MAX: ext.MAX_EXT }
}
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
import { createProgramCache, ProgramCache } from './program' import { createProgramCache, ProgramCache } from './program'
import { createShaderCache, ShaderCache } from './shader' import { createShaderCache, ShaderCache } from './shader'
import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear } from './compat'; import { GLRenderingContext, COMPAT_instanced_arrays, COMPAT_standard_derivatives, COMPAT_vertex_array_object, getInstancedArrays, getStandardDerivatives, getVertexArrayObject, isWebGL2, COMPAT_element_index_uint, getElementIndexUint, COMPAT_texture_float, getTextureFloat, COMPAT_texture_float_linear, getTextureFloatLinear, COMPAT_blend_minmax, getBlendMinMax } from './compat';
export function getGLContext(canvas: HTMLCanvasElement, contextAttributes?: WebGLContextAttributes): GLRenderingContext | null { export function getGLContext(canvas: HTMLCanvasElement, contextAttributes?: WebGLContextAttributes): GLRenderingContext | null {
function getContext(contextId: 'webgl' | 'experimental-webgl' | 'webgl2') { function getContext(contextId: 'webgl' | 'experimental-webgl' | 'webgl2') {
...@@ -100,8 +100,9 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height ...@@ -100,8 +100,9 @@ export function createImageData(buffer: ArrayLike<number>, width: number, height
type Extensions = { type Extensions = {
instancedArrays: COMPAT_instanced_arrays instancedArrays: COMPAT_instanced_arrays
standardDerivatives: COMPAT_standard_derivatives standardDerivatives: COMPAT_standard_derivatives
textureFloat: COMPAT_texture_float, blendMinMax: COMPAT_blend_minmax
textureFloatLinear: COMPAT_texture_float_linear, textureFloat: COMPAT_texture_float
textureFloatLinear: COMPAT_texture_float_linear
elementIndexUint: COMPAT_element_index_uint | null elementIndexUint: COMPAT_element_index_uint | null
vertexArrayObject: COMPAT_vertex_array_object | null vertexArrayObject: COMPAT_vertex_array_object | null
} }
...@@ -144,6 +145,10 @@ export function createContext(gl: GLRenderingContext): Context { ...@@ -144,6 +145,10 @@ export function createContext(gl: GLRenderingContext): Context {
if (standardDerivatives === null) { if (standardDerivatives === null) {
throw new Error('Could not find support for "standard_derivatives"') throw new Error('Could not find support for "standard_derivatives"')
} }
const blendMinMax = getBlendMinMax(gl)
if (blendMinMax === null) {
throw new Error('Could not find support for "blend_minmax"')
}
const textureFloat = getTextureFloat(gl) const textureFloat = getTextureFloat(gl)
if (textureFloat === null) { if (textureFloat === null) {
throw new Error('Could not find support for "texture_float"') throw new Error('Could not find support for "texture_float"')
...@@ -175,6 +180,7 @@ export function createContext(gl: GLRenderingContext): Context { ...@@ -175,6 +180,7 @@ export function createContext(gl: GLRenderingContext): Context {
extensions: { extensions: {
instancedArrays, instancedArrays,
standardDerivatives, standardDerivatives,
blendMinMax,
textureFloat, textureFloat,
textureFloatLinear, textureFloatLinear,
elementIndexUint, elementIndexUint,
......
...@@ -10,10 +10,10 @@ import { PositionData, DensityData, DensityTextureData } from '../common' ...@@ -10,10 +10,10 @@ import { PositionData, DensityData, DensityTextureData } from '../common'
import { Box3D } from '../../geometry' import { Box3D } from '../../geometry'
import { GaussianDensityProps, getDelta } from '../gaussian-density' import { GaussianDensityProps, getDelta } from '../gaussian-density'
import { OrderedSet } from 'mol-data/int' import { OrderedSet } from 'mol-data/int'
import { Vec3, Tensor, Mat4 } from '../../linear-algebra' import { Vec3, Tensor, Mat4, Vec2 } from '../../linear-algebra'
import { GaussianDensityValues } from 'mol-gl/renderable/gaussian-density' import { GaussianDensityValues } from 'mol-gl/renderable/gaussian-density'
import { ValueCell, defaults } from 'mol-util' import { ValueCell, defaults } from 'mol-util'
import { RenderableState } from 'mol-gl/renderable' import { RenderableState, Renderable } from 'mol-gl/renderable'
import { createRenderable, createGaussianDensityRenderObject } from 'mol-gl/render-object' import { createRenderable, createGaussianDensityRenderObject } from 'mol-gl/render-object'
import { Context, createContext, getGLContext } from 'mol-gl/webgl/context'; import { Context, createContext, getGLContext } from 'mol-gl/webgl/context';
import { createFramebuffer } from 'mol-gl/webgl/framebuffer'; import { createFramebuffer } from 'mol-gl/webgl/framebuffer';
...@@ -23,13 +23,16 @@ import { decodeIdRGBA } from 'mol-geo/geometry/picking'; ...@@ -23,13 +23,16 @@ import { decodeIdRGBA } from 'mol-geo/geometry/picking';
export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> { export async function GaussianDensityGPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> {
const webgl = defaults(props.webgl, getWebGLContext()) const webgl = defaults(props.webgl, getWebGLContext())
// always use texture2d when the gaussian density needs to be downloaded from the GPU,
// it's faster than texture3d
console.time('GaussianDensityTexture2d')
const { scale, bbox, texture, dim } = await GaussianDensityTexture2d(ctx, webgl, position, box, radius, props)
console.timeEnd('GaussianDensityTexture2d')
const { field, idField } = fieldFromTexture2d(webgl, texture, dim)
const { transform, texture, gridDimension } = await GaussianDensityTexture(ctx, webgl, position, box, radius, props) const transform = Mat4.identity()
Mat4.fromScaling(transform, scale)
const { field, idField } = webgl.isWebGL2 ? Mat4.setTranslation(transform, bbox.min)
fieldFromTexture3d(webgl, texture, gridDimension) :
fieldFromTexture2d(webgl, texture, gridDimension)
console.log(idField) console.log(idField)
return { field, idField, transform } return { field, idField, transform }
...@@ -56,63 +59,56 @@ async function GaussianDensityTexture2d(ctx: RuntimeContext, webgl: Context, pos ...@@ -56,63 +59,56 @@ async function GaussianDensityTexture2d(ctx: RuntimeContext, webgl: Context, pos
const { drawCount, positions, radii, groups, delta, expandedBox, dim } = await prepareGaussianDensityData(ctx, position, box, radius, props) const { drawCount, positions, radii, groups, delta, expandedBox, dim } = await prepareGaussianDensityData(ctx, position, box, radius, props)
const [ dx, dy, dz ] = dim const [ dx, dy, dz ] = dim
const minDistanceTexture = getMinDistanceTexture(webgl, dx, dy) const { texDimX, texDimY, texCols } = getTexture2dSize(webgl.maxTextureSize, dim)
const minDistanceTexture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'nearest')
minDistanceTexture.define(texDimX, texDimY)
const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness) const renderObject = getGaussianDensityRenderObject(webgl, drawCount, positions, radii, groups, minDistanceTexture, expandedBox, dim, smoothness)
const renderable = createRenderable(webgl, renderObject) const renderable = createRenderable(webgl, renderObject)
// //
const maxTexSize = webgl.maxTextureSize
let fboTexDimX = 0
let fboTexDimY = dim[1]
let fboTexRows = 1
let fboTexCols = dim[0]
if (maxTexSize < dim[0] * dim[2]) {
fboTexCols = Math.floor(maxTexSize / dim[0])
fboTexRows = Math.ceil(dim[2] / fboTexCols)
fboTexDimX = fboTexCols * dim[0]
fboTexDimY *= fboTexRows
} else {
fboTexDimX = dim[0] * dim[2]
}
//
const { gl } = webgl const { gl } = webgl
const { uCurrentSlice, uCurrentX, uCurrentY } = renderObject.values const { uCurrentSlice, uCurrentX, uCurrentY } = renderObject.values
const framebuffer = createFramebuffer(webgl) const framebuffer = createFramebuffer(webgl)
framebuffer.bind() framebuffer.bind()
if (!texture) {
texture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'linear')
}
texture.define(fboTexDimX, fboTexDimY)
const program = renderable.getProgram('draw')
program.use()
setRenderingDefaults(gl) setRenderingDefaults(gl)
texture.attachFramebuffer(framebuffer, 0)
let currCol = 0 if (!texture) texture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'linear')
let currY = 0 texture.define(texDimX, texDimY)
let currX = 0
for (let i = 0; i < dz; ++i) { function render(fbTex: Texture) {
if (currCol >= fboTexCols) { fbTex.attachFramebuffer(framebuffer, 0)
currCol -= fboTexCols let currCol = 0
currY += dy let currY = 0
currX = 0 let currX = 0
for (let i = 0; i < dz; ++i) {
if (currCol >= texCols) {
currCol -= texCols
currY += dy
currX = 0
}
gl.viewport(currX, currY, dx, dy)
ValueCell.update(uCurrentSlice, i)
ValueCell.update(uCurrentX, currX)
ValueCell.update(uCurrentY, currY)
renderable.render('draw')
++currCol
currX += dx
} }
gl.viewport(currX, currY, dx, dy)
ValueCell.update(uCurrentSlice, i)
ValueCell.update(uCurrentX, currX)
ValueCell.update(uCurrentY, currY)
renderable.render('draw')
++currCol
currX += dx
} }
setupMinDistanceRendering(webgl, renderable)
render(minDistanceTexture)
setupDensityRendering(webgl, renderable)
render(texture)
setupGroupIdRendering(webgl, renderable)
render(texture)
framebuffer.destroy() // clean up framebuffer.destroy() // clean up
await ctx.update({ message: 'gpu gaussian density calculation' }); await ctx.update({ message: 'gpu gaussian density calculation' });
...@@ -134,55 +130,33 @@ async function GaussianDensityTexture3d(ctx: RuntimeContext, webgl: Context, pos ...@@ -134,55 +130,33 @@ async function GaussianDensityTexture3d(ctx: RuntimeContext, webgl: Context, pos
// //
const gl = webgl.gl as WebGL2RenderingContext const { gl } = webgl
const { uCurrentSlice } = renderObject.values const { uCurrentSlice } = renderObject.values
const framebuffer = createFramebuffer(webgl) const framebuffer = createFramebuffer(webgl)
framebuffer.bind() framebuffer.bind()
gl.viewport(0, 0, dx, dy)
setRenderingDefaults(gl) setRenderingDefaults(gl)
gl.viewport(0, 0, dx, dy)
if (!texture) { if (!texture) texture = createTexture(webgl, 'volume-uint8', 'rgba', 'ubyte', 'linear')
texture = createTexture(webgl, 'volume-uint8', 'rgba', 'ubyte', 'linear')
}
texture.define(dx, dy, dz) texture.define(dx, dy, dz)
ValueCell.update(renderable.values.dCalcType, 'minDistance') function render(fbTex: Texture) {
renderable.update() for (let i = 0; i < dz; ++i) {
const programMinDistance = renderable.getProgram('draw') ValueCell.update(uCurrentSlice, i)
programMinDistance.use() fbTex.attachFramebuffer(framebuffer, 0, i)
gl.blendFunc(gl.ONE, gl.ONE) renderable.render('draw')
gl.blendEquation(gl.MAX) }
for (let i = 0; i < dz; ++i) {
ValueCell.update(uCurrentSlice, i)
minDistanceTexture.attachFramebuffer(framebuffer, 0, i)
renderable.render('draw')
} }
ValueCell.update(renderable.values.dCalcType, 'density') setupMinDistanceRendering(webgl, renderable)
renderable.update() render(minDistanceTexture)
const programDensity = renderable.getProgram('draw')
programDensity.use()
gl.blendFunc(gl.ONE, gl.ONE)
gl.blendEquation(gl.FUNC_ADD)
for (let i = 0; i < dz; ++i) {
ValueCell.update(uCurrentSlice, i)
texture.attachFramebuffer(framebuffer, 0, i)
renderable.render('draw')
}
ValueCell.update(renderable.values.dCalcType, 'groupId') setupDensityRendering(webgl, renderable)
renderable.update() render(texture)
const programGroupId = renderable.getProgram('draw')
programGroupId.use() setupGroupIdRendering(webgl, renderable)
gl.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ZERO, gl.ONE) render(texture)
gl.blendEquation(gl.FUNC_ADD)
for (let i = 0; i < dz; ++i) {
ValueCell.update(uCurrentSlice, i)
texture.attachFramebuffer(framebuffer, 0, i)
renderable.render('draw')
}
framebuffer.destroy() // clean up framebuffer.destroy() // clean up
...@@ -249,14 +223,9 @@ async function prepareGaussianDensityData(ctx: RuntimeContext, position: Positio ...@@ -249,14 +223,9 @@ async function prepareGaussianDensityData(ctx: RuntimeContext, position: Positio
return { drawCount: n, positions, radii, groups, delta, expandedBox, dim } return { drawCount: n, positions, radii, groups, delta, expandedBox, dim }
} }
function getMinDistanceTexture(webgl: Context, width: number, height: number) {
const minDistanceTexture = createTexture(webgl, 'image-uint8', 'rgba', 'ubyte', 'nearest')
minDistanceTexture.define(width, height)
return minDistanceTexture
}
function getGaussianDensityRenderObject(webgl: Context, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, dimensions: Vec3, smoothness: number) { function getGaussianDensityRenderObject(webgl: Context, drawCount: number, positions: Float32Array, radii: Float32Array, groups: Float32Array, minDistanceTexture: Texture, box: Box3D, dimensions: Vec3, smoothness: number) {
const extent = Vec3.sub(Vec3.zero(), box.max, box.min) const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
const { texDimX, texDimY } = getTexture2dSize(webgl.maxTextureSize, dimensions)
const values: GaussianDensityValues = { const values: GaussianDensityValues = {
drawCount: ValueCell.create(drawCount), drawCount: ValueCell.create(drawCount),
...@@ -273,9 +242,11 @@ function getGaussianDensityRenderObject(webgl: Context, drawCount: number, posit ...@@ -273,9 +242,11 @@ function getGaussianDensityRenderObject(webgl: Context, drawCount: number, posit
uBboxMax: ValueCell.create(box.max), uBboxMax: ValueCell.create(box.max),
uBboxSize: ValueCell.create(extent), uBboxSize: ValueCell.create(extent),
uGridDim: ValueCell.create(dimensions), uGridDim: ValueCell.create(dimensions),
uGridTexDim: ValueCell.create(Vec2.create(texDimX, texDimY)),
uAlpha: ValueCell.create(smoothness), uAlpha: ValueCell.create(smoothness),
tMinDistanceTex: ValueCell.create(minDistanceTexture), tMinDistanceTex: ValueCell.create(minDistanceTexture),
dGridTexType: ValueCell.create(minDistanceTexture.depth > 0 ? '3d' : '2d'),
dCalcType: ValueCell.create('density'), dCalcType: ValueCell.create('density'),
} }
const state: RenderableState = { const state: RenderableState = {
...@@ -292,10 +263,52 @@ function setRenderingDefaults(gl: GLRenderingContext) { ...@@ -292,10 +263,52 @@ function setRenderingDefaults(gl: GLRenderingContext) {
gl.disable(gl.CULL_FACE) gl.disable(gl.CULL_FACE)
gl.frontFace(gl.CCW) gl.frontFace(gl.CCW)
gl.cullFace(gl.BACK) gl.cullFace(gl.BACK)
gl.enable(gl.BLEND)
}
function setupMinDistanceRendering(webgl: Context, renderable: Renderable<any>) {
const { gl } = webgl
ValueCell.update(renderable.values.dCalcType, 'minDistance')
renderable.update()
renderable.getProgram('draw').use()
gl.blendFunc(gl.ONE, gl.ONE)
// the shader writes 1 - dist so we set blending to MAX
gl.blendEquation(webgl.extensions.blendMinMax.MAX)
}
function setupDensityRendering(webgl: Context, renderable: Renderable<any>) {
const { gl } = webgl
ValueCell.update(renderable.values.dCalcType, 'density')
renderable.update()
renderable.getProgram('draw').use()
gl.blendFunc(gl.ONE, gl.ONE) gl.blendFunc(gl.ONE, gl.ONE)
gl.blendEquation(gl.FUNC_ADD) gl.blendEquation(gl.FUNC_ADD)
gl.enable(gl.BLEND) }
function setupGroupIdRendering(webgl: Context, renderable: Renderable<any>) {
const { gl } = webgl
ValueCell.update(renderable.values.dCalcType, 'groupId')
renderable.update()
renderable.getProgram('draw').use()
// overwrite color, don't change alpha
gl.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ZERO, gl.ONE)
gl.blendEquation(gl.FUNC_ADD)
}
function getTexture2dSize(maxTexSize: number, gridDim: Vec3) {
let texDimX = 0
let texDimY = gridDim[1]
let texRows = 1
let texCols = gridDim[0]
if (maxTexSize < gridDim[0] * gridDim[2]) {
texCols = Math.floor(maxTexSize / gridDim[0])
texRows = Math.ceil(gridDim[2] / texCols)
texDimX = texCols * gridDim[0]
texDimY *= texRows
} else {
texDimX = gridDim[0] * gridDim[2]
}
return { texDimX, texDimY, texRows, texCols }
} }
function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) {
...@@ -319,7 +332,7 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { ...@@ -319,7 +332,7 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) {
texture.attachFramebuffer(framebuffer, 0) texture.attachFramebuffer(framebuffer, 0)
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, image) gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, image)
let idx = 0 let j = 0
let tmpCol = 0 let tmpCol = 0
let tmpRow = 0 let tmpRow = 0
for (let iz = 0; iz < dz; ++iz) { for (let iz = 0; iz < dz; ++iz) {
...@@ -329,8 +342,10 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { ...@@ -329,8 +342,10 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) {
} }
for (let iy = 0; iy < dy; ++iy) { for (let iy = 0; iy < dy; ++iy) {
for (let ix = 0; ix < dx; ++ix) { for (let ix = 0; ix < dx; ++ix) {
data[idx] = image[4 * (tmpCol * dx + (iy + tmpRow) * width + ix) + 3] / 255 const idx = 4 * (tmpCol * dx + (iy + tmpRow) * width + ix)
idx++ data[j] = image[idx + 3] / 255
idData[j] = decodeIdRGBA(image[idx], image[idx + 1], image[idx + 2])
j++
} }
} }
tmpCol++ tmpCol++
...@@ -342,38 +357,38 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) { ...@@ -342,38 +357,38 @@ function fieldFromTexture2d(ctx: Context, texture: Texture, dim: Vec3) {
return { field, idField } return { field, idField }
} }
function fieldFromTexture3d(ctx: Context, texture: Texture, dim: Vec3) { // function fieldFromTexture3d(ctx: Context, texture: Texture, dim: Vec3) {
console.time('fieldFromTexture3d') // console.time('fieldFromTexture3d')
const { gl } = ctx // const { gl } = ctx
const { width, height, depth } = texture // const { width, height, depth } = texture
const space = Tensor.Space(dim, [2, 1, 0], Float32Array) // const space = Tensor.Space(dim, [2, 1, 0], Float32Array)
const data = space.create() // const data = space.create()
const field = Tensor.create(space, data) // const field = Tensor.create(space, data)
const idData = space.create() // const idData = space.create()
const idField = Tensor.create(space, idData) // const idField = Tensor.create(space, idData)
const slice = new Uint8Array(width * height * 4) // const slice = new Uint8Array(width * height * 4)
const framebuffer = createFramebuffer(ctx) // const framebuffer = createFramebuffer(ctx)
framebuffer.bind() // framebuffer.bind()
let j = 0 // let j = 0
for (let i = 0; i < depth; ++i) { // for (let i = 0; i < depth; ++i) {
texture.attachFramebuffer(framebuffer, 0, i) // texture.attachFramebuffer(framebuffer, 0, i)
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, slice) // gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, slice)
for (let iy = 0; iy < height; ++iy) { // for (let iy = 0; iy < height; ++iy) {
for (let ix = 0; ix < width; ++ix) { // for (let ix = 0; ix < width; ++ix) {
const idx = 4 * (iy * width + ix) // const idx = 4 * (iy * width + ix)
data[j] = slice[idx + 3] / 255 // data[j] = slice[idx + 3] / 255
idData[j] = decodeIdRGBA(slice[idx], slice[idx + 1], slice[idx + 2]) // idData[j] = decodeIdRGBA(slice[idx], slice[idx + 1], slice[idx + 2])
++j // ++j
} // }
} // }
} // }
framebuffer.destroy() // framebuffer.destroy()
console.timeEnd('fieldFromTexture3d') // console.timeEnd('fieldFromTexture3d')
return { field, idField } // return { field, idField }
} // }
\ No newline at end of file \ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment