Home > TutorialsComputer Graphics Essentials
2.9. Creating a transparent crate 
In this tutorial you will add transparency to a crate.



Click here to go to the forum discussion of this tutorial


 

2.9.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 the previous tutorials.
 

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

 

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

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


 

2.9.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;
BCMesh cube;

BCTransparencyRenderStrategy transparency
;

 

Advertisement
 

2.9.5. The Initialize method 
Blending is a technique with which the pixel being drawn can be combined with a pixel that has already been drawn, that's how the result of this tutorial is achieved; first the plane is drawn, then the crate is drawn, telling XNA how to combine the pixels conforming the crate with the pixels that already exist.

Notice that theres no way to say crate.transparent = true, all you can do is first, draw all non transparent objects and then draw transparent objects combining their color with the color of the already drawn objects.

Now, there are many ways in which the combination can be done, you can see how the actual combination is done in "Introduction to 3D game programming with Direct X 9.0c, A shader approach" by Frank D Luna.

In BetaCell, the combination is done is by using the different implementations of interface BetaCell.Util.RenderStates.BCRenderStateSetStrategy, which has two methods:

push: Prepares XNA to draw objects combining their color with the objects that have already been drawn.
pop: Resets XNA so that objects are drawn how they were drawn before the push call.

The objects drawn between the push and pop calls require more computation, so do as less work as possible between these calls.

The recreateScene method of this tutorial has no significant difference with the ones of previous texture tutorials, hence, won't be explained. The only relevant part of the initialize method of this tutorial is to create the actual render state set strategy, which is done through the following call:

transparency = new BCTransparencyRenderStrategy(false);

This is a simple strategy that draws transparent objects based on their alpha component. The object will be more transparent as the alpha component decreases.

The alpha component is set through the object's base color, so in the recreate scene method, the base color is created to be transparent:

BCColorSet colorSet =
    new BCColorSet(new Color(0,0,0,128));


Notice how the the alpha component of the base color is set to 128 (all components are in the range 0 to 255 so 0 is totally transparent and 255 is not transparent at all).

 

2.9.6. The Draw method
Here is where we do the magic, first we draw all non transparent objects (AKA the plane):

plane.Draw(gameTime);

Then the cube is drawn between a push and pop calls of the transparent render state set strategy.

transparency.push(device);
cube.Draw(gameTime);
transparency.pop(device);

 

2.9.7. Conclusion
Blending is a very interesting subject, the BetaCell approach let you create reusable blending techniques but to do that you must investigate how blending actually works in XNA.

Click here to go to the forum discussion of this tutorial

 

Advertisement
 

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

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;
        BCMesh cube;

        BCTransparencyRenderStrategy transparency;

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

            transparency = new BCTransparencyRenderStrategy(false);
            recreateScene();

            base.Initialize();
        }

        private void recreateScene()
        {
            BCMaterialBase material = new BCMaterialBase();
            material.specRange = 0.8f;
            material.diff = Color.White;
            material.spec = Color.White;
            material.amb = Color.LightGray;

            BCMaterialVisitor materialSetter = new BCMaterialVisitor(material);

            BCColorSet colorSet = new BCColorSet(new Color(0,0,0,128));
            BCDynamicEffectVisitor colorSetter =
                new BCDynamicEffectVisitor(colorSet.getFunction("Shader.ColorSet"), colorSet, 0);

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

            BCDynamicEffectVisitor lightSetter = new BCDynamicEffectVisitor(
                light.getFunction("Shader.Light.Classic.PixelPointLight"),
                light,
                BCDynamicEffect.MAX_FUNCTIONS
            );

            //-------------
            //cube
            //-------------

            cube = ProceduralModelers.CUBE_MODELER.createCube(10, 10, 10, new BCVertexPosNorTexContainer());
            BCMeshGraphicUtil.init(cube, device);

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

            BCTextureFeeder texFeeder = new BCTextureFeeder();
            texFeeder.addSampler(
                "tex",
                new BCSampler(
                    "LINEAR", "LINEAR", "LINEAR", "4",
                    "WRAP", "WRAP", "0xffffffff"
                )
            );
            BCDynamicEffectVisitor textureEffectSetter = new BCDynamicEffectVisitor(
                texFeeder.getFunction("Shader.Texture.Texture"),
                texFeeder,
                BCDynamicEffect.MAX_FUNCTIONS
            );

            cube.transform = Matrix.CreateTranslation(0, 5, 0);
            cube.visit(materialSetter);
            cube.visit(textureSetter);
            cube.visit(colorSetter);
            cube.visit(lightSetter);
            cube.visit(textureEffectSetter);

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

            textureSetter.strategy = new BCMemoryTextureStrategy("Content/gameAssets/bricka", content);

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

            plane.visit(materialSetter);
            plane.visit(textureSetter);
            plane.visit(colorSetter);
            plane.visit(lightSetter);
            plane.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);

            plane.Draw(gameTime);

            transparency.push(device);
            cube.Draw(gameTime);
            transparency.pop(device);

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