top of page
alundrigan2

Unreal Cel-shading



Following on from my experimentations into Unreal as well as GLSL shaders, I wanted to look further into Unreal materials. As per my statement of intent, I want to ‘develop technical art skills which will enhance the pipeline of my GAM202 group game’ – therefore I will be firstly looking at creating shaders within Unreal Engine. Although the style of my group project is more realism, these skills will hopefully be transferable to creating more realistic effects.


I gathered a variety of resources to inform me of different pipelines regarding Unreal shaders – books, articles and educational videos helped me gain a contextual understanding of shaders in Unreal, how they are created and what their uses are.


Initially, I tried watching a YouTube video by Visual Tech Art (real name Andrea Giampietro) on YouTube – I found this channel through an 80lvl article entitled “Becoming a Shader Artist & Making Volumetric Fog in Unreal Engine” (McKenzie, 2022). Within the article he explains his traditional art background, how he became a self-taught tech artist and how he landed his job in the industry. I was intrigued so I followed along with his video, “Cel Shading and Light Types” (Visual Tech Art, 2021).


I think I may have accidentally jumped in the deep end with this tutorial. Evidently my current level of knowledge of Unreal Engine in relation to shaders wasn’t up to scratch as I didn’t understand why he was doing the majority of things in the tutorial. He explained to some degree but not in terms that I could understand; luckily I recognised some functions such as dot product and if evaluation from A-Level computer science but other than that I was kind of lost.


I also wasn’t understanding how to make the shader useable in the world, or why the cel-shaded highlight/shade was fixed in one position. I trawled the comments to find a surplus of beginners also struggling with grasping these concepts. This reassured me that it wasn’t only me struggling, and encouraged me to turn to other, more beginner friendly resources.


Here is the cel-shade material graph, with explanations as to what each section does. Attempting to explain what each step does helped me understand it more myself, with the aide of the Unreal Engine documentation.




Directional Light

  • Calculates dot product between the light and the mesh normals

  • The output would be inverse so we have to multiply by -1 and then clamp it using thee saturate node.

Colour

  • Highlight, base and shadow values are defined and thresholds are set for them to control the gradient. Boolean logic is carried out on the dot product to determine the colour of that section, often comparing the dot product to the threshold.

Outline

  • The dot product of the camera vector and vertex normals is calculated and clamped between 0 and 1. This is then compared to the threshold of 0.2, our outline thickness - if less than 0.2, output no outline, if more than 0.2 output an outline. This is then multiplied with the colour output to create the final colour for the shader.


As mentioned prior, I had to consult the Unreal documentation (Epic, 2023) to comprehend what the nodes I was using were actually doing. Camera Vector outputs a 3 channel vector that stores the direction of the pixel to the camera. VertexNormalWS holds the normals for each vertex in relation to worldspace.


The dot product concept is something I had come across briefly in computer science A-Level - I knew it was something to do with vector calculation but I couldn't remember exactly what. Therefore I consulted Freya Holmer, a renowned technical artist YouTuber who I had been following on Twitter for a while, clueless of her channel that has tons of free lectures and tutorials relating to technical art. She has a short video explaining how the dot product works (Holmer, 2019).


The image I've drawn below parallels the one from Freya's video: Essentially you're projecting one vector onto another and taking the value of where they intersect. The dot product value here would probably be something like 0.6. Freya surmises this in a great way - "[It's] super useful to have a value for how similar 2 normalised vectors are".



This then brought about further questions for me, like what is a normalised vector? Khan Academy came to my rescue here, with their section on normalised vectors on their JavaScript course (Khan Academy, 2023). What I gathered from their article is that normalising something means "making something standard" - the process is taking any vector and changing its magnitude to 1, which makes it a unit vector. This is done by dividing each component of the vector by its magnitude. The unit vector is valuable since it represents a vector's direction without regard to the length


As a stack overflow answer on the same topic notes (HungryCoder and Jay Bosamiya, 2012), "For example, it doesn't mean anything to say that we have a line facing 4 km North. It makes more sense to say we have a line facing North. So what do you do then? You get rid of the 4 km. You destroy the magnitude. All you have remaining is the North (and Winter is Coming)." They also note that the process of normalising vectors is essentially just ignoring the magnitude, but that's too crass so the fancy way or saying it is normalisation.


This type of normalisation makes sense for calculations such as the dot product graph seen above - I'm imagining it would be a lot more complex to visualise and calculate if the vectors were all different sizes. This makes sense to introduce a standard which allows us to perform vector calculations with less complications.


Even though I now understood it, visualisation of the dot product was plaguing me. Sure, I understood how it worked at this point but I couldn't visualise how the camera vector and mesh normals were interacting in order to create the outline. I found a great tool online created by Paul Falstad which has an interactive dot product graph, although the vectors aren't normalised. Further investigation brought me back to Freya Homler's twitter, where she shared these two useful infographics:


(Holmer, 2019)


The first is a visualisation of the dot product, the second a visualisation of how the dot product relates to the cosine rule. This is something that was touched upon in Acerola's Sum of Sines video (Acerola, 2023) when calculating specular highlights for water. This helps me envisage what is going on under the hood when the outline shader is being calculated.


To link back to the actual shader itself, here is how it looks in world on the iconic Utah teapot as well as a primitive sphere.



Despite me not full understanding why this cel-shader wasn't working in realtime, I was pretty happy with the result. I gained a lot of knowledge from trying to wrap my head around this shader and that's the most important thing to me.


Comments


bottom of page