Deferred Engine Playground - download

for example here the bloomshader rendermodule

using DeferredEngine.Recources;
using DeferredEngine.Renderer.Helper;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;

 
    namespace DeferredEngine.Renderer.RenderModules
{
   
    public class BloomShaderModule : IDisposable
    {
        #region fields & properties

        //resolution
        private int _width;
        private int _height;

        //RenderTargets
        private RenderTarget2D _bloomRenderTarget2DMip0;
        private RenderTarget2D _bloomRenderTarget2DMip1;
        private RenderTarget2D _bloomRenderTarget2DMip2;
        private RenderTarget2D _bloomRenderTarget2DMip3;
        private RenderTarget2D _bloomRenderTarget2DMip4;
        private RenderTarget2D _bloomRenderTarget2DMip5;
 
 
 
        //Preset variables for different mip levels
        private float _bloomRadius1 = 1.0f;
        private float _bloomRadius2 = 1.0f;
        private float _bloomRadius3 = 1.0f;
        private float _bloomRadius4 = 1.0f;
        private float _bloomRadius5 = 1.0f;

        private float _bloomStrength1 = 1.0f;
        private float _bloomStrength2 = 1.0f;
        private float _bloomStrength3 = 1.0f;
        private float _bloomStrength4 = 1.0f;
        private float _bloomStrength5 = 1.0f;
 
        private float _radiusMultiplier = 1.0f;


        #region public fields + enums

        public bool BloomUseLuminance = true;
        public int BloomDownsamplePasses = 5;

        //enums
        public enum BloomPresets
        {
            Wide,
            Focussed,
            Small,
            SuperWide,
            Cheap
        };

        #endregion

        #region properties
        public BloomPresets   BloomPreset
        {
            get { return _bloomPreset; }
            set
            {
                if (_bloomPreset == value) return;

                _bloomPreset = value;
                SetBloomPreset(_bloomPreset);
            }
        }
        private BloomPresets _bloomPreset;


        private Texture2D     BloomScreenTexture { set { BloomShader.ScreenTexture.SetValue(value); } }
        private Vector2       BloomInverseResolution
        {
            get { return _bloomInverseResolutionField; }
            set
            {
                if (value != _bloomInverseResolutionField)
                {
                    _bloomInverseResolutionField = value;
                    BloomShader.InverseResolution.SetValue(_bloomInverseResolutionField);
                }
            }
        }
        private Vector2      _bloomInverseResolutionField;

        private float         BloomRadius
        {
            get
            {
                return _bloomRadius;
            }

            set
            {
                if (Math.Abs(_bloomRadius - value) > 0.001f)
                {
                    _bloomRadius = value;
                    BloomShader.Radius.SetValue(_bloomRadius * _radiusMultiplier);
                }

            }
        }
        private float        _bloomRadius;

        private float         BloomStrength
        {
            get { return _bloomStrength; }
            set
            {
                if (Math.Abs(_bloomStrength - value) > 0.001f)
                {
                    _bloomStrength = value;
                    BloomShader.Strength.SetValue(_bloomStrength);
                }

            }
        }
        private float        _bloomStrength;

        public float BloomStreakLength
        {
            get { return _bloomStreakLength; }
            set
            {
                if (Math.Abs(_bloomStreakLength - value) > 0.001f)
                {
                    _bloomStreakLength = value;
                    BloomShader.StreakLength.SetValue(_bloomStreakLength);
                }
            }
        }
        private float _bloomStreakLength;

        public float BloomThreshold
        {
            get { return _bloomThreshold; }
            set {
                if (Math.Abs(_bloomThreshold - value) > 0.001f)
                {
                    _bloomThreshold = value;
                    BloomShader.Threshold.SetValue(_bloomThreshold);
                }
            }
        }
        private float _bloomThreshold;
 
        #endregion
 
        #endregion
 
        #region initialize
 
