Particle Multi-Directional Light Shader

Today I started working on a fake volumetric particle shader that simulates lights from six directions. I wanted to make some improvements to just using the default lit particle shading in unreal, its nice but has a very flat appearance.

The first thing I did was add contrast and gamma controls for the user in order to quite drastically alter the amount of light that appears to hit parts of the billboard. This gives us the ability to make quite different looking particle effects from the same texture sheet. This is particularly important as this technique requires two textures and therefore is more memory intensive than a single flipbook sheet.


I just used a contrast node in UE4, here’s the contrast being adjusted. Contrast tends towards extremes, lengthening the distance between the darkest blacks and brightest whites.


For gamma I just raised the texture to a power. This tends to affect midtones more. A higher gamma value boosts the darker parts of the image, while one less than 0 make the dark regions lighter. Default gamma for most displays is 2.2, but a value of 1.2 was pretty nice. I’d done some gamma correction in Houdini which might be throwing things off.



This is the interesting part! To create that volumetric look, we want to know how far from our imaginary 6 lights that each pixel of the billboard is, in order to determine its intensity.

To do that, we take the texture, and dot it with a unit vector. As the texture is not normalized, we are projecting the texture onto the light direction which returns the length of that projection.

Diving the texture by this result gives us varied intensity based on distance – when the pixel is receiving less light (based on the texture), the intensity is raised.


Here’s what the effect with adjusted gamma and contrast looks like with and without the light direction adjustment.


The current result looks something like this! Next is figuring out how to blend my textures with the particle colour!




Using Specific Browsers with the Webbrowser Module

Fixed my issue where the blog link in Nucleus would point to IE instead of chrome!

def open_webpage(self, webpage):
    webbrowser.register('chrome', None, webbrowser.GenericBrowser("C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"))
    webbrowser.get('chrome').open(webpage, new = 0, autoraise = True)

By using the register function and adding a reference to a predefined browser, a constructor (which can be None because we’ve provided an instance) and an instance. The instance is using the GenericBrowser function to open our browser executable.

This of course wouldn’t work if I was rolling out the tool to others, I’d need to use the %PROGRAMFILES(x86)% environment variable to find path.

Additions to Nucleus

Added a link to this blog to Nucleus! I used the webbrowser module, which is a nice and easy way to open a webpage.

The new flag tells us weather to use a current window if available, or open a new one, with the values 0 and 1 respectively. Autoraise tells us weather to pop up the window., new = 0, autoraise = True)

Had an interesting gotcha when trying to convert my new .ui file. I’d moved the directory of the script from C:/Users/Amy/Documents… to E:/My Docs/Projects/Pyscripts…
Having the space in the filename meant I couldn’t use pyside-uic.exe without getting the error:

Error: One input ui-file must be specified

The fix is simple – just put double quotes around the filepath! Thought it was worth noting as this is something I will forget it future!

Here’s the new tool! Made myself a nifty wee chrome-wordpress logo. (Though its opening in IE right now – the module is supposed to use your default browser, so I’ll work out what’s going on there later…)




Applying Compositing to Real Renders

I applied the logic I discussed in my last post to some real renders today! I’ll speak a bit more about my simulation and lighting setup in another post, but I’d like to mention a few additions to the expression and a couple of gotchas that I found.

The simulation that I’d created was far too small at the beginning for me to want in my sheet – I was trying to create something that was fairly generic and didn’t have too much movement inside of the flipbook as this would be done in the particle system in engine.

Because of this, I wanted to start my render partway in, and of course, I didn’t want 240 images in my sheet, so I only used every third image.


To load in the rendered images for the composite, I took my previous file loading logic, but added the start frame – 1 to it. This allowed me to offset the number that the node stepped though.

N = frame increment , S = start frame

padzero(4, (($F-1)*N+1)+(S-1))


This didn’t work for me originally, until I found a wee gotcha. As I’d rendered the image from frame 49, the file node was defaulting to a frame range between 49 and 240. To correct this, I overrode the frame range to do 1 – 64, one frame for each of my flipbook frames.


This worked brilliantly, but the final images came out very dark. I’m not sure if this was due to my light setup or something common to Houdini (I have heard others mention using gamma adjustment before rendering out) but I’d like to find out!


To correct this I upped the gamma and the levels slightly.


This is my final result! A 2k 64 frame flipbook, created from a 240 frame simulation.


Flipbook Compositing in Houdini

I’ve written about this topic before, but I wanted to revisit it with a better solution.

Previously, to create flipbooks in Houdini I had been rendering every frame of my sim, using a standalone python script to delete and renumber frames, then used a basic mosciac cop to stich the remaining frames together.

I decided I wanted to bring the solution entirely into Houdini, so had a look at adding some script-y bits to my cop setup to eliminate the tool.

I rendered only the frames I wanted by changing the increment on my mantra node. I’m going to refer to this number as N or the Nth frame. By rendering out every 3rd frame of a 48 frame long simulation, I got 16 images – perfect for a flipbook!

An important note – my first frame is frame 1, not frame 0. In order to correctly import the files in the cop, we need to start an image named 0001. I’ll explain why in the next section.


Once rendered, to get these frames into a flipbook I made a cop net with a file node attached to a mosaic node.


If I tried to load the files using the default image sequencing stuff, I’d have gotten an error, because it was looking for frames numbered 0000, 0001, 0002 etc., as the $F4 in the filepath means current frame number with four leading zeros.


My render was producing 0001, 0004, 0007 and so on. To make it look for these numbers, I had to replace the $F4 with that sequence. To get the leading zeros, I used the padzero() function, which takes a number of leading zeros and an integer.

To get the integer that would match up to my render sequence, I took the current frame, took one away from it, multiplied this by N then added one.

The cop moves through frames ($F), starting at 1 and incrementing by 1. This is very important, because the presumption that this was base 0 was breaking things for a while! The textport is your friend for finding these things…

​padzero(4, ($F-1)*N+1)

This gave us a complete file path that looked like this. The backticks are important, as they tell Houdini to evaluate that section as an expression. Otherwise, it will treat it as part of the string and produce an error as we don’t have a filepath with that name!

$HIP/render/flipbook_test.mantra_ipr.​padzero(4, ($F-1)*3+1)`.exr


I then set my mosaic up to take 16 images in a frame and 4 per line, and made myself a nice square texture sheet!



Sand Deformation Finished!

I finished my sand deformation and kick up vfx! The lighting isn’t great and I’m still unhappy with the horribly inefficient blueprints, but visually I’m happy with the shader and VFX and am ready to move on with this one. Check it out below!

Its been nice to be presenting things properly again – its been more than a year since I last posted to vimeo…


Lighting Changes



I made a couple tweaks to the shader, removing the specular from it, then edited the min. rougness and shadow resolution of the main light to produce sharper spec reflections and smoother shadows.

The lighting is still pretty rubbish, but I’d need to do a lot of research to improve it and am ready to move on from this, so calling it done!