# How to add texture to solid Graphics3D object such as cylinder?

I'd like to add texture to a Cylinder inside Graphics3D. I can't see how to use FaceForm and tell it to use Texture. The problem is Texture needs TextureCoordinateFunction.

I saw few solutions, but many use ParametricPlot3D, which I could use, but I need a solid Cylinder, so I would have to do the top/bottom faces manually. For example, using the solution in Applying an ArrayPlot as a texture to the surface of a cylinder I could do

mplt = MatrixPlot[Table[Sin[x y/100], {x, -10, 10}, {y, -10, 10}],
ColorFunction -> "Rainbow", Frame -> False, ImagePadding -> 0,
p = ParametricPlot3D[{ Cos[theta], Sin[theta], rho}, {theta, -Pi, Pi}, {rho, 0, 3},
PlotStyle -> Directive[Specularity[White, 30], Texture[mplt]],
TextureCoordinateFunction -> ({#1, #3} &), Lighting -> "Neutral",
Mesh -> None, PlotRange -> All, TextureCoordinateScaling -> True];

Graphics3D[First@p] But what I want is to add texture to outside surface of

  Graphics3D[Cylinder[{{0, 0, 0}, {0, 0, 3}}, 1], Axes -> True] There is solution here for 2D objects How to texturize a Disk/Circle/Rectangle? since one can find the VertexTextureCoordinates are easy to do for these.

I think what is needed here is to tell FaceForm to use Texture? but do not know how to go about this. Version 9.01

• I'd do Graphics3D[{First@p, Cylinder[{{0, 0, 0}, {0, 0, 3}}, .99]}, Axes -> True]
– Kuba
Jul 9 '14 at 6:19
• @Kuba I actually thought about this, but the top/bottom faces will be different, and more important, I am not sure it is efficient, since I am rendering a 3D object (cylinder) in addition to the texture itself. I am trying to see if I can make a circle with same texture and add these to the ParametricPlot3D to build the cylinder manually. If all else fails, will use what you suggested. Jul 9 '14 at 6:28

In general, I don't think it's possible to use Texture directly with the built-in primitives such as Sphere and Cylinder. See also Texture mapping and resizing a sphere primitive in Mathematica.

So you have to write your own replacement for those primitives. Since you specifically mentioned the Cylinder, I added the ability to handle Texture to my answer here. There, I already had added VertexNormals to give the smooth appearance that the Cylinder primitive has. Here, I inserted the VertexTextureCoordinates option into all the polygons making up the sides of my custom cylinder. The result is the following:

ClearAll[prism];
prism[pts_List, h_] :=
Module[{bottoms, tops, surfacePoints, sidePoints, n},
surfacePoints =
Table[Map[PadRight[#, 3, height] &, pts], {height, {0, h}}];
{bottoms, tops} = {Most[#], Rest[#]} &@surfacePoints;
sidePoints =
Flatten[{bottoms, RotateLeft[bottoms, {0, 1}],
RotateLeft[tops, {0, 1}], tops}, {{2, 3}, {1}}];
n = Length[sidePoints];
Polygon[#1, VertexNormals -> (#1 - #2),
VertexTextureCoordinates -> #3] &, {
Join[sidePoints, surfacePoints],
Join[Map[{0, 0, 1} # &, sidePoints, {2}],
Map[({1, 1, 0} # - {0, 0, h/2}) &, surfacePoints, {2}]
],
Join[
Table[{{i/n, 0}, {(i + 1)/n, 0}, {(i + 1)/n, 1}, {i/n, 1}}, {i,
0, n - 1}],
Table[None, {Length[surfacePoints]}]]
}
]]

Clear[cyl];
cyl[{pt1_, pt2_}, r_: 1, n_: 90] :=
Module[{circle =
r Table[{Cos[\[Phi]], Sin[\[Phi]]}, {\[Phi], Pi/n, 2 Pi, Pi/n}],
h = EuclideanDistance[pt1, pt2]},
GeometricTransformation[prism[circle, h],
Composition[TranslationTransform[pt1],
Quiet[Check[RotationTransform[{{0, 0, 1.}, pt2 - pt1}],
Identity]]]]]


The actual work is done in prism, and the compatibility with Cylinder is provided by the wrapper cyl. Here is a test:

img = ExampleData[{"TestImage", "Lena"}];

Graphics3D[{Texture[img], EdgeForm[],
cyl[{{0, 0, 0}, {0, 0, 2 Pi}}, 1]}, Boxed -> False] To get the smoothness of the surface, it's good to set the proper VertexNormals as I do in the prism function.

Edit

As an extension of this answer, you can also add textures to the base and top of the cylinder. That's done in my answer to the question How can this texture be inserted in the beginning and the end of cylinder?.