        public BloomShaderModule()
        {
            //An interesting blendstate for merging the initial image with the bloom.
            //BlendStateBloom = new BlendState();
            //BlendStateBloom.ColorBlendFunction = BlendFunction.Add;
            //BlendStateBloom.ColorSourceBlend = Blend.BlendFactor;
            //BlendStateBloom.ColorDestinationBlend = Blend.BlendFactor;
            //BlendStateBloom.BlendFactor = new Color(0.5f, 0.5f, 0.5f);
 
            //Default threshold.
            BloomThreshold = 0.8f;
            //Setup the default preset values.
            BloomPreset = BloomPresets.SuperWide;
            SetBloomPreset(BloomPreset);
 
            BloomDownsamplePasses = 5;
        }

        //Initialize graphicsDevice
        public void Initialize(int width, int height)
        {
            UpdateResolution(width, height);
        }

       

        /// <summary>
        /// A few presets with different values for the different mip levels of our bloom.
        /// </summary>
        /// <param name="preset">See BloomPresets enums. Example: BloomPresets.Wide</param>
        private void SetBloomPreset(BloomPresets preset)
        {
            switch(preset)
            {
                case BloomPresets.Wide:
                {
                        _bloomStrength1 = 0.5f;
                        _bloomStrength2 = 1;
                        _bloomStrength3 = 2;
                        _bloomStrength4 = 1;
                        _bloomStrength5 = 2;
                        _bloomRadius5 = 4.0f;
                        _bloomRadius4 = 4.0f;
                        _bloomRadius3 = 2.0f;
                        _bloomRadius2 = 2.0f;
                        _bloomRadius1 = 1.0f;
                        BloomStreakLength = 1;
                        BloomDownsamplePasses = 5;
                        break;
                }
                case BloomPresets.SuperWide:
                    {
                        _bloomStrength1 = 0.9f;
                        _bloomStrength2 = 1;
                        _bloomStrength3 = 1;
                        _bloomStrength4 = 2;
                        _bloomStrength5 = 6;
                        _bloomRadius5 = 4.0f;
                        _bloomRadius4 = 2.0f;
                        _bloomRadius3 = 2.0f;
                        _bloomRadius2 = 2.0f;
                        _bloomRadius1 = 2.0f;
                        BloomStreakLength = 1;
                        BloomDownsamplePasses = 5;
                        break;
                    }
                case BloomPresets.Focussed:
                    {
                        _bloomStrength1 = 0.8f;
                        _bloomStrength2 = 1;
                        _bloomStrength3 = 1;
                        _bloomStrength4 = 1;
                        _bloomStrength5 = 2;
                        _bloomRadius5 = 4.0f;
                        _bloomRadius4 = 2.0f;
                        _bloomRadius3 = 2.0f;
                        _bloomRadius2 = 2.0f;
                        _bloomRadius1 = 2.0f;
                        BloomStreakLength = 1;
                        BloomDownsamplePasses = 5;
                        break;
                    }
                case BloomPresets.Small:
                    {
                        _bloomStrength1 = 0.8f;
                        _bloomStrength2 = 1;
                        _bloomStrength3 = 1;
                        _bloomStrength4 = 1;
                        _bloomStrength5 = 1;
                        _bloomRadius5 = 1;
                        _bloomRadius4 = 1;
                        _bloomRadius3 = 1;
                        _bloomRadius2 = 1;
                        _bloomRadius1 = 1;
                        BloomStreakLength = 1;
                        BloomDownsamplePasses = 5;
                        break;
                    }
                case BloomPresets.Cheap:
                    {
                        _bloomStrength1 = 0.8f;
                        _bloomStrength2 = 2;
                        _bloomRadius2 = 2;
                        _bloomRadius1 = 2;
                        BloomStreakLength = 1;
                        BloomDownsamplePasses = 2;
                        break;
                    }
            }
        }

        #endregion

