OpenGL - How to draw a 3D pipeline as a screensaver for Windows

Given the group of three-dimensional points and the diameter size, I want to draw a 3D pipeline in the same way as the screensaver of the conveyor window http://answers.yahoo.com/question/index?qid=20080919090035AAO55Qv .

I use C ++ and OpenGL. Can someone help me find a resource that can show me how to do this? After a little investigation, it seems that we need to do extra work to make the turning point smooth. If possible, I am looking for a few code examples that illustrate how to implement this.

thanks

+6
opengl
source share
4 answers

I will tell you how I made such a screen saver. My pipes fit into a 3d grid, each cell is a cube:

Y^ |_______ / 2 /| 0 vs 3 /______/ | 1 vs 4 | |1| 2 vs 5 | 3 | / |______|/ -->X / -Z/ 

The configuration of the pipes in each cell is described by six bits - one bit for each side. 0 means that the cell is empty, 63 means that it has six segments going to the center. If you break down combinations into types, there will be few of them:

  • short sticks, x6
  • long sticks, x3 (0-3, 1-4, 2-5)
  • arches, x12 (2 - 1, 1 - 3, 2 - 3)
  • T-junction, x12 (1 - 3 - 4)
  • angles, x8 (2 - 1 - 3, 2 - 3 - 4)
  • crosses, x3 (3 - 1 - 2 - 4)
  • four-segment cluster, x12 (1 - 2 - 3 - 4)
  • five-segment cluster, x6
  • six segment star, x1.

I used the torus square for the arch (self-synthesizing), the spherical triangular patch for corners and cylinders for everything else. The star, crosses and five segments are just intersecting cylinders in my model.

Edit: some code in C # (I just hope this will be useful in some way).

Everything on stage is combined with three models - an arch, a cylinder and a spherical triangular patch, rotating and visualized many times. All models are in vertex arrays. Very soon, I ran into a performance issue and implemented a simple remote LOD to deal with it. So, I generate not one model of each type, but a series of models with a different number of segments.

  /// <summary> /// Generates full row of arch models and lod map /// to render them. /// </summary> /// <param name="radius">Pipe radius</param> /// <returns>Model with lod</returns> Model GenerateArches(double radius) { //Determine total number of vertices for full row LodEntry[] lod = new LodEntry[slicesLod.Length]; int totalVertices = 0; int totalIndices = 0; for (int level = 0; level < slicesLod.Length; ++level) { int sl = slicesLod[level]; int st = archStacksLod[level]; if (st < 3) st = 3; int vertices = (sl + 1)*(st + 1); int indices = ((sl + 1)*2 + 4)*(st) - 4; lod[level].start = totalIndices; totalVertices += vertices; totalIndices += indices; lod[level].count = indices; } int[] indexArray = new int[totalIndices]; VertexAttributes[] va = new VertexAttributes[totalVertices]; int vCounter = 0; //index for vertices int iCounter = 0; //indices counter for (int level = 0; level < slicesLod.Length; ++level) { int iOffset = vCounter; int slices = slicesLod[level]; int stacks = archStacksLod[level]; if (stacks < 3) stacks = 3; for (int st = 0; st <= stacks; ++st) { double a = Math.PI*0.5*st/stacks; float texCoordS = st/(float) stacks; for (int sl = 0; sl <= slices; ++sl) { double b = Math.PI*2*sl/slices; float texCoordT = sl/(float) slices; va[vCounter].S = texCoordS; va[vCounter].T = texCoordT; //point on central arch double x0 = 0.5*Math.Sin(a); double y0 = 0.5*Math.Cos(a); const double z0 = 0; //point displacement double rx = radius*Math.Sin(a)*Math.Sin(b); double ry = radius*Math.Cos(a)*Math.Sin(b); double rz = radius*Math.Cos(b); //normal factor double nf = 1.0/Math.Sqrt(rx*rx + ry*ry + rz*rz); va[vCounter].NX = (float)(rx * nf); va[vCounter].NY = (float)(ry * nf); va[vCounter].NZ = (float)(rz * nf); //position va[vCounter].X = (float) (x0 + rx); va[vCounter].Y = (float) (y0 + ry); va[vCounter].Z = (float) (z0 + rz); ++vCounter; } } for (int stack = 0; stack < stacks; ++stack) { for (int slice = 0; slice <= slices; ++slice) { indexArray[iCounter++] = iOffset + stack * slices + slice + stack; indexArray[iCounter++] = iOffset + (stack + 1) * slices + slice + 1 + stack; } if (stack < stacks - 1) { indexArray[iCounter++] = iOffset + stack * slices + slices + stack; indexArray[iCounter++] = iOffset + stack * slices + slices + stack; indexArray[iCounter++] = iOffset + (stack + 1) * slices + slices + 2 * (stack + 1) - stack; indexArray[iCounter++] = iOffset + (stack + 1) * slices + slices + 2 * (stack + 1) - stack; } } } return new Model(va, indexArray, lod); } /// <summary> /// Generates indices for rendering of vertex array, /// representing a cylinder section. /// Vertices assumed to be stored slice by slice: /// 0 1 2 3 ................... cylStacks-1, /// cylStacks .................. 2*cylStacks-1, /// ...................................., /// (cylSlices-1)*cylStacks .. cylSlices*cylStacks-1. /// </summary> /// <param name="radius"></param> private Model GenerateCylinders(double radius) { LodEntry[] lod = new LodEntry[slicesLod.Length]; int totalVertices = 0; int totalIndices = 0; for (int level = 0; level < slicesLod.Length; ++level) { int sl = slicesLod[level]; int st = cylStacksLod[level]; int vertices = (sl + 1)*(st + 1); int indices = ((sl+1)*2 + 4)*st - 4; lod[level].start = totalIndices; totalVertices += vertices; totalIndices += indices; lod[level].count = indices; } int[] indexArray = new int[totalIndices]; VertexAttributes[] va = new VertexAttributes[totalVertices]; int vCounter = 0; //index for vertex attributes int iCounter = 0; //indices counter for (int level = 0; level < slicesLod.Length; ++level) { int iOffset = vCounter; int slices = slicesLod[level]; int stacks = cylStacksLod[level]; for (int st = 0; st <= stacks; ++st) { double i = 0.5 - 0.5 * st / stacks; float texCoordS = st / (float)stacks; for (int sl = 0; sl <= slices; ++sl) { double b = Math.PI * 2 * sl / slices; //tex coords float texCoordT = sl / (float)slices; va[vCounter].S = 0.5f * texCoordS; va[vCounter].T = texCoordT; //point on central axis const double x0 = 0; const double y0 = 0; double z0 = i; //point displacement double rx = radius*Math.Cos(b); double ry = radius*Math.Sin(b); const double rz = 0; //normal factor double nf = 1.0/Math.Sqrt(ry*ry + rx*rx); va[vCounter].NX = (float)(rx * nf); va[vCounter].NY = (float)(ry * nf); va[vCounter].NZ = 0.0f; va[vCounter].X = (float)(x0 + rx); va[vCounter].Y = (float)(y0 + ry); va[vCounter].Z = (float)(z0 + rz); ++vCounter; } } for (int stack = 0; stack < stacks; ++stack) { for (int slice = 0; slice <= slices; ++slice) { indexArray[iCounter++] = iOffset + stack*slices + slice + stack; indexArray[iCounter++] = iOffset + (stack + 1)*slices + slice + 1 + stack; } if (stack < stacks - 1) { indexArray[iCounter++] = iOffset + stack * slices + slices + stack; indexArray[iCounter++] = iOffset + stack * slices + slices + stack; indexArray[iCounter++] = iOffset + (stack + 1) * slices + slices + 2 * (stack + 1) - stack; indexArray[iCounter++] = iOffset + (stack + 1) * slices + slices + 2 * (stack + 1) - stack; } } } return new Model(va, indexArray, lod); } static int R0(int _slices, int _level) { return _level * (_slices+2) - (int)(0.5 * _level * (_level + 1)); } static int RL(int _slices, int _level) { return _slices - _level + 1; } private Model GenerateSphereSegment(double radius) { //Determine total number of vertices for full row LodEntry[] lod = new LodEntry[slicesLod.Length]; int totalVertices = 0; int totalIndices = 0; for (int level = 0; level < slicesLod.Length; ++level) { int sl = slicesLod[level] >> 2; int vertices = (((2 + sl) * (sl + 1)) >> 1); int indices = sl * (sl + 3); lod[level].start = totalIndices; totalVertices += vertices; totalIndices += indices; lod[level].count = indices; } int[] indexArray = new int[totalIndices]; VertexAttributes[] va = new VertexAttributes[totalVertices]; int vCounter = 0; //index for vertices int iCounter = 0; //indices counter for (int level = 0; level < slicesLod.Length; ++level) { int sphSlices = slicesLod[level]>>2; int iOffset = vCounter; //index offset for level for (int sl = 0; sl <= sphSlices; ++sl) { double a = Math.PI*sl*0.5/sphSlices; double Y = radius*Math.Sin(a); double Ry = radius*Math.Cos(a); for (int st = 0; st <= sphSlices - sl; ++st) { double X, Z, b; if (sphSlices > sl) { b = Math.PI*0.5*st/(sphSlices - sl); X = Ry*Math.Sin(b); Z = Ry*Math.Cos(b); } else { X = 0; Z = 0; b = 0; } va[vCounter].S = (float)(0.5 / 3 * a); va[vCounter].T = (float)(0.14 * b); double coeff = 1/Math.Sqrt(X*X + Y*Y + Z*Z); va[vCounter].NX = (float)(X * coeff); va[vCounter].NY = (float)(Y * coeff); va[vCounter].NZ = (float)(Z * coeff); va[vCounter].X = (float)(va[vCounter].NX * radius); va[vCounter].Y = (float)(va[vCounter].NY * radius); va[vCounter].Z = (float)(va[vCounter].NZ * radius); ++vCounter; } } for (int k = 0; k < sphSlices; ++k) { int lastS = RL(sphSlices, k); for (int s = 0; s < lastS - 1; ++s) { int c0 = R0(sphSlices, k) + s; int cn = R0(sphSlices, k) + s + RL(sphSlices, k); indexArray[iCounter++] = cn + iOffset; indexArray[iCounter++] = c0 + iOffset; } int tail = R0(sphSlices, k) + lastS - 1; indexArray[iCounter++] = tail + iOffset; indexArray[iCounter++] = tail + iOffset; } } return new Model(va, indexArray, lod); } 
+12
source share

Here are the steps you must follow:

  • Find out what order you want to connect to the points (if you choose random, this may be strange, I recommend looking for an algorithm that gives you a good order.
  • Create the geometry along this path - what you want to do is basically create a cylinder at every step of this path, you can deal with connecting these cylinders later. Fortunately, cylinders are a fairly simple piece of geometry, and GLUT has methods that generate them for you.
+1
source share

Connecting cylinders is easy if you are ready to do a little extra work. Simple draw a sphere in joints with gluSphere() . Cylinders can be used with gluCylinder()
After you figure out how to use them correctly, all you have to do is select a series of points for the joints to stretch the tube through them.

Note that saving the screen in tubes also has a mode in which it draws flexible tubes that bend smoothly around corners. It can be a little harder to do.

+1
source share

Traditionally, the NeHe openGL tutorial was started - they are a bit outdated, for example, they won’t work under Windows7, don’t know if this has improved.

OpenGL only draws primitives, lines, points, triangles, so you need to make them yourself - time to remember the whole trigonometry of high school

0
source share

All Articles