Éclairage dynamique 2D en Java


Je fais un jeu qui a des objets de feu de camp. Ce que je veux faire, c'est éclairer tous les pixels d'un cercle autour de chaque feu de camp. Cependant, boucler chaque pixel et changer ceux dans le rayon n'est pas si efficace et fait fonctionner le jeu à ~7 fps. Des idées sur la façon de rendre ce processus efficace ou de simuler la lumière différemment?

Je n'ai pas écrit le code pour les incendies mais c'est la boucle de base pour vérifier chaque pixel/changer sa luminosité en fonction d'un nombre:

public static BufferedImage updateLightLevels(BufferedImage img, float light)
{
    BufferedImage brightnessBuffer = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);

    brightnessBuffer.getGraphics().drawImage(img, 0, 0, null);

    for(int i = 0; i < brightnessBuffer.getWidth(); i++)
    {
        for(int a = 0; a < brightnessBuffer.getHeight(); a++)
        {
            //get the color at the pixel
            int rgb = brightnessBuffer.getRGB(i, a);

            //check to see if it is transparent
            int alpha = (rgb >> 24) & 0x000000FF;

            if(alpha != 0)
            {
                //make a new color
                Color rgbColor = new Color(rgb);

                //turn it into an hsb color
                float[] hsbCol = Color.RGBtoHSB(rgbColor.getRed(), rgbColor.getGreen(), rgbColor.getBlue(), null);

                //lower it by the certain amount
                //if the pixel is already darker then push it all the way to black
                if(hsbCol[2] <= light)
                    hsbCol[2] -= (hsbCol[2]) - .01f;
                else
                    hsbCol[2] -= light;

                //turn the hsb color into a rgb color
                int rgbNew = Color.HSBtoRGB(hsbCol[0], hsbCol[1], hsbCol[2]);

                //set the pixel to the new color
                brightnessBuffer.setRGB(i, a, rgbNew);
            }


        }
    }

    return brightnessBuffer;
}

Je m'excuse si mon code n'est pas propre, je suis autodidacte.

Author: Johndel, 2014-01-07

2 answers

Je peux vous donner beaucoup d'approches.

Vous effectuez actuellement un rendu sur le PROCESSEUR et vous vérifiez chaque pixel. C'est la force brute hardcore, et la force brute n'est pas ce que le processeur est le meilleur. Cela fonctionne, mais comme vous l'avez vu, la performance est abyssale.

Je vous indiquerais deux directions qui amélioreraient massivement vos performances:

Méthode 1 - Abattage. Chaque pixel a-t-il vraiment besoin d'avoir son éclairage calculé? Si vous pouviez plutôt calculer un général "lumière ambiante", alors vous pouvez peindre la plupart des pixels dans cette lumière ambiante, puis calculer seulement l'éclairage vraiment approprié pour les pixels les plus proches des lumières; ainsi, les lumières jettent un effet" spot " qui s'estompe dans l'ambiance. De cette façon, vous n'avez d'effectuer des vérifications sur quelques pixels de l'écran à un temps (le cercle autour de chaque lumière). Le code que vous avez posté semble juste peindre chaque pixel, je ne vois pas où le dépôt "cercle" est égal appliquer.

Modifier:

Au lieu de cela, balayez les lumières et parcourez simplement les décalages locaux de la position de la lumière.

for(Light l : Lights){

for(int x = l.getX() -LIGHT_DISTANCE, x< l.getX() + LIGHT_DISTANCE, y++){

for(int y = l.getY() - LIGHT_DISTANCE, y < l.getY() + LIGHT_DISTANCE, y++){

//calculate light
int rgb = brightnessBuffer.getRGB(x, y);
//do stuff
}

}

Vous pouvez ajouter une vérification avec cette méthode afin que les lumières qui se chevauchent ne provoquent pas un tas de revérifications, sauf si vous voulez ce comportement (idéalement, ces pixels seraient deux fois plus brillants)

Méthode 2 - Calcul désinvolte au GPU. Il y a une raison pour laquelle nous avons des cartes graphiques; ils sont spécialement conçus pour être en mesure de nombre crunch ces situations où vous avez vraiment besoin de force brute. Si vous pouvez décharger ce processus sur le GPU en tant que shader, il s'exécutera licketysplit, même si vous l'exécutez plusieurs fois sur chaque pixel. Cela vous obligera cependant à apprendre les API graphiques, mais si vous travaillez en java, LibGDX rend le rendu très indolore à l'aide du GPU et transmet quelques shaders au GPU.

 3
Author: SpacePrez, 2014-01-06 22:39:36

Je ne suis pas sûr de la façon dont vous calculez les valeurs de lumière, mais je le sais en utilisant le BufferedImage.getRGB () et BufferedImage.Les méthodes setRGB () sont très lentes.

Je suggérerais d'accéder aux pixels du BufferedImage directement à partir d'un tableau (beaucoup plus rapide IMO)

Pour ce faire:

BufferedImage lightImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
Raster r = lightImage.getRaster();
int[] lightPixels = ((DataBufferInt)r.getDataBuffer()).getData();

Maintenant, changer n'importe quel pixel de ce tableau s'affichera sur votre image. Notez que les valeurs utilisées dans ce tableau sont des valeurs de couleur au format de n'importe quel format vous avez défini votre image.

Dans ce cas, il s'agit de TYPE_INT_ARGB, ce qui signifie que vous devrez inclure la valeur alpha dans le nombre lors de la définition du coloar (RRGGBB*AA*)

Comme ce tableau est un tableau 1D, il est plus difficile d'accéder aux pixels en utilisant les coordonnées x et y. La méthode suivante est une implémentation permettant d'accéder plus facilement aux pixels du tableau lightPixels.

public void setLight(int x, int y,int[] array,int width, int value){
    array[width*y+x] = value;
}

*remarque: largeur est la largeur de votre niveau, ou la largeur du tableau 2D votre niveau pourrait exister comme, s'il s'agissait d'un tableau 2D.

Vous pouvez également obtenir des pixels du tableau lightPixels avec une méthode similaire, en excluant simplement la valeur et en renvoyant le array[width*y+x].

C'est à vous de décider comment vous utilisez les méthodes setLight() et getLight() mais dans les cas que j'ai rencontrés, l'utilisation de cette méthode est beaucoup plus rapide que l'utilisation de getRGB et setRGB.

J'espère que cela aide

 0
Author: grimrader22, 2014-01-20 03:12:26