Skip to content

Commit

Permalink
Merge branch 'master' into feature/NA-194
Browse files Browse the repository at this point in the history
  • Loading branch information
seankmartin committed May 20, 2024
2 parents 8aa9340 + f805b54 commit 97e6493
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 58 deletions.
2 changes: 1 addition & 1 deletion python/neuroglancer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
PlaceEllipsoidTool, # noqa: F401
BlendTool, # noqa: F401
OpacityTool, # noqa: F401
VolumeRenderingModeTool, # noqa: F401
VolumeRenderingTool, # noqa: F401
VolumeRenderingGainTool, # noqa: F401
VolumeRenderingDepthSamplesTool, # noqa: F401
CrossSectionRenderScaleTool, # noqa: F401
Expand Down
4 changes: 2 additions & 2 deletions python/neuroglancer/viewer_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ class OpacityTool(Tool):


@export_tool
class VolumeRenderingModeTool(Tool):
class VolumeRenderingTool(Tool):
__slots__ = ()
TOOL_TYPE = "volumeRenderingMode"
TOOL_TYPE = "volumeRendering"


@export_tool
Expand Down
127 changes: 74 additions & 53 deletions src/perspective_view/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,21 +153,26 @@ export function perspectivePanelEmitOIT(builder: ShaderBuilder) {
}

export function maxProjectionEmit(builder: ShaderBuilder) {
builder.addOutputBuffer("vec4", "v4f_fragData0", 0);
builder.addOutputBuffer("highp vec4", "v4f_fragData1", 1);
builder.addOutputBuffer("highp vec4", "v4f_fragData2", 2);
builder.addOutputBuffer("vec4", "out_color", 0);
builder.addOutputBuffer("highp vec4", "out_z", 1);
builder.addOutputBuffer("highp vec4", "out_intensity", 2);
builder.addOutputBuffer("highp vec4", "out_pickId", 3);
builder.addFragmentCode(`
void emit(vec4 color, float depth, float pick) {
v4f_fragData0 = color;
v4f_fragData1 = vec4(1.0 - depth, 1.0 - depth, 1.0 - depth, 1.0);
v4f_fragData2 = vec4(pick, pick, pick, 1.0);
void emit(vec4 color, float depth, float intensity, highp uint pickId) {
float pickIdFloat = float(pickId);
float bufferDepth = 1.0 - depth;
out_color = color;
out_z = vec4(bufferDepth, bufferDepth, bufferDepth, 1.0);
out_intensity = vec4(intensity, intensity, intensity, 1.0);
out_pickId = vec4(pickIdFloat, pickIdFloat, pickIdFloat, 1.0);
}`);
}

const tempVec3 = vec3.create();
const tempVec4 = vec4.create();
const tempMat4 = mat4.create();

// Copy the OIT values to the main color buffer
function defineTransparencyCopyShader(builder: ShaderBuilder) {
builder.addOutputBuffer("vec4", "v4f_fragColor", null);
builder.setFragmentMain(`
Expand All @@ -180,31 +185,45 @@ v4f_fragColor = vec4(accum.rgb / accum.a, revealage);
`);
}

// Copy the max projection color to the OIT buffer
function defineMaxProjectionColorCopyShader(builder: ShaderBuilder) {
builder.addOutputBuffer("vec4", "v4f_fragColor", null);
builder.addOutputBuffer("vec4", "v4f_fragData0", 0);
builder.addOutputBuffer("vec4", "v4f_fragData1", 1);
builder.addFragmentCode(glsl_perspectivePanelEmitOIT);
builder.setFragmentMain(`
v4f_fragColor = getValue0();
vec4 color = getValue0();
float bufferDepth = getValue1().r;
float weight = computeOITWeight(color.a, 1.0 - bufferDepth);
vec4 accum = color * weight;
float revealage = color.a;
emitAccumAndRevealage(accum, revealage, 0u);
`);
}

// Copy the max projection depth and pick values to the main buffer
function defineMaxProjectionPickCopyShader(builder: ShaderBuilder) {
builder.addOutputBuffer("vec4", "v4f_fragData0", 0);
builder.addOutputBuffer("highp vec4", "v4f_fragData1", 1);
builder.addOutputBuffer("highp vec4", "v4f_fragData2", 2);
builder.addOutputBuffer("vec4", "out_color", 0);
builder.addOutputBuffer("highp vec4", "out_z", 1);
builder.addOutputBuffer("highp vec4", "out_pickId", 2);
builder.setFragmentMain(`
v4f_fragData0 = vec4(0.0);
v4f_fragData1 = getValue0();
v4f_fragData2 = getValue1();
out_color = vec4(0.0);
out_z = getValue0();
out_pickId = getValue1();
`);
}

