[Tutorial] III.7 - Las dos caras del polígono, triángulos STRIP y FAN

Ver el tema anterior Ver el tema siguiente Ir abajo

[Tutorial] III.7 - Las dos caras del polígono, triángulos STRIP y FAN

Mensaje  HarZe el Vie Jul 31, 2009 6:59 pm

III.7 Las dos caras del polígono, triángulos STRIP y FAN
Novedades:
  • Uso de GL_TRIANGLE_STRIP en glBegin()
  • Uso de GL_TRIANGLE_FAN en glBegin()
  • Uso de GL_CULL_FACE en glEnable()
  • glFrontFace()
  • glPolygonMode()
  • glShadeModel()


En realidad, no hay demasiado añadido respecto al código de la lección anterior, pero para no agobiar, lo añadimos ahora. Son pocas pocas, pero influyen mucho. Hay dos caras para todo polígono, delantera y trasera, hasta ahora, por defecto, se pintan ambas, pero podemos definir que solo se pinta una cara (suponiendo que la otra nunca va a ser vista) y ahorrar cálculos. Aquí el código, esta vez es mejor que no lo pruebes hasta leer toda la explicación.
Código:
#include <GL/glut.h>

typedef struct {
  GLfloat verticeXYZ[3];
  GLfloat colorRGB[3];
} Vertice;

typedef struct {
  float x,y;
  int izda, dcha;
} EstadoRaton;

Vertice cuadrado[4] = {
  {{1,0,0},{1,0,0}},
  {{5,-4,0},{1,1,0}},
  {{9,0,0},{0,1,0}},
  {{5,4,0},{0,0,1}}
};
Vertice triangulo[3] = {
  {{-9,4,0},{1,0,0}},
  {{-5,-4,0},{0,1,0}},
  {{-1,4,0},{0,0,1}}
};
/* El triángulo sigue el sentido CCW, contra el sentido del reloj:
*    0-------2
*    \    /
*      \  /
*      1
*/
Vertice selector = {{-9,4,0},{1,1,1}};
EstadoRaton raton;
int ventana[2], vertice_sel;
GLfloat formato_global;
int cull, sentido, linear;

void IniciarGLUT() {
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(600,600);
  glutInitWindowPosition(100,100);
  glutCreateWindow("Practica III,7 de OpenGL");
}

void PintarEscena() {
  glMatrixMode(GL_MODELVIEW);
  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();
 
  if (cull) glEnable(GL_CULL_FACE);
  else glDisable(GL_CULL_FACE);
  if (sentido) glFrontFace(GL_CW);
  else glFrontFace(GL_CCW);
  if (linear) glPolygonMode(GL_BACK,GL_LINE);
  else glPolygonMode(GL_BACK,GL_FILL);
 
  glShadeModel(GL_FLAT);
  glBegin(GL_TRIANGLE_STRIP);
      glColor3f(1,0,0);
      glVertex3i(-9,9,0);
      glVertex3i(-8,8,0);
      glVertex3i(-7,9,0);
      glColor3f(0,1,0);
      glVertex3i(-6,8,0);
      glColor3f(0,0,1);
      glVertex3i(-5,9,0);
  glEnd();
 
  glBegin(GL_TRIANGLE_FAN);
      glColor3f(1,0,0);
      glVertex3i(8,8,0);
      glVertex3i(6,8,0);
      glVertex3i(7,9,0);
      glColor3f(0,1,0);
      glVertex3i(9,9,0);
      glColor3f(0,0,1);
      glVertex3i(10,8,0);
  glEnd();
 
  glShadeModel(GL_SMOOTH);
  int i;
  glBegin(GL_TRIANGLES);
      for (i=0; i<3; i++) {
        glColor3fv(triangulo[i].colorRGB);
        glVertex3fv(triangulo[i].verticeXYZ);
      }
  glEnd();
 
  glBegin(GL_QUADS);
        for (i=0; i<4; i++) {
        glColor3fv(cuadrado[i].colorRGB);
        glVertex3fv(cuadrado[i].verticeXYZ);
      }
  glEnd();
 
  glPointSize(7);
  glBegin(GL_POINTS);
      glColor3fv(selector.colorRGB);
      glVertex3fv(selector.verticeXYZ);
  glEnd();
 
  glutSwapBuffers();
}

void ReProyectar(int w, int h) {
  GLfloat formato;

  ventana[0] = w;
  ventana[1] = h;
 
  if(h == 0) h = 1;
   
    glViewport(0, 0, w, h);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  formato = (GLfloat)w / (GLfloat)h;
  formato_global = formato;
    if (w <= h) glOrtho (-10.0f, 10.0f, -10.0f / formato, 10.0f / formato, -1.0f, 1.0f);
    else glOrtho (-10.0f * formato, 10.0f * formato, -10.0f, 10.0f, -1.0f, 1.0f);
}

float ObtenerPosPlanoX(float x, int ancho_ventana, int alto_ventana, float pos_x_min, float pos_x_max, float format) {
  float pos_x_relativa = ((float)x/ancho_ventana); //La posición relativa de 0 a 1 en X
  float pos_plano;
 
  if (ancho_ventana<=alto_ventana) pos_plano = (pos_x_min+((pos_x_max-pos_x_min)*pos_x_relativa));
  else pos_plano = ((pos_x_min * format)+(((pos_x_max-pos_x_min) * format)*pos_x_relativa));
 
  return pos_plano;
}

float ObtenerPosPlanoY(float y, int ancho_ventana, int alto_ventana, float pos_y_min, float pos_y_max, float format) {
  float pos_y_relativa = ((float)y/alto_ventana); //La posición relativa de 0 a 1 en Y
  float pos_plano;
 
  if (ancho_ventana<=alto_ventana) pos_plano = -((pos_y_min / format)+(((pos_y_max-pos_y_min) / format)*pos_y_relativa));
  else pos_plano = -(pos_y_min+((pos_y_max-pos_y_min)*pos_y_relativa));
 
  return pos_plano;
}

void ControlRaton(int button, int state, int x, int y) {
  if (button==GLUT_LEFT_BUTTON) {
      if (state==GLUT_DOWN) raton.izda = 1;
      else raton.izda = 0;
  }
  else if (button==GLUT_RIGHT_BUTTON) {
      if (state==GLUT_DOWN) {
            raton.dcha = 1;
       
        raton.x = ObtenerPosPlanoX(x,ventana[0],ventana[1],-10,10,formato_global);
        raton.y = ObtenerPosPlanoY(y,ventana[0],ventana[1],-10,10,formato_global);
 
        int i;
        for (i=0; i<3; i++) {
            if (raton.x > triangulo[i].verticeXYZ[0] - 0.5f &&
              raton.x < triangulo[i].verticeXYZ[0] + 0.5f &&
              raton.y > triangulo[i].verticeXYZ[1] - 0.5f &&
              raton.y < triangulo[i].verticeXYZ[1] + 0.5f ) {
              vertice_sel = i;
            }
        }
        for (i=0; i<4; i++) {
            if (raton.x > cuadrado[i].verticeXYZ[0] - 0.5f &&
              raton.x < cuadrado[i].verticeXYZ[0] + 0.5f &&
              raton.y > cuadrado[i].verticeXYZ[1] - 0.5f &&
              raton.y < cuadrado[i].verticeXYZ[1] + 0.5f ) {
              vertice_sel = 3 + i;
            }
        }
        }
      else raton.dcha = 0;
  }
}

void MovimRaton(int x, int y) {
  raton.x = ObtenerPosPlanoX(x,ventana[0],ventana[1],-10,10,formato_global);
  raton.y = ObtenerPosPlanoY(y,ventana[0],ventana[1],-10,10,formato_global);
}



void MoverVertice(int value) {
  switch (vertice_sel) {
      case 0: case 1: case 2:
        selector.verticeXYZ[0] = triangulo[vertice_sel].verticeXYZ[0];
        selector.verticeXYZ[1] = triangulo[vertice_sel].verticeXYZ[1];
      break;
      case 3: case 4: case 5: case 6:
        selector.verticeXYZ[0] = cuadrado[vertice_sel-3].verticeXYZ[0];
        selector.verticeXYZ[1] = cuadrado[vertice_sel-3].verticeXYZ[1];
      break;
  }
 
  if (raton.izda) {
      if (vertice_sel<=2) {
        triangulo[vertice_sel].verticeXYZ[0] = selector.verticeXYZ[0] = raton.x;
        triangulo[vertice_sel].verticeXYZ[1] = selector.verticeXYZ[1] = raton.y;
      }
      else {
        cuadrado[vertice_sel-3].verticeXYZ[0] = selector.verticeXYZ[0] = raton.x;
        cuadrado[vertice_sel-3].verticeXYZ[1] = selector.verticeXYZ[1] = raton.y;
      }
  }
 
  glutTimerFunc(33,MoverVertice,1);
  glutPostRedisplay();
}

void Teclado(unsigned char key, int x, int y) {
   switch(key) {
      case 99: cull = !cull; break; //Letra c
      case 119: sentido = !sentido; break; //Letra w
      case 108: linear = !linear; break; //Letra l
   }
}

int main(int argc, char **argv) {
  glutInit(&argc,argv); //Solo necesario en Linux
  IniciarGLUT();
 
  glutReshapeFunc(ReProyectar);
  glutDisplayFunc(PintarEscena);
  glutIdleFunc(PintarEscena);
  glutMouseFunc(ControlRaton);
  glutTimerFunc(33,MoverVertice,1);
  glutMotionFunc(MovimRaton);
  glutKeyboardFunc(Teclado);
 
  glutMainLoop();
  return 0;
}

