0
\$\begingroup\$

I am trying to draw an object composited by two cubes (A & B) (one on top of the other, but for now I have them a little bit more open). I am able to do it and this is the result.

enter image description here (Cube A is the blue and Cube B is the one with brown text that comes from a png texture)

But I want to have any text as parameter in the cube B. I have tried what @alecnash suggested in his question, but for some reason when I try to draw cube B, cube A dissapears and everything turns purple.

enter image description here

This is my draw code:

public void Draw(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch, Matrix viewMatrix, Matrix projectionMatrix)
        {
            graphicsDevice.BlendState = BlendState.Opaque;
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp;


            // CUBE A
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;
            basicEffect.World = Matrix.CreateTranslation(ModelPosition);
            basicEffect.VertexColorEnabled = true;
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                drawCUBE_TOP(graphicsDevice);
                drawCUBE_Floor(graphicsDevice);
                DrawFullSquareStripesFront(graphicsDevice, _numStrips, Color.Red, Color.Blue, _levelPercentage);
                DrawFullSquareStripesLeft(graphicsDevice, _numStrips, Color.Red, Color.Blue, _levelPercentage);
                DrawFullSquareStripesRight(graphicsDevice, _numStrips, Color.Red, Color.Blue, _levelPercentage);
                DrawFullSquareStripesBack(graphicsDevice, _numStrips, Color.Red, Color.Blue, _levelPercentage);

            }

            // CUBE B
            // Set the World matrix which defines the position of the cube
            texturedCubeEffect.World = Matrix.CreateTranslation(ModelPosition);
            // Set the View matrix which defines the camera and what it's looking at
            texturedCubeEffect.View = viewMatrix;
            // Set the Projection matrix which defines how we see the scene (Field of view)
            texturedCubeEffect.Projection = projectionMatrix;
            // Enable textures on the Cube Effect. this is necessary to texture the model
            texturedCubeEffect.TextureEnabled = true;
            Texture2D a = SpriteFontTextToTexture(graphicsDevice, spriteBatch, arialFont, "TEST ", Color.Black, Color.GhostWhite);
            texturedCubeEffect.Texture = a;
            //texturedCubeEffect.Texture = cubeTexture;
            // Enable some pretty lights
            texturedCubeEffect.EnableDefaultLighting();
            // apply the effect and render the cube
            foreach (EffectPass pass in texturedCubeEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                cubeToDraw.RenderToDevice(graphicsDevice);
            }


        }

    private Texture2D SpriteFontTextToTexture(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch, SpriteFont font, string text, Color backgroundColor, Color textColor)
    {
        Vector2 Size = font.MeasureString(text);
        RenderTarget2D renderTarget = new RenderTarget2D(graphicsDevice, (int)Size.X, (int)Size.Y);
        graphicsDevice.SetRenderTarget(renderTarget);

        graphicsDevice.Clear(Color.Transparent);

        spriteBatch.Begin();
        //have to redo the ColorTexture
        //spriteBatch.Draw(ColorTexture.Create(graphicsDevice, 1024, 1024, backgroundColor), Vector2.Zero, Color.White);

        spriteBatch.DrawString(font, text, Vector2.Zero, textColor);
        spriteBatch.End();

        graphicsDevice.SetRenderTarget(null);

        return renderTarget;
    }

The way I generate texture with dynamic text is:

 Texture2D a = SpriteFontTextToTexture(graphicsDevice, spriteBatch, arialFont, "TEST ", Color.Black, Color.GhostWhite);

After commenting several parts to see what caused the problem, it seems to be located in this line

graphicsDevice.SetRenderTarget(renderTarget);
\$\endgroup\$
1
  • \$\begingroup\$ I have commented the line in SpriteFontTextToTexture because it is killing my fps and makes no cube appear in screen. \$\endgroup\$ Commented Nov 25, 2012 at 17:25

1 Answer 1

1
\$\begingroup\$

That purple colour is the "uninitialized surface" colour.

Basically whenever you call GraphicsDevice.SetRenderTarget, the render target that you set gets cleared (by default). In this case, the back-buffer counts as a render target (setting null).

You could set RenderTargetUsage.PreserveContents on the backbuffer. But preserving the contents of a render target is slow on Xbox 360 and Windows Phone. The default is to clear in order to be fast on those devices (and Windows matches that behaviour to make your life easier when porting).

The recommended way to solve this is to order your drawing so that you fill your render targets before you draw anything to the backbuffer.

This is explained in detail in this blog post. And also in my answer here.


Also it looks like you are creating a fresh render-target each frame. That's a big no-no. Create it once and re-use it!

\$\endgroup\$
3
  • \$\begingroup\$ I've tried quickly to use PreserveContents (as I am doing my project in windows) by changing declaration of rendertarget with RenderTarget2D renderTarget = new RenderTarget2D(graphicsDevice, (int)Size.X, (int)Size.Y,false,SurfaceFormat.Color,DepthFormat.None,1,RenderTargetUsage.PreserveContents); and doesn't seem to work. This night I will read deeply the blog post... \$\endgroup\$ Commented Nov 26, 2012 at 6:49
  • 1
    \$\begingroup\$ @cad The target you need to be preserving is the backbuffer itself. When you call SetRenderTarget(null) you are clearing it. You have to mess around with PreparingDeviceSettings to make this change. \$\endgroup\$ Commented Nov 26, 2012 at 8:38
  • \$\begingroup\$ I've changed the order as you suggested and draw first cube B and later cube A. It worked :) Also did as you suggested and only create render targer once with this: if (renderTarget==null) { renderTarget = new RenderTarget2D(graphicsDevice, (int)Size.X, (int)Size.Y, false, SurfaceFormat.Color, DepthFormat.None, 1, RenderTargetUsage.PreserveContents); } \$\endgroup\$ Commented Dec 1, 2012 at 15:46

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .