Is there a way to increase the smoothness of a cylinder?
You can fix this problem by using the following Option in Graphics3D
:
Method -> {"CylinderPoints" -> {200, 1}}
Adjust 200
to match your requirements. (Indeed the default is 40
.)
Edit: I don't know exactly what the second parameter does, but using the single parameter form shown in the documentation linked below results in a big slow-down. I could guess that it is points in the other direction but that doesn't seem to make sense. Anyway I can't tell the visual difference between {200, 1}
and {200, 200}
but the former is much faster than the latter. ("CylinderPoints" -> 200
is apparently equivalent to "CylinderPoints" -> {200, 200}
.)
You can make the change permanent with the Option Inspector by changing this value in the Graphics3DBoxOptions
:
From Three-Dimensional Graphics Primitives:
Even though
Cone
,Cylinder
,Sphere
, andTube
produce high-quality renderings, their usage is scalable. A single image can contain thousands of these primitives. When rendering so many primitives, you can increase the efficiency of rendering by using special options to change the number of points used by default to renderCone
,Cylinder
,Sphere
, andTube
. The"ConePoints"
Method
option toGraphics3D
is used to reduce the rendering quality of each individual cone. Cylinder, sphere, and tube quality can be similarly adjusted using"CylinderPoints"
,"SpherePoints"
, and"TubePoints"
, respectively.
40 points:
200 points:
The direct answer has been given by Mr. Wizard already, but there is also another way that renders smoothly while giving some additional advantages:
Use Tube
instead of Cylinder
. One advantage is that Tube
allows you to do additional styling with VertexColors
, not supported by Cylinder
.
I will assume that we named your large list of Cylinder
objects artwork
. Using this, you can render the Tube
version like this:
Graphics3D[{CapForm["Butt"],
artwork /. Cylinder -> Tube},
Method -> {"TubePoints" -> 600}]
Here, TubePoints
is the equivalent to CylinderPoints
in Mr.Wizard's answer. I deliberately cranked up the number of points to 600
to see if there is any noticeable lag with Tube
. It seems that this method produces output that is just as responsive as the Cylinder
method with Method -> {"CylinderPoints" -> {600, 1}}
.
Edit to address follow-up question about Export
As was not initially clear, the ultimate goal of the question is to produce a 3D graphics that can be exported to STL
format at the same vertex count that is displayed in Mathematica.
This is not the case with solutions based on Cylinder
or Tube
as far as we've been able to tell so far. Therefore, I revisited another answer where I made a custom cylinder function motivated by the desire to incorporate VertexNormals
. It's slight overkill here because that function allows an arbitrary cross-sectional shape which we don't need here. But since I already have it, this seemed easiest to me. Also, prism
can be used in its own right to generalize the question.
First I recall the function prism
from that answer, and then I wrap it by a function cyl
that emulates a Cylinder
between two points:
ClearAll[prism]
prism[pts_List, h_] :=
Module[{bottoms, tops, surfacePoints, sidePoints},
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}}];
MapThread[
Polygon[#1, VertexNormals -> (#1 - #2)] &,
{
Join[sidePoints, surfacePoints],
Join[Map[{0, 0, 1} # &, sidePoints, {2}],
Map[({1, 1, 0} # + {0, 0, h/2}) &, surfacePoints, {2}]
]
}
]
]
cyl[{pt1_, pt2_}, r_, n_: 90] := Module[{
circle =
r Table[{Cos[ϕ], Sin[ϕ]}, {ϕ, 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]]]]]
gg = Graphics3D[artwork /. Cylinder -> cyl];
Export["gg.stl", gg]
The result is in gg
, and the default vertex count around the perimeter is n=90
. You can verify in an external program that this count is preserved in the Export
. Here is what it looks like in Blender with the default 90
polygon points:
Here's a replacement for Cylinder
that uses splines.
Clear[splineCylinder];
splineCylinder[{a_, b_}, r_: 1] :=
Module[{
base = r {{0, -1, 0}, {1, -1, 0}, {1, 1, 0}, {0, 1, 0},
{-1, 1, 0}, {-1, -1, 0}, {0, -1, 0}},
weights = {1, 0.5, 0.5, 1, 0.5, 0.5, 1},
knots = {0, 0, 0, 1/4, 1/2, 1/2, 3/4, 1, 1, 1},
transform, baseA, baseB
},
transform = If[Chop@Cross[{0, 0, 1}, b - a] == {0, 0, 0}, Identity,
RotationTransform[{{0, 0, 1}, Normalize[b - a]}]];
baseA = a + transform@# & /@ base;
baseB = b + transform@# & /@ base;
BSplineSurface[#, SplineDegree -> 2, SplineKnots -> {Automatic, knots},
SplineWeights -> {weights, weights}, SplineClosed -> {False, True}] & /@
{
{baseA, baseB},
{baseA, a + 0 # & /@ base},
{baseB, b + 0 # & /@ base}
}
]
It's smoother, yet slower. It also has a balloon knot in the centre of each cap. But you can't see that in your graphic.
Edit: This fails utterly to be exported to an STL file. It appears that exporting a 3D spline is not yet fully implemented in Mathematica (9.0.1).