35
35
op : typing .Optional [c4d .BaseObject ] # The selected object within that active document. Can be None.
36
36
37
37
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.
39
39
"""
40
40
def MapVector (value : c4d .Vector , inMin : c4d .Vector , inMax : c4d .Vector ) -> c4d .Vector :
41
41
"""Maps a vector from a given range to the positive unit quadrant.
42
42
"""
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 .
46
46
return c4d .Vector (
47
47
c4d .utils .RangeMap (value .x , inMin .x , inMax .x , 0 , 1 , True ),
48
48
c4d .utils .RangeMap (value .z , inMin .z , inMax .z , 0 , 1 , True ), 0 )
49
49
50
50
def ProjectIntoPlane (p : c4d .Vector , q : c4d .Vector , normal : c4d .Vector ) -> c4d .Vector :
51
51
"""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.
60
52
"""
61
53
# The distance from the point #p to its orthogonal projection #p' on the plane. Or, in short,
62
54
# 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
72
64
sphere : c4d .PolygonObject = geometries [1 ]
73
65
cylinder : c4d .PolygonObject = geometries [2 ]
74
66
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.
80
72
81
73
# Create a UVW tag for the plane object and get the points of the plane object.
82
74
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
88
80
for i , poly in enumerate (plane .GetAllPolygons ()):
89
81
# Calculate the uvw data for each point of the polygon. We operate here on the implicit
90
82
# 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.
95
86
a : c4d .Vector = MapVector (points [poly .a ], - radius , radius )
96
87
b : c4d .Vector = MapVector (points [poly .b ], - radius , radius )
97
88
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
105
96
# components of each point to get a top-down uvw projection on the sphere. But we make it a
106
97
# bit more interesting by projecting each point into a plane defined by the normal of (1, 1, 0),
107
98
# 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).
109
100
110
101
# Our projection orientation and point, there is nothing special about these values, they are
111
102
# just look good for this example.
112
103
projectionNormal : c4d .Vector = c4d .Vector (1 , 1 , 0 ).GetNormalized ()
113
- projectionPoint : c4d .Vector = c4d .Vector (0 )
104
+ projectionOrigin : c4d .Vector = c4d .Vector (0 )
114
105
115
106
uvwTag : c4d .UVWTag = sphere .MakeVariableTag (c4d .Tuvw , sphere .GetPolygonCount ())
116
107
points : typing .List [c4d .Vector ] = sphere .GetAllPoints ()
117
108
118
109
radius : c4d .Vector = sphere .GetRad ()
119
110
poly : c4d .CPolygon
120
111
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 )
126
118
127
119
# We must still map the projected points to the unit square. What we do here is not quite
128
120
# 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
138
130
# Doing this comes with the huge disadvantage that we must be in a certain GUI state, i.e., the
139
131
# UV tools only work if the object is in the active document and the UV tools are in a certain
140
132
# state. This makes it impossible to use the UV tools inside a generator object's GetVirtualObjects
141
-
142
133
uvwTag : c4d .UVWTag = cylinder .MakeVariableTag (c4d .Tuvw , cylinder .GetPolygonCount ())
143
134
144
135
# 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
177
168
178
169
return None
179
170
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 .
182
173
183
174
def BuildGeometry (doc : c4d .documents .BaseDocument ) -> tuple [c4d .PolygonObject , c4d .PolygonObject ]:
184
175
"""Constructs a plane and sphere polygon object.
185
176
"""
186
- # Instantiate a plane and sphere generator .
177
+ # Instantiate the generators .
187
178
planeGen : c4d .BaseObject = mxutils .CheckType (c4d .BaseObject (c4d .Oplane ), c4d .BaseObject )
188
179
sphereGen : c4d .BaseObject = mxutils .CheckType (c4d .BaseObject (c4d .Osphere ), c4d .BaseObject )
189
180
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
193
184
temp .InsertObject (planeGen )
194
185
temp .InsertObject (sphereGen )
195
186
temp .InsertObject (cylinderGen )
196
-
197
- # Build the caches of the plane and sphere generators.
198
187
if not temp .ExecutePasses (None , False , False , True , c4d .BUILDFLAGS_0 ):
199
188
raise RuntimeError ("Could not build the cache for plane and sphere objects." )
200
189
201
- # Retrieve the caches of the plane and sphere generators.
190
+ # Retrieve the caches of the generators.
202
191
planeCache : c4d .PolygonObject = mxutils .CheckType (planeGen .GetCache (), c4d .PolygonObject )
203
192
sphereCache : c4d .PolygonObject = mxutils .CheckType (sphereGen .GetCache (), c4d .PolygonObject )
204
193
cylinderCache : c4d .PolygonObject = mxutils .CheckType (cylinderGen .GetCache (), c4d .PolygonObject )
@@ -217,7 +206,7 @@ def BuildGeometry(doc: c4d.documents.BaseDocument) -> tuple[c4d.PolygonObject, c
217
206
sphere .SetMg (c4d .Matrix (off = c4d .Vector (0 , 0 , 0 )))
218
207
cylinder .SetMg (c4d .Matrix (off = c4d .Vector (300 , 0 , 0 )))
219
208
220
- # Insert the plane and sphere into the active document and return them.
209
+ # Insert the result the passed document and return them.
221
210
doc .InsertObject (plane )
222
211
doc .InsertObject (sphere )
223
212
doc .InsertObject (cylinder )
0 commit comments