Урок 11
Урок 11
Здравейте всички. За тези, които искат да знаят какво правим тук: това нещо може да се види в края на моята демонстрация/хак "Worthless!". Казвам се Боско и ще направя всичко възможно да ви науча как да направите анимирана картина със синусоида върху нея. Този урок е базиран на урок №6 на NeHe и вие трябва поне да знаете и да можете да правите това, което се казва. Трябва да изтеглите архива с изходния код, да го разопаковате някъде, да вземете снимката от папката с данни и да я поставите в подпапката с данни на папката, където се намира вашият изходен код :). Е, или използвайте своя собствена текстура, ако е правилният размер за OpenGL.
Първо, отворете Урок 6 за Visual C++ и добавете това # включване веднага след останалите. Това # включване ще ни позволи да използваме различни библиотечни математически функции като синус и косинус.
#include // за функцията Sin().
Ще използваме масив от точки ( точки ), за да съхраним отделните координати x, y и z на нашата мрежа. Размерът на решетката е 45х45, а тя от своя страна образува квадратчета 44х44. wiggle_count ще се използва, за да се определи колко бързо се мърда текстурата. Всеки три кадъра изглежда достатъчно добре и променливата за задържане ще съдържа число с плаваща запетая, за да изглади вълните. Тези редове могат да се добавят в началото на програмата, някъде под последния # ред за включване и преди реда за текстура GLuint [1]:
плаващи точки[ 45 ][ 45 ][3]; // масив от точки на мрежата на нашата "вълна"
int wiggle_count = 0; // брояч за контрол на скоростта на размахване на флага
GLfloat задържане; // временно съдържа число с плаваща запетая
Нека преминем надолу към функцията LoadGLTextures(). Искаме да използваме текстура на име Tim. bmp.Намерете LoadBMP (" Data / NeHe . bmp ") и променете на LoadBMP (" Data / Tim . bmp ").
if (TextureImage[0]=LoadBMP("Data/Tim.bmp")) // зареждане на изображение
Сега добавете кода по-долу в края на функцията InitGL(), преди да върне TRUE:
glPolygonMode(GL_BACK, GL_FILL); // долната (задна) страна е запълнена
glPolygonMode(GL_FRONT, GL_LINE); // горна (предна) страна, начертана с линии
Този код просто означава, че искаме долните (задните) странични полигони да бъдат напълно изчертани, а горните (предните) странични полигони да бъдат само очертани.
Това са моите лични предпочитания. Причината е ориентацията на многоъгълника или посоката на лицата. Разгледайте Червената книга (за OpenGL), ако искате да научите повече. Използвайки случая, искам да кажа, че тази книга е само една от тези, които ми помагат да науча OpenGL, без да броим сайта NeHe :). Благодаря NeHe. Купете Ръководството на програмиста за OpenGL от Addison-Wesley. Тя е неизчерпаем ресурс за програмиране на OpenGL. Добре, обратно към урока.
Точно под предишния код и над return TRUE добавете следните редове:
// преминаване на оста x
// преминаване на оста y
// прилагаме вълна към нашата мрежа
Благодаря на Греъм Гибънс, че посочи цикъла на целите числа, за да се избегнат пикове във формата на вълната.
Двата цикъла по-горе инициализират точките на нашата мрежа. Инициализирам променливите в моя цикъл, за да помня, че те са само променливи в цикъл. Не съм сигурен дали е добре. Използваме цикли с цели числа, за да предотвратим проблеми, които възникват при изчисления с плаваща запетая. Разделяме променливите x и y на 5 (т.е. 45 / 9 = 5) и изваждаме 4,5 от всяка, за да центрираме "вълната". Да отидасъщият ефект може да се постигне чрез прехвърляне (превод), но този метод ми харесва повече.
Крайната стойност на точки [ x ][ y ][2] е нашата синусова стойност. Функцията sin() приема параметър в радиани. Взимаме нашите градуси, което се получава чрез умножаване на float _ x ( x /5.0 f ) по 40.0 f и за да ги преобразуваме в радиани чрез деление, вземаме градуси, разделяме на 360.0 f, умножаваме по pi (или приближение) и по 2.0 f.
Ще пренапиша функцията DrawGLScene, така че изтрийте нейния текст и го заменете с текста по-долу.
int DrawGLScene ( GLvoid ) // начертайте нашата сцена
int x, y; // циклични променливи
// за разделяне на знамето на малки квадратчета
float float _ x, float _ y, float _ xb, float _ yb;
За управление в цикли се използват различни променливи. Разгледайте кода по-долу - по-голямата част от него е само за контролиране на цикли и съхраняване на временни стойности.
glClear ( GL _ COLOR _ BUFFER _ BIT GL _ DEPTH _ BUFFER _ BIT ); // изчистване на екрана и буфера за дълбочина
glLoadIdentity(); // нулиране на текущата матрица
glTranslatef(0.0f ,0.0f ,-12.0f ); // преместете 17 единици дълбоко в екрана
glRotatef (xrot,1.0 f,0.0 f,0.0 f); // въртене по оста X
glRotatef (yrot,0.0 f,1.0 f,0.0 f); // въртене по оста Y
glRotatef ( zrot ,0.0 f ,0.0 f ,1.0 f ); // въртене по оста Z
glBindTexture(GL_TEXTURE_2D, текстура[0]); // изберете нашата текстура
Може би сте виждали всичко това преди. Всичко тук е същото като в урок номер 6, с изключение на това, че просто вземам сцената малко по-далеч от камерата.
glBegin(GL_QUADS); // започнете да рисувате квадрати
за ( x = 0; x x ++ ) // цикъл през оста x 0-44 (45 точки)
for( y = 0; y y ++ ) // преминаване презY ос 0-44 (45 точки)
Просто започваме цикъла на рисуване на нашите многоъгълници. Тук използвам цели числа, за да избегна използването на функцията int(), която използвах по-рано, за да получа индекса на препратка към масив като цяло число.
float _ x = float (x)/44,0 f; // създаване на X стойност като float
float _ y = float (y)/44,0 f; // създаване на Y стойност като float
float _ xb = float (x +1)/44.0 f; // създаване на X стойност като float плюс 0,0227 f
float _ yb = float (y +1)/44.0 f; // създаване на Y стойност като float плюс 0,0227 f
Използваме четирите променливи по-горе за текстурни координати. Всеки от нашите многоъгълници (квадрат в мрежата) има 1/44 x 1/44 секция с текстура, нанесена върху нея. В началото на циклите се посочва долният ляв връх на секцията и след това просто добавяме съответно 0 или 1 към този връх, за да получим останалите три върха (т.е. x +1 или y +1 ще бъде горният десен връх).
// първата координата на текстурата (долу вляво)
glTexCoord2f( float_x, float_y);
glVertex3f( точки[x][y][0], точки[x][y][1], точки[x][y][2]);
// втора текстурна координата (горе вляво)
glTexCoord2f( float_x, float_yb);
glVertex3f( точки[x][y+1][0], точки[x][y+1][1], точки[x][y+1][2]);
// трета текстурна координата (горе вдясно)
glTexCoord2f( float_xb, float_yb);
glVertex3f( точки[x+1][y+1][0], точки[x+1][y+1][1], точки[x+1][y+1][2]);
// четвърта текстурна координата (долу вдясно)
glTexCoord2f( float_xb, float_y);
glVertex3f( точки[x+1][y][0], точки[x+1][y][1], точки[x+1][y][2]);
glend(); // направено с квадрати
Горните редове просто правят OpenGL извиквания, за да предадат всички данни, за които говорихме. Четириотделни извиквания към всяка функция glTexCoord 2 f () и glVertex 3 f (). Да продължим. Имайте предвид, че квадратите са начертани по посока на часовниковата стрелка. Това означава, че страната, която виждате, ще бъде първата на гърба. Гърбът е запълнен. Предната част се състои от линии.
Ако трябваше да рисувате обратно на часовниковата стрелка, тогава страната, която ще видите първа, ще бъде предната. Така ще видите текстура, която изглежда като мрежа (написахте: като мрежа), вместо повърхност, изпълнена с текстура.
if ( wiggle _ count == 2 ) // за забавяне на вълната (само всеки втори кадър)
Сега искаме да повторим стойностите на синуса, като по този начин създадем "движение".
for ( y = 0; y y ++ ) // пресичане на оста y
// съхранява текущата стойност на една точка от лявата страна на вълната
задържане = точки[0][y][2];
за ( x = 0; x x ++) // пресичане на оста x
// текущата стойност на вълната е равна на стойността отдясно
// последната стойност се взема от най-лявата съхранена стойност
точки[44][ y ][2]= задържане;
wiggle_count = 0; // нулира отново брояча
wiggle_count++; // увеличаване на брояча
Ето какво правим: запазваме първата стойност на всеки ред, след което преместваме вълната наляво, карайки текстурата да трепти. Стойността, която запазихме, след това се вмъква в края, за да създаде безкрайна вълна по повърхността на текстурата. След това нулираме wiggle_count, за да продължим анимацията.
xrot +=0,3 f; // увеличаване на стойността на променливата за въртене X
yrot +=0,2 f; // увеличаване на стойността на променливата за въртене Y
zrot +=0,4 f; // увеличаване на стойността на променливата за въртене Z
връща TRUE; // връщане от функция
Обичайните стойности на въртене за NeHe. :) Това е всичко. Компилирайте и трябва да иматехубава малка въртяща се "вълна". Не знам какво друго да кажа, уф... Мина толкова МНОГО! Но се надявам, че можете да следвате или да получите нещо полезно за себе си. Ако имате някакви въпроси, ако искате да коригирам нещо или да ми кажете как в крайна сметка колко ужасно пиша програми :), тогава ми изпратете писмо.
Беше импровизирано, но спести много време и усилия. Той ме накара да оценя много повече възгледите на NeHe. Благодаря на всички ви.