        /// <summary>
        /// Main draw function
        /// </summary>
        /// <param name="inputTexture">the image from which we want to extract bright parts and blur these</param>
        /// <param name="width">width of our target. If different to the input.Texture width our final texture will be smaller/larger.
        /// For example we can use half resolution. Input: 1280px wide -> width = 640px
        /// The smaller this value the better performance and the worse our final image quality</param>
        /// <param name="height">see: width</param>
        /// <returns></returns>
        public Texture2D Draw(Texture2D inputTexture, int width, int height)
        { 
            //Check if we are initialized
            
            ApplyGameSettings();

            //Change renderTarget resolution if different from what we expected. If lower than the inputTexture we gain performance.
            if (width != _width || height != _height)
            {
                UpdateResolution(width, height);

                //Adjust the blur so it looks consistent across diferrent scalings
                _radiusMultiplier = (float)width / inputTexture.Width;
                
                //Update our variables with the multiplier
                SetBloomPreset(BloomPreset);
            }

            Gl.GraphicsDevice.RasterizerState = RasterizerState.CullNone;
            Gl.GraphicsDevice.BlendState = BlendState.Opaque;

            //EXTRACT  //Note: Is setRenderTargets(binding better?)
            //We extract the bright values which are above the Threshold and save them to Mip0
            Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip0);

            BloomScreenTexture = inputTexture;
            BloomInverseResolution = new Vector2(1.0f / _width, 1.0f / _height);
            
            if (BloomUseLuminance) BloomShader.ExtractLuminance_Pass.Apply(); 
            else BloomShader.Extract_Pass.Apply();
            Gl.QuadRenderer.RenderFullQuad();
            
            //Now downsample to the next lower mip texture
            if (BloomDownsamplePasses > 0)
            {
                BloomInverseResolution *= 2;
                //DOWNSAMPLE TO MIP1
                Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip1);

                BloomScreenTexture = _bloomRenderTarget2DMip0;
                //Pass
                BloomShader.Downsample_Pass.Apply();
                Gl.QuadRenderer.RenderFullQuad();

                if (BloomDownsamplePasses > 1)
                {
                    //Our input resolution is halfed, so our inverse 1/res. must be doubled
                    BloomInverseResolution *= 2;

                    //DOWNSAMPLE TO MIP2
                    Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip2);

                    BloomScreenTexture = _bloomRenderTarget2DMip1;
                    //Pass
                    BloomShader.Downsample_Pass.Apply();
                    Gl.QuadRenderer.RenderFullQuad();

                    if (BloomDownsamplePasses > 2)
                    {
                        BloomInverseResolution *= 2;

                        //DOWNSAMPLE TO MIP3
                        Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip3);

                        BloomScreenTexture = _bloomRenderTarget2DMip2;
                        //Pass
                        BloomShader.Downsample_Pass.Apply();
                        Gl.QuadRenderer.RenderFullQuad();
                        
                        if (BloomDownsamplePasses > 3)
                        {
                            BloomInverseResolution *= 2;

                            //DOWNSAMPLE TO MIP4
                            Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip4);

                            BloomScreenTexture = _bloomRenderTarget2DMip3;
                            //Pass
                            BloomShader.Downsample_Pass.Apply();
                            Gl.QuadRenderer.RenderFullQuad();

                            if (BloomDownsamplePasses > 4)
                            {
                                BloomInverseResolution *= 2;

                                //DOWNSAMPLE TO MIP5
                                Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip5);

                                BloomScreenTexture = _bloomRenderTarget2DMip4;
                                //Pass
                                BloomShader.Downsample_Pass.Apply();
                                Gl.QuadRenderer.RenderFullQuad();

                                ChangeBlendState();

                                //UPSAMPLE TO MIP4
                                Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip4);
                                BloomScreenTexture = _bloomRenderTarget2DMip5;
                                
                                BloomStrength = _bloomStrength5;
                                BloomRadius = _bloomRadius5;
                                BloomShader.Upsample_Pass.Apply();
                                Gl.QuadRenderer.RenderFullQuad();

                                BloomInverseResolution /= 2;
                            }
                            
                            ChangeBlendState();

                            //UPSAMPLE TO MIP3
                            Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip3);
                            BloomScreenTexture = _bloomRenderTarget2DMip4;

                            BloomStrength = _bloomStrength4;
                            BloomRadius = _bloomRadius4;
                            BloomShader.Upsample_Pass.Apply();
                            Gl.QuadRenderer.RenderFullQuad();

                            BloomInverseResolution /= 2;

                        }

                        ChangeBlendState();

                        //UPSAMPLE TO MIP2
                        Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip2);
                        BloomScreenTexture = _bloomRenderTarget2DMip3;

                        BloomStrength = _bloomStrength3;
                        BloomRadius = _bloomRadius3;
                        BloomShader.Upsample_Pass.Apply();
                        Gl.QuadRenderer.RenderFullQuad();

                        BloomInverseResolution /= 2;

                    }

                    ChangeBlendState();

                    //UPSAMPLE TO MIP1
                    Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip1);
                    BloomScreenTexture = _bloomRenderTarget2DMip2;

                    BloomStrength = _bloomStrength2;
                    BloomRadius = _bloomRadius2;
                    BloomShader.Upsample_Pass.Apply();
                    Gl.QuadRenderer.RenderFullQuad();

                    BloomInverseResolution /= 2;
                }

                ChangeBlendState();

                //UPSAMPLE TO MIP0
                Gl.GraphicsDevice.SetRenderTarget(_bloomRenderTarget2DMip0);
                BloomScreenTexture = _bloomRenderTarget2DMip1;

                BloomStrength = _bloomStrength1;
                BloomRadius = _bloomRadius1;

                BloomShader.Upsample_Pass.Apply();
                Gl.QuadRenderer.RenderFullQuad();
            }

            //Note the final step could be done as a blend to the final texture.
            
            return _bloomRenderTarget2DMip0;
        }

        private void ApplyGameSettings()
        {
            _bloomRadius1 = GameSettings.g_BloomRadius1;
            _bloomRadius2 = GameSettings.g_BloomRadius2;
            _bloomRadius3 = GameSettings.g_BloomRadius3;
            _bloomRadius4 = GameSettings.g_BloomRadius4;
            _bloomRadius5 = GameSettings.g_BloomRadius5;

            _bloomStrength1 = GameSettings.g_BloomStrength1;
            _bloomStrength2 = GameSettings.g_BloomStrength2;
            _bloomStrength3 = GameSettings.g_BloomStrength3;
            _bloomStrength4 = GameSettings.g_BloomStrength4;
            _bloomStrength5 = GameSettings.g_BloomStrength5;

            BloomThreshold = GameSettings.g_BloomThreshold * 0.1f;
        }

        private void ChangeBlendState()
        {
            Gl.GraphicsDevice.BlendState = BlendState.AlphaBlend;
        }

        /// <summary>
        /// Update the InverseResolution of the used rendertargets. This should be the InverseResolution of the processed image
        /// We use SurfaceFormat.Color, but you can use higher precision buffers obviously.
        /// </summary>
        /// <param name="width">width of the image</param>
        /// <param name="height">height of the image</param>
        public void UpdateResolution(int width, int height)
        {
            _width = width;
            _height = height;

            if (_bloomRenderTarget2DMip0 != null)
            {
                Dispose();
            }

            _bloomRenderTarget2DMip0 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width),
                (int) (height), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
            _bloomRenderTarget2DMip1 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width/2),
                (int) (height/2), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
            _bloomRenderTarget2DMip2 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width/4),
                (int) (height/4), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
            _bloomRenderTarget2DMip3 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width/8),
                (int) (height/8), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
            _bloomRenderTarget2DMip4 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width/16),
                (int) (height/16), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
            _bloomRenderTarget2DMip5 = new RenderTarget2D(Gl.GraphicsDevice,
                (int) (width/32),
                (int) (height/32), false, SurfaceFormat.HalfVector4, DepthFormat.None, 0, RenderTargetUsage.PreserveContents);
        }

        /// <summary>
        //Dispose our RenderTargets. This is not covered by the Garbage Collector so we have to do it manually
        /// </summary>
        public void Dispose()
        {
            _bloomRenderTarget2DMip0?.Dispose();
            _bloomRenderTarget2DMip1?.Dispose();
            _bloomRenderTarget2DMip2?.Dispose();
            _bloomRenderTarget2DMip3?.Dispose();
            _bloomRenderTarget2DMip4?.Dispose();
            _bloomRenderTarget2DMip5?.Dispose();
            Gl.GraphicsDevice?.Dispose();
            BloomShader.bloomEffect?.Dispose();
            
        }
    }
}

You should use git to make a pullrequest to @kosmonautgames, so he would be able and for you too, to comment it with you

1 Like

I agree with Alkher - just make a pull request and I can easily integrate your code without having to copy it myself. Also easier for you :slight_smile:

the thing is, there are 2 coding styles at conflict.

And I do want to get away from using globals for things that are not globally used, for example bloom parameters. It’s nice and tidy to have a different static class for them, but I do believe static variables should be avoided if possible and I am actively looking to insource Shaders.cs into the respective rendermodules.

So, I think overall your code is a big improvement to what it looks like right now, but, for example the bloom shader is basically it’s own repository which I just copied to the deferred engine files. You can find the bloom stand-alone here: https://github.com/UncleThomy/BloomFilter-for-Monogame-and-XNA
I don’t necessarily think that shader code that is used only for this specific class should be outsourced.

hello kosmonautgames,

i agree, in future it will be better to provide code templated by using github.
I haven’t used git very much except downloading content, so i will make myself familiar how to contribute code by a pull request.

here some other questions after further investigation of the code:

  • when using the environment cubemap for reflections there a position in world space is defined an from this point there a 6 projection matricies an with each of them a draw to rendertarget is made.

=> so it is used as a reflection cubemap

the code takes into account wheter the cupbemap shall be updated every frame draw or not.

e.g. when a object a moving or suddenly appears in world space they will not be appearent in the reflection map until it is updated.

the reflection can only be “realistic” according to the lightprobe position.
e.g. the speres in the example show all the same reflection pattern not coresponing to their actual position.

the resolution of the cubemap defines how sharp or detailed the reflection can be produced.

now my question:

  • does the computation cost for creation and sampling of the envireonmet cubemap depend from its resolution ?
    i think the “creation cost” is always the same but for sampling the map i dont know ?

At the moment the cubemap serves to enlighten the scene quite much. When i put off all point lights an put on only one directional light then we get what we would expect. Only the “directional parts” are lit all others are completely dark.
putting on the environment mapping the scene becomes nicely lit.

Is this inentionally ? It has a nice effect, the scene looks good, but is far from being realistic.

my question:
should not the reflection probe sampling take the summerized lightintensity into account. so the reflections would be visible but only in the parts of the scene that are actually lit.

How complicated would it be to implement a reflective shadowmap with the same technic to realize a more realistic global illumination ?

I know that the actual scene is only a playground of course.

Many thanks for every answer

bettina form good old germany

Hey!

Not for cubemaps, at least in the default code. Light’s do update only when objects move, but I just don’t update the cubemap… ever (to expensive)

Yes it does. The creation cost is linked directly to resolution, in fact, as is the normal application, at least for me it is GPU (Pixel Shader) bound, so it scales more or less linearly with pixels.
Reading textures also depends on resolution, but it’s not that expensive in comparison.

Although the environment cube only realistically adds to the scene at the position where it is actually placed, it’s a good enough approximation for the objects around it to add to the scene.

Yes. The common solution to this problem is to have multiple environment cubes and blend between them. Or have a radius for each one (like lights), so it only affects things close to it.

