Les shaders peuvent-ils (et comment) peindre des pixels d'écran au-delà de ceux occupés par le maillage ombré?

8

J'ai une certaine expérience en programmation de géométrie et de calcul de shaders - mais je ne me suis jamais aventuré en jouant vraiment avec les shaders de fragments. Actuellement, j'essaie de mieux comprendre comment ils fonctionnent et leur potentiel. L'une des choses que j'ai lues à plusieurs endroits est qu'un fragment (c'est-à-dire un pixel d'écran) ne peut pas s'étendre au-delà de lui-même dans le fragment shader. Ce qui signifie qu'un fragment donné en cours d'itération ne peut qu'affecter lui-même.

Par conséquent, et dans un souci d'apprentissage, je voudrais savoir si ce qui suit est possible (et si c'est le cas, comment, en termes généraux, peut-il être réalisé). Supposons que nous ayons, par souci de simplicité, un maillage ponctuel composé de seulement deux sommets (situés dans l'espace 3D World). Pouvons-nous programmer un shader de telle sorte que chacun de ces deux sommets soit peint à l'écran à leur position exacte WorldToViewport, mais aussi qu'un cercle autour de chacun d'eux de rayon = R soit également peint dans les pixels environnants même s'ils s'étendent au-delà du maillage d'origine auquel le shader est attaché? Comme dans la figure ci-dessous (où le carré rouge au centre des cercles représente les sommets peints à l'écran):

entrez la description de l'image ici

Si cela est possible, un shader peut-il également être programmé de telle manière que ces cercles qui s'étendent au-delà des sommets influencent la couleur (RGBA) les uns des autres? Comme dans la figure ci-dessous:

entrez la description de l'image ici

Comme je l'ai dit, si ce sont des choses possibles, j'aimerais savoir un peu comment y parvenir - en termes conceptuels ou pratiques. Est-ce fait dans le shader de fragment, ou doit-il être calculé avant au shaders de vertex ou de géométrie? Comment calculer et passer des "fragments supplémentaires" qui s'étendent au-delà des fragments occupés par le corps maillé?

AndrewSteer
la source
Un shader de géométrie peut ajouter plus de primitives que celles trouvées dans le maillage d'origine. Est-ce que cela le fait pour vous?
Andreas

Réponses:

6

Lorsque vous utilisez la largeur de ligne ou l'anticrénelage de ligne ou la largeur de point ou les pointsprites, OpenGL crée pour vous un petit rectangle au lieu de la ligne ou du point, avec des coordonnées de texture. De nos jours, vous pouvez même le programmer vous-même en utilisant des shaders de géométrie ou même le tesselator.

Une approche totalement différente consiste à utiliser un ombrage différé, en utilisant un passage géométrique juste pour stocker des informations dans le tampon RGBAZ, puis un deuxième passage que vous exécutez sur tous les pixels de l'écran pour effectuer un processus. (pour agir sur tous les pixels, dessinez simplement un rectangle plein écran). De nos jours, vous pouvez même faire le premier passage comme un ou plusieurs "rendre à la texture", puis MIPmap ces textures, de sorte que le passage final puisse facilement accéder à moins de valeurs locales.

Fabrice NEYRET
la source
Merci! J'ai fait ce que vous avez dit au début, en utilisant des shaders de géométrie pour créer une géométrie autour des points et ainsi permettre de dessiner des pixels autour du point. Cela fonctionne, bien sûr, mais c'est une solution plus lourde. Je me suis particulièrement intéressé aux derniers morceaux de ce que vous avez dit: si je vous ai bien compris, ce que vous mentionnez, c'est que l'on pourrait rendre la scène entière, puis utiliser un ombrage d'écran visant la zone d'intérêt, puis faire un passage sur le cadre rendu afin de travailler sur combien de pixels on veut autour des points au centre?
AndrewSteer
Vous pouvez rendre le premier passage dans une texture. Ensuite, dans la deuxième passe en plein écran, dans chaque pixel, vous pouvez inspecter le contenu de la texture dans un disque autour du pixel et faire ce que vous voulez (par exemple, la couleur en fonction du pixel rempli le plus proche, ou peindre en blanc uniquement si la distance est inférieure à un certain seuil) . Bien sûr, pour dessiner des disques, c'est loin d'être le moyen le plus efficace ;-)
Fabrice NEYRET
Bien sûr, je viens de donner l'exemple simple auquel je pouvais penser. Mais oui, je pense que ce que vous dites est conforme à ce que j'ai pensé, c'est-à-dire le rendu d'une texture en une seule passe et ensuite nous avons les informations pour, dans d'autres passes, modifier les pixels par rapport à ce qui se trouve dans les pixels environnants . Merci beaucoup.
AndrewSteer
3

Une bonne façon d'organiser le tracé d'un cercle (ou d'une autre forme) pour chaque sommet d'un maillage consiste à utiliser l' instanciation de la géométrie . Il s'agit d'une fonction GPU qui permet de dessiner plusieurs instances (copies) d'un maillage à la fois, avec les sommets / indices du maillage donnés par un ensemble de tampons et un autre tampon de sommet qui peut fournir des données supplémentaires par instance. Le vertex shader peut être utilisé pour combiner les données des deux tampons de la manière que vous choisissez.

Pour être concret, dans votre cas, vous pouvez créer un maillage représentant un cercle du rayon souhaité, avec ses sommets spécifiés directement en coordonnées d'écran et centrés à l'origine. Ensuite, vous utiliseriez l'instanciation pour que le GPU rende une nouvelle copie du maillage circulaire pour chaque sommet de votre maillage ponctuel d'origine. Dans le vertex shader, vous calculez la position d'espace d'écran du point (en utilisant les transformations de vision du monde comme d'habitude), puis vous traduisez le maillage du cercle pour qu'il soit centré à cette position.

Quant à la deuxième partie de votre question, sur la façon dont les cercles s'influencent mutuellement: cela dépend de ce que vous voulez faire, en particulier. Le mélange de matériel peut être utilisé pour gérer des cas simples, tels que l'ajout ou la multiplication des couleurs, ou le mélange alpha. Si vous voulez quelque chose de plus compliqué que cela, alors il pourrait être possible de le faire avec un algorithme multi-passes ou (sur les derniers GPU) un mélange programmable.

Nathan Reed
la source