How to color the triangles of a mesh?
There are 69,451 different polygons in the bunny, so that is why it takes so long to plot, so let's use a simpler example with only ~1,400 polygons:
MeshVertices[mesh_] :=
First@Cases[mesh, GraphicsComplex[x_, __] :> x, Infinity]
MeshFaces[mesh_] :=
Block[{faces},
faces = Cases[mesh, Polygon[x_, ___] :> x, Infinity];
If[faces == {},
faces = Cases[mesh, Triangle[x_, ___] :> x, Infinity];];
If[faces == {}, {}, First@faces]];
donut = ParametricPlot3D[{(3 + Cos[v]) Cos[u], (3 + Cos[v]) Sin[u],
Sin[v]}, {u, 0, 2 Pi}, {v, 0, 2 Pi}, Mesh -> None];
faces = MeshFaces[donut];
nFaces = Length[faces];
faceColors = RGBColor[#, 0.0, 0.0] & /@ Rest[Subdivide[1.0, nFaces]];
vertices = MeshVertices[donut];
When you run your code, it places a black border around every triangle. Compare these
Graphics3D /@ {Triangle[{{0, 0, 0}, {1, 0, 0}, {0, 1,
1}}], {EdgeForm[], Triangle[{{0, 0, 0}, {1, 0, 0}, {0, 1, 1}}]}}
So you need to turn off the EdgeForm[]
in your final line,
coloredDonut =
Graphics3D[
GraphicsComplex[vertices,
Thread[{faceColors, {EdgeForm[], Polygon[#]} & /@ faces}]],
Boxed -> False]
Here is what it looks like with the borders:
When you apply this to your bunny, here is the result:
By the way, here is slightly shorter code that produces the exact same result,
bunny = ExampleData[{"Geometry3D", "StanfordBunny"}];
colors = RGBColor[#, 0.0, 0.0] & /@
Subdivide[1.0,
Length[Cases[Normal@bunny, Polygon[__], Infinity]]];
i = 1;
Normal[bunny] /. {Polygon[a__] :>
Sequence[i++; colors[[i]], Polygon[a]]}
The above code with replacement rule should work on many Graphics3D
objects, like the donut
above. But in that case it is necessary to adjust the lighting by adding another replacement rule HoldPattern[Lighting -> {__}] :> Lighting -> {{"Ambient", Red}}
But since you are working on a ExampleData["Geometry3D"]
object, you can get the polygons as a list directly and then just use Thread
to combine them with colors. Thanks to Yves Klett for pointing this out
With[{pgons =
ExampleData[{"Geometry3D", "UtahVWBug"}, "PolygonObjects"]},
Graphics3D[{EdgeForm[],
Thread[{RGBColor[#, 0.0, 0.0] & /@
Subdivide[1.0, Length@pgons - 1], pgons}]}, Boxed -> False]
]
Or a one-liner to give a psychedelic bunny
Normal[ExampleData[{"Geometry3D", "StanfordBunny"}]] /. {Polygon[
a__] :> Sequence[RandomColor[], Polygon[a]]}
Jason already said a lot of what I wanted to say, so I'll just offer this little snippet that avoids Normal[]
chicanery:
gc = ExampleData[{"Geometry3D", "StanfordBunny"}, "GraphicsComplex"];
Graphics3D[Insert[gc, EdgeForm[], {2, 1}] /. Polygon[m_?MatrixQ] :>
Riffle[Table[RandomColor[], {Length[m]}], Polygon /@ m]]
Just for variety, here's another method for coloring the bunny. Recall that GraphicsComplex[]
takes a VertexColors
option to specify how the polygons within should be colored. (Line[]
objects are not affected by this, which may or may not be wanted in an application.) Thus,
(* some color function that takes a point as an argument *)
woody[pt_?VectorQ] := Blend[{RGBColor[3/4, 22/41, 1/3], RGBColor[1/2, 2/9, 7/38]},
Haversine[π SawtoothWave[50 EuclideanDistance[pt,
{0.08, 0.06, 0.08}]]]]
Graphics3D[Insert[gc, EdgeForm[], {2, 1}] /.
gc : GraphicsComplex[pts_, rest___] :>
Append[gc, VertexColors -> (woody /@ pts)], Lighting -> "Neutral"]