Home > TutorialsComputer Graphics Essentials
2.7. Scroll two textures in a plane
In this tutorial you will learn how to use the scroll texture effect and reinforce the sampler - feeder - texture - mesh relationship.



Click here to go to the forum discussion of this tutorial


 

2.7.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.7.2. Game Assets 
Game assets [2.3.2] for this tutorial:

 

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

using BetaCell.Environment;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Util.Procedural;
using BetaCell.Common.Vertex;
using BetaCell.Environment.Mesh;
using BetaCell.Environment.Texture;
using BetaCell.Environment.Texture.Feeder;
using BetaCell.Effects;


 

2.7.4. 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;
BCTimedTextureFeeder timedTexFeeder
;

 

Advertisement
 

2.7.5. The Initialize method 
This tutorial is going to need a texture feeder capable of maintaining a time state and setting it to the effect, also is introducing a new texture effect that scrolls two textures over a mesh.

The important lines will be explained, we'll start by defining the visitors that will set the textures in the plane mesh:

BCTextureVisitor cloud0 = new BCTextureVisitor(
    "tex",
    new BCMemoryTextureStrategy(content.Load<Texture2D>("Content/gameAssets/cloud0"))
);

BCTextureVisitor cloud1 = new BCTextureVisitor(
    "tex1",
    new BCMemoryTextureStrategy(content.Load<Texture2D>("Content/gameAssets/cloud1"))
);

Notice that the name of the textures are "tex" and "tex1"; that's because the scroll texture effect is expecting these texture names.

Now we are going to create the texture feeder and add the necessary samplers to it.

timedTexFeeder = new BCTimedTextureFeeder();
timedTexFeeder.addSampler(
    "tex",
    new BCSampler(
        "LINEAR", "LINEAR", "LINEAR", "4",
        "WRAP", "WRAP", "0xffffffff"
    )
);
timedTexFeeder.addSampler(
    "tex1",
    new BCSampler(
        "LINEAR", "LINEAR", "LINEAR", "4",
        "WRAP", "WRAP", "0xffffffff"
    )
);

The BCTimedTextureFeeder is a subclass of BCTextureFeeder and it's purpose is to maintain a time to set to the effect, for it to change the way the texture is applied to the mesh over time.

Then a sampler for each texture is added to the feeder; notice that the names with which the samplers are added to the feeder are the same than the names with which the textures are added to the mesh and are the names of the textures that the scroll texture effect is expecting.

Now the visitor is created and the plane is visited:

BCDynamicEffectVisitor textureEffectSetter =
    new BCDynamicEffectVisitor(
        timedTexFeeder.getFunction("Shader.Texture.Motion.ScrollTexture"),
        timedTexFeeder,
        BCDynamicEffect.MAX_FUNCTIONS
    );

plane.visit(cloud0);
plane.visit(cloud1);
plane.visit(textureEffectSetter);

Notice that the BCFunction is obtained from the timed texture feeder and set to the dynamic effect visitor in a single statement, also notice that the feeder from which the function is obtained is the same one from used as the feeder parameter of the dynamic effect visitor.

The BCDynamicEffect.MAX_FUNCTIONS parameter just states that the scroll texture effect part is to be the last effect part to apply in the final effect. 

 

 2.7.6. The Update method
Here we update the time in the timed texture feeder to update the texture position.

timedTexFeeder.gTime = (float)gameTime.TotalGameTime.TotalSeconds / 10;

 

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

plane.Draw(gameTime);

 

2.7.8. Conclusion
This tutorial was a reinforcement of the texture concepts introduced in previous tutorials.

Click here to go to the forum discussion of this tutorial

 

Advertisement
 

2.7.9. 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;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Util.Procedural;
using BetaCell.Common.Vertex;
using BetaCell.Environment.Mesh;
using BetaCell.Environment.Texture;
using BetaCell.Environment.Texture.Feeder;
using BetaCell.Effects;

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;
        BCTimedTextureFeeder timedTexFeeder;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;
            content = new ContentManager(Services);
#if(XBOX360)
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
#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.White);
            BCDynamicEffectVisitor colorSetter =
                new BCDynamicEffectVisitor(colorSet.getFunction("Shader.ColorSet"), colorSet, 0);

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

            plane = ProceduralModelers.PLANE_MODELER.createPlane(4, 4, 25, 25, new Vector3(0, 0, 0),
                new BCVertexPosNorTexContainer(), 1);
            BCMeshGraphicUtil.init(plane, device);

            //Setting texture
            BCTextureVisitor cloud0 = new BCTextureVisitor(
                "tex",
                new BCMemoryTextureStrategy(content.Load<Texture2D>("Content/gameAssets/cloud0"))
            );

            BCTextureVisitor cloud1 = new BCTextureVisitor(
                "tex1",
                new BCMemoryTextureStrategy(content.Load<Texture2D>("Content/gameAssets/cloud1"))
            );

            timedTexFeeder = new BCTimedTextureFeeder();
            timedTexFeeder.addSampler(
                "tex",
                new BCSampler(
                    "LINEAR", "LINEAR", "LINEAR", "4",
                    "WRAP", "WRAP", "0xffffffff"
                )
            );
            timedTexFeeder.addSampler(
                "tex1",
                new BCSampler(
                    "LINEAR", "LINEAR", "LINEAR", "4",
                    "WRAP", "WRAP", "0xffffffff"
                )
            );

            BCDynamicEffectVisitor textureEffectSetter =
                new BCDynamicEffectVisitor(
                    timedTexFeeder.getFunction("Shader.Texture.Motion.ScrollTexture"),
                    timedTexFeeder,
                    BCDynamicEffect.MAX_FUNCTIONS
                );

            plane.visit(cloud0);
            plane.visit(cloud1);
            plane.visit(colorSetter);
            plane.visit(textureEffectSetter);
        }

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

        void buildViewMatrix()
        {
            Vector3 pos = new Vector3(-70, 40, -70);
            Vector3 look = new Vector3(7, -4, 7);
            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)
        {
            timedTexFeeder.gTime = (float)gameTime.TotalGameTime.TotalSeconds / 10;
        }

        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);
        }
    }
}