Перейти к содержимому

Фотография

Кубнужно, чтобы он вращался :rotate:


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 5

#1
RAWMIND

RAWMIND
  • Частый гость
  • 53 сообщений
Простая задачка. :eek: , но вкурить не получается :D

Задача: разработать программу, которая рисует вращающийся куб с разноцветными гранями в проекции Кавалье.
нерешенная проблема: определить, какие грани видимы (т.е. находятся на переднем плане проекции)

что есть: вращающийся куб без закрашивания граней (видны только линии пересечения этих граней).

Нужен алгоритм (или прога на любом языке).

Код на паскале вращающегося куба с видимыми линиями:
uses crt,graph;
const
  S=80; { размер стороны}
  ntck=8; { количество точек}
  nlin=6; { количество граней}
  EYEY=300;	 { расстояние до глаза}
  EYEL=200;	 { расстояние до экрана  }

type
  figura=record
{ Точки }
	tck:array [1..ntck] of record
	  x3,y3,z3:real;	{ Координаты 3D }
	  x2,y2:integer;	{ Координаты 2D }
	end;
{ Грани }
	lin:array [1..nlin] of record
	  a,b,c,d:integer;  { номера точек из tck }
	  cl:integer;	   { цвет }
	end;
  end;
  matr=array [1..4,1..4] of real;	   { тип «матрица»для преобразований }

{ выводим фигуру на экран }
procedure output(var f:figura);
var n:integer;
  t:array [1..5] of pointtype;
  cenX, cenY: integer;
begin
  cenX:= GetMaxX div 2;
  cenY:= GetMaxY div 2;
  SetLineStyle( 2, 0, 1);
  
  for n:=1 to ntck do with f.tck[n] do begin
{ приводим 3D к 2D }
	x2:=trunc(x3*EYEL/(z3-EYEY));
	y2:=trunc(y3*EYEL/(z3-EYEY));
  end;
{ просто закрашиваем старый экран }
  SetFillStyle(SolidFill, black);
  bar( 0,0, GetMaxX, GetMaxY);

  with f do for n:=1 to nlin do begin
	setfillstyle(1,lin[n].cl);
	t[1].x:=cenX+tck[lin[n].a].x2; t[1].y:=cenY-tck[lin[n].a].y2;
	t[2].x:=cenX+tck[lin[n].b].x2; t[2].y:=cenY-tck[lin[n].b].y2;
	t[3].x:=cenX+tck[lin[n].c].x2; t[3].y:=cenY-tck[lin[n].c].y2;
	t[4].x:=cenX+tck[lin[n].d].x2; t[4].y:=cenY-tck[lin[n].d].y2;
	t[5]:=t[1];

	SetColor(lin[n].cl);
	DrawPoly( 5, t);
  end;
end;

{преобразование фигуры в каждом цикле}
procedure prc(var f:figura;m:matr);
var
  nx,ny,nz:real;
  n:integer;
begin
{ просто умножаем каждую точку на матрицу, описываем изменения }
  for n:=1 to ntck do with f.tck[n] do begin
	nx:=m[1,1]*x3+m[1,2]*y3+m[1,3]*z3+m[1,4];
	ny:=m[2,1]*x3+m[2,2]*y3+m[2,3]*z3+m[2,4];
	nz:=m[3,1]*x3+m[3,2]*y3+m[3,3]*z3+m[3,4];
	x3:=nx;y3:=ny;z3:=nz;
  end;
end;

{ процедуры работы с матрицами }

{ создание матрицы смещения}
procedure one(var mm:matr);
var n,m:integer;
begin
  for n:=1 to 4 do for m:=1 to 4 do
	if (n<>m) then mm[n,m]:=0 else mm[n,m]:=1;
end;

{ создаем матрицы вращения любой оси координат }
procedure rot3(var m:matr;a:real;n:integer);
var
  ax1,ax2:integer;
begin
  one(m);
  ax1:=n+1;if ax1=4 then ax1:=1;
  ax2:=ax1+1;if ax2=4 then ax2:=1;
  m[ax1,ax1]:=cos(a);
  m[ax1,ax2]:=-sin(a);
  m[ax2,ax1]:=sin(a);
  m[ax2,ax2]:=cos(a);
end;

{ переменные программы }
var
  drv,mode:integer;	{для Initgraph }
  c:char;			  { считынный с клавиатуры }
  fg:figura;		   { данные фигуры }
  rt:matr;			 { матрица преобразования (вращения) }

begin
  drv:=DETECT;
  mode:=VGAHI;
  initgraph(drv,mode,'..\bgi');
  if (GraphResult=grOk) then begin
{ создаем фигуру }
  with fg do begin
{ создаем точки }
	tck[1].x3:=-S; tck[1].y3:=-S; tck[1].z3:=-S;
	tck[2].x3:=-S; tck[2].y3:=S; tck[2].z3:=-S;
	tck[3].x3:=S; tck[3].y3:=S; tck[3].z3:=-S;
	tck[4].x3:=S; tck[4].y3:=-S; tck[4].z3:=-S;
	tck[5].x3:=-S; tck[5].y3:=-S; tck[5].z3:=S;
	tck[6].x3:=-S; tck[6].y3:=S; tck[6].z3:=S;
	tck[7].x3:=S; tck[7].y3:=S; tck[7].z3:=S;
	tck[8].x3:=S; tck[8].y3:=-S; tck[8].z3:=S;
{ создаем плоскости и цвет }
	with lin[1] do begin a:=1;b:=2;c:=3;d:=4; cl:=red;end;
	with lin[2] do begin a:=1;b:=2;c:=6;d:=5; cl:=yellow;end;
	with lin[3] do begin a:=5;b:=6;c:=7;d:=8; cl:=green;end;
	with lin[4] do begin a:=8;b:=7;c:=3;d:=4; cl:=blue;end;
	with lin[5] do begin a:=1;b:=5;c:=8;d:=4; cl:=white;end;
	with lin[6] do begin a:=2;b:=6;c:=7;d:=3; cl:=magenta;end;

  end;
{ Поворачиваем фигуру, чтобы стояла не вертикально }
  rot3(rt,0.4,1);
  prc(fg,rt);
{ создаем матрицу для вращения вокруг оси Y }
	rot3(rt,0.01,2);
{ предварительно вычисляем плоские координаты}
	repeat
{ ‚выводим картинку }
	  output(fg);
	  delay(2000);	  {ждем некоторое время }
	  prc(fg,rt);	 { Преобразовываем (вращаем) }
	  if (keypressed) then begin
		c:=readkey;
	  end else c:=' ';
	until c=#27;
	closegraph;
  end else begin
	writeln;
	writeln(' Cannot initialize GRAPH');
  end;
end.


Пожалста, понимаю, что решение где-то на поверхности, но не могу понять...

вывод в конце процедуры output:

SetColor(lin[n].cl);
DrawPoly( 5, t);
  • 0

#2
Zulkar

Zulkar

    Читатель

  • В доску свой
  • 3 243 сообщений
Тебе именно нужно самому рисовать 3d? Как я понял, ты хочешь определить какие грани не видимы для того чтобы не рисовать их. Во всех GAPI делается следующим образом - треугольник (в общем случае полигон) рисуется только тогда, когда его вершины обходятся по часовой стрелке. (Поэтому порядок задания вершин очень важен!)

Для треугольника например можно определить каким является обход ABC классическим кодом
function isClockWise (A, B, C: point): boolean;
begin
  isClockWise :=
	((B.x - A.x) * (C.y - A.y)
	-(C.x - A.x) * (B.y - A.y) < 0);
end;

Так что у тебя будет 6 граней -> 12 треугольников. На каждом кадре проверяешь, как обходится треугольник, уже спроецированный на плоскость экрана. Если по часовой - то рисуешь его. Если нет - то не рисуешь. Или наоборот. Только не запутайся когда будешь треугольники создавать. Глядя прямо на каждую грань, когда она перед тобой (а не самая дальная!!) ее треугольники должны обходится против часовой, то есть прорисовываться. Когда куб повернется, то эти треугольники будут обходится против часовой. Идея надеюсь понятна.

Еще есть вариант - создать Z-буффер. То есть каждая точка рендерится только если перед ней ничего нет. Но нафиг.
  • 0

#3
v04bvs

v04bvs
  • В доску свой
  • 2 062 сообщений
Можно для каждой грани помимо координат вершин хранить вектор нормали и рисовать только тогда, когда этот вектор смотрит на камеру.
  • 0

#4
Zulkar

Zulkar

    Читатель

  • В доску свой
  • 3 243 сообщений
v04bvs - можно и так. Фактически это то же самое, что и обход по вершинам.
  • 0

#5
RAWMIND

RAWMIND
  • Частый гость
  • 53 сообщений

создать Z-буффер

боюсь быть казнен за извращения

каким является обход ABC классическим кодом

А вот за это большое спасибо! Правда, в таком случае видимость крышки (т.е. верхней грани) надо реверсировать
visbl:= ((t[2].x - t[1].x) * (t[3].y - t[1].y)
	-(t[3].x - t[1].x) * (t[2].y - t[1].y) < 0) xor (n=5);
	if visbl then
	  FillPoly( 4, t);
здесь t[1]=A;t[2]=B;t[3]=C;

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

У меня было почти так-же (я использовал площадь многоугольника), однако предложенный вами метод гораздо лучше. Спасибо.

И еще вопрос - как сделать, чтобы круг вращался не в изометрической проекции, как это есть, а в проекции Кавалье (военная перспектива)?

В проекции Кавалье (рис. 3.11.) направление проецирования составляет с плоскостью угол 45°. В результате проекция отрезка, перпендикулярного проекционной плоскости, имеет ту же длину, что и сам отрезок, т. е. укорачивание отсутствует.

http://compgraph.ad....projections.htm
  • 0

#6
Visual1

Visual1
  • В доску свой
  • 1 198 сообщений

http://compgraph.ad....projections.htm

Кстати, об учебнике (автор темы, спасибо за интересную ссылку). Сорри за некоторый оффтопик, но все же интересно, почему они в своем учебнике при рассмотрении проблемы принадлежности точки заданному многоугольнику (см. http://compgraph.ad....fillpolygon.htm) рассмотрели только построчное сканирование, как самый простой метод? Если многоугольник не является самопересекающимся, то есть способ еще проще (с достаточной для практики надежностью) определить, находится ли точка внутри произвольного многоугольника, в том числе и невыпуклого.
  • 0


Количество пользователей, читающих эту тему: 1

пользователей: 0, неизвестных прохожих: 1, скрытых пользователей: 0

Размещение рекламы на сайте     Предложения о сотрудничестве     Служба поддержки пользователей

© 2011-2022 vse.kz. При любом использовании материалов Форума ссылка на vse.kz обязательна.