Announcement

Collapse
No announcement yet.

[Updated for 4.20.1] Let it rain! (But not indoors!)

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

    #16
    Looking forward to your new write up on this. Will be needing a similar effect on a project in the future. =)


    SEJonF.com | Twitter | Youtube | ArtStation | WIP | UE4 Marketplace SciFi Assets - Season 1 & Season 2 Discount Bundles! Free Asset Demo | Fantasy WIP | Ice Shader

    Comment


      #17
      EDIT: I accidentally left the RT_RainDepth texture at 1024x1024. Please reduce that back down before using this. You will have to play around to get the size that suits you. I had very little artifacts with sizes as low as 64x64 but 128x128 seems to work almost flawlessly. Obviously smaller size = less precision and granularity, but faster performance.

      Well, I went ahead and spent some time to re-create this code in 4.20.1. After a bit I've managed to get it working. I'm presenting the Blueprint "as is" for now and if anyone has any questions as to how it works let me know and I'll explain to the best of my abilities. To get this to work just drop the RainOcclusion folder into your project's Content folder and you should be set. Put a BP_AttachedRain actor into your level and it should work automatically. Right now the rain covers a range of 20 meters around the player and the process of expanding it requires to change the following things:

      1. The Orthographic Width on the SceneCaptureComponent in BP_AttachedRain
      2. The TextureSize parameter in MF_RainDepthOpacity
      3. The Initial Location and Boundary of the particle system

      You can substitute the rain particle with any particle you want. The only important part of the whole setup (both particle and particle material) is the call to MF_RainDepthOpacity in the material. As long as you add that to your own rain you can put that into the BP instead of the placeholder one I've set up.

      To give a brief overview on how it works - the SceneCaptureComponent captures the scene depth into a render target. The render target is set to R32f meaning it only has a red channel and it's 32 bits long. This means that the depth stores the actual centimeter distance from the SceneCaptureComponent instead of a black-to-white mask. This makes the math in MF_RainDepthOpacity quite a bit simpler.

      The first part is to calculate the "depth" of the current particle. In order to do this we can't just do PixelPosition - ParticlePosition because that's a diagonal line that is only accurate for the particles along the central axis. This means that we have to project the location we're testing onto the particle's central axis. That's what this bit is about:

      Click image for larger version  Name:	1.PNG Views:	1 Size:	76.2 KB ID:	1514604
      It now becomes trivial to check if this depth (i.e. the vector length) is smaller than the depth. Since the depth is already stored in centimeters we don't have to do any conversions at all. The tricky part is getting which pixel of the depth texture we're testing against, i.e. calculating the UV. The math I have for this is actually finicky and seems to produce wrong results at certain angles so if anyone has any idea how to improve it I'd love to hear it.

      The gist of it is this:

      1. Take the previously projected vector and subtract it from the pixel position (i.e. moving it "up" to the origin plane of the rain).
      2. Transform it into local space, filter out only X and Y.
      3. Normalize this to be between -0.5 and 0.5 in both axis.
      4. Add 0.5 to offset it to 0-1

      It works at what seems +/- 30 degrees Pitch and Roll which should be more than enough for all rain scenarios, but again if someone has a better way to do this math bit please share!
      Attached Files
      Last edited by DamirH; 08-12-2018, 09:02 PM.

      Comment


        #18
        Good stuff. Thanks for sharing! We will be testing this in our project soon.

        Comment


          #19
          Oh wow, this is great. I just tried it out and works really well.

          I moved the components over to my character blueprint so I don't need to have a separate actor following the character around and it works fine. There is a number of rendering features that can be turned off on the scene capture as well to improve performance further. Pretty much everything except for bsp, meshes, landscape and foliage really.

          I also set up a rain particle effect in Niagara instead of Cascade, since that is the way of the future and all works fine with that too. This looks better and runs a lot faster than using CPU particles with collision, which is what I was doing before.

          The only downside of the GPU particles is you lose the trace collision that the CPU particles had, which I was using to then spawn little splash particles where the rain hits the ground. However, I've come up with an idea that might work, just not 100% sure how to do it. Perhaps you can offer some advice.

          I'm thinking of creating a splash particle effect that just spawns splash mesh particles at random (in the x,y plane) around the player up to a certain radius and let the material control the z. So in the splash mesh particle material, I could perhaps sample the same scene render target and use it to set the z position to render the splash at in world space. That way the splash will always render where the rain stops (i.e. on the ground or roof, etc...) if that makes sense. Do you think this would work? Any pointers on how I could specify the z position of a pixel for a splash mesh particle from the scene render target?

          Comment


            #20
            There's actually a way to simplify the splash even further. Make the splash a separate emitter on the rain particle that spawns identically to the rain but modify its material calculation to not just do "if below depth, set opacity to 0" but rather have it be 0 below depth as well as above "depth - SplashThickness". That way you only get it a few centimetres above the surfaces. Of course this has the disadvantage of rendering effectively invisible particles all around you at all times.

            Edit: Actually this can be optimized. Have an emitter that spawns splashes and move them down to whatever the depth is using world position offset. I will try hacking this together.
            Last edited by DamirH; 08-13-2018, 11:22 AM.

            Comment


              #21
              Thanks for the share..

              Comment


                #22
                Originally posted by DamirH View Post
                Actually this can be optimized. Have an emitter that spawns splashes and move them down to whatever the depth is using world position offset. I will try hacking this together.
                That is exactly what I’m trying to do, just explained it a bit different in my previous post.

                I was thinking that the splashes could be spawned on the x,y plane around the player at z height zero, with a very short life time. Then just sample the scene depth capture texture to adjust the world position offset up/down to match the value in the render target texture. It is this bit I’m not quite sure about. Since the splash is an actual 3D mesh, you don’t want all it’s pixels to be rendered at the same height, which will flatten it. So each pixel needs to take into account the height and is z value of the mesh, so the splash mesh retains its shape.

                Comment


                  #23
                  Well I gave it a try. Forgot that the World Position Offset, is exactly that, an offset. So my previous concern about the mesh being flattened is of no concern. Ran into another problem though with splashes stretching along edges, where part of the splash reads one height and the rest reads a different height, so the whole splash mesh get stretched vertically.

                  I found a work around by using Particle Position instead of Absolute World Position. This way only a single depth is read for the entire particle. But for this to work right, the render target resolution has to be much higher, basically 1:1 with the capture size. Obviously not the best for performance.

                  The only other way I could think to get around this would be to take multiple depth samples around the particle's position and use the lowest value. Should allow a lower resolution render target, but would result in a more expensive material, so bit of a toss up there for performance.

                  Unless you have some other ideas on how to solve this?

                  Comment


                    #24
                    Hm, that would indeed be an issue... The only thing I can think of is to make the particles smaller but that's not really a solution. It might be possible with Niagara, maybe... I'll try and think of something as well.

                    Comment


                      #25
                      Originally posted by DamirH
                      Well, trying to launch the project on the Switch with gFur enabled just crashes the whole thing outright when trying to serialize some material.

                      Edit: Meant to edit the previous post, meh. If a mod sees this merge the posts pretty please.
                      I think you posted this in the wrong thread.

                      Comment


                        #26
                        Indeed I did!

                        Comment


                          #27
                          Hi DamirH and Team

                          Firstly I would like to thank you for this excellent rain solution, it is exactly what I was after.

                          My problem is that I cannot figure out how to make the splashes work even with the advice given in the last few posts.
                          I have tried to copy in the particle splash from SoulCave and SoulCity but it doesn't work as expected (due to my inexperience I figured that would be the case).

                          I don't suppose a kind soul could give some "noob" advice on how to get the splashes to work.

                          Thanks in advance.

                          Comment

                          Working...
                          X