Skip to content

Commit 3d514b4

Browse files
authored
fix(core): render volume viewports without float-linear filtering (#2810)
1 parent c547b4a commit 3d514b4

3 files changed

Lines changed: 68 additions & 5 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Returns whether the current WebGL context can linearly sample a float
3+
* opacity texture.
4+
*
5+
* WebGL2 includes float textures, but linear filtering of those textures is
6+
* still gated by OES_texture_float_linear. In WebGL1, both extensions are
7+
* required.
8+
*/
9+
export default function canUseFloatOpacityTexture(openGLRenderWindow, context) {
10+
const supportsFloatTextures =
11+
openGLRenderWindow.getWebgl2() ||
12+
Boolean(context.getExtension('OES_texture_float'));
13+
const supportsFloatLinearFiltering = Boolean(
14+
context.getExtension('OES_texture_float_linear')
15+
);
16+
17+
return supportsFloatTextures && supportsFloatLinearFiltering;
18+
}

packages/core/src/RenderingEngine/vtkClasses/vtkStreamingOpenGLVolumeMapper.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getTransferFunctionsHash } from '@kitware/vtk.js/Rendering/OpenGL/Rende
88
import { Representation } from '@kitware/vtk.js/Rendering/Core/Property/Constants';
99
import { BlendMode } from '@kitware/vtk.js/Rendering/Core/VolumeMapper/Constants';
1010
import { getCanUseNorm16Texture } from '../../init';
11+
import canUseFloatOpacityTexture from './canUseFloatOpacityTexture';
1112

1213
/**
1314
* vtkStreamingOpenGLVolumeMapper - A derived class of the core vtkOpenGLVolumeMapper class.
@@ -211,11 +212,7 @@ function vtkStreamingOpenGLVolumeMapper(publicAPI, model) {
211212
// for this table. Errors in low values of opacity accumulate to
212213
// visible artifacts. High values of opacity quickly terminate without
213214
// artifacts.
214-
if (
215-
model._openGLRenderWindow.getWebgl2() ||
216-
(model.context.getExtension('OES_texture_float') &&
217-
model.context.getExtension('OES_texture_float_linear'))
218-
) {
215+
if (canUseFloatOpacityTexture(model._openGLRenderWindow, model.context)) {
219216
newOpacityTexture.create2DFromRaw({
220217
width: oWidth,
221218
height: 2 * numIComps,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import canUseFloatOpacityTexture from '../src/RenderingEngine/vtkClasses/canUseFloatOpacityTexture';
2+
3+
function createContext(supportedExtensions) {
4+
return {
5+
getExtension: jest.fn((name) =>
6+
supportedExtensions.includes(name) ? {} : null
7+
),
8+
};
9+
}
10+
11+
function createRenderWindow(webgl2) {
12+
return {
13+
getWebgl2: jest.fn(() => webgl2),
14+
};
15+
}
16+
17+
describe('canUseFloatOpacityTexture', () => {
18+
it('rejects a WebGL2 float texture without float-linear filtering', () => {
19+
const renderWindow = createRenderWindow(true);
20+
const context = createContext([]);
21+
22+
expect(canUseFloatOpacityTexture(renderWindow, context)).toBe(false);
23+
});
24+
25+
it('accepts a WebGL2 float texture with float-linear filtering', () => {
26+
const renderWindow = createRenderWindow(true);
27+
const context = createContext(['OES_texture_float_linear']);
28+
29+
expect(canUseFloatOpacityTexture(renderWindow, context)).toBe(true);
30+
});
31+
32+
it('accepts WebGL1 only when both float extensions are available', () => {
33+
const renderWindow = createRenderWindow(false);
34+
const context = createContext([
35+
'OES_texture_float',
36+
'OES_texture_float_linear',
37+
]);
38+
39+
expect(canUseFloatOpacityTexture(renderWindow, context)).toBe(true);
40+
});
41+
42+
it('rejects WebGL1 when either float extension is unavailable', () => {
43+
const renderWindow = createRenderWindow(false);
44+
const context = createContext(['OES_texture_float_linear']);
45+
46+
expect(canUseFloatOpacityTexture(renderWindow, context)).toBe(false);
47+
});
48+
});

0 commit comments

Comments
 (0)