![]() |
Autor artykułu: mgr Jerzy Wałaszek, wersja1.0 |
©2011 mgr
Jerzy Wałaszek
|
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:
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).


| 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.
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.
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe