SDL / OpenGL - rysowanie figur 3D

Teraz zajmiemy się efektywnym tworzeniem figur trójwymiarowych. Dla wygody rysowania figurę możemy zdefiniować w tablicach wierzchołków i ścian. Biblioteka OpenGL posiada wiele różnych funkcji, które umożliwiają zdefiniowanie wierzchołka. Dotychczas poznaliśmy dwie: glVertex2f() i glVertex3f(). Poniżej podajemy ważniejsze funkcje glVertex - różnią się one sposobami podawania współrzędnych wierzchołka:

 

void glVertex2s(GLshort x, GLshort y); x,y - krótkie dane całkowite 16-bitowe, odpowiednik typu short, z = 0
void glVertex2i(GLint x, GLint y); x,y - liczby całkowite 32-bitowe, odpowiednik typu int, z = 0
void glVertex2f(GLfloat x, GLfloat y); x,y - liczby zmiennoprzecinkowe pojedynczej precyzji, odpowiednik typu float, z = 0
void glVertex2d(GLdouble x, GLdouble y); x,y - liczby zmiennoprzecinkowe podwójnej precyzji, odpowiednik typu double, z = 0
void glVertex3s(GLshort x, GLshort y, GLshort z); x,y,z - krótkie dane całkowite 16-bitowe, odpowiednik typu short
void glVertex3i(GLint x, GLint y, GLint z); x,y,z - liczby całkowite 32-bitowe, odpowiednik typu int
void glVertex3f(GLfloat x, GLfloat y, GLfloat z); x,y,z - liczby zmiennoprzecinkowe pojedynczej precyzji, odpowiednik typu float
void glVertex3d(GLdouble x, GLdouble y, GLdouble z); x,y,z - liczby zmiennoprzecinkowe podwójnej precyzji, odpowiednik typu double
void glVertex2sv(const GLshort * v); v - jest wskaźnikiem tablicy 2 elementowej, która zawiera x,y jako liczby typu GLshort, z = 0
void glVertex2iv(const GLint * v); v - jest wskaźnikiem tablicy 2 elementowej, która zawiera x,y jako liczby typu GLint, z = 0
void glVertex2fv(const GLfloat * v); v - jest wskaźnikiem tablicy 2 elementowej, która zawiera x,y jako liczby typu GLfloat, z = 0
void glVertex2dv(const GLdouble * v); v - jest wskaźnikiem tablicy 2 elementowej, która zawiera x,y jako liczby typu GLdouble, z = 0
void glVertex3sv(const GLshort * v); v - jest wskaźnikiem tablicy 3 elementowej, która zawiera x,y,y jako liczby typu GLshort
void glVertex3iv(const GLint * v); v - jest wskaźnikiem tablicy 3 elementowej, która zawiera x,y,y jako liczby typu GLint
void glVertex3fv(const GLfloat * v); v - jest wskaźnikiem tablicy 3 elementowej, która zawiera x,y,y jako liczby typu GLfloat
void glVertex3dv(const GLdouble * v); v - jest wskaźnikiem tablicy 3 elementowej, która zawiera x,y,y jako liczby typu GLdouble

 

Jeśli współrzędna z jest pominięta na liście parametrów, to przyjmuje wartość 0. Istnieje jeszcze wersja 4-ro parametrowa funkcji glVertex, gdzie czwarty parametr jest współczynnikiem skalującym, ale nie będziemy tutaj z niej korzystać. Zainteresowanych odsyłam do instrukcji biblioteki OpenGL.

W dalszych przykładach będziemy wykorzystywali funkcję glVertex3fv(). Parametrem tej funkcji jest adres tablicy 3 elementowej typu GLfloat, która zawiera kolejno współrzędne x, y i z.

W podobny sposób możemy definiować w tablicy również kolory wierzchołków. Do tego celu wykorzystuje się funkcje rodziny glColor. Funkcje te przyjmują następujące parametry:

 

