Wednesday 11 July 2012

Volumetric Clouds in XNA 4.0

As mentioned in the last post and the comments before that, I got asked to port my old XNA 3.x volumetric clouds over to XNA 4.0, and that’s just what I have done, but with a few changes.
The first is I am using instancing, if you don’t know what instancing is, it’s a way we can pass one set of geometry to the graphic card, but have it render lots and lots of instances of that geometry. So, in the case of our clouds, we render wisps' that are render on a quad or billboard, this billboard is just verts, so as far as the vertex buffer goes, it just holds these 4 verts, on another channel we send the graphics card a list of transforms, these transforms (or world matrix’s) represent and instance to be rendered, so, if we send ten transforms, then 10 billboards will be rendered.
You can find my archived post on the original code base here.
So, that’s quite a change from the old implementation, in the earlier version I had Point Sprites (never a good idea) and billboards, and I would chain them up into a single draw call, so the vertex buffer would be the number of wisps multiplied by four, one for each vert in the quad. It gave a good result, and looked like this
You can see in the clip, it’s a bit laggy, but to be fair it was running on a very old and crappy laptop.
I also changed the shader a little, as I had to anyway to get the instancing to work, but also to get a better fade as the camera got close to the cloud, before as you approached the cloud, it would fade out, but as I was doing this in the vertex shader, if it was a big billboard you would see the billboard rotate and  then start to fade. I am still doing this check in the vertex shader, but I am also now doing it in the pixel shader, it now fades the cloud out much better and reduces the visibility of the twisting billboard artifact on large billboards.
This is what it now looks like
So, here is the code for the clouds in XNA 4.0
Next post ill expand on instancing a bit more and show how I used it to render 1 million particles :)
REMEMBER: DO NOT COMERCIALY USE THE CLOUD TEXTURE IN THE ZIP AS IT IS PROPERTY OF MS!
Just so you know and don’t get your self stung, I have put this comment in the code where ever it is referenced.
            //////////////////////////////////////////////////////////////////
            // REMEMBER THE CloudSpriteSheetOrg texture is property of MS   //
            // Do not comercialy use this texture!                          //
            //////////////////////////////////////////////////////////////////

20 comments:

  1. Pretty :)

    But your xna4 link isn't very happy ....

    ReplyDelete
  2. Charles,

    That's awesome! I look forward to your expansion (as I'm still trying to get my head around instancing.)

    Thank you.

    ReplyDelete
  3. Hey Charles,

    I got a funny thing whit this code... Cloud field and Cloud Spot killed my machine, while Cloud Sky and Splatter runs really fast !

    I have the old implementation ( 3.1 ) and it runs like a charm in any SkyType...

    Taking a look at the code now... to see what is happening, probably me doing some noob stuff, any ideas ?

    Zeniac

    ReplyDelete
  4. The implementation is the same for all types, just the number and placement is different, could be a resource issue. Try lowering the particle count for those types and see how it goes.

    ReplyDelete
    Replies
    1. I posted a question on your other post regarding fps, please ignore that as you have already given the answer above.

      I am using SkyType.CloudySky and I only have 5 instead of 50 wisps. I now get a solid 60fps on my old test laptop.

      It's great piece of code, Thanks! I am definitely using it in my game. Specifically the players will be spawned in a parachute. Your code is ideal :)

      Delete
    2. :D cool when you are using it, would be great to see some screen shots :)

      Delete
  5. Great work.

    Have you done any work on lighting the clouds at different times of the day?

    I am looking to use clouds in my game for; ground fog, horizon clouds and upper atmosphere clouds.

    I could just colour them, but I was wondering if you had any thoughts on dynamically lighting them?

    Thanks, Garold.

    ReplyDelete
    Replies
    1. If you look at the shader there should be a param for "time of day" It's set at 12 (mid day) by default. I may have removed it, but the old version had it, if I have it's easy to implement.

      Delete
    2. Thanks, that worked great. I can darken the clouds by simply changing timeOfDay from 12 to 1. It looks good.

      Next, I'm going to play around with colours to achieve a sunset effect :)

      Delete
  6. Is it possible to reupload the source code?

    ReplyDelete
    Replies
    1. The link seems fine to me, are you having issues?

      Delete
  7. I know you wrote this over 3 years ago, but I'm hoping you can still help me. I'm working on a little game and am implementing clouds right now. I'm looking at yours as an example, but there's one thing I don't understand.

    You disable writing to the depth buffer when drawing the clouds. How do you manage to draw other objects semi-occluded by the clouds? As I'm implementing it, either the clouds are all in front of my terrain, or they're all behind it.

    ReplyDelete
    Replies
    1. I am guessing you are Peethor too, if not then see my comment below :)

      Delete
  8. I know this is a very old post, but I hope you can still help me with a little problem.

    I'm writing a game and am implementing clouds right now. I'm using your work (amazing work at that) as an example, but can't get my head around one thing:

    You disable the depth buffer when drawing the clouds. So if I draw clouds using your method, I could choose if I draw them all in front of my terrain, or behind it. Somehow, you managed to get your spaceship and platform semi-occluded by the clouds. How did you manage to do that?

    ReplyDelete
    Replies
    1. Yes, this is a very old bit of code lol

      So My understanding is, the write to depth is disabled for the clouds so that when they are renderered against each other I don't have to worry about depth sorting them and so having crappy alpha artifacts. The depth buffer write is then switched back on for the other objects in my scene.

      I don't recall all the ins and outs of my code, but I would think that my clouds are rendered after the scene, so the resulting alpha blend is then applied to the objects in the scene, but as the objects HAVE written to the depth buffer, the clouds pixels are culled where the scene objects are in front of them.

      Delete
    2. Thanks for the reply.

      This makes sense. I've checked the old xna 3.1 code, and that disables writing to the depth buffer. However, in your XNA 4 code (they changed some things around with the depth buffer) you couldn't disable writing like you did before and have to set a DepthStencilState. For future reference: You changed it to DepthStencilState.None. This also disables reading from the depth buffer. I set it to DepthStencilState.DepthRead and it now works like a charm. Thanks for the help!

      Delete
    3. Oh OK cool, as I say, it's been a long time since I looked at this code lol.

      Glad you sorted it though, feel free to post some screen shots, be cool to see how you are using it. Also are you doing this in MonoGame?

      Delete
    4. I got the cloud system working the way I want it, but am still going to rewrite it a bit so it fits my code better. Right now I use simplex noise to determine where clouds should be. Then I create clouds as the player gets closer, and remove them as he moves further away.

      Screenshots:
      Clouds
      Seeing Through Clouds

      For more screenshots visit Beaufort.tk

      At the moment I'm still using XNA, but since that's been dead for quite a while and Monogame no longer depends on it, I do want to make the switch . I kind of want to do that this year, but I still have so many ideas I want to implement in the game first.

      Delete
    5. That looks awesome, look up my god rays too for your sun, they work great with the clouds too :D

      I mostly use Unity3D now, very different structure, but I find I can do all I could in XNA and more with it.

      Good luck with your project, it looks interesting :)

      Delete