6 min read

The BasicEffect Class

Introduction

In this tutorial, we will be taking an initial look at effects in XNA, especially the BasicEffect class. In the Drawing 3D Models, we looked at how to draw 3D models. In that tutorial, we actually ran into the BasicEffect class. Here, we will pick up where we left off in that tutorial, and discuss some of the basics of the BasicEffect class. While you don’t need to, I would recommend starting from the code that we had made at the end of that tutorial.

Effects in XNA

An effect is simply a method of designating how an object should be rendered on the screen. Back in the past, a graphics API would have a list of variables that you could set that would tell the graphics card everything it needed to know, like the position of lights in the scene, the textures to use, and other things. More recently, as graphics programmers wanted more flexibility, and graphics cards became more powerful, it became possible for a person to create a small program that could be run for each vertex that you were handling, and for each pixel that you draw on the screen. With this, the possibilities became limitless, and you can now do anything you want, as long as your graphics card can keep up with it.

These programs are written in a programming language called HLSL, and there will be tutorials later that will discuss how to use this. There is one small problem though. It can be quite a bit of work to create a complete effect from scratch, and so the XNA people provide an easy-to-use but powerful effect for you, which is utilized with the BasicEffect class. In this tutorial and the next couple of tutorials, we will look at how this class is used.

Some BasicEffect Basics

In the next couple of tutorials, we will take a look at how to do lighting and fog with the BasicEffect class. In this tutorial, we will look at where the BasicEffect class was used earlier in our game and a few simple things that you can do with it. Recall that in the previous tutorial we created a DrawModel() method that looked like this:

private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
{
    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (BasicEffect effect in mesh.Effects)
        {
            effect.World = world;
            effect.View = view;
            effect.Projection = projection;
        }

        mesh.Draw();
    }
}

Notice that the inner foreach loop states that we want to look at all of the BasicEffects that are in each mesh of the model. By default, when you load a model, the Content Pipeline prepares the model with a BasicEffect to handle the rendering. Later, we will see that you can replace the BasicEffect class with something of your own, but for now, we will keep this the same. Before, we set the world, view, and projection matrices of the effect to be what we wanted, and the BasicEffect class took care of it from there.

In addition to what we already have here, there are two things that we want to look at. First, you can set a different texture for the BasicEffect. (This requires that your model has texture coordinates in the first place, so in your 3D model editor, you’ll need to do this before you can assign textures to it.) For instance, continuing on with the code from the previous tutorial, I have loaded another texture called “GreenShipTexture.png”, which can be downloaded from the Texture Library . You can then put in the other texture with a line of code like the following:

effect.Texture = otherTexture; // otherTexture is of the type "Texture2D"

This gives us something like the image below when we run it:

Screenshot 1

The second thing we want to do is to try using no texture at all. This can easily be done with the following line of code:

effect.TextureEnabled = false;

When we do this, we get a solid white drawing, like in the image below, because the effect has no other indication of what color should be used.

Screenshot 2

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Using3DModels
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        /// <summary>
        /// Stores the model that we are going to draw.
        /// </summary>
        private Model model;

        /// <summary>
        /// Stores a second texture that can be applied to the model.
        /// </summary>
        private Texture2D otherTexture;

        /// <summary>
        /// Stores the position of the model.
        /// </summary>
        private Vector3 position;

        /// <summary>
        /// Stores the rotation angle of the model.  This
        /// is used as a roll angle. (So changing it will make the
        /// object roll as it moves forward.)
        /// </summary>
        private float angle;

        /// <summary>
        /// Stores the world matrix for the model, which transforms the
        /// model to be in the correct position, scale, and rotation
        /// in the game world.
        /// </summary>
        private Matrix world = Matrix.CreateTranslation(new Vector3(0, 0, 0));

        /// <summary>
        /// Stores the view matrix for the model, which gets the model
        /// in the right place, relative to the camera.
        /// </summary>
        private Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 10), new Vector3(0, 0, 0), Vector3.UnitY);

        /// <summary>
        /// Stores the projection matrix, which gets the model projected
        /// onto the screen in the correct way.  Essentially, this defines the
        /// properties of the camera you are using.
        /// </summary>
        private Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 480f, 0.1f, 100f);


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            model = Content.Load<Model>("Ship");
            otherTexture = Content.Load<Texture2D>("GreenShipTexture");
            position = new Vector3(0, 0, 0);
            angle = 0;
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // Update the properties of the model here
            position += new Vector3(0, 0.001f, 0);
            angle += 0.003f;

            // This updates the world matrix, so that it reflects the changes to the position
            // and angle.  Remember that this matrix determines where the model will be located
            // at in the 3D world.
            world = Matrix.CreateRotationY(angle) * Matrix.CreateTranslation(position);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            DrawModel(model, world, view, projection);

            base.Draw(gameTime);
        }

        /// <summary>
        /// Does the work of drawing a model, given specific world, view, and projection
        /// matrices.
        /// </summary>
        /// <param name="model">The model to draw</param>
        /// <param name="world">The transformation matrix to get the model in the right place in the world.</param>
        /// <param name="view">The transformation matrix to get the model in the right place, relative to the camera.</param>
        /// <param name="projection">The transformation matrix to project the model's points onto the screen correctly.</param>
        private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.Texture = otherTexture;
                    effect.TextureEnabled = false;
                    effect.World = world;
                    effect.View = view;
                    effect.Projection = projection;
                }

                mesh.Draw();
            }
        }

    }
}
Download the complete project