BasicEffect system in XNA

In this article I wish to talk about the built-in effect system in XNA - BasicEffect.


Hi,

In this article I wish to talk about the built-in effect system in XNA – BasicEffect

Effects are the objects that make games much more dynamic.XNA supports Effects too.You can use XNA's.

BasicEffect System or use an external effect file such as HLSL.

A Simple Basic Effect should look like this:

BASIC EFFECT

Matrix[] transforms = new Matrix[myModel.Bones.Count];
myModel.CopyAbsoluteBoneTransformsTo(transforms);           
foreach (ModelMesh mesh in myModel.Meshes )
{               
  foreach (BasicEffect effect in mesh.Effects)
   {
     effect.EnableDefaultLighting();                   
     effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(modelRotation)
                        * Matrix.CreateTranslation(modelPosition);
     effect.View = Matrix.CreateLookAt(cameraPosition,Vector3.Zero,Vector3.Up);
     effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(75.0f),                        aspectRatio, 1.0f, 10000.0f);
    }               

   mesh.Draw();
}         


"Basic Effect" represents shader model 1.1 Effect that has optional support for vertex colors, texturing, and lighting.as you can see its not as advanced as HLSL or other Effect Systems.As Microsoft's HLSL supports Shader Model 5,the Basic Effect System inside XNA will look simple to you but in some cases you can use it.
You can have a look at Shader Model 5 here:

http://msdn.microsoft.com/en-us/library/ff471356(VS.85).aspx

Ok.Now lets make a simple example on how to create effects in XNA using Basic Effect.

Create a new project in XNA 3.0 or 3.1

Fig1.gif

Add some variables in your class

Matrix worldMatrix;
Matrix viewMatrix;
Matrix projectionMatrix;
VertexPositionNormalTexture[] cubeVertices;
VertexDeclaration basicEffectVertexDeclaration;
VertexBuffer vertexBuffer;
BasicEffect basicEffect;
GraphicsDeviceManager graphics;

We are adding Vertex variables we will be using to build a Cube! Which are cubevertices that has 36 vertices and 6 faces(6 vertices for each face)


Ok now we have declared our variables now lets add some codes to get it working!

Update your LoadContent,InitializeTransform,InitializeEffect,InitializeCube,Draw functions as seen below.

