Inside a self-written filter (C++) I am applying a “TubeFilter” to some line segments - works fine.
In order to make things perfect, I would like to have some of the tubes appear “round” and others appear “polygonal”. Normally this is achieved by switching shading between “Gouraud” or “Flat”.
Now this is a display property, not normally a job for the geometric part of the code, but still my first attempt was to simply remove the “Normals” attribute from the tube polydata - with the hope that the Gouraud shading would “fail” and leave them polygonal.
No chance - that Gouraud code seems to be too smart!
Or is there still a way how I can turn the effect locally off? At least I see that the “caps” of the tubes are showing quite “angular” transitions to the “round faces”, so somehow it must be possible!? Or is it just a question of an acute angle that is “seen” and then avoided? Not possible: even triangular “tubes” are still rounded, and their angles are even more acute than with the caps!
Another option would go the other way round, but so far I did not succeed either: If there would be some “Hint” to be put into the servermanager XML, like “shading=flat”, in order to simply turn off the Gouraud shading I would also have half the way already. I would then simply increase the number of faces a bit for the “round” tubes" (8 or 10 instead of normally 6 for “round” tubes): this might also look ok already.
Right, the PassArrays filter might be the better option still!
But just realize it might be a bit more complicated anyway, because the setup is the following:
loop over n tube types (with one being round, the others should be angular)
{
lines set (n)
apply Tube filter
if this is not the round case: remove the “Normals” attribute
(so far I did it with “RemoveArray” from the “CellData” of the polydata object)
append the resulting thing to the output polydata with the vtkAppendPolyData filter
}
The complication comes from the vtkAppendPolyData filter: the documentataion says that it will bring together also attributes that exist in ALL the input polydata sets (hmm, what else should it do??).
Meaning that I would lose the Normals also for my “round” data set - and the fact that it does not work so far only shows that I did not do the removal correctly yet…
But once I am doing better I will have the next problem!
Playing with the normals finally did the trick!
However, the Tube filter generates “TubeNormals”, and with the vtkPolyDataNormals filter and edge splitting I can generate “Normals” that will not be “smoothed”, like this (inside a loop that finally puts several such polydata items together, some “rounded”, others not):
vtkSmartPointer<vtkTubeFilter> tube = vtkSmartPointer<vtkTubeFilter>::New();
tube->SetInputData(generateSampling->GetOutput());
tube->SetCapping(true);
tube->SetNumberOfSides(sd);
tube->SetRadius(std::stod((*it1)[2]));
tube->SetOutputPointsPrecision(vtkTubeFilter::DOUBLE_PRECISION);
tube->Update();
if(rounded)
{
// use the TubeNormals attribute, copy into Normals and make "standard normals"
vtkPointData* pData = tube->GetOutput()->GetPointData();
vtkFloatArray* tnArr = vtkFloatArray::SafeDownCast(pData->GetArray("TubeNormals"));
if(nullptr != tnArr)
{
vtkSmartPointer<vtkFloatArray> narr = vtkSmartPointer<vtkFloatArray>::New();
narr->DeepCopy(tnArr);
narr->SetName("Normals");
pData->AddArray(narr);
pData->SetNormals(narr);
}
pd->DeepCopy(tube->GetOutput());
}
else
{
// calculate normals with splitting, to avoid rounding effect
vtkSmartPointer<vtkPolyDataNormals> pnorm = vtkSmartPointer<vtkPolyDataNormals>::New();
pnorm->SetInputData(tube->GetOutput());
pnorm->SetSplitting(true);
pnorm->SetFeatureAngle(10.);
pnorm->Update();
pd->DeepCopy(pnorm->GetOutput());
}