Would be easier if monogame supported compute shaders, but it does not. Hard to do with the CPU alone since reading from GPU memory is incredibly slow. Global illumination is an interesting topic though, I’ll surely try something in future.

Hey,

Supposed i dont intend to release my game on other plattforms than Windows. Is it possible to access the active sharpdx directx device context directly to implement a compute shader in monogame ?

Is it possible to access the active sharpdx directx device context directly to implement a compute shader in monogame ?

yes

Hello kosmonautgames,

please forgive me for asking so much. I have studied Catalin ZZ tutorial about deferred rendering and also the source code of your deferred directional light and deferred pointlight shader.

Butt sorry i still havent got it.

Its now clear to me how to get the needed information from the GBuffer rendertargets for albedo, normal…

The lighting equations for directional an point light is also clear to me.

But what i cant understand is the conjunction with the vertex shader.

Die directional light shader gets only 2 vertecies which cover the whole screen.
And therefore all pixels of the whole screen are beeing processed, i think ??
So in principal this will by pricipal cost quite a lot of processing time.

Can this be compared virtually with 2 loops

for row_idx = 0 to screen_width
for col_idx = 0 to screen_height

So i assume only this pixels of the screen are processes which are covered be the vertecies of the vertexshader ? In this case all.

So why we pass a sphere to the pointlight shader ?
I assume tha actually we want to project a circle to the screen but because of the world, view transformation we pass a sphere the will allway be projected as circle no matter from side it is viewed.
When i understand corectly we only do this because we want only the screen pixels be processed which are in the max radius distance of the light ?

Depending from the distance of the sphere to the screen plane it will appear as a small or greater circle and the pixel shader will have more or less to do.

So the vertecies positions of the spere are only for the purpose to set the active range which will be processed from the pixel shader ???

For example: if i want to blur a certain part of the screen
Solution: I could take some vertecies in the vertexbuffer and indexbuffer an draw them like a 2d "paper scissor " and then apply a blur shader it would be applied only to that part.

So in the pixelshader i would NOT need to have a function that would allways check whether to process the pixel or not.

Sorry, soory for the questions but i would really like to understand

bettina, Germany

Yes absolutely correct, except for one thing: drawing a sphere is not a circle, unless using orthogonal projection. It would make things easier if it were but it isn’t.

I’ve added a FOV slider to the project, so you can change the field of view of the camera. This makes it easier to see how a sphere behaves when transformed to projection space:

But yes, the general theory is correct. We draw geometry to mark the pixels we want processed in the pixel shader.

