Moim zadaniem było zaproponowanie i zaimplementowanie algorytmu generującego model góry za pomocą funkcji Weierstrassa. Postanowiłem dokonać tego obracając wygenerowany wykres wokół osi OX. Oczywiście obracanie wykresu w zbyt małych odstępach byłoby dość trudne i czasochłonne do wykonania, a po za tym powodowałoby duże opuźnienie. Dlatego wygenerowałem tylko 7 wykresów co 300. Po wygenerowaniu wykresów (chmóry punktów) rysowałem siatkę łącząc kolejne punkty w odpowiedniej kolejności.
Funkcja draws przyjmuje parametr a, będący parametrem funkcji Weierstrassa. Poniżej zamieszczam kod programu.
/*************************************************************************************/
// Program rysujący siatkę (model) góry przy pomocy funkcji Weierstrassa wykorzystujący funkcje biblioteki OpenGL
/*************************************************************************************/
#include <windows.h>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <gl/gl.h>
#include <gl/glut.h>
typedef float point3[3];
typedef float point2[2];
point2 tab2D[100];
point3 tab[7][100];
static GLfloat theta[] = {0.0, 0.0, 0.0}; // trzy kąty obrotu
/*************************************************************************************/
//funkcja zwracająca wartość (y) funkcji weierstrassa w punkcie x
float weierstrass(float a, float x)
{
float wynik = 0;
for( int k = 1 ; k<=20 ; k++ )
{
wynik += sin(3.14*pow(k,a)*x)/(3.14*pow(k,a));
}
return wynik;
}
// funkcja generująca współrzędne 2D (wykres funkcji weierstrassa)
void generuj_tab2D( float a )
{
float x = 0;
float s = 0.01;
float mn = 10;
for( int i = 0 ; i<100 ; i++ )
{
tab2D[i][0] = x*mn;
tab2D[i][1] = mn*weierstrass(a,x);
x += s;
}
}
// funkcja obracająca wykres wokół OX (rzutowanie na 3D)
void generuj_3D()
{
for( int j = 0 ; j<7 ; j++ )
{
for( int i = 0 ; i<100 ; i++ )
{
tab[j][i][0] = tab2D[i][0];
// generowanie współrzędnych dla kolejnych kątów obrotu
// zaczynając od 0 skacząc co 30
switch( j )
{
case 0 :
tab[j][i][1] = 0;
tab[j][i][2] = (-1)*tab2D[i][1];
break;
case 1 :
tab[j][i][1] = tab2D[i][1]/2;
tab[j][i][2] = (-5)*tab2D[i][1]/6;
break;
case 2 :
tab[j][i][1] = 5*tab2D[i][1]/6;
tab[j][i][2] = (-1)*tab2D[i][1]/2;
break;
case 3 :
tab[j][i][1] = tab2D[i][1];
tab[j][i][2] = 0;
break;
case 4 :
tab[j][i][1] = 5*tab2D[i][1]/6;
tab[j][i][2] = tab2D[i][1]/2;
break;
case 5 :
tab[j][i][2] = 5*tab2D[i][1]/6;
tab[j][i][1] = tab2D[i][1]/2;
break;
case 6 :
tab[j][i][1] = 0;
tab[j][i][2] = tab2D[i][1];
break;
}
}
}
}
//rysowanie siatki złożonej z prostokątów
//nie definiuję funkcji rysującej wypełnione postokąty,
//ponieważ przy wypełnieniu nie będzie widoczna przestrzenność góry
//wypełnianie prostokątów ma sens dopiero, gdy wprowadzone zostanie światło
void draws( float a )
{
generuj_tab2D(a);
generuj_3D();
for( int j = 0 ; j<7 ; j++ )
{
for( int i = 0 ; i<99 ; i++ )
{
// rysowanie wykresu o konkretnym koncie (kąt zależny od j)
glBegin(GL_LINES);
glVertex3fv(tab[j][i]);
glVertex3fv(tab[j][i+1]);
glEnd();
//jeżeli nie jest to ostatni wykres to łączymy kolejne punkty (x) sąsiedniego (o większym koncie) wykresu
if( j<6 )
{
glBegin(GL_LINES);
glVertex3fv(tab[j][i]);
glVertex3fv(tab[j+1][i]);
glEnd();
}
}
}
}
//funkcja obracająca górę
void spinGora()
{
theta[0] -= 0.5;
if( theta[0] > 360.0 ) theta[0] -= 360.0;
theta[1] -= 0.5;
if( theta[1] > 360.0 ) theta[1] -= 360.0;
theta[2] -= 0.5;
if( theta[2] > 360.0 ) theta[2] -= 360.0;
_sleep(10); //dodane w celu wolniejszego obracania
glutPostRedisplay(); //odświeżenie zawartości aktualnego okna
}
/*************************************************************************************/
// Funkcaja określająca, co ma być rysowane
// (zawsze wywoływana, gdy trzeba przerysować scenę)
void RenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Czyszczenie okna aktualnym kolorem czyszczącym
glLoadIdentity();
// Czyszczenie macierzy bieżącej
glColor3f(1.0f, 1.0f, 1.0f); // Ustawienie koloru rysowania na biały
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
draws(3);
glFlush();
// Przekazanie poleceń rysujących do wykonania
glutSwapBuffers();
//
}
/*************************************************************************************/
// Funkcja ustalająca stan renderowania
void MyInit(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Kolor czyszcący (wypełnienia okna) ustawiono na czarny
}
/*************************************************************************************/
// Funkcja ma za zadanie utrzymanie stałych proporcji rysowanych
// w przypadku zmiany rozmiarów okna.
// Parametry vertical i horizontal (wysokość i szerokość okna) są
// przekazywane do funkcji za każdym razem gdy zmieni się rozmiar okna.
void ChangeSize(GLsizei horizontal, GLsizei vertical )
{
GLfloat AspectRatio;
// Deklaracja zmiennej AspectRatio określającej proporcję
// wymiarów okna
if(vertical == 0) // Zabezpieczenie przed dzieleniem przez 0
vertical = 1;
glViewport(0, 0, horizontal, vertical);
// Ustawienie wielkościokna okna widoku (viewport)
// W tym przypadku od (0,0) do (horizontal, vertical)
glMatrixMode(GL_PROJECTION);
// Przełączenie macierzy bieżącej na macierz projekcji
glLoadIdentity();
// Czyszcznie macierzy bieżącej
AspectRatio = (GLfloat)horizontal/(GLfloat)vertical;
// Wyznaczenie współczynnika proporcji okna
// Gdy okno nie jest kwadratem wymagane jest określenie tak zwanej
// przestrzeni ograniczającej pozwalającej zachować właściwe
// proporcje rysowanego obiektu.
// Do okreslenia przestrzeni ograniczjącej służy funkcja
// glOrtho(...)
if(horizontal <= vertical)
glOrtho(-7.5,7.5,-7.5/AspectRatio,7.5/AspectRatio,10.0, -10.0);
else
glOrtho(-7.5*AspectRatio,7.5*AspectRatio,-7.5,7.5,10.0,-10.0);
glMatrixMode(GL_MODELVIEW);
// Przełączenie macierzy bieżącej na macierz widoku modelu
glLoadIdentity();
// Czyszcenie macierzy bieżącej
}
/*************************************************************************************/
// Główny punkt wejścia programu. Program działa w trybie konsoli
void main(void)
{
glutIdleFunc(spinGora);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB |GLUT_DEPTH);
glutInitWindowSize(300, 300);
glutCreateWindow("Układ współrzędnych 3-D");
glutDisplayFunc(RenderScene);
// Określenie, że funkcja RenderScene będzie funkcją zwrotną
// (callback function). Bedzie ona wywoływana za każdym razem
// gdy zajdzie potrzba przeryswania okna
glutReshapeFunc(ChangeSize);
// Dla aktualnego okna ustala funkcję zwrotną odpowiedzialną
// zazmiany rozmiaru okna
MyInit();
// Funkcja MyInit() (zdefiniowana powyżej) wykonuje wszelkie
// inicjalizacje konieczne przed przystąpieniem do renderowania
glEnable(GL_DEPTH_TEST);
// Włączenie mechanizmu usuwania powierzchni niewidocznych
glutMainLoop();
// Funkcja uruchamia szkielet biblioteki GLUT
}
/*************************************************************************************/