[064] How to Transform UV Coordinates in CityEngine CGA
Understanding UV transformations in Esri CityEngine to rotate, scale, translate, tile, and delete texture mapping coordinates using CGA rules.
This tutorial covers essential UV manipulation commands in CityEngine CGA, including rotateUV, scaleUV, translateUV, normalizeUV, tileUV, and deleteUV, enabling precise texture placement and alignment on 3D procedural geometries.
This is the final lesson on texture control.
Today, we will learn about commands to control texture rotation, scale,
position, and more after applying textures using projectUV().
You might wonder why separate commands exist when size or position can be
configured in setupProjection().
However, strictly speaking, the commands used here are not applied directly to the texture itself, but rather to the UV coordinates of the texture. They transform the UV coordinates assigned to the texture.
When we generally perform modeling in 3D programs, the coordinate system consists of X, Y, and Z.
Textures are also mapped and applied based on a coordinate system, but to avoid confusion with the XYZ coordinate system, the UVW coordinate system is used.
Modeling uses XYZ, while textures use UVW.
The commands we will learn today—such as rotateUV,
scaleUV, translateUV, normalizeUV, and
deleteUV—modify these UV coordinates.
As a result, changes occur together with the texture mapped onto the UV coordinates, making it visually appear as if the texture itself is changing.
The phrase "changes occur together with the texture mapped onto the UV coordinates" means that transformations must be applied after executing
projectUV() to apply the texture.
In other words,
@Angle
attr UV_value = 0
Lot -->
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
rotateUV(0,UV_value)
X.
It means that rotateUV() for the corresponding uvSet must come
after projectUV() has been executed.
If rotateUV on line 9 is written before projectUV,
no change will occur.
Do not forget this. It is important.
Let's take a look at the reference for each command.
First is rotateUV.
It is simple.
You only need to specify the target uvSet and the angle to rotate.
The center of rotation is the origin of the UV coordinate system.
@Angle
attr UV_value = 0
Lot -->
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
rotateUV(0,UV_value)
X.
Type the code above and try moving the slider bar.
Next, let's look at scaleUV().
The explanation sounds complicated, but think of it simply.
It increases the layout density of the texture by the values entered in uFactor and vFactor.
In other words, if it is written as scaleUV(0, 2, 2), it does not
mean expanding the size of the texture to double its width and height.
It means tiling the texture twice as densely compared to what was defined in
setupProjection().
What if it is scaleUV(0, 0.5, 0.5)?
That's right. It applies the texture at half the density configured in
setupProjection(). Naturally, the visible texture size will
become larger.
Type the code below yourself and try moving the slider bar.
@Range(min=0.1, max=5, stepsize=0.1)
attr UV_value = 1
Lot -->
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
scaleUV(0,UV_value,UV_value)
X.
Cityengine scaleUV() Demonstration
Does that make sense?
Next is translateUV().
It follows a similar format.
You specify the uvSet and offset it in the U and V directions. (The offset range is from 0 to 1.)
However, the unit used for offsetting here is not the distance unit used in the project,
but a relative distance after setting the full span of the U and V directions to 1 each.
If it says translateUV(0, 0.5, 0.1),
it means move uvSet 0 by 50% of the U range and 10% of the V range.
Shall we look at the code?
@Range(min=0, max=1, stepsize=0.1)
attr U_offset = 0
@Range(min=0, max=1, stepsize=0.1)
attr V_offset = 0
Lot -->
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
translateUV(0,U_offset,V_offset)
X.
CityEngine translateUV() Demonstration
Although it appears as if the texture is moving, strictly speaking, it is the UV coordinates that are changing.
Next is normalizeUV().
It is a bit complex.
This command does not need to be used when there is only a single isolated face; it is used when multiple faces are connected or form a 3D shape.
It combines multiple faces into a single UV space or separates UVs independently for each face.
I have rarely used this.
@Enum("uv","uvUniform","u","v")
attr mode = "uv"
@Enum("separatePerFace","collectiveAllFaces")
attr type = "separatePerFace"
Lot -->
extrude(10)
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
normalizeUV(0, mode, type)
X.
Cityengine normalizeUV() Demonstration
Next is tileUV().
This command repeats the texture like tiling so that top, bottom, left, and right edges fit perfectly to the texture size.
If you look at the red underlined area, you can see '~' and '\'' that we learned during the split lesson. This means mapping can be performed using approximate values and ratios.
Note!! Although the command syntax is similar, textureWidth and textureHeight entered here use real-world distance units used in the project. It does not touch UV coordinates directly, but transforms the actual texture size. Keep this in mind.
@Range(min=1, max=10, stepsize=0.5)
attr tileX = 1
@Range(min=1, max=10, stepsize=0.5)
attr tileY = 1
Lot -->
extrude(10)
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
tileUV(0, ~tileX, ~tileY)
X.
Cityengine tileUV() Demonstration
You can confirm that the size is precisely adjusted to fit the overall UV size.
Finally, here is deleteUV().
It is simple. It deletes the specified uvSet.
@Angle
attr UVrotate = 0
Lot -->
extrude(10)
setupProjection(0,scope.xz,scope.sx,scope.sz,0,0)
texture("images/texture.jpg")
projectUV(0)
rotateUV(0, UVrotate)
A
A -->
case UVrotate >90 :
deleteUV(0)
X.
else : X.
If the UV rotation value exceeds 90, the texture is deleted.
Cityengine deleteUV() Demonstration
At last~ we have completed all basic CGA commands and concepts.
From next time, we will take a photo of a simple building and walk through the process of modeling it step by step.
That's all for today~
- Learn previous workflow in [063] How to Apply Multiple UV Sets and Maps in CityEngine
- Continue learning with [065] How to Insert External 3D Objects 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.)