diff --git a/Sources/Filters/Core/PolyDataNormals/example/controlPanel.html b/Sources/Filters/Core/PolyDataNormals/example/controlPanel.html
new file mode 100644
index 00000000000..d5b0ca6793f
--- /dev/null
+++ b/Sources/Filters/Core/PolyDataNormals/example/controlPanel.html
@@ -0,0 +1,14 @@
+
diff --git a/Sources/Filters/Core/PolyDataNormals/example/index.js b/Sources/Filters/Core/PolyDataNormals/example/index.js
new file mode 100644
index 00000000000..75256b35463
--- /dev/null
+++ b/Sources/Filters/Core/PolyDataNormals/example/index.js
@@ -0,0 +1,112 @@
+import '@kitware/vtk.js/favicon';
+
+// Load the rendering pieces we want to use (for both WebGL and WebGPU)
+import '@kitware/vtk.js/Rendering/Profiles/Geometry';
+import '@kitware/vtk.js/Rendering/Profiles/Glyph';
+
+import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
+
+import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
+import vtkArrowSource from '@kitware/vtk.js/Filters/Sources/ArrowSource';
+import vtkCubeSource from '@kitware/vtk.js/Filters/Sources/CubeSource';
+import vtkLookupTable from '@kitware/vtk.js/Common/Core/LookupTable';
+import vtkGlyph3DMapper from '@kitware/vtk.js/Rendering/Core/Glyph3DMapper';
+import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
+import vtkPolyDataNormals from '@kitware/vtk.js/Filters/Core/PolyDataNormals';
+
+import controlPanel from './controlPanel.html';
+
+const { ColorMode, ScalarMode } = vtkMapper;
+
+// ----------------------------------------------------------------------------
+// Standard rendering code setup
+// ----------------------------------------------------------------------------
+
+const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
+ background: [0.9, 0.9, 0.9],
+});
+const renderer = fullScreenRenderer.getRenderer();
+const renderWindow = fullScreenRenderer.getRenderWindow();
+
+// ----------------------------------------------------------------------------
+// Example code
+// ----------------------------------------------------------------------------
+
+const lookupTable = vtkLookupTable.newInstance({ hueRange: [0.666, 0] });
+
+const source = vtkCubeSource.newInstance();
+const inputPolyData = source.getOutputData();
+inputPolyData.getPointData().setNormals(null);
+
+const mapper = vtkMapper.newInstance({
+ interpolateScalarsBeforeMapping: true,
+ colorMode: ColorMode.DEFAULT,
+ scalarMode: ScalarMode.DEFAULT,
+ useLookupTableScalarRange: true,
+ lookupTable,
+});
+const actor = vtkActor.newInstance();
+actor.getProperty().setEdgeVisibility(true);
+
+const polyDataNormals = vtkPolyDataNormals.newInstance();
+
+// The generated 'z' array will become the default scalars, so the plane mapper will color by 'z':
+polyDataNormals.setInputData(inputPolyData);
+
+mapper.setInputConnection(polyDataNormals.getOutputPort());
+actor.setMapper(mapper);
+
+renderer.addActor(actor);
+
+const arrowSource = vtkArrowSource.newInstance();
+
+const glyphMapper = vtkGlyph3DMapper.newInstance();
+glyphMapper.setInputConnection(polyDataNormals.getOutputPort());
+glyphMapper.setSourceConnection(arrowSource.getOutputPort());
+glyphMapper.setOrientationModeToDirection();
+glyphMapper.setOrientationArray('Normals');
+glyphMapper.setScaleModeToScaleByMagnitude();
+glyphMapper.setScaleArray('Normals');
+glyphMapper.setScaleFactor(0.1);
+
+const glyphActor = vtkActor.newInstance();
+glyphActor.setMapper(glyphMapper);
+renderer.addActor(glyphActor);
+
+renderer.resetCamera();
+renderWindow.render();
+
+// ----------------------------------------------------------------------------
+// UI control handling
+// ----------------------------------------------------------------------------
+
+fullScreenRenderer.addController(controlPanel);
+
+// Checkbox
+document
+ .querySelector('.computePointNormals')
+ .addEventListener('change', (e) => {
+ polyDataNormals.setComputePointNormals(!!e.target.checked);
+ renderWindow.render();
+ });
+
+document
+ .querySelector('.computeCellNormals')
+ .addEventListener('change', (e) => {
+ polyDataNormals.setComputeCellNormals(!!e.target.checked);
+ renderWindow.render();
+ });
+
+// -----------------------------------------------------------
+// Make some variables global so that you can inspect and
+// modify objects in your browser's developer console:
+// -----------------------------------------------------------
+
+global.mapper = mapper;
+global.actor = actor;
+global.source = source;
+global.renderer = renderer;
+global.renderWindow = renderWindow;
+global.lookupTable = lookupTable;
+global.polyDataNormals = polyDataNormals;
+global.glyphMapper = glyphMapper;
diff --git a/Sources/Rendering/Core/Glyph3DMapper/index.d.ts b/Sources/Rendering/Core/Glyph3DMapper/index.d.ts
index c4a47862838..e76c6e7e2b9 100755
--- a/Sources/Rendering/Core/Glyph3DMapper/index.d.ts
+++ b/Sources/Rendering/Core/Glyph3DMapper/index.d.ts
@@ -1,4 +1,4 @@
-import { Bounds } from "../../../types";
+import { Bounds, vtkPipelineConnection } from "../../../types";
import vtkMapper, { IMapperInitialValues } from "../Mapper";
import { OrientationModes, ScaleModes } from "./Constants";
@@ -87,6 +87,12 @@ export interface vtkGlyph3DMapper extends vtkMapper {
*/
getPrimitiveCount(): IPrimitiveCount;
+ /**
+ * Sets the name of the array to use as orientation.
+ * @param {String} arrayName Name of the array
+ */
+ setOrientationArray(arrayName: Nullable): boolean;
+
/**
* Orientation mode indicates if the OrientationArray provides the direction
* vector for the orientation or the rotations around each axes.
@@ -138,6 +144,13 @@ export interface vtkGlyph3DMapper extends vtkMapper {
* Set scale to `SCALE_BY_CONSTANT`
*/
setScaleModeToScaleByConstant(): boolean;
+
+ /**
+ * Convenient method to set the source glyph connection
+ * @param {vtkPipelineConnection} outputPort The output port of the glyph source.
+ */
+ setSourceConnection(outputPort: vtkPipelineConnection): void;
+
}
/**
diff --git a/Sources/Rendering/Core/Glyph3DMapper/index.js b/Sources/Rendering/Core/Glyph3DMapper/index.js
index 4612ae80c33..a3d9ac232f6 100644
--- a/Sources/Rendering/Core/Glyph3DMapper/index.js
+++ b/Sources/Rendering/Core/Glyph3DMapper/index.js
@@ -134,6 +134,7 @@ function vtkGlyph3DMapper(publicAPI, model) {
model.normalArray = new Float32Array(9 * numPts);
const nbuff = model.normalArray.buffer;
const tuple = [];
+ const orientation = [];
for (let i = 0; i < numPts; ++i) {
const z = new Float32Array(mbuff, i * 64, 16);
trans[0] = pts[i * 3];
@@ -142,7 +143,6 @@ function vtkGlyph3DMapper(publicAPI, model) {
mat4.translate(z, identity, trans);
if (oArray) {
- const orientation = [];
oArray.getTuple(i, orientation);
switch (model.orientationMode) {
case OrientationModes.MATRIX: {
@@ -299,6 +299,9 @@ function vtkGlyph3DMapper(publicAPI, model) {
};
return pcount;
};
+
+ publicAPI.setSourceConnection = (outputPort) =>
+ publicAPI.setInputConnection(outputPort, 1);
}
// ----------------------------------------------------------------------------