Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
patch lighting and surface normal

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 21 Mar, 2010 19:41:03

Message: 1 of 12

I'm trying to create a 3D sphere using patch ('Vertices' and 'Faces' method), that reflects light from a light object.

All works well except for one very annoying, and perplexing, problem.

While most patch surfaces reflect light corrrectly (outside surface only), for others -- only their inside surface reflects light, and the outside remains unaffected by the light.

When creating the 'faces' matrix I have listed my vertex indices in consistent counterclockwise direction -- I assumed this was how Matlab determined which side to light-up... but apparenty not. I set the 'BackLighting' property to 'reverselit' as that seems to work best, but the other options give worse results.

When I look at the surface normal data that Matlab generates (and stores in the VertexNormal property) its size is the number of vertices and not the number of surfaces... How can a vertex have a normal? It is a point.

Can someone explain to me how Matlab determines which side a patch to light?

Subject: patch lighting and surface normal

From: Walter Roberson

Date: 21 Mar, 2010 20:02:08

Message: 2 of 12

Chris McGibbon wrote:

> When I look at the surface normal data that Matlab generates (and stores
> in the VertexNormal property) its size is the number of vertices and not
> the number of surfaces... How can a vertex have a normal? It is a point.

Speaking in generalities, which might be completely different than how
Matlab actually does things:

In geometry and calculus, tangents (and thus normals) are *always* at a
point, and reflect the direction that the nearby points are to the point
in question. You can then see how this could be extended to a vertex by
calculating the vectors towards each of the connected vertices instead
of going through a full differentiation (of a formula you don't even
have) to calculate the slopes of connected points in "all directions".

You could possibly find a normal by minimizing the sum of squares of the
2D angles between a proposed normal and the vectors towards each of the
connected vertices (though you might need a hint to know which side is
"outside"). But there's probably a much simpler way to calculate it!

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 21 Mar, 2010 20:22:03

Message: 3 of 12

Walter Roberson <roberson@hushmail.com> wrote in message <ho5u01$1to$1@canopus.cc.umanitoba.ca>...
> Chris McGibbon wrote:
>
> > When I look at the surface normal data that Matlab generates (and stores
> > in the VertexNormal property) its size is the number of vertices and not
> > the number of surfaces... How can a vertex have a normal? It is a point.
>
> Speaking in generalities, which might be completely different than how
> Matlab actually does things:
>
> In geometry and calculus, tangents (and thus normals) are *always* at a
> point, and reflect the direction that the nearby points are to the point
> in question. You can then see how this could be extended to a vertex by
> calculating the vectors towards each of the connected vertices instead
> of going through a full differentiation (of a formula you don't even
> have) to calculate the slopes of connected points in "all directions".
>
> You could possibly find a normal by minimizing the sum of squares of the
> 2D angles between a proposed normal and the vectors towards each of the
> connected vertices (though you might need a hint to know which side is
> "outside"). But there's probably a much simpler way to calculate it!

A surface normal is usually found by taking the cross-product of the direction vectors of any two edges of the patch (surface) -- this will give you the direction that the face points for lighting purposes. I still don't understand why Matlab calculates vertex normals instead -- they are 1-D points and techincally do not have normals!

Anyway, the work around was to use camlight('headlight') instead of a default light source - that seemed to solve the lighting problem.

Subject: patch lighting and surface normal

From: Walter Roberson

Date: 21 Mar, 2010 20:58:50

Message: 4 of 12

Chris McGibbon wrote:

> A surface normal is usually found by taking the cross-product of the
> direction vectors of any two edges of the patch (surface) -- this will
> give you the direction that the face points for lighting purposes. I
> still don't understand why Matlab calculates vertex normals instead --
> they are 1-D points and techincally do not have normals!

Hmmm? Vertices are only 1-D points if you are working with line segments
in a single dimension. When you have a patch object, the vertices are
all 2D (plus an implicit 0 for Z) or 3D.

Suppose you have a complex curved surface and you wish to find the
normal to it at a given point. Then you start by examining the gradient
in one direction, and you refine by examining the gradient in another
direction... but you do not have the "true" normal until you have
examined the gradient in all directions. To phrase that another way, the
"true" normal is a limit over all possible (infinite number of)
directions of a calculation involving the gradients in each direction.
If the surface is generated by a polynomial then by looking at the order
of the polynomial you can calculate the number of basis vectors you will
need to use to find the true normal; likewise, if the surface is
generated by an infinite function (e.g, e^x) that gives "nice" results
when a series expansion of it is calculated, *possibly* you could prove
convergence without evaluating the gradients along an infinite number of
basis vectors. Unfortunately, some surfaces are just not tractable to
being approximated by polynomials, so for them, to calculate the normal,
you have to truncate somewhere and hope that you can express the error
bounds and that the error bounds are not highly non-linear...

Thus it seems to me that it *is* meaningful to calculate the normal of a
vertex given the directions of the connected edges -- meaningful as a
truncation of the infinite expansion of adding more and more connected
edges as the approximation to the curved surface is refined.

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 21 Mar, 2010 21:49:04

Message: 5 of 12

Walter Roberson <roberson@hushmail.com> wrote in message <ho61ab$6rs$1@canopus.cc.umanitoba.ca>...
> Chris McGibbon wrote:
>
> > A surface normal is usually found by taking the cross-product of the
> > direction vectors of any two edges of the patch (surface) -- this will
> > give you the direction that the face points for lighting purposes. I
> > still don't understand why Matlab calculates vertex normals instead --
> > they are 1-D points and techincally do not have normals!
>
> Hmmm? Vertices are only 1-D points if you are working with line segments
> in a single dimension. When you have a patch object, the vertices are
> all 2D (plus an implicit 0 for Z) or 3D.
>
> Suppose you have a complex curved surface and you wish to find the
> normal to it at a given point. Then you start by examining the gradient
> in one direction, and you refine by examining the gradient in another
> direction... but you do not have the "true" normal until you have
> examined the gradient in all directions. To phrase that another way, the
> "true" normal is a limit over all possible (infinite number of)
> directions of a calculation involving the gradients in each direction.
> If the surface is generated by a polynomial then by looking at the order
> of the polynomial you can calculate the number of basis vectors you will
> need to use to find the true normal; likewise, if the surface is
> generated by an infinite function (e.g, e^x) that gives "nice" results
> when a series expansion of it is calculated, *possibly* you could prove
> convergence without evaluating the gradients along an infinite number of
> basis vectors. Unfortunately, some surfaces are just not tractable to
> being approximated by polynomials, so for them, to calculate the normal,
> you have to truncate somewhere and hope that you can express the error
> bounds and that the error bounds are not highly non-linear...
>
> Thus it seems to me that it *is* meaningful to calculate the normal of a
> vertex given the directions of the connected edges -- meaningful as a
> truncation of the infinite expansion of adding more and more connected
> edges as the approximation to the curved surface is refined.

I was thinking in much simpler terms (the sphere I need is more like a disco ball), but yes, I can see why it would advantageous to have normals at vertices for more complex surfaces. So I guess if I'm going to give Matlab the VertexNormal matrix, I would have to first compute the suface normals, and then from surface normals that associate with each vertex, compute an "average" normal?

Subject: patch lighting and surface normal

From: Walter Roberson

Date: 21 Mar, 2010 22:11:42

Message: 6 of 12

Chris McGibbon wrote:

> I was thinking in much simpler terms (the sphere I need is more like a
> disco ball), but yes, I can see why it would advantageous to have
> normals at vertices for more complex surfaces. So I guess if I'm going
> to give Matlab the VertexNormal matrix, I would have to first compute
> the suface normals, and then from surface normals that associate with
> each vertex, compute an "average" normal?

Ummm, I don't know how to efficiently calculate a vertex normal. If you
set the other properties, then Matlab will calculate the VertexNormal
matrix itself. You would only provide the VertexNormal matrix if you
wish to override the way that Matlab lights the surface.


You mentioned in an earlier posting that normally the normal of a flat
surface would be calculated by taking the cross product of the direction
vector of any two edges of the patch. That leads me to ponder what the
mathematical result would be of taking the cross product of the
direction vectors of all of the edges connected to a vertex? My linear
algebra is quite rusty so I'm blanking on what to expect from such a
calculation.

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 21 Mar, 2010 22:25:06

Message: 7 of 12

Walter Roberson <roberson@hushmail.com> wrote in message <ho61ab$6rs$1@canopus.cc.umanitoba.ca>...
> Chris McGibbon wrote:
>
> > A surface normal is usually found by taking the cross-product of the
> > direction vectors of any two edges of the patch (surface) -- this will
> > give you the direction that the face points for lighting purposes. I
> > still don't understand why Matlab calculates vertex normals instead --
> > they are 1-D points and techincally do not have normals!
>
> Hmmm? Vertices are only 1-D points if you are working with line segments
> in a single dimension. When you have a patch object, the vertices are
> all 2D (plus an implicit 0 for Z) or 3D.
>
> Suppose you have a complex curved surface and you wish to find the
> normal to it at a given point. Then you start by examining the gradient
> in one direction, and you refine by examining the gradient in another
> direction... but you do not have the "true" normal until you have
> examined the gradient in all directions. To phrase that another way, the
> "true" normal is a limit over all possible (infinite number of)
> directions of a calculation involving the gradients in each direction.
> If the surface is generated by a polynomial then by looking at the order
> of the polynomial you can calculate the number of basis vectors you will
> need to use to find the true normal; likewise, if the surface is
> generated by an infinite function (e.g, e^x) that gives "nice" results
> when a series expansion of it is calculated, *possibly* you could prove
> convergence without evaluating the gradients along an infinite number of
> basis vectors. Unfortunately, some surfaces are just not tractable to
> being approximated by polynomials, so for them, to calculate the normal,
> you have to truncate somewhere and hope that you can express the error
> bounds and that the error bounds are not highly non-linear...
>
> Thus it seems to me that it *is* meaningful to calculate the normal of a
> vertex given the directions of the connected edges -- meaningful as a
> truncation of the infinite expansion of adding more and more connected
> edges as the approximation to the curved surface is refined.

I was thinking in much simpler terms (the sphere I need is more like a disco ball), but yes, I can see why it would advantageous to have normals at vertices for more complex surfaces. So I guess if I'm going to give Matlab the VertexNormal matrix, I would have to first compute the suface normals, and then from surface normals that associate with each vertex, compute an "average" normal?

Subject: patch lighting and surface normal

From: Jan Simon

Date: 21 Mar, 2010 22:42:03

Message: 8 of 12

Dear Chris!
> I'm trying to create a 3D sphere using patch ('Vertices' and 'Faces' method), that reflects light from a light object.

Have you seen this function from Andres:
  http://www.mathworks.com/matlabcentral/fileexchange/23882-surfo

Good luck, Jan

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 22 Mar, 2010 06:05:22

Message: 9 of 12

"Jan Simon" <matlab.THIS_YEAR@nMINUSsimon.de> wrote in message <ho67br$fel$1@fred.mathworks.com>...
> Dear Chris!
> > I'm trying to create a 3D sphere using patch ('Vertices' and 'Faces' method), that reflects light from a light object.
>
> Have you seen this function from Andres:
> http://www.mathworks.com/matlabcentral/fileexchange/23882-surfo
>
> Good luck, Jan

Thanks, it sounded positive and I gave it a try.

When using facenorm to recompute the VertexNormals, none of my patches show lighting.

Here's the code I'm using (including call to facenorm). It's not terribly sophisticated but it should be able to draw a lighted sphere.

-----------------------------------------------------------------------


% Program to draw a sphere and paint the quadrants alternating colors

% Construct the sphere coordinates. Order of vertices has 1st point at
% north pole (z=1) and last point at south pole (z=-1). Points in between
% fall on latitude circles and go counter-clockwise around the sphere from
% north to south pole.
ph = [60,30,0,-30,-60]*pi/180; np = length(ph); % Elevation angles
th = [0:11]*30*pi/180; nt = length(th); % Azimuth angles
nc = np*nt+2; % Number of vertices
xyz = zeros(3,nc);
for i=1:np % First compute all the points in between the poles
    for j=1:nt
        xyz(1,1+j+nt*(i-1)) = cos(ph(i)).*cos(th(j));
        xyz(2,1+j+nt*(i-1)) = cos(ph(i)).*sin(th(j));
        xyz(3,1+j+nt*(i-1)) = sin(ph(i));
    end
end
xyz(1:3,1)=[0.0,0.0,1.0]; % Then add the pole coordinates.
xyz(1:3,nc)=[0.0,0.0,-1.0];

% Use facenorm.m to recompute vertex normals
Vnorm = zeros(nc,3);
Vnorm(:,:) = facenorm(xyz(1,:),xyz(2,:),xyz(3,:));

Q = zeros(4,9,8); % Initialize a matrix to hold face indices
% Quadrant I
Q(1,:,1) = [1,1,1,2,3,4,14,15,16];
Q(2,:,1) = [2,3,4,14,15,16,26,27,28];
Q(3,:,1) = [3,4,5,15,16,17,27,28,29];
Q(4,:,1) = [NaN,NaN,NaN,3,4,5,15,16,17];
% Quadrant II
Q(1,:,2) = [1,1,1,5,6,7,17,18,19];
Q(2,:,2) = [5,6,7,17,18,19,29,30,31];
Q(3,:,2) = [6,7,8,18,19,20,30,31,32];
Q(4,:,2) = [NaN,NaN,NaN,6,7,8,18,19,20];
% Quadrant III
Q(1,:,3) = [1,1,1,8,9,10,20,21,22];
Q(2,:,3) = [8,9,10,20,21,22,32,33,34];
Q(3,:,3) = [9,10,11,21,22,23,33,34,35];
Q(4,:,3) = [NaN,NaN,NaN,9,10,11,21,22,23];
% Quadrant IV
Q(1,:,4) = [1,1,1,11,12,13,23,24,25];
Q(2,:,4) = [11,12,13,23,24,25,35,36,37];
Q(3,:,4) = [12,13,2,24,25,14,36,37,26];
Q(4,:,4) = [NaN,NaN,NaN,12,13,2,24,25,14];
% Quadrant V
Q(1,:,5) = [26,27,28,38,39,40,50,51,52];
Q(2,:,5) = [38,39,40,50,51,52,62,62,62];
Q(3,:,5) = [39,40,41,51,52,53,51,52,53];
Q(4,:,5) = [27,28,29,39,40,41,NaN,NaN,NaN];
% Quadrant VI
Q(1,:,6) = [29,30,31,41,42,43,53,54,55];
Q(2,:,6) = [41,42,43,53,54,55,62,62,62];
Q(3,:,6) = [42,43,44,54,55,56,54,55,56];
Q(4,:,6) = [30,31,32,42,43,44,NaN,NaN,NaN];
% Quadrant VII
Q(1,:,7) = [32,33,34,44,45,46,56,57,58];
Q(2,:,7) = [44,45,46,56,57,58,62,62,62];
Q(3,:,7) = [45,46,47,57,58,59,57,58,59];
Q(4,:,7) = [33,34,35,45,46,47,NaN,NaN,NaN];
% Quadrant VIII
Q(1,:,8) = [35,36,37,47,48,49,59,60,61];
Q(2,:,8) = [47,48,49,59,60,61,62,62,62];
Q(3,:,8) = [48,49,38,60,61,50,60,61,50];
Q(4,:,8) = [36,37,26,48,49,38,NaN,NaN,NaN];

