-
Notifications
You must be signed in to change notification settings - Fork 0
/
MyApp.cpp
342 lines (268 loc) · 10.4 KB
/
MyApp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
#include "MyApp.h"
#include "GLUtils.hpp"
#include <math.h>
CMyApp::CMyApp(void)
{
m_vaoID = 0;
m_vboID = 0;
m_ibID = 0;
m_programID = 0;
}
CMyApp::~CMyApp(void)
{
}
//
// egy parametrikus felület (u,v) paraméterértékekhez tartozó pontjának
// kiszámítását végző függvény
//
glm::vec3 CMyApp::GetPos(float u, float v)
{
// origó középpontú, egységsugarú gömb parametrikus alakja: http://hu.wikipedia.org/wiki/G%C3%B6mb#Egyenletek
// figyeljünk: matematikában sokszor a Z tengely mutat felfelé, de nálunk az Y, tehát a legtöbb képlethez képest nálunk
// az Y és Z koordináták felcserélve szerepelnek
u *= 2*3.1415f;
v *= 2*3.1415f; // gömbre pi, tóruszra 2*pi
float cu = cosf(u), su = sinf(u), cv = cosf(v), sv = sinf(v);
// Gömb
//return glm::vec3( r*cu*sv, r*cv, r*su*sv );
//Tórusz
return glm::vec3(
(R + r * cu) * cv,
r * su,
(R + r * cu) * sv
);
}
bool CMyApp::Init()
{
// törlési szín legyen kékes
glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
glEnable(GL_CULL_FACE); // kapcsoljuk be a hatrafele nezo lapok eldobasat
glEnable(GL_DEPTH_TEST); // mélységi teszt bekapcsolása (takarás)
glCullFace(GL_BACK); // GL_BACK: a kamerától "elfelé" néző lapok, GL_FRONT: a kamera felé néző lapok
//
// geometria letrehozasa
//
// NxM darab négyszöggel közelítjük a parametrikus felületünket => (N+1)x(M+1) pontban kell kiértékelni
Vertex vert[(N+1)*(M+1)];
for (int i=0; i<=N; ++i)
for (int j=0; j<=M; ++j)
{
float u = i/(float)N;
float v = j/(float)M;
vert[i + j*(N+1)].p = GetPos(u, v);
vert[i + j*(N+1)].c = glm::normalize( vert[i + j*(N+1)].p );
}
// indexpuffer adatai: NxM négyszög = 2xNxM háromszög = háromszöglista esetén 3x2xNxM index
GLushort indices[3*2*(N)*(M)];
for (int i=0; i<N; ++i)
for (int j=0; j<M; ++j)
{
// minden négyszögre csináljunk kettő háromszöget, amelyek a következő
// (i,j) indexeknél született (u_i, v_i) paraméterértékekhez tartozó
// pontokat kötik össze:
//
// (i,j+1)
// o-----o(i+1,j+1)
// |\ | a = p(u_i, v_i)
// | \ | b = p(u_{i+1}, v_i)
// | \ | c = p(u_i, v_{i+1})
// | \ | d = p(u_{i+1}, v_{i+1})
// | \|
// (i,j) o-----o(i+1, j)
//
// - az (i,j)-hez tartózó 1D-s index a VBO-ban: i+j*(N+1)
// - az (i,j)-hez tartózó 1D-s index az IB-ben: i*6+j*6*(N+1)
// (mert minden négyszöghöz 2db háromszög = 6 index tartozik)
//
indices[6*i + j*3*2*(N) + 0] = (i) + (j)* (N+1);
indices[6*i + j*3*2*(N) + 1] = (i+1) + (j)* (N+1);
indices[6*i + j*3*2*(N) + 2] = (i) + (j+1)*(N+1);
indices[6*i + j*3*2*(N) + 3] = (i+1) + (j)* (N+1);
indices[6*i + j*3*2*(N) + 4] = (i+1) + (j+1)*(N+1);
indices[6*i + j*3*2*(N) + 5] = (i) + (j+1)*(N+1);
}
// 1 db VAO foglalasa
glGenVertexArrays(1, &m_vaoID);
// a frissen generált VAO beallitasa aktívnak
glBindVertexArray(m_vaoID);
// hozzunk létre egy új VBO erőforrás nevet
glGenBuffers(1, &m_vboID);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID); // tegyük "aktívvá" a létrehozott VBO-t
// töltsük fel adatokkal az aktív VBO-t
glBufferData( GL_ARRAY_BUFFER, // az aktív VBO-ba töltsünk adatokat
sizeof(vert), // ennyi bájt nagyságban
vert, // erről a rendszermemóriabeli címről olvasva
GL_STATIC_DRAW); // úgy, hogy a VBO-nkba nem tervezünk ezután írni és minden kirajzoláskor felhasnzáljuk a benne lévő adatokat
// VAO-ban jegyezzük fel, hogy a VBO-ban az első 3 float sizeof(Vertex)-enként lesz az első attribútum (pozíció)
glEnableVertexAttribArray(0); // ez lesz majd a pozíció
glVertexAttribPointer(
0, // a VB-ben található adatok közül a 0. "indexű" attribútumait állítjuk be
3, // komponens szam
GL_FLOAT, // adatok tipusa
GL_FALSE, // normalizalt legyen-e
sizeof(Vertex), // stride (0=egymas utan)
0 // a 0. indexű attribútum hol kezdődik a sizeof(Vertex)-nyi területen belül
);
// a második attribútumhoz pedig a VBO-ban sizeof(Vertex) ugrás után sizeof(glm::vec3)-nyit menve újabb 3 float adatot találunk (szín)
glEnableVertexAttribArray(1); // ez lesz majd a szín
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
sizeof(Vertex),
(void*)(sizeof(glm::vec3)) );
// index puffer létrehozása
glGenBuffers(1, &m_ibID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0); // feltöltüttük a VAO-t, kapcsoljuk le
glBindBuffer(GL_ARRAY_BUFFER, 0); // feltöltöttük a VBO-t is, ezt is vegyük le
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // feltöltöttük a VBO-t is, ezt is vegyük le
//
// shaderek betöltése
//
GLuint vs_ID = loadShader(GL_VERTEX_SHADER, "myVert.vert");
GLuint fs_ID = loadShader(GL_FRAGMENT_SHADER, "myFrag.frag");
// a shadereket tároló program létrehozása
m_programID = glCreateProgram();
// adjuk hozzá a programhoz a shadereket
glAttachShader(m_programID, vs_ID);
glAttachShader(m_programID, fs_ID);
// VAO-beli attribútumok hozzárendelése a shader változókhoz
// FONTOS: linkelés előtt kell ezt megtenni!
glBindAttribLocation( m_programID, // shader azonosítója, amiből egy változóhoz szeretnénk hozzárendelést csinálni
0, // a VAO-beli azonosító index
"vs_in_pos"); // a shader-beli változónév
glBindAttribLocation( m_programID, 1, "vs_in_col");
// illesszük össze a shadereket (kimenő-bemenő változók összerendelése stb.)
glLinkProgram(m_programID);
// linkeles ellenorzese
GLint infoLogLength = 0, result = 0;
glGetProgramiv(m_programID, GL_LINK_STATUS, &result);
glGetProgramiv(m_programID, GL_INFO_LOG_LENGTH, &infoLogLength);
if (GL_FALSE == result || infoLogLength != 0)
{
std::vector<char> error_massage(infoLogLength);
glGetProgramInfoLog(m_programID, infoLogLength, NULL, error_massage.data());
std::cout << "Hiba a shader letrehozasakor: " << error_massage.data() << std::endl;
}
// mar nincs ezekre szukseg
glDeleteShader( vs_ID );
glDeleteShader( fs_ID );
//
// egyéb inicializálás
//
// vetítési mátrix létrehozása
m_matProj = glm::perspective( 45.0f, 640/480.0f, 1.0f, 1000.0f );
// shader-beli transzformációs mátrixok címének lekérdezése
m_loc_mvp = glGetUniformLocation( m_programID, "MVP");
return true;
}
void CMyApp::Clean()
{
glDeleteBuffers(1, &m_vboID);
glDeleteBuffers(1, &m_ibID);
glDeleteVertexArrays(1, &m_vaoID);
glDeleteProgram( m_programID );
}
void CMyApp::Update()
{
// nézeti transzformáció beállítása
//float t = SDL_GetTicks()/1000.0f; glm::vec3( 10*cosf(t), 8, 10*sinf(t)
m_matView = glm::lookAt(glm::vec3( 10, 10, 10), // honnan nézzük a színteret
glm::vec3( 0, 0, 0), // a színtér melyik pontját nézzük
glm::vec3( 0, 1, 0)); // felfelé mutató irány a világban
}
void CMyApp::Render()
{
// töröljük a frampuffert (GL_COLOR_BUFFER_BIT) és a mélységi Z puffert (GL_DEPTH_BUFFER_BIT)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// shader bekapcsolasa, ebben a projektben a teljes programot jelöli, hisz nem váltunk a shaderek között
glUseProgram(m_programID);
// shader parameterek beállítása
/*
GLM transzformációs mátrixokra példák:
glm::rotate<float>( szög, glm::vec3(tengely_x, tengely_y, tengely_z) ) <- tengely_{xyz} körüli elforgatás
glm::translate<float>( glm::vec3(eltol_x, eltol_y, eltol_z) ) <- eltolás
glm::scale<float>( glm::vec3(s_x, s_y, s_z) ) <- léptékezés
*/
m_matWorld = glm::mat4(1.0f);
glm::mat4 mvp = m_matProj * m_matView * m_matWorld;
// majd küldjük át a megfelelő mátrixot!
// Uniform változó bindolása csak a program bindolása után lehetséges! (glUseProgram() )
glUniformMatrix4fv(m_loc_mvp,// erre a helyre töltsünk át adatot
1, // egy darab mátrixot
GL_FALSE, // NEM transzponálva
&(mvp[0][0])); // innen olvasva a 16 x sizeof(float)-nyi adatot
// kapcsoljuk be a VAO-t (a VBO jön vele együtt)
glBindVertexArray(m_vaoID);
// kirajzolás
//A draw hívásokhoz a VAO és a program bindolva kell legyenek (glUseProgram() és glBindVertexArray())
glDrawElements(GL_TRIANGLES, // primitív típus
3 * 2 * (N) * (M), // hany csucspontot hasznalunk a kirajzolashoz
GL_UNSIGNED_SHORT, // indexek tipusa
0); // indexek cime
/*
a kis tórusz külső (legnagyobb) köre (r+R+r)*size sugarú kör =>
(2r+R)*size * 2*M_PI hosszan gurul míg körbe ér
a nagy tórusz legfelső körén gurul, ami R sugarú kör =>
R * 2*M_PI
a kis tóruszok ezt a távot 3 mp alatt teszik meg
arány: nagy/kicsi = (R*2*M_PI) / ((2r+R)*size * 2*M_PI)
a kis tóruszoknak az arányszámmal többet kell fordulniuk adott idő alatt,
hogy ugyanannyi utat tegyenek meg, mint a nagy tórusz felső köre
*/
const int n = 5;
const float size = 0.15f; // kis tóruszok méretaránya a nagyhoz képest
float ratio = (R * 2 * M_PI) / ((2 * r + R) * size * 2 * M_PI);
const float secs = 4.f; // ennyi idő alatt tesz meg egy kistórusz egy nagy kört
const float secs2 = secs / ratio; //ennyi idő alatt fordul körbe a kis tórusz a saját tengelye körül
float time = SDL_GetTicks() / 1000.0f;
float alpha = time * (2*M_PI) / secs;
float alpha2 = time * (2 * M_PI) / secs2;
for (int i = 0; i < n; i++) {
m_matWorld =
glm::rotate<float>(2 * M_PI / n * i, glm::vec3(0, 1, 0)) * // egyenlő távolságra legyenek
glm::rotate<float>(alpha, glm::vec3(0, 1, 0)) * // körvonalban forgása
glm::translate<float>(glm::vec3(R, r+size*(R+r), 0)) * // magasság: r /sugara a nagy torusznak/ + size(R+r) /fél magassága a kis torusznak/
glm::rotate<float>(-alpha2, glm::vec3(1, 0, 0)) * // kis tórusz forgása (saját tengelye körül)
glm::rotate<float>(M_PI/2.f, glm::vec3(0, 0, 1)) * // élére állít
glm::scale<float>(glm::vec3(size, size, size))
;
mvp = m_matProj * m_matView * m_matWorld;
glUniformMatrix4fv(m_loc_mvp, 1, GL_FALSE, &(mvp[0][0]));
glDrawElements(GL_TRIANGLES, 3 * 2 * (N) * (M), GL_UNSIGNED_SHORT, 0);
}
// VAO kikapcsolasa
glBindVertexArray(0);
// shader kikapcsolasa
glUseProgram( 0 );
}
void CMyApp::KeyboardDown(SDL_KeyboardEvent& key)
{
}
void CMyApp::KeyboardUp(SDL_KeyboardEvent& key)
{
}
void CMyApp::MouseMove(SDL_MouseMotionEvent& mouse)
{
}
void CMyApp::MouseDown(SDL_MouseButtonEvent& mouse)
{
}
void CMyApp::MouseUp(SDL_MouseButtonEvent& mouse)
{
}
void CMyApp::MouseWheel(SDL_MouseWheelEvent& wheel)
{
}
// a két paraméterbe az új ablakméret szélessége (_w) és magassága (_h) található
void CMyApp::Resize(int _w, int _h)
{
glViewport(0, 0, _w, _h);
m_matProj = glm::perspective( 45.0f, // 90 fokos nyilasszog
_w/(float)_h, // ablakmereteknek megfelelo nezeti arany
0.01f, // kozeli vagosik
100.0f); // tavoli vagosik
}