Tutorial: Creating a Scene, adding terrain, adding objects, and adding a simple GUI to your scene

Getting Started with Visual3D.NET 
 

The following is a tutorial to get you started making a basic scene, adding terrain, adding objects, and adding a simple GUI to your scene. 
 
 

Building your first Demo Scene 
 

1.  Load Visual Studio 2008

2.  Load Visual3d.NET with dependencies  I loaded onto "C:\Visual3D.NET”

3.  Start Visual Studio 2008

4.  Load Tech Demos Project

    Visual Studio 2008 should come up with the start page and the “Recent Projects” on the upper left corner of the screen.  To open up tech demo project, “Recent Projects” press the open “Project…”  link or do File/New/Project.  The “Tech Demos” project file is found in:

        “C:\Visual3D.NET\Tech Demos/Tech Demos.csproj” 
 

5.  Create New Scene Class in “Tech Demos/Scenes” 
 

    The next step is to create a simple test scene.  Once you have loaded the Tech Demo Project, make sure with Visual Studio 2008, you “View” the “Solution Explorer”.  Under the solution explorer, open “Tech Demos” and then “Scenes”  Do a right click on “Scenes” and then “Add” then “New Class”

 
 
 

      Type: MyDemoScene.cs in the Add New Item – Tech Demos Name field and press the “Add” button. 
 

6.  Overwrite the entire contents of the default file “MyDemoScene.cs” created by Visual Studio 2008 with the following code: 
 

// start of my first simple demo scene with sky and terrain

using System;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Visual3D.Terrains;

using Visual3D.Terrains.Topography;

using Visual3D.Terrains.GIS2; 
 

namespace Visual3D.Demo.Scenes

{

    [Serializable]

    public class MyDemoScene : BaseDemoScene

    {

        public MyDemoScene()

        {

            InitialAmbientLight = new Color(128, 128, 128);

            InitialSkyDefinitionName = "Afternoon.sky.xml";

        } // end public MyDemoScene() 
 

        protected override void OnStarted()

        {

            SceneRootNode = new MyDemoRegion();

            base.OnStarted(); 
 

        } // end protected override void OnStarted()

    } // end public class MyDemoScene : BaseDemoScene 
 

    public class MyDemoRegion : BaseDemoRegion

    {

        private Terrains.InfiniteTerrain _terrain; 
 

        public MyDemoRegion()

        { 
 

        } // end public MyDemoRegion() 
 

        protected override void OnLoadStaticContent()

        {

            // Infinite terrain:

            _terrain = Terrains.InfiniteTerrain.SetSceneTerrain("GrassyFlat.InfiniteTerrain.xml");

            _terrain.Node.ShadowSettings.IsShadowReceiver = true; 
 

            base.OnLoadStaticContent();

        } // end protected override void OnLoadStaticContent() 
 

    } // end  public class MyDemoRegion : BaseDemoRegion 
 

} // end namespace Visual3D.Demo.Scenes 
 

// end of my first simple demo scene with sky and terrain 
 

7.  Note:

    As a matter of coding practice, I sometimes get lost in which end brace “}” is the end of which beginning brace “{“.  So I simply put a comment saying end and the actual name of procedure or class.  If I am using an if or while I may explain what the if is all about, not just repeating the code unless I have done such a good job with my variable names that the variable is truly self explanatory. 
     

8.  Modify Visual3d.NET/World/TechDemosWorld.cs to create a new menu item add the following new line: 
 

The main menu for Tech Demos is found in “C:\Visual3d.NET\World\TechDemosWorld.cs”.  Add the following line somewhere in the table.  I just copied and pasted a line and changed the line to the following: 
 

  , new SceneInfo("My Demo Scene", typeof(MyDemoScene))

 
 
 

9.  With Visual Studio 2008, build with  “F6” or click on the Build top menu button, and then “Build Solution”

 
 
 

10.  Now run "C:\Visual3D.NET\World Launcher.exe" 
 

11.  Open World “Tech Demos”

 
 
 

      See “My Demo Scene”  Which is the text typed in the line added to “TechDemoWorld.cs” 
 

12.  Click on the radio button next the “My Demo Scene”  and press start scene. 
 

       
 

Victory!  You have just created your first simple scene with a nice afternoon partly cloudy sky and a nice green grass infinite terrain. 
 
 

Adding Object and Avatar 
 

1.  Add the following include file to the top of the code: 
 

using Visual3D.Demo.Actors; 
 
 

2.  In MyDemoScene.cs in routine: “OnLoadStaticContent()” 
 

After the code

            // Infinite terrain:

           _terrain = Terrains.InfiniteTerrain.SetSceneTerrain("GrassyFlat.InfiniteTerrain.xml");

            _terrain.Node.ShadowSettings.IsShadowReceiver = true; 
 

Add the following: 
 

            Actor tree = new Actor("tree", "bigtree1.mesh", 1f);

            tree.Spatial.RelativePosition = new Vector3(20, 0f, 20);

            tree.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(tree); 
 

            Actor woman = new CasualHumanFemaleAvatar("woman", 5f, 1f);

            woman.Spatial.RelativePosition = new Vector3(0f, 0, 0f);

            woman.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(woman); 
 

3.  Build and run  and see the following new code:

 
 
 

4.  Fixing the Camera Focus: The problem is the starting camera position is off and we need to change the initial camera position and focus. 
 

Add the following lines to the routine “MyDemoScene()” 
 
 

            InitialCameraPosition = new Vector3(-10f, 3f, -10f);

            InitialCameraFocusPoint = new Vector3(70f, 30f, 100f); 
 

 
 

5.  The complete code so far will look like the following: 
 

using System;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Visual3D.Terrains;

using Visual3D.Terrains.Topography;

using Visual3D.Terrains.GIS2;

using Visual3D.Demo.Actors; 
 

namespace Visual3D.Demo.Scenes

{

    [Serializable]

    public class MyDemoScene : BaseDemoScene

    {

        public MyDemoScene()

        {

            InitialAmbientLight = new Color(128, 128, 128);

            InitialSkyDefinitionName = "Afternoon.sky.xml";

            InitialCameraPosition = new Vector3(-10f, 3f, -10f);

            InitialCameraFocusPoint = new Vector3(70f, 30f, 100f);

        } // end public MyDemoScene() 
 

        protected override void OnStarted()

        {

            SceneRootNode = new MyDemoRegion();

            base.OnStarted(); 
 

        } // end protected override void OnStarted() 
 

    } // end public class MyDemoScene : BaseDemoScene

    public class MyDemoRegion : BaseDemoRegion

    {

        private Terrains.InfiniteTerrain _terrain; 
 

        public MyDemoRegion()

        { 
 

        } // end public MyDemoRegion() 
 

        protected override void OnLoadStaticContent()

        {

            // Infinite terrain:

            _terrain = Terrains.InfiniteTerrain.SetSceneTerrain("GrassyFlat.InfiniteTerrain.xml");

            _terrain.Node.ShadowSettings.IsShadowReceiver = true; 
 

            Actor tree = new Actor("tree", "bigtree1.mesh", 1f);

            tree.Spatial.RelativePosition = new Vector3(20, 0f, 20);

            tree.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(tree); 
 

            Actor woman = new CasualHumanFemaleAvatar("woman", 5f, 1f);

            woman.Spatial.RelativePosition = new Vector3(0f, 0, 0f);

            woman.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(woman); 
 

            base.OnLoadStaticContent();

        } // end protected override void OnLoadStaticContent() 
 

    } // end  public class MyDemoRegion : BaseDemoRegion 
 

} // end namespace Visual3D.Demo.Scenes 
 

Adding GUI 
 
 

1. Add the following to the top of the code to let the routine know where to find the GUI includes. 
 

using Visual3D.UI;

using Visual3D.UI.Controls;

using Visual3D.UI.CommonForms; 
 

2.  Add the following to the end of the following routine OnStarted() 
 
 

            MyDemoGui Gui = new MyDemoGui();

            Gui.Initialize(this);

            Gui.Show(); 
 

3.  Add the following statement after the “}” of routine OnStarted() 
 
 

    public MyDemoGui Gui; 
 

4.  Add the following to OnLoadStaticContent() 
 
 

MyDemoGui gui = ((MyDemoScene)Scene).Gui; 
 
 

5.  Add the following class after the “}” of // end  public class MyDemoRegion : BaseDemoRegion 
 
 

    [Serializable]

    public class MyDemoGui : GuiForm

    {//I'm not 100% on this, however each interface that I've seen always has this

        //The reasoning behind this seems to be if you dive through the other interfaces

        //they seem to pull other UIs, this method allows them to all open the same window

       //Without pointers I imagine I'd do the same thing... but I'd go through a lot of

        //trial and error before realizing it. 
 

        public MyDemoGui()

            : base(GuiIds.New("FantasyGuiDemoMenu"), false, ScreenRectangle.FullSize)

        {

        }

        static public MyDemoGui _instance;

        public static MyDemoGui Instance

        {

            get

            {

                if (_instance != null)

                    return _instance;

                else

                {

                    MyDemoGui custom = new MyDemoGui();

                    custom.PrepareForUse();

                    return custom;

                }

            }

        }

        //destructor

        protected override void OnDispose(bool isDisposing)

        {

            base.OnDispose(isDisposing);

            _instance = null;

        } 
 

        //declare any other consoles you want to be able to pull from here... this includes every form item so add em

        protected Label _avatarName;//we'll show them their name.

        protected ProgressBar _healthBar;//and I think that we'll show them their health, that should be enough for now. 
 

        protected override void OnActivated()

        {

            base.OnActivated();//I'm guessing that this calls the BuildGui function.

        }

        protected override void BuildGui()

        {

            if (_healthBar != null)//not entirely certain on this one... seems like redundant error checking, but whatever.

                return; 
 

            float ScreenWidth = World.GuiRenderer.Width;

           float ScreenHeight = World.GuiRenderer.Height;

            int barWidth = 100;

            //public Label AddText(string name, float posX, float posY, float width, float height, string text);

            //is what you pull up if you look at it in metadata. So basically, it does what it says.

            //I wonder about that last string though. The next few lines are ripped straight from CharacterStatsConsole.cs

            _avatarName = (Label)this.AddText("AvatarName", 10, 65, barWidth, 20, "");

            //I'm going to guess that the first bit is just to reference, the second and third is the same as above

            //the barwidth.... I have no clue why its not just an int but its nice to know what that field does.

            //and the next few I do not know.

            _healthBar = (ProgressBar)this.AddColorProgressBar(

            "HealthBar", 10, 90, barWidth, 20, 0, 100, 100,

            ProgressBarConfig.Orientation.Horizontal);//can I call diagonal?

            //thats kindof a nifty feature though.

            _healthBar.Prefix = "H:";

            //Not sure on this one but guessing where the thing appears?

            this.TopSheet.ThemeFileName = SkinIDs.Fantasy;

        }

        public void UpdateBeforeRender()

        {//I think this is on the todo list, so put it here to be safe.

        }

        public void UpdateStats()

        {//ripped from their files, is obvious.

            if (!this.IsActive || !this.IsShowing)

                return; // not active!

            Avatar avatar = World.Selections.FocusedObject as Avatar;

            //need a reference on who to get the health on.

            if (avatar != null)

            {

                _avatarName.Text = avatar.Name; 
 

                // We have a player, update his stats

                _healthBar.MaxRange = avatar.MaxHitPoints;

                _healthBar.Progress = avatar.HitPoints;

            }

            return;

        }

    } // end public class MyDemoGui : GuiForm 
 

6.  Build and Run,  See green status bar with the hit points. 
 

 
 
 

7.  Double left click on the avatar, then do some single right clicks and watch the health bar go down. 
 

 
 

In case you made some mistake along the way. You can cut and paste the complete code should look like the following: 
 

using System;

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Visual3D.Terrains;

using Visual3D.Terrains.Topography;

using Visual3D.Terrains.GIS2;

using Visual3D.Demo.Actors; 
 

using Visual3D.UI;

using Visual3D.UI.Controls;

using Visual3D.UI.CommonForms; 
 
 

namespace Visual3D.Demo.Scenes

{

    [Serializable]

    public class MyDemoScene : BaseDemoScene

    {

        public MyDemoScene()

        {

            InitialAmbientLight = new Color(128, 128, 128);

            InitialSkyDefinitionName = "Afternoon.sky.xml";

            InitialCameraPosition = new Vector3(-10f, 3f, -10f);

            InitialCameraFocusPoint = new Vector3(70f, 30f, 100f);

        } // end public MyDemoScene() 
 

        protected override void OnStarted()

        {

            SceneRootNode = new MyDemoRegion();

            base.OnStarted(); 
 

            MyDemoGui Gui = new MyDemoGui();

            Gui.Initialize(this);

            Gui.Show(); 
 

        } // end protected override void OnStarted() 
 

        public MyDemoGui Gui; 
 

    } // end public class MyDemoScene : BaseDemoScene

    public class MyDemoRegion : BaseDemoRegion

    {

        private Terrains.InfiniteTerrain _terrain; 
 

        public MyDemoRegion()

        { 
 

        } // end public MyDemoRegion() 
 

        protected override void OnLoadStaticContent()

        {

            // Infinite terrain:

            _terrain = Terrains.InfiniteTerrain.SetSceneTerrain("GrassyFlat.InfiniteTerrain.xml");

            _terrain.Node.ShadowSettings.IsShadowReceiver = true; 
 

            Actor tree = new Actor("tree", "bigtree1.mesh", 1f);

            tree.Spatial.RelativePosition = new Vector3(20, 0f, 20);

            tree.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(tree); 
 

            Actor woman = new CasualHumanFemaleAvatar("woman", 5f, 1f);

            woman.Spatial.RelativePosition = new Vector3(0f, 0, 0f);

            woman.ShadowSettings.IsShadowCaster = true;

            Spatial.AddChild(woman); 
 

            MyDemoGui gui = ((MyDemoScene)Scene).Gui; 
 

            base.OnLoadStaticContent();

        } // end protected override void OnLoadStaticContent() 
 

    } // end  public class MyDemoRegion : BaseDemoRegion 
 

    [Serializable]

    public class MyDemoGui : GuiForm

    {//I'm not 100% on this, however each interface that I've seen always has this

        //The reasoning behind this seems to be if you dive through the other interfaces

        //they seem to pull other UIs, this method allows them to all open the same window

        //Without pointers I imagine I'd do the same thing... but I'd go through a lot of

        //trial and error before realizing it. 
 

        public MyDemoGui()

            : base(GuiIds.New("FantasyGuiDemoMenu"), false, ScreenRectangle.FullSize)

        {

        }

        static public MyDemoGui _instance;

        public static MyDemoGui Instance

        {

            get

            {

                if (_instance != null)

                    return _instance;

                else

                {

                    MyDemoGui custom = new MyDemoGui();

                    custom.PrepareForUse();

                    return custom;

                }

            }

        }

        //destructor

        protected override void OnDispose(bool isDisposing)

        {

            base.OnDispose(isDisposing);

            _instance = null;

        } 
 

        //declare any other consoles you want to be able to pull from here... this includes every form item so add em

        protected Label _avatarName;//we'll show them their name.

        protected ProgressBar _healthBar;//and I think that we'll show them their health, that should be enough for now. 
 

        protected override void OnActivated()

        {

            base.OnActivated();//I'm guessing that this calls the BuildGui function.

        }

        protected override void BuildGui()

        {

            if (_healthBar != null)//not entirely certain on this one... seems like redundant error checking, but whatever.

               return; 
 

            float ScreenWidth = World.GuiRenderer.Width;

            float ScreenHeight = World.GuiRenderer.Height;

            int barWidth = 100;

            //public Label AddText(string name, float posX, float posY, float width, float height, string text);

            //is what you pull up if you look at it in metadata. So basically, it does what it says.

            //I wonder about that last string though. The next few lines are ripped straight from CharacterStatsConsole.cs

            _avatarName = (Label)this.AddText("AvatarName", 10, 65, barWidth, 20, "");

            //I'm going to guess that the first bit is just to reference, the second and third is the same as above

            //the barwidth.... I have no clue why its not just an int but its nice to know what that field does.

            //and the next few I do not know.

            _healthBar = (ProgressBar)this.AddColorProgressBar(

            "HealthBar", 10, 90, barWidth, 20, 0, 100, 100,

            ProgressBarConfig.Orientation.Horizontal);//can I call diagonal?

            //thats kindof a nifty feature though.

            _healthBar.Prefix = "H:";

            //Not sure on this one but guessing where the thing appears?

            this.TopSheet.ThemeFileName = SkinIDs.Fantasy;

        }

        public void UpdateBeforeRender()

        {//I think this is on the todo list, so put it here to be safe.

        }

        public void UpdateStats()

        {//ripped from their files, is obvious.

            if (!this.IsActive || !this.IsShowing)

                return; // not active!

            Avatar avatar = World.Selections.FocusedObject as Avatar;

            //need a reference on who to get the health on.

            if (avatar != null)

            {

                _avatarName.Text = avatar.Name; 
 

                // We have a player, update his stats

                _healthBar.MaxRange = avatar.MaxHitPoints;

                _healthBar.Progress = avatar.HitPoints;

            }

            return;

        }

    } // end public class MyDemoGui : GuiForm 
 

} // end namespace Visual3D.Demo.Scenes 





by Mike Hoisington
 


Sources
http://game-engine.visual3d.net/wiki/tutorial-adding-gui
http://game-engine.visual3d.net/wiki/simple-scene-creation