Comments 77
а двойной кватернион быстрее ускоренного(SIMD) перемножения матриц и ничего тут не поделать, а всё дело в том, что у мулматриц и дк количества операций, примерно по моему бенчмарку, который можно узнать через rdtsc видел даже и в 10 раз минимум, представляете как увеличивает скорость если знать как без оверкеша гонять скининг анимации через dqs, и врятли это будет Анриал мне кажется. соотв это своя физика, в паралельном процессе должна быть со всеми нужными солверами, интересно - солвер физики cli
а еще если камера на кватернионе или дк то еще быстрее соотв.
пользоваться виртуальными функциями с математикой почти нельзя, все виртуалки на сколько я видел по годболту у С++ превращаются в табличные штуки, когда в С будет сплошной СИМД изза математики, ну и С быстрее компилируется, придётся велосипедить, зато у С++ есть вектор и анимацию проще получается можно достигнуть, а в С пока разберешься со скелетом, пока из блендера в нужном виде отправишь скелет файликом ) пока разберешься со структурой с этими указателями ) и прочее
поэтому квейк, дум, серии быстрее оптимальнее, может даже халфа там тоже ведь сурс. читал их подходы и в целом они годные, а если наивно делать с оверкешем, то можно захлестнуть либо памяти много, либо перенапрячь кадр, но анимация будет 100%, вот запустить сейчас Морровинд наверняка он мало кушать будет и будет работать сносно
лучше помойму не даблы, а флоаты использовать, с косинусами не сталкивался, косинусы можно частично заменить векторными операциями, которые могут быть ускорены если это позволяет ПК
Распространённый совет — предпочитать std::vector обычным C-массивам и статическим векторам
Блин, да вы бы читать научились, раз уж приводите цитату из GSL. Там же прямое противоречие вашему утверждению про "распространенный совет -- предпочитать std::vector ... и статическим векторам".
For a fixed-length array, use std::array, which does not degenerate to a pointer when passed to a function and does know its size. Also, like a built-in array, a stack-allocated std::array keeps its elements on the stack.
Совет предпочитать использовать std::vector С-шным массивам, действительно, очень давний. ЕМНИП, Страуструп дает его начиная с 3-го издания своей книги "Язык программирования C++", которое вышло уже после появления и стандартизации STL. Но, во-первых, относился он в большей степени к массивам, которые меняют свой размер в динамине. И, во-вторых, с тех пор уже поколение выросло, а в STL уже почти полтора десятка лет есть std::array. Надо бы делать проправки на современные реалии.
Да, все как вы говорите, но открываешь рабочий проект, а там вектора... никто даже не смотрит в сторону std::array, pmr, boost::small_array.
Когда вектора -- это еще неплохо, бывает что и векторов нет, а люди бабахаются с голыми new, а то и malloc-ами. Только вот это же про говнокод, а не про язык. В языке-то давно средства есть, и рекомендации по их использованию.
Мне кажется вы зелёное с тёплым сравниваете. В чем виноваты оптимизированные алгоритмы и контейнеры стандартной библиотеки, если их используют не по месту? Да и реализацию stl можно было бы и посмотреть, коль вставляете свои суждения о том как там всё реализовано и почему это плохо. std::variant основан на рекурсивных юнионах и аллокации памяти там нет, tuple - на рекурсивных структурах. Как следствие - динамических аллокаций в этих контейнерах не происходит. Да, есть проверки в variant при получении значения на соответствие типу, который сейчас там находится. Но чем это будет отличаться от обычного юниона с индексом?
Наивно полагать, что
std::pair
работает так же быстро, как и простаяstruct { T1 first; T2 second; }
.
Ну почему же наивно. std::pair это и есть структура с двумя полями и набором методов. Реализация из libstdc++ ниже.
template<typename _T1, typename _T2>
struct pair
: public __pair_base<_T1, _T2>
{
typedef _T1 first_type; ///< The type of the `first` member
typedef _T2 second_type; ///< The type of the `second` member
_T1 first; ///< The first member
_T2 second; ///< The second member
...
};
Мне кажется, что ошибочно делать суждения предварительно не удостоверившись в их правдивости. Большинство предположений об неоптимальности реализаций stl в статье - пустые доводы.
https://quick-bench.com/q/Wcunfj0d_wvpfCxYOdC1eNAdFIQ, собственно тут это и видно. Компилятор clang, библиотека libcxx. GCC, к сожалению, провалил этот тест, возможно в новых релизах поправят
Про этот кейс я написал, что зависит от настроек и компилятора. На плоечном сдк самый свежий 16 кланг и хреновая поддержка 20 стандарта, 17 кланг завезут хорошо если через год, а то и два, судя по темпам адаптации компилятора под вендора. У меня сейчас вот как-то так, и будет так минимум еще год, потому что уже зафризили версию сдк на препроде. Что там внутри компилятора творится и как это поправить в сдк никто разбираться не будет
https://quick-bench.com/q/M1q0ipx9v9wFlnCYMbgy0JuhP9w
Скрытый текст

если она по зависимостям от фрибсд вам надо разобраться как обновиться до 14.2 версии залить туда 20 кланг и радоваться успехам ), хотя у клиента может быть другая версия, но всё равно)
14.2 и 20 кланг это просто феерверк по производительности ) если разрабы плойки всё правильно сделали )
хотя наверно это нереально сделать
вы наверное не очень в курсе апдейтов сдк на препроде, как минимум продюсеры не дадут ничего менять ибо риск сломать то что работает, апдейт сдк, либ и всякие новшества точно фризят за год а то и больше до релиза, если там конечно не супер прирост обещают.

ну а с указателями быстрее или что тут не правильно?
код не вижу, картинка очень мутная, но разница в скорости в 10х очень подозрительная, даже в 3х подозрительная, всё правильно сделали?
не знаю правильно или нет, я просто взял и создал 2 массива по миллиону через new,
static void packaging_custom_game_objects(benchmark::State& state) {
struct GameObjectData {
int entity_id;
float velocity;
};
//GameObjectData* source, destination;
GameObjectData* source= new GameObjectData[1000000]; // типичный пул данных из игры
GameObjectData* destination= new GameObjectData[1000000];
for (const auto& _ : state) {
benchmark::DoNotOptimize(destination = source); // симулируем копирование при репликации или обновлении физики
}
}
Ну тут вы только указатель копируете, а в двух остальных случаях все содержимое
можно так
memmove(&dst,&src,sizeof(src)); // и поидее это и
// возвращает к семантике итераторов и прочее
правда нюанс если удалить срц сразу после меммув будут артефакты соотв это уже задача когда владение выходит из окна управления соотв сделали меммув посчитали удалили получается
наверно, еще если там именно копирование я видел можно легко передать вектор сам
и сделать std::vector<type> vec(vec1); < и ниче heightmap рисуется кстати
а вектор в игре во фрейме это фильтр - выборка чтобы собрать метаданную и посчитать что-то и на основе этого обновить, какое-то уже проинициализированное состояние, в конце скобочки такой вектор сбросится, соотв на сцене в области видимости камеры ну 1000 обьектов зачастую, у нас персонажи это не партиклы же и дома, может деревья, поэтому это не идеальный случай 1000000 там будут категории обьектов
потом есть и другие случаи определения где камера и что рисуем, наверняка есть еще много нюансов
цифра 1000000 она может быть близка к рейтрейсу наверно(такой маленький рейтрейс типо)
сюда же берем это число и перекладываем на реалии, значит есть возможность деления числа в зависимости от того где камера.
а значит это не 1000 000 постоянно а кусочки которые в сумме 1000 000 игрок находится там где 100 зачем ему весь 1000 000, а если на сцене в каждом кадре по 1000 000 то это разве так делают, наверняка есть тонкости и такого деления(прохода)
например оффлайн одна из возможностей, наверно
тоесть мульти математика, обьект не рисуется но его общее состояние общитывается и когда оно видимо, оно просыпается в нужной точке, соотв там просто около 5 параметров обновлять по таймеру, вот уже нюансы пошли, и соотв может наверно уложится в нагрузку
а есть игры где это можно и не делать, не во всех играх симуляция жизни НПЦ, зачастую достаточно запомнить состояние и перестать рисовать, а когда он проснётся, то пошла его обработка
вот как раз физика, тоже вполне, НПЦшки замерли их 1000000 надо каждому присвоить задачу, 999 800 заснули, надо включить таймер, взависимости от их задач, посчитать интерполированные действия, соотв нужен такого рода солвер(не тот солвер где скурпулезно всё указано до частиц, а в этом контексте солвер это обсчет возможно язык определений что они делают в зависимости от задач), а можно просто считать только ближайших ну тоже таким физическим солвером)
в этом контексте в зависимости от задач, надо прыгнуть во времени вперед и знать на каждую задачу уже решение(поэтому это контекст физики)
1/3 нпц стоит, а то 90% соотв таких активных нпц мало...
соотв невидимый хвост просто отключается, и то что не видим не рисуется
Мне кажется, что ошибочно делать суждения предварительно не удостоверившись в их правдивости. Большинство предположений об неоптимальности реализаций stl в статье - пустые доводы.
Насчет производительности std::pair
vs struct
в рантайм сомнительно. Но вы ведь не будете спорить, что <pair>
, <tuple>
, <variant>
могут значительно поесть время компиляции?)
Автор неоднократно говорит что у всего есть цена - даже если в рантайме бесплатно)
Кажется, оверхед std::pair и tuple'ов в сравнении со struct может быть вызван наличием пользовательских конструкторов, которые хоть и делают семантически ровно то же, что мог бы сделать компилятор, но почему-то оптимизируются хуже
Вот да, за pmr особенно обидно, с самого C++17 уже есть удобный способ управлять размещением стандартных контейнеров в памяти, но вместо этого люди пытаются отказываться от них и писать велосипеды.
Да, даже допиленная в современных стандартах система аллокаторов, увы, не так удобна как бы хотелось, вложенные контейнеры может понадобиться учить принимать родительский аллокатор, но это очень мощное средство, позволяющее ускорить проблемное место зачастую буквально несколькими поправками к коду.
Любопытно, а почему плавающее деление быстрее целого?
предположу, что на это потрачено больше транзисторов.
Скрытый текст
В современных процессорах вещественное деление (FP division) часто быстрее целочисленного (integer division) из-за особенностей аппаратной реализации и исторических оптимизаций. Вот основные причины:
1. Разные алгоритмы выполнения
Вещественное деление (FP division)
Использует аппаратный блок деления (FPU/ALU), оптимизированный для конвейеризации.
Часто реализуется через итерационные методы (например, алгоритм Ньютона-Рафсона), которые можно распараллелить.
Современные CPU (начиная с Intel Haswell, AMD Zen) имеют конвейеризированные FP-делители с пропускной способностью 1 операция за ~3–15 тактов (зависит от точности).
Целочисленное деление (integer division)
Требует последовательной обработки (побитовые сдвиги и вычитания), которую сложнее конвейеризировать.
Аппаратные делители для целых чисел часто не конвейеризированы (или слабо конвейеризированы).
На многих CPU (например, x86) целочисленное деление выполняется за 10–40 тактов и блокирует весь конвейер.
2. Разные стандарты точности
Вещественные числа (IEEE 754) имеют предсказуемую точность, что позволяет использовать приближенные вычисления с последующей коррекцией.
Целочисленное деление требует точного результата, что усложняет аппаратную реализацию.
3. Исторические причины
FP-деление критично для научных вычислений, поэтому инженеры сильнее оптимизировали FPU (Floating-Point Unit).
Целочисленное деление встречается реже (чаще используют умножение и битовые операции), поэтому его ускоряли меньше.
4. SIMD-ускорение
Современные CPU (AVX, SSE) поддерживают SIMD-деление для вещественных чисел (например,
mm256
div_ps
), которое выполняется параллельно для нескольких чисел.Для целочисленного деления SIMD-инструкций нет (кроме редких случаев, вроде ARM NEON).
Примеры задержек (latency) на Intel Skylake:
Операция Тип Задержка (тактов) DIVSD
(FP64) Вещественное 13–14 DIVSS
(FP32) Вещественное 11 DIV
(32-bit) Целое 23–26 DIV
(64-bit) Целое 32–95
Источник: Agner Fog's Instruction Tables
Когда целочисленное деление может быть быстрее?
Если делитель — степень двойки (заменяется на сдвиг).
При использовании умножения на обратное (компиляторы иногда заменяют
x / 10
наx * 0xCCCD >> 19
).На GPU (где целочисленные операции часто оптимизированы лучше).
Вывод
Вещественное деление быстрее в современных CPU из-за:
Конвейеризированной аппаратной реализации,
Использования приближенных методов,
Большего внимания к оптимизации FPU.
Если вам нужно быстрое целочисленное деление, лучше использовать битовые трюки или умножение на обратное.
и не дабл а весь мир можно в флоат и вы ничего не потеряете, дабл в экзотических случаях, и на всякий случай 16 знаков после запятой в пи это очень много для точности достаточно 5-6-7
Нельзя, местами даже double не хватает.
Например, радиус Земли около 6 тысяч километров = 6 * 10^6 и семь знаков точности от float значат, что координаты дадут точность плюс-минус метр.
И это я говорю про хранение, а если делать какую-то логику вычислений, то может потребоваться точность на порядки выше.
Допустим, автосимулятор - размер трассы 10км и делается 1000 шагов физики в секунду.
10км = 10_000_000 мм - а вот и предел точности - миллиметр. И если за шаг физики автомобиль смещается на расстояние порядка миллиметра - это фиаско, смещаться он будет куда попало из-за погрешности округления. При 1000 шагов в секунду 1 мм за шаг это 1м/с = 3.6 км/ч - вполне наблюдаемая ненулевая скорость, на которой машину будет колбасить.
Eщё учтём, что если используется интегрирование Верле, когда новая позиция рассчитывается на основе текущей и предыдущей, то ошибка в позиции будет отклонять заодно и скорость. Типичный порядок скорости для гонок пусть будет 30 метров в секунду и 30 мм за шаг. За каждый шаг физики из-за округления будет вылазить погрешность в 3%, и таких шагов - тысяча в секунду. И даже если взять 100 шагов в секунду вместо тысячи, что откровенно мало, погрешность в 0.3% за каждый шаг это ужасно.
Заметьте - это будет, даже если вычисления идеально точные и округление один раз при сохранении во float.
Только проблема в том, что если в промежуточных вычислениях тоже float - погрешность будет ощутимо расти на каждой промежуточной операции.
Я в своём физическом движке всерьёз задумываюсь про добавление DoubleDouble - потому что иногда даже Double не хватает. Например, можно тензор инерции считать не относительно центра масс, а относительно центра координат. И это математически очень просто и красиво получается - тензоры можно перевести в глобальные координаты, там поскладывать и потом перевести обратно в локальную форму. Причём сложение инерции в глобальной СО - это просто поэлеметное сложение 16 чисел.
Но есть нюанс - инерция это m * r^2, и вот это r^2 может заметно повлиять точность, если тело далеко от центра координат. Да, можно в локальной системе отсчёта такое делать и будет точно, я просто привожу пример когда математически красивый и простой код упирается в точность double и начинаются хаки вокруг.
А с сумматор-компенсатором точности по Kahan не сталкивались?
А кажется это оно и есть.
Когда в одном double хранится какое-то число и в ещё одном - поправка к нему.
И кроме суммирования можно при желании ещё остальных арифметических операций надобавлять. Я вот такое нашёл, но не очень понятно что там с лицензией: https://github.com/Hellblazer/Utils/blob/master/src/main/java/com/hellblazer/utils/math/DoubleDouble.java
ну про пи может я погарячился, но флоата хватит, в игре конкретно, можно настроить по 1 кускам в нужных масштабах вокруг нуля так? и уходить в ++(заполнять четверть с плюсами и там делать локацию, там такие размеры с таким масштабом как указан далее, что пока мы дойдём с таким масштабом до кривоты контента должно хватить), поидее я смотрел должно получиться при условии, что масштаб подобран типо 1 к 400(кусок 40 тыщ вертексов запакованых, тоесть умножаем на 3(в апи есть репитер надо смотреть его описание с ним всё проще становится), его скривляем+применяем сглаживание, делаем хейтмапу, и вот он кусочек условно острова) больше и не нужно поидее
вытаскиваем такие 8 кусков вокруг того куска где игрок, кладём туман на границах, а система зданий и деревьев должны быть в пространстве типо ноды, чтобы можно было скрывать то что не видим, и по маске кидать в дымку, чот такое, но с кусками получается, на С++ не знаю, но на С у меня такие 9 кусков бодро грузятся и ниче не отьедает лишнего
последний замер у меня камера на кватернионе и повороты, так вот, 1 к 400, там есть места где нету отклонений, да и зачем рисовать бескрайний мир, понятно же что это эмуляция бескрайнего мира а в загрузке просто новая сцена или участок, вспомните почему в варкрафте 2 таких континента, я выше описал почему +-, заступаем 3 кусочками на 3 четверти и пошли ++ по ширине и вниз
редактор под такое это генератор с возможностью правки полигонов и сохранение кусочков с нужным масштабом, тоесть в блендере это болезненно
и там моделька маленькая выходит в запаковке из-за репитера, а мы скалируем кусочки

