如何使用 TikZ 或 PSTricks 将 2D 矩形图像附加到 3D 曲面?

如何使用 TikZ 或 PSTricks 将 2D 矩形图像附加到 3D 曲面?

我想要做所谓的纹理映射,即将图像附加到曲面上。

如何使用 TikZ 或 PSTricks 将 2D 矩形图像附加到 3D 曲面?

为简单起见,设曲面为z=f(x,y)=asin(bx+cy)+d

答案1

正如克里斯蒂安所说,您可以使用外部程序并使用 pgfplots 包含图像。

作为概念验证,这里有一个命令\drapeimageonsurface{<image>}{<equation>},它接受一个图像文件名和一个方程式,并使用rglR 中的库将图像覆盖在表面上。它从图像中移除背景,并计算和设置必要的映射以将其包含在 pgfplots 中。

整个东西的边缘非常粗糙,基本上没有用户界面,但它可以工作。

此图像(地图取自http://en.wikipedia.org/wiki/File:Equirectangular_projection_SW.jpg

由以下生成

    \begin{document}
    \begin{tikzpicture}
    \drapeimageonsurface{worldmap.png}{abs(x)+abs(y)}
    \begin{axis}[3d box=complete, zmin=0, zmax=2]
    \addplot3 graphics {draped.png};

    \draw [fill=yellow] (axis cs:-0.67,0.41,1.08) circle [radius=3pt] node [font=\small, right=2pt, fill=white, fill opacity=0.5, text opacity=1] {San Francisco};
    \draw [fill=yellow] (axis cs:0.78,0.39,1.17) circle [radius=3pt] node [font=\small, text depth=0pt,below left=2pt, fill=white, fill opacity=0.5, text opacity=1] {Tokyo};
    \end{axis}
    \end{tikzpicture}
    \end{document}

由以下生成

\begin{document}
\begin{tikzpicture}
\drapeimageonsurface{worldmap.png}{1+sin(2*x)*(-cos(y))}
\begin{axis}[3d box=complete, zmin=0, zmax=2]
\addplot3 graphics {draped.png};

\end{axis}
\end{tikzpicture}
\end{document}

完整代码如下:

\documentclass{article}
\usepackage{pgfplots}
\makeatletter
\newcommand{\drapeimageonsurface}[2]{
% Create R script
\newwrite\tempfile
\immediate\openout\tempfile=rscript.r
\immediate\write\tempfile{library(rgl)^^J%
open3d()^^J%
par3d(windowRect=c(0,0,800,800))^^J%
x <- matrix(seq(-1,1,len=50),50,50,byrow=F)^^J%
y <- -matrix(seq(-1,1,len=50),50,50,byrow=T)^^J%
z<-#2^^J%
persp3d(x,y,z,col="white", texture="#1",specular="black",box=F,axes=F,xlab="",zlab="",ylab="")^^J%
view3d(userMatrix= rotate3d(rotationMatrix(-0.3*pi/2, 1,0,0),-pi/9,0,0,1),fov=0, scale=c(1,1,1))^^J%
rgl.snapshot('test.png')^^J%
M = par3d("modelMatrix")^^J%
viewport = par3d("viewport")^^J%
bbox=par3d("bbox")^^J%
v=rbind(matrix(bbox[c(1,3,5,2,3,5,1,4,5,2,4,6)],3),rep(1,4))^^J%
u = M \@percentchar*\@percentchar v^^J%
P = par3d("projMatrix")^^J%
A<-P \@percentchar*\@percentchar u^^J%
a=A / outer(rep(1,4),A[4,])^^J%
(a[1,]+1)/2*(viewport[3]-viewport[1])^^J%
(a[2,]+1)/2*(viewport[4]-viewport[2])^^J%
sink("3dmapping.txt")^^J%
cat("(")^^J%
cat(v[1:3,1],sep=",")^^J%
cat(") => (")^^J%
cat((a[1,1]+1)/2*(viewport[3]-viewport[1]),(a[2,1]+1)/2*(viewport[3]-viewport[1]),sep=",")^^J%
cat(")\@backslashchar n")^^J%
cat("(")^^J%
cat(v[1:3,2],sep=",")^^J%
cat(") => (")^^J%
cat((a[1,2]+1)/2*(viewport[3]-viewport[1]),(a[2,2]+1)/2*(viewport[3]-viewport[1]),sep=",")^^J%
cat(")\@backslashchar n")^^J%
cat("(")^^J%
cat(v[1:3,3],sep=",")^^J%
cat(") => (")^^J%
cat((a[1,3]+1)/2*(viewport[3]-viewport[1]),(a[2,3]+1)/2*(viewport[3]-viewport[1]),sep=",")^^J%
cat(")\@backslashchar n")^^J%
cat("(")^^J%
cat(v[1:3,4],sep=",")^^J%
cat(") => (")^^J%
cat((a[1,4]+1)/2*(viewport[3]-viewport[1]),(a[2,4]+1)/2*(viewport[3]-viewport[1]),sep=",")^^J%
cat(")")}
\immediate\write\tempfile{sink()}
\immediate\write\tempfile{viewport}
\immediate\write\tempfile{u}
\immediate\closeout\tempfile

% Run R script
\immediate\write18{R CMD BATCH rscript.r rscript.log}

% Remove image background
\immediate\write18{convert test.png -alpha set -channel alpha -fill none -floodfill +0+0 white draped.png}

% Set mapping
\everyeof{\relax}
\makeatletter
\def\auxmacro##1\relax{\pgfplotsset{plot graphics/points={##1}}}
\expandafter\auxmacro\@@input 3dmapping.txt 
\makeatother
}


\begin{document}
\begin{tikzpicture}
\drapeimageonsurface{worldmap.png}{1+sin(2*x)*(-2*cos(y))}
\begin{axis}[3d box=complete, zmin=-1, zmax=4]
\addplot3 graphics {draped.png};
\end{axis}
\end{tikzpicture}
\end{document}

答案2

据我所知,TikZ 没有纹理映射库。

您可以做的是:使用外部工具(可能是 matlab)生成纹理映射图像,然后将图形(仅图形)导入 pgfplots。这将导致 TikZ 生成轴描述。Pgfplots 可以将正确的 3d 轴叠加在某些 3d 场景的 2d 投影(正交投影)的下方/上方。

pgfplots 中的三维直方图对于相关示例(即通过第三方工具生成并导入到 pgfplots 中的内容)。

相关内容