WLJS LogoWLJS Notebook

GraphicsComplex

Supports Offload
GraphicsComplex[{pt1, pt2, ...}, data]

represents a graphics complex in which coordinates given as integers i in graphics primitives in data are taken to be pti.

GraphicsComplex provides faster rendering for a complex primitives with many vertices and colors. It looks similar to an interfaces of OpenGL or other graphics framework, where buffers with coordinates are provided separately from the object instances.

See also a variant for 3D graphics.

Supported primitives

Line

Supported without HW acceleration. For example:

GraphicsComplex[{{0,0}, {1,0}, {1,1}}, Line[{1,2,3}]] // Graphics

VertexColors are not supported.

Polygon

Here it uses WebGL graphics acceleration for rendering:

GraphicsComplex[{{0,0}, {1,0}, {1,1}}, Polygon[{1,2,3}], "VertexColors"->{{1,1,0}, {0,1,1}, {0,1,1}}] // Graphics

Point

Here it uses WebGL graphics acceleration for rendering:

GraphicsComplex[{{0,0}, {1,0}, {1,1}}, Point[{1,2,3}]] // Graphics

or with colors

GraphicsComplex[{{0,0}, {1,0}, {1,1}}, Point[{1,2,3}], "VertexColors"->{{1,0,0}, {0,1,0}, {0,0,1}}] // Graphics

Arrow

Supported without HW acceleration

Disk

Supported without HW acceleration

Options

VertexColors

Defines sets of colors used for shading vertices:

v = {{1, 0}, {1, 1}, {0, 0}};
Graphics[{GraphicsComplex[v, Polygon[{1,2,3}], VertexColors -> {Red, Blue, Green}]}]

We recommend to provide VertexColors as a plain list which should have the following form

"VertexColors" ->{{r1,g1,b1}, {r2,g2,b2}, ...}

This will avoid high memory and CPU load on many polygons count.

VertexTextureCoordinates

Defines sets of UV coordinates used for mapping Texture.

img = ExampleData[{"TestImage", "Lena"}];
Graphics[{
  Texture[img],
  GraphicsComplex[
    {{-1, -1}, {1, -1}, 0.2 {1, 1}, {-1, 1}},
    Polygon[{1, 2, 3, 4}],
    VertexTextureCoordinates -> {{0, 1}, {0, 0}, {1, 0}, {1, 1}}
  ]
}]

"VertexFence"

Defaults to False. When enabled, it sets an update barrier for all dependent primitives, ensuring they update their data only after the vertex data has been updated.

This helps prevent desynchronization issues where the vertex buffer updates lag behind polygon or line indices (or vice versa), which can lead to visual artifacts and WebGL buffer errors.

Pack vertices and colors to a single symbol. This will help to avoid data racing. "VertexFence" indeed eliminates races with indices, but it is helpless against the mutations of GraphicsComplex attributes.

How to update things

Fixed indexes, variable vertices

Use Offload wrapper and AnimationFrameListener:

vert2 = CirclePoints[0.7, 50]//N;
f = Uncompress["1:eJxTTMoPSmNkYGAo5gASbqV5ySWZ+XlpTCARFiARnlmSgeD5ZBaXQHjMQCI4taQYpLUAYgBIQXBOfkkmiIepqiSNASTEAyQck4rzc0pLUkMyc1MRhgfklBZDzUOxMJMBbh4rkABpKi76s/LjJd+kAntU7RCHgG3NzEOTQjUgkwvFkS75JVitBolB7GdG1f4fCDJByqB+Q3OeMRg8tifBQXxEOQjkFkgAY3MQG9xBAJbbXNw="];
  
Graphics[{
  GraphicsComplex[vert2//Offload, {
    LightBlue, Polygon[Range[1,50]], Red, Point[Range[1,50]]
  }],
  EventHandler[AnimationFrameListener[vert2//Offload], 
    Function[Null, vert2 = f /@ vert2]
  ]
}, PlotRange->{{-1,1}, {-1,1}}]

Here is another beautiful example with 10000 points:

ClearAll[handler, n, r, f, s, x, p , q]

n = 10000/4; 
r := RandomInteger[{1, n}];
f := (#/(.01 + Sqrt[#.#])) & /@ (x[[#]] - x) &;
s := With[{r1 = r}, p[[r1]] = r; q[[r1]] = r];
x = RandomReal[{-1, 1}, {n, 2}];
ox = x;
{p, q} = RandomInteger[{1, n}, {2, n}];
    x = 0.995 x + 0.02 f[p] - 0.01 f[q];
    colors = MapThread[(List@@(RGBColor[Hue[Norm[#1-#2] 20.0]]))&, {x,ox}];    
    ox = x;
    If[r < 100, s];
    data = {x,colors};
Graphics[{
  PointSize[0.007], GraphicsComplex[data[[1]]//Offload, Point[Range[n]], VertexColors->Offload[data[[2]]]],
  EventHandler[AnimationFrameListener[data // Offload], With[{},
    x = 0.995 x + 0.02 f[p] - 0.01 f[q];
    colors = MapThread[(List@@(RGBColor[Hue[Norm[#1-#2] 20.0]]))&, {x,ox}];    
    ox = x;
    If[r < 100, s];
    data = {x,colors};
  ]&],
}, PlotRange -> {{-2,2}, {-2,2}}, TransitionType->None, Background->Black]

Update everyhting

Here is comprehensive example:

(* Grid dimensions *)
nx = 50; ny = 50;

xs = Subdivide[-1., 1., nx - 1];
ys = Subdivide[-1., 1., ny - 1];

allIndices = Flatten[Table[
  With[{v = (i - 1) ny + j},
    {{v, v + 1, v + ny + 1}, {v, v + ny + 1, v + ny}}
  ],
  {i, nx - 1}, {j, ny - 1}
], 2];

restXY = N @ Flatten[Table[{x, y}, {x, xs}, {y, ys}], 1];
nVerts = Length[restXY];
restX = restXY[[All, 1]];
restY = restXY[[All, 2]];

(* Pre-extract per-triangle vertex columns *)
tri1 = allIndices[[All, 1]];
tri2 = allIndices[[All, 2]];
tri3 = allIndices[[All, 3]];

generateFrame2D[t_] := Module[
  {vx, vy, holes, holeR = 0.22, insideAny, 
   dx, dy, dist, inH, safe, triKeep, verts},

  (* Ripple distortion *)
  vx = restX + 0.04 Sin[6 restY - 3 t];
  vy = restY + 0.04 Sin[6 restX + 2 t];

  holes = {{0.55 Cos[t], 0.55 Sin[t]},
           {0.55 Cos[t + Pi], 0.55 Sin[t + Pi]}};

  insideAny = ConstantArray[0, nVerts];

  Do[
    dx = vx - h[[1]];
    dy = vy - h[[2]];
    dist = Sqrt[dx^2 + dy^2];
    inH = UnitStep[holeR - dist];
    insideAny = Clip[insideAny + inH, {0, 1}];

    (* Project inside vertices onto the hole boundary circle *)
    safe = dist + 0.001; (* avoid division by zero *)
    vx = vx (1 - inH) + inH (h[[1]] + holeR dx / safe);
    vy = vy (1 - inH) + inH (h[[2]] + holeR dy / safe);
  , {h, holes}];

  (* Only remove triangles where ALL 3 vertices are inside *)
  triKeep = 1 - insideAny[[tri1]] insideAny[[tri2]] insideAny[[tri3]];

  verts = Transpose[{vx, vy}];

  {Pick[allIndices, triKeep, 1], {verts,
   Map[With[{s = Rescale[Sqrt[#[[1]]^2 + #[[2]]^2], {0, 1.4}]},
     List @@ RGBColor[Hue[Mod[s + 0.2 t, 1.], 0.8, 0.95]]] &, verts]}}
];

{indices, complex2D} = generateFrame2D[0.];

Graphics[{
  EdgeForm[],
  GraphicsComplex[
    Offload[complex2D[[1]]],
    {Polygon[Offload[indices]]},
    VertexColors -> Offload[complex2D[[2]]],
    "VertexFence"->True
  ],
  EventHandler[AnimationFrameListener[complex2D // Offload],
    Function[Null, {indices, complex2D} = generateFrame2D[AbsoluteTime[]]]
  ]
}, PlotRange -> {{-1.1, 1.1}, {-1.1, 1.1}}]

On this page