9
votes

Dessiner une image à l'aide de la précision du niveau de sous-pixel à l'aide de graphiques2D

Je tente actuellement de dessiner des images à l'écran à un rythme régulier comme dans un jeu vidéo.

Malheureusement, en raison de la vitesse à laquelle l'image bouge, des cadres sont identiques car l'image n'a pas encore été déplacée. un pixel complet.

existe un moyen de fournir des valeurs float à graphiques2D pour une position à l'écran pour dessiner l'image, plutôt que int valeurs?

Initialement ici est ce que j'avais fait: xxx

Ceci des seuils de cours, de sorte que l'image ne se déplace pas entre les pixels, mais saute d'un à Le suivant.

La méthode suivante consistait à régler la couleur de la peinture sur une texture et dessinez à une position spécifiée. Malheureusement, cela produisait des résultats incorrects qui ont montré un carrelage plutôt que correct antialiasing. xxx

Que dois-je faire pour atteindre l'effet souhaité du rendu de sous-pixel d'une image en Java?


0 commentaires

4 Réponses :


0
votes

Modifier la résolution de votre image en conséquence, il n'y a pas de bitmap avec des coordonnées sous-pixels, de sorte que ce que vous pouvez effectuer est de créer une image en mémoire plus grande que ce que vous voulez rendre rendu à l'écran, mais vous permet " Sous-pixel "Précision.

Lorsque vous dessinez à l'image plus grande en mémoire, vous copiez et rééchantillonnez cela dans le plus petit rendu visible à l'utilisateur final.

Par exemple: une image 100x100 et c'est une contrepartie redimensionnée / réaménagée 50x50:

Récupération

voir: http://fr.wikipedia.org/wiki/resampling_%28Bitmap % 29


5 commentaires

Cela implémente également un double tampon, de sorte que vous pouvez effectuer plusieurs révisions dans l'image en mémoire en mémoire tout en ne mettant pas à jour l'interface utilisateur qui peut être un processeur intense


Image d'une balle se déplaçant sur l'écran, mais sa déplacement très lentement. Son émouvant 1 pixel chaque seconde. Si je dessine 2 fois à l'écran chaque seconde, la deuxième fois, le dessin sera exactement le même que la première fois. La troisième fois montrera la balle qui aurait déplacé un pixel en une étape. Ce que je veux à la place, c'est que la balle soit déplacée partiellement pour qu'elle puisse être dessinée comme si elle se trouvait entre les deux pixels. Cette fonctionnalité est-elle disponible en Java?


Vous devez l'imiter à l'aide du processus ci-dessus. Donc, disent que votre zone de rendu est de 800x600, vous avez besoin d'une image en mémoire de mémoire 2X qui - 1600x1200 - et au lieu de vous déplacer au niveau du point flottant, vous déplacez des pixels entiers ... donc au lieu de déplacer une boule de 0,5 px Vous le déplacez 1px dans l'image à base de mémoire la plus grande, et lorsque vous le rééchappiez dans la zone visible (800x600), il sera émulé de précision du sous-pixel.


Oh! Je vois ce que tu veux dire. Est-ce que cette mémoire est efficace?


Il doit y avoir une autre façon d'obtenir l'effet anti-aliasing sans avoir à doubler chaque dimension!



3
votes

Vous pouvez composer l'image vous-même utilisant une précision du sous-pixel, mais c'est plus de travail de votre part. Une interpolation bilinéaire simple devrait fonctionner assez bien pour une partie. Vous trouverez ci-dessous le code Psuedo-C ++ pour le faire.

Normalement, pour dessiner un sprite à l'emplacement (A, B), vous feriez quelque chose comme ceci: P>