protected override void LoadContent()
        {
            InitializeTransform();
            InitializeEffect();
            InitializeCube();
        }

        private void InitializeTransform()
        {
            float tilt = MathHelper.ToRadians(22.5f);
            worldMatrix = Matrix.CreateRotationX(tilt) * Matrix.CreateRotationY(tilt);
 
            viewMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 5), Vector3.Zero, Vector3.Up);

            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45), (float)GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height, 1.0f, 100.0f);
        }

        private void InitializeEffect()
        {
            basicEffectVertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice, VertexPositionNormalTexture.VertexElements);

            basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
            basicEffect.Alpha = 1.0f;
            basicEffect.DiffuseColor = new Vector3(1.0f, 0.0f, 1.0f);
            basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
            basicEffect.SpecularPower = 5.0f;
            basicEffect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);

            basicEffect.DirectionalLight0.Enabled = true;
            basicEffect.DirectionalLight0.DiffuseColor = Vector3.One;
            basicEffect.DirectionalLight0.Direction =
                Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f));
            basicEffect.DirectionalLight0.SpecularColor = Vector3.One; 

            basicEffect.DirectionalLight1.Enabled = true;
            basicEffect.DirectionalLight1.DiffuseColor =
                new Vector3(0.5f, 0.5f, 0.5f);
            basicEffect.DirectionalLight1.Direction =
                Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f));
            basicEffect.DirectionalLight1.SpecularColor =
                new Vector3(0.5f, 0.5f, 0.5f);
 
            basicEffect.LightingEnabled = true;

            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;
        }

        private void InitializeCube()
        {
            cubeVertices = new VertexPositionNormalTexture[36];

            Vector3 topLeftFront = new Vector3(-1.0f, 1.0f, 1.0f);
            Vector3 bottomLeftFront = new Vector3(-1.0f, -1.0f, 1.0f);
            Vector3 topRightFront = new Vector3(1.0f, 1.0f, 1.0f);
            Vector3 bottomRightFront = new Vector3(1.0f, -1.0f, 1.0f);
            Vector3 topLeftBack = new Vector3(-1.0f, 1.0f, -1.0f);
            Vector3 topRightBack = new Vector3(1.0f, 1.0f, -1.0f);
            Vector3 bottomLeftBack = new Vector3(-1.0f, -1.0f, -1.0f);
            Vector3 bottomRightBack = new Vector3(1.0f, -1.0f, -1.0f);

            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
            Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

            Vector3 frontNormal = new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 backNormal = new Vector3(0.0f, 0.0f, -1.0f);
            Vector3 topNormal = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 bottomNormal = new Vector3(0.0f, -1.0f, 0.0f);
            Vector3 leftNormal = new Vector3(-1.0f, 0.0f, 0.0f);
            Vector3 rightNormal = new Vector3(1.0f, 0.0f, 0.0f);

            cubeVertices[0] =
                new VertexPositionNormalTexture(
                topLeftFront, frontNormal, textureTopLeft);
            cubeVertices[1] =
                new VertexPositionNormalTexture(
                bottomLeftFront, frontNormal, textureBottomLeft);
            cubeVertices[2] =
                new VertexPositionNormalTexture(
                topRightFront, frontNormal, textureTopRight);
            cubeVertices[3] =
                new VertexPositionNormalTexture(
                bottomLeftFront, frontNormal, textureBottomLeft);
            cubeVertices[4] =
                new VertexPositionNormalTexture(
                bottomRightFront, frontNormal, textureBottomRight);
            cubeVertices[5] =
                new VertexPositionNormalTexture(
                topRightFront, frontNormal, textureTopRight);

            cubeVertices[6] =
                new VertexPositionNormalTexture(
                topLeftBack, backNormal, textureTopRight);
            cubeVertices[7] =
                new VertexPositionNormalTexture(
                topRightBack, backNormal, textureTopLeft);
            cubeVertices[8] =
                new VertexPositionNormalTexture(
                bottomLeftBack, backNormal, textureBottomRight);
            cubeVertices[9] =
                new VertexPositionNormalTexture(
                bottomLeftBack, backNormal, textureBottomRight);
            cubeVertices[10] =
                new VertexPositionNormalTexture(
                topRightBack, backNormal, textureTopLeft);
            cubeVertices[11] =
                new VertexPositionNormalTexture(
                bottomRightBack, backNormal, textureBottomLeft);

            cubeVertices[12] =
                new VertexPositionNormalTexture(
                topLeftFront, topNormal, textureBottomLeft);
            cubeVertices[13] =
                new VertexPositionNormalTexture(
                topRightBack, topNormal, textureTopRight);
            cubeVertices[14] =
                new VertexPositionNormalTexture(
                topLeftBack, topNormal, textureTopLeft);
            cubeVertices[15] =
                new VertexPositionNormalTexture(
                topLeftFront, topNormal, textureBottomLeft);
            cubeVertices[16] =
                new VertexPositionNormalTexture(
                topRightFront, topNormal, textureBottomRight);
            cubeVertices[17] =
                new VertexPositionNormalTexture(
                topRightBack, topNormal, textureTopRight);

            cubeVertices[18] =
                new VertexPositionNormalTexture(
                bottomLeftFront, bottomNormal, textureTopLeft);
            cubeVertices[19] =
                new VertexPositionNormalTexture(
                bottomLeftBack, bottomNormal, textureBottomLeft);
            cubeVertices[20] =
                new VertexPositionNormalTexture(
                bottomRightBack, bottomNormal, textureBottomRight);
            cubeVertices[21] =
                new VertexPositionNormalTexture(
                bottomLeftFront, bottomNormal, textureTopLeft);
            cubeVertices[22] =
                new VertexPositionNormalTexture(
                bottomRightBack, bottomNormal, textureBottomRight);
            cubeVertices[23] =
                new VertexPositionNormalTexture(
                bottomRightFront, bottomNormal, textureTopRight);

            cubeVertices[24] =
                new VertexPositionNormalTexture(
                topLeftFront, leftNormal, textureTopRight);
            cubeVertices[25] =
                new VertexPositionNormalTexture(
                bottomLeftBack, leftNormal, textureBottomLeft);
            cubeVertices[26] =
                new VertexPositionNormalTexture(
                bottomLeftFront, leftNormal, textureBottomRight);
            cubeVertices[27] =
                new VertexPositionNormalTexture(
                topLeftBack, leftNormal, textureTopLeft);
            cubeVertices[28] =
                new VertexPositionNormalTexture(
                bottomLeftBack, leftNormal, textureBottomLeft);
            cubeVertices[29] =
                new VertexPositionNormalTexture(
                topLeftFront, leftNormal, textureTopRight);

            cubeVertices[30] =
                new VertexPositionNormalTexture(
                topRightFront, rightNormal, textureTopLeft);
            cubeVertices[31] =
                new VertexPositionNormalTexture(
                bottomRightFront, rightNormal, textureBottomLeft);
            cubeVertices[32] =
                new VertexPositionNormalTexture(
                bottomRightBack, rightNormal, textureBottomRight);
            cubeVertices[33] =
                new VertexPositionNormalTexture(
                topRightBack, rightNormal, textureTopRight);
            cubeVertices[34] =
                new VertexPositionNormalTexture(
                topRightFront, rightNormal, textureTopLeft);
            cubeVertices[35] =
                new VertexPositionNormalTexture(
                bottomRightBack, rightNormal, textureBottomRight);

            vertexBuffer = new VertexBuffer(
                graphics.GraphicsDevice,
                VertexPositionNormalTexture.SizeInBytes * cubeVertices.Length,
                BufferUsage.None
            );

            vertexBuffer.SetData<VertexPositionNormalTexture>(cubeVertices);

        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {

            graphics.GraphicsDevice.Clear(Color.Azure);
            graphics.GraphicsDevice.RenderState.CullMode =
            CullMode.CullClockwiseFace;

            graphics.GraphicsDevice.VertexDeclaration =
                basicEffectVertexDeclaration;
            graphics.GraphicsDevice.Vertices[0].SetSource(vertexBuffer, 0,
                VertexPositionNormalTexture.SizeInBytes);

            basicEffect.Begin();
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
 
                graphics.GraphicsDevice.DrawPrimitives(

                    PrimitiveType.TriangleList,
                    0,
                    12
                );
 
                pass.End();
            }
            basicEffect.End();

            base.Draw(gameTime);
        }

