Генерация вершин для сферы - PullRequest
13 голосов
/ 10 декабря 2010

В примере мобильного освещения 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)


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

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, но может быть изменено для вывода набора полос треугольника

Ответы [ 3 ]

11 голосов
/ 10 декабря 2010

Базовый способ думать об этом:

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

Уже давно, поэтому я могу ошибиться ...

Единичный круг, определенный параметрически:

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

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

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

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

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

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


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

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

tetrahdralSphere (int recursions) {}

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


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


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

Давайте нарисуем 10 очков за кольцо ... так что фи будет шагать с шагом 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
5 голосов
/ 10 декабря 2010

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

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

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

2 голосов
/ 13 декабря 2010

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

...