6
$\begingroup$

This is the default lighting:

Graphics3D[Cube[], Boxed -> False]
AbsoluteOptions[%, Lighting]

enter image description here

{Lighting -> {{"Ambient", RGBColor[{0.4, 0.2, 0.2}]}, 
   {"Directional", RGBColor[{0., 0.18, 0.5}], 
    ImageScaled[{2, 0, 2}]}, {"Directional", 
    RGBColor[{0.18, 0.5, 0.18}], ImageScaled[{2, 2, 3}]}, 
   {"Directional", RGBColor[{0.5, 0.18, 0.}], 
    ImageScaled[{0, 2, 2}]}, {"Directional", 
    RGBColor[{0., 0., 0.18}], ImageScaled[{0, 0, 2}]}}}

How the lighting should be changed so that the blue and orange colors are swapped (in default view point) like in this image?

enter image description here

I tried swapping x, y, z coordinates in ImageScaled in many different ways but none of them produced correct result.

A logical explanation how to achieve any permutation of three default colors would be great.

$\endgroup$
2
  • $\begingroup$ This is an interesting question, and I'm not sure what the answer is. But, surprisingly (to me), the camera-rotation also matters in the computation of the color: Graphics3D[Cube[],ViewVector->{{2,-2,1.4},{0,0,0}},ViewVertical->Prepend[AngleVector[#],0],ViewAngle->0.6]&/@Subdivide[0,2Pi,30] $\endgroup$ Commented 3 hours ago
  • $\begingroup$ @SHuisman I just want to match the colors only for default viewpoint ViewPoint -> {1.3, -2.4, 2.}, when you evaluate input without additional manual rotation or any additional specification in the code that changes view point. $\endgroup$ Commented 3 hours ago

2 Answers 2

4
$\begingroup$

This is not easy. Thanks for a challenging problem.

origLighting = {{"Ambient", RGBColor[{0.4, 0.2, 0.2}]},
               {"Directional",RGBColor[{0., 0.18, 0.5}], ImageScaled[{2, 0, 2}]}, 
               {"Directional",RGBColor[{0.18, 0.5, 0.18}],ImageScaled[{2, 2, 3}]}, 
               {"Directional", RGBColor[{0.5, 0.18, 0.}],ImageScaled[{0, 2, 2}]}, 
               {"Directional", RGBColor[{0., 0., 0.18}],ImageScaled[{0, 0, 2}]}};

eye = AbsoluteOptions[Graphics3D[Cube[], Boxed -> False], ViewPoint][[1, 2]] 25/24;
target = {0., 0., 0.};
up = {0., 0., 1.};

1. Create an orthonormal rotation matrix that converts a vector from "camera space" (the 2D screen + depth) into true 3D "world space"

imageToWorldBasis[eye_, target_, up_] := 
  Module[{z, x, y}, z = Normalize[eye - target];
   x = Normalize[Cross[up, z]];
   y = Cross[z, x];
   Transpose[{x, y, z}]];

2. Map the original lighting setup into Euclidean 3D vectors.

toWorldDirections[lights_, eye_, target_, up_] := 
  Module[{B = imageToWorldBasis[eye, target, up]}, 
   lights /. {{"Directional", col_, ImageScaled[p_]} :> {"Directional",
        col, Normalize[B . p]}}];

3. This matrix represents an exact geometric transformation that cyclically maps the cube's faces to one another.

faceCycle = {{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}};

4. Apply the 120 degrees rotation to the frozen world-space lights.

rotateDirections[lights_, k_] := 
  Module[{R = MatrixPower[faceCycle, k]}, 
   lights /. {{"Directional", col_, dir_} :> {"Directional", col, 
       Normalize[R . dir]}}];

5. Precompute world space directional lights

worldDirs = Rest@toWorldDirections[origLighting, eye, target, up];

ambient = First@origLighting;

6. Final visualization:

Table[Graphics3D[Cube[], Boxed -> False, 
   Lighting -> Join[{ambient}, rotateDirections[worldDirs, k]], 
   ViewVector -> {eye, target}, ViewVertical -> up, 
   ViewCenter -> {{0.5, 0.5, 0.5}, {0.5, 0.5}}, 
   ViewAngle -> Automatic], {k, 0, 2, 
   1}] // GraphicsRow

Cubes under transformed lighting

Edit in response to comment

B = imageToWorldBasis[eye, target, up];
cameraSpaceRotation[k_] := 
  MatrixPower[Transpose[B] . faceCycle . B, k];

rotateCameraLights[lights_, k_] := 
  Module[{Q = cameraSpaceRotation[k]}, 
   lights /. {{"Directional", col_, ImageScaled[p_]} :> {"Directional",
        col, ImageScaled[Q . p]}}];

Manipulate[
 Graphics3D[Cube[], Boxed -> False, 
  Lighting -> rotateCameraLights[origLighting, k], 
  SphericalRegion -> True], {k, 0, 2, 1}]

Edit in response to the second comment

Here is a much more compact code with options set via AbsoluteOptions.

With[{o = AbsoluteOptions@Graphics3D[]}, 
 With[{Q = # . {{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}} . Transpose@# &[
     Normalize /@ 
        With[{Z = Subtract @@ #1}, {#2~Cross~Z, Z~Cross~(#2~Cross~Z), 
          Z}] &[ViewVector /. o, ViewVertical /. o]], 
   L = Lighting /. o}, 
  Manipulate[
   Graphics3D[Cube[], Boxed -> False, SphericalRegion -> True, 
    Lighting -> (L /. 
       ImageScaled[p_] :> ImageScaled[MatrixPower[Q, k] . p])], {k, 0,
     2, 1}]]]
$\endgroup$
5
  • $\begingroup$ (+1) Thanks, lots of work. But it is static, I want it with ImageScaled definition of directional light. The colors should change on manual rotation as usual only the corresponding colors would be swapped. $\endgroup$ Commented 3 hours ago
  • $\begingroup$ Where did you get this from eye = {1.35417, -2.5, 2.08333};? Why these specific values? $\endgroup$ Commented 3 hours ago
  • $\begingroup$ @azerbajdzan You are welcome. I was experimenting with the ViewPoint and simply set eye to 25/24 of its standard value. $\endgroup$ Commented 2 hours ago
  • $\begingroup$ Will it work with default {1.3, -2.4, 2.} view point the same way or is your code dependent on precisely {1.35417, -2.5, 2.08333}? $\endgroup$ Commented 2 hours ago
  • $\begingroup$ @azerbajdzan It will work without any problems. I added a shorter code with all 3D graphics options set automatically. $\endgroup$ Commented 2 hours ago
1
$\begingroup$

To swap colours for default view only (rotation will break it), use Graphics3D[{Cube[]},Boxed->False,Lighting->{{"Directional",RGBColor[{0.475,0.271,0.416}],{1,0,0}},{"Directional",RGBColor[{0.537,0.659,0.820}],{0,-1,0}},{"Directional",RGBColor[{1,0.863,0.663}],{0,0,1}}}]. ImageScaled blends the light sources. Need to use Orthogonal directionals and no ImageScaled for no blending.enter image description here

$\endgroup$
1
  • 1
    $\begingroup$ For static use it is OK, but I want it with ImageScaled definition of directional light. $\endgroup$ Commented 3 hours ago

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.