MATLAB Answers

3D point clouds with variable marker transparency, color and size

45 views (last 30 days)
Tim
Tim on 23 Dec 2019
Edited: Tim on 14 Feb 2020
I would like to make 3D point clouds in which the markers have variable color, transparency and/or marker size. I would like to do this in one function call, because it seems like Matlab can have some strange occlusion issues if multiple point-clouds are combined via a loop and the viewpoint is changed.
I have tried using the hidden MarkerHandle settings as described here and it works brilliantly with the exception that transparency is only binary for markers of the '.' type (i.e. the only alpha value that affects the graph is 0, in which case the point is un-rendered), unless the marker size is > 15, in which it seems that a different openGL primitive may be used. To get small points with variable transparency one can use e.g. 'o', and set EdgeColorType/Binding/Data and FaceColorType/Binding/Data appropriately.
In both cases, however, if the number of points >25,000 then rotating, zooming or scaling the figure resets the marker handles on-the-fly which makes it impossible to interact with the point cloud while maintaining the custom markerhandle settings.
Variable markersize could function as an alternative to transparency but I don't see how to do that with a single function call, and in any case the marker handle resetting still causes problems for interactive data exploration for large point clouds. Any pointers on how to accomplish this?

  5 Comments

Show 2 older comments
Tim
Tim on 23 Dec 2019
Figured out why that last example using MarkerHandle doesn't work all the time: sometimes the value for H.MarkerHandle.VertexData is less than the passed number of xyz points (???) That's really strange but if you modify as done below it works consistently:
clf
N = 10000;
xyz = randn(N, 3);
clr = ones(N, 3).*rand(1, 3);
for n = 1:4
xyz = [xyz; randn(N, 3)];
clr = [clr; ones(N, 3).*rand(1, 3)];
end
clr = [clr, ones(size(clr, 1), 1)];
H = plot3(xyz(:, 1), xyz(:, 2), xyz(:, 3), '.');
pause(0);
set(H.MarkerHandle,...
'EdgeColorBinding', 'discrete',...
'EdgeColorData',...
uint8(255*clr(1:size(H.MarkerHandle.VertexData, 2), :)'));
Adam Danz
Adam Danz on 24 Dec 2019
The layering of colors in the first of your demos above is to be expected. You're plotting the data in layers within a loop and at a very high density. The chances of a point at (x,y,z) overlapping another point at (x0,y0,z0) is very high and since each iteration has it's own color, you're seeing the layers of color change as you change the viewing angle. That's not surprising.
The second and third demo above use undocumented features so I didn't dig too deeply into them.
Tim
Tim on 24 Dec 2019
That's not at all to be expected. If I have two random 3D point clouds normally distributed around the origin, and each distribution has it's own color, I shouldn't see one distribution layered on top of the other. The second version, using MarkerHandles, is how the graph should appear:LoopDemo.PNG

Sign in to comment.

Answers (3)

Yair Altman
Yair Altman on 3 Jan 2020
As an alternative to scatter3, you could keep using plot3 and attach a callback function to the axes that gets invoked whenever the axes is repainted. In this callback function you could reattach the transparency to the ploted points (don't replot - just update the plotted handles' color property/ies). You can attach such a callback in several maners:
  1. The zoom, pan, and rotate3d functions enable setting a callback function that gets invoked whenever they are used. This is fully-documented functionality, but requires you to set the callback seperately in several places.
  2. You can attach the callback to the axes' MarkedClean event, as explained on http://undocumentedmatlab.com/articles/undocumented-hg2-graphics-events
I'm not claiming that this is a better alternative than scatter3, but in cases where you wish to avoid scatter3 (for example, if performance is problematic), then it might be worth checking.

  1 Comment

Tim
Tim on 14 Feb 2020
Thank you for the input, Yair. I didn't realize, when I originally marked this question as answered, that scatter3 doesn't allow the transparency values of points to be independently set on a per-point basis, though it has this functionality with color. As a result I still have to use the MarkerHandle property, (as outlined on your amazing blog) to independently adjust these values for each point. Interestingly, unlike plot3, if scatter3 is used then zoom/pan/rotate can be performed without the transparencies being reset, even if more than 25,000 points are being rendered.
Scatter3 still doesn't solve the problem of correctly rendering multiple point clouds generated from different function calls as demonstrated above (occlusions aren't correct), but it does take care of the difficulty with interacting with larger point clouds for which transparencies of points have been independently defined using MarkerHandle. This seems to me to be a nice under-the-hood increase of functionality in scatter3 vs plot3.

Sign in to comment.


Adam Danz
Adam Danz on 24 Dec 2019
"I would like to make 3D point clouds in which the markers have variable color, transparency and/or marker size. "
I suggest using scatter3() where marker size and marker color can be set for each individual point. Here's a demo that creates a 3D volume of 30k points with varying colors and marker sizes that are defined by the depth of each point along the z-axis. The transparency of all points are set to 0.5.
% Create data (30k 3D points)
n = 30000;
x = rand(1,n)*100;
y = rand(1,n)*100;
z = rand(1,n)*100;
% Define color of each point based on z value
colors = jet(numel(z));
[~, ~, depthIdx] = unique(abs(z));
colorData = colors(depthIdx,:);
% Define size gradient based on z value
dotSize = linspace(10,100,numel(x));
sizeData = dotSize(depthIdx);
% Plot 3D points
scatter3(x,y,z,sizeData,colorData,'filled','o','MarkerEdgeColor','k', ...
'MarkerFaceAlpha',0.5);
grid on
box on
xlabel('x')
ylabel('y')
zlabel('z')
% Choose your viewing angle:
view(0,180) % (x,z) view
view(2) % (x,y) view
view(3) % (x,y,z) view
191224 060821-Figure 1.png

  2 Comments

Tim
Tim on 24 Dec 2019
Yes, I guess I've avoided scatter3 because it isn't as fast as plot3 using the '.' primitive but it does solve the issue of rotating the viewpoint with plots that have markers with variable transparency and size, at least for moderate numbers of scatterers. Incidentally, have you cranked the number of points up to 1,000,000 in your test code above and seen the results? Looks like below, at least on my computer:
In contrast, you can plot >2,000,000 points with multiple colors and proper occlusion using marker handle but the colors reset the moment viewpoint is changed. For example, after initial construction (~2,500,000 points):
After rotating:
(It's fair to ask why someone may want to visualize that many points, but I'm working with point clouds having features at varying scales and the ability to rotate and zoom for data exploration is important)
Adam Danz
Adam Danz on 24 Dec 2019
You can use '.' markers as shown below but you'll want to increase the range of the marker sizes.
% Define size gradient based on z value
dotSize = linspace(10,1000,numel(x));
sizeData = dotSize(depthIdx);
% Plot 3D points
scatter3(x,y,z,sizeData,colorData,'.','MarkerFaceAlpha',0.5);
And yes, it does take some time to render 1-million points with varying colors and sizes but it also solves your problem.

Sign in to comment.


Tim
Tim on 24 Dec 2019
Well, it’s probably the official MATLAB function that comes closest... the scatter3 examples posted above pretty clearly don’t render transparency or layer markers correctly, at least for dense clusters of points. I’ll confess what I’m trying to do is find a MATLAB alternative to PPTK, a fairly buggy OpenGL point cloud renderer with a Python interface that makes fast renderings of large point clouds (>20 million) using primitives that handle transparency. It renders beautifully but has many other problems, and doesn’t interface natively with MATLAB. I’ll mark this answered but I think Scatter3’s rendering needs some improvement.

  4 Comments

Show 1 older comment
Tim
Tim on 27 Dec 2019
Yeah, I have some screenshots here, along with with Matlab. The transparency isn't the problem with scatter3, it works beautifully when it can handle the number of points. Something gets funky with the rendering past a certain number of points though. I've re-ran your posted code but turned the edges off and show the results for n = 30,000 with alpha of 0.2 (top right), 0.5 (middle). Mine seems to render correctly, whereas the version you posted doesn't for some reason... maybe the video card? (I'm using an RTX2070). I cranked the number of points up to 1,000,000 for the bottom right figure which has similar rendering artifacts to your posted result above. PPTK shows results for alpha of 0.2 (top), 0.5 (middle), and for n = 20 millon on the bottom left.
Pex4.PNG
Adam Danz
Adam Danz on 28 Dec 2019
My first two thoughts are
1) use axis equal to equate the aspect ratio across all 3 axes. It seems like that's already being done in the OpenGL version.
2) zoom out a bit by setting the xlim(), ylim(), zlim() so the axis background appears. That's already being done in the OpenGL version, too. It will increase the concentration of the dots.
Here's more info on rendering in Matlab
Tim
Tim on 28 Dec 2019
  • My problem with the rendering is not the axis scaling or point density, it is the problematic rendering of transparency that you can see in, for example, the bottom right figure of the set above (which is absent in all the others). You should not, for example, be seeing any dark blue points near the center of the cloud - they should be occluded by the red layer on top.
  • This problematic rendering seems to occur for different systems above different numbers of points
  • Both renderers (pptk and Matlab) are openGL (Matlab defaults to OpenGL / Hardware supported if it can, and at least in my case it is using openGL with full hardware support)
I thought the problem might be that depthpeeltransparency was flipping off for points above a threshold but for n=1,000,000 rendererinfo() shows that it is indeed still on, even though the rendering is being corrupted, so it is still a mystery to me.

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!