2
$\begingroup$

I try to draw a figure with a following code, where one ContourPlot3D should be shown above another ContourPlot3D:

a[t_, x1_, x2_, 
   x3_] := (x1 + x3)/(x1 + x3 + Exp[2*t]*x2) - (x2 + x3)/(x2 + x3 + 
      Exp[2*t]*x1) + (x1 + x2)/(x1 + x2 + Exp[2*t]*x3);
b[t_, x1_, x2_, 
   x3_] := -(x1 + x3)/(x1 + x3 + Exp[2*t]*x2) + (x2 + x3)/(x2 + x3 + 
      Exp[2*t]*x1) + (x1 + x2)/(x1 + x2 + Exp[2*t]*x3);
c[t_, x1_, x2_, 
  x3_] := (x1 + x3)/(x1 + x3 + Exp[2*t]*x2) + (x2 + x3)/(x2 + x3 + 
     Exp[2*t]*x1) + -(x1 + x2)/(x1 + x2 + Exp[2*t]*x3)

Show[ContourPlot3D[
  v1 + v2 + v3 == 1, {v1, 0, 1}, {v2, 0, 1}, {v3, 0, 1}, 
  RegionFunction -> 
   Function[{v1, v2, v3, f}, 
    a[0, v1, v2, v3] > 0 && b[0, v1, v2, v3] > 0 && 
     c[0, v1, v2, v3] > 0], PerformanceGoal -> "Quality", 
  Ticks -> {{0, 1}, {0, 1}, {0, 1}}, ContourStyle -> Green, 
  Mesh -> None, PlotPoints -> 200, WorkingPrecision -> 10, 
  MaxRecursion -> 2], 
 ContourPlot3D[v1 + v2 + v3 == 1, {v1, 0, 1}, {v2, 0, 1}, {v3, 0, 1}, 
  RegionFunction -> 
   Function[{v1, v2, v3, f}, 
    a[10, v1, v2, v3] > 0 && b[10, v1, v2, v3] > 0 && 
     c[10, v1, v2, v3] > 0], PerformanceGoal -> "Quality", 
  ContourStyle -> Black, Mesh -> None, PlotPoints -> 200, 
  WorkingPrecision -> 10, MaxRecursion -> 2]]

My problem is: the picture is very "noisy" ("pixelated"), the green layer is visible there where (only) the black layer should be. Which pixels show through changes as the figure is rotated. I cannot really fix this behaviour by increasing the number of points or working precision. What can help here?

$\endgroup$
5
$\begingroup$

3D graphics primitives are not layered the way 2D primitives are. They are sorted and if not actually drawn back-to-front, the color of a pixel is determined by the corresponding front-most primitive. Showing the contour plots together means you have two surfaces that mathematically should occupy the same points. If that were to happen, there must be some sort of tie-breaker to decide which of the two colors to use. It looks like it is which ever primitive comes last in the initial specification, maybe. However, due to rounding error, they probably don't always occupy the same points. Knowing what I do about plotting, I am not surprized to se more pixelation near the edge of the black, because ContourPlot3D will do some extra refinement there. Since it's not doing the same calculations, the probability that rounding error will sometimes put a green polygon in front of a black one and sometimes not is greater. The flickering that occurs when rotating is typically of this rounding error. The rounding error happens in the GPU, after the kernel is done, so raising WorkingPrecision to greater than $MachinePrecision, which is about 15.95, won't help.

The way to avoid it is to use MeshShading. However, that's difficult to get to look nice in ContourPlot3D because of the way the sample space is discretized. Here's a good way for the case at hand, which relies on its symmetry:

ParametricPlot3D[{1, 1, 1}/3 + 
  r (Sin[t] {-1, -1, 2}/Sqrt[6] + Cos[t] {-1, 1, 0}/Sqrt[2]), {t, 0, 
  2 Pi}, {r, 0, 
  Min[Select[Positive]@{Sec[t + Pi/2], Sec[t - Pi/6], 
      Sec[t - 5 Pi/6]}/Sqrt[6]]},
 MeshFunctions -> {Function[{v1, v2, v3}, 
    If[v1 > 0 && v2 > 0 && v3 > 0, (* this should be unnecessary *)
     a[10, v1, v2, v3] b[10, v1, v2, v3] c[10, v1, v2, v3], -1]]},
 MeshShading -> {Green, Black}, Mesh -> {{0}},
 PlotPoints -> {97, 25},(* pick of the form {6n+1, m} *)
 Ticks -> {{0, 1}, {0, 1}, {0, 1}}, MaxRecursion -> 0]

enter image description here

It's a polar paramterization centered at the centroid. The vertices align with the angles at Pi/2, 7Pi/6, and 11Pi/6. As long as the t domain is subdivided into a multiple of 6 intervals, the MeshFunctions will find the green/black boundary. This can be insured by setting PlotPoints for t to be a multiple of 6 plus one. Setting MaxRecursion greater than 0 causes points outside the triangle to be included (why, I do not know). In that case, the MeshFunction, which is only a valid representation of the OP's RegionFunction inside the triangle, cause some of the edge of the triangle to be colored black -- rather frustrating.

Here's a ContourPlot3D way, implementing the same idea:

ContourPlot3D[v1 + v2 + v3 == 1, {v1, 0, 1}, {v2, 0, 1}, {v3, 0, 1},
 MeshFunctions -> {Function[{v1, v2, v3}, 
    a[10, v1, v2, v3] b[10, v1, v2, v3] c[10, v1, v2, v3]]},
 MeshShading -> {Green, Black}, Mesh -> {{0}},
 RegionFunction -> 
  Function[{v1, v2, v3, f}, 
   a[0, v1, v2, v3] > 0 && b[0, v1, v2, v3] > 0 && 
    c[0, v1, v2, v3] > 0], Ticks -> {{0, 1}, {0, 1}, {0, 1}}, 
 PlotPoints -> 200, MaxRecursion -> 2]

enter image description here

A close inspection will show that the black region become disconnected as it approaches the vertices.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.