red - składowa czerwona, 0...1
green - składowa zielona, 0...1
blue - składowa niebieska, 0...1

alpha - przezroczystość, 0...1

 

Dla składowych kolorów 0 oznacza brak składowej, 1 oznacza pełną intensywność składowej. Jeśli składowe podawane są jako liczby całkowite, to zostają one przekształcone na wartości zmiennoprzecinkowe tak, że całkowita wartość maksymalna odpowiada wartości 1, a minimalna wartości -1. Na przykład dla typu GLbyte otrzymamy: -128 → -1...127 → 1. Zwróć uwagę, że w takim przekształceniu zero całkowite nie odpowiada dokładnie zeru zmiennoprzecinkowemu z powodu niesymetryczności zakresu liczb U2 względem 0 (całkowitych liczb dodatnich jest zawsze o 1 mniej niż całkowitych liczb ujemnych). Z tego powodu istnieją również wersje dla danych całkowitych bez znaku. W tym przypadku największa wartość odpowiada 1, a zero odpowiada intensywności 0. Na przykład dla typu GLubyte otrzymujemy 0 → 0...255 → 1.

 

void glColor3b(GLbyte red, GLbyte green, GLbyte blue); - trzy liczby całkowite 8-bitowe, -128...127
void glColor3s(GLshort red, GLshort green, GLshort blue); - trzy liczby całkowite 16-bitowe, -32768...32767
void glColor3i(GLint red, GLint green, GLint blue); - trzy liczby całkowite 32-bitowe, -2147483648...2147483647
void glColor3f(GLfloat red, GLfloat green, GLfloat blue); - trzy liczby zmiennoprzecinkowe pojedynczej precyzji
void glColor3d(GLdouble red, GLdouble green, GLdouble blue); - trzy liczby zmiennoprzecinkowe podwójnej precyzji
void glColor3ub(GLubyte red, GLubyte green, GLubyte blue); - trzy liczby całkowite 8-bitowe bez znaku, 0...255
void glColor3us(GLushort red, GLushort green, GLushort blue); - trzy liczby całkowite 16-bitowe bez znaku, 0...65535
void glColor3ui(GLuint red, GLuint green, GLuint blue); - trzy liczby całkowite 32-bitowe bez znaku, 0...4294967295
void glColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); - cztery liczby całkowite 8-bitowe, -128...127
void glColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha); - cztery liczby całkowite 16-bitowe, -32768...32767
void glColor4i(GLint red, GLint green, GLint blue, GLint alpha); - cztery liczby całkowite 32-bitowe, -2147483648...2147483647
void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); - cztery liczby zmiennoprzecinkowe pojedynczej precyzji
void glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); - cztery liczby zmiennoprzecinkowe podwójnej precyzji
void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); - cztery liczby całkowite 8-bitowe bez znaku, 0...255
void glColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha); - cztery liczby całkowite 16-bitowe bez znaku, 0...65535
void glColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha); - cztery liczby całkowite 32-bitowe bez znaku, 0...4294967295
void glColor3bv(const GLbyte * v); - wskaźnik do tablicy 3 liczb typu GLbyte
void glColor3sv(const GLshort * v); - wskaźnik do tablicy 3 liczb typu GLshort
void glColor3iv(const GLint * v); - wskaźnik do tablicy 3 liczb typu GLint
void glColor3fv(const GLfloat * v); - wskaźnik do tablicy 3 liczb typu GLfloat
void glColor3dv(const GLdouble * v); - wskaźnik do tablicy 3 liczb typu GLdouble
void glColor3ubv(const GLubyte * v); - wskaźnik do tablicy 3 liczb typu GLubyte
void glColor3usv(const GLushort * v); - wskaźnik do tablicy 3 liczb typu GLushort
void glColor3uiv(const GLuint * v); - wskaźnik do tablicy 3 liczb typu GLuint
void glColor4bv(const GLbyte * v); - wskaźnik do tablicy 4 liczb typu GLbyte
void glColor4sv(const GLshort * v); - wskaźnik do tablicy 4 liczb typu GLshort
void glColor4iv(const GLint * v); - wskaźnik do tablicy 4 liczb typu GLint
void glColor4fv(const GLfloat * v); - wskaźnik do tablicy 4 liczb typu GLfloat
void glColor4dv(const GLdouble * v); - wskaźnik do tablicy 4 liczb typu GLdouble
void glColor4ubv(const GLubyte * v); - wskaźnik do tablicy 4 liczb typu GLubyte
void glColor4usv(const GLushort * v); - wskaźnik do tablicy 4 liczb typu GLushort
void glColor4uiv(const GLuint * v); - wskaźnik do tablicy 4 liczb typu GLuint

 

Z początku może ci się wydawać, że funkcji tych jest bardzo dużo, jednak tak na prawdę są tylko dwie glVertex i glColor. Odpowiednie ich odmiany tworzysz zawsze przez dodanie przyrostków:

 

2 3 4 - określa liczbę argumentów: glVertex2...  glColor3...
b - argumenty typu GLbyte: glColor3b...
ub - argumenty typu GLubyte: glColor4ub...
s - argumenty typu GLshort: glVertex3s...
us - argumenty typu GLushort: glColor4us...
i - argumenty typu GLint: glVertex2i...
ui - argumenty typu GLuint: glColor3ui...
f - argumenty typu GLfloat: glVertex3f...
d - argumenty typu GLdouble: glVertex2d...
v - dodawane na końcu oznacza wskaźnik do tablicy, która przechowuje argumenty funkcji: glColor2dv(...)

 

A teraz praktyczny przykład. Napiszemy prosty program, który będzie animował sześcian. Definicję sześcianu umieścimy w trzech tablicach:

 

V - definicje wierzchołków figury, każdy element będzie tablicą 3 elementową typu GLfloat, która określa współrzędne wierzchołka w przestrzeni.

C - definicje kolorów wierzchołków, każdy element będzie tablicą 3 elementową typu GLfloat, która określa składowe red, green i blue koloru w punkcie wierzchołka

F - definiuje ściany, każdy element będzie zbudowany z 4 liczb całkowitych, które określają numery wierzchołków tworzących ścianę - ściany będą czworokątami. Dodatkowo umawiamy się, że wszystkie wierzchołki tworzące ścianę będą ułożone w kolejności zgodnej z ruchem wskazówek zegara (dlaczego tak, wyjaśnimy później).

 

Uwaga - uruchomienie programu wymaga odpowiedniego ustawienia środowiska SDL i OpenGL. Zobacz na: Grafika SDL / OpenGL - tworzenie prostych obiektów 3D i animowanie ich

 

 

 

Code::Blocks
// Tworzenie figur 3D
// (C)2012 Koło Informatyczne
// I LO w Tarnowie
//-------------------------------

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

const int W = 640; // szerokość okna
const int H = 480; // wysokość okna

const int NV = 8;  // liczba wierzchołków figury
const int NF = 6;  // liczba ścian figury

// Definicja wierzchołków kwadratu

GLfloat V[][3] = {{-1, 1, 1}, // wierzchołek 0
                  { 1, 1, 1}, // wierzchołek 1
                  { 1,-1, 1}, // wierzchołek 2
                  {-1,-1, 1}, // wierzchołek 3
                  {-1, 1,-1}, // wierzchołek 4
                  { 1, 1,-1}, // wierzchołek 5
                  { 1,-1,-1}, // wierzchołek 6
                  {-1,-1,-1}  // wierzchołek 7
                  };

// Definicja kolorów wierzchołków

