#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); } }
Комментариев нет:
Отправить комментарий