0
\$\begingroup\$

I'm stuck with a framerate perf down with getData from a rendertarget, what's your idea, what are the other options I can use ?

I explain my problem : I'm making a board game, the objects or monsters are overflow the board rooms, I use kryton framework to manage light sources, krypton is an efficient 2D pixel shader raycasting engine, I've made Hulls (#blocking light blocks) all around the rooms of my board, but the objects and monsters Texture2D were cutted by the hull shadows of the board sides... So I can't use Krypton to light my monsters

krypton give me a rendertarget of the screen which is a screen light color map If I pick color from center board square, It give me the perfect color to draw my monsters, but with getData it's reaaaallllyy slow.

I'm using this code :

public Color GetLightColorOnPoint(Vector2 position) {
Vector2 v = WorldToScreen(position); return lightManager.GetLightColorAtPoint((int)v.X, (int)v.Y); }

public Color LightManagerClass.GetLightColorAtPoint(int x, int y) { Color[] lightPixel = new Color[ 1 ]; Rectangle sourceRectangle = new Rectangle(x, y, 1, 1); //rendertarget2D
this.krypton_SolShadow.mMap.GetData(0, sourceRectangle, lightPixel, 0, 1); return lightPixel[0]; }

(I don't understand well pixel shaders and I don't think you can pick a board square center color and apply it to an entire monster texture2D with the correct offset/zoom of a camera 2D of course and variable texture2D size (a giant vs a rat texture2D size))

enter image description here

with 40 GetData (40 monsters on screen) per draw, the FrameRate slow down to 7 FPS :(, please help

\$\endgroup\$
  • \$\begingroup\$ ok, I dig internet forever alone, you can't getData from gpu to cpu during a draw because it will cause pipeline stalling. the options are : wait one frame or two and getData from an unused rendertarget from last frame, or calculate shadow and apply color without touching the gpu data :( \$\endgroup\$ – Ch'nycos Aug 28 '15 at 9:22
0
\$\begingroup\$

So you have a lightmap in a texture, and later in the drawcall you want to use that information as a base to draw sprites. Create a shader for this. The shader should have the lightmap as a register, and a parameter should be the position you want sampled. This one is updated for each sprite. Start a spritebatch with the effect, and draw all sprites with it. It should then tint everything on GPU power only. Note the code below is all from my head as I have no XNA near me right now, so it is untested. But it should show the basic principle.

//set the lightmap in the GPU's register.
GraphicsDevice.Textures[1] = this.lightManager.krypton_SolShadow.mMap;

//begin the spritebatch with the "tint" effect.
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, null, null, null, tinteffect);

foreach(GameEntity entity in entities)
{
    //note, the shader expects coordinates to be between 0.0 and 1.0.
    tinteffect.Parameters["lightmappos"].SetValue(new Vector2(entity.Position.X/lightmapwidth,entity.Position.Y/lightmapheiht));

    spriteBatch.Draw(entity.texture,entity.position,Color.White); // your draw call here;
}

spriteBatch.End();

The shader should have a sampler set up for the lightmap like this:

sampler LightMapTexture: register(s1); //note s1 corresponds to GraphicsDevice.Textures register 1.

And you can read the value like this:

float4 entitycolor = tex2D(s0, coords);
float4 tintcolor = tex2D(LightMapTexture, lightmappos.xy);

Entitycolor should now have the color value of the pixel in the sprite that is being drawn. Tintcolor holds the sampled color in the lightmap at the provided coordinates. You can then return the color of the pixel using these 2 values (for example mutiply them?):

return entitycolor*tintcolor; 

I did a quick Google for you, this tutorial seems a nice starting guide for shaders: https://gmjosack.github.io/posts/my-first-2d-pixel-shaders-part-1/

\$\endgroup\$
0
\$\begingroup\$

One Big GetData of all the fullscreen renderTarget per draw seems to be more efficient than doing multiple GetData of one pixel per object to draw

        public override void Initialize()
        {
                    ....
            //initializing the Color Table
            this.lightManager.LightMap = new Color[this.graphics.PreferredBackBufferWidth * this.graphics.PreferredBackBufferHeight];
        }


       public override void Draw(GameTime gameTime)
       {
            ...
            //getting the lightMap from krypton        
            this.lightManager.krypton_SolShadow.mMap.GraphicsDevice.SetRenderTarget(null);
            this.lightManager.krypton_SolShadow.mMap.GetData<Color>(this.lightManager.LightMap);

            //for each object get the color (do not affect the FPS)
            //Object position (x,y)
            Color objectColor = this.lightManager.LightMap[this.krypton_SolShadow.mMap.Width * y + x];
       }

if I found a better solution, I share...

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.