GLfloat C[][3] = {{1,0,0},    // kolor wierzchołka 0
                  {0,1,0},    // kolor wierzchołka 1
                  {0,0,1},    // kolor wierzchołka 2
                  {1,1,0},    // kolor wierzchołka 3
                  {0,1,1},    // kolor wierzchołka 4
                  {1,0,1},    // kolor wierzchołka 5
                  {1,1,1},    // kolor wierzchołka 6
                  {0.5,0,1}   // kolor wierzchołka 7
                  };

// Definicje ścian

int F[][4] = {{0,1,2,3},      // ściana nr 0
              {1,5,6,2},      // ściana nr 1
              {5,4,7,6},      // ściana nr 2
              {4,0,3,7},      // ściana nr 3
              {4,5,1,0},      // ściana nr 4
              {3,2,6,7}       // ściana nr 5
              };

int main(int argc, char *argv[])
{
   SDL_Event event;

   SDL_Init(SDL_INIT_VIDEO);

   SDL_GL_SetAttribute(SDL_GL_RED_SIZE,    8);
   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,   8);
   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,  8);
   SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);

   SDL_SetVideoMode(W, H, 0, SDL_OPENGL);

   glViewport(0, 0, W, H);

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

   gluPerspective(45.0f,(GLfloat)W/(GLfloat)H,0.1f,300.0f);

   glMatrixMode(GL_MODELVIEW);

   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

   glEnable(GL_DEPTH_TEST);
   glDepthFunc(GL_LEQUAL);

   GLfloat k = 0, dk = 1;

   for(int done = 0; !done;)
   {
     SDL_Delay(10);                  // opóźnienie poszczególnych klatek

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();               // zerujemy przekształcenia

     // Tutaj umieszczamy rysowanie sceny

     glTranslatef(0.0f,0.0f,-5.0f);  // do miejsca rysowania sześcianu
     glRotatef(k,1.0f,1.0f,0.0f);    // obrót wokół osi

     // Rysujemy kolejne ściany

     for(int i = 0; i < NF; i++)
     {
       glBegin(GL_QUADS);
       for(int j = 0; j < 4; j++)
       {
          glColor3fv(C[F[i][j]]);  // definiujemy kolor wierzchołka
          glVertex3fv(V[F[i][j]]); // definiujemy współrzędne wierzchołka
       }
       glEnd();
     }

     k += dk;  // modyfikujemy kąt obrotu
     if(k > 360) k = 1;

     SDL_GL_SwapBuffers();         // wyświetlamy scenę w oknie podglądu

     SDL_PollEvent(&event);        // sprawdzamy kolejkę zdarzeń
     if(event.key.keysym.sym == SDLK_ESCAPE) done = 1;
   }

   return 0;
}

 

Powyższy program wykorzystuje bufor głębokości do ukrywania niewidocznych ścian. Za wykorzystywanie tej opcji odpowiedzialne są dwie funkcje:

 

   glEnable(GL_DEPTH_TEST);
   glDepthFunc(GL_LEQUAL);

 

Pierwsza, glEnable() jest ogólną funkcją, która uaktywnia różne opcje środowiska OpenGL - w tym przypadku testowanie głębokości. Druga funkcja określa warunek widoczności piksela ściany - jeśli jego współrzędna z jest mniejsza lub równa od współrzędnej z zapamiętanej w buforze głębokości. Po narysowaniu piksela jego współrzędna z trafia do bufora. Umieść obie funkcje w komentarzu i sprawdź jak wpłynie to na sposób rysowania figury. Ściany zasłaniają się zgodnie z kolejnością rysowania a nie z ich położeniem w przestrzeni.

 

Wykorzystywanie bufora głębokości jest dosyć kosztowne. W wielu przypadkach wystarcza prostsza metoda, która polega na rezygnacji z rysowania danej ściany, jeśli na obrazie jest widoczny jest jej tył, a nie przód. Powstaje problem - jak wykryć, że obraz ściany przedstawia jej przód? Metoda jest dosyć prosta i polega na sprawdzaniu kolejności wierzchołków definiujących ścianę. Zobacz na poniższy rysunek:

 

 

Gdy ściana jest umieszczona tyłem w kierunku obserwatora, to zmienia się kolejność jej wierzchołków - to dlatego definiowaliśmy wszystkie ściany wierzchołkami ułożonymi zgodnie z ruchem wskazówek zegara.

Aby włączyć eliminację ścian odwróconych tyłem, musimy dodać do naszego programu wywołania trzech funkcji (wstaw je za umieszczonymi w komentarzu funkcjami włączającymi bufor głębokości):

 

glEnable(GL_CULL_FACE);   // włącza opcję eliminacji ścian

glFrontFace(GL_CW);       // ściany o wierzchołkach ułożonych zgodnie z ruchem wskazówek
                          // zegara będą traktowane jako zwrócone przodem

glCullFace(GL_BACK);      // pomija rysowanie ścian odwróconych tyłem 

 

Jeśli uruchomisz tak zmodyfikowany program, to będzie on działał tak samo jak przy buforze głębokości. Możesz zatem dojść do wniosku, że bufor głębokości jest zbędny. Nic z tego. Dalej go potrzebujemy. Uruchom poniższy program - tworzy on na scenie dwa sześciany umieszczone w pewnej odległości jeden od drugiego:

 

 

Code::Blocks
// Tworzenie figur 3D
// (C)2012 Koło Informatyczne
// I LO w Tarnowie
//-------------------------------

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

const int W = 640;
const int H = 480;

const int NV = 8;  // liczba wierzchołków figury
const int NF = 6;  // liczba ścian figury

// Definicja wierzchołków kwadratu

GLfloat V[][3] = {{-1, 1, 1}, // wierzchołek 0
                  { 1, 1, 1}, // wierzchołek 1
                  { 1,-1, 1}, // wierzchołek 2
                  {-1,-1, 1}, // wierzchołek 3
                  {-1, 1,-1}, // wierzchołek 4
                  { 1, 1,-1}, // wierzchołek 5
                  { 1,-1,-1}, // wierzchołek 6
                  {-1,-1,-1}  // wierzchołek 7
                  };

// Definicja kolorów wierzchołków

GLfloat C[][3] = {{1,0,0},    // kolor wierzchołka 0
                  {0,1,0},    // kolor wierzchołka 1
                  {0,0,1},    // kolor wierzchołka 2
                  {1,1,0},    // kolor wierzchołka 3
                  {0,1,1},    // kolor wierzchołka 4
                  {1,0,1},    // kolor wierzchołka 5
                  {1,1,1},    // kolor wierzchołka 6
                  {0.5,0,1}   // kolor wierzchołka 7
                  };

// Definicje ścian

int F[][4] = {{0,1,2,3},      // ściana nr 0
              {1,5,6,2},      // ściana nr 1
              {5,4,7,6},      // ściana nr 2
              {4,0,3,7},      // ściana nr 3
              {4,5,1,0},      // ściana nr 4
              {3,2,6,7}       // ściana nr 5
              };

int main(int argc, char *argv[])
{
   SDL_Event event;

   SDL_Init(SDL_INIT_VIDEO);

   SDL_GL_SetAttribute(SDL_GL_RED_SIZE,    8);
   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,   8);
   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,  8);
   SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);

   SDL_SetVideoMode(W, H, 0, SDL_OPENGL);

   glViewport(0, 0, W, H);

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

   gluPerspective(45.0f,(GLfloat)W/(GLfloat)H,0.1f,300.0f);

   glMatrixMode(GL_MODELVIEW);

   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

   //glEnable(GL_DEPTH_TEST);
   //glDepthFunc(GL_LEQUAL);

   glEnable(GL_CULL_FACE);   // włącza opcję eliminacji ścian

   glFrontFace(GL_CW);       // ściany o wierzchołkach ułożonych zgodnie z ruchem wskazówek
                             // zegara będą traktowane jako zwrócone przodem

   glCullFace(GL_BACK);      // pomija rysowanie ścian odwróconych tyłem

   GLfloat k = 0, dk = 1;

   for(int done = 0; !done;)
   {
     SDL_Delay(10);

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();               // zerujemy przekształcenia

     // Tutaj umieszczamy rysowanie sceny

     glTranslatef(1.5f,0.0f,-7.0f);  // do miejsca rysowania pierwszego sześcianu
     glRotatef(k,1.0f,1.0f,0.0f);    // obrót wokół osi

     // Rysujemy pierwszy sześcian

     for(int i = 0; i < NF; i++)
     {
       glBegin(GL_QUADS);
       for(int j = 0; j < 4; j++)
       {
          glColor3fv(C[F[i][j]]);  // definiujemy kolor wierzchołka
          glVertex3fv(V[F[i][j]]); // definiujemy współrzędne wierzchołka
       }
       glEnd();
     }

     glTranslatef(-3.0f,0.0f,0.0f);  // do miejsca rysowania drugiego sześcianu

     // Rysujemy drugi sześcian

     for(int i = 0; i < NF; i++)
     {
       glBegin(GL_QUADS);
       for(int j = 0; j < 4; j++)
       {
          glColor3fv(C[F[i][j]]);  // definiujemy kolor wierzchołka
          glVertex3fv(V[F[i][j]]); // definiujemy współrzędne wierzchołka
       }
       glEnd();
     }

     k += dk;  // modyfikujemy kąt obrotu
     if(k > 360) k = 1;

     SDL_GL_SwapBuffers();         // wyświetlamy scenę w oknie podglądu

     SDL_PollEvent(&event);        // sprawdzamy kolejkę zdarzeń
     if(event.key.keysym.sym == SDLK_ESCAPE) done = 1;
   }

   return 0;
}

 

A teraz usuń komentarze z funkcji glEnable(GL_DEPTH_TEST) i glDepthFunc(GL_LEQUAL) i uruchom program jeszcze raz. Wnioski wyciągnij sam.

Rysowanie siatki 3D

Napiszemy program, który rysuje siatkę zbudowaną z prostokątów:

 

 

Siatka będzie się składała z n x m wierzchołków. Na początek będą one ułożone na płaszczyźnie zawierającej osie OX i OY. Wierzchołki zdefiniujemy w tablicy 3 wymiarowej V. Pierwszy wymiar będzie określał numer wiersza. Drugi wymiar będzie określał numer kolumny. Trzeci wymiar będzie wynosił 3 - liczba współrzędnych dla każdego punktu. Tablicę tę będziemy inicjować programowo. W identyczny sposób będzie zdefiniowana tablica kolorów. Z tablicy ścian zrezygnujemy.

 

 

Code::Blocks
// Tworzenie figur 3D
// (C)2012 Koło Informatyczne
// I LO w Tarnowie
//-------------------------------

#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <ctime>
#include <cstdlib>

const int W = 640;
const int H = 480;

const int N = 21;   // liczba wierszy
const int M = 31;   // liczba kolumn

GLfloat V[N][M][3];
GLshort C[N][M][3];

// Funkcja ustawia współrzędne wierzchołków oraz ich kolory

void UstawFigure()
{
  GLfloat dx,dy;

  // określamy odstępy pomiędzy punktami

  dx = 2.0 / (N-1);
  dy = 2.0 / (M-1);

  // wyliczamy kolejne współrzędne
  for(int i = 0; i < N; i++)
    for(int j = 0; j < M; j++)
    {
        V[i][j][0] = -1 + i * dx;  // współrzędna x
        V[i][j][1] =  1 - j * dy;  // współrzędna y
        V[i][j][2] = 0;            // współrzędna z

        for(int k = 0; k < 3; k++) C[i][j][k] = rand();
    }
}

