Table of Contents

Laboratorul 1

Marching cubes

Algoritmul marching cubes extrage din volum o suprafață 3D formată din triunghiuri.

Figura 1

Concepte teoretice

Voxel

Izosuprafața - suprafața care are aceeași valoare scalară (izovaloare) în toate punctele sale

Izovaloarea - o valoare care are o anumită semnificație în funcție de domeniu. Exemple:

Un vârf al unui voxel poate fi

Figura 2

Exista 15 configurații posibile ale vârfurilor unui voxel față de suprafață Pentru codificarea configurațiilor: 2 tabele de căutare

Tabelele - adresate de un indice pe 8 biți:

Calculul coordonatelor punctelor de intersecție

Figura 3

Calculul normalei intr-un vârf al unui voxel

Figura 4

Implementare

Framework-ul de laborator se poate descărca de aici sau de pe Moodle.

Atribute

  unsigned int xsize, ysize, zsize; // dimensiunile volumului de date
  unsigned char *volumeData; //tablou care conține valorile scalare din volum
  double isolevel;  //izovaloarea izosuprafeței
  TRIANGLE *tri;  //tabloul în care se stochează suprafața triunghiulară  

Metode

Încărcare date din fișier

 bool loadRAWFile(const string& fileLocation, unsigned int xsize, unsigned int ysize, unsigned int zsize); 

Această funcție este deja completată. Se încarcă în volumeData datele dintr-un fișier .raw. Fișierele .raw se găsesc în \assets\volumes\ iar informațiile despre dimensiunea fiecărui volum, în \assets\volumes\readme.txt

Reconstrucție suprafață

 void reconstructSurface(Mesh *mesh) 

Această funcție este completată parțial. Aici se completează informațiile pentru voxelul curent GRIDCELL grid;:

grid.p[0]=glm::vec3(x,y,z)
grid.p[1]=glm::vec3(x+1,y,z)
//A se vedea ordinea vârfurilor în LookupTables.h  !!!
 grid.val[0] = volumeData[z * xsize * ysize + y * xsize + x];
 grid.val[1] = volumeData[z * xsize * ysize + y * xsize + (x+1)];
 grid.n[0] = glm::vec3(volumeData[z * xsize * ysize + y * xsize + (x+1)] - volumeData[z * xsize * ysize + y * xsize + (x-1)],volumeData[z * xsize * ysize + (y+1) * xsize + x] - volumeData[z * xsize * ysize + (y-1) * xsize + x],volumeData[(z+1) * xsize * ysize + y * xsize + x] - volumeData[(z-1) * xsize * ysize + y * xsize + x]);
 grid.n[1] = glm::vec3(volumeData[z * xsize * ysize + y * xsize + (x+2)] - volumeData[z * xsize * ysize + y * xsize + x],volumeData[z * xsize * ysize + (y+1) * xsize + (x+1)] - volumeData[z * xsize * ysize + (y-1) * xsize + (x+1)],volumeData[(z+1) * xsize * ysize + y * xsize + (x+1)] - volumeData[(z-1) * xsize * ysize + y * xsize + (x+1)]);
//Atentie sa nu ieșiti din volum  !!!

Calcul intersecție dintre un voxel și suprafață

 int PolygoniseCube(GRIDCELL g, double iso, TRIANGLE *tri); 

Această funcție este completată parțial. Ea

Interpolare liniară

glm::vec3 VertexInterp(double isolevel, glm::vec3 p1, glm::vec3 p2, double valp1, double valp2); 

Această funcție este deja completată. Se întoarce poziția punctului de intersecție de pe muchia dintre p1 și p2, în funcție de izovaloare (isolevel) și de valorile punctelor p1 și p2.

Cerinte laborator

  1. Să se completeze pozitiile și valorile scalare ale vârfurilor voxelilor din volum, grid.p[] și grid.val[]. Dacă se completează corect, pe ecran va apărea suprafața triunghiulară (cu normale per triunghi)
  2. Să se modifice izovaloarea la apăsarea unor taste (în onInputUpdate()). La modificarea izovalorii, trebuie reapelată funcția reconstructSurface()
  3. Să se calculeze normalele vârfurilor voxelilor din volum, grid.n[] prin diferențe finite (și apoi să se normalizeze)
  4. Să se completeze normallist[] - tabloul cu normalele asociate punctelor de intersecție de pe muchiile voxelului curent (calculate prin interpolare între normalele din vârfurile voxelului)
  5. Să se determine normalele normal1, normal2 și normal3 asociate triunghiului curent care rezultă în urma intersecției dintre izosuprafață și voxel. Să se înlocuiască normala per triunghi cu normalele per vârfurile triunghiului. Dacă se completează corect, pe ecran va apărea suprafața triunghiulară netedă

Demo