размер куска будь здоров, а их тут 9 тоесть слева еще куски
тогда получается у вас и все настройки, в шейдере по отрисовке мира тоже в даблах? я пока всё рисую флоатом, библиотеку математики тоже написал всё на флоатах, двойной кватернион тоже флоат, перспектива - флоат, орто там я чуть подправил под себя, чтобы было всё где надо, и на С у меня всё работает как часы без усердия со скруглениями, если я начну сейчас вообще все расчеты округлять и шаманить с этим то конечно не запуститься, а так в целом без скругления вся система пашед на 9 кусках хотябы, ну типо как не земля бескрайняя, а как остров или стартовая локация вроде всё работает, ну пока, а вообще согласен с вами если это ударит на солверы(скелетная анимация частный случай так как есть солверы кручений и кинематика базовая по-сути это вход в физику) если её от костей проигрывать в рантайме да, но цена такой костной физики, сейчас скажу какая. на 1 модельку в распакованном виде без скелетки та которая у синк матрикса, это 85900 вершин(в распакованом виде = 2 мегабайта, 1 действия в памяти), альтернатива физически костями их проигрывать, что тоже накладывает ограничения, например те какие вы указали
вы как раз указали это, в блендере все матрицы - солверы поидее в локальном пространстве считаются, типо гоняем инверсией туда-сюда, да и блендер хранит матрицу-базис, матрицу-локаль, и матрицу-мировую
Скрытый текст
import bpy
# Path to output your data
output_file = "mesh_data.txt"
# Get your object
ob = bpy.context.object
# Save the current frame to restore later
original_frame = bpy.context.scene.frame_current
# Define the frame range
frame_start = bpy.context.scene.frame_start
frame_end = bpy.context.scene.frame_end
with open(output_file, "w") as f:
for frame in range(frame_start, frame_end + 1):
depsgraph = bpy.context.evaluated_depsgraph_get()
bpy.context.scene.frame_set(frame)
bpy.context.view_layer.update()
# Get evaluated mesh
eval_obj = ob.evaluated_get(depsgraph)
mesh_eval = eval_obj.to_mesh()
# Get the world matrix
world_matrix = eval_obj.matrix_local
# Transform vertices into world space
mesh_eval.transform(world_matrix)
# Write frame header
f.write(f"frame {frame}\n")
# For each polygon, write the vertices' positions in order
for poly in mesh_eval.polygons:
for v_idx in poly.vertices:
v = mesh_eval.vertices[v_idx]
f.write(f"{v.co.x} {v.co.y} {v.co.z}\n")
# Separator for next frame
#f.write("\n")
# Clear the mesh
eval_obj.to_mesh_clear()
# Restore original frame
bpy.context.scene.frame_set(original_frame)
bpy.context.view_layer.update()
В шейдерах можно и флоаты.
Допустим, камера рядом с объектом и объект с камерой где-то далеко от центра координат.
Тогда в матрицах и объекта и камеры появляюстя большие числа. Но поскольку камера и объект рядом, произведение этих матриц даст матрицу, в которой больших чисел нет (MV) и которую можно безболезненно передавать в шейдер (или вообще сразу MVP передать).
Т.е., произведение M*V лучше с большой точностью считать, а дальше можно в шейдере.
P.S. Я сильно подозреваю что двойной кватернион это то же самое что и мотор в геометрической алгебре. Он же описывает одновременно и позицию и поворот? Вот с ними при уделении от центра координат у меня тоже не очень хорошо получается, потому что поворот описывается косинусами-синусами в интервале [-1, +1], а линейные координаты растут.
Вот тут в тесте можно примерные числа глянуть (причём мне тут точности double недостаточно оказывается)
https://github.com/Kright/ScalaGameMath/blob/master/pga3dPhysics/src/test/scala/com/github/kright/pga3dphysics/Pga3dInertiaLocalTest.scala#L26
Я даже задумываюсь над тем, чтобы мотор обратно разложить на перемещение + вращение и в таком виде везде хранить
я проверил у себя, у меня ни одного косинуса-синуса, на дукате, их там избежать можно вроде(сужу пока по дукату и по тесту я сравнивал мультик матрицы на СИМДЕ транслейт*поворот с дукатом они индентичны по итогу, но дукат быстрее на порядок)
пейпер надо открывать вникать
я видел ролики есть сравнение с ротором, но я не вникал в это потомучто не нужно покачто
Скрытый текст
0.23127034 -0.022801302 -0.026058631
0.019543974 0.110749185 -0.016286645
-0.17589577 0.0032573289 0.1465798
-----------------------------------------#то что выше другое
real: 0.26726124 0.5345225 0.8017837 0
dual: 12.026755 -8.017838 1.3363063 -45.43441
time equation for operation 3928
-0.857143 0.28571433 0.42857152 0
0.28571433 -0.42857152 0.85714304 0
0.42857152 0.85714304 0.28571433 0
10.000001 30.000006 90.000015 1
0.26726124 0.5345225
180.00006
time equation for operation 14100
-0.8571427 0.2857151 0.42857084 0
0.28571343 -0.42857128 0.8571431 0
0.42857197 0.8571425 0.28571433 0
9.999999 29.999996 89.99999 0.9999999
снизу кватернион на нём у меня камера покачто по ней сужу что работает, а вот тут по углам приходилось по оси брать угол указывать и указывать ось, так что они равны, но видимо по ходу счета есть нюансы
всё по факту(ничего не знаю)) равны и rdtsc зафиксировал скорость
если судить по дукату то можно избавиться от косинуса синуса, и вообще не использовать в углах их, тогда нету гимбол лока и прочее, не знаю у меня работает, беру ось текущую результирующую и угол и камера летит в любом месте, естессно я про повороты покачто, камера же от мышки крутится соотв есть direction куда смотрим, и оси куда крутим
тоесть ничего не проверяем просто даём камере смотреть и крутиться по оси, я так могу описать это
Скрытый текст
void rotateBy(Camera1 *camera,float deg)
{
Quaternion q;
q=QAngleAxisdV3(deg,(vec3){0,1,0});
mat4 rot;
rot=ToMatrixQQ1(q);
vec3 tN = getNormalView(camera);
vec4 rotViewVec = Mulmv4(rot, (vec4){tN.x, tN.y, tN.z, 0});
camera->vp = Addv3(camera->cameraPos, (vec3){rotViewVec.x, rotViewVec.y, rotViewVec.z});
}
void rotateUD(Camera1 *camera,float deg)
{
vec3 viewVector = getNormalView(camera);
vec3 viewVectorNoY = Normalizev3((vec3){viewVector.x, 0.0f, viewVector.z});
float currentAngleDegrees = Anglev3(viewVectorNoY,viewVector);
if (viewVector.y < 0.0f) {
currentAngleDegrees = -currentAngleDegrees;
}
float newAngleDegrees = currentAngleDegrees + deg;
if (newAngleDegrees > -85.0f && newAngleDegrees < 85.0f)
{
vec3 rotationAxis = Crossv3(getNormalView(camera), camera->cameraUp);
rotationAxis = Normalizev3(rotationAxis);
Quaternion q;
q = QAngleAxisdV3(deg, rotationAxis);
mat4 rot;
rot = ToMatrixQQ1(q);
vec3 tN = getNormalView(camera);
vec4 rotViewVec = Mulmv4(rot, (vec4){tN.x, tN.y, tN.z, 0});
camera->vp = Addv3(camera->cameraPos, (vec3){rotViewVec.x, rotViewVec.y, rotViewVec.z});
}
}
...
void mouse_callback(GLFWwindow *window, double xposIn, double yposIn)
{
if (mouseHandleInCenter)
{
vec2 curMPos = WindowCenterPos(&win);
vec2 delta = Subv2(curMPos, (vec2){xposIn, yposIn});
rotateBy(&camera, -delta.x);
rotateUD(&camera, -delta.y);
glfwSetCursorPos(window, win.wi / 2, win.he / 2);
}
}
что-то типо такого у вас?

