Blog

Shader part #3 - Fade in/out

posted Mar 30, 2013, 6:47 PM by Erno Pakarinen   [ updated Mar 31, 2013, 2:54 AM ]

Things devolve, I should be sleeping and such but since I can not sleep why not make few more posts?

The simplest shader there is is just to return the color of the source pixel. Something like this:

TEH shader!

float4 Color; 
Color = tex2D( input , uv.xy); 
return Color;



Yeah, it is not very usable, does not serve any real purpose. :) However,

If we want to gain a fade in/out to/from black effect, do something like this, take the color of the source image and multiply its value by the intensity you desire. Intensity can be updated in your game loop (object update for example).

             // In my framework stateTransitionValue goes from 1.0f -> 0.0f or 0.0f -> 1.0f depending on exit or entry
            postEffect.Parameters["intensity"].SetValue(stateTransitionValue);


Fade.fx

sampler2D input : register(s0); 

float intensity = 1.0f;

float4 PS_Color(float2 uv : TEXCOORD) : COLOR 
    float4 Color; 
Color = tex2D( input , uv.xy); 
return Color * intensity;
}

technique PostProcessWiggle
{
pass Pass1
{
// A post process shader only needs a pixel shader.
PixelShader = compile ps_2_0 PS_Color();
}
}


And again, here's a screenshot of the effect doing its task while the state is fading out (Exit was pressed):




-erno@codesmith.fi


Shader part #2

posted Mar 30, 2013, 4:17 PM by Erno Pakarinen   [ updated Mar 30, 2013, 4:27 PM ]

Relating to the previous post about my first take into pixel shader thingies... (not tights:P). Here is a very simple shader that will just cause the screen to wobble. It's pretty self explanatory.

It's one pass effect which only deforms the image by sin/cos detransform.

Notice, due to the intensity multiplier of 100, the effect is pretty big. :P

Text Box

sampler ColorMapSampler : register(s0);

float timer;
float intensity = 1.0f;
float colorIntensity = 1.0f;

struct PixelShaderInput
{
    float4 TexCoord: TEXCOORD0;
};

float4 PixelShaderFunction(PixelShaderInput input) : COLOR
{
// let's take pixels with circle motion around the current pixel, 
// causing the screen to wobble
input.TexCoord.x += ( sin( timer + input.TexCoord.x * 100 * intensity) * 0.01f );
input.TexCoord.y += ( cos( timer + input.TexCoord.y * 100 * intensity) * 0.01f );
float4 Color = tex2D( ColorMapSampler, input.TexCoord );
    return Color * colorIntensity;
}

technique PostProcessWiggle
{
pass Pass1
{
// A post process shader only needs a pixel shader.
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}


Below is an example image of the above shader. As you can see the effect is pretty large with those settings.

Huge Wobble effect with the shader



Blur - My first take to HLSL and shaders

posted Mar 30, 2013, 4:10 PM by Erno Pakarinen   [ updated Mar 30, 2013, 4:58 PM ]

Yeah, I tought things with shaders are too complex for my simple brain to understand. But *BAH*, it's just code which just runs in a different environment making your life much easier in the end.

So as a last post for today, here's a shader intro with XNA + HLSL.

Please see this Reference to HLSL by Microsoft for HLSL syntax and stuff.

What and why?

I wanted to have an effect which blurs a state for example in situations when the state is exiting. So this needs few things:
  • Intensity of the effect, "intensity" parameter in my shader. 1.0f means the effect is at maximum level, 0.0f means it's off
  • Color intensity "colorIntensity", meaning that I can also control the color output value, allowing me to fade in/out with the same effect
  • The actual blurring effect, this sounds complex but it actually is not
  • The code, it's pretty self explanatory

2 pass Gaussian Blur

sampler2D input : register(s0); 

#define WEIGHT_COUNT 6

float weight[WEIGHT_COUNT] = {
0.9,
    0.85,
    0.70,
    0.50,
    0.25,
0.10
};

float colorIntensity = 1.0f;
float intensity = 1.0f;
float2 pixelAspect = {1.0/1280, 1.0/768};

float4 PS_BlurHorizontal(in float2 uv : TEXCOORD) : COLOR 
    float4 Color = tex2D(input, uv);
float mult = 1;
for(int i=0; i<WEIGHT_COUNT; i++)
{
Color += tex2D(input, float2(uv.x-(intensity*pixelAspect.x*mult), uv.y)) * weight[i];
Color += tex2D(input, float2(uv.x+(intensity*pixelAspect.x*mult), uv.y)) * weight[i];
mult = mult + 4;
}
Color /= WEIGHT_COUNT;
return Color * colorIntensity; 
}

float4 PS_BlurVertical(in float2 uv : TEXCOORD) : COLOR
float4 Color = tex2D(input, uv);
  float mult = 1;
for(int i=0; i<WEIGHT_COUNT; i++)
{
Color += tex2D(input, float2(uv.x, uv.y-(intensity*pixelAspect.y*mult))) * weight[i];
Color += tex2D(input, float2(uv.x, uv.y+(intensity*pixelAspect.y*mult))) * weight[i];
mult = mult + 4;
}
Color /= WEIGHT_COUNT;
return Color * colorIntensity;
}

