10.04.2009, 20:22 | #1 |
Участник
Регистрация: 28.05.2008
Сообщений: 81
ICQ: 224116 Репутация: 100
|
[delphi] Простейший 3d двиг средствами delphi. Тор.
Простейший 3d двиг средствами delphi. Тор
Итак, господа, что мы сегодня будем делать? Мы попытаемся реализовать свой простой 3d движок и на радостях построить такой замечательный объект как тор (в простонародии бублик). Готовый проект и немного extra примеров ищи на http://parsers.info/pub/3d Будем работать без перспективы, чисто черчение, мы не художники. Перспективу, впрочем, потом несложно добавить - всего-то рассчитать расстояние до точки и домножить на коэффициент. [[часть 1]] [средства] Мы будем использовать компонент TImage и массив Pixels в Canvas. И больше ничего, никаких компонентов ; ) [приготовления #1] Напишем вспомогательные функции, которые будут нам давать центр изображения. Нам он не раз понадобится, и это более чем удобно. Код:
function cx(im:TImage):integer; begin result:=im.ClientWidth div 2; end; function cy(im:TImage):integer; begin result:=im.ClientHeight div 2; end; Введем некоторые понятия для облегчения наших действий: оригинал - точка в пространстве, в котором мы будем представлять наш объект, проекция - точка на поверхности картинки. Чуть позже напишем функции для преобразования оригинала в проекцию и отображения. [типы] Какие типы нам понадобятся? Для начала точка в пространстве: Код:
type TOriginal=record x:real; y:real; z:real; end; Для проекции используем уже существующий тип TPoint с целочисленными значениями x и y. При преобразовании и будет происходить округление. Вспомним, что мы собираемся рисовать в изометрии, но их же много! Мы будем использовать прямоугольную изометрию(гуглим), но сделаем всё по уму, чтобы мы всегда могли поменять изометрию на диметрию, проекцию на проецирующую плоскость и т.д. Вводим следующий тип: Код:
type TAxonometry=record xkx:real; xky:real; ykx:real; yky:real; zkx:real; zky:real; end; [константы] И константочка для изометрии: Код:
const Izometry:TAxonometry=(xkx:-0.866{cos(pi/6)}; xky:0.5{sin(pi/6)}; ykx:0.866{-cos(pi/6)}; yky:0.5{sin(pi/6)}; zkx:0; zky:-1;); В комментариях указаны формулы, приближенные значения которых мы видим, их достаточно легко получить. Кстати, это очень прикольный способ задания констант типа record. [приготовления #2] По горячим следам напишем функцию для преобразования оригинала: Код:
function Original2Point(v:TOriginal;ax:TAxonometry;im:TImage):TPoint; var p:TPoint; begin with ax do p.X:=Round(cx(im)+xkx*v.x+ykx*v.y+zkx*v.z); with ax do p.Y:=Round(cy(im)+xky*v.x+yky*v.y+zky*v.z); Result:=p; end; И рисовальня: Код:
procedure OriginalDraw(v:TOriginal;ax:TAxonometry;c:TColor;im:TImage); var p:TPoint; begin p:=Original2Point(v,ax,im); im.Canvas.Pixels[p.X,p.Y]:=c; end; Функции, аналогичные MoveTo и LineTo: Код:
procedure OriginalMoveTo(v:TOriginal;ax:TAxonometry;im:TImage); var p:TPoint; begin p:=Original2Point(v,ax,im); im.Canvas.MoveTo(p.X,p.Y); end; procedure OriginalLineTo(v:TOriginal;ax:TAxonometry;c:TColor;im:TImage); var p:TPoint; begin p:=Original2Point(v,ax,im); im.Canvas.Pen.Color:=c; im.Canvas.LineTo(p.X,p.Y); end; [подитог] Ну что, чувачки? Ожидали чего-то посложней? Простое домножение на коэффициент и у нас есть простейший 3d двиг. Надо сходить поесть и займемся тором. Напоминаю, что в оригинале эта статья опубликована на http://parsers.info [[часть 2]] [матчасть] Строить тор будем основываясь на параметрических уравнениях: <i>x(i,k) = (R + r cos i) cos k y(i,k) = (R + r cos i) sin k z(i,k) = r sin i где пераметры i,k варьируются от 0 до 2pi</i> Из констант нам надо объявить шаги параметров для циклов рисования горизонально и вертикально расположенных окружностей, мы их будем рисовать отдельно. Шаг для вертикальных окружностей должен быть больше, для ощущения равномерности. [пишем процедуру] 1) Начальный этап. Объявим локальные переменные и константы. Код:
procedure DrawTor(r1,r2:real;ax:TAxonometry;c:TColor;im:TImage); var i,k:integer; ir,kr:real; curr:TOriginal; const steph:real=28.8; stepv:real=3.6; begin 2) Рисуем горизонтальные окружности. Код:
for i:=0 to Round(360/steph) do begin ir:=DegToRad(i * steph); curr.x:=(r1 + r2 * cos(ir)) * cos(0); curr.y:=(r1 + r2 * cos(ir)) * sin(0); curr.z:=r2 * sin(ir); OriginalMoveTo(curr,ax,im); for k:=0 to 360 do begin kr:=DegToRad(k); curr.x:=(r1 + r2 * cos(ir)) * cos(kr); curr.y:=(r1 + r2 * cos(ir)) * sin(kr); curr.z:=r2 * sin(ir); OriginalLineTo(curr,ax,c,im); end; // for end; // for 3) Дорисовываем вертикальные окружности. Код:
for i:=0 to Round(360/stepv) do begin ir:=DegToRad(i * stepv); curr.x:=(r1 + r2 * cos(0)) * cos(ir); curr.y:=(r1 + r2 * cos(0)) * sin(ir); curr.z:=r2 * sin(0); OriginalMoveTo(curr,ax,im); for k:=0 to 360 do begin kr:=DegToRad(k); curr.x:=(r1 + r2 * cos(kr)) * cos(ir); curr.y:=(r1 + r2 * cos(kr)) * sin(ir); curr.z:=r2 * sin(kr); OriginalLineTo(curr,ax,c,im); end; // for end; // for 4) Финал. На форму ставим компонент TImage, свойство Align ставим alClient, чтобы занимало всё пространство. На событие создания формы пишем: Код:
DrawTor(200,40,Izometry,clRed,imgOut); [вывод] В результате наших изысканий мы написали простейшие функции преобразования координат и, используя параметрические уравнения, нарисовали тор. Это всего лишь образец того, что можно сделать (c) crystalbit, http://parsers.info, 10.04.2009 допускается копирование при сохранении копирайта
__________________
Мой скромный delphi блог |