Własny silnik graficzny. Część II: detekcja kolizji.

30.11.2010 - Robert Kraus
TrudnośćTrudnośćTrudnośćTrudność

Część I    Część II    Część III    Część IV   

Czym będziemy się zajmować?

Wyprowadzimy wzory na przecięcie promienia ze sferą i trójkątem. Zaprogramujemy te wzory poznając pułapki jakie czekają na nas z powodu ograniczonej precyzji liczb zmiennoprzecinkowych. Na koniec dowiemy się nieco o tym, co ma największy wpływ na szybkość działania naszego silnika graficznego.

Zaczniemy od kilku definicji

Punkty na trasie przebywanej przez promień

Dowolny punkt $ p $ na trasie jaką pokonuje promień możemy opisać wzorać wzorem:

$$p = origin + aheadDir * t  \hspace{0.5cm} t > 0.$$
Przyjmijmy oznaczenia:
$$origin = (o_x, o_y, o_z)$$
$$aheadDir = (d_x, d_y, d_z).$$

Definicja sfery i trójkąta

Sfera opisana jest przez punkt będący jej środkiem ciężkości, promień oraz wskaźnik na materiał.

1
2
3
4
5
6
7
8
struct sphere {
  typedef const sphere& i;
  vec3 center;   // środek sfery
  float radius;  // promień sfery
  material* mat; // wskaźnik na materiał
 
  // konstruktory
};

Trójkąt naturalnie opisujemy poprzez trzy wierzchołki. Dodatkowo przechowujemy położenie wierzchołków trójkąta w przestrzeni tekstury oraz równanie płaszczyzny, na której leży trójkąt oraz wskaźnik na materiał.

1
2
3
4
5
6
7
8
9
10
11
12
// trójkąt
struct triangle {
  typedef const triangle& i; // input ref
 
  vec3 v1, v2, v3;    // wierzchołki trójkąta
  vec2 uv1, uv2, uv3; // wierzchołki trójkąta w przestrzeni tekstury
  vec3 N;             // wektor normalny do płaszczyzny trójkąta
  float d;            // równanie płaszczyzny: dotProd(N,(x,y,z)) + d = 0
  material* mat;      // wskaźnik na materiał
 
  // konstruktory
};

Przy okazji zobaczmy jak wyznaczać wektory normalne do naszych prymitywów geometrycznych.

Wektor normalny w dowolnym punkcie $ p $ na sferze można łatwo obliczyć odejmując od punktu $ p $ środek sfery. Wektor ten można też taniej znormalizować - wystarczy go podzielić przez promień sfery.

1
2
inline vec3 normal(sphere::i s, vec3::i p)
{  return (p - s.center) / s.radius;  }

Wektor normalny do powierzchni trójkąta mamy zapamiętany w trójkącie, więc go po prostu wyciągamy.

1
2
inline vec3 normal(triangle::i t)
{  return t.N;  } 

Definicja struktury zawierającej informacje o zderzeniu

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
struct hit {
  float t;  // odległość trafienia od źródła promienia
  vec3 ip;  // punkt przecięcia
  vec3 N;   // wektor normalny do powierzchni trafionego obiektu
  vec3 Ex;  // wektor na osi X w przestrzeni rozpiętej na wektorach Ex, N, Ez
  vec3 Ez;  // wektor na osi Z w przestrzeni rozpiętej na wektorach Ex, N, Ez
  vec2 uv;  // współrzędne trafienia w przestrzeni tekstury
  material* mat; // wskaźnik na materiał
  
  hit() : t(undefined) {}
 
  hit(sphere::i S, float t, ray::i r) : t(t) {
    if (t == undefined)  return;
    ip = r.origin + r.aheadDir * t;  // punkt przecięcia
    mat = S.mat;                     // wskaźnik na materiał
    N = normal(S, ip);               // normalna do powierzchni
    if ( ! mat -> hasTextures ) return;
    uv = mapSurfaceToTexture(S, ip); // punkt ip w przestrzeni tekstury
    if ( ! mat -> hasNormalMap ) return;
    Ex = mapTextureToSurface(S, vec2(uv.u + epsilon3, uv.v)) - ip;
    Ex = unitise(Ex);
    Ez = mapTextureToSurface(S, vec2(uv.u, uv.v + epsilon3)) - ip;
    Ez = unitise(Ez);
  }
 
  hit(triangle::i T, float t, ray::i r) : t(t) {
    if (t == undefined) return;
    ip = r.origin + r.aheadDir * t;  // punkt przecięcia
    mat = T.mat;                     // wskaźnik na materiał
    N = normal(T);                   // normalna do powierzchni
    if ( ! mat -> hasTextures ) return;
    uv = mapSurfaceToTexture(T, ip); // punkt ip w przestrzeni tekstury
    if ( ! mat -> hasNormalMap ) return;
    Ex = mapTextureToSurface(T, vec2(uv.u + epsilon3, uv.v)) - ip;
    Ex = unitise(Ex);
    Ez = mapTextureToSurface(T, vec2(uv.u, uv.v + epsilon3)) - ip;
    Ez = unitise(Ez);
  }
};

5
Twoja ocena: Brak Ocena: 5 (2 ocen)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com