### Paper-worthy rendering in MATLAB

Thursday, July 20th, 2017

MATLAB is not a great tool for creating 3D renderings. However, the learning curves for most commercial rendering tools are quite steep. Other tools like Mitsuba can create beautiful pictures, but can feel quite cumbersome for rendering pure geometry rather than the physical scenes their designed for.

Over the years, I’ve developed a way of creating plots of 3D shapes in MATLAB using a few extra functions in gptoolbox. This started as a way to just make images from research prototypes more palatable, but eventually became the usual way that I render images for papers. If the code for my research is already written in MATLAB then one huge advantage is that every image in my paper can have a *.m script that deterministically generates the result and the corresponding image with user intervention. This helps with reproducibility, editing and sharing between collaborators.

Here’s a “VFX Breakdown” of rendering a 3D shape in MATLAB.

t = tsurf(F,V);
set(gcf,'COlor',0.94*[1 1 1]);
teal = [144 216 196]/255;
pink = [254 194 194]/255;
bg_color = pink;
fg_color = teal;
for pass = 1:10
switch pass
case 1
% blank run
axis([-209.4       119.38      -181.24       262.67      -247.28 247.38]);
case 2
axis equal;
axis([-209.4       119.38      -181.24       262.67      -247.28 247.38]);
axis vis3d;
case 3
t.EdgeColor = 'none';
case 4
set(t,fphong,'FaceVertexCData',repmat(fg_color,size(V,1),1));
case 5
set(t,fsoft);
case 6
l = light('Position',[0.2 -0.2 1]);
case 7
set(gca,'Visible','off');
case 8
set(gcf,'Color',bg_color);
case 9
case 10
end

vidObj = VideoWriter(sprintf('nefertiti-%02d.mp4',pass),'MPEG-4');
vidObj.Quality = 100;
vidObj.open;
thetas = linspace(30,-30,450);
for theta = thetas(1:end-1)
view(theta,30);
drawnow;
vidObj.writeVideo(getframe(gcf));
end
vidObj.close;

end


### Matlab’s trisurf confuses face colors with vertex colors

Sunday, July 28th, 2013

I recently had trouble getting matlab’s trisurf to display interpolated colors inside each face. I was calling:


set(trisurf(F,V(:,1),V(:,2),V(:,3)),'FaceColor','interp');


But the display looked like flat shading.

The problem turned out to be that I had 9 faces and 9 vertices. In this rare instance matlab decides that the vertex colors (which actually are just the Z coordinates in V(:,3)) should be attached (incorrectly) to the faces and are not interpolatable.

I hacked a fix to this by appending an extra ghost vertex:


set(trisurf(F,[V(:,1);0],[V(:,2);0],[V(:,3);0]),'FaceColor','interp');


### Isointerval contour plots on triangle meshes in Matlab

Wednesday, February 29th, 2012

Matlab let’s you plot contours of scalar functions defined on grid-surfaces. But this is not easily achieved if you’re working with a triangle mesh. I had previously attempted to achieve this by first resampling the function onto a grid surface and then using Matlab’s built-in contour. This eventually (very slowly) gives you nice contour intervals and isolines separating them, but it makes the boundary of the domain ugly and doesn’t easily extend to 3d surfaces.

But now I’ve found that using the right colormap and the right rendering flags you can get pretty close to that sort of contour plot without the slow resampling step. The trick seems to be using a relatively small colormap and setting the ‘FaceLighting’ flag to ‘phong’ and the ‘FaceColor’ flag to ‘interp’. If your mesh is in V and F and you have some scalar functions in the columns of W then you can render 10 isointervals of alternating green and yellow using:


t = trisurf(F,V(:,1),V(:,2),V(:,3),W(:,5),'EdgeColor','none','FaceColor','interp','FaceLighting','phong');
colormap(repmat([1.0 0.95 0;0.1 0.5 0.2],10/2,1));
light('Position',[-1.0,-1.0,100.0],'Style','infinite');
axis equal;
view(2);


Note: the light command is not necessary to achieve sharp isointervals. But the setting the face “lighting” to ‘phong’ is necessary

And with a little effort, you can achieve something close to isointervals separated by isolines:


% number of isointervals
nin = 8;
M = jet(nin);
% thickness ratio of each isointerval compared to "isoline"
thickness = 10;
MM = reshape(permute(cat(3,repmat(M,[1 1 thickness]),zeros([nin 3 1])),[3 1 2]),nin*thickness + nin,3);
colormap(MM)
colorbar


Or on a 2D mesh without the light call: