Jonathan H
Jonathan H

Reputation: 7943

Shading does not work with patches specifying face colors?

I don't understand why the following code throws a warning:

% mesh of a plane at z=0 for x,y in [0,5] with 20 vertices per side
n = 20;
[x,y] = ndgrid( linspace(0,5,n) );
x = x(:); y = y(:); z = zeros(n^2,1);

% triangulation to obtain faces, and draw a patch with random color for each face
F = delaunay(x,y);
V = [x,y,z];
patch( 'Vertices', V, 'Faces', F, 'FaceVertexCData', rand( size(F,1), 1 ) );
axis tight; grid on; box off;

% faceted shading works fine, but interp doesn't seem to work
shading('faceted'); % works fine
shading('interp'); % throws a warning

   Warning: Error creating or updating Patch
    Error in value of property  FaceVertexCData
    Number of colors must equal number of vertices

Hopefully the comments are enough explanation to understand the issue -- but briefly, it seems that interpolation of face color does not work when the property FaceVertexCData specifies the colors of faces and not vertices.

Upvotes: 1

Views: 3513

Answers (2)

Jonathan H
Jonathan H

Reputation: 7943

FYI, if you want to convert a vector of colors for each face to a vector of colors for each vertex, you can use the following function:

function cdata = face2vertex(cdata,faces,nvert)

    fmax = max(faces(:));
    if nargin < 3, nvert=fmax; end
    if size(faces,1)~=3, faces=faces'; end

    assert( size(faces,1)==3, 'Bad faces size.' );
    assert( size(faces,2)==numel(cdata), 'Input size mismatch.' );
    assert( nvert >= fmax, 'Number of vertices too small.' );

    faces = faces(:);
    cdata = repelem( cdata(:), 3 ); % triplicate face colors

    nfpv  = accumarray( faces, 1, [nvert,1] ); % #of faces per vertex
    cdata = accumarray( faces, cdata, [nvert,1] ) ./ max(1,nfpv);

end

This function takes in input:

  • a Nfaces x 1 column vector of colors cdata,
  • a Nfaces x 3 array of vertex indices (one triangle per row),
  • optionally the number of vertices, which will override the size of the output (otherwise inferred from face indices).

and returns a Nvertices x 1 column vector of colors such that for each vertex, the color is averaged across the faces that contain it.

Upvotes: 1

Suever
Suever

Reputation: 65430

As the warning message states, if you want to use the 'interp' shading method, you need to have your FaceVertexCData have an entry for each vertex. Currently, you have an entry for each face.

patch( 'Vertices', V, 'Faces', F, 'FaceVertexCData', rand( size(V,1), 1 ) );
shading('interp')

This is not an issue or a bug, because shading sets the FaceColor property of the patch object to 'interp' which explicitly requires that there be an entry in FaceVertexCData for each vertex.

'interp' — Interpolate the color across each face. First, specify CData or FaceVertexCData as an array containing one value per vertex. Determine the face colors by using a bilinear interpolation of the values at each vertex.

Upvotes: 2

Related Questions