Pixel bilinearInterp (Sprite* sprite, float x, float y)
{
    // Interpolate the upper row of pixels
    Pixel* topPtr = sprite->dataPtr + ((floor (y) + 1) * sprite->rowBytes) + floor(x) * sizeof (Pixel);
    Pixel* bottomPtr = sprite->dataPtr + (floor (y) * sprite->rowBytes) + floor (x) * sizeof (Pixel);

    float xOffset = x - floor (x);
    float yOffset = y - floor (y);

    Pixel top = *topPtr + ((*(topPtr + 1) - *topPtr) * xOffset;
    Pixel bottom = *bottomPtr + ((*(bottomPtr + 1) - *bottomPtr) * xOffset;
    return bottom + (top - bottom) * yOffset;
}


3 commentaires

Comment allais-je faire de telles opérations en Java? Existe-t-il des optimisations qui peuvent être faites? J'ai beaucoup d'objets et calculer quelque chose comme ça semble que cela puisse prendre un peu de temps ...


Je ne parle pas très couramment Java, mais vraisemblablement, vos sprites ont une certaine structure, non? Dans des langues basées sur C, il y a généralement un pointeur sur le premier pixel et un certain nombre d'octets par rangée. J'imagine en Java que vous avez probablement une gamme de pixels sans espaces entre rangées. Donc, un sprite peut littéralement être un très grand tableau de rouge, vert, bleu, alpha (ou éventuellement alpha, rouge, vert, bleu). Donc, au lieu de calculer l'adresse d'une structure de pixels, vous obtenez simplement les compensations dont vous avez besoin. Dans Bilinéearinterp, les 2 premières lignes ne sont que calculer l'index des 4 pixels autour du point souhaité.


C'est correct, mais pour calculer chaque image dans mon code peut ne pas être le meilleur moyen. J'espérais qu'il peut y avoir une sorte de fonction intégrée dans le cadre de l'API de Java qui effectue cela.



9
votes

Vous pouvez utiliser un bufferedimage code> et affinetransform code>, dessinez sur l'image tamponnée, puis dessinez l'image tamponnée sur le composant de l'événement de peinture.

    /* overrides the paint method */
    @Override
    public void paint(Graphics g) {
        /* clear scene buffer */
        g2d.clearRect(0, 0, (int)width, (int)height);

        /* draw ball image to the memory image with transformed x/y double values */
        AffineTransform t = new AffineTransform();
        t.translate(ball.x, ball.y); // x/y set here, ball.x/y = double, ie: 10.33
        t.scale(1, 1); // scale = 1 
        g2d.drawImage(image, t, null);

        // draw the scene (double percision image) to the ui component
        g.drawImage(scene, 0, 0, this);
    }


2 commentaires

Hey Lawren! Merci d'avoir répondu. Merci beaucoup de me montrer comment faire ça!


pourquoi t.cale (1, 1); ?? Afaik cette instruction ne fait rien? (échelle à sa taille réelle?)



1
votes

J'ai résolu avec succès mon problème après avoir fait quelque chose comme la législative proposée.

À l'origine, j'ai eu le code suivant, où g code> est transformé en un système de coordonnées de 16: 9 avant que la méthode soit appelée: P>

private void drawStar(Graphics2D g, Star s) {

    AffineTransform originalTransform = g.getTransform();

    double radius = s.getRadius();
    double x = s.getX() - radius;
    double y = s.getY() - radius;
    double width = radius*2;
    double height = radius*2;

    try {

        BufferedImage image = ImageIO.read(this.getClass().getResource("/images/star.png"));

        g.translate(x, y);
        g.scale(width/image.getWidth(), height/image.getHeight());

        g.drawImage(image, 0, 0, this);

    } catch (IOException ex) {
        Logger.getLogger(View.class.getName()).log(Level.SEVERE, null, ex);
    }

    g.setTransform(originalTransform);

}


2 commentaires

Merci d'avoir posté; J'ai fini par faire quelque chose de similaire aussi; C'est définitivement malheureux que le dessin n'a aucun soutien à cela.


Amazing merci beaucoup !! En outre, j'ai utilisé g.setrenderinghint (renduinghints.key_interpolation, renduinghints.value_interpolation_bilinear); pour le rendre meilleur.