[PloobsEngine] Tutorial 4 – Lights and Cameras


 

This tutorial will teach you about the PloobsEngine Lights and Camera System. (tutorials series here)

It is very important to say that in this version the Light system is exclusive of the Deferred Rendering technich. We implemented lights for Forward Render also, but it is not included in the PLoobsEngine (performance issues >.<), we plan in the near future to make a tutorial about Phong Shading using that code as example.

Camera System

The PloobsEngine camera system is quite simple and intuitive. In few words: we have an interface called ICamera where all cameras extends. The engine provides some build in implementation for convenience but everyone can make yours as needed. All IScenes must have at least one camera active. You add, remove, interpolate, change …  cameras using the IWorld property called CameraManger.

Avaliable build-in Cameras:

  • CameraFirstPerson (classic FPS camera without restriction, use mouse and keyboard WASD QZ to controls it)
  • CameraFollowObject (camera that follows a IObject)
  • CameraFollowPath (Camera that follows a previous recorded path)
  • CameraStatic (Camera that does not change its location, normally used as base camera when building others (instead of extending from ICamera, sometimes is easier to extend from CameraStatic))

You can have more than one camera added to the current IWorld’s CameraManager, but only one is active at time (=P)

The following example shows how to add more than one camera in the IWorld and smoothly navigate between them: (this part is very intutive, so we wont bother you with obvious comments)

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using PloobsEngine;
using PloobsEngine.Cameras;
using PloobsEngine.Commands;
using PloobsEngine.DataStructure;
using PloobsEngine.Input;
using PloobsEngine.Light;
using PloobsEngine.Material;
using PloobsEngine.Modelo;
using PloobsEngine.Physics;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.SceneControl;
using PloobsEngine.Utils;
using PloobsEngine.Engine;

namespace IntroductionDemo4._0
{
    ///
    /// Camera Screen
    ///
    public class CameraScreens : IScene
    {
        BindKeyCommand bk;

        ///
        /// Circular list that holds the cameras (Circular list is a PloobsEngine build in data structure, we will talk about all of them in other tutorial)
        ///
        private CircularList camerasNames = new CircularList(3);

        protected override void SetWorldAndRenderTechnich(out IRenderTechnic renderTech, out IWorld world)
        {
            world = new IWorld(new BepuPhysicWorld(-9.8f, true), new SimpleCuller());

            DeferredRenderTechnicInitDescription desc = DeferredRenderTechnicInitDescription.Default();
            desc.UseFloatingBufferForLightMap = true;
            desc.BackGroundColor = Color.CornflowerBlue;
            renderTech = new DeferredRenderTechnic(desc);
        }

        protected override void LoadContent(PloobsEngine.Engine.GraphicInfo GraphicInfo, PloobsEngine.Engine.GraphicFactory factory, IContentManager contentManager)
        {
            base.LoadContent(GraphicInfo, factory, contentManager);                        

            #region Models

            ///Cria uma textura 1x1 com a cor branca
            Texture2D white = factory.CreateTexture2DColor(1,1, Color.White);
            {
                SimpleModel sm = new SimpleModel(factory, "..\\Content\\Model\\cubo");
                sm.SetTexture(white, TextureType.DIFFUSE);

                BoxObject pi = new BoxObject(new Vector3(100, 20, 0), 1,1,1, 5,new Vector3(100, 5, 100),Matrix.Identity,MaterialDescription.DefaultBepuMaterial());
                DeferredNormalShader shader = new DeferredNormalShader();
                ///Setando alguns parametros do material
                shader.SpecularIntensity = 0.01f;
                shader.SpecularPower = 50;
                IMaterial mat = new DeferredMaterial(shader);
                IObject obj3 = new IObject(mat, sm, pi);
                this.World.AddObject(obj3);
            }

            {
                SimpleModel sm = new SimpleModel(factory,"..\\Content\\Model\\cubo");
                sm.SetTexture(white, TextureType.DIFFUSE);

                BoxObject pi = new BoxObject(new Vector3(90, 30, 0), 1,1,1, 10,new Vector3(1),Matrix.Identity,MaterialDescription.DefaultBepuMaterial());
                DeferredNormalShader shader = new DeferredNormalShader();                

                IMaterial mat = new DeferredMaterial(shader);
                IObject obj3 = new IObject(mat, sm, pi);
                this.World.AddObject(obj3);
            }

            {
                SimpleModel sm = new SimpleModel(factory,"..\\Content\\Model\\cenario");
                IPhysicObject pi = new TriangleMeshObject(sm,Vector3.Zero,Matrix.Identity,Vector3.One,MaterialDescription.DefaultBepuMaterial());
                DeferredNormalShader shader = new DeferredNormalShader();
                IMaterial mat = new DeferredMaterial(shader);
                IObject obj3 = new IObject(mat, sm, pi);
                this.World.AddObject(obj3);
            }

            #endregion                                    

            #region NormalLight
            ///Conjunto de luzes direcionais
            DirectionalLightPE ld1 = new DirectionalLightPE(Vector3.Left, Color.White);
            DirectionalLightPE ld2 = new DirectionalLightPE(Vector3.Right, Color.White);
            DirectionalLightPE ld3 = new DirectionalLightPE(Vector3.Backward, Color.White);
            DirectionalLightPE ld4 = new DirectionalLightPE(Vector3.Forward, Color.White);
            DirectionalLightPE ld5 = new DirectionalLightPE(Vector3.Down, Color.White);
            float li = 0.4f;
            ld1.LightIntensity = li;
            ld2.LightIntensity = li;
            ld3.LightIntensity = li;
            ld4.LightIntensity = li;
            ld5.LightIntensity = li;
            this.World.AddLight(ld1);
            this.World.AddLight(ld2);
            this.World.AddLight(ld3);
            this.World.AddLight(ld4);
            this.World.AddLight(ld5);
            #endregion

            ///Creating the first Static Camera
            CameraStatic camx = new CameraStatic(new Vector3(130, 100, 700), Vector3.Zero);
            ///Naming it (To recover later)
            camx.Name = "default";
            camx.FarPlane = 3000;
            ///Adding to the manager (ITS NOT BEING ACTIVATED, JUST ADDED)
            this.World.CameraManager.AddCamera(camx, camx.Name);
            ///NOW ACTIVATING=P (If we add a camera using World.AddCamera(cam) we automatically set this camera as active)
            this.World.CameraManager.SetActiveCamera(camx.Name);
            ///Add to the circular list
            camerasNames.Value = camx.Name;
            camerasNames.Next();          

            ///Same for the second camera (this is not activated)
            CameraStatic cam2 = new CameraStatic(new Vector3(100, 100, 100), Vector3.Zero);
            cam2.Name = "StaticCamera";
            cam2.FarPlane = 3000;
            this.World.CameraManager.AddCamera(cam2, cam2.Name);
            camerasNames.Value = cam2.Name;
            camerasNames.Next();

            ///Again ...
            CameraStatic cam3 = new CameraStatic(new Vector3(500, 300, 300), Vector3.Zero);
            cam3.Name = "StaticCamera3";
            cam3.FarPlane = 3000;
            this.World.CameraManager.AddCamera(cam3, cam3.Name);
            camerasNames.Value = cam3.Name;
            camerasNames.Next();
            ///When pressing SPACE, a function will be called, WE COULD use the screen binding (but we did not ... no specific reason ....)
            SimpleConcreteKeyboardInputPlayable ikp = new SimpleConcreteKeyboardInputPlayable(StateKey.PRESS, Keys.Space, KeyStateChange);
            bk = new BindKeyCommand(ikp, BindAction.ADD);
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(bk);
        }

        protected override void Draw(GameTime gameTime, RenderHelper render)
        {
            base.Draw(gameTime, render);
            render.RenderTextComplete("Demo: Preset Cameras", new Vector2(GraphicInfo.Viewport.Width - 315, 15), Color.White,Matrix.Identity);
            render.RenderTextComplete("Space = Move to next camera", new Vector2(GraphicInfo.Viewport.Width - 315, 40), Color.White, Matrix.Identity);
        }

        ///
        /// When Escape is pressed
        ///
        ///
        void KeyStateChange(InputPlayableKeyBoard ipk)
        {
            ///TO CHANGE ONLY IN THE END OF THE INTERPOLATION
            //if (mundo.CameraManager.ActiveCameraType != State.INTERPOLATING)
            //{
                //camerasNames.Next();
                //mundo.CameraManager.SetActiveCamera(camerasNames.Value,InterpolationType.BYSTEP, 0.005f);
                //mundo.CameraManager.SetActiveCamera(camerasNames.Value, InterpolationType.BYTIME, 3);
            //}

            ///Advance on position in the circular list
            camerasNames.Next();
            ///Activate the current camera in the circular list
            ///There are two types of interpolator (take care of the camera transition smoothly). The first takes a fixed time (BYTIME( to make the transition and the second use a fixed speed (BYSTEP))
            this.World.CameraManager.SetActiveCamera(camerasNames.Value, InterpolationType.BYTIME, 3);
        }

        protected override void CleanUp(EngineStuff engine )
        {
            bk.BindAction = BindAction.REMOVE;
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(bk);
        }

    }
}

Pretty easy =P In the IntroductionDemos you can find this sample and another one showing how to record a path and play it after.

Lights

As said in the beggining, Lights are only avaliable if you choose the DeferredRenderTechnich. We have the following Light Types avaliable: (we wont explain what each light is, good reference for this are: http://robertokoci.com/basics-of-light-in-3d-computer-graphics/ and in this marvelous book http://www.realtimerendering.com/book.html)

  • DirectionalLightPE
  • PointLightPE
  • SpotLightPE

The silly name DirectionalLightPE is used because in XNA 4.0, the xna already has a class called DirectionalLight, so to avoid confusion we changed the name (PE = Ploobs Engine =P)

We use Phong Equation to calculate each light contribuition. This blog post from Catalin Zilma shows some implementation details (if you want to play with any deferred rending light code, first look at that post) , we used a slightly diferent aproach.

The Directional Light and the SpotLight can cast Shadow (we will talk about it in the future =P).

You can create your own lights, but it is not simple, you need to extend ILight,extend IDeferredLightMap and create a shader that procces you light and create the light map for it. (we will talk about this in other tutorial).

The Introduction packages has some samples explaining how to add, remove and customize the behavior of the lights. We wont show them here cause this is very straightforward, instead we will show a simple but very interesting sample that integrates lights and physics.

Ball Throw Example

We will build a sample with the following behavior:

  • When left mouse button is clicked, a ball with a point light attached to it will be throw in the direction of the camera target vector
  • When right mouse button is clicked, a point light is placed in the current cameras position

This sample with show lots of things we already seen in last tutorials.

To begin, we need to extend the Point Light, cause we need to update its position every frame according to the Ball. The implementation is show bellow:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Light;
using PloobsEngine.Physics;

namespace AdvancedDemo4._0
{
    ///
    /// Point light that follow an object
    ///
    public class MoveablePointLight : PointLightPE
    {

        IPhysicObject ob;

        public MoveablePointLight(IPhysicObject obj, Color color, float lightRadius, float lightIntensity)
            : base(obj.Position, color, lightRadius, lightIntensity)
        {
            this.ob = obj;
        }

        public override Vector3 LightPosition
        {
            get
            {
                return ob.Position;
            }
            set
            {
                ob.Position = value;
            }
        }

    }
}

We just overrided the LightPosition property, return the object position instead of the light static position.

The following code shows how to bind the mouse buttons, create the ball and the point light.

using System;
using PloobsEngine.SceneControl;
using PloobsEngine;
using PloobsEngine.Input;
using Microsoft.Xna.Framework;
using PloobsEngine.Physics.Bepu;
using PloobsEngine.Modelo;
using PloobsEngine.Material;
using Microsoft.Xna.Framework.Graphics;
using PloobsEngine.Utils;
using PloobsEngine.Commands;
using Microsoft.Xna.Framework.Input;
using PloobsEngine.Light;
using PloobsEngine.Engine;
using PloobsEngine.Physics;

namespace EngineTestes
{
    public class LightThrowBepu
    {
        IWorld _mundo;
        Random rd = new Random();
        BindMouseCommand mm0 = null;
        BindMouseCommand mm1 = null;
        GraphicFactory factory;

        public void CleanUp()
        {
            mm0.BindAction = BindAction.REMOVE;
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(mm0);

            mm1.BindAction = BindAction.REMOVE;
            CommandProcessor.getCommandProcessor().SendCommandAssyncronous(mm1);
        }        

        public LightThrowBepu(IWorld mundo,GraphicFactory factory)
        {
            this.factory = factory;
            _mundo = mundo;
            {
                ///Register a function to be called when the the mouse is pressed
                InputPlaybleMouseBottom ip1 = new SimpleConcreteMouseBottomInputPlayable(StateKey.PRESS, EntityType.IOBJECT, MouseButtons.LeftButton, mousebuttonteste);
                mm0 = new BindMouseCommand(ip1, BindAction.ADD);
                CommandProcessor.getCommandProcessor().SendCommandAssyncronous(mm0);
            }
            {
                InputPlaybleMouseBottom ip = new SimpleConcreteMouseBottomInputPlayable(StateKey.PRESS, EntityType.IOBJECT, MouseButtons.RightButton, mousebuttontesteRight);
                mm1 = new BindMouseCommand(ip, BindAction.ADD);
                CommandProcessor.getCommandProcessor().SendCommandAssyncronous(mm1);
            }

        }

        public void mousebuttontesteRight(MouseState ms)
        {
            PointLightPE pl = new PointLightPE(_mundo.CameraManager.ActiveCamera.Position, StaticRandom.RandomColor(), 100, 5);
            pl.UsePointLightQuadraticAttenuation = true;
            _mundo.AddLight(pl);
        }

        int i = 0;
        public void mousebuttonteste(MouseState ms)
        {
            ///Create an object
            IObject physObj = SpawnPrimitive(_mundo.CameraManager.ActiveCamera.Position, Matrix.CreateRotationX(0.5f));
            physObj.PhysicObject.Velocity = (_mundo.CameraManager.ActiveCamera.Target - _mundo.CameraManager.ActiveCamera.Position) * 15.0f;

            ///Create a light that follow an object
            MoveablePointLight mvp = new MoveablePointLight(physObj.PhysicObject as SphereObject, new Color((float)rd.NextDouble(),(float) rd.NextDouble(),(float) rd.NextDouble()),25, 5);
            mvp.UsePointLightQuadraticAttenuation = true;
            ///Add them to the world
            _mundo.AddLight(mvp);
            physObj.Name = "FlyingBall " + ++i;
            _mundo.AddObject(physObj);

        }
        ///
        /// Create a simple Sphere object
        ///
        ///

        ///

        ///
        private IObject SpawnPrimitive(Vector3 pos, Matrix ori)
        {
            ///Load a Model with a custom texture
            SimpleModel sm2 = new SimpleModel(factory,"Model\\ball");
            sm2.SetTexture(factory.CreateTexture2DColor(1,1,Color.White,false), TextureType.DIFFUSE);
            DeferredNormalShader nd = new DeferredNormalShader();
            IMaterial m = new DeferredMaterial(nd);
            SphereObject  pi2 = new SphereObject(pos, 1,0.5f,1,MaterialDescription.DefaultBepuMaterial());
            IObject o = new IObject(m,sm2,pi2);
            return o;
        }

    }
}

Nothing new here =P, just the same stuff we learned from previous tutorials.

The code for this demo can be found in our Introduction Demos package (called LightThrowBepu.cs and MoveablePointLight.cs), you can download it here. (there are lots of others demos in this package from the previous tutorials =P).

Any doubts, critics, suggestions, pls go to our forum or leave a comment here.

See you guys =P

Links

 

, , , , , ,

  1. #1 by Kristin on 17 de janeiro de 2017 - 2:14 am

    No added fees to Offshore Handbook or the obtaining bank, or
    any other 3rd party, need be made prior to your company will prepare to accept settlement by bank card online.

  2. #2 by pc games free download on 17 de janeiro de 2017 - 2:15 am

    I’ve been browsing online more than 3 hours today, yet I never found any interesting article like yours. It’s pretty worth enough for me. Personally, if all web owners and bloggers made good content as you did, the web will be a lot more useful than ever before.

  3. #3 by quibids strategy 2013 on 17 de janeiro de 2017 - 2:17 am

    Hello there! This is kind of off topic but I need some help from an established blog.
    Is it tough to set up your own blog? I’m not
    very techincal but I can figure things out pretty quick.
    I’m thinking about creating my own but I’m not sure where to start.
    Do you have any tips or suggestions? Appreciate it

  4. #4 by joma jewellery inverness on 17 de janeiro de 2017 - 2:26 am

    Among sailors, many imagine that if their our bodies
    were recovered after a sea voyage mishap, the one who recovered the physique could declare the earring
    to be the fee for a correct burial.

  5. #5 by Lovense on 17 de janeiro de 2017 - 2:27 am

    I read this article completely on the topic of the
    comparison of hottest and preceding technologies, it’s amazing article.

  6. #6 by Thao on 17 de janeiro de 2017 - 2:27 am

    Keep up to date on funds: late or missed funds for loans, credit
    cards or utilities are recorded in your credit score report
    and will stay there for years.

  7. #7 by android games free download on 17 de janeiro de 2017 - 2:39 am

    I like this weblog very much, Its a real nice office to read and get information.

  8. #8 by Création sites internet Québec on 17 de janeiro de 2017 - 2:47 am

    Hi, just wanted to mention, I loved this article. It was helpful.
    Keep on posting!

  9. #9 by カルティエ 結婚指輪 評判 toeic on 17 de janeiro de 2017 - 3:00 am

    ルイヴィトン – N級バッグ、財布 専門サイト問屋
    弊社は販売LOUIS VUITTON) バッグ、財布、 小物類などでございます。
    弊社は「信用第一」をモットーにお客様にご満足頂けるよう、
    送料は無料です(日本全国)! ご注文を期待しています!
    下記の連絡先までお問い合わせください。
    是非ご覧ください!
    激安、安心、安全にお届けします.品数豊富な商
    商品数も大幅に増え、品質も大自信です
    100%品質保証!満足保障!リピーター率100%!
    カルティエ 結婚指輪 評判 toeic http://giginza.com/article/list.html

  10. #10 by Best Travel Deals on 17 de janeiro de 2017 - 3:23 am

    you’re actually a excellent webmaster. The website loading speed is incredible. It kind of feels that you’re doing any distinctive trick. Also, The contents are masterpiece. you have done a great activity on this subject!

  11. #11 by Types Of Lawyers on 17 de janeiro de 2017 - 3:26 am

    Hello. Great job. I did not imagine this. This is a splendid story. Thanks!

  12. #12 by wifey on 17 de janeiro de 2017 - 3:36 am

    Hello there, You have done a great job. I will definitely digg it and personally suggest to my friends.
    I’m confident they will be benefited from this website.

  13. #13 by psychic readings by phone on 17 de janeiro de 2017 - 3:44 am

    Oh my goodness! a terrific article dude. I appreciate you
    for sharing it.

  14. #14 by log cabin holidays looe cornwall on 17 de janeiro de 2017 - 3:54 am

    You will be amazed that such landscapes in fact exists in UK as well as
    be thankful that you in fact come to know regarding log cabins.

  15. #15 by Roseanna on 17 de janeiro de 2017 - 3:55 am

    SoFi, which started as a student loan refinancing firm, has recently began providing personal loans as nicely, with a few of the best charges
    in the trade.

  16. #16 by barbour shop online on 17 de janeiro de 2017 - 3:58 am

    Hey great weblog, just looking about some blogs, appears a pretty nice platform youre making use of. Im currently using WordPress for a couple of of my web sites but looking to change 1 of them more than to a platform comparable to yours as being a trial run. Anything in specific youd recommend about it?
    barbour shop online http://www.barbourgoutlet.com

  17. #17 by patagonia south america on 17 de janeiro de 2017 - 4:24 am

    Your internet site came up in my research and I’m taken by what you have written on this topic. I am presently extending my enquiry and thus cannot contribute further, nonetheless, I have bookmarked your online world content and will be returning to keep up with any next updates. Just Now love it and gives thank you for tolerating my remark.
    patagonia south america http://www.bedcapdealers.com

  18. #18 by cheap real ugg boots uk sale on 17 de janeiro de 2017 - 4:30 am

    Well when I notice natural healing , I assume of all of the other remedies for depression internet sites which possess or show some chinese herbal remedies and I cant assist but to consider the medicines herbal and various XXXX due to the fact once other people, I imply all of my friends possess attempted medicines herbal , they possess often appear up dissatisfied with herbal supplements stuff.
    cheap real ugg boots uk sale http://www.uggoutletstoreu.us

  19. #19 by รับทำ seo ราคาถูก on 17 de janeiro de 2017 - 4:35 am

    I do not even know how I ended up here, but I thought this post was great.
    I do not know who you are but certainly you are going to a famous blogger if you are not already 😉 Cheers!

  20. #20 by евтини самолетни билети варна софия on 17 de janeiro de 2017 - 4:40 am

    After study a few of the blog posts on your website now, and I truly like your way of blogging. I bookmarked it to my bookmark website list and will be checking back soon. Pls check out my web site as well and let me know what you think.

  21. #21 by Kostenlos on 17 de janeiro de 2017 - 4:42 am

    I’m no longer positive the place you’re getting your info, but great topic.
    I must spend a while finding out more or figuring out more.
    Thank you for great info I used to be looking for this
    information for my mission.

1 1.122 1.123 1.124
(não será publicado)