简体   繁体   中英

OpenGL: How to lathe a 2D shape into 3D?

I have an OpenGL program (written in Delphi) that lets user draw a polygon. I want to automatically revolve (lathe) it around an axis (say, Y asix) and get a 3D shape.

How can I do this?

For simplicity, you could force at least one point to lie on the axis of rotation. You can do this easily by adding/subtracting the same value to all the x values, and the same value to all the y values, of the points in the polygon. It will retain the original shape.

The rest isn't really that hard. Pick an angle that is fairly small, say one or two degrees, and work out the coordinates of the polygon vertices as it spins around the axis. Then just join up the points with triangle fans and triangle strips.

To rotate a point around an axis is just basic Pythagoras. At 0 degrees rotation you have the points at their 2-d coordinates with a value of 0 in the third dimension.

Lets assume the points are in X and Y and we are rotating around Y. The original 'X' coordinate represents the hypotenuse. At 1 degree of rotation, we have:

sin(1) = z/hypotenuse
cos(1) = x/hypotenuse

(assuming degree-based trig functions)

To rotate a point (x, y) by angle T around the Y axis to produce a 3d point (x', y', z'):

y' = y
x' = x * cos(T)
z' = x * sin(T)

So for each point on the edge of your polygon you produce a circle of 360 points centered on the axis of rotation.

Now make a 3d shape like so:

  1. create a GL 'triangle fan' by using your center point and the first array of rotated points
  2. for each successive array, create a triangle strip using the points in the array and the points in the previous array
  3. finish by creating another triangle fan centered on the center point and using the points in the last array

One thing to note is that usually, the kinds of trig functions I've used measure angles in radians, and OpenGL uses degrees. To convert degrees to radians, the formula is:

degrees = radians / pi * 180

Essentially the strategy is to sweep the profile given by the user around the given axis and generate a series of triangle strips connecting adjacent slices.

Assume that the user has drawn the polygon in the XZ plane. Further, assume that the user intends to sweep around the Z axis (ie the line X = 0) to generate the solid of revolution, and that one edge of the polygon lies on that axis (you can generalize later once you have this simplified case working).

For simple enough geometry, you can treat the perimeter of the polygon as a function x = f(z), that is, assume there is a unique X value for every Z value. When we go to 3D, this function becomes r = f(z), that is, the radius is unique over the length of the object.

Now, suppose we want to approximate the solid with M "slices" each spanning 2 * Pi / M radians. We'll use N "stacks" (samples in the Z dimension) as well. For each such slice, we can build a triangle strip connecting the points on one slice (i) with the points on slice (i+1). Here's some pseudo-ish code describing the process:

double dTheta = 2.0 * pi / M;
double dZ = (zMax - zMin) / N;

// Iterate over "slices"
for (int i = 0; i < M; ++i) {
  double theta = i * dTheta;
  double theta_next = (i+1) * dTheta;

  // Iterate over "stacks":
  for (int j = 0; j <= N; ++j) {
    double z = zMin + i * dZ;

    // Get cross-sectional radius at this Z location from your 2D model (was the
    // X coordinate in the 2D polygon):
    double r = f(z);  // See above definition

    // Convert 2D to 3D by sweeping by angle represented by this slice:
    double x = r * cos(theta);
    double y = r * sin(theta);

    // Get coordinates of next slice over so we can join them with a triangle strip:
    double xNext = r * cos(theta_next);
    double yNext = r * sin(theta_next);

    // Add these two points to your triangle strip (heavy pseudocode):
    strip.AddPoint(x, y, z);
    strip.AddPoint(xNext, yNext, z);
  }
}

That's the basic idea. As sje697 said, you'll possibly need to add end caps to keep the geometry closed (ie a solid object, rather than a shell). But this should give you enough to get you going. This can easily be generalized to toroidal shapes as well (though you won't have a one-to-one r = f(z) function in that case).

If you just want it to rotate, then:

glRotatef(angle,0,1,0);

will rotate it around the Y-axis. If you want a lathe, then this is far more complex.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM