OpenGL/Hankalat monikulmiot

OpenGL osaa piirtää vain yksinkertaisia, kuperia monikulmioita. Esimerkiksi 3d-mallia ladatessa saattaa olla tarpeen käsitellä myös monimutkaisempia monikulmioita. GLU-kirjastossa on funktioita, joiden avulla voidaan yksinkertaistaa kuinka monimutkainen monikulmio tahansa kolmioiksi.

Esimerkki muokkaa

Esimerkkiä ei ole vielä testattu, eikä siinä tarkisteta taulukoiden arvoalueita tai joitakin virheitä. Lisäksi olisi hyvä käsitellä combine-operaatio ja pintakuvion koordinaatit.

#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>

/* GLU:n antama piirtotila, jolla seuraavat kolmiot määritellään */
GLenum nykyinen_tila;

/* GLU:n tuottamat nurkkapisteet pinotaan pistepuskuriin */
#define PISTEPUSKURIN_KOKO 256
float pistepuskuri[PISTEPUSKURIN_KOKO];
int pistepuskurin_kirjoituspaa = 0;

/* nurkkapisteiden määrittelyn päätyttyä niistä muodostetaan
 * käytetyn piirtotilan mukaisesti kolmioita kolmiopuskuriin  */
#define KOLMIOPUSKURIN_KOKO 1024
float kolmiopuskuri[KOLMIOPUSKURIN_KOKO];
int kolmiopuskurin_kirjoituspaa = 0;

/* callback-funktiot annetaan GLU:lle, joka kutsuu niitä */
void begin_callback(GLenum piirtotila)
{
    nykyinen_tila = piirtotila;
}

void vertex_callback(double xyz[])
{
    pistepuskuri[pistepuskurin_kirjoituspaa    ] = xyz[0];
    pistepuskuri[pistepuskurin_kirjoituspaa + 1] = xyz[1];
    pistepuskuri[pistepuskurin_kirjoituspaa + 2] = xyz[2];
    pistepuskurin_kirjoituspaa += 3;
}

void end_callback(void)
{
    int i;
    switch (nykyinen_tila) {
    case GL_TRIANGLES:
        for (i = 0; i < pistepuskurin_kirjoituspaa; i++) {
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa] = pistepuskuri[i];
            kolmiopuskurin_kirjoituspaa++;
        }
        break;
    case GL_TRIANGLE_STRIP:
        for (i = 0; i < pistepuskurin_kirjoituspaa - 8; i += 3) {
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa    ] = pistepuskuri[i    ];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 1] = pistepuskuri[i + 1];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 2] = pistepuskuri[i + 2];

            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 3] = pistepuskuri[i + 3];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 4] = pistepuskuri[i + 4];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 5] = pistepuskuri[i + 5];

            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 6] = pistepuskuri[i + 6];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 7] = pistepuskuri[i + 7];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 8] = pistepuskuri[i + 8];
            kolmiopuskurin_kirjoituspaa += 9;
        }
        break;
    case GL_TRIANGLE_FAN:
        for (i = 3; i < pistepuskurin_kirjoituspaa - 5; i += 3) {
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa    ] = pistepuskuri[0];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 1] = pistepuskuri[1];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 2] = pistepuskuri[2];

            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 3] = pistepuskuri[i    ];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 4] = pistepuskuri[i + 1];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 5] = pistepuskuri[i + 2];

            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 6] = pistepuskuri[i + 3];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 7] = pistepuskuri[i + 4];
            kolmiopuskuri[kolmiopuskurin_kirjoituspaa + 8] = pistepuskuri[i + 5];
            kolmiopuskurin_kirjoituspaa += 9;
        }
    default:
        break;
    }
    pistepuskurin_kirjoituspaa = 0;
}

void error_callback(GLenum error_code)
{
    const GLubyte *error_string;

    error_string = gluErrorString(error_code);
}  

GLdouble v1[] = { 0.0,  0.0,  0.0};
GLdouble v2[] = {-1.0, -1.0,  0.0};
GLdouble v3[] = { 0.0,  1.0,  0.0};
GLdouble v4[] = { 1.0, -1.0,  0.0};

int main(int argc, char* argv[])
{
    /* luodaan uusi tesselointiolio */
    GLUtesselator* tess = gluNewTess();

    /* rekisteröidään callback-funktiot GLU:n käytettäväksi */
    gluTessCallback(tess, GLU_TESS_VERTEX, (GLvoid (*) ()) &vertex_callback);
    gluTessCallback(tess, GLU_TESS_BEGIN,  (GLvoid (*) ()) &begin_callback);
    gluTessCallback(tess, GLU_TESS_END,    (GLvoid (*) ()) &end_callback);
    gluTessCallback(tess, GLU_TESS_ERROR,  (GLvoid (*) ()) &error_callback);

    /* tesseloidaan */
    gluTessBeginPolygon(tess, NULL);
      gluTessBeginContour(tess);
        gluTessVertex(tess, v1, (GLvoid*)v1);
        gluTessVertex(tess, v2, (GLvoid*)v2);
        gluTessVertex(tess, v3, (GLvoid*)v3);
        gluTessVertex(tess, v4, (GLvoid*)v4);
      gluTessEndContour(tess);
    gluTessEndPolygon(tess);
  
    /* poistetaan tesselointiolio */
    gluDeleteTess(tess);
    
    /* tulostetaan kolmiot */
    int i;
    for (i = 0; i < kolmiopuskurin_kirjoituspaa; i++) {
       printf("%f ", kolmiopuskuri[i]);
    }
    return 0;
}

Huomautuksia muokkaa

  • GLU:n tesselointifunktiot taipuvat vaikeahkosti yksinkertaiseen kolmiointiin, sillä ne ovat hyvin yleiskäyttöisiä.
  • Usein 3d-mallien monikulmiot muutetaan kolmioiksi Delaunayn kolmioinniksi kutsuttuun muotoon. En tiedä tekeekö GLU niin.