# VTK 9.6.1 regression in edges appearance

**URL:** https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393
**Category:** Development
**Created:** [April 22, 2026, 10:13am UTC](https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393 "2026-04-22T10:13:35Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![CharInt0](https://discourse.vtk.org/user_avatar/discourse.vtk.org/charint0/32/2983_2.png) [@CharInt0](https://discourse.vtk.org/u/CharInt0)
#### Post date: [April 22, 2026, 10:13am UTC](https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393/1 "2026-04-22T10:13:36Z")

</div>

After updating the VTK library in my C++ application (from v. 9.4.2 to .9.6.1), the rendering of some Surfaces shows some unexpected edge artifacts. All is compiled in Release mode. This image is with VTK 9.4.2:

 ![image](https://discourse.vtk.org/uploads/default/original/2X/e/ee119e23b17794aa12421dfd01fa8cbffa83bdff.jpeg)

This with VTK 9.6.1:

 ![image](https://discourse.vtk.org/uploads/default/original/2X/9/9f69a1a1d9ebe154a0f8e76feff24d1bc3103b19.jpeg)

This does not happen on all the surfaces I still haven’t understood the reason. Here is the method with the pipeline that I use for drawing the surface (with some accessory classes/code lines)

```auto
	std::tuple<int, vtkSmartPointer<vtkActor>> Geo3DGrid::draw(int sourceId, const GridProperties& properties)
	{
		auto sourceData = m_sourceDataCollector->getItem(sourceId);

		if (sourceData.get() == nullptr)
		{
			char buff[128];
			snprintf(buff, sizeof(buff), "Source data for id: %d does not exists", sourceId);
			throw std::runtime_error{ buff };
		}

		auto* gridData = static_cast<GridSourceData*>(sourceData.get());
		auto* imageData = vtkImageData::SafeDownCast(gridData->getData()); // Do not get ownership

		vtkNew<vtkExtractVOI> extract_voi;
		extract_voi->SetInputData(imageData);
		extract_voi->SetSampleRate(properties.decimation, properties.decimation, 1);
		extract_voi->UpdateWholeExtent();

		vtkNew<vtkWarpScalar> warp;
		warp->SetInputConnection(extract_voi->GetOutputPort());

		vtkNew<vtkStructuredGridGeometryFilter> geo_filter;
		geo_filter->SetInputConnection(warp->GetOutputPort());

		vtkNew<vtkTriangleFilter> triangle_filter;
		triangle_filter->SetInputConnection(geo_filter->GetOutputPort());

		vtkNew<vtkTriangleMeshPointNormals> poly_data_norm;
		poly_data_norm->SetInputConnection(triangle_filter->GetOutputPort());

		auto* scalarRange = imageData->GetScalarRange();

		vtkNew<vtkPolyDataMapper> mapper;
		mapper->SetInputConnection(poly_data_norm->GetOutputPort());
		mapper->SetScalarRange(scalarRange);

		auto actor = vtkSmartPointer<vtkActor>::New();
		actor->SetMapper(mapper);
		actor->SetUserTransform(m_zTransform);
		actor->GetProperty()->SetOpacity(properties.opacity);
		actor->GetProperty()->SetLighting(properties.lighting);

		colorizeGrid(mapper.GetPointer(), actor.GetPointer(), properties.colorByElevation, properties.colorScaleId, properties.color);

		auto elem = std::make_shared<GridVisualElement>(sourceId, properties, extract_voi.GetPointer());
		elem->addActor(ActorIDs::Grid2D, actor);

		auto id = m_visualElementCollector->addItem(elem);
		elem->setId(id); // Store Visual element id

		return { id, actor };
	}

```

Thank you,

Carlo

---

<div class="post-metadata">

### Author: ![CharInt0](https://discourse.vtk.org/user_avatar/discourse.vtk.org/charint0/32/2983_2.png) [@CharInt0](https://discourse.vtk.org/u/CharInt0)
#### Post date: [April 22, 2026, 1:42pm UTC](https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393/2 "2026-04-22T13:42:51Z")

</div>

I have found the cause of the problem. The black edge is visible only if:

`auto* imageData = vtkImageData::SafeDownCast(gridData->getData());`

is created passing scalars that contain some values set to double.NAN. Otherwise it behaves as before without the black edges.

So it seems that it is not supported anymore or it is a regression in the new VTK .

Carlo

---

<div class="post-metadata">

### Author: ![sankhesh](https://discourse.vtk.org/user_avatar/discourse.vtk.org/sankhesh/32/73_2.png) [@sankhesh](https://discourse.vtk.org/u/sankhesh)
#### Post date: [April 23, 2026, 2:07pm UTC](https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393/3 "2026-04-23T14:07:54Z")

</div>

The behavior of `vtkGeometryFilter` has changed in v9.6.1. Try toggling the `RemoveGhostInterfaces` i.e. in your code → `geo_filter->SetRemoveGhostInterfaces(false);`.

---

<div class="post-metadata">

### Author: ![CharInt0](https://discourse.vtk.org/user_avatar/discourse.vtk.org/charint0/32/2983_2.png) [@CharInt0](https://discourse.vtk.org/u/CharInt0)
#### Post date: [April 23, 2026, 3:19pm UTC](https://discourse.vtk.org/t/vtk-9-6-1-regression-in-edges-appearance/16393/4 "2026-04-23T15:19:49Z")

</div>

Thank you Jhaveri

However I tried it but It seems not to work, either setting `SetRemoveGhostInterfaces(false) or SetRemoveGhostInterfaces(true)`.

In any case I’ve already changed my code and now I use a vtkUnsignedCharArray (I called it “ValidMask”) to keep a mask value for each NAN. I call a method that replace NAN to 0 and the pipeline code is filtering these values using the mask array and removing cells that are invalid (if any masked value is present):

```auto
		auto* gridData = static_cast<GridSourceData*>(sourceData.get());
		auto* imageData = vtkImageData::SafeDownCast(gridData->getData()); // Do not get ownership

		vtkNew<vtkExtractVOI> extract_voi;
		extract_voi->SetInputData(imageData);
		extract_voi->SetSampleRate(properties.decimation, properties.decimation, 1);
		extract_voi->UpdateWholeExtent();

		vtkNew<vtkWarpScalar> warp;
		warp->SetInputConnection(extract_voi->GetOutputPort());

		vtkNew<vtkGeometryFilter> geom;
		geom->SetInputConnection(warp->GetOutputPort());

		// Remove invalid geometry using the ValidMask array
		vtkNew<vtkThreshold> threshold;
		threshold->SetInputConnection(geom->GetOutputPort());
		threshold->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "ValidMask");
		threshold->SetUpperThreshold(0.5);
		threshold->SetThresholdFunction(vtkThreshold::THRESHOLD_UPPER);
		threshold->SetAllScalars(1); // do not keep cells where any of the point is invalid

		// threshold -> unstructured grid -> back to polydata
		vtkNew<vtkGeometryFilter> geom2;
		geom2->SetInputConnection(threshold->GetOutputPort());

		vtkNew<vtkTriangleFilter> triangle_filter;
		triangle_filter->SetInputConnection(geom2->GetOutputPort());

		vtkNew<vtkTriangleMeshPointNormals> poly_data_norm;
		poly_data_norm->SetInputConnection(triangle_filter->GetOutputPort());

		vtkNew<vtkPolyDataMapper> mapper;
		mapper->SetInputConnection(poly_data_norm->GetOutputPort());
		mapper->SetScalarRange(gridData->getZMin(), gridData->getZMax());
		mapper->SetScalarModeToUsePointData();

		auto actor = vtkSmartPointer<vtkActor>::New();
		actor->SetMapper(mapper);
		actor->SetUserTransform(m_zTransform);
		actor->GetProperty()->SetOpacity(properties.opacity);
		actor->GetProperty()->SetLighting(properties.lighting);

```

It is working, although it may be not very optimized because I am duplicating the geometry (geom2).
