Skip to main content

GraphicsComplex

WLJS
Execution environment
Supports dynamics
GraphicsComplex[data_List, primitives_, opts___]

represents an efficient graphics structure for drawing complex 3D objects (or 2D - see GraphicsComplex) storing vertices data in data variable. It replaces indexes found in primitives (can be nested) with a corresponding vertices and colors (if specified)

Most plotting functions such as ListPlot3D and others use this way showing 3D graphics.

The implementation of GraphicsComplex is based on a low-level THREE.js buffer position attribute directly written to a GPU memory.

Supported primitives

Line

No restrictions

v = PolyhedronData["Dodecahedron", "Vertices"] // N;
i = PolyhedronData["Dodecahedron", "FaceIndices"];
GraphicsComplex[v, {Black, Line[i]}] // Graphics3D 

Polygon

Triangles works faster than quads or pentagons

GraphicsComplex[v, Polygon[i]] // Graphics3D 

Non-indexed geometry

One can provide only the ranges for the triangles to be rendered

GraphicsComplex[v, Polygon[1, Length[v]]] // Graphics3D 
warning

it assumes you are using triangles

Point

Sphere

Tube

Options

"VertexColors"

Defines sets of colors used for shading vertices

info

"VertexColors" is a plain list which must have the following form

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

Supports dynamic updates

"VertexNormals"

Defines sets of normals used for shading

Supports dynamic updates

Dynamic updates

Basic fixed indexes

It does support dynamic updates for vertices data and colors. Use Offload wrapper.

cell 1
(* generate mesh *)
proc = HardcorePointProcess[50, 0.5, 2];
reg = Rectangle[{-10, -10}, {10, 10}];
samples = RandomPointConfiguration[proc, reg]["Points"];

(* triangulate *)
Needs["ComputationalGeometry`"];
triangles2[points_] := Module[{tr, triples},
tr = DelaunayTriangulation[points];
triples = Flatten[Function[{v, list},
Switch[Length[list],
(* account for nodes with connectivity 2 or less *)
1, {},
2, {Flatten[{v, list}]},
_, {v, ##} & @@@ Partition[list, 2, 1, {1, 1}]
]
] @@@ tr, 1];
Cases[GatherBy[triples, Sort], a_ /; Length[a] == 3 :> a[[1]]]]

triangles = triangles2[samples];

(* sample function *)
f[p_, {x_,y_,z_}] := z Exp[-(*FB[*)(((*SpB[*)Power[Norm[p - {x,y}](*|*),(*|*)2](*]SpB*))(*,*)/(*,*)(2.))(*]FB*)]

(* initial data *)
probe = {#[[1]], #[[2]], f[#, {10, 0, 0}]} &/@ samples // Chop;
colors = With[{mm = MinMax[probe[[All,3]]]},
(Blend[{{mm[[1]], Blue}, {mm[[2]], Red}}, #[[3]]] )&/@ probe /. {RGBColor -> List} // Chop];
cell 2
Graphics3D[{
GraphicsComplex[probe // Offload, {Polygon[triangles]}, "VertexColors"->Offload[colors, "Static"->True]],

EventHandler[Sphere[{0,0,0}, 0.1], {"transform"->Function[data, With[{pos = data["position"]},
probe = {#[[1]], #[[2]], f[#, pos]} &/@ samples // Chop;
colors = With[{mm = MinMax[probe[[All,3]]]},
(Blend[{{mm[[1]], Blue}, {mm[[2]], Red}}, #[[3]]] )&/@ probe /. {RGBColor -> List} // Chop];
]]}]
}]

The result is interactive 3D plot

Or the variation of it, if we add a point light source

light = {0,0,0};
Graphics3D[{
GraphicsComplex[probe // Offload, {Polygon[triangles]}],
PointLight[Red, light // Offload],

EventHandler[Sphere[{0,0,0}, 0.1], {"transform"->Function[data, With[{pos = data["position"]},
probe = {#[[1]], #[[2]], f[#, pos]} &/@ samples // Chop;
light = pos;
]]}]
}]

Update indexes and vertices

For more complicated example you can update both. Here is an example with dynamic adapter for ParametericPlot3D

define shapes

cell 1
sample[t_] := With[{
complex = ParametricPlot3D[
(1 - t) * {
(2 + Cos[v]) * Cos[u],
(2 + Cos[v]) * Sin[u],
Sin[v]
} + t * {
1.16^v * Cos[v] * (1 + Cos[u]),
-1.16^v * Sin[v] * (1 + Cos[u]),
-2 * 1.16^v * (1 + Sin[u]) + 1.0
},
{u, 0, 2\[Pi]},
{v, -\[Pi], \[Pi]},
MaxRecursion -> 2,
Mesh -> None
][[1, 1]]
},
{
complex[[1]],
Cases[complex[[2]], _Polygon, 6] // First // First,
complex[[3, 2]]
}
]

now construct the scene

LeakyModule[{
vertices, normals, indices
},
{
EventHandler[InputRange[0,1,0.1,0], Function[value,
With[{res = sample[value]},
normals = res[[3]];
indices = res[[2]];
vertices = res[[1]];
];
]],

{vertices, indices, normals} = sample[0];

Graphics3D[{
MeshMaterial[MeshToonMaterial[]], Gray,
SpotLight[Red, 5 {1,1,1}], SpotLight[Blue, 5 {-1,-1,1}],
SpotLight[Green, 5 {1,-1,1}],
PointLight[Magenta, {10,10,10}],

GraphicsComplex[vertices // Offload, {
Polygon[indices // Offload]
}, VertexNormals->Offload[normals, "Static"->True]]

}, Lighting->None]
} // Column // Panel
]

Non-indexed

This is a another mode of working with Non-indexed geometry in Polygon. The benefit of this approach, you can use fixed length buffer for vertices and limit your drawing range using two arguments of Polygon.

tip

Use non-indexed geometry if your polygon count reaches 1 million.

Paint 3D

Marching Cubes examples