¿Cómo dibujo un rectángulo de un destino de renderizado a otro sin perder datos?

I asked a question earlier in the week (aquí) regarding transferring data from a rendertarget to the CPU so that collisions could be tested on it. From the responses I got there, I decided that drawing a section of the render target to a smaller render target and then retrieving that data would be a valid solution and tried to implement that.

After drawing the full sized render target (1280x1024), I switch the active render target to a smaller one (59X47 - the collision size of my players) and try to draw the section of the large render target which falls under the player onto the smaller target. At first, I thought this had worked, but then I noticed that collisions would sometimes be wildly inaccurate.

I drew the smaller render target to the screen to inspect its contents and found that it only had a handful of pixels occupied at any one time, and that these were always in the top left corner.

            // Render rectangle under player from foreground to collision layer
            Rectangle sourceRectangle = new Rectangle(sourceX, sourceY,
                                                       (int)sizeX, (int)sizeY);
            gd.SetRenderTarget(collisionLayer[i]);
            gd.Clear(Color.Transparent);
            spriteBatch.Draw(foregroundLayer, collisionLayer[i].Bounds,
                                                sourceRectangle, Color.White);
            gd.SetRenderTarget(null);

Drawing the full large render target to the smaller target results in the data carrying over successfully (though scaled, obviously), so I'm not sure what is going wrong.

            // Render full target onto collision layer
            gd.SetRenderTarget(collisionLayer[i]);
            gd.Clear(Color.Transparent);
            spriteBatch.Draw(foregroundLayer,new Vector2(0.0f),Color.White);
            gd.SetRenderTarget(null);

The image below shows the large target with the small target superimposed on the top left corner. The large target's full data seems to be drawn correctly.

preguntado el 10 de marzo de 12 a las 12:03

Is the picture showing things not working? It looks fairly correct to me - the small image seems to be a pretty good representation of the large one. You're going from 1280x1024 down to 59x47. You can't expect a perfect looking smaller image when the scale change is that large. -

I'm sorry if it wasn't clear in the question. The problem is that, whilst copying the full image works, I am not able to just grab the rectangle under the player. If I were to use the first code snippet, then the picture in the top left should be blank in this instance because no player is sitting on black ink (the paper texture is non-collidable) and contain black pixels which map 1-to-1 with the image underneath the player if they were on top of the ink blot. what I actually get doesn't seem to relate to the data which is there at all as I just get a few pixels of black around (0,0). -

I don't see anything obviously wrong with the code you're showing. I guess my first hunch would be that your sourceRectangle isn't what you're expecting it to be. Have you tried hard coding the rectangle to somewhere you know is over the ink and seeing how that turns out? -

I hadn't, because I was fairly sure that it was correct but I just tried (900,450) which is quite comfortably in the middle of the black ink and I just get a small black dot like before. -

1 Respuestas

You're not showing your spriteBatch.Begin y spriteBatch.End calls, but it looks like you need to move them. Specifically, you're setting your render target to null before calling spriteBatch.End, or at least it appears so from your sample code.

I set up a sample project, and when I do the following everything works as expected...

  GraphicsDevice.SetRenderTarget(target);
  GraphicsDevice.Clear(Color.Transparent);
  spriteBatch.Begin();
  spriteBatch.Draw(texture, target.Bounds, new Rectangle(50, 500, 100, 100), Color.White);
  spriteBatch.End();

  GraphicsDevice.SetRenderTarget(null);
  GraphicsDevice.Clear(Color.CornflowerBlue);
  spriteBatch.Begin();
  spriteBatch.Draw(texture, new Rectangle(0, 0, 640, 480), texture.Bounds, Color.White);
  spriteBatch.Draw(target, Vector2.Zero, target.Bounds, Color.White);
  spriteBatch.End();

But if I move spriteBatch.End después de SetRenderTarget(null) my render target is empty.

respondido 10 mar '12, 17:03

The sprite batch started long ago and ends even longer after where this came from, but I don't see any reason why we can't just change it around so that different parts of render process start and end the batch as needed. I'm away from the project until tomorrow, but I'll try it out then and if that works, I'll accept your answer. Thanks for your help. - LlamaCloud

Ending the SpriteBatch is what does the actual drawing, so by ending it after you've changed render targets you're either drawing into the wrong render target, or your draw calls get lost - not sure which. Actually, it's possible the SpriteBatch keeps track of the render target it draws to, but still, the End call flushes the draw calls, so if you're not calling it, the drawing isn't happening. - Dave Carlile

I just moved the end and begin calls around (separated the draw into several batches) and it has worked perfectly. Thank you very much for your assistance. - LlamaCloud

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.