Another good XNA tutorial is this one from jcoluna https://jcoluna.wordpress.com/2011/01/18/xna-4-0-light-pre-pass/
(There are a lot of effects described on his page https://jcoluna.wordpress.com/ -> check it out!)

It’s about LPP, so a different variation of deferred rendering. However, just as an example, he uses quads / billboards to mark the pixels of the light.
This is wasteful, however, since the quads cover more space than the light needs. In later posts he also goes ahead and uses spheres.

By the way, I’m German, too. If you have some specific questions you can drop me private messages, too, if you want.

Hello kosmonautgames,

i was very busy but i dont want to miss to thank you very much for your answer and the explanation picture / feature in the engine.

At the moment i am preparint my own engine step by step to include deffered and pbr rendering features.

I still have more questions about your engine…

Nice to hear that you are also german !!
Its easier for me to write in german ( in private message) but your english is very good.

When reading you blog i didn’t expect that the author is german.

By Bettina

1 Like

seem like all the source code link had down. here is previous source file that i downloaded. i did try to improve ur directional shadow with cascaded shadow maps in the source, but it look weird not sure is the xna 3D coordinate system different with monogame?

https://drive.google.com/file/d/0BwtN8HNVzAZzNGd4ektCcmU1V3M/view?usp=sharing

no, the coordinate systems are the same, but there is no such thing as a hard definition. It all gets transformed based on projection matrix etc… The default behaviour from XNA to monogame didn’t change.

By default Y is up ( 0,1,0) but I use Z as up (0,0,1) in my engine.

Vry weird still cant get it right. Maybe when u free you can help me to figure out how it work. Thanks :slight_smile:

what parts aren’t working?

Basically it goes as follows

if you place an object in the default XNA / Monogame scene at 1 height, it will have coordinates (0, 1, 0).

In my coordinate system it sits at (0, 0, 1). This is because I made some strategy games that worked in 2d but had a 3d representation, so for example objects can move only on a plane. Basically you see all the objects from above. The 2d coordinate system is XY, so the physics and everything are calculated in XY, too. Then, for the 3d part, i needed to add height, so that’s my 3rd component -> Z.

It didn’t make sense for me to have the ground plane be represented in xy for 2d and xz in 3d.

Plus, I was used to z being the height from other engines, like CryEngine, for example.

Now what does that mean?

It means that to get from xyz to xzy you just have to flip y and z and you are in the other coordinate system.
However, that is true only for my world coordinates. The shaders are exactly the same.

For the shaders it makes sense to have xy be vertical/horizontal directions, since that is all you need for 2d graphics. Z is the depth component then.

Since I use Z as my up vector, when creating the view matrix of the camera I also have to define z as “up”.

            _view = Matrix.CreateLookAt(camera.Position, camera.Lookat, camera.Up /* == 0,0,1 */);

if i used the xna way of y = up I would have to change the view matrix, too.

Thanks for the reply, i would try it out… :slight_smile:

hi kosmonaut,

at the weekend i was still working on your engine and after some copy of the souce code to another folder on my disk i noticed that the build process takes a long time. e.g. 2 minutes
After this it worked all well.

Just to learn i made a break of the build and realized in the log file that there is a background task working, i think it is the content pipeline processor, that is importing the ressources and takes time to create normals, tangents an so on.

In c++ i can see all the external commands that happen in the comiling process.

In C# there are also some coresponding fields in the solution properties window but they are here all empty.

So i cannot find the souce of this action or command to start this additional tasks
in the build process. it just happens.

Can someone give me an advice where to find the trigger of this recalculation of the importer ?

bettina from germany

what do you mean exactly? In the monogame source code or in the content pipeline?

  1. Step : We have a stable working situation.
    The user code e.g. deferred playground source was compiled and is running fine.
    …\master\defered_playgound…
    close VS 2015

2.Step: The whole Solution directory with all subdirectories is copied to a new folder
…\master2\defered_playgound…

  1. Step: Open the solution now placed in \master2…
    open VS 2015 and do recompile all

           now it takes very long time.
           the output window of the compiler/ build process shows only a few lines and then
           just says compiling....
    
           when i now break / cancel the build process then the real work which was done in  
          background is showed in the VS2015 build status window.
           Now it shows all the single filenames e.g. of the sponca scene and what  he was doing.
          e.g. calculate tangent or such things
          So i dont mean something that is going after the program was started but only during 
         build process.

There are 2 things that need to build for a long time ->

  1. GenerateTangentFrames for meshes. This is a checkbox in the content pipeline. For each vertex it generates binormal and tangent.

  2. Loops in shader code. If you use [unroll] or basic for loops it will transform the loop into code. Even for [branch] code the compiler has to check all the iterations afaik.
    (So the default behaviour is like this
    for(i = 0; i<2; i++)
    {
    x += i;
    }

unrolled code after compiling
-> x+= 0; x+=1;

Some of my shaders have for loops with another layer of for loops in between. That can take a while to compile.

" Generate MipMaps" for textures. Can take a tiny bit, too.

hi komonautgames,

i am really thankfull for you answer, but maybe i miss something obviously. ??

I still dont understand what mechanism is calling/triggering the start of the content processor during compilation ?

Should not be any config for the VS2015 with a line so to say
pseudo: If (build is started) "exec mgcp.exe " /param1 / param2