Siirry sisältöön

OpenGL/Hankalat monikulmiot

Wikikirjastosta

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ä 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;
}
  • 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.