Ok lets explain what we have done: We have created 36 vertices-6 faces for a cube and added some BasicEffects' effect values such as Lighting,Colors and WVP.

What is WVP(World-View-Projection)?


Object -> World -> View -> Projection

Points in the vertex buffer are in "Object" space, which can be transformed to a shared "World" coordinate system. Transforming from "World" to "View" space sets the points to be located relative to the camera's location and orientation, and the final matrix transforms them into projected screen space.

This definition is the most suitable one for WVP as it cannot be explained,you have to see it for yourself(talked like a Morpheus in Matrix)

All the Effect-Applied Models or Primitive Objects use this way to make it right.

Thats why WVP is a must-have while writing effects.

Ok Lets run the project and see what happens.

 Fig2.gif

Allright thats it! If you rotate this cube you will see that every face of the has been painted to pink.

Now lets develop it further to make it look nicer

Update InitializeEffect function as seen below:

private void InitializeEffect()
        {
            basicEffectVertexDeclaration = new VertexDeclaration(
                graphics.GraphicsDevice, VertexPositionNormalTexture.VertexElements);

            basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
            basicEffect.Alpha = 1.0f;
            basicEffect.DiffuseColor = new Vector3(0.0f, 0.0f, 1.0f);
            basicEffect.SpecularColor = new Vector3(25.25f, 25.25f, 25.25f);
            basicEffect.SpecularPower = 5.0f;
            basicEffect.AmbientLightColor = new Vector3(2.75f, 2.75f, 2.75f);

            basicEffect.DirectionalLight0.Enabled = true;
            basicEffect.DirectionalLight0.DiffuseColor = Vector3.One;
            basicEffect.DirectionalLight0.Direction =
                Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f));
            basicEffect.DirectionalLight0.SpecularColor = Vector3.One;

            basicEffect.DirectionalLight1.Enabled = true;
            basicEffect.DirectionalLight1.DiffuseColor =
                new Vector3(1.5f, 2.5f, 3.5f);
            basicEffect.DirectionalLight1.Direction =
                Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f));
            basicEffect.DirectionalLight1.SpecularColor =
                new Vector3(0.5f, 0.5f, 0.5f);

            basicEffect.LightingEnabled = true;

            basicEffect.World = worldMatrix;
            basicEffect.View = viewMatrix;
            basicEffect.Projection = projectionMatrix;
        }


And now see what happens.

Fig3.gif

Much more nicer isn't it?

SpecularColor looks much more brighter than the previous one.

So thats it!

BasicEffect can help you do simple things but its worth a try.