Home > TutorialsComputer Graphics Essentials
2.6.Textured Scene
In this tutorial you practice the texturing techniques by completing the scene started in 1.2.



Click here to go to the forum discussion of this tutorial


 

2.6.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
  • For a better understanding, is preferred to have finished 2.3.
  • Completed tutorial 1.2
  • Completed tutorial 2.1
   
 

2.6.2. Game Assets 
Game assets [2.3.2] for this tutorial:

 

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

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

 

Advertisement
 

2.6.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 sphere;
BCMesh cylinder;
BCMesh plane;
BCProceduralRotator rotator
;

 


2.6.5. The Initialize method 
In order to wrap around the textures on the spheres and the cylinders, the following render states have to be set:

device.RenderState.Wrap0 = TextureWrapCoordinates.Zero;
device.RenderState.Wrap1 = TextureWrapCoordinates.Zero;

Please note that there's a single texture effect setter visitor, so the texture effect is the same for all meshes, nevertheless, each mesh has it's own texture, that's because as mentioned in [2.3.5] the textures are assigned to the mesh, not to the effect. Also note that we assign different textures to the meshes but ALL THE TEXTURES HAVE THE SAME NAME ("tex"), that's because the texture effect is expecting this name.
 

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

plane.Draw(gameTime);

 

2.6.7. Conclusion
This tutorial is the combination of 1.2, 2.1 and 2.3.

Click here to go to the forum discussion of this tutorial

 

Advertisement
 

2.6.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.Behavior.Procedural;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Environment;
using BetaCell.Effects.Composer;
using BetaCell.Environment.Light;
using BetaCell.Environment.Texture.Feeder;
using BetaCell.Util.Procedural;
using BetaCell.Common.Vertex;
using BetaCell.Environment.Texture;
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 sphere;
        BCMesh cylinder;
        BCMesh plane;
        BCProceduralRotator rotator;

        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();
            rotator = new BCProceduralRotator(0, 0.0f, 0.1f, 0f, 1000.0f);

            base.Initialize();
        }

        private void recreateScene()
        {
            //Creating a base material for the cube
            BCMaterialBase material = new BCMaterialBase();
            material.specRange = 0.8f;
            material.diff = Color.White;
            material.spec = Color.White;
            material.amb = Color.LightGray;
            BCMaterialVisitor materialVisitor = new BCMaterialVisitor(material);

            //Color set effect composition part
            BCColorSet colorSet = new BCColorSet(Color.Black);
            BCFunction baseColor = colorSet.getFunction("Shader.ColorSet");
            BCDynamicEffectVisitor colorSetter = new BCDynamicEffectVisitor(baseColor, colorSet, 0);

            //Light effect composition part
            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 lightPart = light.getFunction("Shader.Light.Classic.PixelPointLight");
            BCDynamicEffectVisitor lightSetter = new BCDynamicEffectVisitor(lightPart, light, 1);

            //Creating a sampler for the texture
            BCSampler sampler = new BCSampler(
                "LINEAR", "LINEAR", "LINEAR", "4",
                "WRAP", "WRAP", "0xffffffff"
            );

            //Creating a texture feeder for the texture
            //Adding a sampler per expected texture of the channel blend effect part
            BCTextureFeeder texFeeder = new BCTextureFeeder();
            texFeeder.addSampler("tex", sampler);

            //Getting the texture effect part function from the texture feeder
            BCFunction texturePart = texFeeder.getFunction("Shader.Texture.Texture");

            //Creating the texture effect setter visitor
            BCDynamicEffectVisitor textureEffectSetter =
                new BCDynamicEffectVisitor(texturePart, texFeeder, BCDynamicEffect.MAX_FUNCTIONS);

            //-------------
            //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 planeTex = new BCTextureVisitor(
                "tex",
                new BCMemoryTextureStrategy(content.Load<Texture2D>("Content/gameAssets/ground0"))
            );

            plane.visit(planeTex);
            plane.visit(materialVisitor);
            plane.visit(colorSetter);
            plane.visit(lightSetter);
            plane.visit(textureEffectSetter);

            //-------------
            //sphere
            //-------------

            sphere = ProceduralModelers.SPHERE_MODELER.createSlicedSphere(5, 6, 1,
                new BCVertexPosNorTexContainer());
            BCMeshGraphicUtil.init(sphere, device);

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

            sphere.visit(sphereTex);
            sphere.visit(materialVisitor);
            sphere.visit(colorSetter);
            sphere.visit(lightSetter);
            sphere.visit(textureEffectSetter);

            //-------------
            //cylinder
            //-------------

            cylinder = ProceduralModelers.CYLINDER_MODELER.createCylinder(5, 6, 1, 1,
                new BCVertexPosNorTexContainer());
            BCMeshGraphicUtil.init(cylinder, device);

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

            cylinder.visit(cylinderTex);
            cylinder.visit(materialVisitor);
            cylinder.visit(colorSetter);
            cylinder.visit(lightSetter);
            cylinder.visit(textureEffectSetter);
        }

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

        void buildViewMatrix()
        {
            Vector3 pos = new Vector3(30, 10, 30);
            Vector3 look = new Vector3(-3, -1, -3);
            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)
        {
        }

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

            Matrix rotMatrix = rotator.getRotationMatrix(gameTime);

            plane.transform = rotMatrix;
            plane.Draw(gameTime);
            drawCylinders(rotMatrix, gameTime);
            drawSpheres(rotMatrix, gameTime);

            BCLogger.instance.printFPS(gameTime);
            BCLogger.instance.flush();

            base.Draw(gameTime);
        }

        public void drawCylinders(Matrix rotMatrix, GameTime gameTime)
        {
            Matrix r, t;
            //Creates the compose transformation described i the tutorial
            r = Matrix.CreateRotationX((float)Math.PI / 2) * Matrix.CreateTranslation(0, 6, 0);

            //Draws 12 the cylinders
            for (float z = -30; z <= 30; z += 10)
            {
                //Creates the positional translation of the actual cylinder
                t = Matrix.CreateTranslation(-10.0f, 0.0f, z);
                //Sets the cylinder transformation as the composed transformation described in the
                //tutorial multiplied by the
                //positional translation that was just calculated
                cylinder.transform = r * t * rotMatrix;
                cylinder.Draw(gameTime);

                t = Matrix.CreateTranslation(10.0f, 0.0f, z);
                cylinder.transform = r * t * rotMatrix;
                cylinder.Draw(gameTime);
            }
        }

        public void drawSpheres(Matrix rotMatrix, GameTime gameTime)
        {
            Matrix t;
            for (float z = -30; z <= 30; z += 10)
            {
                t = Matrix.CreateTranslation(-10.0f, 8.0f, z);
                sphere.transform = t * rotMatrix;
                sphere.Draw(gameTime);

                t = Matrix.CreateTranslation(10.0f, 8.0f, z);
                sphere.transform = t * rotMatrix;
                sphere.Draw(gameTime);
            }
        }
    }
}