All the fun you can have with NGons

by jfyelle

Hello everyone,

I’m joining this blog and as a first topic, will be talking about my friend, the Ngon.

As you may know, a PolygonObject is composed of CPolygons which are 4 sided polygons.  The triangle case is supported by using the same vector ID for the c and d members.  There is an abstraction called a NGon that represents 5+ sided polygons.  So, while I was fiddling with them for my own interop related work, I figured I could share a few tips about them and throw a couple freebies in while at it.

First, NGon is a system extending the polygon definition only : there is no support for normals or UVs – these will need to be supported independently at the sub-polygon level.

There are different ways of accessing NGons. Some are more private/difficult to use than others. In any case you will need to refer to the header file lib_ngon.h

Terminology and useful secrets


An edge is a polygon side. it is a line starting from point A and finishing at point B. (3D points are represented by class Vector (LVector) or SVector in Cinema 4D)


  • A segment in a NGon is a list of edges.  There is at least 1 segment in a NGon.
  • Segment 0 is the NGon outline.
  • Any additional segment is a hole. Holes are defined with an inverted winding.

Extracting NGon data

via Ngon and the modeling library

The Ngon class is a little bit light in term of features but will let you get most of the data you are interested in. To use the Ngon class, you need to use the method Modeling::GetNgon found in the modeling lib (lib_modeling.h).

Here`s a code snippet to iterate the Polygons, find which are NGons and process them (using Ngon, or NgonHelper described below.)

// given mesh is a PolygonObject
const CPolygon* currentPoly = NULL;
const CPolygon* polygons = NULL;
const Vector* vertices = NULL;

LONG polyCount = mesh->GetPolygonCount();
LONG ngonIdx = NOTOK;
Pgon* ngonData = NULL;
NgonBase* ngBase = mesh->GetNgonBase();
if (ngBase)
  ngonData = mesh->GetAndBuildNgon();

polygons = mesh->GetPolygonR();
vertices = mesh->GetPointR();

for (LONG i = 0; i < polyCount; ++i, ++currentPoly)
  // if ngBase there are some ngons in the mesh
  ngonIdx = NOTOK;
  if (ngBase)
    ngonIdx = ngBase->FindPolygon(i); 

  // if ngonIdx != NOTOK poly is a part of ngonIdx Ngon
  if (ngonIdx == NOTOK)
    // Standard polygon
    // This CPolygon is part of a NGon.
    // This NGon will be processed n times 
    // (n == the number of sub polygons)
    // You might want to remember which NGon were processed.

Following is a helper class that will abstract the segment concept and the pointer offsets to reach specific elements of the ngon definition. Don’t hesitate to comment and propose changes.

Via PGon

Requesting the NGon information through NGonBase::GetNgon is how it`s done internally in Cinema 4D. It is said to be faster than through the Ngon interface but I have yet to witness a sizable time difference. The internal data use the Segment concept described earlier and define it using edges.

The edges that outline the Ngon aren`t standing out of the other and you won`t find that much documentation on the topic. It`s a sign and if you haven`t picked the hint so far, let me be clear :

Use the Ngon class with the modeling library.

Yes you can thank me.

Creating NGons

Creating NGons in a PolygonObject can only be done after the triangles/quads are created.  In other words, the NGons’ CPolygon are added in the buffer right after the triangles/quads CPolygons. Not listening to this will, if you are lucky, crash Cinema 4D.

Following is a code snippet (which doesn’t deal with errors. If you plan on using this, please add some test on the values received)

AutoAlloc<Modeling> mod;

LONG index;

array ngonIndices;
[pseudo: loop all ngons (5+ sided polygons)]
  [pseudo: loop all vertices of the ngon]
    index = mod->AddPoint(mesh, [pseudo:current-vertex]);
  index = mod->CreateNgon(mesh, &ngonIndices[0], ngonIndices.GetCount());

I would like to extend my thanks to Franz for helping me out getting through the Ngons. (Other folks were involved but they seem to appreciate their relative anonymity so I won`t name them here but I’m grateful!)