OpenGL - Как нарисовать 3D конвейер в качестве заставки Windows - PullRequest
6 голосов
/ 08 марта 2011

Учитывая группу 3D-точек и размер диаметра, я хочу нарисовать 3D-конвейер, такой же, как и экранная заставка Windows http://answers.yahoo.com/question/index?qid=20080919090035AAO55Qv.

Я использую C ++ и OpenGL. Может ли кто-нибудь помочь мне найти ресурс, который может показать мне, как этого добиться? После небольшого исследования кажется, что нам нужно проделать дополнительную работу, чтобы поворотный момент выглядел гладко. Если возможно, я ищу некоторые примеры кодов, которые иллюстрируют, как реализовать это

Спасибо

Ответы [ 4 ]

12 голосов
/ 09 марта 2011

Я расскажу, как я сделал такую ​​заставку. Мои трубы вписаны в 3d сетку, каждая ячейка - это куб:

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

Конфигурация канала в каждой ячейке описывается шестью битами - один бит для каждой стороны. 0 означает, что ячейка пуста, 63 означает, что она имеет шесть сегментов, идущих в центр. Если разбить комбинации на типы, их будет мало:

  • короткие палочки, х6
  • длинные палки, х3 (0-3, 1-4, 2-5)
  • арок, х12 (2 - 1, 1 - 3, 2 - 3)
  • Т-образные перекрестки, х12 (1 - 3 - 4)
  • углов, х8 (2 - 1 - 3, 2 - 3 - 4)
  • крестов, х3 (3 - 1 - 2 - 4)
  • четырехсегментный кластер, x12 (1 - 2 - 3 - 4)
  • пятисегментный кластер, x6
  • шестисегментная звезда, х1.

Я использовал четверть тора для арок (самосинтез), патч сферического треугольника для углов и цилиндры для всего остального. Звезда, кресты и пять сегментов - это просто пересекающиеся цилиндры в моей модели.

Редактировать: некоторый код в C # (я просто надеюсь, что он будет полезен в некотором роде).

Все на сцене объединено из трех моделей - арка, цилиндр и сферический треугольный патч, которые многократно вращаются и визуализируются. Все модели представлены в массивах вершин. Очень скоро я столкнулся с проблемой производительности и внедрил простой LOD на основе расстояния для борьбы с ним. Итак, я создаю не одну модель каждого вида, а серию моделей с разным количеством сегментов.

    /// <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);
    }
1 голос
/ 09 марта 2011

Соединить цилиндры легко, если вы готовы сделать немного больше работы.Просто нарисуйте шар в суставах с gluSphere().Цилиндры, которые вы можете нарисовать, используя gluCylinder()
После того, как вы поймете, как правильно их использовать, все, что вам осталось сделать, - это выбрать ряд точек для соединений, чтобы протянуть трубу через них.

Обратите внимание, что экран сохранения труб также имеет режим, в котором он рисует гибкие трубки, которые плавно огибают углы.Это может быть немного сложнее рисовать.

1 голос
/ 09 марта 2011

Вот шаги, которые вы должны выполнить:

  • Определите, в каком порядке вы хотите соединить точки (если вы выбираете случайное, это может быть странно, я рекомендую поискать алгоритм, который даетхороший порядок.
  • Создайте геометрию вдоль этого пути - в основном вы хотите создать цилиндр на каждом шаге этого пути, вы можете позже подключиться к этим цилиндрам. К счастью, цилиндры - довольно простая частьу геометрии и GLUT есть методы, которые генерируют их для вас.
0 голосов
/ 08 марта 2011

Традиционно NeHe учебник openGL был отправной точкой - они немного устарели, например, не будут работать под Windows7, не знаю, было ли это улучшено.

OpenGL рисует только примитивы, линии, точки, треугольники, поэтому вы должны сами придать им форму - время вспомнить всю тригонометрию средней школы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...