Recherche…


Bases de texturation

Une texture est une forme de stockage de données qui permet un accès pratique non seulement à des entrées de données particulières, mais également à des échantillons de points mélangeant (interpolant) plusieurs entrées.

Dans OpenGL, les textures peuvent être utilisées pour beaucoup de choses, mais le plus souvent, elles mappent une image sur un polygone (par exemple un triangle). Afin de mapper la texture sur un triangle (ou un autre polygone), nous devons indiquer à chaque sommet la partie de la texture à laquelle il correspond. Nous assignons une coordonnée de texture à chaque sommet d'un polygone et celle-ci sera ensuite interpolée entre tous les fragments de ce polygone. Les coordonnées de texture sont généralement comprises entre 0 et 1 dans les axes x et y, comme illustré ci-dessous:

coordonnées de texture

Les coordonnées de texture de ce triangle ressembleraient à ceci:

GLfloat texCoords[] = {
    0.0f, 0.0f,  // Lower-left corner  
    1.0f, 0.0f,  // Lower-right corner
    0.5f, 1.0f   // Top-center corner
};

Mettez ces coordonnées dans VBO (objet tampon de vertex) et créez un nouvel attribut pour le shader. Vous devriez déjà avoir au moins un attribut pour les positions de sommet, créez-en une autre pour les coordonnées de texture.


Générer de la texture

La première chose à faire sera de générer un objet texture qui sera référencé par un identifiant qui sera stocké dans une texture int non signée:

GLuint texture;
glGenTextures(1, &texture); 

Après cela, il doit être lié pour que toutes les commandes de texture suivantes configurent cette texture:

glBindTexture(GL_TEXTURE_2D, texture); 

Chargement de l'image

Pour charger une image, vous pouvez créer votre propre chargeur d'image ou vous pouvez utiliser une bibliothèque de chargement d'image telle que SOIL (Simple OpenGL Image Library) dans c ++ ou PNGDecoder de TWL dans Java.

Un exemple de chargement d'image avec SOIL serait:

int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB); 

Vous pouvez maintenant affecter cette image à l'objet texture:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

Après cela, vous devez dissocier l'objet texture:

glBindTexture(GL_TEXTURE_2D, 0); 

Paramètre Wrap pour les coordonnées de texture

Comme vu ci-dessus, le coin inférieur gauche de la texture a les coordonnées UV (st) (0, 0) et le coin supérieur droit de la texture a les coordonnées (1, 1), mais les coordonnées de texture d'un maillage peuvent être dans toute gamme. Pour gérer cela, il faut définir comment les coordonnées de texture sont enveloppées dans la texture.

Le paramètre wrap de la coordonnée de texture peut être défini avec glTextureParameter à l' aide de GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T et 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);

Les paramètres possibles sont:

  • GL_CLAMP_TO_EDGE provoque le GL_CLAMP_TO_EDGE des coordonnées de la texture dans la plage [1 / 2N, 1 - 1 / 2N] , où N est la taille de la texture dans la direction.

  • GL_CLAMP_TO_BORDER fait la même chose que GL_CLAMP_TO_EDGE , mais dans les cas où le blocage, les données de texel récupérées sont remplacées par la couleur spécifiée par GL_TEXTURE_BORDER_COLOR .

  • GL_REPEAT fait en sorte que la partie entière de la coordonnée de texture soit ignorée. La texture est en mosaïque .

répéter la texture

  • GL_MIRRORED_REPEAT : Si la partie entière de la coordonnée de texture est paire, alors elle est ignorée. Contrairement à, si la partie entière de la coordonnée de texture est impaire, la coordonnée de texture est définie sur 1 - frac (s) . fract (s) est la partie fractionnaire de la coordonnée de texture. Cela fait que la texture est reflétée toutes les 2 fois.

texture miroir

  • GL_MIRROR_CLAMP_TO_EDGE provoque la répétition de la coordonnée textue comme pour GL_MIRRORED_REPEAT pour une reptition de la texture, point auquel la coordonnée doit être bloquée comme dans GL_CLAMP_TO_EDGE .

Notez que la valeur par défaut pour GL_TEXTURE_WRAP_S , GL_TEXTURE_WRAP_T et GL_TEXTURE_WRAP_R est GL_REPEAT .


Appliquer des textures

La dernière chose à faire est de lier la texture avant l'appel de dessin:

glBindTexture(GL_TEXTURE_2D, texture);

Texture et tampon

Vous pouvez attacher une image dans une texture à un framebuffer, de sorte que vous pouvez rendre directement à cette texture.

glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
                       GL_COLOR_ATTACHMENT0,
                       GL_TEXTURE_2D,
                       texture,
                       0);

Remarque: vous ne pouvez pas lire et écrire à partir de la même texture dans la même tâche de rendu, car elle appelle un comportement non défini. Mais vous pouvez utiliser: glTextureBarrier() entre les appels de rendu pour cela.

Lire les données de texture

Vous pouvez lire les données de texture avec la fonction 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);

Remarque: le type de texture et le format ne sont que par exemple et peuvent être différents.

Utiliser les PBO

Si vous liez un tampon à GL_PIXEL_UNPACK_BUFFER le paramètre data de glTexImage2D est un décalage dans ce tampon.

Cela signifie que glTexImage2D n'a pas besoin d'attendre que toutes les données soient copiées hors de la mémoire de l'application avant de pouvoir revenir, réduisant ainsi la surcharge dans le thread principal.

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);

Mais où les PBO brillent vraiment, c'est lorsque vous devez lire le résultat d'un rendu dans la mémoire de l'application. Pour lire les données de pixel dans un tampon, liez-le à GL_PIXEL_PACK_BUFFER puis le paramètre data de glGetTexImage sera un décalage dans ce tampon:

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);

}

Utiliser des textures dans les shaders GLSL

Le vertex shader n'accepte que les coordonnées de texture en tant qu'attribut de sommet et transmet les coordonnées au fragment shader. Par défaut, cela garantira également que le fragment recevra la coordonnée correctement interpolée en fonction de sa position dans un triangle:

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;
}

Le fragment shader accepte alors la variable de sortie texCoord tant que variable d'entrée. Vous pouvez ensuite ajouter une texture au fragment shader en déclarant un uniform sampler2D . Pour échantillonner un fragment de la texture, nous utilisons une texture fonction intégrée dotée de deux paramètres. Le premier est la texture dont nous voulons échantillonner et le second est la coordonnée de cette texture:

in vec2 texCoordOut;

out vec4 color;

uniform sampler2D image;

void main()
{
    color = texture(image, texCoordOut);
}

Notez que l' image n'est pas l'id de texture directe ici. C'est l'id de l' unité de texture qui sera échantillonnée. À leur tour, les textures ne sont pas liées directement aux programmes; ils sont liés aux unités de texture. Ceci est obtenu en rendant d'abord l'unité de texture active avec glActiveTexture , puis en appelant glBindTexture affectera cette unité de texture particulière. Cependant, comme l'unité de texture par défaut est l'unité de texture 0 , les programmes utilisant une texture peuvent être simplifiés en omettant cet appel.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow