Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.08.01;
Скачать: CL | DM;

Вниз

3D колизии   Найти похожие ветки 

 
Goorus   (2004-04-13 16:36) [0]

ПОМОГИТЕ! :( Я уже два года бьюсь над одной, казалось бы элементарной задачей: проверка на столкновения/препятствия/колизии (называйте как хотите) в 3D. Поисковики не предлагать - пробывал, и не раз, так ничего и не нашёл :(

Вроде бы всё элементарно: сначала ищем пересечение линии пути с треугольниками( procedure Naskvoz ), а потом - близость к тем же треугольникам (function Blizko - по сути движени по нормали к поверхности), но при совпадении каких-то (неизвестных мне) условий, всё это оказывается бесполезным :(

Вот процедура из движка, которая должна не давать камере нарушать законы физики(в качестве параметров передаются изменение координат по X, Y, Z):


const

_X=0;
_Y=1;
_Z=2;

type

 TgFrac=Single; { Что бы можно было быстро сменить тип (повысить проиводительность или точность) }

TMap3D=record
 tr:TTriangleArr;
 n :array of Integer; // номер нормали в массиве
end;

 TVector=array[0..2]of TgFrac;
 TTriangle=Array[0..2]of TVector;

procedure TPhysGame3D.Camera_CheckOnCollision(const dx, dy, dz: TgFrac);
var    col_d,  dist:TgFrac;
col_n, ctr,       k:Integer;
   col_p, vn1, vn2:TVector;
vs, vf, vd, cp, vn:TVector;

procedure Naskvoz;
var i, c:Integer;
begin
 k:=0;
 repeat
  col_n:=-1;   col_d:=Camera_Size;
  // ищем ближайшее пересечение со стеной
  for i:=0 to High(map.tr) do begin
   if Camera_RayLineTriangle(vs, vd, map.tr[i],
      Normals[ map.n[i] ], dist, cp) then
   if dist<col_d then begin
    col_d:=dist;
    col_n:=i;
    col_p:=cp;
   end;
  end;
  // отталкиваем
  if col_n>=0 then begin
   Inc(k);
   if k>ctr then begin
    vf:=vs;
    vd:=Vector(0, 0, 0);
    col_n:=-100;
   end else begin
    vn:=Normals[ map.n[col_n] ];
    for c:=_X to _Z do begin
     if(col_p[c]>vs[c])
     then vf[c]:=col_p[c]-Abs(vn[c])*Camera_Size
     else vf[c]:=col_p[c]+Abs(vn[c])*Camera_Size;
    end;
    Vector_Minus(vf, vs, vd);
    k:=ctr+1;
   end;
  end;
 until(col_n<0);
end;

function Blizko:Boolean;
var i, c:Integer;
begin
 Result:=False;
 k:=0;
 repeat
  col_n:=-1;   col_d:=Camera_Size;
  // ищем ближайшее пересечение со стеной
  for i:=0 to High(map.tr) do begin
   vn1:=Vector_Scale(Normals[ map.n[i] ], +Camera_Size);
   vn2:=Vector_Scale(Normals[ map.n[i] ], -Camera_Size);
   if Camera_RayLineTriangle(vf, vn1, map.tr[i],
      Normals[ map.n[i] ], dist, cp) then
   begin
    if dist<col_d then begin
     col_d:=dist;
     col_n:=i;
     col_p:=cp;
    end;
   end else
   if Camera_RayLineTriangle(vf, vn2, map.tr[i],
      Normals[ map.n[i] ], dist, cp) then
   begin
    if dist<col_d then begin
     col_d:=dist;
     col_n:=i;
     col_p:=cp;
    end;
   end;
  end; // for i:=
  // отталкиваем
  if col_n>=0 then begin
   Result:=True;
   Inc(k);
   if(k>3)then begin
    vf:=vs;
    vd:=Vector(0, 0, 0);
    col_n:=-100;
   end else begin
    vn:=Normals[ map.n[col_n] ];
    for c:=_X to _Z do begin
     if(col_p[c]>vs[c])
     then vf[c]:=col_p[c]-Abs(vn[c])*Camera_Size
     else vf[c]:=col_p[c]+Abs(vn[c])*Camera_Size;
    end;
    Vector_Minus(vf, vs, vd);
   end;
  end;
 until(col_n<0);
end;

begin
ctr:=Length(map.tr);
if ctr<1 then Exit;
if ctr<>Length(map.n) then Exit;
if Length(normals)<1 then Exit;
vs:=Vector(Camera.X, Camera.Y, Camera.Z);
vd:=Vector(dx, dy, dz);
Vector_Plus(vs, vd, vf);

repeat
 // прохождение сквозь препятствия
 Naskvoz;
until Blizko=False;// близость к стене

Naskvoz; // для верности

Camera.X:=vf[_X];
Camera.Y:=vf[_Y];
Camera.Z:=vf[_Z];
end;

// эта процедура проверяет пересечение линии и шара

function TPhysGame3D.Camera_RayLineTriangle(const vStart, vMove: TVector;
 const tr: TTriangle; const Normal: TVector; var dist: TgFrac;
 var CollisionPoint: TVector): Boolean;

var t, u, v, det, invDet : Single;
v1, v2, qvec, tvec, pvec : TVector;
begin
Vector_Minus(tr[1], tr[0], v1);
Vector_Minus(tr[2], tr[0], v2);
Vector_Normal(vMove, v2, pvec);
det:=Vector_DotProduct(v1, pvec);
if((-EPSILON2<det)and(det<EPSILON2))then begin
 // линия параллельна плоскости треугольника
 Result:=False;
 Exit;
end;
invDet:=1/det;
Vector_Minus(vStart, tr[0], tvec);
u:=Vector_DotProduct(tvec, pvec)*invDet;
if (u<0)or(u>1) then Result:=False
else begin
 Vector_Normal(tvec, v1, qvec);
 v:=Vector_DotProduct(vMove, qvec)/det;
 Result:=(v>=0) and (u+v<=1);
 if Result then begin
  t:=Vector_DotProduct(v2, qvec)/det;
  if t>0 then begin
   Vector_Combine(vStart, vMove, 1, t, CollisionPoint);
   Vector_Minus(vStart, CollisionPoint, v1);
   dist:=Vector_Length(v1);
  end else Result:=False;
 end;
end;
end;



Если что не понятно - спрашивайте, только помогите.


 
Мараканец ©   (2004-04-13 16:46) [1]

вобщем так, что тебя не устраивает? объекты проваливаются друг в друга?


 
Мараканец ©   (2004-04-13 16:52) [2]

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


 
miek ©   (2004-04-13 20:14) [3]

>Я уже два года бьюсь над одной, казалось бы элементарной задачей: проверка на столкновения/препятствия/колизии (называйте как хотите) в 3D

И еще столько же будешь биться. Задача не из простых.


 
Goorus   (2004-04-14 03:18) [4]

Сцена простая - куб, каждая грань которого - отдельный кубик(точнее параллелепипед).

Вообще процедура работает, но при небольшом тормозе (DeltaTime=100, на большее стоит ограничение) камера проходит через углы комнаты :(.

P.S. RayLinrTriangle - пересечени линии и треугольника(обшибся).


 
Мараканец ©   (2004-04-14 08:19) [5]

т.е. сцена у тебя расположена внутри куба? или ты хочешь чтоб камера не пролетала в куб?

мне чесно говоря лень разбираться в твоем коде....
и еще это что у тебя за Если DeltaTime = 100 - это медленно то скока у тебя стоит реально DeltaTime ?

{X(t); X(t+DeltaTime)} - вот кстати этот отрезок и нужно проверять на пересечение с треугольником.

кароче, пиши на мыло или ломись в аську я те возможно объясню что к чему, тут еще много вопросов может попутно возникнуть так что вот:

100065267
yarik@ross.usinsk.ru


 
Goorus   (2004-04-16 12:23) [6]

Ярик, не могу тебе письмо отправить, говрит нет пользователя с таким именем. Зарегись где-нибудь на mail.ru, а?


 
Goorus   (2004-04-17 11:12) [7]

Мараканец? Сервер почты выплюнул письмо назад и сказал, что у них такик нет. Проверь.



Страницы: 1 вся ветка

Текущий архив: 2004.08.01;
Скачать: CL | DM;

Наверх




Память: 0.49 MB
Время: 0.038 c
9-1081859786
Goorus
2004-04-13 16:36
2004.08.01
3D колизии


3-1089352878
Jiny
2004-07-09 10:01
2004.08.01
Как на SQL подрубиться с одной базы в другую


3-1089140159
Zhekson
2004-07-06 22:55
2004.08.01
Фильтрация по полю второстепенной таблицы.


1-1090097687
Arm79
2004-07-18 00:54
2004.08.01
Как сохранить строку в св-ве Objects типа TStringList?


14-1089982428
Рамиль
2004-07-16 16:53
2004.08.01
Кто нибудь додумался до такого использования компа?