mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 20:48:12 +08:00
alpha blending fix in scatterplots (#2033)
* explicitly specify alpha blending; rename NaN flag to accurately describe function * fix incorret dest alpha blending function
This commit is contained in:
@@ -14,7 +14,7 @@ export default function drawPointsRegl(regl) {
|
|||||||
uniform float nPoints;
|
uniform float nPoints;
|
||||||
uniform float minViewportDimension;
|
uniform float minViewportDimension;
|
||||||
|
|
||||||
varying vec4 fragColor;
|
varying lowp vec4 fragColor;
|
||||||
|
|
||||||
const float zBottom = 0.99;
|
const float zBottom = 0.99;
|
||||||
const float zMiddle = 0.;
|
const float zMiddle = 0.;
|
||||||
@@ -27,23 +27,23 @@ export default function drawPointsRegl(regl) {
|
|||||||
${glPointSize}
|
${glPointSize}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
bool isNaN, isSelected, isHighlight;
|
bool isBackground, isSelected, isHighlight;
|
||||||
getFlags(flag, isNaN, isSelected, isHighlight);
|
getFlags(flag, isBackground, isSelected, isHighlight);
|
||||||
|
|
||||||
float size = pointSize(nPoints, minViewportDimension, isSelected, isHighlight);
|
float size = pointSize(nPoints, minViewportDimension, isSelected, isHighlight);
|
||||||
gl_PointSize = size * pow(distance, 0.5);
|
gl_PointSize = size * pow(distance, 0.5);
|
||||||
|
|
||||||
float z = isNaN ? zBottom : (isHighlight ? zTop : zMiddle);
|
float z = isBackground ? zBottom : (isHighlight ? zTop : zMiddle);
|
||||||
vec3 xy = projView * vec3(position, 1.);
|
vec3 xy = projView * vec3(position, 1.);
|
||||||
gl_Position = vec4(xy.xy, z, 1.);
|
gl_Position = vec4(xy.xy, z, 1.);
|
||||||
|
|
||||||
float alpha = isNaN ? 0.9 : 1.0;
|
float alpha = isBackground ? 0.9 : 1.0;
|
||||||
fragColor = vec4(color, alpha);
|
fragColor = vec4(color, alpha);
|
||||||
}`,
|
}`,
|
||||||
|
|
||||||
frag: `
|
frag: `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
varying vec4 fragColor;
|
varying lowp vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
|
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
|
||||||
discard;
|
discard;
|
||||||
@@ -67,5 +67,15 @@ export default function drawPointsRegl(regl) {
|
|||||||
count: regl.prop("count"),
|
count: regl.prop("count"),
|
||||||
|
|
||||||
primitive: "points",
|
primitive: "points",
|
||||||
|
|
||||||
|
blend: {
|
||||||
|
enable: true,
|
||||||
|
func: {
|
||||||
|
srcRGB: "src alpha",
|
||||||
|
srcAlpha: 1,
|
||||||
|
dstRGB: 0,
|
||||||
|
dstAlpha: "zero",
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ import CentroidLabels from "./overlays/centroidLabels";
|
|||||||
import actions from "../../actions";
|
import actions from "../../actions";
|
||||||
import renderThrottle from "../../util/renderThrottle";
|
import renderThrottle from "../../util/renderThrottle";
|
||||||
|
|
||||||
|
import {
|
||||||
|
flagBackground,
|
||||||
|
flagSelected,
|
||||||
|
flagHighlight,
|
||||||
|
} from "../../util/glHelpers";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Simple 2D transforms control all point painting. There are three:
|
Simple 2D transforms control all point painting. There are three:
|
||||||
* model - convert from underlying per-point coordinate to a layout.
|
* model - convert from underlying per-point coordinate to a layout.
|
||||||
@@ -62,10 +68,6 @@ function createModelTF() {
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
const flagSelected = 1;
|
|
||||||
const flagNaN = 2;
|
|
||||||
const flagHighlight = 4;
|
|
||||||
|
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
annoMatrix: state.annoMatrix,
|
annoMatrix: state.annoMatrix,
|
||||||
crossfilter: state.obsCrossfilter,
|
crossfilter: state.obsCrossfilter,
|
||||||
@@ -159,8 +161,9 @@ class Graph extends React.Component {
|
|||||||
const flags = new Float32Array(nObs);
|
const flags = new Float32Array(nObs);
|
||||||
if (colorByData) {
|
if (colorByData) {
|
||||||
for (let i = 0, len = flags.length; i < len; i += 1) {
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
if (!Number.isFinite(colorByData[i])) {
|
const val = colorByData[i];
|
||||||
flags[i] = flagNaN;
|
if (typeof val === "number" && !Number.isFinite(val)) {
|
||||||
|
flags[i] = flagBackground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default function drawPointsRegl(regl) {
|
|||||||
uniform float nPoints;
|
uniform float nPoints;
|
||||||
uniform float minViewportDimension;
|
uniform float minViewportDimension;
|
||||||
|
|
||||||
varying vec4 fragColor;
|
varying lowp vec4 fragColor;
|
||||||
|
|
||||||
const float zBottom = 0.99;
|
const float zBottom = 0.99;
|
||||||
const float zMiddle = 0.;
|
const float zMiddle = 0.;
|
||||||
@@ -26,22 +26,22 @@ export default function drawPointsRegl(regl) {
|
|||||||
${glPointSize}
|
${glPointSize}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
bool isNaN, isSelected, isHighlight;
|
bool isBackground, isSelected, isHighlight;
|
||||||
getFlags(flag, isNaN, isSelected, isHighlight);
|
getFlags(flag, isBackground, isSelected, isHighlight);
|
||||||
|
|
||||||
gl_PointSize = pointSize(nPoints, minViewportDimension, isSelected, isHighlight);
|
gl_PointSize = pointSize(nPoints, minViewportDimension, isSelected, isHighlight);
|
||||||
|
|
||||||
float z = isNaN ? zBottom : (isHighlight ? zTop : zMiddle);
|
float z = isBackground ? zBottom : (isHighlight ? zTop : zMiddle);
|
||||||
vec3 xy = projection * vec3(position, 1.);
|
vec3 xy = projection * vec3(position, 1.);
|
||||||
gl_Position = vec4(xy.xy, z, 1.);
|
gl_Position = vec4(xy.xy, z, 1.);
|
||||||
|
|
||||||
float alpha = isNaN ? 0.9 : 1.0;
|
float alpha = isBackground ? 0.9 : 1.0;
|
||||||
fragColor = vec4(color, alpha);
|
fragColor = vec4(color, alpha);
|
||||||
}`,
|
}`,
|
||||||
|
|
||||||
frag: `
|
frag: `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
varying vec4 fragColor;
|
varying lowp vec4 fragColor;
|
||||||
void main() {
|
void main() {
|
||||||
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
|
if (length(gl_PointCoord.xy - 0.5) > 0.5) {
|
||||||
discard;
|
discard;
|
||||||
@@ -64,5 +64,15 @@ export default function drawPointsRegl(regl) {
|
|||||||
count: regl.prop("count"),
|
count: regl.prop("count"),
|
||||||
|
|
||||||
primitive: "points",
|
primitive: "points",
|
||||||
|
|
||||||
|
blend: {
|
||||||
|
enable: true,
|
||||||
|
func: {
|
||||||
|
srcRGB: "src alpha",
|
||||||
|
srcAlpha: 1,
|
||||||
|
dstRGB: 0,
|
||||||
|
dstAlpha: "zero",
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,11 @@ import {
|
|||||||
createColorQuery,
|
createColorQuery,
|
||||||
} from "../../util/stateManager/colorHelpers";
|
} from "../../util/stateManager/colorHelpers";
|
||||||
import renderThrottle from "../../util/renderThrottle";
|
import renderThrottle from "../../util/renderThrottle";
|
||||||
|
import {
|
||||||
const flagSelected = 1;
|
flagBackground,
|
||||||
const flagNaN = 2;
|
flagSelected,
|
||||||
const flagHighlight = 4;
|
flagHighlight,
|
||||||
|
} from "../../util/glHelpers";
|
||||||
|
|
||||||
function createProjectionTF(viewportWidth, viewportHeight) {
|
function createProjectionTF(viewportWidth, viewportHeight) {
|
||||||
/*
|
/*
|
||||||
@@ -135,8 +136,9 @@ class Scatterplot extends React.PureComponent {
|
|||||||
const flags = new Float32Array(nObs);
|
const flags = new Float32Array(nObs);
|
||||||
if (colorByData) {
|
if (colorByData) {
|
||||||
for (let i = 0, len = flags.length; i < len; i += 1) {
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
if (!Number.isFinite(colorByData[i])) {
|
const val = colorByData[i];
|
||||||
flags[i] = flagNaN;
|
if (typeof val === "number" && !Number.isFinite(val)) {
|
||||||
|
flags[i] = flagBackground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,24 @@ PointFlags:
|
|||||||
|
|
||||||
We want a bitmask-like flag structure, but due to webgl limitations
|
We want a bitmask-like flag structure, but due to webgl limitations
|
||||||
must emulate it with floats.
|
must emulate it with floats.
|
||||||
|
|
||||||
|
Supported flags are:
|
||||||
|
|
||||||
|
selected: the point is currently selected
|
||||||
|
highlight: the point is currently highlighted
|
||||||
|
background: the point is background information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// for JS
|
// for JS
|
||||||
export const flagSelected = 1;
|
export const flagSelected = 1;
|
||||||
export const flagNaN = 2;
|
export const flagBackground = 2;
|
||||||
export const flagHighlight = 4;
|
export const flagHighlight = 4;
|
||||||
|
|
||||||
// for GLSL
|
// for GLSL
|
||||||
export const glPointFlags = `
|
export const glPointFlags = `
|
||||||
|
|
||||||
const float flagSelected = 1.;
|
const float flagSelected = 1.;
|
||||||
const float flagNaN = 2.;
|
const float flagBackground = 2.;
|
||||||
const float flagHighlight = 4.;
|
const float flagHighlight = 4.;
|
||||||
|
|
||||||
bool isLowBitSet(float f) {
|
bool isLowBitSet(float f) {
|
||||||
@@ -32,12 +38,12 @@ export const glPointFlags = `
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getFlags(in float flag,
|
void getFlags(in float flag,
|
||||||
out bool isNaN,
|
out bool isBackground,
|
||||||
out bool isSelected,
|
out bool isSelected,
|
||||||
out bool isHighlight) {
|
out bool isHighlight) {
|
||||||
isSelected = isLowBitSet(flag);
|
isSelected = isLowBitSet(flag);
|
||||||
flag = shiftRightOne(flag);
|
flag = shiftRightOne(flag);
|
||||||
isNaN = isLowBitSet(flag);
|
isBackground = isLowBitSet(flag);
|
||||||
flag = shiftRightOne(flag);
|
flag = shiftRightOne(flag);
|
||||||
isHighlight = isLowBitSet(flag);
|
isHighlight = isLowBitSet(flag);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user