видите не правильные деформации? и повороты
вы написали последовательность M*V, а должно быть вроде
p * v * m * vec4(apos,1.0);
так же имеет значение row-major или collumn-major матрица, от этого будет перспектива и lookat соотвественно и отрисовка
соотв солвер(кость и её вьюшка, в зависимости от выбранной конфигурации мат аппарата должны быть в пространстве мировых координат) будет из-за этого соотвествующий, потомучто блендер например хранит матрицы
[
a b c t
a b c t
a b c t
0 0 0 1
]
для этого надо выбрать фрейм числом, выбрать зависимость на всякий случай, выбрать арматуру, выбрать кость и линкануть в консоль матрицу, и в консольке в блендере можно посмотреть как до нее достучаться
вобщем там из-за конфигурации мат аппарата еще нюансы
и вы сказали от -1 до 1 это надо точно знать какие координаты, какое пространство, потомучто мировые координаты это ну 4 четвертные
вот на скриншоте моделька в пространстве камеры а не в мировых координатах как я понимаю, и проблема с кручением
для глубины картины, напишу наблюдения, в блендере я как-то хотел отрисовать анимированный инстанс от 1 модельки в лоб, и увидел ваш еффект все синстансенные анимации были привязаны на Origin(0 0 0) тоесть там чото не хватает типо какого-то домножения, которое бы поставило бы точку относительности. Например (T*R*S) даже если вы не используете чтото есть момент что всё промножить следует, Scale(1,1,1), Rotate надо проставить 0 по 1,1,1 и типо того.
тоесть матрицу модели всё равно можно простроить. хотя с единичной матрицей тоже рисует не знаю
ну всё я понял, Affine_transformation тут описано rotate как sin/cos, еще другая форма расчета ротейта существует с таким тригонометрическим комплексом(sin/cos),
пошли нюансы, допустим мы имеем свою перспективу, знаем очередность перемножения, и знаем очередность построения модели, к виду в шейдере в p v m vec4(vec,1.0f); , не важно как мы догадались до этого, главное чтобы комплекс расчета работал визуально корректно, может у вас ортогональная матрица екзотическая, но отвечает функционалу так, что всё на своих местах
тогда когда мы переходим на кватернион(закладываем его в фундамент всех расчетов) мы уходим от афинного представления матрицы(может они и будут как-то появляться частично, но это еффект межрасчетный, потомучто если перешли на кват, то там пайплайн прямолинейный T*R*S),
тогда если мы хотим в какойто момент вернуть возможность афинного представления, или в наших расчетах появилась афинная матрица(если она попадёт в базис с кватернионом, матрица не правильно представится и будет поломанная матрица, как на моём скриншоте+-), поворот надо извлеч(тоесть надо увидеть знать в каком месте появилась афинная декомпозировать её и всё) и привести к кватерниону, и там как раз не будет ни косинуса ни синуса(ни на пути извлечения, ни на пути установки угла от полученных значений, вот такой вот нюанс), далее, надо извлеч перемещение, соотв всё зависит от того как мы сконструировали мат аппарат я теперь уверен.
TestDSAOpenglWorld вот пример на ваш скала пример
все источники указаны
извините пока механика не ясна, теоретически всё звучит интересно)
имеем точку 0 0 0 пошли точкой сначало до 10 0 10 и пошли точкой в 10 0 +
delta 0.16(ну можно сделать и 1.16) механика переполнения пока не ясна, каждый 0.16 будет смещение вы хотите сказать float переполнится в определенный момент или что?) вы выстраивали террейны в + хотябы по 9 террейнов шириной(с масштабом 800 каждый)? это очень большой размер, пока флоат переполнится мы где то пол часа бежать будем, мне интересно есть ли понимание масштаба?
при этом мы пользуемся векторной математикой ) окей 9 на 30 надо будет посмотреть!

