Перейти к содержанию
СофтФорум - всё о компьютерах и не только

Работа в графическом режиме (Pascal)


Рекомендуемые сообщения

Привет!

Есть такая задачка: нарисовать куб и начать его вращать вокруг всех трех осей с одинаковым ускорением (суть не в ускорении).

В общем у меня есть процедурки:

1. Вычисляет двумерные координаты точек для построения куба через данные трехмерные (которые вычисляются при преобразованиях)

2. Ищет "заднюю" точку куба, т.е. нижнюю и дальнюю (от экрана туда к трубке в элт мониторах)

Что делает программа:

Сначала задаются координаты всех вершины при помощи единичек, ноликов и -1, после этого создается массив граней grani[1..6,1..4], который хранит для каждой грани номера вершин, которые образуют эту грань. Рисуются грани при помощи стандартной процедуры FillPoly(4,s); где в массив s заносятся двумерные координаты (проекции) массив такой s:array[1..8,1..2].

После этого рисуем сначала куб (ну масштабируем там и все такое, чтобы он был не мелким и по центру экрана, описывать это не буду, т.к. все просто).

Далее применяем преобразования для вращения вокруг оси х и оси z (Еще потом надо будет добавить вокруг у - у меня это пока не получается)

Вот эти преобразования:x_b:=v[i][1]; v[i][1]:=round(x_b*cos(da)+ver[i][2]*sin(da)); v[i][2]:=round(-x_b*sin(da)+ver[i][2]*cos(da)); - это вокруг оси z (координата z не меняется) i меняется от 1 до 8 (для всех вершин)Потом стразу для вращения вокрух оси х:y_b:=ver[i][2]; ver[i][2]:=round(y_b*cos(da)+ver[i][3]*sin(da)); ver[i][3]:=round(ver[i][3]*cos(da)-y_b*sin(da));

После этих преобразований применяем процедуру для преобразования полученных трехмерных координат в массиве v в двумерные координаты (проекции). Далее процедура для вычисления задней точки вычисляет ее. Теперь строим куб. По граням. Если в грань входит задняя вершина, то не строим эту грань. Ну потом задержка,стирание, преобразования трехмерных точек, опять построение и т.д.

Проблема: при вращении очень рано исчезают "задние" грани, т.е. получается вращается кусок куба, состоящий из трех смежных граней.

если вращаю вокруг одной оси, то раннее исчезновение оно хоть и есть но не такое заметное.

Проблема2: при рассчетах координат происходит округление=> получается искажение координат, т.е. если долго вращать куб, то это уже будет не куб, а неизвестно что. Для устранения этой проблемы придумано вот что, когда угол вращения накапливается до 6,24, координаты опять задаются исходные. Но если взять малый угол (примерно 0,01, то искажение заметно при повороте уже на 3,14 (т.е на пи). как это устранить? ассемблер использовать нельзя.

Вопрос:

y_b:=ver[1];

ver[1]:=round(y_b*cos(da)-ver[3]*sin(da));

ver[3]:=round(y_b*cos(da)+ver[3]*cos(da));

по ходу дела это преобразования для вращения вокрух оси у, но если их применять, то куб начинает "разрастаться" вширь. Может кто подскажет что здесь неправильно?

И еще мааленький вопросик: чем отличается вращение куба вокрух всех трех осей координат и спокойный куб во вращающейся системе координат?

Ссылка на комментарий
Поделиться на другие сайты

Бумер:

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

Во-вторых, насчет округления - его можно использовать только при выводе рисунка куба на экран. Расчетные координаты точек должны оставаться действительными числами, иначе погрешности расчета будут стремительно расти.

Ссылка на комментарий
Поделиться на другие сайты

А эти формулы, которые я использую неправильные? Это я взял с сайта http://www.marstu.mari.ru, конкретно со странички http://www.marstu.mari.ru:8101/mmlab/home/...ion4/index.html там правда в матричном виде, но я уже преобразовал. Если можете, подскажите пожалуйста эти формулы, т.к. под рукой по геометрии ничего нет, один матем анализ блин!

Насчет второго замечания: у меня как делается: вычисляем новые точки, преобразуем в двумерные, строим куб, на основе вычисленных новых точек вычисляем опять новые точки, опять строим куб, когда угол накопился до 6,28 восстанавливаем исходные значения точек.

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

Ссылка на комментарий
Поделиться на другие сайты

Я думаю может сделать это так: наращивать угол, потом по этому углу каждый раз вычислять на основе исходных координат координаты для построения. Так будет правильно?
Будет правильно. Кроме того, делать, как было раньше, "когда угол вращения накапливается до 6,24, координаты опять задаются исходные", не слишком-то хорошо, во-первых, 6,24 - это не два Pi, во-вторых, сумма шагов может при подходе к 360° проскакивать их, например, если задать шаг 7°, то после 357° должно быть сразу 364°, то есть в принципе так делать нельзя, будут опять же набираться ошибки. Можно спокойно продолжать увеличивать углы, функции вычисления синусов и косинусов отлично работают и для углов, больших 2 Pi.

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

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

P.S. Кстати, красиво было бы после того, как остальное будет сделано, раскрасить ребра в разные цвета.

Изменено пользователем Тролль
Ссылка на комментарий
Поделиться на другие сайты

Сделал вращение по любезно предоставленным мне Троллем формулам (за что тебе отдельное спасибо!). Теперь куб нормально вращается вокруг всех трех осей.

Пробовал сделать вращение без закраски и удаления ненужных ребер - все отлично!

Теперь мне надо сделать так чтобы стирались лишние ребра и грани.

Как это предполагается делать: ищем "заднюю" точку и не строим те грани, которые содержат эту точку. На рисунке указана та самая задняя точка.

Так как куб строится процедурой FillPoly, то не рисовать грани довольно просто, пропускать соответствующий массив с координатами проекций (можно goto заюзать).

У меня это не получается, т.е. вращается кусок куба, также показанный на рисунке.

По указанию Тролль подозрение пало на процедуру вычисления этой самой задней точки. Процедура была протестирована ручной прокруткой (F7) и ничего подозрительного не было замечено - вроде вычисляет правильно точку.

Прилагается сама процедура для ваших зорких глаз, мож кто и увидит ошибку.


Procedure z_t(const ver:koordver3;var min:integer); //ver-трехмерные координаты вершин куба (они меняются) min - номер задней точки

var j,minx,miny,minz,num:integer;

mas:array[1..4] of integer;

begin

minz:=ver[1][3]; num:=1; // запоминаем координату z первой точки.

for j:=2 to 8 do

if ver[j][3]>minz then minz:=ver[j][3]; // ищем максимальное значение z (т.к. координатные оси расположены см. рис)

for j:=1 to 8 do

if ver[j][3]=minz then begin mas[num]:=j;num:=num+1;end; // заносим в массив mas номера точек с минимальным z (их может быть не более 4)

miny:=ver[mas[1]][2];

for j:=2 to num-1 do // среди них ищем точку с минимальным у

if ver[mas[j]][2]<miny then miny:=ver[mas[j]][2];

minx:=ver[mas[1]][1];

for j:=2 to num-1 do // среди них же ищем точку с минимальным х

if ver[mas[j]][1]<minx then minx:=ver[mas[j]][1];

for j:=1 to 8 do // просматриваем все вершины и ищем вершину у которой минимальные значения х у z

if (ver[j][1]=minx)and(ver[j][2]=miny)and(ver[j][3]=minz) then min:=j;

end;

[\code]

Сразу звиняюсь - использовал комментарии в стиле Си, ну просто привыно так, не бейте, ок?

В чем может быть быть дело? Перед каждым построением эта процедура юзается!

__________.JPG

post-34963-1195137093_thumb.jpg

Ссылка на комментарий
Поделиться на другие сайты

Мне навскидку кажется, что кое-где есть небольшие ошибки, например, я не понял, почему задние точки перебираются только до num-1, но я вообще не вижу смысла во всей этой работе по выбору ближайшей к началу координат задней точки и соответственно ее проверке. При наличии нескольких одинаково удаленных от плоскости XY задних точек нам для рисования достаточно знать одну любую из них, даже хватит знания ее координаты по z, обозначим ее zmax.

zmax:=0; for j:=1 to 8 do if ver[j][3]>zmax then zmax:=ver[j][3];

Это вместо всей процедуры. Координата по z задней точки - zmax. Задних точек может быть, как ты заметил, до 4-х, но нам достаточно знать координату zmax любой из них, zmax у всех задних точек одинакова.

На твоем рисунке ось z идет косо. Так рисуют, чтобы показать глубину объекта, как бы находясь от него сбоку. Но зачем нам рассчитывать вид на куб из точки сбоку от него? Все равно он крутится. Кто просил рисовать аксонометрию, то есть косую координатную систему? У нас техническое черчение, вид спереди. На твоем чертеже не одна задняя точка, как это показано, а четыре, абсолютно равноправные, и выбирать из них одну, как это ты делаешь на рисунке и в процедуре, бессмысленно. На рисунке - аксонометрия, но на экране нам нужен только вид спереди.

Если у нас четыре точки находятся сзади на одинаковом расстоянии от плоскости XY, как это на твоем рисунке, это значит, что все боковые стороны куба и его четыре ребра сзади скрыты ребрами передней поверхности куба, мы видим квадрат. Художник, конечно, учел бы еще перспективу ("а рельсы-то, как водится, у горизонта сходятся..."), но мы - не художники, а конструкторы, у нас линии к горизонту не сходятся.

Если мы чертим куб из ребер, без закраски граней, то при рисовании ребер нам надо проверять, не является ли одной из вершин, которые соединяет ребро, точка с координатой zmax, этого достаточно. Ребро, которое нельзя рисовать, обязательно содержит такую точку. Точно так же при закраске граней нам надо проверять, не входит ли в число вершин закрашиваемой грани точка с координатой zmax. Грань, которую нельзя закрашивать, обязательно содержит такую точку.

Доказательство приводить не буду, достаточно повертеть перед глазами кубик, хотя бы мысленно.

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

P.S. Программирование и кодирование - вещи разные. Программирование - разработка алгоритма, кодирование - его запись. Даже не ошибка, а только небольшая непродуманность алгоритма оборачивается часто лишними страницами кода, о том, сколько в этих страницах наберется лишних ошибок и работы по их вылавливанию, я уже и не говорю :) .

Изменено пользователем Тролль
Ссылка на комментарий
Поделиться на другие сайты

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

x=xt+zt/2 y=yt-zt/2 где х и у - двумерные координаты, а хt yt zt - трехмерные координаты, т.е. на экране у меня строится аксонометрическая проекция. Из твоего предыдущего сообщения у меня возникает впечатление, что я это НЕправильно. Нужно строить просто проекцию на фронтальную плоскость?

Но как тогда сделать статический куб, который бы не вращался, но видно было бы что он куб, а не квадрат! Ну к примеру при нажатии кнопки Enter он начинает крутиться.

Ссылка на комментарий
Поделиться на другие сайты

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

В отношении

Но как тогда сделать статический куб, который бы не вращался, но видно было бы что он куб, а не квадрат! Ну к примеру при нажатии кнопки Enter он начинает крутиться.
- так пусть он слегка повернется хотя бы по двум осям еще до нажатия клавиши Enter. Задать в начале программы простейшие наглядные значения координат, когда стороны куба ориентированы вдоль осей, а потом слегка повернуть его подпрограммой поворота и остановиться. А потом при нажатии клавиши пусть он крутится дальше в цикле вызова этой подпрограммы.
Ссылка на комментарий
Поделиться на другие сайты

Тролль, спасибо тебе огромное, теперь все понятно. От аксонометрич. проекции я отказался!

Программа написана!

Ссылка на комментарий
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...