Matlab correctly stops interpolating colors on a grid if it is larger than 120 triangles

I am trying to draw a large grid in Matlab using the trimesh function, with the z coordinate of the vertices that control the color. Unfortunately, Matlab stops correctly interpolating colors when the mesh size exceeds 120 triangles. Here's an image showing the problem, with 120 triangles on the left and 121 triangles on the right.

A picture demonstrating the problem

As you can see, for large grids, Matlab interpolates directly from the color of one vertex to the color of another vertex. This was probably done for performance reasons, but I'm trying to create beautiful photos for my dissertation, and I don't care how long it takes to figure them out. Is there any way to disable this approximation?

Here is the code for generating the image:

 function test(n) %%% Generate a mesh with n triangles. oneTriVerts = [0 0 0; 1 0 0; 1 0 1]; offset = [0 (1/n) 0; 0 (1/n) 0; 0 (1/n) 0]; verts = zeros(0,3); tris = zeros(0,3); for i = 0:(n-1) verts = [verts; (oneTriVerts + i * offset)]; tris = [tris; i*3+1, i*3+2, i*3+3]; end %%% Draw the mesh, with color corresponding to the z coordinate. trimesh(tris, verts(:,1), verts(:,2), verts(:,3), verts(:,3)); title(sprintf('n = %d', n)) shading interp axis equal 
+8
matlab plot 3d mesh
source share
1 answer

I think that after a certain threshold, MATLAB switched to OpenGL rendering to improve performance (hardware acceleration). Unfortunately, this is not without errors.

I have not looked closely at how you build triangular faces (there may be a problem with the way they are ordererd), but a simple solution is to explicitly set the rendering method. Just add the following call at the end of your function:

 set(gcf, 'Renderer','zbuffer') 

EDIT

The workaround above should be wonderful. Now the real problem is not OpenGL buggies, but rather a documented limitation:

OpenGL does not perform colormap interpolation. If you create a surface or patch using indexed color and interpolated coloring on faces or edges, OpenGL interpolates colors through the RGB color cube instead of through the color map.

Note that calling TRIMESH is equivalent to the following:

 patch('Faces',tris, 'Vertices',verts, 'FaceVertexCData',verts(:,3), ... 'EdgeColor','none', 'FaceColor','interp', 'CDataMapping','scaled') 

So, for each vertex you specify a color equal to its z-coordinate (you have only two unique values: 0 or 1). This is interpreted as indexed color into the current digital map using scaled matching (the default color map of the jet is used). Thus, two colors end:

 clr = jet(64); % default colormap clr(1,:) % blueish color [0 0 0.5625] mapped from 0 clr(end,:) % reddish color [0.5 0 0] mapped from 1 

Unfortunately, as the above quote explains, the OpenGL renderer will not do interpolation using the colors of the colormap palette, rather we will interpolate in the RGB color space between the two colors above. Thus, we get the blue-red gradient that you saw.

So your only option is to use one of the other two renderers, zbuffer is the best way here.


Here is the code to see the difference between the two rendering methods:

 % plot patch clf patch('Faces',tris, 'Vertices',verts, 'FaceVertexCData',verts(:,3), ... 'EdgeColor','none', 'FaceColor','interp', 'CDataMapping','scaled') view(3) axis vis3d colorbar % choose one of the two set(gcf, 'Renderer','opengl') set(gcf, 'Renderer','zbuffer') 

Opengl

opengl renderer

Z-buffer

zbuffer renderer

+5
source share

All Articles