бежать ну минут 10(ну ладно не 10 но не мгновенно пробегаются 30 квадратов даже по прямой) там много пространства, 30 на 30 это очень много, очень, я пока не понял проблемы!
скорее всего вы про переполнение флоата, типо как еффект в майнкрафте.
визуально было бы наверно как обливион, если еще с пещерами и порталами этож я даже не знаю
кстати морровинд после даггерфола стал ограниченным, и обливион визуально маловат, еще туда можно добавить масштаб фолаут76(стадии первый месяц после релиза)
если проверить 100 квадратиков, а нужны ли 100 квадратов в масштабе тоже интересно, 30 на локацию достаточно(с нулём тоесть с загрузкой, но логичной а не так где попало)
вот 30 на 30 с генерацией трека (тоесть пути вполне), туда же еще симуляция(скорость разгон) 5 кругов в 30 квадратах, вроде получается
вот так опять молчаливый минус и нет конкретики )
Вам чуть ниже уже написали про достаточно длинные ответы, которые не всегда соотносятся с темой статьи. Попробуйте собрать Ваши мысли в формат статьи, что-ли. А то получается, что вы сами себе отвечаете. Тем более 3д графика, там много своих нюансов, которые не бьются с обычным программированием, пытаться здесь искать параллели - ну они конечно будут, но различий намного больше будет. Кстати хорошая тема, я бы почитал.