// Copy the max projection depth and picking to the max projection pick buffer.
// Note that the depth is set as the intensity value from the render layer.
// This is to combine max projection picking data via depth testing
// on the maximum intensity value of the data.
function defineMaxProjectionToPickCopyShader(builder: ShaderBuilder) {
builder.addOutputBuffer("highp vec4", "v4f_fragData0", 0);
builder.addOutputBuffer("highp vec4", "v4f_fragData1", 1);
builder.addOutputBuffer("highp vec4", "out_z", 0);
builder.addOutputBuffer("highp vec4", "out_pickId", 1);
builder.setFragmentMain(`
v4f_fragData0 = getValue0();
v4f_fragData1 = getValue1();
gl_FragDepth = v4f_fragData1.r;
out_z = getValue0();
out_pickId = getValue2();
gl_FragDepth = getValue1().r;
`);
}

Expand Down Expand Up @@ -306,13 +325,13 @@ export class PerspectivePanel extends RenderedDataPanel {
OffscreenCopyHelper.get(this.gl, defineTransparencyCopyShader, 2),
);
protected maxProjectionColorCopyHelper = this.registerDisposer(
OffscreenCopyHelper.get(this.gl, defineMaxProjectionColorCopyShader, 1),
OffscreenCopyHelper.get(this.gl, defineMaxProjectionColorCopyShader, 2),
);
protected maxProjectionPickCopyHelper = this.registerDisposer(
OffscreenCopyHelper.get(this.gl, defineMaxProjectionPickCopyShader, 2),
);
protected maxProjectionToPickCopyHelper = this.registerDisposer(
OffscreenCopyHelper.get(this.gl, defineMaxProjectionToPickCopyShader, 2),
OffscreenCopyHelper.get(this.gl, defineMaxProjectionToPickCopyShader, 3),
);

