jcsnider Posted October 4, 2015 Share Posted October 4, 2015 This has been requested wayyyy to many times so I am finally caving in. Here is a really simple tutorial for making basic spotlights in C# and VB.Net with SFML. If you are using another rendering library this may still help. C# Guide Step 1 Start with a blank WinForms project, add references to the SFML .dlls and place the csfml dlls into the output folder of the application. Here is my starting code for reference. Program.cs using SFML.Graphics; using SFML.Window; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace LightingTutSharp {   static class Program   {     /// <summary>     /// The main entry point for the application.     /// </summary>     [sTAThread]     static void Main()     {       MySFMLProgram app = new MySFMLProgram();       app.StartSFMLProgram();     }   }   class MySFMLProgram   {     RenderWindow _window;     public void StartSFMLProgram()     {       _window = new RenderWindow(new VideoMode(640, 480), "2D Spotlight Tutorial",Styles.Default);       _window.SetVisible(true);       _window.Closed += new EventHandler(OnClosed);       while (_window.IsOpen)       {         _window.DispatchEvents();         _window.Clear(Color.White);         _window.Display();       }     }     void OnClosed(object sender, EventArgs e)     {       _window.Close();     }   } } Step 2 Lets go ahead and add some graphics. I am going to be using these two... Save both of these images to your projects build folder! Right Click and Save As > "Character.png" and Right Click and Save As > "Map.png" Step 3 Now, lets add the code to load these graphics. Before:       _window = new RenderWindow(new VideoMode(640, 480), "2D Spotlight Tutorial",Styles.Default); Add:       //Load our map and character textures. Attach then to drawable sprite objects.       Texture charTex = new Texture("Character.png");       Texture mapTex = new Texture("Map.png");       Sprite charSprite = new Sprite(charTex);       charSprite.Position = new SFML.System.Vector2f(290, 150);       Sprite mapSprite = new Sprite(mapTex); Step 4 The next step is to render our graphics to the screen. Before: _window.Display(); Add:         _window.Draw(mapSprite);         _window.Draw(charSprite); If you run your program you should see a window like this. So, how do we darken the window? Well, lets take a step back and thing about how we would do it outside of code. Making the map dark is easy. We can take a layer of black, make it semi transparent, and then throw it on top of the image like so. This is how you could do it using GIMP. Step 5 Lets do it via code! Lights often change, so we have to generate the dark texture and the lights at runtime. We can do this with a RenderTexture. After:       Sprite mapSprite = new Sprite(mapTex); Add:       //Create a RenderTexture for our Dark/Night overlay       RenderTexture darkTex = new RenderTexture(640,480);       Sprite darkSprite = new Sprite(darkTex.Texture);       darkTex.Clear(new Color(0,0,0,200));       darkTex.Display(); and After:         _window.Draw(charSprite); Add:         _window.Draw(darkSprite); Compile again, your window should look like this now: So, how do we add light!? We cannot render our dark texture and then render something light on top of it, or else we would get a terrible effect that looks like this. So, we have to cut-out piece of the dark texture before it is drawn to the game screen. This is done by multiplicative blending. Give me a moment to try to explain myself. Let's put this into numbers. I am telling you: Transparency  == 0 and White == 1 Bear with me for a moment while I explain. Remember the rules you were taught in elementary school? Any Number * 1 = Itself. Any Number * 0 = 0 We are going to use those same rules with our graphics. With that same logic, I am telling you that Transparency  * Black == Transparency White  * Black == Black Do you see the trick now? If not it's fine but we are going to put this concept to work. Lets say we had this image loaded as a texture.... and then we multiplied that somewhere over our darkness texture What would happen? The center of our light graphic is transparent, so multiplying would remove all color from our dark texture, while the white on the edges would multiply leaving black with a smooth transition in the middle. Something like the graphic below: Want to see it in action? Let's try it! Step 6 We need to add our new light texture! Right Click and Save this Image as > "Light.png" Add it to your projects build folder. Then in your code. After:       darkTex.Clear(new Color(0,0,0,200)); Add: //Create the light texture to multiply over the dark texture.       Texture lightTex = new Texture("Light.png");       Sprite lightSprite = new Sprite(lightTex);       lightSprite.Position = new SFML.System.Vector2f(156, 24);       //We are putting the light onto the drawTex by multiplying. Not drawing to the game window.       darkTex.Draw(lightSprite, new RenderStates(BlendMode.Multiply)); Now if you run the application you will see a nice spotlight effect! Final Product: Here is the full code too! using SFML.Graphics; using SFML.Window; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; namespace LightingTutSharp {   static class Program   {     /// <summary>     /// The main entry point for the application.     /// </summary>     [sTAThread]     static void Main()     {       MySFMLProgram app = new MySFMLProgram();       app.StartSFMLProgram();     }   }   class MySFMLProgram   {     RenderWindow _window;     public void StartSFMLProgram()     {       //Load our map and character textures. Attach then to drawable sprite objects.       Texture charTex = new Texture("Character.png");       Texture mapTex = new Texture("Map.png");       Sprite charSprite = new Sprite(charTex);       charSprite.Position = new SFML.System.Vector2f(290, 150);       Sprite mapSprite = new Sprite(mapTex);       //Create a RenderTexture for our Dark/Night overlay       RenderTexture darkTex = new RenderTexture(640,480);       Sprite darkSprite = new Sprite(darkTex.Texture);       darkTex.Clear(new Color(0,0,0,200));       darkTex.Display();       //Create the light texture to multiply over the dark texture.       Texture lightTex = new Texture("Light.png");       Sprite lightSprite = new Sprite(lightTex);       lightSprite.Position = new SFML.System.Vector2f(156, 24);       //We are putting the light onto the drawTex by multiplying. Not drawing to the game window.       darkTex.Draw(lightSprite, new RenderStates(BlendMode.Multiply));       darkTex.Display();             _window = new RenderWindow(new VideoMode(640, 480), "2D Spotlight Tutorial",Styles.Default);       _window.SetVisible(true);       _window.Closed += new EventHandler(OnClosed);       while (_window.IsOpen)       {         _window.DispatchEvents();         _window.Clear(Color.White);         _window.Draw(mapSprite);         _window.Draw(charSprite);         _window.Draw(darkSprite);         _window.Display();       }     }     void OnClosed(object sender, EventArgs e)     {       _window.Close();     }   } } Link to comment Share on other sites More sharing options...
Ricardo Posted March 5, 2016 Share Posted March 5, 2016 Sorry revive the topic, the system is very interesting, and I would like to know how to add this effect: "BlendMode.MULTIPLY" in DirectX9. Thank you. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now