opengl
texturering
Sök…
Grunderna i textureringen
En struktur är en form av datalagring som tillåter bekväm åtkomst, inte bara till specifika datainmatningar, utan också till sampelpunkter som blandar (interpolerar) flera poster tillsammans.
I OpenGL kan strukturer användas för många saker, men oftast är det att kartlägga en bild till en polygon (till exempel en triangel). För att kartlägga strukturen till en triangel (eller annan polygon) måste vi berätta för varje toppunkt vilken del av strukturen den motsvarar. Vi tilldelar en texturskoordinat till varje topp av en polygon och den interpoleras sedan mellan alla fragment i den polygonen. Texturkoordinater sträcker sig vanligtvis från 0 till 1 i x- och y-axeln, som visas på bilden nedan:
Strukturkoordinaterna för den här triangeln skulle se ut så här:
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
Sätt de koordinaterna i VBO (vertexbuffertobjekt) och skapa ett nytt attribut för skuggaren. Du bör redan ha minst ett attribut för toppunktpositionerna så skapa ett annat för texturkoordinaterna.
Generera konsistens
Det första som ska göras är att generera ett texturobjekt som kommer att refereras av ett ID som kommer att lagras i en osignerad int- struktur :
GLuint texture;
glGenTextures(1, &texture);
Efter det måste den bindas så att alla efterföljande texturkommandon konfigurerar denna textur:
glBindTexture(GL_TEXTURE_2D, texture);
Laddar bild
För att ladda en bild kan du skapa din egen bildläsare eller använda ett bildbelastningsbibliotek som SOIL (Simple OpenGL Image Library) i c ++ eller TWL: s PNGDecoder i java.
Ett exempel på att ladda bild med SOIL skulle vara:
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
Nu kan du tilldela denna bild till texturobjektet:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
Efter det bör du ta bort texturobjektet:
glBindTexture(GL_TEXTURE_2D, 0);
Radera parameter för texturkoordinater
Som ses ovan har det nedre vänstra hörnet av strukturen UV (st) -koordinaterna (0, 0) och det övre högra hörnet av strukturen har koordinaterna (1, 1), men strukturens koordinater kan vara i valfritt område. För att hantera detta måste det definieras hur texturkoordinaterna lindas till strukturen.
Wrap-parametern för texturkoordinaten kan ställas in med glTextureParameter med GL_TEXTURE_WRAP_S
, GL_TEXTURE_WRAP_T
och 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 möjliga parametrarna är:
GL_CLAMP_TO_EDGE
gör att texturkoordinaterna fastklämmas till intervallet [1 / 2N, 1 - 1 / 2N] , där N är storleken på texturen i riktningen.GL_CLAMP_TO_BORDER
gör samma sak somGL_CLAMP_TO_EDGE
, men i de fallGL_CLAMP_TO_EDGE
den hämtade texeldata med den färg som anges avGL_TEXTURE_BORDER_COLOR
.GL_REPEAT
gör att heltalets del av texturkoordinaten ignoreras. Konsistensen är kaklat .
-
GL_MIRRORED_REPEAT
: Om heltalets del av texturkoordinaten är jämn, ignoreras den. I motsats till, om heltalets del av texturkoordinaten är udda, är texturkoordinaten inställd på 1 - frac (s) . frakt (er) är bråkdelen av texturkoordinaten. Det gör att strukturen speglas varannan gång.
-
GL_MIRROR_CLAMP_TO_EDGE
får textkoordinaten att upprepas som förGL_MIRRORED_REPEAT
för en reptition av strukturen, vid vilken punkt koordinaten ska klämmas fast som iGL_CLAMP_TO_EDGE
.
Observera att standardvärdet för GL_TEXTURE_WRAP_S
, GL_TEXTURE_WRAP_T
och GL_TEXTURE_WRAP_R
är GL_REPEAT
.
Applicera strukturer
Det sista att göra är att binda strukturen innan dragningen:
glBindTexture(GL_TEXTURE_2D, texture);
Textur och Framebuffer
Du kan fästa en bild i en struktur till en bildbuffer, så att du kan återge direkt till den strukturen.
glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture,
0);
Obs! Du kan inte läsa och skriva från samma struktur i samma renderingsuppgift, eftersom det kallar odefinierat beteende. Men du kan använda: glTextureBarrier()
mellan återgivna samtal för detta.
Läs textdata
Du kan läsa texturdata med funktionen 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);
Obs! Texturtyp och format är bara till exempel och kan vara olika.
Använda PBO: er
Om du binda en buffert till GL_PIXEL_UNPACK_BUFFER
då data
parametern i glTexImage2D
är en förskjutning i denna buffert.
Detta betyder att glTexImage2D inte behöver vänta på att all data kopieras ur programminnet innan den kan återgå, vilket reducerar omkostnaderna i huvudtråden.
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);
Men där PBO: er verkligen lyser är när du behöver läsa resultatet av en render tillbaka till applikationsminnet. För att läsa pixeldata till en buffert binder den till GL_PIXEL_PACK_BUFFER
då kommer glGetTexImage
för glGetTexImage
att vara en förskjutning i den bufferten:
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);
}
Använda strukturer i GLSL-skuggare
Korsskärmarna accepterar endast texturkoordinaterna som ett toppskyddsattribut och vidarebefordrar koordinaterna till fragmentskäraren. Som standard garanterar det också att fragmentet får den korrekt interpolerade koordinaten baserat på dess position i en triangel:
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;
}
Fragmentet shader accepterar sedan texCoord
utgångsvariabeln som en inmatningsvariabel. Du kan sedan lägga till en textur i fragmentet genom att förklara en uniform sampler2D
. Att prova ett fragment av texturen använder vi en inbyggd funktion texture
som har två parametrar. Den första är den textur vi vill ta prov från och den andra är koordinaten för denna textur:
in vec2 texCoordOut;
out vec4 color;
uniform sampler2D image;
void main()
{
color = texture(image, texCoordOut);
}
Observera att image
inte är den direkta textur-ID här. Det är id för texturenheten som kommer att samplas. I sin tur är strukturer inte bundna till program direkt; de är bundna till texturenheter. Detta uppnås genom att först göra texturenheten aktiv med glActiveTexture
, och sedan ringa glBindTexture
kommer att påverka denna speciella texturenhet. Eftersom standardkonstruktionsenheten är texturenhet 0
, kan program som använder en struktur dock göras enklare att undvika detta samtal.