private sharedObject: PerspectiveViewState;
Expand Down Expand Up @@ -730,6 +749,12 @@ export class PerspectivePanel extends RenderedDataPanel {
WebGL2RenderingContext.RED,
WebGL2RenderingContext.FLOAT,
),
new TextureBuffer(
this.gl,
WebGL2RenderingContext.R32F,
WebGL2RenderingContext.RED,
WebGL2RenderingContext.FLOAT,
),
],
depthBuffer: new DepthStencilRenderbuffer(this.gl),
}),
Expand Down Expand Up @@ -1004,6 +1029,7 @@ export class PerspectivePanel extends RenderedDataPanel {
renderContext.depthBufferTexture =
this.offscreenFramebuffer.colorBuffers[OffscreenTextures.Z].texture;
}
// Draw max projection layers
if (
renderLayer.isVolumeRendering &&
isProjectionLayer(renderLayer as VolumeRenderingRenderLayer)
Expand All @@ -1021,21 +1047,26 @@ export class PerspectivePanel extends RenderedDataPanel {
bindMaxProjectionPickingBuffer();
this.maxProjectionToPickCopyHelper.draw(
this.maxProjectionConfiguration.colorBuffers[1 /*depth*/].texture,
this.maxProjectionConfiguration.colorBuffers[2 /*pick*/].texture,
this.maxProjectionConfiguration.colorBuffers[2 /*intensity*/]
.texture,
this.maxProjectionConfiguration.colorBuffers[3 /*pick*/].texture,
);

// Copy max projection color result to color only buffer
// Copy max projection color result to the transparent buffer with OIT
// Depth testing off to combine max layers into one color via blend
this.offscreenFramebuffer.bindSingle(OffscreenTextures.COLOR);
renderContext.bindFramebuffer();
gl.depthMask(false);
gl.disable(WebGL2RenderingContext.DEPTH_TEST);
gl.enable(WebGL2RenderingContext.BLEND);
gl.blendFunc(
gl.blendFuncSeparate(
WebGL2RenderingContext.ONE,
WebGL2RenderingContext.ONE,
WebGL2RenderingContext.ZERO,
WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
);
this.maxProjectionColorCopyHelper.draw(
this.maxProjectionConfiguration.colorBuffers[0 /*color*/].texture,
this.maxProjectionConfiguration.colorBuffers[1 /*depth*/].texture,
);

// Reset the max projection buffer
Expand All @@ -1052,19 +1083,15 @@ export class PerspectivePanel extends RenderedDataPanel {
gl.clearDepth(1.0);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.depthMask(false);
gl.blendFuncSeparate(
WebGL2RenderingContext.ONE,
WebGL2RenderingContext.ONE,
WebGL2RenderingContext.ZERO,
WebGL2RenderingContext.ONE_MINUS_SRC_ALPHA,
);
gl.enable(WebGL2RenderingContext.DEPTH_TEST);
gl.depthFunc(WebGL2RenderingContext.LESS);
renderContext.emitter = perspectivePanelEmitOIT;
renderContext.bindFramebuffer();
continue;
}
renderLayer.draw(renderContext, attachment);
// Draw regular transparent layers
else if (renderLayer.isTransparent) {
renderLayer.draw(renderContext, attachment);
}
}
// Copy transparent rendering result back to primary buffer.
gl.disable(WebGL2RenderingContext.DEPTH_TEST);
Expand Down Expand Up @@ -1109,27 +1136,21 @@ export class PerspectivePanel extends RenderedDataPanel {
/*dppass=*/ WebGL2RenderingContext.REPLACE,
);
gl.stencilMask(2);
if (hasMaxProjection) {
this.maxProjectionPickCopyHelper.draw(
this.maxProjectionPickConfiguration.colorBuffers[0].texture /*depth*/,
this.maxProjectionPickConfiguration.colorBuffers[1].texture /*pick*/,
);
}
for (const [renderLayer, attachment] of visibleLayers) {
if (!renderLayer.isTransparent || !renderLayer.transparentPickEnabled) {
if (
!renderLayer.isTransparent ||
!renderLayer.transparentPickEnabled ||
renderLayer.isVolumeRendering
) {
// Skip non-transparent layers and transparent layers with transparentPickEnabled=false.
// Volume rendering layers are handled separately and are combined in a pick buffer
continue;
}
// For max projection layers, can copy over the pick buffer directly.
if (renderLayer.isVolumeRendering) {
if (isProjectionLayer(renderLayer as VolumeRenderingRenderLayer)) {
this.maxProjectionPickCopyHelper.draw(
this.maxProjectionPickConfiguration.colorBuffers[0]
.texture /*depth*/,
this.maxProjectionPickConfiguration.colorBuffers[1]
.texture /*pick*/,
);
}
// Draw picking for non min/max volume rendering layers
else {
// Currently volume rendering layers have no picking support
// Outside of min/max mode
continue;
}
// other transparent layers are drawn as usual
} else {
renderLayer.draw(renderContext, attachment);
}
Expand Down
9 changes: 7 additions & 2 deletions src/volume_rendering/volume_render_layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ void emitRGBA(vec4 rgba) {
savedIntensity = intensityChanged ? newIntensity : savedIntensity;
savedDepth = intensityChanged ? depthAtRayPosition : savedDepth;
outputColor = intensityChanged ? newColor : outputColor;
emit(outputColor, savedDepth, savedIntensity);
emit(outputColor, savedDepth, savedIntensity, uPickId);
defaultMaxProjectionIntensity = 0.0;
userEmittedIntensity = -100.0;
`;
Expand Down Expand Up @@ -311,6 +311,7 @@ void emitRGBA(vec4 rgba) {

builder.addUniform("highp float", "uBrightnessFactor");
builder.addUniform("highp float", "uGain");
builder.addUniform("highp uint", "uPickId");
builder.addVarying("highp vec4", "vNormalizedPosition");
builder.addTextureSampler(
"sampler2D",
Expand Down Expand Up @@ -368,7 +369,7 @@ vec2 computeUVFromClipSpace(vec4 clipSpacePosition) {
`;
if (isProjectionMode(shaderParametersState.mode)) {
glsl_emitWireframe = `
emit(outputColor, 1.0, uChunkNumber);
emit(outputColor, 1.0, uChunkNumber, uPickId);
`;
}
builder.setFragmentMainFunction(`
Expand Down Expand Up @@ -625,6 +626,9 @@ void main() {
gl.enable(WebGL2RenderingContext.CULL_FACE);
gl.cullFace(WebGL2RenderingContext.FRONT);

const pickId = isProjectionMode(this.mode.value)
? renderContext.pickIDs.register(this)
: 0;
forEachVisibleVolumeRenderingChunk(
renderContext.projectionParameters,
this.localPosition.value,
Expand Down Expand Up @@ -802,6 +806,7 @@ void main() {
}
newSource = false;
gl.uniform3fv(shader.uniform("uTranslation"), chunkPosition);
gl.uniform1ui(shader.uniform("uPickId"), pickId);
drawBoxes(gl, 1, 1);
++presentCount;
} else {
Expand Down

0 comments on commit 97e6493

Please sign in to comment.