am using ActiViz / VTK 9.5 in a .NET desktop application for large point-cloud visualization. I am trying to implement fast class visibility toggling for LAS-style classification data.
Current data model:
-
vtkPolyData
-
vtkPointGaussianMapper
-
point arrays:
-
Classification as vtkUnsignedCharArray
-
RGB as vtkUnsignedCharArray
-
Elevation as vtkFloatArray
-
Intensity
-
-
display modes: Classification, RGB, Elevation, Intensity
The goal is to toggle visibility by class without rebuilding a per-point visibility mask for large datasets.
What Works
This works visually, but appears to take time on large datasets because VTK likely remaps opacity per point:
mapper.SetOpacityArray(“Classification”)
mapper.SetOpacityArrayComponent(0)
mapper.SetOpacityTableSize(256)
Dim pwf = vtkPiecewiseFunction.[New]()
pwf.ClampingOn()
For i = 0 To 255
Dim alpha As Double = If(classVisible(i), 1.0, 0.0)
pwf.AddPoint(CDbl(i), alpha)
Next
mapper.SetScalarOpacityFunction(pwf)
Dim mi = mapper.GetType().GetMethod(“SetUseOpacityArray”)
If mi IsNot Nothing Then mi.Invoke(mapper, New Object() {True})
This correctly preserves RGB/elevation/intensity coloring while using Classification as opacity. However, with large datasets, class toggling is not instant.
Attempt 1: Classification LUT Alpha
This worked only when display mode was Classification:
Dim lut = vtkLookupTable.[New]()
lut.SetNumberOfTableValues(256)
lut.SetTableRange(0.0, 255.0)
lut.Build()
For cid = 0 To 255
Dim alpha = If(classVisible(cid), 1.0, 0.0)
lut.SetTableValue(cid, r, g, b, alpha)
Next
mapper.SetScalarModeToUsePointFieldData()
mapper.SetColorModeToMapScalars()
mapper.ColorByArrayComponent(“Classification”, 0)
mapper.SetLookupTable(lut)
This does not help RGB/elevation/intensity modes because color scalar is no longer Classification.
Attempt 2: Shader Replacement
I tried mapping Classification as a vertex attribute and using a fragment shader uniform table:
mapper.MapDataArrayToVertexAttribute(
"aplcClassAttr",
"Classification",
vtkDataObject.FieldAssociations.FIELD_ASSOCIATION_POINTS,
-1)
Dim sp = actor.GetShaderProperty()
sp.AddVertexShaderReplacement(“//VTK::System::Dec”, False,
"in float aplcClassAttr;
out float aplcClassId;", False)
sp.AddVertexShaderReplacement(“//VTK::Normal::Impl”, False,
" aplcClassId = aplcClassAttr;", False)
sp.AddFragmentShaderReplacement(“//VTK::System::Dec”, False,
"in float aplcClassId;
uniform int uAplcClassVisEnabled;
uniform float uAplcClassVis[256];", False)
sp.AddFragmentShaderReplacement(“//VTK::Color::Impl”, False,
" if (uAplcClassVisEnabled != 0) {
int cid = int(clamp(floor(aplcClassId + 0.5), 0.0, 255.0));
if (uAplcClassVis\[cid\] < 0.5) { discard; }
}", False)
Uniform upload:
Dim values(255) As Single
For i = 0 To 255
values(i) = If(classVisible(i), 1.0F, 0.0F)
Next
Dim handle = GCHandle.Alloc(values, GCHandleType.Pinned)
Try
Dim fu = sp.GetFragmentCustomUniforms()
fu.SetUniformi("uAplcClassVisEnabled", 1)
fu.SetUniform1fv("uAplcClassVis", values.Length, handle.AddrOfPinnedObject())
fu.Modified()
sp.Modified()
Finally
handle.Free()
End Try
This compiles, but the render view becomes blank.