## Posts Tagged ‘lighting’

### 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


### Two-sided material in matlab

Monday, March 23rd, 2015

Unfortunately there seems to be no builtin support for two-sided surfaces in matlab. There’s some rudimentary control over back-face lighting, but that’s all. At least you can determine the back-facing triangles for a given camera position:

N = normals(V,F);
BC = barycenter(V,F);
back_facing = sum(N.*bsxfun(@minus,BC,campos),2)<=0;


Here’s an example for an armadillo mesh:

t = tsurf(F,V,'EdgeColor','none','FaceLighting','phong');view(2);
axis equal;
camproj('persp')
t.FaceVertexCData = 1*(sum(N.*bsxfun(@minus,BC,campos),2)<=0)
apply_ambient_occlusion();


Of course, if you change the view, the coloring is no longer valid:

So you need to recompute the coloring:

You can also insert nans to achieve back-face culling:

t.FaceVertexCData(sum(N.*bsxfun(@minus,BC,campos),2)>0) = nan;


### OpenGL lighting not working, GL_POSITION is in homogenous coordinates

Monday, September 23rd, 2013

A while ago I somehow introduced a bug in my opengl app that occasionally caused my app to render a shaded object without lighting like this:

Now, there must be 101 ways that you can screw up the opengl lighting. What I was doing was setting the light position incorrectly. I was calling something like:

float light[4];
light[0] = x;
light[1] = y;
light[2] = z;
glLightfv(GL_LIGHT0,GL_POSITION,light);


I new enough to use a 4-dimensional (homogenous) vector for the light direction. But I wasn’t setting the w-component. I guess occasionally this was getting a crazy value like NaN and killing the lights.

float light[4];
light[0] = x;
light[1] = y;
light[2] = z;
light[2] = w;// e.g. w = 0 or 1
glLightfv(GL_LIGHT0,GL_POSITION,light);


### Turn off all the lights in Matlab

Wednesday, June 27th, 2012

One-liner to hit the lights on the current figure:


delete(findall(gcf,'Type','light'))


### 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: