Страницы

Поиск по вопросам

среда, 22 января 2020 г.

Деформация 3D модели с помощью кривых Безье

#cpp #3d #directx #mesh


Пишу программу, которая должна деформировать модель по опорным точкам. 

Получилось написать следующий код, который создает полотно процедурно по 16 опорным
точкам. Вот как это выглядит:



//вычисляем полином Бершнейна третьей степени на основании четырех точек
XMFLOAT3 Bernstein(float u, XMFLOAT3 p1, XMFLOAT3 p2, XMFLOAT3 p3, XMFLOAT3 p4) {
    XMFLOAT3 a, b, c, d;

    a = pointTimes(pow(u, 3), p1);
    b = pointTimes(3 * pow(u, 2) * (1 - u), p2);
    c = pointTimes(3 * u * pow((1 - u), 2), p3);
    d = pointTimes(pow((1 - u), 3), p4);

    return pointAdd(pointAdd(a, b), pointAdd(c, d));
}

//тоже самое что и верхняя функция, только принимаем указатель на массив точек
XMFLOAT3 Bernstein(float u, XMFLOAT3 *p) {
    XMFLOAT3 a, b, c, d;

    a = pointTimes(pow(u, 3), p[0]);
    b = pointTimes(3 * pow(u, 2) * (1 - u), p[1]);
    c = pointTimes(3 * u * pow(1 - u, 2), p[2]);
    d = pointTimes(pow(1 - u, 3), p[3]);

    return pointAdd(pointAdd(a, b), pointAdd(c, d));
}

void CreateSurfaceByControlPoints(XMFLOAT3 points[], D3DTextureVertex **ppVertices) {
    const int step = 16;    //количество делений у полотна
                            //чем больше делений, тем глаже модель становится (создается
больше вершин)

    const int max = (step * (step + 1) * 2);    //общее количество вершин у модели

    XMFLOAT3 temp[4];
    XMFLOAT3 *last = new XMFLOAT3[step + 1];

    //в массиве points, размером 16 точек,
    //у меня верхняя линия с индексами от 0 до 3, следющая от 4 до 7 и т.д.

    for(int i = 0; i < 4; i++) {
        temp[i] = points[(i + 1) * 4 - 1];
    }

    for(int i = 0; i < step + 1; i++) {
        last[i] = Bernstein((float)i / (float)step, temp);
    }

    *ppVertices = new D3DTextureVertex[max];

    int c = 0; //счетчик текущей вершины

    for(int i = 1; i < step + 1; i++) {
        float py = (float)i / (float)step;
        float pyold = ((float)i - 1.0f) / (float)step;

        for(int j = 0; j < 4; j++) {
            temp[j] = Bernstein(py, points[j * 4 + 0], points[j * 4 + 1], points[j
* 4 + 2], points[j * 4 + 3]);
        }

        for(int j = 0; j <= step; j++) {
            float px = static_cast(j) / (float)step;

            (*ppVertices)[c++] = D3DTextureVertex(last[j].x, last[j].y, last[j].z,
pyold, px);

            last[j] = Bernstein(px, temp);

            (*ppVertices)[c++] = D3DTextureVertex(last[j].x, last[j].y, last[j].z,
py, px);
        }
    }

    delete[] last;
}


Все вышесказанное работает отлично, но теперь задача усложнилась и мне нужно загружать
произвольную модель (она тоже 2D, как и моя процедурная), добавлять опорные точки таким
же образом и деформировать меш по такому же подобию.

Модель уже имеет свою геометрию и UV координаты.
Выглядит следующим образом:


Главный вопрос - есть ли какая-нибудь формула, чтобы рассчитать позицию для каждого
вертекса, основываясь на 8 кривых Безье (4 горизонтальных и 4 вертикальных), учитывая
их первоначальную позицию? Как, например, в профессиональных программах Maya или Blender
есть такие инструменты, как произвольно расставить опорные точки и делать с моделью
любые деформации.
    


Ответы

Ответ 1



Спасибо за помощь! Получилось решить проблему следующим образом: //1378 и 861 - значения у меня рассчитаны, чтобы вся модель умещалась на экране //у вас они могут быть другие или вообще по-другому считаться, главное, чтобы pz и px были в пределах [0.0f, 1.0f] //в переменной points хранятся опорные точки //в ppOutVertices хранится указатель на вершины, которые будем задавать //в ppBaseVertices хранится массив вершин по-умолчанию, на основе которых формируем новый массив //nVertices - количество вершин в моделе void UpdateSurface(XMFLOAT3 points[], D3DTextureVertex **ppOutVertices, D3DTextureVertex **ppBaseVertices, UINT nVertices) { XMFLOAT3 tmp[4]; *ppOutVertices = new D3DTextureVertex[nVertices]; for(int i = 0; i < nVertices; i++) { float pz = (float)(*ppBaseVertices)[i].Pos.x / (1378.0f / 100.0f); for(int j = 0; j < 4; j++) { tmp[j] = Bernstein(pz, points[j * 4 + 0], points[j * 4 + 1], points[j * 4 + 2], points[j * 4 + 3]); } float px = (float)(*ppBaseVertices)[i].Pos.z / (861.0f / 100.0f); XMFLOAT3 bern = XMFLOAT3(Bernstein(px, tmp)); (*ppOutVertices)[i].Pos = XMFLOAT3(bern.x, 0.0f, bern.z); } }

Комментариев нет:

Отправить комментарий