[033] How to Use the Comp Command in Esri CityEngine for Component-Based Modeling
Learn how to decompose 3D volumes into editable sub-elements using the component split.
This tutorial introduces the 'comp' command, explaining the fundamental differences between it and the 'split' command. You will learn how to isolate vertices, edges, and faces from a 3D model, understand the difference between shared and independent edges, and use operators to control model hierarchy and indexing for targeted rule applications.
When I first started this blog, I thought it would be enough to simply explain a few commands, organize the important details, and finish after writing about 50 posts. Even though I have covered less than 10% of what I originally planned, this series has already reached its 33rd post.
Not long ago, I saw the music video for "Standing Next to You" and started playing the drums again, which I had forgotten about for a while. I had taken a break because my right knee would ache every time I kicked. I started by reducing the BPM to 50%, but it looks like I'll have to work hard to catch up to my original speed. Hopefully my knee can keep up.
What Is the comp Command in CityEngine?
Starting from this post, we will explore the comp command.
Why comp() Is Different from split()
The biggest difference between split and comp is that split divides faces, and its output is always another face. In other words, split operations always produce faces as their output. However, the results of comp are more diverse, including points (vertices), lines (edges), faces, groups, materials, and holes.
Understanding the Structure of comp()
The usage is as follows.
'Component' is the element to be split (point, line, face), 'selector' defines the condition used to identify matching components. 'operator' determines whether to split those elements individually or group them, and 'operation' is the part where the rule is applied.
It looks simple, but to extract components that meet specific conditions, you must construct the conditions (selector) reasonably.
In the process of using CGA to turn a simple box into a detailed 3D object by subdividing it, there are many things to consider. Since all of this must be implemented through coding, you must use appropriate selectors to select the elements you want. More selectors will likely be added in the future, allowing for even more precise selection of desired elements.
Since there is so much to cover, I'm worried about where to start. Shall we start with the component types first?
Component Types in comp()
There are seven types of components: v (vertex), e (edge or edge where faces meet), fe (face edge), f (face), g (group), m (material), and h (hole). Among these, g, m, and h are used when importing 3D objects created externally, so they aren't topics for basic comp lessons. We will focus on v, e, fe, and f.
We start with the easiest and simplest. First, create a shape and model like the following.
Using comp(v) to Extract Vertices
First, I created the code below to extract only the vertices.
Lot1 --> A
Lot2 --> extrude(world.up, 20) A
A --> comp(v) { all : color(1, 0, 0) X. }
Lot1 proceeds directly to rule A, and Lot2 proceeds to A after being extruded by 20m.
In line 3, each model selects only 'v' (vertices) and colors them red. The result is as follows.
Currently, the vertices on the ground are not visible because 'Shapes' are active in the Visibility settings of the 3D View panel.
If you uncheck 'Shapes' as shown in the figure above (F11), you will be able to see the generated vertices. The reason they look black even though they were colored red is...
Currently, you just need to disable 'Wireframe on shaded/textured' in the View settings of the 3D View panel. However, since they are literally just points, they are not easily visible unless you zoom in.
Let's change the settings a bit in the Preferences of the Edit menu.
Run Preferences and increase the Edge size and Vertices size from their default values in 'Procedural Runtime'. The setting above means to express edges at 0.1m width and vertices at 1m size.
Then it will look like the following.
The vertices have become larger. Now they are clearly recognizable.
Understanding comp(e) and Shared Edges
Next, let's try separating by 'e'. You just need to change the code from comp(v) to comp(e).
Lot1 --> A
Lot2 --> extrude(world.up, 20) A
A --> comp(e) { all : color(1, 0, 0) X. }
The result is:
While comp(e) extracts the boundaries of faces, it treats an edge where two faces meet as a single component. Shall we check the number of edges generated on the left and right? Let's check the Model Hierarchy panel.
4 edges were generated for Lot1, and 12 edges for Lot2. Keep in mind that comp(e) treats the part where faces meet as one edge.
Difference Between comp(e) and comp(fe)
Now let's look at comp(fe).
Lot1 --> A
Lot2 --> extrude(world.up, 20) A
A --> comp(fe) { all : color(1, 0, 0) X. }
Let's look at the result.
It doesn't look different from comp(e), but let's check with the Model Hierarchy panel.
How Face-Edges Work in comp(fe)
Lot1 generated 4 edges as before, but Lot2 generated 24 edges. comp(fe) treats each face boundary independently, even when edges are shared between adjacent faces. This is the difference between comp(e) and comp(fe). Keep this in mind.
Using comp(f) to Isolate Faces
Next is the most commonly used comp(f).
Lot1 --> A
Lot2 --> extrude(world.up, 20) A
A --> comp(f) { all : color(1, 0, 0) X. }
The result is:
Yes. It seems that only the initial shape and color have changed, but if you look at the Model Hierarchy:
You can see that each face is separated as a 'face'. In the case of Lot2, we can now access each of these faces and apply separate rules. Right now, we are only covering the basics of comp(). Applying rules to separated elements is something that will be done later. For now, understanding the fundamentals is more important than rushing into advanced modeling. Strong fundamentals make advanced modeling much easier later.
Difference Between ':' and '=' Operators in comp()
Next, we will compare the difference between the operators ':' and '='.
':' means that the separated elements will be processed individually, and '=' means that the separated elements will be grouped and processed as one. You can use these after the selector. The usage is as follows.
Lot1 --> extrude(world.up, 20) Equal
Lot2 --> extrude(world.up, 20) Colon
Equal --> comp(f) { all = color(0.5, 0.5, 0) X. }
Colon --> comp(f) { all : color(0, 0.5, 0.5) X. }
Lot1 separates the faces forming the shape with '=', and Lot2 separates them with ':'. The results are shown below, and if you check the Model Hierarchy:
Lot1 groups all separated faces and sends them out as one unit, while Lot2 sends out the separated faces individually. This principle applies to v, e, fe, and f in the same way. The difference lies in whether you want to receive the desired elements as a bundle to apply the next rule collectively, or separate them individually. Remember the 'index' we covered before? It allows us to find out the order in which splits or comps were performed.
How to Use comp.index in CityEngine
In the case of Lot1, comp is performed once, and in Lot2, comp is performed 6 times. This means that for Lot2, you can select a specific face and apply a rule simply by using the index.
If you click the third 'X' of Lot2 in the Hierarchy panel on the right, that specific face will be highlighted in the 3D View window. This means that by accessing index = 2, you can proceed with a separate rule for that face.
Selecting Individual Faces with comp.index
Shall we try it? I've coded it like this.
Lot2 --> extrude(world.up, 20) Colon
Colon --> comp(f) { all : A }
A -->
case (comp.index == 2) :
color(1, 0, 0)
else : X.
Line 7: Passes the faces separated by ':' to rule A.
Line 9: Colors the face red where comp.index is 2. The result?
If you select that face in the model hierarchy:
Yes. The face with index = 2 has turned red. There is still more to cover, but this post is already getting long.
I will cover the remaining content in the next post.
FAQ About comp() in CityEngine
What is the difference between split() and comp() in CityEngine?
split() divides geometry into smaller faces, while comp() extracts existing components such as vertices, edges, and faces for separate processing.
What is the difference between comp(e) and comp(fe)?
comp(e) treats shared edges between faces as a single edge, while comp(fe) generates separate edges for each face independently.
How does comp.index work in CityEngine?
comp.index stores the order of generated components, allowing you to target specific faces, edges, or vertices with conditional rules.
When should I use ':' instead of '=' in comp()?
Use ':' when you want components processed individually. Use '=' when you want all selected components grouped into a single shape.
- Learn previous workflow in [032]How to Create 3D Volumes Using Extrude in Esri CityEngine
- Continue learning with [034] Using Comp Selectors to Target Specific Faces in CityEngine
Comments
Post a Comment
Feel free to leave a comment if you have any questions about Global Mapper or CityEngine. I will get back to you with a sincere response as soon as possible. (Please note that all comments are moderated and manually approved to maintain a high-quality community. Promotional or spam content will not be published.)