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

handle negative isovalues in gpu mc

parent 5df55e6b
Branches
No related tags found
No related merge requests found
...@@ -32,6 +32,7 @@ const IsosurfaceSchema = { ...@@ -32,6 +32,7 @@ const IsosurfaceSchema = {
uSize: UniformSpec('f'), uSize: UniformSpec('f'),
uLevels: UniformSpec('f'), uLevels: UniformSpec('f'),
uCount: UniformSpec('f'), uCount: UniformSpec('f'),
uInvert: UniformSpec('b'),
uGridDim: UniformSpec('v3'), uGridDim: UniformSpec('v3'),
uGridTexDim: UniformSpec('v3'), uGridTexDim: UniformSpec('v3'),
...@@ -44,7 +45,7 @@ type IsosurfaceValues = Values<typeof IsosurfaceSchema> ...@@ -44,7 +45,7 @@ type IsosurfaceValues = Values<typeof IsosurfaceSchema>
const IsosurfaceName = 'isosurface'; const IsosurfaceName = 'isosurface';
function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, packedGroup: boolean): ComputeRenderable<IsosurfaceValues> { function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean): ComputeRenderable<IsosurfaceValues> {
if (ctx.namedComputeRenderables[IsosurfaceName]) { if (ctx.namedComputeRenderables[IsosurfaceName]) {
const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues; const v = ctx.namedComputeRenderables[IsosurfaceName].values as IsosurfaceValues;
...@@ -56,6 +57,7 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture ...@@ -56,6 +57,7 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ValueCell.updateIfChanged(v.uSize, Math.pow(2, levels)); ValueCell.updateIfChanged(v.uSize, Math.pow(2, levels));
ValueCell.updateIfChanged(v.uLevels, levels); ValueCell.updateIfChanged(v.uLevels, levels);
ValueCell.updateIfChanged(v.uCount, count); ValueCell.updateIfChanged(v.uCount, count);
ValueCell.updateIfChanged(v.uInvert, invert);
ValueCell.update(v.uGridDim, gridDim); ValueCell.update(v.uGridDim, gridDim);
ValueCell.update(v.uGridTexDim, gridTexDim); ValueCell.update(v.uGridTexDim, gridTexDim);
...@@ -66,12 +68,12 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture ...@@ -66,12 +68,12 @@ function getIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture
ctx.namedComputeRenderables[IsosurfaceName].update(); ctx.namedComputeRenderables[IsosurfaceName].update();
} else { } else {
ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, packedGroup); ctx.namedComputeRenderables[IsosurfaceName] = createIsosurfaceRenderable(ctx, activeVoxelsPyramid, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
} }
return ctx.namedComputeRenderables[IsosurfaceName]; return ctx.namedComputeRenderables[IsosurfaceName];
} }
function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, packedGroup: boolean) { function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Texture, activeVoxelsBase: Texture, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, levels: number, scale: Vec2, count: number, invert: boolean, packedGroup: boolean) {
// console.log('uSize', Math.pow(2, levels)) // console.log('uSize', Math.pow(2, levels))
const values: IsosurfaceValues = { const values: IsosurfaceValues = {
...QuadValues, ...QuadValues,
...@@ -85,6 +87,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text ...@@ -85,6 +87,7 @@ function createIsosurfaceRenderable(ctx: WebGLContext, activeVoxelsPyramid: Text
uSize: ValueCell.create(Math.pow(2, levels)), uSize: ValueCell.create(Math.pow(2, levels)),
uLevels: ValueCell.create(levels), uLevels: ValueCell.create(levels),
uCount: ValueCell.create(count), uCount: ValueCell.create(count),
uInvert: ValueCell.create(invert),
uGridDim: ValueCell.create(gridDim), uGridDim: ValueCell.create(gridDim),
uGridTexDim: ValueCell.create(gridTexDim), uGridTexDim: ValueCell.create(gridTexDim),
...@@ -112,7 +115,7 @@ function setRenderingDefaults(ctx: WebGLContext) { ...@@ -112,7 +115,7 @@ function setRenderingDefaults(ctx: WebGLContext) {
state.clearColor(0, 0, 0, 0); state.clearColor(0, 0, 0, 0);
} }
export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Texture, volumeData: Texture, histogramPyramid: HistogramPyramid, gridDim: Vec3, gridTexDim: Vec3, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
const { gl, resources, extensions } = ctx; const { gl, resources, extensions } = ctx;
const { pyramidTex, height, levels, scale, count } = histogramPyramid; const { pyramidTex, height, levels, scale, count } = histogramPyramid;
const width = pyramidTex.getWidth(); const width = pyramidTex.getWidth();
...@@ -167,7 +170,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex ...@@ -167,7 +170,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
groupTexture.attachFramebuffer(framebuffer, 1); groupTexture.attachFramebuffer(framebuffer, 1);
normalTexture.attachFramebuffer(framebuffer, 2); normalTexture.attachFramebuffer(framebuffer, 2);
const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, packedGroup); const renderable = getIsosurfaceRenderable(ctx, pyramidTex, activeVoxelsBase, volumeData, gridDim, gridTexDim, transform, isoValue, levels, scale, count, invert, packedGroup);
ctx.state.currentRenderItemId = -1; ctx.state.currentRenderItemId = -1;
const { drawBuffers } = ctx.extensions; const { drawBuffers } = ctx.extensions;
...@@ -201,7 +204,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex ...@@ -201,7 +204,7 @@ export function createIsosurfaceBuffers(ctx: WebGLContext, activeVoxelsBase: Tex
* *
* Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/ * Implementation based on http://www.miaumiau.cat/2016/10/stream-compaction-in-webgl/
*/ */
export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) { export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDim: Vec3, gridTexDim: Vec3, gridTexScale: Vec2, transform: Mat4, isoValue: number, invert: boolean, packedGroup: boolean, vertexTexture?: Texture, groupTexture?: Texture, normalTexture?: Texture) {
// console.time('calcActiveVoxels'); // console.time('calcActiveVoxels');
const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale); const activeVoxelsTex = calcActiveVoxels(ctx, volumeData, gridDim, gridTexDim, isoValue, gridTexScale);
// ctx.waitForGpuCommandsCompleteSync(); // ctx.waitForGpuCommandsCompleteSync();
...@@ -213,7 +216,7 @@ export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDi ...@@ -213,7 +216,7 @@ export function extractIsosurface(ctx: WebGLContext, volumeData: Texture, gridDi
// console.timeEnd('createHistogramPyramid'); // console.timeEnd('createHistogramPyramid');
// console.time('createIsosurfaceBuffers'); // console.time('createIsosurfaceBuffers');
const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, packedGroup, vertexTexture, groupTexture, normalTexture); const gv = createIsosurfaceBuffers(ctx, activeVoxelsTex, volumeData, compacted, gridDim, gridTexDim, transform, isoValue, invert, packedGroup, vertexTexture, groupTexture, normalTexture);
// ctx.waitForGpuCommandsCompleteSync(); // ctx.waitForGpuCommandsCompleteSync();
// console.timeEnd('createIsosurfaceBuffers'); // console.timeEnd('createIsosurfaceBuffers');
......
...@@ -18,6 +18,7 @@ uniform float uIsoValue; ...@@ -18,6 +18,7 @@ uniform float uIsoValue;
uniform float uLevels; uniform float uLevels;
uniform float uSize; uniform float uSize;
uniform float uCount; uniform float uCount;
uniform bool uInvert;
uniform vec3 uGridDim; uniform vec3 uGridDim;
uniform vec3 uGridTexDim; uniform vec3 uGridTexDim;
...@@ -163,6 +164,13 @@ void main(void) { ...@@ -163,6 +164,13 @@ void main(void) {
// current vertex for the up to 15 MC cases // current vertex for the up to 15 MC cases
int currentVertex = vI - idot4(m, starts); int currentVertex = vI - idot4(m, starts);
// ensure winding-order is the same for negative and positive iso-levels
if (uInvert) {
int v = imod(currentVertex + 1, 3);
if (v == 1) currentVertex += 2;
else if (v == 0) currentVertex -= 2;
}
// get index into triIndices table // get index into triIndices table
int mcIndex = 16 * int(edgeIndex) + currentVertex; int mcIndex = 16 * int(edgeIndex) + currentVertex;
vec4 mcData = texture2D(tTriIndices, vec2(imod(mcIndex, 64), mcIndex / 64) / 64.); vec4 mcData = texture2D(tTriIndices, vec2(imod(mcIndex, 64), mcIndex / 64) / 64.);
...@@ -273,11 +281,18 @@ void main(void) { ...@@ -273,11 +281,18 @@ void main(void) {
voxelPadded(b1 - c3).a - voxelPadded(b1 + c3).a, voxelPadded(b1 - c3).a - voxelPadded(b1 + c3).a,
voxelPadded(b1 - c4).a - voxelPadded(b1 + c4).a voxelPadded(b1 - c4).a - voxelPadded(b1 + c4).a
)); ));
mat3 normalMatrix = transpose3(inverse3(mat3(uGridTransform))); gl_FragData[2].xyz = -vec3(
gl_FragData[2].xyz = normalMatrix * -vec3(
n0.x + t * (n0.x - n1.x), n0.x + t * (n0.x - n1.x),
n0.y + t * (n0.y - n1.y), n0.y + t * (n0.y - n1.y),
n0.z + t * (n0.z - n1.z) n0.z + t * (n0.z - n1.z)
); );
// ensure normal-direction is the same for negative and positive iso-levels
if (uInvert) {
gl_FragData[2].xyz *= -1.0;
}
// apply normal matrix
gl_FragData[2].xyz *= transpose3(inverse3(mat3(uGridTransform)));
} }
`; `;
\ No newline at end of file
...@@ -182,7 +182,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit, ...@@ -182,7 +182,7 @@ async function createGaussianSurfaceTextureMesh(ctx: VisualContext, unit: Unit,
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor; const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get(); const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, buffer?.vertex, buffer?.group, buffer?.normal); const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, buffer?.vertex, buffer?.group, buffer?.normal);
const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure)); const boundingSphere = Sphere3D.expand(Sphere3D(), unit.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
...@@ -241,7 +241,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str ...@@ -241,7 +241,7 @@ async function createStructureGaussianSurfaceTextureMesh(ctx: VisualContext, str
const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor; const isoLevel = Math.exp(-props.smoothness) / densityTextureData.radiusFactor;
const buffer = textureMesh?.doubleBuffer.get(); const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, true, buffer?.vertex, buffer?.group, buffer?.normal); const gv = extractIsosurface(ctx.webgl, densityTextureData.texture, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.gridTexScale, densityTextureData.transform, isoLevel, false, true, buffer?.vertex, buffer?.group, buffer?.normal);
const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure)); const boundingSphere = Sphere3D.expand(Sphere3D(), structure.boundary.sphere, props.radiusOffset + getStructureExtraRadius(structure));
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, boundingSphere, textureMesh);
......
...@@ -176,7 +176,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol ...@@ -176,7 +176,7 @@ async function createVolumeIsosurfaceTextureMesh(ctx: VisualContext, volume: Vol
const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl); const { texture, gridDimension, gridTexDim, gridTexScale, transform } = VolumeIsosurfaceTexture.get(volume, ctx.webgl);
const buffer = textureMesh?.doubleBuffer.get(); const buffer = textureMesh?.doubleBuffer.get();
const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, false, buffer?.vertex, buffer?.group, buffer?.normal); const gv = extractIsosurface(ctx.webgl, texture, gridDimension, gridTexDim, gridTexScale, transform, isoLevel, value < 0, false, buffer?.vertex, buffer?.group, buffer?.normal);
const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh); const surface = TextureMesh.create(gv.vertexCount, 1, gv.vertexTexture, gv.groupTexture, gv.normalTexture, Volume.getBoundingSphere(volume), textureMesh);
......
...@@ -73,7 +73,7 @@ async function init() { ...@@ -73,7 +73,7 @@ async function init() {
console.timeEnd('gpu mc pyramid2'); console.timeEnd('gpu mc pyramid2');
console.time('gpu mc vert2'); console.time('gpu mc vert2');
createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, true); createIsosurfaceBuffers(webgl, activeVoxelsTex2, densityTextureData2.texture, compacted2, densityTextureData2.gridDim, densityTextureData2.gridTexDim, densityTextureData2.transform, isoValue, false, true);
webgl.waitForGpuCommandsCompleteSync(); webgl.waitForGpuCommandsCompleteSync();
console.timeEnd('gpu mc vert2'); console.timeEnd('gpu mc vert2');
console.timeEnd('gpu mc2'); console.timeEnd('gpu mc2');
...@@ -96,7 +96,7 @@ async function init() { ...@@ -96,7 +96,7 @@ async function init() {
console.timeEnd('gpu mc pyramid'); console.timeEnd('gpu mc pyramid');
console.time('gpu mc vert'); console.time('gpu mc vert');
const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, true); const gv = createIsosurfaceBuffers(webgl, activeVoxelsTex, densityTextureData.texture, compacted, densityTextureData.gridDim, densityTextureData.gridTexDim, densityTextureData.transform, isoValue, false, true);
webgl.waitForGpuCommandsCompleteSync(); webgl.waitForGpuCommandsCompleteSync();
console.timeEnd('gpu mc vert'); console.timeEnd('gpu mc vert');
console.timeEnd('gpu mc'); console.timeEnd('gpu mc');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment