Home > TutorialsMeshes and I/O
3.1. Loading a mesh from blender 
In this tutorial you will learn how to load a mesh in a program and additionally, how to obtain the mesh using blender.



Click here to go to the forum discussion of this tutorial


 

3.1.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.
  • If you want to obtain the mesh from blender, a blender installation with a version equal or greater than 2.45 is required; if you just want to load the mesh, it's a game asset of the tutorial. 
 

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

 

3.1.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.Environment.Mesh.Content;
using BetaCell.Common.Bounding;
using BetaCell.Environment;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Environment.Light;
using BetaCell.Util.RenderStates
;

 

3.1.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 treeMesh;

BCAlphaGreaterRenderStrategy alphaBlock
;

 

3.1.5. Blender 

BetaCell can be extended to use any 3D mesh format, but out of the box, it supports the bcm (beta cell mesh) format. This is a new format and it's not supposed to replace or even compete with the already popular formats out there, it's just that the current formats have some undesired complications like:
  • The free ones have no visible owner, this allowed different parties to create extensions over the time to a point where writing an importer for them is very difficult.
  • The proprietary ones have a closed definition so writing an importer for them requires reverse engineering from the mesh files which is difficult.
  • Some formats store information that's not commonly used in a BetaCell program, this makes them complicated and writing an importer for them is also very difficult. 
The purpose of the BCM file format is to be an intermediary between popular 3D content creation tools and BetaCell, nothing more. In this tutorial you will load an oak tree in blender, export it to a BCM mesh and finally load it in BetaCell. If you want to skip the blender part of the tutorial, you can just download the oakTree.bcm mesh file, the textures and skip to 3.2.5.

default.jpg
In the tutorials of BetaCell we will be using blender as a 3D content creation tool, you can visit the bender home page from the links to learn about it's many usages.

The figure shows the oak.blend loaded in blender, there are many tutorials that can help you learn about blender in the web. The idea of this tutorial is to export this tree mesh. First we must prepare blender to be able to export BCM files.

You can find the export_BetaCell.py file in the downloads section; this  file is a Blender exporter that has to be placed in the following directory:

{blender installation}\.blender\scripts




For example, I pasted it in the following folder:

D:\Program Files\Blender Foundation\Blender\.blender\scripts

Because I installed blender in:

D:\Program Files\Blender Foundation\Blender

default.jpg
Once you paste the exporter, restart blender. If you pasted the exporter in the right location, when you select: file>export, the BetaCell option appears.

Now to export the tree, you must select both the leaves mesh and the bark mesh (you will notice they are selected because their border will turn pink) and click file>export>BetaCell. If you couldn't export the mesh, please investigate a little about blender and custom exporters.

If everything went fine, the bcm file with the name you selected will be created; for simplicity, choose the name oakTree.bcm.

Finally add the bcm mesh you just created in the gameAssets folder along with the two textures it uses (the ones in 3.1.2).

 

Advertisement
 

3.1.6. The Initialize method 

default.jpg
First let's make sure that we are building the mesh content right. Right click oak.bcm>properties; that will display the properties of the file. The file needs to be imported and processed as a mesh so the mesh importer and the mesh processor are used as shown in the image.




Most of the parts of the initialize method were discussed in previous tutorials, the new part is how to load a mesh.

treeMesh = BCMeshReader.readMesh(
    "Content/gameAssets/oak",
    null,
    device,
    content
);

The read mesh method receives the path of the mesh without the extension from the content folder, a null parameter that will be explained later in the tutorials and the device and the content objects.

Notice that we create a color setter and a light setter but not a texture setter; that's because the mesh reader creates the texture effect, the feeder and the samplers from the BCM file. Also notice that the init method isn't called; that's because it's called in the readMesh method.

Finally we visit the mesh, note that we don't use a color setter, the mesh loader already adds this effect for us:

treeMesh.visit(lightSetter);

 

3.1.7. The Draw method
Here we draw the tree blocking alpha vales; this is useful to let the leafs be created with a texture.

alphaBlock.push(device);
treeMesh.Draw(gameTime);
alphaBlock.pop(device);

 

3.1.8. Conclusion
This is a very important tutorial, you can now create the content of your application using blender and load it using BetaCell. This tutorial is very shallow in the blender subject because that information is already in the web.

Click here to go to the forum discussion of this tutorial

 

Advertisement
 

3.1.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.Mesh;
using BetaCell.Environment.Mesh.Content;
using BetaCell.Common.Bounding;
using BetaCell.Environment;
using BetaCell.Environment.Mesh.Visitors;
using BetaCell.Environment.Light;
using BetaCell.Util.RenderStates;

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

        BCAlphaGreaterRenderStrategy alphaBlock;

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

            alphaBlock = new BCAlphaGreaterRenderStrategy();

            //Mesh
            treeMesh = BCMeshReader.readMesh(
                "Content/gameAssets/oak",
                null,
                device,
                content
            );

            //-----
            //Light Effect
            //-----

            BCBasicLight light = new BCBasicLight();
            light.range = 3000;
            light.transform = Matrix.CreateTranslation(-2.5f, -2.5f, 0);
            light.cubAtten = 0;
            light.constAtten = 0.4f;
            light.linAtten = 0.05f;
            light.useShadows = false;

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

            treeMesh.visit(lightSetter);

            base.Initialize();
        }

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

        void buildViewMatrix()
        {
            Vector3 pos = new Vector3(6, 3.1f, 6);
            Vector3 look = new Vector3(-6, -1, -6);
            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);

            alphaBlock.push(device);
            treeMesh.Draw(gameTime);
            alphaBlock.pop(device);

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