TikZ/PGFPlots를 사용한 3D 조명 및 음영

TikZ/PGFPlots를 사용한 3D 조명 및 음영

기본 3D 조명 모델을 사용하여 3D 파라메트릭 표면을 음영처리하려고 하는데이 답변TikZ는 조명을 지원하지 않는다고 말합니다. 유일한 옵션은 색상 그라데이션을 사용하여 정점을 음영 처리하는 것입니다. 이는 특정 그래프에서는 허용될 수 있지만 3D 개체의 실제 모양을 표시하려는 경우에는 허용되지 않습니다.

하지만 TikZ에는 이를 수행하는 데 사용할 수 있는 모든 데이터가 분명히 있습니다. 도함수는 각 꼭지점에 대해 수치적으로 계산할 수 있습니다(즉, 사용자가 각 표면에 대해 수동으로 분석적으로 파생할 필요가 없습니다). 그런 다음 이를 사용하여 법선을 구성할 수 있습니다. 사용자가 포인트 라이트 위치를 지정하게 하면 확산 조명이 됩니다. 카메라 위치를 잡아서 반사광 조명도 갖게 됩니다.

Asymptote와 같은 패키지가 멋진 3D 이미지를 생성할 수 있다는 것을 알고 있지만 이러한 솔루션은 래스터 그래픽을 생성하므로 벡터 그래픽이 필요합니다.

TikZ에 3D 조명 및 음영을 어떻게 추가할 수 있나요?이미 존재하지 않는 이유가 있나요? TikZ가 어떻게 구현되는지 모르고 이전에 확장 기능을 작성한 적이 없기 때문에 이 기능을 어떻게 추가할지 모르겠습니다.

답변1

여기에 이미지 설명을 입력하세요

이는 TikZ 내부에서 직접 계산을 통해 얻습니다. 표면은 파라메트릭 방식으로 제공되지만 LaTeX 메모리 제한은 이미 거의 다뤄졌습니다. 코드는 아래에 내가 제공한 답변에서 수정되었습니다.TikZ에서 토러스 음영 처리. 거기에 몇 가지 설명이 있습니다. 그림자를 추가했기 때문에 코드를 다시 제공합니다.

좌표에는 그림자가 없습니다. 의 캐스트 섀도우를 사용해 보고 싶은 유혹이 있습니다.온스축... 어쩌면 sagetex계산을 수행하는 데 사용하는 DJP의 아이디어가 합리적인 것일 수도 있습니다.

\documentclass[margin=10pt]{standalone}
\usepackage{ifthen}
\usepackage[rgb]{xcolor}
\usepackage{tikz}
\usetikzlibrary{cd, arrows, matrix, intersections, math, calc}
\xdefinecolor{O}{RGB}{255, 102, 17}
\xdefinecolor{B}{RGB}{17, 87, 221}

\begin{document}

\tikzmath{%
  real \slongit, \slatit, \sunx, \suny, \sunz;  % towards the light source 
  real \longit, \latit, \tox, \toy, \toz;
  real \newxx, \newxy, \newyx, \newyy, \newzx, \newzy;  
  \slongit = 100; \slatit = 45;
  \sunx = sin(\slongit)*cos(\slatit);
  \suny = sin(\slatit);
  \sunz = cos(\slongit)*cos(\slatit);
  \longit = 25;  \latit = 36;  % 35;
  \tox = sin(\longit)*cos(\latit);
  \toy = sin(\latit);
  \toz = cos(\longit)*cos(\latit);
  \newxx = cos(\longit); \newxy = -sin(\longit)*sin(\latit);
  \newyy = cos(\latit);
  \newzx = -sin(\longit); \newzy = -cos(\longit)*sin(\latit);
  real \ry, \rz;
  \ry = 4;
  \rz = 1.5;  
  integer \Ny, \Nz, \j, \k, \prevj, \prevk, \aj, \ak;
  % j moves around Oy and k moves around Oz.
  % They describe full circles of radii \ry and \rz respectively.
  \Nz = 48;  % 24;  % 60;
  \Ny = 80;  % 36;  % 120;
  \ktmp = \Nz-1; 
  \jtmp = \Ny-1;
  \aj = 10;
  \ak = 0;
  function isSeen(\j, \k) {
    let \px = cos(360*(\k/\Nz))*cos(360*(\j/\Ny));
    let \py = -sin(360*(\k/\Nz));
    let \pz = cos(360*(\k/\Nz))*sin(360*(\j/\Ny));
    let \res = \px*\tox + \py*\toy + \pz*\toz;
    if \res>0 then {return 1;} else {return 0;};
  };
  function inLight(\j, \k) {%
    let \px = cos(360*(\k/\Nz))*cos(360*(\j/\Ny));
    let \py = -sin(360*(\k/\Nz));
    let \pz = cos(360*(\k/\Nz))*sin(360*(\j/\Ny));
    return {\px*\sunx + \py*\suny + \pz*\sunz};
  };
  function projX(\j, \k) {%
    let \px = \ry+\rz*cos(360*(\k/\Nz))*cos(360*(\j/\Ny));
    let \py = -\rz*sin(360*(\k/\Nz));
    let \t = -(\rz+\py)/\suny;
    return {\px + \t*\sunx};
  };
  function projZ(\j, \k) {%
    let \py = -\rz*sin(360*(\k/\Nz));
    let \pz = \ry+\rz*cos(360*(\k/\Nz))*sin(360*(\j/\Ny));
    let \t = -(\rz+\py)/\suny;
    return {\pz + \t*\sunz};
  };
  function T(\j, \k) {%
    let \py = -\rz*sin(360*(\k/\Nz));
    let \pz = \ry+\rz*cos(360*(\k/\Nz))*sin(360*(\j/\Ny));
    return {\rz*(-1+sin(360*(\k/\Nz)))/\suny};
  };
}


\begin{tikzpicture}[every node/.style={scale=.8},
  x={(\newxx cm, \newxy cm)},
  y={(0 cm, \newyy cm)},
  z={(\newzx cm, \newzy cm)},
  evaluate={%
    % int \j, \k;
    real \tmp;
    for \j in {0, 1, ..., \Ny}{%
      for \k in {0, 1, ..., \Nz}{%
        \test{\j,\k} = isSeen(\j, \k);
        if \test{\j,\k}>0 then {%
          \tmp{\j,\k} = int(100*inLight(\j,\k)));
          if \tmp{\j,\k}>0 then {%
            \tmpW{\j,\k}=int(100*inLight(\j,\k)^2);
          }
          else {%
            \tmpK{\j,\k}=-int(100*inLight(\j,\k));
          };
        } else {};
      };
    };
  }]

  % points (P-\j-\k)
  \foreach \j in {0, ..., \Ny}{%
    \foreach \k in {0, ..., \Nz}{%
      \path
      ( {( \ry+\rz*cos(360*(\k/\Nz)) )*cos(360*(\j/\Ny))},
      {-\rz*sin(360*(\k/\Nz))},
      {( \ry+\rz*cos(360*(\k/\Nz)) )*sin(360*(\j/\Ny))} )
      coordinate (P-\j-\k);
    }
  }


  % shadow
  \foreach \k [remember=\k as \prevk (initially 0)] in {1, ..., \Nz}{%
    \foreach \j [remember=\j as \prevj (initially 0)] in {1, ..., \Ny}{%
      \fill[gray!70!black, opacity={.4*abs(inLight(\j,\k))}]
      ($(P-\j-\prevk)+T(\j,\prevk)*(\sunx, \suny, \sunz)$)
      -- ($(P-\prevj-\prevk)+T(\prevj,\prevk)*(\sunx, \suny, \sunz)$)
      -- ($(P-\prevj-\k)+T(\prevj,\k)*(\sunx, \suny, \sunz)$)
      -- ($(P-\j-\k)+T(\j,\k)*(\sunx, \suny, \sunz)$) -- cycle;
    }
  }
  
  % coordinate system $Oxyz$; first layer
  \draw[green!50!black]
  (0, 0, 0) -- (\ry, 0, 0)
  (0, 0, 0) -- (0, 0, \ry);

  % "squares"---the mesh
  \foreach \k [remember=\k as \prevk (initially 0)] in {1, ..., \Nz}{%
    \foreach \j [remember=\j as \prevj (initially 0)] in {1, ..., \Ny}{%
      \ifthenelse{\test{\j,\k}=1}{
        \ifthenelse{\tmp{\j,\k}>0}{
          \filldraw[white!\tmpW{\j,\k}!B]
          (P-\j-\prevk) -- (P-\prevj-\prevk)
          -- (P-\prevj-\k) --(P-\j-\k) -- cycle;
        }{%
          \filldraw[black!\tmpK{\j,\k}!B]
          (P-\j-\prevk) -- (P-\prevj-\prevk)
          -- (P-\prevj-\k) --(P-\j-\k) -- cycle;
        }
      }{}
    }
  }

  % longitude cycle
  \foreach \k [remember=\k as \prevk (initially 0)] in {1, ..., \Nz}{%
    \ifthenelse{\test{\aj,\k}=1}{
      \draw[red, thick] (P-\aj-\k) -- (P-\aj-\prevk);
    }{
      \draw[red, very thin, opacity=.4] (P-\aj-\k) -- (P-\aj-\prevk);
    }
  }

  % latitude cycle
  \foreach \j [remember=\j as \prevj (initially 0)] in {1, ..., \Ny}{%
    \ifthenelse{\test{\j,\ak}=1}{
      \draw[red, thick] (P-\j-\ak) -- (P-\prevj-\ak);
    }{
      \draw[red, very thin, opacity=.3] (P-\j-\ak) -- (P-\prevj-\ak);
    }
  }
  
  % coordinate system $Oxyz$; second layer
  \draw[green!50!black, -{Latex[length=5pt, width=5pt]}]
  (\ry+\rz, 0, 0) -- (8, 0, 0) node[right] {$x$};
  \draw[green!50!black, -{Latex[length=5pt, width=5pt]}]
  (0, 0, 0) -- (0, 6, 0) node[above] {$y$};
  \draw[green!50!black, -{Latex[length=5pt, width=5pt]}]
  (0, 0, \ry+\rz) -- (0, 0, 8) node[below left] {$z$};
\end{tikzpicture} 
\end{document}

관련 정보