Igértem, hogy írom a bugról, amit Jimmy segített megoldani. A hiba a point sprite-okkal volt.
A point sprite a legegyszerűbb a megjeleníthető alakzatok közül, mert egy fix méretű folt a képernyőn, de nagyon sok lehetőséget rejt magában, főleg ha shaderekkel megbolondítjuk.
Az alapja egyszerű, kell egy vertex array, amiben egyedül a pontok koordinátáit kell elhelyezni. Természetesen ha egy részecske rendszert akarunk, akkor további attribútumokat is pakolhatunk a koordináták mellé, de most ezzel nem foglalkozom.
Először lehetővé kell tennünk, hogy a shaderünk teljes egészében kezelhesse a point sprite megjelenését:
glEnable(GL_PROGRAM_POINT_SIZE);
Ezután fel kell tölteni egy puffert koordinátákkal. Ez teljesen olyan, mint amit bármelyik más OpenGL programban is találunk:
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, buffer);
glBindBuffer(GL_ARRAY_BUFFER, &buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 3 * count, &pos[0], GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
A megjelenítés is nagyon egyszerű:
glUseProgram(shader);
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, count);
De mi legyen a shader-ben? Itt kezdődnek a lehetőségek. A tutorialok ki is merülnek abban, hogy leírják a vertex shadert és a fragment shadert. De nagyon kevés szó esik a geometry shaderről, pedig azzal lehet csak igazán megbolondítani a pontjainkat.
A vertex shader nagyon egyszerű:
#version 450
layout (location = 1) in vec3 vertex;
void main(){
gl_Position = vec4(vertex, 1.0);
}
A legtöbb tutorial ide helyezi a point sprite méretét meghatározó változó értékadását. A változó neve gl_PointSize. Ez pixelben meghatározza, hogy mekkora legyen a képernyőn a sprite-unk. Ha nincs geometry shaderünk, továbbra is itt kell beállítani.
De miért jó a geometry shader? Egyáltalán minek kell? A geometry shaderrel megváltoztathatjuk a pontunkat. Például több pontot csinálunk belőle! Esetleg háromszöggé változtatjuk azt. Különböző méretű pontokat készítünk.
#version 450
layout (points) in;
layout (points, max_vertices = 1) out;
void main() {
gl_Position = gl_in[0].gl_Position;
gl_PointSize = 6.0;
EmitVertex();
EndPrimitive();
}
A layout in és out határozza meg, mi legyen a be és kilépő geometria. A fenti példában ezek pontok, de semmi nem akadályozza meg, hogy kilépésnél vonal, háromszög vagy négyszög legyen. Ha több geometriát is akarunk kimenetnek, akkor a max_vertices értéket ennek megfelelően emelni kell. A főmenüben kell definiálni a pont tulajdonságait. Először a koordinátáit a gl_Position-al, majd a méretét. Ez nem volt nekem tiszta. Bár utólag logikus, hiszen én több pontot is készíthetek, azok nem fogják "örökölni" a tulajdonságokat a vertex shaderből, hanem nekem kell beállítanom. A két végső utasítás az EmitVertex() és az EndPrimitive(). Pontok esetén primitívenként egy vertexet tudunk létrehozni, háromszögek esetén háromszor annyi EmitVertex utasítás kell, mint EndPrimitive.
Végezetül jöjjön a fragment shader, ahol a pont megjelenését tudjuk befolyásolni. A legunalmasabb fragment shader, amit csak létezik a következő:
#version 450
layout (location = 0) out vec4 FragColor;
void main(void){
FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
Egy fehér négyzetet fogunk látni, olyan méretben, ahogy a gl_PointSize-al megadtuk. A gl_PointCoord viszont ad nekünk pozíciót a ponton belül. Ezt használhatjuk például textúrázásra, ahogy a legtöbb internetes példa említeni szokta. Ha nem akarunk textúrázni, akkor is hasznunkra lehet, ha a discard-ot használjuk.
#version 450
layout (location = 0) out vec4 FragColor;
void main(void){
float d = distance(gl_PointCoord, vec2(0.5));
if(d > 0.5) discard;
else FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
Az eredmény szép kör alakú pontok lesznek. Kísérletezzünk bátran egyéb módszerekkel!
