это ответ к memove
тоесть прибавляем математика висит на своей библиотеке и все контейнеры висят на своих библиотеках, а отсюда следует либо нужны указатели с STL либо надо понимать зависимости к чему и почему пишут свои реализации, получается условие не трогать STL а вы смотрите STL
тоесть надо выбирать в ваших тестах очевидно что мы придём к указателям, возвращаясь к миллиону обьектов(это подсказка потомучто вы только сказали про миллион обьектов, я тоже просто говорю тут и будет ключевая зависимость почему придётся сделать ключевое производительное решение и это +- так и есть), там как раз там и вся суть из-за этого и будет
Да что за конкретика может быть на ваши потоки мыслей. Это даже читать тяжело, не то что вникать
граффика 3д, ошибки, производительность в граффике какие-то показатели того о чем пишется сопровождение в картинке где видно что этот подход ударит по производительности, дело в том что если это не смотреть, а просто представлять то это не совсем очевидно, бенчмарк не очень удобный кстати тоже, поэтому очевидно что рассматривать комплексно FPS, диспетчер задач, кусок кода, и %GPU/CPU, renderdoc еще можно
тоесть а действительно это не инициализация например? а вдруг в тесте это похоже на инициализацию и тогда это совсем другая история. и этот ситуативный вопрос решающий
std::vector<int> createVector(int size) {
std::vector<int> result;
result.resize(size);
for (int ii = 0; ii < size; ++ii) {
result.push_back(ii * ii);
}
return result;
}
Тут явно опечатка. Вместо result.resize(size) должно быть result.reserve(size). Я не знаю проверяли ли вы ассемблер на resize или все таки reserve, хотелось бы обновленный ассемблер если все таки на resize :)
Спасибо, поправил. Опечатка там конечно reserve, выше в тексте ссылка godbolt, листинг оттуда
а если в этом конкретно случае оставить так, то
//result.resize(size);//потомучто уже ресайз
//int count=0;//откуда дописываем если ресайз не
//уничтожит то что было )если так то нужна
//проверка перед ресайзом чтобы новый ресайз был больше предыдущего
//тогда
int count = -1;
bool check = false;
if(size > result.size()){
count = result.size();
result.resize(size);
check=false;
}
else if (size < result.size() )
check = true;
for(int i=0;i<size;i++){
if(check)result.push_back(i*i);
else result[count++]=i*i;
}
Хранить данные в std::array может быть иногда не так эффективно, как в std::vector. Ведь под std::array обычно выделяют памяти с запасом - под максимально-возможное количество элементов. Это может сказаться в худшую сторону на потреблении памяти. К тому же увеличивается вероятность кеш-промахов, ибо будут читаться данные из незаполненной части массива, которые по факту не нужны.
на крайний случай конкретно в вашем примере про GameObject
если оставить указатели то, то что в указателях инициализируется из файла(если из файла это история про сериализацию обьектов она не связана никак с инициализацией во время отрисовки на сколько я понимаю - это вроде менеджмент ресурсов),
второй конструктор если принципиально хотите поменять
можно всё закинуть в массив
struct GameObject1{ // тогда это будет DOD
float specAttribs[6];// первое целое число ID )))
};
//или
struct GameObject2{
vec3 idHealthTeam;
vec3 pos;
};
std::vector<GameObject1> objs;
for(auto& a: objs)
std::println("{} {} {} {} {} {}",
a[0],a[1],a[2],
a[3],a[4],a[5]);
Великолепная серия статей! Продолжайте, пожалуйста :)
Делал игры разве что в качестве курсовых, а на C++ не пишу более 10 лет, но все равно крайне интересно читается. Ведь большинство практик и выводов неплохо переносятся на другие языки и технологии!
... а std::function, оказывается, иногда аллоцирует в куче.
Для интересующихся - как раз есть std::move_only_function (начиная с C++23), который умеет хранить объект callable в себе:
Implementations may store a callable object of small size within the std::move_only_function object.
Но весь вопрос как обычно сводится к "а какой у нас размер лямбды с контекстом?".
Порой помогает простое человеческое спасибо вписывание захватываемых объектов руками:
[&a, &b, ...](...){}
Таким образом мы логично не засасываем в захват лямбды всё подряд из контекста над ней.
Ещё помогает завернуть одну лямбду по ссылке в контекст другой, но там уже надо осторожно, в малых дозах.
За статью плюс.
Таким образом мы логично не засасываем в захват лямбды всё подряд из контекста над ней
Зачем? [&]
/[=]
захватит только то что реально используется в теле лямбды. В явном виде имеет смысл перечислять только если у вас отличаются правила кэпчура для разных переменных.
, , — одни из самых "тяжёлых" заголовков стандартной библиотеки, содержащие десятки тысяч строк шаблонного кода, этот код не может быть закеширован и будет пересобираться в каждом юните компиляции, да - только нужные части, но файл все равно будет парситься заново.
Precompiled header?
скажу сразу: статья полезная! ее лучше читать, чем не читать :) но вот в деталях...
прежде всего, ОЧЕНЬ много опечаток!! может кто-то считает, что для программиста это нормально, но... 100% такое же будет и в коде ;((
нарушает локальность данных в кэше, первые несколько обращений к данным вектора (обычно 10-15) пока внутренние структуры CPU не адаптируются к новому паттерну, проходят "вхолодную"
это как ТАКОЕ возможно?!
что, первые несколько обращений CPU не загружает данные в кэш?!?! жесть.
Однако за убогость и всеядность приходится платить производительностью
вот тут не поспоришь!
на коленке сделанная int_map сразу работает в несколько раз быстрее std::unordered_map<int, int>. это конечно позор.
https://www.linkedin.com/pulse/do-you-still-trust-stl-sergey-derevyago-bzenf
Кто же знал, что атомарные инкременты у
shared_ptr
не бесплатные?
а знали не только лишь все: https://ders.by/cpp/norefs/norefs.html#4.1
У вас хороший слог, почему не писать на хабре (только без капса плиз) ? Я бы почитал с удовольствием. З.ы. Ссылка выдаёт 403.
тут суть в том что либо надо в векторе хранить указатель или писать на С тогда по маллоку будет работать железобетонно, и в одном файле и в разных, а С++ оброс требованиями, чтобы вектор с переменными заработал надо постараться, фикситься раздельными файлами, тоесть увеличиваем время компиляции, писать код явно, и придётся указатели использовать, тогда всё будет на плечах разраба, а не вектора.
тоесть борьба с таким вектором не имеет никаких побед, надо просто вызвать память и работать с ней, нет смысла увиливать вектор с переменными фигово фурычик, взял выделил память и следишь за ней вручную тогда, как быыыыыыыыы, берем кусок кода валве и там ну почти всё будет на указателях, автор этой статьи избегает упоминания работы с памятью через указатели и долго ждать вобщем
вобщем избегать указатель это я не знаю, переменные не вариант вобщем, кеши-меши, когда нужна память, пользователь не будет 100 раз запускать игру, всё должно быть выделено, должны быть ексепшены я не знаю, но работать с переменными не варик, вот с памятью через указатель проще работать сразу всё встаёт на свои места, а так числа гонять, да я скажу вдогонку числа и я могу гонять, а дальше примера чисел с кешем и таким вектором дело не дошло покачто и что я наблюдаю у себя от такого вектора это отказ при запуске из-за как раз миссов. вобщем долго еще будем смотреть наверно на вектор с переменными
может кто-то считает, что для программиста это нормально, но... 100% такое же будет и в коде
Опечатки — дело житейское, тем более в русских текстах, когда люди 99,9% рабочего времени пишут и, возможно, говорят на английском. Не только лишь все могут писать чисто и публиковаться без корректора, но их статьи от этого хуже не становятся.
И напоследок цитата одного «широко известного в узких кругах» программиста:
«We didn’t have spell checkers in our editors back then, and I always had poor spelling. The word "collumn" appears in the source code dozens of times. After I released the source code, one of the emails that stands out in memory read: It’s "COLUMN", you dumb FUCK!».
бенчей мало в данном контексте нужно рассматривать в целом, сцена - игра - код,
вот код, вот бенч, вот зависание и там будет видно что зависает какая реализация )
если делаем игры примерами с инициализацией миллиона компонентов не отделаться, на реализации всё сразу видно будет
возможно было бы получше еще добавить рендердок на такие обзоры чтобы уж наверняка(на ваших примерах будет видно какой геометрией вы пользуетесь, а так же расплывчатость исчезнет и будет одна конкретика), много воды, некоторые темы повторяются, буквально несколько обзоров про вектора, и нету никакой конкретики, что надо почерпнуть в статье, что узнать чему научиться? только примеры инициализаций
где синус кладёт нет примера, только цифры, где кладут вектора, тоже самое, где кладёт memmove тоже самое, вопросов больше, как тогда подразумевается не правильное использование и как правильное? что такое тогда оптимизация,проект,образование проекта,как им пользоваться,как компилировать, какая библиотека, какой движок, какой фреймворк, какой сдк участвует в обзоре (это всё не точки ситуативные, а выбранные автором должны быть, если тут нету ентузиазма смысл смотреть инициализацию), вобщем это не конкретные ситуации, а всё расплывчато, если это всё положить на уровень NDA, может и не надо вообще это всё
например 1000 000 кубиков(который имеет координаты, а значит тоже подподал под пример, который у вас в статье), и так далее, любой кто сталкивался с 3д скажет на примере std::vector<obj> obj; //миллион (туда же тригонометрия и все примеры, которые повторяются без паралели с вопросом, вообще о чем речь ) скрывается бездна ситуаций, просто мерить миллион в ините нету смысла, просто мерить стл нету смысла, эти вопросы должны быть в синергии о чем речь, таких туториалов полно в сети(посмотрите примеры, где показывают как что-то в 3д начать делать хотябы, там поменьше теории, зато сразу видно с чем имеем дело), все что-то показывают, что узнали нового, взять любой пример dx12, а так мы просто застряли на какой-то теории, которая на практике и не нужна вовсе, тоесть всё не правильно, медленно, у меня не медленно например, и я имею партиклы например, и ваш пример, а еще с бенчмарком, ни о чем не говорит, инициализация 1000000 обьектов в вектор ни о чем не говорит, косинус тоже ни о чем не говорит, потомучто есть нюансы моменты
Jijiki, я вас умоляю, завязывайте с этим флудом, а то вам карму начали по третьему разу уже сливать, и скоро опять по комменту в сутки сможете только писать.
Я ваш энтузиазм разделяю и им восхищаюсь, но ради Б-га, вместо написания кучи комментов, потратьте лучше время, не знаю, например, на эти 7 видео-лекций от Шодана (не вздумайте мне сейчас говорить, что их уже смотрели!), напишите по ним свой STL хоть на голых Сях и запилите статью для Хабра (можете мне на вычитку сначала ее дать, чтобы до вас не так сильно докапывались).
спасибо за ваш отзыв, просто в статье нету конкретики, это не флуд кстати, а констатация фактов, просто замерять стл/косинус/вектор нету смысла, пока нету конкретной ситуации на екране, я пойду дальше и разовью суть повествования контекста, у каждой программы есть мало мальски проект, если мы пишем на колнке реализацию, то результат будет соотвествующий, значит должны быть конкретные примеры, а не просто замерили вектор и вектор виновник(как раз нет), это будет зависеть от многих факторов, далее у каждой программы есть стадии(компиляция-инициализация-момент исполнения) тут только граффик чего? вектора/косинуса/стл? идём далее, открываем 2005 год слайд GDC господин Ульрих показывает конкретно! прошу заметить на сколько это возможно его продвижения с хотябы минимальными примерами, делаем вывод, все замеры без какой-то ситуации конкретной не имеют смысла в граффическом контексте.
тогда получается если у автора есть интерес показать какую-то фишку, есть очень много моментов как это сделать, но ведь это надо сузить до единственного условия ситуации (компиляция-инициализация-исполнение-визуализация)
и там уже видно где вектор/косинус/стл виновник торжества
(например я вот симд переменожение матриц включил увидел глазами ускорение, стал пользоваться кватернионом без rotate и без афинных матриц увидел наглядно работу, так могу еще примером накидать, например загрузил милион кубиков и увидел что будет), тоесть это всё это не теория как раз, это примеры как раз, но если кватернион можно реально замерить включив его, то с вектором и косинусом в широком контексте бездна вариантов, поэтому примеры были бы желательны
далее туда же и про functional, очень много вопросов к таким замерам и именно такому повествованию
спасибо мне математики достаточно!
мне очень интересно было бы узнать что bind functional тоже такой плохой? если functional такой, отсюда и появляются вопросы
Красной нитью по всей этой серии статей проходит мысль: «Включай башку и профайлер, бенчмаркай, не пролюби кэш-миссы/долгую-сборку/дедлоки/просадки-fps/ect в гонке за модой и выпендрежем, нужен велосипед — делай, но обрати внимание на ..., хочешь запилить что-то поддерживаемое — можешь сделать вот так ...». И всё это иллюстрируется случаями из практики и/или фатальными факапами.
Если нужна серьезная конкретная конкретика я полезу за докладами GDC или SIGGRAPH, где все всё победили, и в книжку загляну, код свой побенчмаркаю, в профайлер залезу, покурю, а чужие примеры запускать навряд ли буду (просто ознакомлюсь) — у меня на экране фризы от моего говнокода и от моей же неграмотности (ну или из-за забагованного компилятора и тормозной STL!/s).
И ждать от этого цикла объема и подробностей всех изданий «Black Art of Effective Modern Game Programming in C++ with Engine Architecture Gems, Tips & Tricks» я, понятное дело, не стану — оно мне по-другому полезно.
да текстовые примеры кода, а подразумеваем в каких-то местах например кадр(что там что-то нагрузит когда граффика будет), и он не показан, и не показан простенький пример такой ситуации, и это в таких обзорах большой промах, ну вот вы попробуйте последуйте своему совету(с какой-то попытки начнёте более точно пытаться говорить о предмете), тогда всё грузит, в условиях анимации так и есть, и это расширяет диапазон манёвра для обсуждения, тогда это обсуждение вектора стл и косинуса просто бесконечно без конкретики, тоесть практика вектора в обсуждении когда так преподносим не даёт картины того что оно действительно так, а значит есть случай когда так может быть, почему вы считаете что интересно только коротенько без конкретики показать ошибку?
ну вот у вас фризы сделайте обзор своего кода это может быть интересно почему нет вообще? вот у меня на С нету пока фризов
можно начать с базы, которая у thecplusplusguy и от него стартовать наверно он как мог заобзорил всю базу до конца, там конечно есть моменты с математикой, но это в целом переносимо на буфферы, а значит и до dx12 - vulkan, идея кубов например тех самых учит работать с сеткой, есть повод о чем задуматься, и математика вот уже антифриз, остаётся только физика - полное погружение
коннектеры - это и есть кости, кости работают по принципу кинематики с идеей относительности и координат и весов - это настоящая физика, и вот так по чуть чуть так и до нод дойти можно
вот они же в 2д только

и вот опишу пример почему пришлось смотреть как это рисовать в 2д, потомучто так проще понять, и на этом примере 0 нагрузки например, ну это очевидно, соотв коннектер это вектор а не 3д моделька, и он в векторном пространстве принципиально
а блендер например рисует 3д модельку коннектора-кости, и отсюда много визуальных моментов, поэтому приходится разбираться, вот разобравшись стало ясно, что коннектор-кость - это вектор с параметрами, который действует на вершины меша-сетки
видите пошли нюансы давайте покажу, фризы! сразу какой апи, как организован проект, матеша скорее всего у DirectX(ну или глм), это первый блок обычно где надо определиться, второй блок под примеры, что фризит? открывали ли вы рендердок вкладку где видно drawcall, меш-статический или партикли, опять же если это партикли помимо вектора и того что даже в статье сказано есть принципы как это делать еффективнее. выделить партикли не проблема 100 штучек, надо чтобы происходило обновление, партиклей, и партикли были запакованы определенным образом это самый первый параграфф с партиклами, а далее система партиклей с буфферами доводятся до последних возможностей апи - а это уже даже не совсем тема вектора, а комплекс того как еффективно воспользоваться практикой по отрисовке партиклей
кароче есть практики, и эти практики не корелируют на начальном знакомстве с 3д с архитектурой, потомучто пока нет понимания как это должно выглядеть вы будете переписывать по стадии из самой простой до самой финальной, вот чтоб понять финал, надо интелектуально посмотреть пример, переходя к статьям про вектора и синусы, которых нету! ни единого конкретного примера, ни с фризами, ни без фризов, а без этого это даже не база, а просто теория, на подобии вектор грузит/косинус тяжелый
как видим 3д без примеров на сухих векторах и теории об этом это хуже отрицательного результата в 3д
В коде ниже не может произойти RVO, потому что возвращаемый тип не соответствует тому, что мы возвращаем. Нам нужно построить std::optional объект, и тут вызовется конструктор перемещения, что не так плохо, но не RVO. В версией с const действительно конструктор перемещения не может быть использован, и будет конструктор копирования.
std::optional<ParticleSystem> make_editable_particle_system() {
ParticleSystem ps(100); // тяжелая аллокация
return ps;
}
Чтобы в вашем примере случился RVO надо написать сразу вот так
return std::optional<ParticleSystem>(ParticleSystem(100));
P.S. В этом, кстати проблема современных std::optional, std:expected и им подобных.
Про использование std::function
добавлю. В C++26 появился std::function_ref
(P0792) - не владеет callable-объектом, а держит reference-wrapper + тривиальный function-pointer thunk. Его размер - два указателя, ни аллокаций, ни type-erasure-state.
Насчёт деления float. Хоть оно и быстрее, чем у целых чисел, оно всё равно медленнее, чем умножение. Поэтому если делишь на константу, то лучше использовать умножение на обратное число. Не уверена, насколько это важно для центрального процессора, но при написании шейдеров это порой критично
обычно компиляторы про это знают, называется strength reduction и делают там где получается.
Об этом всё равно стоит знать. Например, если несколько чисел нужно разделить на НЕ константу, то лучше 1 раз выполнить деление, а все числа умножать на это обратное число. Учитывая, как много математики в игровых движках, это может иметь смысл. Просто если в статье упоминается деление на double, то и эта микрооптимизация не будет лишней, имхо
Статья хороша в том плане, что можно увидеть, где именно у вас в проекте могут быть проблемы и как их можно решить. Но с самого начала следовать им я бы не советовал, иначе проект рискует не добраться до момента, когда кому-то будет не пофиг на его производительность.
Особенно это касается замены вектора на сырой массив, избегания туплов и других движений в сторону примерно С++03. Не поймите меня неправильно, они скорее всего действительно работают и полезны в плане перфы, но точно не для рандомных багов выделения памяти или увеличенного времени на реализацию фичи, потому что чёрт ногу сломит в низкоуровневом коде.
Совершенно верно, сначала профайлер потом улучшения, если у вас "потерялся" мьютекс в горячей функции никакими хаками вы это не исправите. А вот если вы залезли по локоть в профайлер и оптимизируете например A*, то смысл соблюдать правила?
ну тогда это приведёт к выбору библиотеки и решению ... для которого оно нужно было(фича), ну а какие баги могут быть ? всё тетстить так и так и если уйти от СТЛ дебажить и годами тестить, и если использовать СТЛ тоже могут быть моменты, но всё будет в итоге упираться на решение для которого(или почему вернулись на стл, в случае если не делаем ускорялку), тоесть тут будут выборы ускорялка своя или накачали либ и подконектили и всё это будет тесно связано с архитектурой и структурой ключевой под ... которую задумывалась ускорялка(там будет целая зависимость)
зачем в сторону 03 достаточно не использовать и не инклюдить стл как я понял
Это приведёт к выбору решения, которое адаптировано под конкретный проект.
не спорю, is_an_aabb_bvh_the_right_choice_for_a_tilebased/ тут еще можно посмотреть, как влияет структура хотябы и что могут быть зависимости
вот решение как мне кажется выбрать из миллиона ближайших

ни sqrt ни косинус только относительность(типо боксы рисуются только для дебага а так это просто центроид и 8 точек или макс/мин) и сравнение по боксу, звучит лаконично вообще имба(даже бильярд вроде можно будет сделать)
соотв тут от апи будет зависеть, не знаю как на DX делаются тени, но на гл это бокс на обзор теней если есть, бокс на контакт игрока, бокс определитель, и бокс отсекатель ну там уже придётся разбираться сколько и какой оставить
я в блендере прикинул простой пример вроде всё сходится, я заряжен энтузиазмом буду проверять ) я почему-то увидел что такое столкновение быстрейшее)
Game++. Performance traps