LINUX.ORG.RU

3д математика

 ,


0

1

Хелоу парни, с вами снова Ксения Собчак. http://habrahabr.ru/post/248611/ помогите понять что они херачат с коэффициентом в конце статьи, понять не могу. Другие подобные статьи по перспективной проекции разобрал, но тут какие то непонятки. Вместо того что бы проецировать на near plan они на far plan растягивают... (После заголовка «Пора перейти к трем измерениям»)



Последнее исправление: jerekao (всего исправлений: 3)

Ты предлагаешь всё это читать нам что ли? Что ты, не осилил матрицу поворотов? В чем нужна помощь?

anonymous
()
Ответ на: комментарий от jerekao

Но подобные статьи я то осилил, значит я не безнадежен. Просто этот фокус понять не могу.

jerekao
() автор топика
Ответ на: комментарий от jerekao

Там конец статьи не понятен без начала. Я вообще когда камеру себе писал, делал на простом подобии треугольников (одна из вершин - камера, другие — точки на экране и на какой-нибудь плоскости в мире). Цель камеры была перевести координаты на экране в координаты в мире.

Вот кода немного.

https://github.com/shamazmazum/voxvision/blob/master/src/voxrnd/camera.c

anonymous
()
Ответ на: комментарий от I-Love-Microsoft

«Там есть трюк, с помощью которого перспективную проекцию получают при помощи растяжки и последующей ортогональной проекции» как сделали растяжку, вроде понимаю, не понимаю зачем и что за фокус с ортогональной проекцией?

jerekao
() автор топика
Ответ на: комментарий от jerekao

Ок, ты можешь просто написать координаты пучка векторов, расходящихся из одной точки в пространство, с одинаковыми углами между соседними векторами?

anonymous
()
Ответ на: комментарий от jerekao

http://higgs.rghost.ru/6htlcxlY9/image.png

Вот (y,x) — мировые координаты, (y',x') — координаты, связанные с камерой.

Пока пусть они получены только трансляцией.

y' = y + a
x' = x + b

Сможешь в этой системе задать единичные векторы, которые расходятся из (0,0) в стороны, как показано на рисунке?

anonymous
()
Ответ на: комментарий от anonymous

Ну кхмхмх, можно наверное увеличивать w, а потом смещение.

jerekao
() автор топика
Ответ на: комментарий от anonymous

Ой, не заметил что с одинаковыми углами, ну можно сделать формулу, а потом ее пускать по каким нибудь значениям углов через цикл.

jerekao
() автор топика
Ответ на: комментарий от jerekao

Ну пусть центр пучка — вектор (1, 0) в системе камеры (y',x'). Пока пусть на 2d.

Далее, тебе нужен угол обзора 2*alpha. Значит уравнения для векторов будут

y' = -sin(alpha) + 2*i*sin(alpha)/n
x' = 1

Где n - количество векторов, которые тебе надо. Для простоты, это кол-во пикселей на экране. sin(alpha) можно поменять просто на alpha, это не даст особых искажений.

Для 3d ты делаешь то же самое, но лучи расходятся не треугольником, а пирамидкой.

z' = -sin(alpha) + 2*i*sin(alpha)/sz
y' = -sin(alpha) + 2*i*sin(alpha)/sy
x' = 1

Где sy и sz — ширина и высота экрана. Вот теперь у тебя есть камера, которую ты можешь двигать трансляцией (просто прибавляя к x',y',z' положение камеры в пространстве), но вращать пока не можешь. Как вращать-то понял?

anonymous
()
Ответ на: комментарий от jerekao

Вот то что я говорил, в моём коде. Ты даешь функции координаты точки на экране sx и sy и она записывает в ray направление луча, соответствующее этим координатам

static void simple_screen2world (void *obj, vox_dot ray, int sx, int sy)
{
    vox_simple_camera *camera = obj;
    SDL_Surface *surface = camera->iface.ctx->surface;
    ray[0] = camera->fov*(2.0*sx/surface->w - 1.0);
    ray[1] = 1.0;
    ray[2] = camera->fov*(2.0*sy/surface->h - 1.0);
    vox_rotate_vector (camera->rotation, ray, ray);
}
anonymous
()
Ответ на: комментарий от jerekao

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

Ещё раз, забей на то, что не понятно. Тебе надо всего лишь:

1) Для точки на экране построить луч в системе координат, связанной с камерой. Как это сделать, я написал.

2) Повернуть этот луч в соответствии с тем, как повернута твоя камера.

3) Транслировать луч в соответствии с тем, как твоя камера расположена.

Шаги 2 и 3 можно делать с помощью умножения матриц. Трансляция, например, будет осуществляться как

[x]   [1 0 0 a] [x']
[y] = [0 1 0 b] [y']
[z]   [0 0 1 c] [z']
[1]   [0 0 0 1] [1 ]

Но лучше её делать обычным сложением, а не умножать матрицы.

Обратная задача делается в точности наоборот

anonymous
()
Ответ на: комментарий от anonymous

Матрицы как умножаются - знаю из статьи, комплексные числа - понимаю что такое, кватерионы вообще не представляю. Мой уровень - школьный курс тригонометрии и те несколько статей + неплохие скилы в программировании. Как себя можно апнуть? Посоветовали аналитическую геометрию почитать.

jerekao
() автор топика
Ответ на: комментарий от jerekao

Посоветовали аналитическую геометрию почитать.

Не-не-не. Там будешь читать про кривые второго порядка и прочую муть. Прочитай что-нибудь из линейной алгебры для освоения матриц получше. И ту же тригонометрию вспомни.

Вот представь, что у тебя камера повернута относительно мировой СК на угол фи.

http://rghost.net/7RY4LhWHj/image.png

Пардон за рисунок такой. Орт Z мы не видим на нем. Он протыкает монитор под 90 градусов.

Ты посчитал координаты луча в СК камеры. Как повернуть эти координаты, чтобы получить их в мировой СК?

Из тригонометрии мы помним:

x = x'*cos(phi) - y'*sin(phi) + a
y = x'*sin(phi) + y'*cos(phi) + b

a и b просто сдвиг (трансляция) одной СК относительно другой. Как это записать в виде матриц? Просто:

    [cos(phi)  -sin(phi)  0   a]
    [sin(phi)   cos(phi)  0   b]
A = [0          0         1   c]
    [0          0         0   1]

Теперь смотри:

  [x']   [x]
A [y'] = [y]
  [z']   [z]
  [1 ]   [1]

Т.е. мы повернули наш вектор с координатами (x',y',z') на угол phi относительно оси z и сместили его на (a,b,c) превратив в (x,y,z)

anonymous
()
Ответ на: комментарий от jerekao

Теперь, например, мы хотим крутануть вектор после того, как мы крутанули его вокруг z, вокруг оси x на угол psi. Отдельно матрица для этого:

     [1   0          0         a]
     [0   cos(psi)  -sin(psi)  b]
B =  [0   sin(psi)   cos(psi)  c]
     [0   0          0         1]

Теперь, чтобы получить x нам нужно A умножить на x' и B умножить на результат этого действия.

x = A(Bx)

Но у матриц (как и у действительных чисел) есть свойство операции умножения — ассоциативность. Это значит, что

A(Bx) = (AB)x

То есть, чтобы вращать вокруг обеих осей, тебе достаточно одного умножения, а не двух. Помножь A на B: C=AB и координату x ты получишь, умножая C на x'.

Ещё раз, для 5 степеней свободы (трансляция (3) + вращения (2)) матрица будет такая:

    [1    0          0         0][cos(phi)   -sin(phi)  0   0]
C = [0    cos(psi)  -sin(psi)  0][sin(phi)    cos(phi)  0   0] +
    [0    sin(psi)   cos(psi)  0][0           0         1   0]
    [0    0          0         1][0           0         0   1]

    [0   0    0  a]
+   [0   0    0  b]
    [0   0    0  c]
    [0   0    0  0]

Т.е. находишь координаты луча x в СК камеры, Cx будут координаты луча в СК мира. Ну и всё. Ну или наоборот. Из СК мира делаешь СК камеры, а потом СК экрана (проецируешь подобием)

anonymous
()
Ответ на: комментарий от jerekao

Помни, что AB /= BA

Итого тебе понадобится перемножатор матриц и место для 12 чисел в памяти (потому что последняя строка всегда (0 0 0 1), но для простоты можно и её запомнить).

С кватернионами тоже можно вращать, и ещё как. Там и запоминать нужно будет меньше — положение камеры в пространстве (3 числа) + 4 числа, итого 7. Думается, что современные компы щёлкают кватернионы не медленнее, чем матрицы, так что стоит задуматься

anonymous
()
Ответ на: комментарий от jerekao

Ну только если почта. shamaz.mazum at gmail.com

Ну или вконтакт vk.com/zhmudo

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.