Now that we have explicit color in pm3d, there is one last ingredient to make it easy to color a figure based on the normal vector (this is how Mathematica makes it's beautiful 3d plots and helps convey details like shape and curve more effectively than a height-map). It must be possible for gnuplot to determine the normal vector for each tile it places down for the pm3d plot, which allows us to do something like this...
plot '++' u 1:2:3:(color(nvx($1,$2),nvy($1,$2),nvz($1,$2))) w pm3d lc rgb var
An external routine could compute the functions nvx,nvy,nvz and put them in the fourth, fifth, and sixth data columns, but it would be better to be able to feed in a 3D data set and leave the coloring to gnuplot.
Since I am not a developer, I don't know what hidden conventions this would break, but it seems possible and extraordinarily useful, since now we have a platform for beautiful 2D plots, but have to go into the hideously complicated and difficult-to-adjust Mathematica to get 3D plots that convey shape effectively.
To anyone who takes this up or gives a good reason not to, thank you!
Ethan Merritt
2012-03-06
Please clarify the proposed coloring scheme. Are you talking about Phong shading?
The plot command you give above uses only the x and y coordinates to derive the color, which doesn't seem to match your mention of surface normals. Maybe you could give a URL for a figure that illustrates what you want?
Douglas
2012-03-06
So here's an idea of how this works in Mathematica: http://reference.wolfram.com/mathematica/ref/NormalsFunction.html
And a nice explanation of the normal vector:
http://en.wikipedia.org/wiki/Normal_vector
The idea is that each polygon you draw has some orientation in 3D space which is defined by the normal vector. If you have access to the orientation of the polygon, you can define a function of the normal vector which gives a color. The classic scheme in Mathematica is something like blue is proportional to normal_x, red to normal_y, green to normal_z.
I suspect it would be possible to make this possible either using explicit pm3d coloring, or like a palette function.
Ethan Merritt
2012-03-06
Got it.
So this would be a per-tile color, which we can do, rather than a pixel-by-pixel color, which unfortunately we can't do.
You can already color a pm3d surface based on an explicit function. See for example the final two plots in
http://gnuplot.sourceforge.net/demo_canvas/heatmaps.html
What's missing is a way for a function to refer generically to the surface normal, or indeed any other property, of the "current" face of the surface. I'll have to think about how that might be achieved. Possibly we could modify the existing "set pm3d corners2color" option somehow, or add a parallel "set pm3d normal2color" option. But I don't immediately see how you would associate a user-specifid function with it.
Douglas
2012-03-06
Exactly! A solution that comes to mind is how we define the palette function. For example, this produces the rainbow palette:
set palette model HSV functions gray,1,1
Why not something similar
set normal model RGB functions x,y,z
to recreate the Mathematica normal shading, and where x, y, and z refer to each component of the normal vector. Then in the plot command..
splot '++' u 1:2:3 w pm3d lc normal
As for the pixel-by-pixel, I don't think it's necessary with the current abilities of gnuplot. Per-polygon shading will approximate pixel-by-pixel for high-resolution data, functions where the resolution is arbitrary, or using any of the myriad interpolation schemes that produce higher-resolution data automatically.
Ethan Merritt
2012-03-06
The palette assumes a function of a single variable. We can already do that. You want a function of three variables, none of which are currently stored anywhere. That's the tricky part.
Ethan Merritt
2012-03-07
So I tried this, implementing it as "set pm3d corners2color normal".
It works, but the result does not look very much like the Mathematica plot that you gave as an example. Are you sure that mapping the surface normal components onto RGB is really what you want? Perhaps they are taking into account the curvature also? Anyhow, here's a patch you can play with. Let me know if this is heading in a useful direction.
Ethan Merritt
2012-03-07
set pm3d corners2color normal
Douglas
2012-04-17
Okay, I'm installing the patch today and I'll see what I can come up with. Once we have the normal vector data, we can then do whatever we want. Ideally, the most flexible solution is to be able to determine a palette based both on height and the normal vector, which permits simple shading on top of useful height information. I'll update as soon as I can.
Douglas
2012-04-17
Gorgeous normal-vector rendering
Douglas
2012-04-17
Ethan, that is GORGEOUS! I'm thrilled that my favorite graphing program can do something so beautiful!
From the script:
gnuplot> set xrange [0:10]
gnuplot> set yrange [0:10]
gnuplot> set samples 100, 100
gnuplot> set isosamples 100
gnuplot> set pm3d corners2color normal
gnuplot> splot '++' u 1:2:(sin($1)+sin($2)) w pm3d
See attached.
So, to recapitulate my prior comment; I think the next goal is just to let the user define the functions that color by normal. I'm imagining an implementation like:
set normal functions RGB r(nx,ny,nz),g(nx,ny,nz),b(nx,ny,nz)
And here's my relentless imagination coming in. If the above is possible, I might also suggest in the future the option to determine an alpha parameter in these functions
set normal functions RGBA r(nx,ny,nz),g(nx,ny,nz),b(nx,ny,nz),a(nx,ny,nz)
so that a height-based coloring can come through. This would be helpful, for instance, in establishing some basic shading on top of the helpful height-based coloring. This would be a holy grail because it would give the user more control over making informative 3D surface maps than any software in the world can provide.