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.
Douglas
2012-04-18
Poor rotation without normal vector accounting for rotation of axes
Douglas
2012-04-18
Okay, so I just showed this feature off to a bunch of colleagues and they were absolutely blown away. They pointed out something crucial that would be easy to implement with the current patch, if only we knew how to get this information. Currently, the normal shading is entirely determined by the function, and does not account for the rotation of the x,y, and z axes. To achieve ideal normal vector shading like the first example I posted, you need to subtract from the normal vector a unit vector describing the orientation of the axes around the origin, which is entirely determined by the 2-vector from "set view". This simple subtraction allows 3d plots at certain rotations, like the new one I've attached, to flash into their proper perspective at ANY rotation angle. The result should be astounding.
Ethan Merritt
2012-04-18
But if the coloring changes as you alter the view angle, what physical meaning does it have?
Can you give an example of a plot that uses such a coloring to convey useful information?
Douglas
2012-04-18
Absolutely. Every function page on Wolfram's mathworld uses two plots to convey the shape of the function
1) A simple heightmap (height-based shading) but with "set view map"
2) A 3D-surface in perspective using the normal-vector shading subtracting off the orientation of the axes
(Scroll half-way through http://mathworld.wolfram.com/GammaFunction.html for a nice example)
The reason is as follows. I've attached an example of two plots, one with the current shading technique and another with the normal shading. In the height-based shading technique, you'll notice that there are weird visual effects that detract from the conveyance of information which are instantly resolved in the normal shaded version. For instance, It's hard to interpret the curvature of the top lobes, and when they overlap in the perspective, it is difficult to visually separate them.
In contrast, the normal vector shading version leaves no ambiguity. And better still, the eye is perfectly capable of "filling in the gaps" so that it is always obvious what the height of the function is even though there is no explicit color telling us that. The eye and the visual cortex are beautiful things!
The normal vector shading I'm describing is the default behavior on Mathematica, and Ethan is right to be suspicious of relying entirely on shading-like algorithms to convey information. However, I think adding this tool to the arsenal of someone conveying information is crucial. For instance, the solution used at Wolfram Mathworld -- showing both a non-perspective heightmap AND the normal-vector shading in perspective -- is probably the best of both worlds. In my view, these are the two pieces to the puzzle of conveying 3D information on a 2D screen. Gnuplot currently does heightmaps better than any other software in the world -- imagine what will be possible when it can complete the picture!
Douglas
2012-04-18
Problematic Function looks beautiful in normal-vector shading!
Douglas
2012-04-18
A problematic function is visually indiscernible using height-based shading...
Douglas
2012-04-18
Thus far I have been using full three-valued notation of the normal vector in Cartesian coordinates. It's probably worth mentioning that the normal vector is an orientation, so it actually only needs two inputs (theta and phi). The view parameter, which is shown in the lower-left-hand of the "Problematic Function" image files, is also expressed in this form. Therefore, it should be easy to create functions r(theta_n,theta_v,phi_n,phi_v),g(...),b(...) which are dependent upon the orientation angles of the normal vector (theta_n) and the axes (theta_v). It would be thrilling to give the user access to the normal vector shading function, but in the meantime, I think getting normal-vector shading to work at all axes orientation using the current hard-coded function is a huge first step, and a goal in and of itself.
Douglas
2012-04-18
So I've never done open source (or any) development since I'm a physicist, but I've written a pm3d.c that does the trick based on your patch. I've attached the new version of pm3d and a snapshot. The results are just so beautiful! Here's my script for testing:
set xrange [-3:3]
set yrange [-3:3]
set samples 100, 100
set isosamples 100
set pm3d corners2color normal
splot '++' u 1:2:(sqrt(9-$1**2-$2**2)) w pm3d
Douglas
2012-04-18
Beautiful rendering of a half-sphere using rotated normal-vector shading
Douglas
2012-04-18
New version of pm3d.c after applying Ethan's patch
Ethan Merritt
2012-04-18
It's pretty, yes. But is there actually any useful information added? Here's your "problematic" plot rendered in gnuplot's traditional hidden3d mode. To my eyes this is arguably more clear than the pretty normal-based coloring.
I'm not disputing that there may be some real world cases where the value of the surface normal encodes important information. If we're going to pursue this as a code feature, I'd much rather test+optimize on a such a real world case so that we can evaluate it in terms of effective presentation rather than prettiness.
Ethan Merritt
2012-04-18
compare hidden3d and pm3d color-by-normal
Douglas
2012-04-19
I've now added a new option "set pm3d corners2color shade" which does a very simple shading algorithm on top of the palette heightmap. I've attached a screenshot and the patch file which (I hope) will make this happen. Here's the script for the screenshot:
set xrange [-8:8]
set yrange [-8:8]
set samples 100, 100
set isosamples 100
set pm3d
set pm3d corners2color shade
splot cos(x)+cos(y) w pm3d
Douglas
2012-04-19
With new "color-by-shading"
Douglas
2012-04-19
In my enthusiasm for the shaded version, I missed your last comment. I agree that finding a "killer app" for this feature important, and I'll try to brainstorm. In the meantime, here's a useful example: placing the shaded pm3d above the non-shaded flat plane, as is often used in the demos. To me, this is the best of both worlds: a nicely-rendered 3d image indicating curvature, and the pixel-by-pixel accuracy of the flat plane. By shading the palette in the surface, you also help the eye connect the heightmap at the bottom to the curvature at the top. I can't re-create it here because the normal shading currently also affects results at the base. But here's the script based on the new patch, and I have attached the result:
set xrange [-8:8]
set yrange [-8:8]
set samples 100, 100
set isosamples 100
set pm3d
set pm3d corners2color shade
splot cos(x)+cos(y) w pm3d
set xrange [-8:8]
set yrange [-8:8]
set samples 100, 100
set isosamples 100
set pm3d
set pm3d corners2color shade
set pm3d implicit at bs
splot cos(x)+cos(y) w pm3d