technique FunkyBlur
{
pass Pass1
{
// A post process shader only needs a pixel shader.
PixelShader = compile ps_2_0 PS_BlurHorizontal();
}
pass Pass2
{
// A post process shader only needs a pixel shader.
PixelShader = compile ps_2_0 PS_BlurVertical();
}
}


I am doing two pass pixel shader technique called FunkyBlur. First it does blur horizontally then vertically in the second pass. 
If you check the actual Pixel Shader functions (PS_BlurVertical, PS_BlurHorizontal) you'll see that they do several iterations per pixel, summing up color values from surrounding pixels. 

The weights table just tells how much effect each iteration in the Effect pass will have. 1.0 = full effect, 0.0 = no effect at all. We have 6 weights, meaning that each pass does pixel color summing six times with different weights. Each iteration of the effect pass will take a pixel from around the current pixel (-/+ directions), each iteration causes the reference pixel to be farther than the previous. This does the blur effect, with weights we can control how much each iteration affects to the pixel color value. 

The variable "pixelAspect" tells the aspect ratio of one pixel on the actual screen, this of course depends on the screen resolution. In the example it is set to resolution 1280/720. This ratio is used in each iteration to get the color of the surrounding pixels.

Here's an example image with the effect blurring MainMenuState while in transition between two states. Note, the second state is not affected by the effect.

GaussianBlur


-erno@codesmith.fi

XNA and Game development #1

posted Mar 30, 2013, 1:39 PM by Erno Pakarinen   [ updated Mar 30, 2013, 3:47 PM ]

Hola!

Update: Compiled binary with setup now included, check at the bottom:

So, recently I got interested in Microsoft's XNA framework. Yes, of course I know Microsoft has pulled the plug and stopped developing the framework. But still, the 4.0 version of XNA is pretty good framework to start writing your games with. It still can target to multiple platforms including Windows, Windows Phone and XBox 360. And which is even neater, there is an Open Source and compatible framework available which can target even more devices (Including Android), check out Monogame. It should be mostly compatible with XNA meaning that the same source code can be used with Monogame as with XNA. Anyways, I am still doing things with XNA 4.0 and hopefully move to Monogame later.

So what is going on?

I am writing my own game framework which makes it a lot easier to start up a new game project. What? Another framework, based on another framework? Really?

Yes REALLY. Even though XNA provides a lot for you, you still need to do many things on top of it to actually make your game live. For example, one of the biggest things a game developer faces at one point or another is: Game State Management.

