@@ -38,11 +38,12 @@ def GenerateUvwData(geometries: tuple[c4d.PolygonObject]) -> None:
38
38
"""Demonstrates how to generate UVW data for polygon objects.
39
39
"""
40
40
def MapVector (value : c4d .Vector , inMin : c4d .Vector , inMax : c4d .Vector ) -> c4d .Vector :
41
- """Maps a vector from a given range to the positive unit quadrant .
41
+ """Maps a vector from a given range to the values 0 to 1 .
42
42
"""
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.
43
+ # Put the z component of our input into the x component of the output, because UV are the
44
+ # relevant components for a 2D UV(W) vector, and because the points in the planes in this
45
+ # example lie in the x/z plane, so we move z to y(v) and then leave z(w) empty as we are
46
+ # not generating 3D texture mapping data.
46
47
return c4d .Vector (
47
48
c4d .utils .RangeMap (value .x , inMin .x , inMax .x , 0 , 1 , True ),
48
49
c4d .utils .RangeMap (value .z , inMin .z , inMax .z , 0 , 1 , True ), 0 )
@@ -52,11 +53,11 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
52
53
"""
53
54
# The distance from the point #p to its orthogonal projection #p' on the plane. Or, in short,
54
55
# the length of the shortest path (in Euclidean space) from #p to the plane.
55
- distance = (p - q ) * normal
56
+ distance : float = (p - q ) * normal
56
57
# Calculate #p' by moving #p #distance units along the inverse plane normal.
57
58
return p - normal * distance
58
59
59
- # Check our inputs for being what we think they are, at least two PolygonObjects.
60
+ # Check our inputs for being what we think they are, at least three PolygonObjects.
60
61
mxutils .CheckIterable (geometries , c4d .PolygonObject , minCount = 3 )
61
62
62
63
# Give the three inputs meaningful names.
@@ -66,11 +67,11 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
66
67
67
68
# A simple way to generate UVW data is a planar layout which can be directly derived from point
68
69
# 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.
70
+ # be applied when extruding or lathing/rotating a line, as we then can also associate each point
71
+ # with a percentage of the total length of the line (u) , and a percentage of the total extrusion
72
+ # height or lathing rotation (v) , the uv coordinates of that point.
72
73
73
- # Create a UVW tag for the plane object and get the points of the plane object.
74
+ # Create a UVW tag for the plane object and get all the points of the plane object.
74
75
uvwTag : c4d .UVWTag = plane .MakeVariableTag (c4d .Tuvw , plane .GetPolygonCount ())
75
76
points : typing .List [c4d .Vector ] = plane .GetAllPoints ()
76
77
@@ -88,8 +89,8 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
88
89
c : c4d .Vector = MapVector (points [poly .c ], - radius , radius )
89
90
d : c4d .Vector = MapVector (points [poly .d ], - radius , radius )
90
91
91
- # Set the uvw data for the polygon, nothing special here, just setting the uvw data for the
92
- # polygon #i to the calculated values .
92
+ # Set the four uvw coordinates for the uvw- polygon #i which corresponds to the geometry
93
+ # polygon #i.
93
94
uvwTag .SetSlow (i , a , b , c , d )
94
95
95
96
# Now we basically do the same for the sphere object. We could also just take the x and z
@@ -98,7 +99,7 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
98
99
# resulting in planar projection from that angle. This is a bit more formal than projecting by
99
100
# just discarding a component (the y component in the former case).
100
101
101
- # Our projection orientation and point, there is nothing special about these values, they are
102
+ # Our projection orientation and point, there is nothing special about these values, they
102
103
# just look good for this example.
103
104
projectionNormal : c4d .Vector = c4d .Vector (1 , 1 , 0 ).GetNormalized ()
104
105
projectionOrigin : c4d .Vector = c4d .Vector (0 )
@@ -109,8 +110,7 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
109
110
radius : c4d .Vector = sphere .GetRad ()
110
111
poly : c4d .CPolygon
111
112
for i , poly in enumerate (sphere .GetAllPolygons ()):
112
- # We project each point of the polygon into the plane define by the projection plane origin
113
- # and normal.
113
+ # We project each point of the polygon into the projection plane.
114
114
a : c4d .Vector = ProjectIntoPlane (points [poly .a ], projectionOrigin , projectionNormal )
115
115
b : c4d .Vector = ProjectIntoPlane (points [poly .b ], projectionOrigin , projectionNormal )
116
116
c : c4d .Vector = ProjectIntoPlane (points [poly .c ], projectionOrigin , projectionNormal )
@@ -132,7 +132,7 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
132
132
# state. This makes it impossible to use the UV tools inside a generator object's GetVirtualObjects
133
133
uvwTag : c4d .UVWTag = cylinder .MakeVariableTag (c4d .Tuvw , cylinder .GetPolygonCount ())
134
134
135
- # Boiler plate code for UV commands to work.
135
+ # Boiler plate code for UV commands to work, see dedicated #CallUVCommand example for details .
136
136
doc : c4d .documents .BaseDocument = mxutils .CheckType (sphere .GetDocument ())
137
137
doc .SetActiveObject (cylinder )
138
138
@@ -149,8 +149,9 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
149
149
handle : c4d .modules .bodypaint .TempUVHandle = mxutils .CheckType (
150
150
c4d .modules .bodypaint .GetActiveUVSet (doc , c4d .GETACTIVEUVSET_ALL ))
151
151
152
- # Retrieve the internal UVW data for the currently opened texture view and then invoke
152
+ # Retrieve the internal UVW data for the current texture view and then invoke
153
153
# the #UVCOMMAND_OPTIMALCUBICMAPPING command, mapping our cylinder object.
154
+
154
155
uvw : list [dict ] = mxutils .CheckType (handle .GetUVW ())
155
156
settings : c4d .BaseContainer = c4d .BaseContainer ()
156
157
if not c4d .modules .bodypaint .CallUVCommand (
@@ -159,20 +160,20 @@ def ProjectIntoPlane(p: c4d.Vector, q: c4d.Vector, normal: c4d.Vector) -> c4d.Ve
159
160
c4d .UVCOMMAND_OPTIMALCUBICMAPPING , settings ):
160
161
raise RuntimeError ("CallUVCommand failed." )
161
162
162
- # Write the updated uvw data back and close the texture view we opened above .
163
+ # Write the updated uvw data back.
163
164
if not handle .SetUVWFromTextureView (uvw , True , True , True ):
164
165
raise RuntimeError ("Failed to write Bodypaint uvw data back." )
165
166
166
167
c4d .modules .bodypaint .FreeActiveUVSet (handle )
167
168
doc .SetMode (oldMode )
168
169
169
- return None
170
+ return
170
171
171
172
# The following code is boilerplate code to create geometry, generate UVW data for it, and apply
172
173
# materials. It is not relevant for the the subject of UVW mapping.
173
174
174
175
def BuildGeometry (doc : c4d .documents .BaseDocument ) -> tuple [c4d .PolygonObject , c4d .PolygonObject ]:
175
- """Constructs a plane and sphere polygon object .
176
+ """Constructs the plane, sphere, and cylinder geometry .
176
177
"""
177
178
# Instantiate the generators.
178
179
planeGen : c4d .BaseObject = mxutils .CheckType (c4d .BaseObject (c4d .Oplane ), c4d .BaseObject )
0 commit comments