Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/annotation/line.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ import {
initializeLineShader,
} from "#src/webgl/lines.js";
import type { ShaderBuilder, ShaderProgram } from "#src/webgl/shader.js";
import { defineVectorArrayVertexShaderInput } from "#src/webgl/shader_lib.js";
import {
defineVectorArrayVertexShaderInput,
glsl_modelToPixels,
} from "#src/webgl/shader_lib.js";
import { defineVertexId, VertexIdHelper } from "#src/webgl/vertex_id.js";

const FULL_OBJECT_PICK_OFFSET = 0;
Expand Down Expand Up @@ -89,6 +92,16 @@ class RenderHelper extends AnnotationRenderHelper {
this.defineShader(builder);
defineLineShader(builder);
builder.addVarying(`highp float[${rank}]`, "vModelPosition");
builder.addVertexCode(glsl_modelToPixels);
builder.addVertexCode(`
float modelToPixels(float value) {
vec2 lineOffset = getLineOffset();
highp vec3 vertexA = projectModelVectorToSubspace(getVertexPosition0());
highp vec3 vertexB = projectModelVectorToSubspace(getVertexPosition1());
highp vec3 vertex = mix(vertexA, vertexB, lineOffset.x);
return value * modelToPixels(vertex, uProjection, uModelView, 1.0 / uLineParams.x);
}
`);
builder.addVertexCode(`
float ng_LineWidth;
`);
Expand Down Expand Up @@ -151,6 +164,15 @@ void setLineEndpointMarkerColor(vec4 startColor, vec4 endColor) {
void setLineEndpointMarkerBorderColor(vec4 startColor, vec4 endColor) {
vBorderColor = mix(startColor, endColor, float(getEndpointIndex()));
}
`);
builder.addVertexCode(glsl_modelToPixels);
builder.addVertexCode(`
float modelToPixels(float value) {
highp vec3 vertexA = projectModelVectorToSubspace(getVertexPosition0());
highp vec3 vertexB = projectModelVectorToSubspace(getVertexPosition1());
highp vec3 vertex = mix(vertexA, vertexB, float(getEndpointIndex()));
return value * modelToPixels(vertex, uProjection, uModelView, 1.0 / uCircleParams.x);
}
`);
builder.setVertexMain(`
float modelPosition[${rank}] = getVertexPosition0();
Expand Down
145 changes: 99 additions & 46 deletions src/skeleton/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import type {
ShaderProgram,
ShaderSamplerType,
} from "#src/webgl/shader.js";
import { glsl_modelToPixels } from "#src/webgl/shader_lib.js";
import type { ShaderControlsBuilderState } from "#src/webgl/shader_ui_controls.js";
import {
addControlsToBuilder,
Expand All @@ -94,7 +95,20 @@ import { defineVertexId, VertexIdHelper } from "#src/webgl/vertex_id.js";

const tempMat2 = mat4.create();

const DEFAULT_FRAGMENT_MAIN = `void main() {
function defineNoOpEdgeSetters(builder: ShaderBuilder) {
builder.addVertexCode(`
void setLineWidth(float width) {}
`);
}

function defineNoOpNodeSetters(builder: ShaderBuilder) {
builder.addVertexCode(`
void setNodeDiameter(float size) {}
`);
}

const DEFAULT_VERTEX_MAIN = `
void main() {
emitDefault();
}
`;
Expand Down Expand Up @@ -126,6 +140,7 @@ class RenderHelper extends RefCounted {
defineVertexId(builder);
builder.addUniform("highp vec4", "uColor");
builder.addUniform("highp mat4", "uProjection");
builder.addUniform("highp mat4", "uViewModel");
builder.addUniform("highp uint", "uPickID");
}

Expand Down Expand Up @@ -165,44 +180,65 @@ class RenderHelper extends RefCounted {
this.defineCommonShader(builder);
this.defineAttributeAccess(builder);
defineLineShader(builder);
defineNoOpNodeSetters(builder);
builder.addAttribute("highp uvec2", "aVertexIndex");
builder.addUniform("highp float", "uLineWidth");
let vertexMain = `
highp vec3 vertexA = readAttribute0(aVertexIndex.x);
highp vec3 vertexB = readAttribute0(aVertexIndex.y);
emitLine(uProjection, vertexA, vertexB, uLineWidth);
highp uint lineEndpointIndex = getLineEndpointIndex();
highp uint vertexIndex = aVertexIndex.x * (1u - lineEndpointIndex) + aVertexIndex.y * lineEndpointIndex;
`;

builder.addFragmentCode(`
vec4 segmentColor() {
return uColor;
builder.addUniform("highp float", "uNodeDiameter");
builder.addVarying("vec4", "vColor");
builder.addVertexCode(glsl_COLORMAPS);
builder.addVertexCode(glsl_modelToPixels);
builder.addVertexCode(`
float modelToPixels(float value) {
vec2 lineOffset = getLineOffset();
highp vec3 vertexA = readAttribute0(aVertexIndex.x);
highp vec3 vertexB = readAttribute0(aVertexIndex.y);
highp vec3 vertex = mix(vertexA, vertexB, lineOffset.x);
return value * modelToPixels(vertex, uProjection, uViewModel, 1.0 / uLineParams.x);
}
float ng_lineWidth;
void setLineWidth(float width) {
ng_lineWidth = width;
}
void emitRGB(vec3 color) {
emit(vec4(color * uColor.a, uColor.a * getLineAlpha() * ${this.getCrossSectionFadeFactor()}), uPickID);
vColor = vec4(color.rgb, uColor.a);
}
void emitRGBA(vec4 color) {
vColor = color;
}
void emitDefault() {
emit(vec4(uColor.rgb, uColor.a * getLineAlpha() * ${this.getCrossSectionFadeFactor()}), uPickID);
emitRGBA(uColor);
}
`);
builder.addFragmentCode(glsl_COLORMAPS);
let vertexMain = `
highp vec3 vertexA = readAttribute0(aVertexIndex.x);
highp vec3 vertexB = readAttribute0(aVertexIndex.y);
highp uint lineEndpointIndex = getLineEndpointIndex();
highp uint vertexIndex = aVertexIndex.x * (1u - lineEndpointIndex) + aVertexIndex.y * lineEndpointIndex;
setLineWidth(uLineWidth);
`;
const { vertexAttributes } = this;
const numAttributes = vertexAttributes.length;
for (let i = 1; i < numAttributes; ++i) {
const info = vertexAttributes[i];
builder.addVarying(`highp ${info.glslDataType}`, `vCustom${i}`);
vertexMain += `vCustom${i} = readAttribute${i}(vertexIndex);\n`;
builder.addFragmentCode(`#define ${info.name} vCustom${i}\n`);
builder.addFragmentCode(
`#define prop_${info.name}() vCustom${i}\n`,
);
builder.addVertexCode(`#define ${info.name} vCustom${i}\n`);
builder.addVertexCode(`#define prop_${info.name}() vCustom${i}\n`);
}
vertexMain += `
userMain();
emitLine(uProjection * uViewModel, vertexA, vertexB, ng_lineWidth);
`;
builder.setVertexMain(vertexMain);
addControlsToBuilder(shaderBuilderState, builder);
builder.setFragmentMainFunction(
shaderCodeWithLineDirective(shaderBuilderState.parseResult.code),
builder.addVertexCode(
"\n#define main userMain\n" +
shaderCodeWithLineDirective(shaderBuilderState.parseResult.code) +
"\n#undef main\n",
);
builder.setFragmentMain(`
emit(vec4(vColor.rgb, vColor.a * getLineAlpha() * ${this.getCrossSectionFadeFactor()}), uPickID);
`);
},
},
);
Expand Down Expand Up @@ -233,45 +269,61 @@ void emitDefault() {
builder,
/*crossSectionFade=*/ this.targetIsSliceView,
);
defineNoOpEdgeSetters(builder);
builder.addUniform("highp float", "uNodeDiameter");
let vertexMain = `
highp uint vertexIndex = uint(gl_InstanceID);
highp vec3 vertexPosition = readAttribute0(vertexIndex);
emitCircle(uProjection * vec4(vertexPosition, 1.0), uNodeDiameter, 0.0);
`;

builder.addFragmentCode(`
vec4 segmentColor() {
return uColor;
builder.addUniform("highp float", "uLineWidth");
builder.addVarying("vec4", "vColor");
builder.addVertexCode(glsl_COLORMAPS);
builder.addVertexCode(glsl_modelToPixels);
builder.addVertexCode(`
float modelToPixels(float value) {
highp uint vertexIndex = uint(gl_InstanceID);
highp vec3 vertexPosition = readAttribute0(vertexIndex);
return value * modelToPixels(vertexPosition, uProjection, uViewModel, 1.0 / uCircleParams.x);
}
void emitRGBA(vec4 color) {
vec4 borderColor = color;
emit(getCircleColor(color, borderColor), uPickID);
float ng_nodeDiameter;
void setNodeDiameter(float size) {
ng_nodeDiameter = size;
}
void emitRGB(vec3 color) {
emitRGBA(vec4(color, 1.0));
vColor = vec4(color.rgb, uColor.a);
}
void emitRGBA(vec4 color) {
vColor = color;
}
void emitDefault() {
emitRGBA(uColor);
}
`);
builder.addFragmentCode(glsl_COLORMAPS);
let vertexMain = `
highp uint vertexIndex = uint(gl_InstanceID);
highp vec3 vertexPosition = readAttribute0(vertexIndex);
setNodeDiameter(uNodeDiameter);
`;
const { vertexAttributes } = this;
const numAttributes = vertexAttributes.length;
for (let i = 1; i < numAttributes; ++i) {
const info = vertexAttributes[i];
builder.addVarying(`highp ${info.glslDataType}`, `vCustom${i}`);
vertexMain += `vCustom${i} = readAttribute${i}(vertexIndex);\n`;
builder.addFragmentCode(`#define ${info.name} vCustom${i}\n`);
builder.addFragmentCode(
`#define prop_${info.name}() vCustom${i}\n`,
);
builder.addVertexCode(`#define ${info.name} vCustom${i}\n`);
builder.addVertexCode(`#define prop_${info.name}() vCustom${i}\n`);
}
vertexMain += `
userMain();
emitCircle(uProjection * uViewModel * vec4(vertexPosition, 1.0), ng_nodeDiameter, 0.0);
`;
builder.setVertexMain(vertexMain);
addControlsToBuilder(shaderBuilderState, builder);
builder.setFragmentMainFunction(
shaderCodeWithLineDirective(shaderBuilderState.parseResult.code),
builder.addVertexCode(
"\n#define main userMain\n" +
shaderCodeWithLineDirective(shaderBuilderState.parseResult.code) +
"\n#undef main\n",
);
builder.setFragmentMain(`
vec4 borderColor = vColor;
emit(getCircleColor(vColor, borderColor), uPickID);
`);
},
},
);
Expand Down Expand Up @@ -318,9 +370,10 @@ void emitDefault() {
renderContext: SliceViewPanelRenderContext | PerspectiveViewRenderContext,
modelMatrix: mat4,
) {
const { viewProjectionMat } = renderContext.projectionParameters;
const mat = mat4.multiply(tempMat2, viewProjectionMat, modelMatrix);
gl.uniformMatrix4fv(shader.uniform("uProjection"), false, mat);
const { viewMatrix, projectionMat } = renderContext.projectionParameters;
const viewModelMat = mat4.multiply(tempMat2, viewMatrix, modelMatrix);
gl.uniformMatrix4fv(shader.uniform("uProjection"), false, projectionMat);
gl.uniformMatrix4fv(shader.uniform("uViewModel"), false, viewModelMat);
this.vertexIdHelper.enable();
}

Expand Down Expand Up @@ -427,7 +480,7 @@ export class SkeletonRenderingOptions implements Trackable {
return this.compound.changed;
}

shader = makeTrackableFragmentMain(DEFAULT_FRAGMENT_MAIN);
shader = makeTrackableFragmentMain(DEFAULT_VERTEX_MAIN);
shaderControlState = new ShaderControlState(this.shader);
params2d: ViewSpecificSkeletonRenderingOptions = {
mode: new TrackableSkeletonRenderMode(SkeletonRenderMode.LINES_AND_POINTS),
Expand Down Expand Up @@ -477,7 +530,7 @@ export class SkeletonLayer extends RefCounted {
private sharedObject: SegmentationLayerSharedObject;
vertexAttributes: VertexAttributeRenderInfo[];
fallbackShaderParameters = new WatchableValue(
getFallbackBuilderState(parseShaderUiControls(DEFAULT_FRAGMENT_MAIN)),
getFallbackBuilderState(parseShaderUiControls(DEFAULT_VERTEX_MAIN)),
);

get visibility() {
Expand Down
15 changes: 15 additions & 0 deletions src/webgl/shader_lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,21 @@ highp int subtractSaturate(highp int x, highp uint y) {
`,
];

export const glsl_modelToPixels = `
float modelToPixels(highp vec3 vertex, mat4 projection, mat4 viewModel, float projectionWidthPixels) {
float viewDistance = 1.0;
vec4 vertexViewOrigin = viewModel * vec4(vertex, 1.0);
vec4 vertexViewOffset = vertexViewOrigin + vec4(viewDistance, 0.0, 0.0, 0.0);
vec4 vertexClipOrigin = projection * vertexViewOrigin;
vec4 vertexClipOffset = projection * vertexViewOffset;
float projectionDistancePixels = abs(vertexClipOrigin.x - vertexClipOffset.x) * projectionWidthPixels;
float viewModalScale = length(viewModel[0].xyz);
float projectionScale = projectionDistancePixels / viewDistance;
float perspectiveScale = 1.0 / vertexClipOrigin.w;
return viewModalScale * projectionScale * perspectiveScale;
}
`;

export function getShaderType(dataType: DataType, numComponents = 1) {
switch (dataType) {
case DataType.FLOAT32:
Expand Down
Loading