Home > TutorialsComputer Graphics Essentials
2.2. Generating Waves
In this tutorial you will exercise the concept of effect composition by adding three effects together. This tutorial also introduces the XNA update method.



Click here to go to the forum discussion of this tutorial


 

2.2.1. Prerequisites
default.jpg
Before you start this tutorial make sure that you have:
  • Installed XNA Game Studio 3.1
  • Downloaded the starter project from the downloads section
  • Successfully run the starter project
   
 

2.2.2. The using statements
Besides the using statements from the starter project, this tutorial needs the following using statements:

using BetaCell.Environment.Mesh;
using BetaCell.Dynamic.Waves;
using BetaCell.Environment;
using BetaCell.Environment.Light;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Effects.Composer;
using BetaCell.Util.Procedural;
using BetaCell.Common.Vertex
;

 

2.2.3. Game Attributes 
The attributes that come with the starter project are explained in tutorial section 1.1.4.

For this tutorial we are going to be needing the following attributes:

BCMesh plane;
BCWavesFeeder wavesFeeder;

 

Advertisement
 

2.2.4. The Initialize method 
You can take a look at the initialization of the base color and lightning effect composition parts at [1.1.6] and [2.1.3]. To learn about the creation of a plane, see [1.2.4].

To add waves to the plane we are going to need a waves feeder, which is constructed with the following line:

wavesFeeder = new BCWavesFeeder();

This object will be responsible to update the waves related parameters of the effect. In order to slow down the waves a little bit, the moduler attribute of the waves feeder is used:

wavesFeeder.gModuler = 250;

Now we are going to obtain the effect composition part that represents the waves in the final effect, this is done with the following line:

BCFunction wavesFunction =
        wavesFeeder.getFunction("Actuator.Waves.RadialWaves");


After that, we create the visitor [1.2.4] that will set the waves effect part [2.1.3] to the effect of the plane.

BCDynamicEffectVisitor wavesSetter =
        new BCDynamicEffectVisitor(wavesFunction, wavesFeeder, 0);


Finally, the plane is created [1.2.4] and visited by the color, the light and the waves visitors.

plane = ProceduralModelers.PLANE_MODELER.createPlane(250, 250, 0.125f, 0.125f, new Vector3(0, 0, 0), new BCVertexPosContainer(), 1);
BCMeshGraphicUtil.init(plane, device);

plane.visit(colorSetter);
plane.visit(lightSetter);
plane.visit(wavesSetter);


 

 2.2.5. The Update method
The update method is used to perform operations that change the scene over time; a good example is to update the waves feeder in order to change the waves over time. The code that does that is:

wavesFeeder.gTime = (float)-gameTime.TotalGameTime.TotalMilliseconds;
 
In XNA and in games in general there are two important times that are handled, one is the time since the last update, which is the time elapsed since the last update call was made by XNA, the other is the total time, which is the time since start of the application.

The waves effect works with the total time; in this particular case, the time is negative to make the waves go out, you can change this to see what happens.
 

2.2.6. The Draw method
Nothing new, just draw the plane:

plane.Draw(gameTime);

 

2.2.7. Conclusion
You can consider this tutorial a little practice, the results though are some what fancy aren't they?

Click here to go to the forum discussion of this tutorial

 

Advertisement
 

2.2.8. Complete source code
using System;
using System.Collections.Generic;
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.Net;
using Microsoft.Xna.Framework.Storage;

using BetaCell.Debug;
using BetaCell.Util.GlobalInfo.Content;
using BetaCell.Environment.Camera;
using BetaCell.Util.GlobalInfo;

using BetaCell.Environment.Mesh;
using BetaCell.Dynamic.Waves;
using BetaCell.Environment;
using BetaCell.Environment.Light;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Effects.Composer;
using BetaCell.Util.Procedural;
using BetaCell.Common.Vertex;

namespace Starter
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        //Game attributes
        GraphicsDeviceManager graphics;
        GraphicsDevice device;
        ContentManager content;

        BCFirstPersonHumanCamera camera;
        //end game attributes

        //This tutorial's attributes
        BCMesh plane;
        BCWavesFeeder wavesFeeder;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;
            content = new ContentManager(Services);
#if(XBOX360)
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 768;
#else
            graphics.PreferredBackBufferWidth = 852;
            graphics.PreferredBackBufferHeight = 480;
#endif
        }

        protected override void Initialize()
        {
            //base initialization
            device = graphics.GraphicsDevice;

            BCLogger.instance.init(device, content);
            BCInitializationManager.initialize(content);

            OnActivated(null, null);

            recreateScene();

            base.Initialize();
        }

        private void recreateScene()
        {
            BCColorSet colorSet = new BCColorSet(Color.Black);
            BCFunction baseColor = colorSet.getFunction("Shader.ColorSet");
            BCDynamicEffectVisitor colorSetter = new BCDynamicEffectVisitor(baseColor, colorSet, 0);

            BCBasicLight light = new BCBasicLight();
            light.range = 200;
            light.transform = Matrix.CreateTranslation(20, 20, 10);
            light.constAtten = 1;
            light.linAtten = 0;
            light.cubAtten = 0;
            light.spotRange = 0.9f;
            light.useShadows = false;

            BCFunction lightFunction = light.getFunction("Shader.Light.Classic.PixelPointLight");
            BCDynamicEffectVisitor lightSetter = new BCDynamicEffectVisitor(lightFunction, light, 1);

            wavesFeeder = new BCWavesFeeder();
            wavesFeeder.gModuler = 250;
            BCFunction wavesFunction = wavesFeeder.getFunction("Actuator.Waves.RadialWaves");
            BCDynamicEffectVisitor wavesSetter = new BCDynamicEffectVisitor(wavesFunction, wavesFeeder, 0);

            //-------------
            //plane
            //-------------

            plane = ProceduralModelers.PLANE_MODELER.createPlane(150, 150, 0.125f, 0.125f,
                                             new Vector3(0, 0, 0), new BCVertexPosContainer(), 1);
            BCMeshGraphicUtil.init(plane, device);

            plane.visit(colorSetter);
            plane.visit(lightSetter);
            plane.visit(wavesSetter);
        }

        protected override void OnActivated(object sender, EventArgs args)
        {
            buildViewMatrix();
            base.OnActivated(sender, args);
        }

        void buildViewMatrix()
        {
            Vector3 pos = new Vector3(30, 30, 30);
            Vector3 look = new Vector3(-1, -1, -1);
            look.Normalize();

            camera = new BCFirstPersonHumanCamera(look, pos,
                MathHelper.PiOver4,
                (float)this.Window.ClientBounds.Width / (float)this.Window.ClientBounds.Height,
                1f, 200);

            BCGlobalInfo.instance.setMatrix(
                BCGlobalInfo.VIEW_INDEX,
                camera.getViewMatrix(-1)
            );

            BCGlobalInfo.instance.setMatrix(
                BCGlobalInfo.PROJECTION_INDEX,
                camera.getProjectionMatrix(-1)
            );
        }

        protected override void Update(GameTime gameTime)
        {
            wavesFeeder.gTime = (float)-gameTime.TotalGameTime.TotalMilliseconds;
        }

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.White, 1.0f, 0);

            plane.Draw(gameTime);

            BCLogger.instance.printFPS(gameTime);
            BCLogger.instance.flush();
            base.Draw(gameTime);
        }
    }
}