Создание вершин для сферы

В образце мобильного освещения DirectX цилиндр генерируется следующим образом:

for( DWORD i=0; i<50; i++ )
            {
                FLOAT theta = (2*D3DMX_PI*i)/(50-1);
                pVertices[2*i+0].position = D3DMXVECTOR3( (float)sin(theta),-1.0f, (float)cos(theta) );
                pVertices[2*i+0].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
                pVertices[2*i+1].position = D3DMXVECTOR3( (float)sin(theta), 1.0f, (float)cos(theta) );
                pVertices[2*i+1].normal   = D3DMXVECTOR3( (float)sin(theta), 0.0f, (float)cos(theta) );
            }

Существует ли аналогичный способ создания вершин для сферы в DirectX Mobile (как полоса треугольника или иначе)? (AFAIK там нет метода D3DMXCreateSphere)


Окончательное решение. Спасибо за quarternion за всю его помощь.

void CreateSphere()
{
    const int iFactor = 20;
    int iPos = 0;

    arr_Vertices = new CUSTOMVERTEX[ui_VCount];
    ui_ShapeCount = iFactor *iFactor * 2; // use when rendering

    float arrV[iFactor* iFactor][3];

    for (DWORD j= 0; j < iFactor; j ++)
    {
        FLOAT theta = (D3DMX_PI*j)/(iFactor);

        for( DWORD i=0; i<iFactor; i++ )
        {
            iPos = j*iFactor+i;
            FLOAT phi = (2*D3DMX_PI*i)/(iFactor);
            arrV[iPos][0] = (float)(sin(theta)*cos(phi));
            arrV[iPos][1] = (float)(sin(theta)*sin(phi));
            arrV[iPos][2] = (float)(cos(theta));

            /*std::cout << "[" << j <<"][" << i << "] = " << arrV[iPos][0]  
                << "," << arrV[iPos][1] << "," << arrV[iPos][2] <<std::endl;*/
        }
    }

    int iNext = 0;

    for (DWORD j= 0; j < iFactor; j ++)
    { 

        for( DWORD i=0; i<iFactor; i++ )
        {
            if (i == iFactor - 1)
                iNext = 0;
            else iNext = i +1;

            iPos = (j*iFactor*6)+(i*6);
            arr_Vertices[iPos].position = D3DMXVECTOR3( arrV[j*iFactor+i][0], arrV[j*iFactor+i][1], arrV[j*iFactor+i][2]);
            arr_Vertices[iPos + 1].position = D3DMXVECTOR3( arrV[j*iFactor+iNext][0], arrV[j*iFactor+iNext][1], arrV[j*iFactor+iNext][2]);


            if (j != iFactor -1)
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+i][0], arrV[((j+1)*iFactor)+i][1], arrV[((j+1)*iFactor)+i][2]);
            else
                arr_Vertices[iPos + 2].position = D3DMXVECTOR3( 0, 0, -1); //Create a pseudo triangle fan for the last set of triangles

            arr_Vertices[iPos].normal = D3DMXVECTOR3( arr_Vertices[iPos].position.x, arr_Vertices[iPos].position.y, arr_Vertices[iPos].position.z);
            arr_Vertices[iPos + 1].normal = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);
            arr_Vertices[iPos + 2].normal = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);

            arr_Vertices[iPos + 3].position = D3DMXVECTOR3( arr_Vertices[iPos+2].position.x, arr_Vertices[iPos+2].position.y, arr_Vertices[iPos+2].position.z);
            arr_Vertices[iPos + 4].position = D3DMXVECTOR3( arr_Vertices[iPos+1].position.x, arr_Vertices[iPos+1].position.y, arr_Vertices[iPos+1].position.z);

            if (j != iFactor - 1)
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( arrV[((j+1)*iFactor)+iNext][0], arrV[((j+1)*iFactor)+iNext][1], arrV[((j+1)*iFactor)+iNext][2]);
            else
                arr_Vertices[iPos + 5].position = D3DMXVECTOR3( 0,0,-1);

            arr_Vertices[iPos + 3].normal = D3DMXVECTOR3( arr_Vertices[iPos+3].position.x, arr_Vertices[iPos+3].position.y, arr_Vertices[iPos+3].position.z);
            arr_Vertices[iPos + 4].normal = D3DMXVECTOR3( arr_Vertices[iPos+4].position.x, arr_Vertices[iPos+4].position.y, arr_Vertices[iPos+4].position.z);
            arr_Vertices[iPos + 5].normal = D3DMXVECTOR3( arr_Vertices[iPos+5].position.x, arr_Vertices[iPos+5].position.y, arr_Vertices[iPos+5].position.z);

            //std::cout << "[" << iPos <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos].position.y <<
            //  "," << arr_Vertices[iPos].position.z <<std::endl;

            //std::cout << "[" << iPos + 1 <<"] = " << arr_Vertices[iPos + 1].position.x << 
            //  "," << arr_Vertices[iPos+ 1].position.y <<
            //  "," << arr_Vertices[iPos+ 1].position.z <<std::endl;

            //std::cout << "[" << iPos + 2 <<"] = " << arr_Vertices[iPos].position.x << 
            //  "," << arr_Vertices[iPos + 2].position.y <<
            //  "," << arr_Vertices[iPos + 2].position.z <<std::endl;
        }
    }
}

Следует использовать только несколько настроек. Это создает TRIANGLELIST, но может быть изменен для вывода набора треугольных полос

Ответы

Ответ 1

Основной способ думать об этом:

Первый метод не использует непрерывную полосу треугольника...

Прошло некоторое время, поэтому я могу ошибиться...

Параметр, заданный параметрически:

Where 0 =< theta < 2pi 
x = sin(theta);
y = cos(theta);

Теперь, когда мы можем определить один круг, представьте концентрические кольца на плоскости x, y. Теперь представьте, что вы поднимаете внутренний кружок, и когда вы поднимаете его, он подтягивает следующее кольцо, как slinky... Этот визуал работает только для половины сферы.

Таким образом, форма, создающая форму сферы из концентрических колец, является, конечно, еще одной окружностью, ортогональной кольцам, плоскостью (z, y)... Конечно, нас интересует только поиск смещения кольцо (как высоко или низко оно должно быть смещено от плоскости (x, y).

Поскольку нам просто нужно смещение, нам нужна только половина круга... и далее полюса будут только одной точкой. Используйте треугольный вентилятор на полюсах и полоски между каждым кольцом.

После этого умственного упражнения см. http://en.wikipedia.org/wiki/Sphere и найдите "Точки на сфере с радиусом r можно параметризовать через", и после этой строки вы увидите параметрическую форму.

Нормали очень легки, сфера всегда должна строиться вокруг (0,0,0), и сфера всегда должна строиться с радиусом 1 (так что вы можете просто масштабировать ее до нужного размера), а затем каждая вершина на поверхности круга равна нормальному.


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

Представьте себе тетраэдр, центрированный вокруг начала координат (точки - 1 единица от 0,0,0). Это довольно жалкое представление сферы, но это приближение. Теперь представьте, что мы находим середину на каждой из четырех сторон, а затем нажимаем эту точку, пока она не окажется на поверхности сферы. Затем мы находим середины этих граней и выталкиваем их на поверхность сферы...

tetrahdralSphere (int рекурсии) {}

Найти среднюю точку очень просто, это всего лишь среднее значение для каждой из компонентов x, y, z. Тогда, поскольку сфера является единичной сферой, перемещающей их на поверхность, так же просто, как нормализация этого нового вектора.


Метод one создает точечное распределение, которое просматривает линии долготы и широты и создает неравномерное распределение (оно выглядит так же, как глобус при использовании квадрациклов и проволочной рамки), его довольно легко реализовать. Второй метод требует рекурсии, поэтому он немного сложнее, но будет выглядеть более равномерным. Если вы хотите стать очень сложным и повредить себе голову... затем попробуйте распределить n точек, а затем имитируйте силу отталкивания между точками, которые перемещают их друг от друга, а затем нормализуют их по поверхности. Существуют всевозможные головные боли, которые необходимо адресовать, чтобы эффективно выполнять эту работу, но тогда у вас есть довольно равномерно распределенные точки, и вы можете контролировать количество вершин, и у вас будет самое начало понимания того, что требуется для инструментов моделирования. найти минимальную геометрию для представления модели.


Переход с первым методом. Нарисуйте точку в (0,0,1), тогда вам понадобится ваше первое концентрическое кольцо (для каждого кольца будет одинаковое количество точек для простоты).

Давайте нарисуем 10 очков за кольцо... так что phi будет шагать с шагом 2pi/10 и позволяет нарисовать 10 концентрических колец

и мы нарисуем 10 колец + 2 полюса, чтобы тета увеличивалась с шагом pi/12.

//this psudo code places the points
//NOT TESTED
deltaTheta = pi/12;
deltaPhi = 2pi/10;
drawVertex(0,0,1) //north pole end cap
for(int ring; ring < 10; ring++){ //move to a new z - offset 
  theta += deltaTheta;
  for(int point; point < 10; point++){ // draw a ring
    phi += deltaPhi;
    x = sin(theta) * cos(phi)
    y = sin(theta) * sin(phi)
    z = cos(theta)
    drawVertex(x,y,z)
  }
}
drawVertex(0, 0, -1) //south pole end cap

Ответ 2

Обычный способ триангуляции единичной сферы состоит в построении тетраэдра или икосаэдра и

  • Если точности достаточно, остановите
  • Иначе, для каждого существующего лица:
  • Добавьте вершину в середину каждого края и нормализуйте ее так, чтобы она находилась на единичной сфере
  • Замените лицо четырьмя новыми лицами. У одного из лиц есть три новых середины в виде углов (нарисуйте их на бумаге, а остальные три лица станут очевидными)
  • Loop.

Чтобы избежать дублирования вершин в средних точках края, вам необходимо отслеживать существующие вершины для повторного использования.

Ответ 3

Я объясняю довольно подробно в своем посте в ответ на этот вопрос.