Zaimplementowałem mechanizm Mesh Materials silnika Physx pozwalający na definicję skomplikowanych obiektów, z którymi kalkulowane będą kolizje.
Mechanizm ten posłużył do detekcji kolizji kostek do rzucania z planszą w grze Backgammon.
Efekt znajduje się na poniższym filmiku.
Rok temu zacząłem tworzyć grę w oparciu o OpenGL. Grą tą był Backgammon, jedna z najstarszych gier świata. Chciałem stworzyć wszystko w 3d i zachować jak największy realizm, co okazało się trudnym zadaniem dla początkującego programisty tego typu aplikacji.
Po kilku miesiącach przerwy zasiadłem do pracy ponownie. Zacząłem bawić się silnikiem Physx firmy NVidia, aby gra była bardziej realna. Jak to bywa, co chwilę napotykam na problemy, z którymi męczę się przez kilka godzin, a rozwiązanie okazuje się banalne 🙂 Poniżej 2 filmiki z etapów tworzenia gry 🙂 To dopiero sam początek, więc za bardzo nie ma czym się zachwycać, ale pokazują one mniej więcej, jak będzie wyglądać gra.
Poniższe filmiki pokazują działanie silnika fizycznego do obsługi kostek. Na razie nie są brane pod uwagę kolizje z planszą, a jedynie pomiędzy kostkami. Kolejnym etapem są kolizje z planszą oraz z pionkami.
Etap 1:
Etap 2:
Nie wiem kiedy powstanie etap 3, ale mam nadzieję, że niedługo…
Na początek taki szkolny przykład dodawanie do siebie dwóch tablic wektorów.
Dodawanie kolejnych par wektorów odbywa się na karcie graficznej. Odpowiada za to funkcja vecAdd z kwalifikatorem global.
Kwalifikator ten oznacza, że funkcja może być wykonywana zarówno jako host (CPU) jak i device (GPU).
Prosty kod odpowiadający za dodawanie 2 wektorów
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
|
#include <stdio.h>
#include <cutil.h>
__global__ void vecAdd (float3 a[10], float3 b[10]) {
int i = threadIdx.x;
a[i].x += b[i].x;
a[i].y += b[i].y;
a[i].z += b[i].z;
}
int main(int argc, char** argv) {
CUT_DEVICE_INIT(argc, argv); // inicjalizacja GPU
float3 *a_h, *b_h, *a_d, *b_d, *result;
int arraySize = 10;
int sizeInBytes = arraySize * sizeof(float3);
a_h = (float3*)malloc(sizeInBytes); // inicjalizacja tablic (na hoscie)
b_h = (float3*)malloc(sizeInBytes);
result = (float3*)malloc(sizeInBytes);
CUDA_SAFE_CALL(cudaMalloc((void**)&a_d, sizeInBytes)); // inicjalizacja tablic na GPU
CUDA_SAFE_CALL(cudaMalloc((void**)&b_d, sizeInBytes));
for(int i = 0; i < arraySize; i++) { // przykładowe dane
a_h[i].x = 100.0f + i;
a_h[i].y = 200.0f + i;
a_h[i].z = 300.0f + i;
b_h[i].x = 50.0f + i;
b_h[i].y = 50.0f + i;
b_h[i].z = 50.0f + i;
CUDA_SAFE_CALL(cudaMemcpy(a_d, a_h, sizeInBytes, cudaMemcpyHostToDevice));
// kopiujemy tablicę z hosta do GPU
CUDA_SAFE_CALL(cudaMemcpy(b_d, b_h, sizeInBytes, cudaMemcpyHostToDevice));
vecAdd<<<1, arraySize>>>(a_d, b_d); // wykonujemy dodawanie
CUDA_SAFE_CALL(cudaMemcpy(result, a_d, sizeInBytes, cudaMemcpyDeviceToHost));
// kopiujemy z powrotem
for(int i = 0; i < arraySize; i++){
printf("Wartość %d.elementu %f, %f, %f \n", i, result[i].x,
result[i].y, result[i].z); // wyswietlamy :)
}
CUT_EXIT(0, NULL); // koniec
}
|
Wydaje się proste :)
W przyszłości postaram się opisać po kolei wszystkie szczegóły.