Zoeken…
Basisprincipes van texturen
Een texture is een vorm van gegevensopslag die gemakkelijke toegang mogelijk maakt, niet alleen tot bepaalde gegevensinvoer, maar ook voor monsterpunten waarbij meerdere gegevens worden gecombineerd (geïnterpoleerd).
In OpenGL kunnen texturen voor veel dingen worden gebruikt, maar meestal wordt een afbeelding toegewezen aan een polygoon (bijvoorbeeld een driehoek). Om de textuur aan een driehoek (of een andere polygoon) toe te wijzen, moeten we elk hoekpunt vertellen met welk deel van de textuur het overeenkomt. We wijzen een textuurcoördinaat toe aan elk hoekpunt van een polygoon en deze wordt vervolgens geïnterpoleerd tussen alle fragmenten in die polygoon. Textuurcoördinaten variëren meestal van 0 tot 1 op de x- en y-as, zoals weergegeven in de onderstaande afbeelding:
De textuurcoördinaten van deze driehoek zien er als volgt uit:
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
Plaats die coördinaten in VBO (hoekpuntbufferobject) en maak een nieuw kenmerk voor de arcering. U moet al ten minste één kenmerk hebben voor de hoekpuntposities, dus maak een ander kenmerk voor de textuurcoördinaten.
Textuur genereren
Het eerste wat u moet doen, is een textuurobject genereren waarnaar wordt verwezen door een ID dat wordt opgeslagen in een niet-ondertekende textuur :
GLuint texture;
glGenTextures(1, &texture);
Daarna moet het worden gebonden, zodat alle volgende texture-opdrachten deze texture configureren:
glBindTexture(GL_TEXTURE_2D, texture);
Afbeelding wordt geladen
Om een afbeelding te laden kunt u uw eigen afbeeldinglader maken of u kunt een bibliotheek voor het laden van afbeeldingen gebruiken, zoals SOIL (Simple OpenGL Image Library) in c ++ of TWL's PNGDecoder in Java.
Een voorbeeld van het laden van afbeeldingen met SOIL zou zijn:
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
Nu kunt u deze afbeelding toewijzen aan het textuurobject:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
Daarna moet u het textuurobject losmaken:
glBindTexture(GL_TEXTURE_2D, 0);
Wrap-parameter voor textuurcoördinaten
Zoals hierboven te zien, heeft de linkeronderhoek van de textuur de UV (st) -coördinaten (0, 0) en de rechterbovenhoek van de textuur heeft de coördinaten (1, 1), maar de textuurcoördinaten van een mesh kunnen binnen zijn elk bereik. Om dit af te handelen, moet worden gedefinieerd hoe de textuurcoördinaten in de textuur worden gewikkeld.
De wrap-parameter voor de textuurcoördinaat kan worden ingesteld met glTextureParameter met behulp van GL_TEXTURE_WRAP_S
, GL_TEXTURE_WRAP_T
en GL_TEXTURE_WRAP_R
.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
De mogelijke parameters zijn:
GL_CLAMP_TO_EDGE
zorgt ervoor dat de textuurcoördinaten worden geklemd in het bereik [1 / 2N, 1 - 1 / 2N] , waarbij N de grootte van de textuur in de richting is.GL_CLAMP_TO_BORDER
doet hetzelfde alsGL_CLAMP_TO_EDGE
, maar in geval van klemmen worden de opgehaalde texel-gegevens vervangen door de kleur gespecificeerd doorGL_TEXTURE_BORDER_COLOR
.GL_REPEAT
zorgt ervoor dat het gehele deel van de textuurcoördinaat wordt genegeerd. De textuur is betegeld .
-
GL_MIRRORED_REPEAT
: Als het gehele deel van de textuurcoördinaat even is, wordt het genegeerd. In tegenstelling tot, als het gehele deel van de textuurcoördinaat oneven is, wordt de textuurcoördinaat ingesteld op 1 - frac (s) . fractuur (s) is het fractionele deel van de textuurcoördinaat. Dat zorgt ervoor dat de textuur elke 2e keer wordt gespiegeld .
-
GL_MIRROR_CLAMP_TO_EDGE
zorgt ervoor dat de tekstcoördinaat wordt herhaald zoals voorGL_MIRRORED_REPEAT
voor één herhaling van de textuur, op welk punt de coördinaat wordt vastgeklemd zoals inGL_CLAMP_TO_EDGE
.
Let op de standaardwaarde voor GL_TEXTURE_WRAP_S
, GL_TEXTURE_WRAP_T
en GL_TEXTURE_WRAP_R
is GL_REPEAT
.
Texturen toepassen
Het laatste wat je moet doen, is de textuur binden voor de tekenaanroep:
glBindTexture(GL_TEXTURE_2D, texture);
Textuur en Framebuffer
U kunt een afbeelding in een textuur aan een framebuffer koppelen, zodat u direct naar die textuur kunt renderen.
glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture,
0);
Opmerking: u kunt niet lezen en schrijven vanuit dezelfde textuur in dezelfde rendertaak, omdat deze ongedefinieerd gedrag aanroept. Maar u kunt hiervoor gebruik maken: glTextureBarrier()
tussen render-aanroepen.
Lees textuurgegevens
U kunt glGetTexImage
lezen met de functie glGetTexImage
:
char *outBuffer = malloc(buf_size);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glGetTexImage(GL_TEXTURE_2D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
outBuffer);
Opmerking: textuurtype en -indeling zijn alleen bijvoorbeeld en kunnen verschillen.
PBO's gebruiken
Als u een buffer aan GL_PIXEL_UNPACK_BUFFER
is de data
in glTexImage2D
een offset in die buffer.
Dit betekent dat de glTexImage2D niet hoeft te wachten tot alle gegevens uit het geheugen van de toepassing zijn gekopieerd voordat deze kunnen terugkeren, waardoor de overhead in de hoofdthread wordt verminderd.
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*3, NULL, GL_STREAM_DRAW);
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
//write data into the mapped buffer, possibly in another thread.
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
memcpy(mappedBuffer, image, width*height*3);
SOIL_free_image(image);
// after reading is complete back on the main thread
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
Maar waar PBO's echt schitteren, is wanneer je het resultaat van een render terug moet lezen in het toepassingsgeheugen. Als u pixelgegevens in een buffer wilt lezen, bindt u deze aan GL_PIXEL_PACK_BUFFER
dan wordt de gegevensparameter van glGetTexImage
een offset in die buffer:
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, NULL, GL_STREAM_COPY);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glGetTexImage(GL_TEXTURE_2D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
null);
//ensure we don't try and read data before the transfer is complete
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// then regularly check for completion
GLint result;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(result), NULL, &result);
if(result == GL_SIGNALED){
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
void* mappedBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
//now mapped buffer contains the pixel data
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
Texturen gebruiken in GLSL-shaders
De hoekpuntschaduw accepteert alleen de textuurcoördinaten als een hoekpuntkenmerk en stuurt de coördinaten door naar de fragmentschaduw. Standaard zal het ook garanderen dat het fragment de correct geïnterpoleerde coördinaat ontvangt op basis van zijn positie in een driehoek:
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoordIn;
out vec2 texCoordOut;
void main()
{
gl_Position = vec4(position, 1.0f);
texCoordOut = texCoordIn;
}
De fragment-arcering accepteert dan de texCoord
uitvoervariabele als een invoervariabele. U kunt vervolgens een textuur aan de fragment-arcering toevoegen door een uniform sampler2D
. Een fragment van de textuur proeven gebruiken we een ingebouwde functie texture
waarin twee parameters heeft. Ten eerste is de textuur waarvan we een monster willen nemen en de tweede is de coördinaat van deze textuur:
in vec2 texCoordOut;
out vec4 color;
uniform sampler2D image;
void main()
{
color = texture(image, texCoordOut);
}
Merk op dat de image
hier niet de directe textuur-ID is. Het is het ID van de texture-eenheid die wordt bemonsterd. Op hun beurt zijn texturen niet direct aan programma's gebonden; ze zijn gebonden aan textuureenheden. Dit wordt bereikt door eerst de texture-eenheid actief te maken met glActiveTexture
en vervolgens glBindTexture
roepen glBindTexture
deze specifieke texture-eenheid te beïnvloeden. Omdat de standaardtexture-eenheid texture-eenheid 0
, kunnen programma's die één texture gebruiken eenvoudiger worden gemaakt om deze oproep weg te laten.