J'ai du mal à restituer un tas de valeurs à une cible de rendu. Les valeurs ne se retrouvent jamais dans la plage exacte que je souhaite. Fondamentalement, j'utilise un quadruple plein écran et un pixel shader pour effectuer le rendu sur ma texture de rendu cible, puis j'ai l'intention d'utiliser les coordonnées de texture comme base pour certains calculs dans le shader. Les coordonnées de texture de la plage quadruple de (0,0) en haut à gauche à (1,1) dans le coin inférieur droit ... le problème est, après interpolation, ces valeurs n'arrivent pas au pixel shader en tant que tel .
Un exemple: je rend une texture 4x4 et le shader dans ce cas produit simplement les coordonnées de texture (u, v) dans les canaux rouge et vert:
return float4(texCoord.rg, 0, 1);
Ce que je veux en retirer, c'est une texture où le pixel en haut à gauche est RGB (0,0,0) et donc noir, le pixel en haut à droite est RGB (255,0,0) et donc un brillant rouge et le pixel en bas à gauche est RVB (0,255,0) - un vert brillant.
Cependant, au lieu de cela, je le trouve ici à droite:
(rendu quadruple droit, pas de correction)
Le pixel supérieur gauche est noir, mais je n'obtiens qu'un rouge et un vert foncé relativement foncés dans les autres coins. Leurs valeurs RVB sont (191,0,0) et (0,191,0). Je soupçonne fortement que cela a à voir avec les emplacements d'échantillonnage du quad: le pixel supérieur gauche échantillonne correctement le coin supérieur gauche du quad et obtient (0,0) en coordonnées UV, mais les autres pixels d'angle ne sont pas échantillonnés à partir de les autres coins du quad. J'ai illustré cela dans l'image de gauche avec la boîte bleue représentant le quad et les points blancs les coordonnées d'échantillonnage supérieures.
Maintenant, je connais le décalage d'un demi-pixel que vous devez appliquer à vos coordonnées lors du rendu des quadrilatères alignés à l'écran dans Direct3D9. Voyons quel genre de résultat j'obtiens:
(rendu quad avec le décalage d'un demi-pixel de DX9)
Le rouge et le vert sont devenus plus lumineux mais ne sont toujours pas corrects: 223 est le maximum que j'obtiens sur le canal de couleur rouge ou vert. Mais maintenant, je n'ai même plus de noir pur, mais plutôt un gris foncé et jaunâtre avec RGB (32,32,0)!
Ce dont j'ai réellement besoin serait ce type de rendu:
(rendu cible, taille quad réduite)
Il semble que je doive déplacer le bord droit et le bord inférieur de mon quad exactement d'un pixel vers le haut et vers la gauche, par rapport à la première figure. Ensuite, la colonne de droite et la rangée inférieure de pixels devraient toutes obtenir correctement les coordonnées UV directement à partir de la bordure du quad:
VertexPositionTexture[] quad = new VertexPositionTexture[]
{
new VertexPositionTexture(new Vector3(-1.0f, 1.0f, 1f), new Vector2(0,0)),
new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, 1.0f, 1f), new Vector2(1,0)),
new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};
Cependant, cela n'a pas tout à fait fonctionné et a empêché le rendu des pixels inférieur et droit. Je suppose que les centres de ces pixels ne sont plus couverts par le quad et ne seront donc pas traités par le shader. Si je modifie le calcul de pixelSize par une petite quantité pour agrandir le quad, il fonctionne un peu ... au moins sur une texture 4x4. Cela ne fonctionne pas sur les textures plus petites et je crains que cela ne déforme subtilement la distribution uniforme des valeurs UV sur les textures plus grandes:
Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);
(J'ai modifié le calcul pixelSize de 0,001f - pour les textures plus petites, par exemple les tables de recherche 1D, cela ne fonctionne pas et je dois l'augmenter à 0,01f ou quelque chose de plus grand)
Bien sûr, ceci est un exemple trivial et je pourrais faire ce calcul beaucoup plus facilement sur le CPU sans avoir à se soucier de mapper les UV aux centres de pixels ... encore, il doit y avoir un moyen de rendre un rendu complet et complet [0, 1] plage de pixels sur une cible de rendu!?
Réponses:
Votre problème est que les UV sont conçus pour être des coordonnées de texture. Une coordonnée de 0,0 est le coin supérieur gauche du pixel supérieur gauche de la texture, qui n'est pas l'endroit où vous souhaitez normalement lire la texture. Pour 2D, vous voulez lire la texture au milieu de ce pixel.
Si mes calculs sont exacts, ce que vous devez faire pour contourner c'est:
return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);
Autrement dit, vous soustrayez le décalage approprié pour obtenir le pixel supérieur gauche à 0,0, puis appliquez une échelle pour obtenir le coin inférieur droit correct.
La même chose pourrait également être obtenue en augmentant les coordonnées UV pour la géométrie en dehors de la plage 0-1.
la source
return float4(texCoord.rg, 0, 1);
.Presque, mais seulement la moitié du pixel. Il suffit de soustraire 0,5 de vos sommets quadruples. Par exemple, vous voulez un quad 256x256 avec la même texture, voici vos points:
Vous pouvez également ajouter la moitié du texel dans le pixel shader (texCoord.rg + 0.5 * (1.0 / texSize))
Le décalage d'un demi-pixel est un fait connu dans DX9. Ceci et ces articles peuvent également vous aider.
la source
Cela est certainement dû à l'échantillonnage linéaire. Si vous regardez les texels à droite et en dessous du pixel noir en haut à gauche, vous verrez qu'ils ont 63 dans les canaux R et / ou G, et 2 d'entre eux en ont 2 dans B. Maintenant, regardez le boueux-jaune foncé vous obtenez; c'est 31 en R et G et 1 en B. C'est certainement le résultat de la moyenne des texels sur un groupe 2x2, donc la solution est de régler votre filtre de texture au point.
la source
C'est simplement parce que vous utilisez les texCoords de la sortie de vertex qui sont interpolés par le disque dur après le traitement du vertex shader.
la source