Skip to content

Commit 071840b

Browse files
committed
Python SDK: UVW tag examples documentation fixes.
1 parent 22e2a8a commit 071840b

File tree

1 file changed

+25
-36
lines changed

1 file changed

+25
-36
lines changed

scripts/04_3d_concepts/modeling/geometry/geometry_uvw_2025.py

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,20 @@
3535
op: typing.Optional[c4d.BaseObject] # The selected object within that active document. Can be None.
3636

3737
def GenerateUvwData(geometries: tuple[c4d.PolygonObject]) -> None:
38-
"""Demonstrates how to generate UVW data for polygon objects..
38+
"""Demonstrates how to generate UVW data for polygon objects.
3939
"""
4040
def MapVector(value: c4d.Vector, inMin: c4d.Vector, inMax: c4d.Vector) -> c4d.Vector:
4141
"""Maps a vector from a given range to the positive unit quadrant.
4242
"""
43-
# We swizzle the vector to only consider the x and z components, as UV are the relevant c
44-
# components for us and the x and z components happened to be the relevant ones for this
45-
# example (the plane object).
43+
# We swizzle the vector to only consider the x and z components, as u and v are the relevant
44+
# components in UVW data for us and the x and z of points components happened to be the
45+
# relevant ones for this example.
4646
return c4d.Vector(
4747
c4d.utils.RangeMap(value.x, inMin.x, inMax.x, 0, 1, True),
4848
c4d.utils.RangeMap(value.z, inMin.z, inMax.z, 0, 1, True), 0)
4949

5050
def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Vector:
5151
"""Projects the point #p orthogonally into the plane defined by #q and #normal.
52-
53-
Args:
54-
p: The point to project.
55-
q: A point in the plane.
56-
normal: The normal of the plane (expected to be a normalized vector).
57-
58-
Returns:
59-
The projected point.
6052
"""
6153
# The distance from the point #p to its orthogonal projection #p' on the plane. Or, in short,
6254
# the length of the shortest path (in Euclidean space) from #p to the plane.
@@ -72,11 +64,11 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
7264
sphere: c4d.PolygonObject = geometries[1]
7365
cylinder: c4d.PolygonObject = geometries[2]
7466

75-
# The simplest way to generate UVW data is the simple planar layout which can be directly
76-
# derived from point or construction data. An example is of course a plane object, but similar
77-
# techniques can also be applied when extruding or lofting a line, as we then can also associate
78-
# each point with a percentage of the total length of the line, and a percentage of the total
79-
# extrusion height or lofting rotation, the uv coordinates of that point.
67+
# A simple way to generate UVW data is a planar layout which can be directly derived from point
68+
# or construction data. An example is of course a plane object, but similar techniques can also
69+
# be applied when extruding or lofting a line, as we then can also associate each point with a
70+
# percentage of the total length of the line, and a percentage of the total extrusion height or
71+
# lofting rotation, the uv coordinates of that point.
8072

8173
# Create a UVW tag for the plane object and get the points of the plane object.
8274
uvwTag: c4d.UVWTag = plane.MakeVariableTag(c4d.Tuvw, plane.GetPolygonCount())
@@ -88,10 +80,9 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
8880
for i, poly in enumerate(plane.GetAllPolygons()):
8981
# Calculate the uvw data for each point of the polygon. We operate here on the implicit
9082
# knowledge that the plane object is centered on its origin, e.g., goes form -radius to
91-
# radius in all three dimensions. We then just map -radius to radius to 0 to 1, as UV data
92-
# is always placed in the positive quadrant unit square ('goes' from 0 to 1). The reason why
93-
# always calculate uvw data for four points, is because Cinema 4D always handles polygons as
94-
# quads, even if they are triangles or n-gons.
83+
# radius in all three dimensions. We then just map [-radius, radius] to [0, 1], as UV data
84+
# always 'goes' from 0 to 1. The reason why we always calculate uvw data for four points,
85+
# is because Cinema 4D always handles polygons as quads, even if they are triangles or n-gons.
9586
a: c4d.Vector = MapVector(points[poly.a], -radius, radius)
9687
b: c4d.Vector = MapVector(points[poly.b], -radius, radius)
9788
c: c4d.Vector = MapVector(points[poly.c], -radius, radius)
@@ -105,24 +96,25 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
10596
# components of each point to get a top-down uvw projection on the sphere. But we make it a
10697
# bit more interesting by projecting each point into a plane defined by the normal of (1, 1, 0),
10798
# resulting in planar projection from that angle. This is a bit more formal than projecting by
108-
# just discarding a component (the y component in our case).
99+
# just discarding a component (the y component in the former case).
109100

110101
# Our projection orientation and point, there is nothing special about these values, they are
111102
# just look good for this example.
112103
projectionNormal: c4d.Vector = c4d.Vector(1, 1, 0).GetNormalized()
113-
projectionPoint: c4d.Vector = c4d.Vector(0)
104+
projectionOrigin: c4d.Vector = c4d.Vector(0)
114105

115106
uvwTag: c4d.UVWTag = sphere.MakeVariableTag(c4d.Tuvw, sphere.GetPolygonCount())
116107
points: typing.List[c4d.Vector] = sphere.GetAllPoints()
117108

118109
radius: c4d.Vector = sphere.GetRad()
119110
poly: c4d.CPolygon
120111
for i, poly in enumerate(sphere.GetAllPolygons()):
121-
122-
a: c4d.Vector = ProjectIntoPlane(points[poly.a], projectionPoint, projectionNormal)
123-
b: c4d.Vector = ProjectIntoPlane(points[poly.b], projectionPoint, projectionNormal)
124-
c: c4d.Vector = ProjectIntoPlane(points[poly.c], projectionPoint, projectionNormal)
125-
d: c4d.Vector = ProjectIntoPlane(points[poly.d], projectionPoint, projectionNormal)
112+
# We project each point of the polygon into the plane define by the projection plane origin
113+
# and normal.
114+
a: c4d.Vector = ProjectIntoPlane(points[poly.a], projectionOrigin, projectionNormal)
115+
b: c4d.Vector = ProjectIntoPlane(points[poly.b], projectionOrigin, projectionNormal)
116+
c: c4d.Vector = ProjectIntoPlane(points[poly.c], projectionOrigin, projectionNormal)
117+
d: c4d.Vector = ProjectIntoPlane(points[poly.d], projectionOrigin, projectionNormal)
126118

127119
# We must still map the projected points to the unit square. What we do here is not quite
128120
# mathematically correct, as there is no guarantee that the projected points have the same
@@ -138,7 +130,6 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
138130
# Doing this comes with the huge disadvantage that we must be in a certain GUI state, i.e., the
139131
# UV tools only work if the object is in the active document and the UV tools are in a certain
140132
# state. This makes it impossible to use the UV tools inside a generator object's GetVirtualObjects
141-
142133
uvwTag: c4d.UVWTag = cylinder.MakeVariableTag(c4d.Tuvw, cylinder.GetPolygonCount())
143134

144135
# Boiler plate code for UV commands to work.
@@ -177,13 +168,13 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
177168

178169
return None
179170

180-
# The following code is boilerplate code to create a plane and sphere object, generate UVW data for
181-
# them, and apply a material to them. This is all boilerplate code and not the focus of this example.
171+
# The following code is boilerplate code to create geometry, generate UVW data for it, and apply
172+
# materials. It is not relevant for the the subject of UVW mapping.
182173

183174
def BuildGeometry(doc: c4d.documents.BaseDocument) -> tuple[c4d.PolygonObject, c4d.PolygonObject]:
184175
"""Constructs a plane and sphere polygon object.
185176
"""
186-
# Instantiate a plane and sphere generator.
177+
# Instantiate the generators.
187178
planeGen: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Oplane), c4d.BaseObject)
188179
sphereGen: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Osphere), c4d.BaseObject)
189180
cylinderGen: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Ocylinder), c4d.BaseObject)
@@ -193,12 +184,10 @@ def BuildGeometry(doc: c4d.documents.BaseDocument) -> tuple[c4d.PolygonObject, c
193184
temp.InsertObject(planeGen)
194185
temp.InsertObject(sphereGen)
195186
temp.InsertObject(cylinderGen)
196-
197-
# Build the caches of the plane and sphere generators.
198187
if not temp.ExecutePasses(None, False, False, True, c4d.BUILDFLAGS_0):
199188
raise RuntimeError("Could not build the cache for plane and sphere objects.")
200189

201-
# Retrieve the caches of the plane and sphere generators.
190+
# Retrieve the caches of the generators.
202191
planeCache: c4d.PolygonObject = mxutils.CheckType(planeGen.GetCache(), c4d.PolygonObject)
203192
sphereCache: c4d.PolygonObject = mxutils.CheckType(sphereGen.GetCache(), c4d.PolygonObject)
204193
cylinderCache: c4d.PolygonObject = mxutils.CheckType(cylinderGen.GetCache(), c4d.PolygonObject)
@@ -217,7 +206,7 @@ def BuildGeometry(doc: c4d.documents.BaseDocument) -> tuple[c4d.PolygonObject, c
217206
sphere.SetMg(c4d.Matrix(off=c4d.Vector(0, 0, 0)))
218207
cylinder.SetMg(c4d.Matrix(off=c4d.Vector(300, 0, 0)))
219208

220-
# Insert the plane and sphere into the active document and return them.
209+
# Insert the result the passed document and return them.
221210
doc.InsertObject(plane)
222211
doc.InsertObject(sphere)
223212
doc.InsertObject(cylinder)

0 commit comments

Comments
 (0)