Ok, not a big deal right? This is just one thing and good examples are provided, one even from Microsoft itself. Check their Game State Management. I will not lie, I of course looked at it, took example of it (because it's quite nice way to do things) and made things in my own way. See the details below for differences.

In addition to game state management, most common tasks people will struggle with are Sprites, Input actions (e.g. sprite being dragged or so) and such. My framework will try to provide generic solutions for these too.

Current progress

  • 2D framework 
  • Sprites
    • mouse events
    • Including events for Drag/Hover/Clic and such stuff.
    • rotation, position etc. basic stuff.
  • SpriteButtons
    • Extending the Sprite, providing all the features of it (including Dragging) and adding button animation and keyboard events etc.
  • Game state management
    • GameStateManager -->[1..n]--> GameState -->[1..n]--> GameCanvas
      • StateManager owns states and each state can own multiple canvases containing multiple game objects (e.g. sprites or spritebuttons)
      • This differs from Microsoft's example which did not have States, only Screens. I wanted to have a State containing everything related to that state, making it easy for state handling. Switching between states is easy, just one line of code. When I switch to a state, everything related to the state is brought up instead of activating invidividual screens at once like in Microsoft's example.
    • Post processing effects
      • Can use any Effect based class (pixel shaders) for post processing the state. 
      • Currently provided effects are Gaussian Blur and Wiggle which deforms the image with sin/cos wobble, see the image
    • Transitions between states, smooth in/out transitions with post processing

So stay tuned for updates. I am planning to make this generally available, as donationware. But let's see. Are you interested?



This image shows a State with 3 sprites and text. Sprites can be dragged with mouse, State draws background image and post processing effect (not so visible in static image heh)

This image shows a main menu. 3 MenuEntry objects, derived from SpriteButton. Middle one is being hovered with a mousepointer.

Example code for GameState

Here is an example of the main menu state which uses the canvas below. Basically it only draws the background for the state

MainMenuState.cs

using System;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Codesmith.SmithNgine.GameState;

namespace Codesmith.SmithTest
{
    public class MainMenuState : GameState
    {
        private Texture2D image;
        private GameCanvas menuCanvas;
        private Effect postEffect;
        float effectTimer = 0.0f;
        public bool exitActivated = false;
        GameState playState;

        public MainMenuState(String name, GameState playState)
            : base(name)
        {
            this.EnterStateInterval = TimeSpan.FromSeconds(1.0f);
            this.ExitStateInterval = TimeSpan.FromSeconds(1.0f);
            this.playState = playState;
        }

        public override void Initialize()
        {
            menuCanvas = new MenuCanvas(this.playState);
            menuCanvas.TransitionSource = this;
            AddCanvas(menuCanvas);            
            base.Initialize();
        }

        public override void LoadContent()
        {
            base.LoadContent();
            image = StateManager.Content.Load<Texture2D>("Images/desert");

            // Set a postprocess effect, this will blur the display with the 
            // state in/out transition value
            postEffect = StateManager.FrameworkContent.Load<Effect>("Effects/GaussianBlur");
            PostProcessingEffect = postEffect;
        }

        public override void Dismiss()
        {
            base.Dismiss();
            if (StateManager.ExitRequested)
            {
                StateManager.Game.Exit();
            }
        }

        public override void Update(GameTime gameTime)
        {
            // Update parameters in the post processing effect. 
            this.effectTimer += (float)gameTime.ElapsedGameTime.Milliseconds / 500;
            postEffect.Parameters["intensity"].SetValue(1.0f - TransitionValue);
            postEffect.Parameters["colorIntensity"].SetValue(TransitionValue);
            if (Status == GameStateStatus.Running)
            {
                PostProcessingEffect = null;
            }
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = StateManager.SpriteBatch;
            Viewport viewport = StateManager.GraphicsDevice.Viewport;

            spriteBatch.Begin();
            spriteBatch.Draw(image, 
                new Rectangle(0, 0, viewport.Width, viewport.Height), 
                Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}


Example code for GameCanvas

Here is an example of the main menu canvas class making the whole menu screen (background image is instantiated in the MainMenuState at this point):

MainMenuCanvas.cs

// ***************************************************************************
// ** SmithTest - demo app for smithNgine framework                         **
// **                                                                       **
// ** Copyright (C) 2013 by Erno Pakarinen. All Rights Reserved.            **
// ** Contact: erno@codesmith.fi                                            **
// ***************************************************************************

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Codesmith.SmithNgine.GameState;

namespace Codesmith.SmithTest
{
    class MenuCanvas : GameCanvas
    {
        Texture2D entryTexture;
        List<MenuEntry> menuEntries = new List<MenuEntry>();
        MenuEntry exitMenuEntry;
        MenuEntry playMenuEntry;
        MenuEntry optionsMenuEntry;
        GameState playState;

        public MenuCanvas(GameState playState)
        {
            this.playState = playState;
        }

        public override void LoadContent()
        {
            base.LoadContent();
            entryTexture = StateManager.Content.Load<Texture2D>("Images/button_clean");
            Vector2 pos = new Vector2(Bounds.Width / 2 - entryTexture.Bounds.Width / 2, 100);
            playMenuEntry = CreateMenuEntry(entryTexture, "Play", pos, Keys.F1);
            pos.Y += entryTexture.Height + 10;
            optionsMenuEntry = CreateMenuEntry(entryTexture, "Options", pos, Keys.F2);
            pos.Y += entryTexture.Height + 10;
            exitMenuEntry = CreateMenuEntry(entryTexture, "Exit", pos, Keys.Escape);
        }

        private MenuEntry CreateMenuEntry(Texture2D t, String label, Vector2 position, Keys key = Keys.None)
        {
            MenuEntry entry = new MenuEntry(t, label, StateManager.Font);
            entry.InputEventSource = StateManager.Input;
            entry.TransitionSource = State;
            entry.Position = position;
            if (key != Keys.None)
            {
                entry.ButtonClicked += button_ButtonClicked;
                entry.BindKey(key);
            }
            AddComponent(entry);
            menuEntries.Add(entry);
            return entry;
        }

        private void button_ButtonClicked(object sender, EventArgs e)
        {
            if (sender == exitMenuEntry)
            {
                StateManager.ExitRequested = true;
                State.ExitState();
            }

            if (sender == playMenuEntry)
            {
                StateManager.SwitchToState(playState);
            }
        }
        
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch spriteBatch = StateManager.SpriteBatch;

            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            foreach (MenuEntry m in menuEntries)
            {
                m.Draw(spriteBatch);
            }
            spriteBatch.End();
        }
    }
}


I included a compiled binary for the framework and test application. You will need to install the XNA 4.0 Refresh Redistributable first and you will also need .NET framework 4.0 atleast installed. 

Instructions

  • There is no game, just showcase of components
  • Use Left/Right to switch between the two states MainMenuState and GamingState
  • Use buttons to navigate also, Options is not implemented so will not work
  • In Gaming State press PAUSE button to pause the game.
  • Sprites can be dragged in GamingState
  • ALT-ENTER toggles fullscreen
  • Thats about it... hopefully it works.

Web pages available

posted Mar 30, 2013, 12:51 PM by Erno Pakarinen

I just published these home pages to be visible for everyone. Sorry about the logo, it's only temporary. Stay tuned for updates and more information on what is going to happen. 

1-5 of 5

Comments