Table of Contents

Creating a Custom Effect with Texturing

Demonstrates how to use a custom effect and a texture to render a 3D object.

Overview

Drawing a textured quad is a basic technique to have in any Game Developers arsenal, which can be populated by any texture from either the Content Pipeline (loaded from disk) or generated in memory (which we will use here for simplicity).

Note

Drawing a texture quad is in effect what a SpriteBatch does under the hood, but while a SpriteBatch natively only draws flat to the screen, a Quad can be positioned in any way you see fit. Either approach has its pros and cons.

There is a but of setup to draw a quad in MonoGame and there are many ways to achieve it.

Note

This example draws from community responses to the same question here, on the MonoGame Community site, with a little clean-up to make it simpler.

To use a custom effect with a texture

  1. Create a custom vertex format declaration and a set of indices to indicate the drawing order.

    // A Vertex format with Texture information
    private VertexPositionColorTexture[] drawingQuad;
    
    // The indices array for drawing a quad
    private short[] drawingIndices;
    
    public void SetupUserIndexedVertexRectangle(Rectangle r)
    {
        drawingQuad = new VertexPositionColorTexture[4];
        drawingQuad[0] = new VertexPositionColorTexture(new Vector3(r.Left, r.Top, 0f), Color.White, new Vector2(0f, 0f));
        drawingQuad[1] = new VertexPositionColorTexture(new Vector3(r.Left, r.Bottom, 0f), Color.Red, new Vector2(0f, 1f));
        drawingQuad[2] = new VertexPositionColorTexture(new Vector3(r.Right, r.Bottom, 0f), Color.Green, new Vector2(1f, 1f));
        drawingQuad[3] = new VertexPositionColorTexture(new Vector3(r.Right, r.Top, 0f), Color.Blue, new Vector2(1f, 0f));
    
        drawingIndices = [0, 2, 1, 2, 0, 3];
    }
    
  2. To make setup simpler, we will also define two methods to Set the Graphics State and create our basic effect.

    // The basic effect definition
    private BasicEffect basicEffect;
    
    // A Texture2D that we will generate data into
    private Texture2D generatedTexture;
    
    /// <summary>
    /// Set the states for the graphics device.
    /// </summary>
    private void SetStates()
    {
        GraphicsDevice.BlendState = BlendState.Opaque;
        GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
        GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
    }
    
    /// <summary>
    /// Creates a basic effect for drawing a textured quad.
    /// </summary>
    private void SetUpBasicEffect()
    {
        basicEffect = new BasicEffect(this.GraphicsDevice);
        basicEffect.VertexColorEnabled = true;
        basicEffect.TextureEnabled = true;
        basicEffect.Texture = generatedTexture;
    
        // set up our matrix to match basic effect.
        Viewport viewport = GraphicsDevice.Viewport;
        basicEffect.World = Matrix.Identity;
        Vector3 cameraUp = Vector3.Transform(Vector3.Down, Matrix.CreateRotationZ(0));
        basicEffect.View = Matrix.CreateLookAt(Vector3.Forward, Vector3.Zero, cameraUp);
        basicEffect.Projection = Matrix.CreateScale(1, -1, 1) * Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
    }
    
    Note

    Note that the basic effect is created with basicEffect.TextureEnabled = true; and the texture to draw using basicEffect.Texture = generatedTexture;, just stating we are drawing a texture and what it is.

  3. Next, we will generate a Texture to draw as part of the quad, a simple white texture which the effect will also draw a coloured "tint" over thanks to the basicEffect.VertexColorEnabled = true; set in the effect.

    private Texture2D GenerateTexture2D()
    {
        Texture2D t = new Texture2D(this.GraphicsDevice, 250, 250);
        var cdata = new Color[250 * 250];
        for (int i = 0; i < 250; i++)
        {
            for (int j = 0; j < 250; j++)
            {
                cdata[i * 250 + j] = Color.White;
            }
        }
        t.SetData(cdata);
        return t;
    }
    
    Note

    Alternatively, you can just use a texture loaded from the Content Pipeline, just be sure to change the Vertex format used in Step 1 to VertexPositionTexture unless you want the coloured gradient, or simply disable basicEffect.VertexColorEnabled = false;. That is unless you want to apply color tints with the vertex declaration.

  4. Putting this together, setup all the relevant artifacts in the LoadContent method.

    protected override void LoadContent()
    {
        // Set render state
        SetStates();
    
        // Setup basic effect
        SetUpBasicEffect();
    
        // Create the quad to draw
        SetupUserIndexedVertexRectangle(new Rectangle(10, 40, 450, 260));
    
        // Generate (or load) the Texture
        generatedTexture = GenerateTexture2D();
    }
    
  5. Finally, draw the primitive quad to the screen using the BasicEffect and generated data.

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
    
        foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
        {
            pass.Apply();
            GraphicsDevice.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, drawingQuad, 0, 4, drawingIndices, 0, 2);
        }
    
        base.Draw(gameTime);
    } 
    
  6. Marvel at the wonder of your drawn Textured Quad plus vertex effect.

    Final effect

See Also

Concepts

Reference

© 2012 Microsoft Corporation. All rights reserved.