This is an old revision of the document!


Laboratorul 2

Ray casting

Ray casting reprezintă implementarea modelului teoretic de redare directă.

Figura 1

Concepte teoretice

Pașii algoritmului

Pentru fiecare rază (pixel):

  1. Calculează direcția razei care pleacă de la observator și trece prin centrul pixelului
  2. Calculează pozițiile de eșantionare de-a lungul razei
  3. Calculează valorile eșantioanelor prin interpolare triliniară
  4. Calculează gradientul în fiecare poziție de eșantionare, prin interpolare triliniară
  5. Determină o culoare și o opacitate pentru fiecare eșantion, folosind funcții de transfer și calcule de iluminare
  6. Acumulează culoarea (și opacitatea) în fiecare punct de eșantionare

Implementare

  • Volumul încadrator al volumului de date, în spațiul obiect, este un cub cu coordonatele vârfurilor în intervalul (0,0,0) - (1,1,1)
  • Astfel, coordonatele textură asociate vârfurilor cubului sunt chiar coordonatele vârfurilor
  • Asociem vârfurilor culorile (R,G,B) corespunzătoare coordonatelor vârfurilor, si rasterizăm fețele cubului
Mesh* lab2::createCube(const char* name)
{
    vector<VertexFormat> vertices
    {
        VertexFormat(glm::vec3(0, 0, 0), glm::vec3(0, 0, 0)),
        VertexFormat(glm::vec3(0, 0, 1), glm::vec3(0, 0, 1)),
        VertexFormat(glm::vec3(0, 1, 0), glm::vec3(0, 1, 0)),
        ...
    }
}
  • Atunci culorile punctelor reprezintă chiar coordonatele lor. În Figura 2.stânga se văd fețele față ale cubului și în dreapta, fețele spate:
    • punctele de pe fețele față sunt punctele în care razele intră în volum
    • punctele de pe fețele spate sunt punctele în care razele ies din volum

Figura 2

Etapa 1

Determinarea punctelor de ieșire din volum ale razelor

  • Se desenează într-un framebuffer (nu în cel default)
    frameBuffer->Bind(); 
  • Se rasterizează fețele din spate ale cubului încadrator
    glEnable(GL_CULL_FACE);
    glCullFace(GL_FRONT);
    RenderMesh(meshes["cube"], shaders["BackFaceShader"], model_matrix);
    glDisable(GL_CULL_FACE);
  • Fiecare pixel al acestei imagini conține adresa (salvată prin culoare) punctului de ieșire din volum al razei care trece prin acel pixel.

Etapa 2

Determinarea punctelor de ieșire din volum ale razelor

  • Se desenează în buffer-ul default
    FrameBuffer::BindDefault();
  • Se rasterizează fețele din față ale cubului încadrator (fie prin enable la back-face culling, fie fără niciun fel de culling)
  • Fiecare pixel al imaginii obținute reprezintă adresa punctului de intrare

Calculul culorilor razelor (Ray Casting)

  • Se trimite către fragment shader textura 3D care conține volumul de date:
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_3D, volumeTexture);
    glUniform1i(glGetUniformLocation(shader->program, "VolumeTex"), 1);
  • Se trimite către fragment shader textura 1D care conține funcția de transfer:
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_1D, tfTexture);
    glUniform1i(glGetUniformLocation(shader->program, "TransferFunc"), 2);
  • Se calculează direcția razei pixelului curent (diferența între punctul de ieșire și punctul de intrare în volum)
    • Punctul de ieșire se obține din valoarea texelului corespunzător pixelului curent (folosind textura framebuffer-ului din Etapa 1)
      • Textura din Etapa 1 se trimite către shader-ul din Etapa 2
        int textureLoc = shader->GetUniformLocation("ExitPoints");
        glUniform1i(textureLoc, 0);
        frameBuffer->BindTexture(0, GL_TEXTURE0);
      • În vertex shader, coordonatele vârfurilor cubului sunt transformate prin MVP în coordonate NDC, cuprinse între (-1,-1,-1) și (1,1,1)
      • Coordonata în NDC a fiecărui vârf e transmisă către fragment shader ca o coordonată de textură
        ExitPointCoord = gl_Position;
      • ExitPointCoord se folosește în fragment shader pentru accesarea texturii create în prima etapă.
      • pentru indexarea texturii se obțin coordonatecoordonate ExitFragCoord cu valori cuprinse între 0 și 1:
    • Punctul de intrare se obține din culoarea fragmentului curent (în VS):
      EntryPoint = v_color;
  • Se calculează versorul razei, lungimea acesteia și vectorul cu care se înaintează pe rază (de la un punct de eșantionare la altul)
  • Pentru fiecare eșantion (pornind de la punctul de intrare al razei în volum):
    • Se calculează valoarea scalară din volum (folosind textura 3D VolumeTex) și coordonata de textură dată de poziția eșantionului
    • Se calculează o culoare folosind textura 1D TransferFunc și coordonata de textură dată de valoarea scalară anterior obținută
    • Se modulează opacitatea și culoarea
    • Se realizează compunere din față în spate
      colorAcum.rgb += (1.0 - colorAcum.a) * colorSample.rgb;
          	    colorAcum.a += (1.0 - colorAcum.a) * colorSample.a;
    • Se verifică dacă raza curentă a ieșit din volum sau dacă opacitatea acumulată a ajuns la 1

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)
vdvac/lab2.1711369321.txt.gz · Last modified: 2024/03/25 14:22 by anca.morar
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0