c = zeros(3,8);
c(:,1) = [0 0 1]; c(:,3) = [0 0 1]; c(:,6) = [0 0 1]; c(:,8) = [0 0 1];
c(:,2) = [1 1 0]; c(:,4) = [1 1 0]; c(:,5) = [1 1 0]; c(:,7) = [1 1 0];

axes
set(gca,'Projection','perspective');
axis vis3d
axis equal
axis off
light('Position',[3,3,3],'Style','infinite');
lighting flat
set(gcf,'Renderer','OpenGL')
%camlight headlight % another lighting option I tried
view(0,0);

for i = 1:8
  patch('Vertices',xyz','Faces',Q(:,:,i)',...
        'FaceColor',c(:,i),'EdgeColor',c(:,i),'FaceVertexCData',c(:,i),...
        'FaceLighting','gouraud','EdgeLighting','gouraud',...
        'AmbientStrength',0.6,'EraseMode','normal',...
        'BackFaceLighting','reverselit','LineStyle','none',...
        'VertexNormals',Vnorm);
end

Subject: patch lighting and surface normal

From: Jan Simon

Date: 22 Mar, 2010 12:48:04

Message: 10 of 12

Dear Chris!

> for i = 1:8
> patch('Vertices',xyz','Faces',Q(:,:,i)',...
> 'FaceColor',c(:,i),'EdgeColor',c(:,i),'FaceVertexCData',c(:,i),...
> 'FaceLighting','gouraud','EdgeLighting','gouraud',...
> 'AmbientStrength',0.6,'EraseMode','normal',...
> 'BackFaceLighting','reverselit','LineStyle','none',...
> 'VertexNormals',Vnorm);
> end

As far as I can see, your VNorm consists of NaN's only. Most likely you call facenorm with the wrong input. And are you sure that you want to apply the same Vnorm to all 8 PATCH objects?!

Kind regards, Jan

Subject: patch lighting and surface normal

From: Chris McGibbon

Date: 24 Mar, 2010 04:27:04

Message: 11 of 12

"Jan Simon" <matlab.THIS_YEAR@nMINUSsimon.de> wrote in message <ho7ou4$gqa$1@fred.mathworks.com>...
> Dear Chris!
>
> > for i = 1:8
> > patch('Vertices',xyz','Faces',Q(:,:,i)',...
> > 'FaceColor',c(:,i),'EdgeColor',c(:,i),'FaceVertexCData',c(:,i),...
> > 'FaceLighting','gouraud','EdgeLighting','gouraud',...
> > 'AmbientStrength',0.6,'EraseMode','normal',...
> > 'BackFaceLighting','reverselit','LineStyle','none',...
> > 'VertexNormals',Vnorm);
> > end
>
> As far as I can see, your VNorm consists of NaN's only. Most likely you call facenorm with the wrong input. And are you sure that you want to apply the same Vnorm to all 8 PATCH objects?!
>
> Kind regards, Jan

Hi Jan
The property 'Vertices' contains all the data points for the sphere, so the 'VertexNormal' property must be the same size. I used the facenorm program in hopes that it would generate the correct vertex normals for the entire sphere when given the X,Y,Z coordinates of the sphere.

Each individual patch object (1/8th of the sphere surface) is specified by the indices in the 'Faces' property. I assume matlab gets the surface normals for each face from 'VertexNormal' property based on the indices in the 'Faces' property.

Perhaps facenorm only works with surface plot data?

Subject: patch lighting and surface normal

From: Thomas Clark

Date: 23 Apr, 2010 16:56:04

Message: 12 of 12

Sorry to bump an oldish post, but I thought it might be worthwhile mentioning this submission on the FEX:

http://www.mathworks.com/matlabcentral/fileexchange/authors/19733

... it's purpose is to calculate vertex normals using an FV array, if you already have a triangulation.

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us