Extruding a cylinder with complex UV mapping

208 Views Asked by At

This is all being done programmatically, not with any kind of 3D editor.

I am being delivered a shape like this: top of cylinder

The UV coordinates that map that checkerboard are just the x,y coordiates of the shape, but I can count on anything I want to map onto this being 1.0,1.0 in size.

Now, my job is to extrude a cylinder from this shape, programmatically. Easy enough:

Extruded cylinder

I just took the UV coordinates from the top and kept them on the vertex on the bottom. But now, the spec says that the final cylinder should look something like this (this is mocked up, I have not been able to generate it):

enter image description here

I thought I was just going to tweak my UV coordinates to account for the height, and get checkers on the side, but what I end up getting is a swirled texture like this:

enter image description here

I understand why. I created that by just adding n to the V coordinate. But since the v coordinate isn't always on a checker boundary when it gets extruded down, it ends up like the image.

I believe I need some kind of directional vector to add the UV coordinate at the bottom of the cylinder to make the side checkers straight, but everything I try produces a worse mess.

How could I UV map those sides correctly?

2

There are 2 best solutions below

8
Erdal Küçük On

Imagine unwrapping a cylinder (for the sake of simplicity, forget about the top and bottom caps). Aren't you left with a rectangle? Now, let us think how the horizontal and vertical coordinates are calculated.

When you're calculating the radians of your ellipse (base shape of your cylinder) you also calculate the U mapping coords. What you still need are the coordinates in the V direction: the bottom of your cylinder could be the v0 and the top the v1 coordinate.

  |< 0..2*PI >|

u0,v1       u1,v1
  x-----------x   ---
  | | | | | | |    ^
  | | | | | | |  height (extrusion length)
  | | | | | | |    v
  x-----------x   ---
u0,v0       u1,v0

Formally:

radian_delta = 2*PI / num_slices;
height_delta = height / num_segments;

u_coord = (slice_index * radian_delta) / (2*PI);
v_coord = (segment_index * height_delta) / height;

Addendum

I've overlooked the fact, that you're not calculating the coords by yourself (you get them from somewhere else) and your intent is to calculate the u-coord from the existing uv-coords. For that, we'll have to take the arctanget (atan2) of each uv-coordinate to get the angle (in radians).

The return value of atan2 is in the range [-PI, PI]. Since we need the range [0, 2*PI] to map the result to the range [0, 1], all you have to do is to add PI to the result and divide by 2*PI or atan2(v, u) / (2 * PI) + 0.5.

Depending on your number of height segments, the v-coord is simply the y-coord of the vertex (mapped to the range [0, 1]). In case of just the bottom and top caps, that would be either 0 or 1.

Pseudocode:

foreach vertex in ellipse
do
    radian  := atan2(vertex.v, vertex.u) + PI;
    u_coord := radian / (2 * PI);
end

See also: https://en.wikipedia.org/wiki/Atan2

1
bob On

I think the problem you're having is that the texture for the cylinder top (and bottom) doesn't determine the texture for the side. And I don't think there's any general solution to that problem. You'll need to be given "an extrusion texture" to apply to the side. You can't produce that from the one for the ends.

I'm not sure how general your algorithm is supposed to be. Does it need to work for any texture or just a specific one?

But here's an approach that might help. Let's assume that your texture is only two colors and that you're given a distance w that defines the length along the side for which the color is constant. Let's assume the desired texture inverts for each distance w down the cylinder. There is no way to derive this length in general. It has to be given. But if you have it, you can "solve" the problem (as I understand it, which might not be accurate).

First step is to produce the inverted texture. Assuming the texture is only two colors, this should be relatively straightforward.

Then divide the side length of the cylinder into segments of length w. For each segment apply either the original texture or the inverted one using your original uv map.

I don't know if there's any easy way to use two different textures (as specified by two different image files) in this manner. If not, the original and inverted textures can be combined into a single texture file using different image areas for each and then the uv coordinates computed appropriately.

If I've misunderstood, or understood correctly but am otherwise wrong, I apologize and would like to be corrected.