Как бы я ни старался учиться электронике, я нахожу занятным освоить в первую очередь аналитическую геометрию, чтобы виртуозно манипулировать векторами и делать разные расчёты.
Я разрабатываю собственный движок, чтобы отработать математические навыки и подготовиться к математическому анализу. Да, мне уже 37 лет, а я всё ещё не знаю как пользоваться правильно дифференциальными уравнениями, хоть и понимаю из одной книги как это было важно для разных открытий, в том числе и для нахождения площади или длины кривых.
Свой путь я начал с линейной алгебры и до сих пор знаю наверное очень мало из этой области. Даже пробовал с утра просить нейросеть давать мне задачки из линейной алгебры и решал их, а потом отдавал на проверку. Эта алгебра показалась более дружелюбной для начала вхождения в изучение математики.
Как только я узнаю какую-то формулу или что-то открываю для себя новое, я тут же воодушевляюсь и очень радуюсь, и конечно не забываю добавлять в игровой движок новые знания, подчерпнутые из книг.
Я бы хотел рассказать как я бросил луч в сцену, на создание которого, а он ещё не доделан, я потратил 4 дня. Движок мой на C и поэтому думаю, что будет понятен каждому.
Я хотел разобраться в этом сам и не боялся времени, которое ускользает у нас каждый день. Больше люблю получать удовольствие от процесса и поэтому я не искал в книгах по началу как правильно бросить луч, но и потом как оказалось, что я не совсем понимаю примеры, которые мне подала нейросеть.
Нейросеть мне подсказала, что можно перемножить обратные (матрицу камеры и проекции) и умножить это на вектор и потом получается что-то, с чем я не понимал как работать и пошёл дальше своим путём.
Я научился немного исследовать разные закономерности, пока пытался это сделать и вот что я сделал. Мне надо было получить начало луча на экранных координатах и долгое время это не удавалось делать. Потом всё же я, с помощью дотошных вычислений определил, что есть некое число, которое должно быть на краю экрана и это число было -1.470588. Я не понимал как найти это число, ведь оно должно же откуда то браться. Таким образом я начал подгонять под результат и мне представилась формула, где можно сложить числа так, что получиться это число. В последствии я спросил у нейросети что это за формула, которую я вывел и она сказала, что это формула масштабирования экрана. Выглядит она так.
Я обрадовался, это же классно, когда можно вывести какую-то формулу, пусть даже она и простая.
Таким образом я смог получить координаты точки по дальности в единицу от экрана.
Так я смог получать координаты по X и Y экрана, но дальше было ещё сложнее. Я не мог бросить отрезок дальше единицы. Я просто не понимал закономерность.
Я создал несколько лучей, чтобы определить что не так.
make_ray_from_cursor (game, cam[CAM_MAIN], ray[0], rays[0], x, y, 2.f, 0.f);
make_ray_from_cursor (game, cam[CAM_MAIN], ray[1], rays[0], x, y, 3.f, 0.1f);
make_ray_from_cursor (game, cam[CAM_MAIN], ray[2], rays[0], x, y, 4.f, 0.2f);
make_ray_from_cursor (game, cam[CAM_MAIN], ray[3], rays[0], x, y, 5.f, 0.3f);
make_ray_from_cursor (game, cam[CAM_MAIN], ray[4], rays[0], x, y, 6.f, 0.4f);
по rays я пытался определить правильно ли падает луч, но не получалось, вечно были проблемы с углами. Да, я пытался использовать тригонометрию, чтобы всё это вычислить.
Итак, вот лучи, когда я кликаю у конца экрана.

дело в том, что спустя два дня я догадался, что можно просто фронт камеры умножить на дальность и потом умножить X координату тоже на дальность и получить желаемый результат, но так не выходило. Как видно на экране, лучи сгущаются в одну точку.
часть кода была такой.
int xx = x - game->sc->w / 2;
int yy = game->sc->h / 2 - y;
float aspect = game->sc->aspect;
float h = game->sc->fw * 0.5f;
float v = game->sc->fh * 0.5f;
float null_vector[3] = {0.f, 0.f, 0.f};
float kh = (aspect + 1.f) / (1.f + aspect / 2.f);
float xxx = (float) xx / (h / kh);
float yyy = (float) yy / (v * (aspect / kh));
float v0[3];
float v1[3];
float d0[3];
float d1[3];
vec3_mul_scalar (v0, cam->front, z_far);
v0[2] = xxx;
vec3_copy (ray->origin, null_vector);
vec3_copy (ray->dir, v0);
ray->dir[1] = up_y;
printf ("xxx: %f\n", xxx);
в последствии я вывел некоторую формулу, которая помогла мне получить ровные линии на удалении.
v0[2] = xxx * ((z_far + 1.f) * kh);
Это было ошеломительно. До этого я догадался, когда искал закономерности и видно было, что дистанция z_far больше на kh из предыдущей z_far.

Лучи стали ровные, но указатель мыши был не там, где надо. Тогда я поделил начальную координату, чтобы она стала более мелкой.
xxx /= 2.f * kh;

И вуаля, теперь линии рисуются прямо по курсору. Что ж. По горизонтали я сделал. Осталось добавить работу по вертикали и луч будет бросаться прямо так как я задумал. Сначала сделаю, чтобы бросался из центра, а потом чтобы из точки курсора.
Вот полный код функции.
void make_ray_from_cursor (struct game *game, struct camera *cam, struct ray *ray, struct ray *check_ray, int x, int y, float z_far, float up_y)
{
int xx = x - game->sc->w / 2;
int yy = game->sc->h / 2 - y;
float aspect = game->sc->aspect;
float h = game->sc->fw * 0.5f;
float v = game->sc->fh * 0.5f;
float null_vector[3] = {0.f, 0.f, 0.f};
float kh = (aspect + 1.f) / (1.f + aspect / 2.f);
float xxx = (float) xx / (h / kh);
float yyy = (float) yy / (v * (aspect / kh));
xxx /= 2.f * kh;
float v0[3];
float v1[3];
float d0[3];
float d1[3];
vec3_mul_scalar (v0, cam->front, z_far);
v0[2] = xxx * ((z_far + 1.f) * kh);
vec3_copy (ray->origin, null_vector);
vec3_copy (ray->dir, v0);
ray->dir[1] = up_y;
printf ("xxx: %f\n", xxx);
#if 0
vec3_mul_scalar (v0, cam->right, xxx);
vec3_sub (d0, cam->front, v0);
float r[3];
float rr[3];
vec3_mul_scalar (v1, cam->real_up, yyy);
vec3_add (d1, d0, v1);
vec3_copy (r, null_vector);
vec3_copy (ray->origin, r);
vec3_copy (ray->dir, d1);
#else
ray->origin[0] = 0.f;
ray->origin[1] = 0.f;
ray->origin[2] = 0.f;
#endif
ray->pos[0] = cam->pos[0];
ray->pos[1] = cam->pos[1];
ray->pos[2] = cam->pos[2];
opengl_ray_setup (ray);
translate (ray->transform, cam->pos[0], cam->pos[1], cam->pos[2]);
float view[16];
mat4x4_mul (view, ray->transform, cam->view);
mat4x4_mul (ray->model, view, ray->projection);
}
Что ж, надеюсь, что моя статья понадобиться кому-нибудь. Хотя мне кажется, что мой вариант не такой классный, как должен быть, ведь существуют методы бросания луча и скорее всего они лучшие из лучших. Тем не менее, я хочу творить и производить расчеты и создавать свой движок, на котором я потом буду делать игры.
FarhodN
Непонятно. Что теперь модно хвастаться своим не знанием?
xverizex Автор
Я восхищаюсь наукой, но не получается в полной мере участвовать в её развитии. Разве я хвастаюсь? Хвастаются, это когда деляться успехами в какой-то области, разве нет? Описание того, чего я не знаю я не просто так привел. Я хотел показать, что уровень знаний у меня не очень большой и не смотря на это, я хочу развиваться. Это вдохновляющая статья должна быть, ведь здесь есть дух исследования. Очень жаль, что моя статья затронула лишь эти чувства в вас и заставила вас написать это. Думал, что будет лучше.
Я например люблю один документальный фильм From Bedrooms to Billions: The Playstation Revolution и хотелось бы тоже сложными вещами в разработке игр заниматься. Очень классно, когда в те годы люди столкнулись с непростой задачей и смогли её решить. Это прям вдохновляет и я стремлюсь так же.