3

I'm getting a plot which is mostly fine with Lighting->Automatic, but a bit too dark. How do I go about getting the Lighting specification used in the plot so I could make it explicit and tweak it?

IE, need a utility which extracts lighting and related specs from a Graphics3D object.

f1[x_, y_] = 
  x (3/16 (9 - Sqrt[17]) x + 1/8 (9 - Sqrt[17]) y) + 
   y (1/8 (9 - Sqrt[17]) x + 3/4 (9 - Sqrt[17]) y);
f2[x_, y_] = 2 x^2 + 4 y^2;
Plot3D[{f1[x, y], f2[x, y]}, {x, -2, 2}, {y, -2, 2}, 
 BoxRatios -> {1, 1, 1}]

enter image description here

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
Yaroslav Bulatov
  • 7,793
  • 1
  • 19
  • 44
  • Cases[plot, HoldPattern[Lighting -> _], All]? – kglr Aug 11 '21 at 14:00
  • 2
    Use SetSystemOptions["VisualizationOptions" -> {"Verbose" -> True}] before plotting, then search for Lightning in the output: Lighting -> {{"Ambient", RGBColor[0.19699838300000003, 0.252204821, 0.33320940200000004]}, {"Directional", RGBColor[0.15473514000000002, 0.21284718000000002, 0.29811516000000005], ImageScaled[{0, 2, 2}]}, {"Directional", RGBColor[0.15473514000000002, 0.21284718000000002, 0.29811516000000005], ImageScaled[{2, 2, 2}]}, {"Directional", RGBColor[0.15473514000000002, 0.21284718000000002, 0.29811516000000005], ImageScaled[{2, 0, 2}]}}. – Domen Aug 11 '21 at 14:00
  • @Domen that doesn't fully reproduce the graph above...I guess there are some extra options I need besides Lighting? – Yaroslav Bulatov Aug 11 '21 at 14:08
  • 1
    You are correct. To reproduce the original plot, setting the Lighting is not enough, you also have to include the option PlotStyle, which can also be found in the verbose output. – Domen Aug 11 '21 at 14:37
  • 1
    Cases[plot, {d__, _GraphicsGroup} :> {d}, All] to get the directives (including Lighting) used for each surface. – kglr Aug 11 '21 at 18:20

1 Answers1

4

Due to this bug, setting Lighting for Graphics3D as an option directly (e.g. via Show) doesn't work, and we must specify it individually for every object (or a group of objects) on the scene like a usual graphics directive. Starting at least from Mathematica 10 the built-in 3D plotting functions like Plot3D take the Lighting specifications from the absolute/resolved value of the PlotStyle option (which they generate from your input), and then build them into the list of graphics primitives (the first argument of Graphics3D). One can turn on verbose logging for this process by setting the system option "VisualizationOptions" -> {"Verbose" -> True}.

We can obtain the default styles with Lighting specifications included, as the value of "DefaultPlotStyle" suboption of Method option, via Charting`ResolvePlotTheme:

defaultplotstyle = "DefaultPlotStyle" /. 
   (Method /. Charting`ResolvePlotTheme[$PlotTheme, Plot3D])

screenshot

We can obtain the actual (absolute) value of PlotStyle (generated by Plot3D for your particular input) from the output generated during evaluation of Plot3D after setting the system option "VisualizationOptions" -> {"Verbose" -> True} as Domen recommends in the comments. The code below automatizes this:

f1[x_, y_] = x (3/16 (9 - Sqrt[17]) x + 1/8 (9 - Sqrt[17]) y) + 
             y (1/8 (9 - Sqrt[17]) x + 3/4 (9 - Sqrt[17]) y);
f2[x_, y_] = 2 x^2 + 4 y^2;

Internal`WithLocalSettings[ SetSystemOptions["VisualizationOptions" -> {"Verbose" -> True}], reap = Reap[Block[{Print = (Sow[{##}] &)}, Plot3D[{f1[x, y], f2[x, y]}, {x, -2, 2}, {y, -2, 2}, BoxRatios -> {1, 1, 1}]]];, SetSystemOptions["VisualizationOptions" -> {"Verbose" -> False}] ];

Cases[reap, HoldPattern[PlotStyle -> _], {1, Infinity}] /. x_Real :> Round[x, .01]

{PlotStyle -> {Directive[Specularity[GrayLevel[1], 3], RGBColor[0.88, 0.61, 0.14], 
    Lighting -> {{"Ambient", RGBColor[0.3, 0.22, 0.09]},
       {"Directional", RGBColor[0.26, 0.18, 0.04], ImageScaled[{0, 2, 2}]}, 
       {"Directional", RGBColor[0.26, 0.18, 0.04], ImageScaled[{2, 2, 2}]}, 
       {"Directional", RGBColor[0.26, 0.18, 0.04], ImageScaled[{2, 0, 2}]}}], 
   Directive[Specularity[GrayLevel[1], 3], RGBColor[0.37, 0.51, 0.71],
     Lighting -> {{"Ambient", RGBColor[0.2, 0.25, 0.33]}, 
       {"Directional", RGBColor[0.15, 0.21, 0.3], ImageScaled[{0, 2, 2}]}, 
       {"Directional", RGBColor[0.15, 0.21, 0.3], ImageScaled[{2, 2, 2}]}, 
       {"Directional", RGBColor[0.15, 0.21, 0.3], ImageScaled[{2, 0, 2}]}}]}}

Having this, you can play with the directives to get the lighting you wish.

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368