Я создал простой «движок» в DirectX, который может загружать и отображать модели из файлов .obj. Это работает хорошо, для объектов, которые я создал, например простой куб с координатами в диапазоне от -1,0 до 1,0. Однако загрузка модели, которая использует разные единицы измерения и имеет координаты в диапазоне от -2k до 2k, приводит к огромному чему-то, что даже не помещается в буфер глубины, так что я вижу одну огромную ногу или похожий эффект.
Я помню, что где-то читал об этом, но, поскольку я недавно прошел через много DX-материалов, я не могу вспомнить, где или что это было. Итак, мой вопрос в том, что если я хочу загружать разные модели, в которых используются разные блоки, каков наилучший способ убедиться, что все они имеют одинаковый размер и хорошо помещаются на экране?
Я мог бы попытаться преобразовать значения при загрузке объекта, но, возможно, есть еще какой-нибудь способ DirectX, который использует матрицы преобразования или шейдеры?
Самый простой способ — найти компонент, который содержит модель с наибольшим диапазоном, и использовать это значение для равномерного масштабирования модели. Чтобы найти наибольший диапазон, вычислите ограничивающий прямоугольник модели (если файлы 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
}
Конечно, вам может понадобиться использовать некоторый коэффициент масштабирования, если ваш вид охватывает большую область, чем блок юнитов (но, очевидно, это то, что вы используете).
Других решений пока нет …