CGA essentials

Coordinate systems

3D coordinate systems are used to describe the position and orientation of objects in space. While CityEngine can work with many types of (georeferenced) coordinate systems, CGA modeling works only with Cartesian coordinate systems. A coordinate system is defined by its origin and the orientation of the three orthogonal axes. While one global coordinate system is sufficient to define each vertex of a geometry, it is more practical to use a hierarchy of coordinate systems that are defined relative to each other.

For example, a car model is placed on a street segment. It makes sense to define the position of the wheels relative to the car and the position of the car relative to the street. The origin and the orientation of the car system are defined with coordinates of the street system. This way, the two coordinate systems are relative to each other and the coordinates of one system can be translated into coordinates of the other.

Several coordinate systems are involved when working with shapes. All transformations described above operate in the system defined by the current shape's scope, the scope system. There is also a pivot system associated to each shape, and every shape defines an object coordinate system.

Multiple coordinate systems are relative to each other in CGA:

World Coordinate System

  • Defined per scene.
  • Global—there can be only one per scene.
  • Can be georeferenced, but doesn't have to be.
  • The position of initial shapes is defined in world coordinates.

World Coordinate System
Object Coordinate System

  • Local coordinate system is defined for each initial shape.
  • The origin is placed at the first point of the initial shape's first edge.
  • The axes are oriented so that the x-axis is directed along the first edge, the y-axis is directed along the first face's normal, and the z-axis is perpendicular to the first two.

Object Coordinate System
Pivot Coordinate System

  • The pivot system is described in object coordinates.
  • In many cases, the pivot origin and orientation are identical with the object coordinates. Still, it becomes a factor, for example, with component splits.

Pivot Coordinate System
Scope Coordinate System

  • The scope is like a bounding box that is placed and oriented in the pivot system.
  • In addition to its characteristics of a coordinate system, the scope has also a size. The size is defined by a width, height, and depth.
  • Using transformations, you can define the position, orientation, and size of the scope.

Scope Coordinate System

CGA shapes

CGA shapes are the central component of the CGA shape grammar. A shape consists of a geometry in an oriented bounding box, the scope. The scope is placed relative to the pivot.

CGA shapes
The translation and size of the scope applied in the pivot coordinate system defines the position, size, and orientation of the geometry.

Initial shapes serve as a starting CGA shape for CGA rules. See Shapes.

A shape has the following components:

Shape Symbol

The name of the shape. Used to find the matching rule that is used to generate the successive shapes.


The pivot describes the shape's coordinate system and is defined by the following:

  • A position vector p (pivot.px,, pivot.pz)
  • An orientation vector o (pivot.ox, pivot.oy, and pivot.oz.

The pivot is given in object coordinates, relative to the initial shape's origin; see Coordinate systems.


The scope represents the oriented bounding box for the shape in space relative to the pivot and is defined by three vectors:

  • Translation vector t (scope.tx, scope.ty, and
  • Rotation vector r (scope.rx, scope.ry, and scope.rz)
  • Size vector s (,, and


The geometry contains the information about the corners, edges, and faces that make up the form of the shape. The geometry can be any type of polygonal mesh. In addition, information about color, material, and textures (shader attributes) is stored in the geometry.


Each shape can have an associated parameter list. The ordered parameter list is implicitly defined in the rule that creates the shape. Three parameter types are supported:

  • Boolean
  • Numeric (internally represented with double-precision float)
  • String

Rule application

The basic purpose of a rule is to replace a shape with a specific shape symbol with a number of new shapes, for example:

PredecessorShape --> Successor

The following is a simple example:

A --> B

On application on a specific shape with symbol A, the rule above creates a copy of the shape and sets its shape symbol to B. The A shape is now considered completed and not processed further. If there is no rule matching symbol B, the generation process is finished. The resulting structure is called the shape tree and looks like the following example:

Shape tree
Shape tree

In the example shape tree, A is the root shape and B is a leaf shape. Leaves are important because the sum of all leaves represents the generated model. Inner nodes are not visible in the final model.

Generated model
Generated model

In this simple example, shape A's geometry is assumed, and scope and pivot are set up so that the shape represents a unit cube in the origin. Because B is a copy of A, B looks exactly the same (see the image above).

A rule can have more complex successors, for example, the right side of the rule can consist of multiple shape symbols and shape operations:

A --> B t(3, 0, 0) C

This successor is now run from the left to the right. Again, B is an identical copy of A. The current shape is then translated by 3 units in x-direction (in other words, scope.t is manipulated) and a new shape C is created. The shape tree now has two leaves:

Shape C created in tree
Shape C created in tree

The two leaves B and C make up the final 3D model:

Leaves B and C make up final model
Leaves B and C make up final model

Add this rule for C:

C --> D s(2, 0.5, 1.75) E

The generation process adds two children, D and E, to shape C. Shape D is an exact copy of shape C, but shape E will have a different-sized scope (because of the s() shape operation). The shape tree and the associated model look like this:

Model with children D and E added
Shape tree and model with children D and E added
Shape tree and model with children D and E added

Now, the leaves (B, D, E) are not on the same level (in other words, they have different distances to the root shape), but they are all part of the model.

Another shape operation is the insert operation i():

E --> i("cylinder.obj") F

After starting the generation again, shape E is no longer a leaf but now has a child shape, F.

Shape E with child shape F
Shape E with child shape F

The geometry of shape F is no longer a cube but is replaced with the mesh read from file "cylinder.obj".


The size (in other words, the scope.s vector) of shape F is still the same as that of shape E.

Shape F with same size as shape E
Shape F with same size as shape E

Terminal shapes

In the E rule above, F is a so-called terminal shape: because no F rule is defined, the generation is stopped at this point. However, the CGA editor will issue an undefined rule warning. This can be suppressed by adding a period after F, which marks F as a terminal shape:

E --> i("cylinder.obj") F.

Anonymous leaf shapes

For convenience, rules such as the E rule above can be truncated:

E --> i("cylinder.obj")

In this case (in other words, when E has no children), the rule interpreter silently inserts an anonymous leaf with the same name as the rule itself. The shape tree after applying the E rule above looks like this:

Shape tree after applying the E rule
The shape tree after applying the E rule