Как нормализовать размер модели в DirectX?

Я создал простой "движок" в DirectX, который может загружать и отображать модели из файлов.obj. Это работает нормально для объектов, которые я создал, например, простой куб с координатами в диапазоне от -1,0 до 1,0. Однако загрузка модели, которая использует разные единицы измерения и имеет координаты в диапазоне от -2k до 2k, приводит к огромному чему-то, что даже не полностью помещается в буфер глубины, поэтому я вижу как одну огромную ногу или похожий эффект.

Я помню, что читал где-то об этом, но, поскольку я недавно прошел через много DX-материалов, я не могу вспомнить, где или что это было. Итак, мой вопрос в том, что если я хочу загружать разные модели, в которых используются разные блоки, каков наилучший способ убедиться, что все они имеют одинаковый размер и хорошо помещаются на экране?

Я мог бы попытаться преобразовать значения при загрузке объекта, но, возможно, есть еще какой-нибудь способ DirectX, который использует матрицы преобразования или шейдеры?

1 ответ

Решение

Самый простой способ - найти, на каком компоненте модель содержит самый большой диапазон, и использовать это значение для равномерного масштабирования модели. Чтобы найти наибольший диапазон, вычислите ограничивающий прямоугольник модели (если файлы obj. Wavefront не предоставляют его уже, но, возможно, вы все равно захотите это проверить), и используйте размер блока в качестве диапазона для сравнения. Это уменьшит масштаб всех импортируемых моделей до диапазона единиц.

Например, если у вас есть модель с ограничительной рамкой, охватывающей 374 * 820 * 512 единиц, самой большой из них является ось Y с 820, поэтому вам просто нужно уменьшить ее на 820 (разделить все компоненты на 820). Это может быть удобно достигнуто с помощью равномерной матрицы масштабирования, которая может быть инициализирована с помощью D3DXMatrixScaling, если я не ошибаюсь. Предполагая, что ограничивающий прямоугольник задан 2 векторами (максимальная и минимальная вершины), вычислите разность этих векторов, затем выберите наибольшее значение и используйте его обратное значение в качестве коэффициента масштабирования для вашей матрицы.

D3DMatrix mScale;
D3DVector mx, mn;
obj->getBoundingBox(&mn,&mx);
float scale = 1.0 / max(mx.x - mn.x, max(mx.y - mn.y, mx.z -mn.z));
D3DXMatrixScaling( &mScale, scale, scale,scale);

Осталось только вставить матрицу в конвейер рендеринга.

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

D3DVector mn, mx;
mn.x = mn.y = mn.z = MAX_FLOAT;
mx.x = mx.y = mx.z = - MAX_FLOAT;
for (int i = 0; i < numVertices ; i++) {
   mn.x = min(mn.x, vertex[i].x);
   mn.y = min(mn.y, vertex[i].y);
   mn.z = min(mn.z, vertex[i].z);
  // same for mx using max
}

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

Другие вопросы по тегам