Il a été suggéré à plusieurs reprises dans les commentaires, mais personne n'a ressenti le besoin de donner une réponse appropriée.Par souci d'exhaustivité, une solution simple et courante à ce problème pourrait être d'utiliser une texture comme table de recherche, en particulier une texture 1D qui contient toutes les valeurs de votre fonction pour la plage d'entrée possible (c'est-à-dire / ]. Cela présente divers avantages:[ 0 , 2 π )[0,360)[0,2π)
- Il utilise des coordonnées normalisées, c'est-à-dire que vous accédez à la texture en mappant vos angles de à . Cela signifie que votre shader n'a pas réellement à se soucier de la quantité spécifique de valeurs . Vous pouvez ajuster sa taille en fonction du compromis mémoire / vitesse / qualité souhaité (et en particulier sur le matériel ancien / intégré, vous voudrez peut-être une puissance de deux comme taille de texture).[ 0 , 1 ][0,360][0,1]
- Vous obtenez l'avantage supplémentaire de ne pas avoir à effectuer votre ajustement d'intervalle de type boucle (bien que vous n'ayez pas besoin de boucles de toute façon et que vous puissiez simplement utiliser une opération de module). Il suffit de l'utiliser
GL_REPEAT
comme mode d'habillage pour la texture et elle recommencera automatiquement au début lors de l'accès avec des arguments> 1 (et de même pour les arguments négatifs).
- Et vous bénéficiez également de l' interpolation linéaire entre deux valeurs du tableau, essentiellement gratuitement (ou disons presque gratuitement) en utilisant
GL_LINEAR
comme filtre de texture, de cette manière, vous obtenez des valeurs que vous n'avez même pas stockées. Bien sûr, l'interpolation linéaire n'est pas précise à 100% pour les fonctions trigonométriques, mais c'est certainement mieux que pas d' interpolation.
- Vous pouvez stocker plusieurs valeurs dans la texture en utilisant une texture RGBA (ou le nombre de composants dont vous avez besoin). De cette façon, vous pouvez obtenir, par exemple, sin et cos avec une seule recherche de texture.
- Pour sin et cos, vous n'avez de toute façon qu'à stocker des valeurs dans , que vous pouvez naturellement mettre à l' échelle à partir de la plage normalisée d'un format à virgule fixe 8 bits commun. Cependant, cela pourrait ne pas être assez précis pour vos besoins. Certaines personnes ont suggéré d'utiliser des valeurs à virgule flottante 16 bits, car elles sont plus précises que les valeurs à virgule fixe normalisées 8 bits habituelles mais moins gourmandes en mémoire que les flottants 32 bits réels. Mais là encore, je ne sais pas non plus si votre implémentation prend en charge les textures à virgule flottante pour commencer. Sinon, vous pouvez peut-être utiliser 2 composants à virgule fixe de 8 bits et les combiner en une seule valeur avec quelque chose comme (ou même plus de composants pour un grain plus fin). Cela vous permet de profiter à nouveau des textures multi-composants.[ 0 , 1 ][−1,1][0,1]
float sin = 2.0 * (texValue.r + texValue.g / 256.0) - 1.0;
Bien sûr, il reste à évaluer si c'est une meilleure solution, car l'accès aux textures n'est pas entièrement gratuit non plus, ainsi que la meilleure combinaison de taille et de format de texture.
En ce qui concerne le remplissage de la texture avec des données et l'adressage d'un de vos commentaires, vous devez considérer que le filtrage de texture renvoie la valeur exacte au centre du texel , c'est-à-dire une coordonnée de texture décalée de la moitié de la taille du texel. Alors oui, vous devez générer des valeurs au niveau des .5
texels , c'est-à-dire quelque chose comme ça dans le code d'application:
float texels[256];
for(unsigned int i = 0; i < 256; ++i)
texels[i] = sin((i + .5f) / 256.f) * TWO_PI);
glTexImage1D(GL_TEXTURE_1D, 0, ..., 256, 0, GL_RED, GL_FLOAT, texels);
Cependant, vous souhaiterez peut-être toujours comparer les performances de cette approche avec une approche utilisant un petit tableau uniforme (c'est-à uniform float sinTable[361]
- dire , ou peut-être moins en pratique, gardez un œil sur la limite de votre implémentation sur la taille du tableau uniforme) que vous chargez simplement avec les valeurs respectives en utilisant glUniform1fv
et accédez en ajustant votre angle à utilisant la fonction et en l'arrondissant à la valeur la plus proche:[0,360)mod
angle = mod(angle, 360.0);
float value = sinTable[int(((angle < 0.0) ? (angle + 360.0) : angle) + 0.5)];