Perspective and STLs: how to create thinning edges along a 3D shape?

5 views (last 30 days)
Hello kind people, I'm trying to create a program that uploads a STL image of a 3D object, have the user rotate the shape to whatever perspective, and then have it output a 2D image of that rotated shape. The catch here is that I want the lines closest to the viewpoint to be thick, and gradually thin out the farther away the edge is from the viewpoint.
I've put in a few basic GUI's guiding the user to upload the file and coded the lighting such that it would accomodate each time the user rotated the image.
I'm basically looking for a function to detect all vertices of the STL, detect the distance from the camera viewpoint, and then somehow create a thick to thin line gradient along the edges such that those edges closest to the camera are thickest and those farthest from the camera are thinnest.
%%Begin GUI
% --- Executes on button press in pushbutton1.
function x = Program()
Button1 = questdlg ('Specify image file?');
switch Button1
case 'Yes'
I = uigetfile ('*.stl*', 'Specify 3D image file');
figure
fv = stlread (I);
patch(fv,'FaceColor', [0.8 0.8 1.0], ...
'EdgeColor', 'none', ...
'FaceColor', [0.5,0.5,0.5], ...
'FaceLighting', 'flat', ...
'EdgeLighting', 'flat', ...
'AmbientStrength', 0.8);
h1 = rotate3d;
h1.ActionPostCallback = @onOrbit;
% Add a camera light, and tone down the specular highlighting
h2 = camlight('headlight');
material('dull');
% Fix the axes scaling, and set a nice view angle
axis('image');
view([-135 35]);
case 'No'
disp ('Operation terminated')
end
function onOrbit(obj,event_obj)
% obj handle to the figure that has been clicked on
% event_obj object containing struct of event data (same as the
% event data of the 'ActionPreCallback' callback)
camlight(h2,'left');
Button2 = questdlg ('Finalize image?');
switch Button2
case 'Yes'
%create function here that thins outermost edges to two pixels
%and maps the closest edges to ten pixels and gradually thins
%them out. The farther away from the camera the edges are, the
%thinner they should be. The edges closest to the camera face
%should be ten pixels and farthest away should be two pixels.
%This will probably require detecting all the vertices and
%defining vertices closest and farthest from the camera face.
%Then, defining edge thickness at intervals away from the
%camera face.
%capture 2d image of rotated 3d figure
fr=getframe(gcf); %need to capture frame of rotated image
%without axes
img=frame2im(fr);
imagesc(img); % <- or imagesc(ff.cdata);
assignin ('base', 'frameshot', img);
%Below is the code to thin a png image to one pixel:
% b= bwmorph(im2bw(-rgb2gray(im2double(frameshot))+1,0.5),'thin'...
% ,Inf);imagesc(frameshot)
disp ('Image finalized')
%Below is the code to enter in an image name and save
%data from a function to the workspace. This is not
%quite right yet.
%Button3 = uiputfile ('Specify folder to save')
% prompt = {'Enter image name:'};
% title = 'Image display - assignin';
% lines = 1;
% def = {};
% answer = inputdlg(prompt, title, lines, def);
% assignin('base', {}, fv);
case 'No'
disp ('Operation terminated')
end
end
end

Accepted Answer

Ahmet Cecen
Ahmet Cecen on 31 May 2016
Simply writing:
R = view;
will yield a proper rotation matrix for the current view like:
0.4384 0.8988 0 -0.6686
-0.5534 0.2699 0.7880 -0.2523
-0.7083 0.3454 -0.6157 9.1495
0 0 0 1.0000
In theory, the following multiplication should yield what you are looking for:
scores = fv.vertices * R;
where the z component of scores should now give you the distance from the viewer. (In theory, don't have time to test.) We probably can't do this on a continuous basis, but you can group the vertices into say 10 bins, where the closest 10% is in bin 1, next 10% is in bin 2 etc. Then you can call patch(or maybe even line) 10 times to create the image wrapping in a for loop like:
for i=1:10
STUFF PLOT STUFF
patch(fv, ...,'LineWidth',i)
MORE STUFF
end
  2 Comments
Andrea Nguyen
Andrea Nguyen on 1 Jun 2016
score = fv.vertices * R yields "error using * inner matrix dimensions must agree"
which somehow only gives me the separate faces and vertices of each triangle from the STL format. It seems like fv.vertices should be using the normal vertices, but I can't find that in the output for the STL file reader linked above.
In theory, this all makes sense and will probably help a lot once I figure out how to get the normal vertices shown. Thanks!
Ahmet Cecen
Ahmet Cecen on 1 Jun 2016
Well you need to do vertices*R(1:3,1:3) to jump from the generalized matrix to 3d rotation. Vertices just needs to be x y z coordinates each row.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!