Repasemos las novedades, no vamos a ir en orden según el código, lo haré a mi manera, primero la parte independiente de las caras ocultas, que es más complejo.
Código:
  glShadeModel(GL_FLAT);
  glBegin(GL_TRIANGLE_STRIP);
      glColor3f(1,0,0);
      glVertex3i(-9,9,0);
      glVertex3i(-8,8,0);
      glVertex3i(-7,9,0);
      glColor3f(0,1,0);
      glVertex3i(-6,8,0);
      glColor3f(0,0,1);
      glVertex3i(-5,9,0);
  glEnd();
 
  glBegin(GL_TRIANGLE_FAN);
      glColor3f(1,0,0);
      glVertex3i(8,8,0);
      glVertex3i(6,8,0);
      glVertex3i(7,9,0);
      glColor3f(0,1,0);
      glVertex3i(9,9,0);
      glColor3f(0,0,1);
      glVertex3i(10,8,0);
  glEnd();
 
  glShadeModel(GL_SMOOTH);
Los triángulos STRIP funcionan como las líneas STRIP, primero damos los vértices de un triángulo, y a partir de ahí, cada nuevo vértice, formará con los dos anteriores otro triángulo, creando así triángulos encadenados. Así con 5 vértices creamos 3 triángulos como en el ejemplo, observa los puntos y mira. En este caso va en el sentido contrario de las agujas del reloj (ya veremos para que digo esto).
Los triángulos FAN son parecidos a los STRIP, el ejemplo común que se dice siempre es que genera abanicos. La explicación es que, los 3 primeros vértices forman un triángulo, y partir de ahí con cada nuevo vértice, se genera un nuevo triángulo con el nuevo vértice, el anterior y el primero. A compartir todos los triángulo un punto, parece una abanico, pero en general se usa para hacer circunferencias. En el ejemplo va en el sentido de las agujas del reloj.
Otra cosa que habrás notado, es un glShadeModel(GL_FLAT) al principio, si ejecutas el programa, verás que entre vértice y vértice no se produce esa gama de color que hay en los otros polígonos de antes. Con esa función puedes desactivar el sombreado, que así se llama, con glShadeModel(GL_SMOOTH) vuelves a activar el sombreado, como antes.

Ahora si, analicemos esto:
Código:
  if (cull) glEnable(GL_CULL_FACE);
  else glDisable(GL_CULL_FACE);
  if (sentido) glFrontFace(GL_CW);
  else glFrontFace(GL_CCW);
  if (linear) glPolygonMode(GL_BACK,GL_LINE);
  else glPolygonMode(GL_BACK,GL_FILL);
Las tres variables de los condicionales, solo son para un activado/desactivado con el teclado, las teclas para activar/desactivar son C, W y L. Miralo en el código. Lo importante, si activas GL_CULL_FACE la cara trasera no se verá. ¿Cuál es la cara trasera? Pues depende lo que tu digas con glFrontFace(), si pones GL_CW, la cara delantera será aquella cuyos puntos signa el sentido de las agujas del reloj, y GL_CCW determina el sentido contrario. Se verán ambas (como hasta ahora) si no activas GL_CULL_FACE. Ahora una cosa un poco aparte. glPolygonMode(GL_BACK,GL_LINE) define cómo representar los polígonos (GL_POINT cada vértice se como un punto, GL_LINE para ver las líneas y GL_FILL para rellenar los polígonos como hasta ahora), según la cara (GL_FRONT, GL_BACK, GL_FRONT_AND_BACK). Se somete a GL_CULL_FACE, si no se ve la cara, no se no puntos, ni lineas, ni mucho menos el relleno. Experimenta, gracias a que puedes cambiar los vértices de sitio, puedes hacer que uno de esos polígonos manipulables pase a ir en sentido contrario al original.

HarZe
WebMaster & Desarrollador

Cantidad de envíos : 58
Fecha de inscripción : 21/06/2009
Edad : 24

Ver perfil de usuario http://opengl-esp.superforo.net

Volver arriba Ir abajo

Re: [Tutorial] III.7 - Las dos caras del polígono, triángulos STRIP y FAN

Mensaje  ivolk el Sáb Oct 13, 2012 6:28 pm

todo esto es usando opg y c++ vdd? y no tiene para java?????

ivolk

Cantidad de envíos : 1
Fecha de inscripción : 13/10/2012

Ver perfil de usuario

Volver arriba Ir abajo

Ver el tema anterior Ver el tema siguiente Volver arriba

- Temas similares

 
Permisos de este foro:
No puedes responder a temas en este foro.