// Funkcja rysuje figurę

void RysujFigure()
{
  for(int i = 0; i < N - 1; i++)
    for(int j = 0; j < M - 1; j++)
    {
      glBegin(GL_QUADS);
        glColor3sv(C[i][j]);      // kolor wierzchołka
        glVertex3fv(V[i][j]);     // lewy górny
        glColor3sv(C[i][j+1]);    // kolor wierzchołka
        glVertex3fv(V[i][j+1]);   // prawy górny
        glColor3sv(C[i+1][j+1]);  // kolor wierzchołka
        glVertex3fv(V[i+1][j+1]); // prawy dolny
        glColor3sv(C[i+1][j]);    // kolor wierzchołka
        glVertex3fv(V[i+1][j]);   // lewy dolny
      glEnd();
    }
}

int main(int argc, char *argv[])
{
   SDL_Event event;

   SDL_Init(SDL_INIT_VIDEO);

   SDL_GL_SetAttribute(SDL_GL_RED_SIZE,    8);
   SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,   8);
   SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,  8);
   SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE,32);

   SDL_SetVideoMode(W, H, 0, SDL_OPENGL);

   srand(time(NULL));

   glViewport(0, 0, W, H);

   glMatrixMode(GL_PROJECTION);

   glLoadIdentity();

   gluPerspective(45.0f,(GLfloat)W/(GLfloat)H,0.1f,300.0f);

   glMatrixMode(GL_MODELVIEW);

   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

   glEnable(GL_DEPTH_TEST);
   glDepthFunc(GL_LEQUAL);

   GLfloat k = 0, dk = 1;

   UstawFigure();

   for(int done = 0; !done;)
   {
     SDL_Delay(10);

     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity();               // zerujemy przekształcenia

     // Tutaj umieszczamy rysowanie sceny

     glTranslatef(0.0f,0.0f,-3.0f);  // do miejsca rysowania figury
     glRotatef(k,1.0f,1.0f,1.0f);    // obrót wokół osi

     RysujFigure();

     k += dk;  // modyfikujemy kąt obrotu
     if(k > 360) k = 1;

     SDL_GL_SwapBuffers();         // wyświetlamy scenę w oknie podglądu

     SDL_PollEvent(&event);        // sprawdzamy kolejkę zdarzeń
     if(event.key.keysym.sym == SDLK_ESCAPE) done = 1;
   }

   return 0;
}

 

Animowana figura jest płaska. Nic nie szkodzi jednak na przeszkodzie, aby ją delikatnie zdeformować. W tym w funkcji UstawFigure() celu zmień wiersz:

 

V[i][j][2] = 0;            // współrzędna z

na

V[i][j][2] = 0.05 * (rand() % 8);  // współrzędna z

 

Na następnych zajęciach zobaczysz, jak z tej siatki utworzyć podstawowe figury obrotowe: walec, stożek, kulę i torus.

 



List do administratora Serwisu Edukacyjnego Nauczycieli I LO

Twój email: (jeśli chcesz otrzymać odpowiedź)
Temat:
Uwaga: ← tutaj wpisz wyraz  ilo , inaczej list zostanie zignorowany

Poniżej wpisz swoje uwagi lub pytania dotyczące tego rozdziału (max. 2048 znaków).

Liczba znaków do wykorzystania: 2048

 

W związku z dużą liczbą listów do naszego serwisu edukacyjnego nie będziemy udzielać odpowiedzi na prośby rozwiązywania zadań, pisania programów zaliczeniowych, przesyłania materiałów czy też tłumaczenia zagadnień szeroko opisywanych w podręcznikach.



   I Liceum Ogólnokształcące   
im. Kazimierza Brodzińskiego
w Tarnowie

©2017 mgr Jerzy Wałaszek

Dokument ten rozpowszechniany jest zgodnie z zasadami licencji
GNU Free Documentation License.