Categories
FMP

FMP | Animation Development

1. Animation Design

In Rushing Place, animation plays an important role in expressing urban anxiety, social pressure and a sense of losing control. As the characters are designed as expressionless plastic mannequins, I focused on body language and movement rhythm to communicate their emotions and gradually reveal the protagonist’s loss of control over their own life.

The animation combines two different approaches: natural everyday movements and exaggerated physical performances with symbolic meanings. In the kitchen, underground and office scenes, I designed actions such as raising a cup, checking a watch, working and reacting to criticism from a supervisor. These everyday behaviours establish the protagonist’s daily routine while conveying time pressure and workplace anxiety through body posture and movement. As the film progresses, the movements gradually become more surreal. The protagonist is suddenly dragged out of bed and suspended in mid-air, before being pulled, rotated and forced into a series of uncontrolled movements, reflecting their inability to control their own fate.

For the dance sequence, I studied performance videos of aerial acrobats and dancers, focusing on body movements involving suspension, stretching, rotation and imbalance. I combined these references with the idea of the character being pulled by an external force, creating a performance that exists somewhere between dance and struggle. While traditional dance often celebrates freedom and bodily control, I wanted this sequence to express the opposite: a character being dragged by fate, struggling to resist but unable to break free.

2. Animation Production

For the technical production, I combined keyframe animation, motion capture and cloth simulation to meet the different requirements of each scene.

I primarily used manual keyframe animation for movements that required precise emotional expression and performance control. This approach allowed me to carefully adjust body poses, movement intensity and timing, particularly in scenes involving checking a watch, reacting to the supervisor, being dragged into the air and performing the dance sequence. Since the characters have limited facial expressions, subtle changes in posture and timing became especially important for communicating emotions. I therefore spent considerable time refining these performances.

For repetitive movements such as walking and running, I used motion capture data to improve production efficiency while maintaining relatively natural human movement. I then adjusted the animation speed and timing to match the film’s increasingly fast-paced rhythm. The continuous walking and running of crowds in the underground station and city environments also reinforced the repetitive and mechanical nature of urban life.

In addition, I used cloth simulation to create flying sheets of paper and ribbons wrapping around the protagonist. In the office scene, the chaotic movement of paper disrupts the structured working environment, representing the growing pressure and disorder experienced by the character. The ribbons interact with the protagonist’s suspended movements and dance performance, using wrapping, stretching and flowing motions to represent invisible restraints. These elements not only add dynamic visual detail but also transform abstract psychological experiences into a more tangible visual language.

3. Reflection

This animation process helped me understand that expressive animation is not simply about creating realistic movements, but about using motion to communicate emotions effectively. By combining repetitive everyday actions with exaggerated and unbalanced physical performances, I aimed to develop an animation language that gradually shifts from realism towards abstraction.

Combining different animation techniques also allowed me to balance production efficiency with artistic control. Motion capture reduced the time required for basic character movements, manual keyframe animation gave me greater control over emotionally significant performances, and cloth simulation introduced more symbolic movement into the film.

The transition from voluntary to involuntary movement, and from everyday actions to physical struggles, became the central idea behind the animation design of Rushing Place. Through this progression, I wanted audiences not only to observe the protagonist’s increasingly fast-paced life but also to experience the anxiety, restrictions and desire for freedom beneath these movements.

Categories
FMP

FMP | Environment Development & Stylised Rendering Tests

1. Environment Design

In Rushing Place, I developed six main environments: a kitchen, an underground station, an underground train carriage, a forest, a city and an office.

These environments not only establish the narrative spaces but also represent different aspects of everyday life.

The kitchen represents the beginning of a daily routine. The underground station and train carriage reflect the repetitive and crowded experience of urban commuting, while the city and office emphasise the fast pace of modern life and the pressures of work.

In contrast, the forest provides a natural environment that visually contrasts with the structured and repetitive architecture of the city, reflecting the film’s exploration of freedom and boundaries.

Through transitions between these environments, I aimed to create an increasingly tense, oppressive and fast-paced visual experience.

2. Environment Development

Considering the time constraints of the project, I decided not to spend excessive time modelling environments from scratch. Instead, I primarily used pre-existing 3D assets to construct the scenes.

This approach allowed me to focus more on composition, visual style and the final rendering results.

During development, I selected, combined and adjusted assets according to the requirements of each shot, ensuring that models from different sources could work together within a consistent visual environment.

For me, environment development was not about creating complex models, but about using available resources effectively to achieve the intended artistic direction.

3. Lighting & Stylised Rendering

Lighting was one of the most time-consuming aspects of the environment development process.

As Rushing Place uses a high-contrast black-and-white rendering style, the final visual result relies heavily on the interaction between lighting and materials.

Unlike traditional realistic rendering, my stylised materials use lighting information to transform surfaces into different black-and-white regions and dithering patterns.

Therefore, lighting not only determines how objects are illuminated but also directly influences the balance of black and white, the density of dithering patterns and the clarity of object silhouettes.

During testing, I found that even with identical materials, changes in light direction, intensity and position could produce significantly different visual results.

Excessive lighting could cause surface details to disappear, while overly dark areas could make the silhouettes of different objects merge together.

As a result, I spent considerable time adjusting the lighting in each environment to maintain strong black-and-white contrast while preserving spatial depth and visual readability.

Categories
FMP

FMP | Character Design Development

1. Design Evolution

At the beginning of the project, I considered using a young girl as the main character to explore anxiety and the pursuit of freedom through her personal experiences.

However, as the project developed, I realised that the girl’s distinct age and identity might lead audiences to interpret the film as a personal coming-of-age story, rather than an exploration of the broader social anxiety I wanted to address.

Therefore, I decided to move away from this design and use a plastic mannequin as the main visual reference.

2. Design Concept

Plastic mannequins have standardised body proportions, smooth surfaces and expressionless faces.

Their lack of individual identity makes them more suitable for representing emotional numbness in urban life, as well as the gradual loss of individuality under social expectations and collective routines.

3. Visual Design

I retained the main characteristics of plastic mannequins, including simplified body structures, smooth surfaces and minimal facial features.

As the film uses stylised black-and-white rendering, I reduced unnecessary surface details and focused on clear silhouettes and body proportions.

I also used clothing and posture to distinguish different characters while maintaining a consistent visual style.

4. Character Movement

Since the characters have limited facial expressions, body movement becomes the primary way of communicating emotion.

I used repetitive walking, running and mechanical movements to represent anxiety and emotional numbness in urban life.

As the film’s pace accelerates, the characters’ movements become increasingly hurried, contrasting with their expressionless faces.

The characters appear emotionless, yet they are constantly moving and unable to stop.

Categories
FMP

FMP|Stylised Rendering Test Demo

Categories
FMP

FMP | Visual Style Test 04: Return of the Obra Dinn 3-Post Process Material Development

1. Technical Challenges

After completing the five-level Toon Shader, I began developing the Post Process Material to convert the scene’s grayscale information into black-and-white dithering patterns.

The goal of this stage was to recreate a visual effect similar to Return of the Obra Dinn, where different brightness levels are represented through the density of black-and-white pixels rather than conventional grayscale values.

Compared with my previous Halftone experiments, this approach was more complex because different tonal regions required different pixel distribution rules while maintaining clear lighting and shadow structures.

I divided the image into five tonal regions:

Tonal Region Visual Representation

Black– Black background with sparse white dots

Dark Grey– Solid black

Mid Grey –Mixed black-and-white dithering

Light Grey –White background with sparse black dots

White –Solid white

To achieve this, I needed to address three main challenges.

First, I needed to accurately extract the scene’s brightness information and divide the continuous grayscale values into stable tonal regions.

Second, I wanted to generate procedural dot patterns and random pixel distributions using mathematical nodes rather than external textures.Finally, I needed to control the pixel density independently for each tonal region instead of applying the same noise pattern across the entire image.

2. Technical Development

I created a Post Process Material in UE5 and used Emissive Color to output the final black-and-white image.

The development process was divided into four main stages.

Step 1: Grayscale Conversion

First, I used SceneTexture: PostProcessInput0 to retrieve the rendered scene colour.

To convert the RGB values into grayscale, I used a Dot Product node to combine the scene colour with a fixed luminance weight vector.

Node connection:

SceneTexture → Dot Product → Grayscale Value

The second input of the Dot Product was:

(0.299, 0.587, 0.114)

These values represent the luminance weights of the red, green, and blue channels.

The grayscale calculation can be expressed as:

[

Gray = 0.299R + 0.587G + 0.114B

]

This converts the original colour information into a single brightness value.

At this stage, the material only extracts brightness information without changing the black-and-white pixel distribution.

Step 2: Tonal Separation

After obtaining the grayscale value, I used several Scalar Parameters to define the boundaries between different tonal regions.

The main parameters included:

* M2: Controls the darker tonal regions.

* M3: Controls the middle tonal regions.

* M4: Controls the brighter tonal regions.

These parameters determine which dithering pattern is applied to each brightness range.

I used If, Power, Subtract, Divide, and Saturate nodes to process the grayscale information.

1. Controlling the Grayscale Range

First, I used Divide and Saturate to normalise the brightness values.

Node connection:

Gray → Divide → Saturate

This maps the brightness values into a controlled range between 0 and 1, making it easier to adjust the dithering density.

2. Creating Tonal Masks

Next, I used multiple If nodes to compare the grayscale values against different thresholds.

For example:

Gray + M2 → If → Mask_M2

Gray + M3 → If → Mask_M3

Gray + M4 → If → Mask_M4

These masks determine which tonal region each pixel belongs to and which dithering pattern should be applied.

3. Adjusting Brightness Distribution

I also used Power nodes to adjust the brightness response curves.

By changing the exponent, I could make the transitions in pixel density more concentrated or gradual.

This allowed me to control the distribution of different tonal regions without directly modifying the lighting in the scene.

Step 3: Procedural Dithering

The next stage was generating black-and-white dot patterns using mathematical nodes.

Unlike applying a noise texture directly, I wanted the patterns to be generated procedurally so that I could control their size, spacing, and randomness.

This process involved three main components: a screen-space grid, circular dots, and pseudo-random values.

1. Creating a Screen-Space Grid

First, I used ScreenPosition to obtain the screen UV coordinates and multiplied them by a GridDensity parameter.

Node connection:

ScreenPosition → Multiply (GridDensity)

GridDensity controls the number of grid cells across the screen.

I then connected the result to both Frac and Floor nodes.

* Frac: Extracts the local coordinates within each grid cell.

* Floor: Generates integer coordinates identifying individual grid cells.

This creates a regular two-dimensional grid across the screen.

2. Creating Circular Dots

To generate circular dots within each grid cell, I used Frac, Subtract, and Length nodes.

Node connection:

Frac → Subtract (0.5, 0.5) → Length

The Frac node produces local coordinates between 0 and 1.

Subtracting (0.5, 0.5) shifts the centre of each grid cell to the origin.

The Length node then calculates the distance between the current pixel and the centre of the cell.

I used the DotSize parameter to control the radius of each dot and an If node to determine whether a pixel falls inside the circular area.

Node connection:

Distance + DotSize → If → Dot Mask

If the distance is smaller than the specified radius, the pixel is included in the dot. Otherwise, it belongs to the background.

This produces a regular pattern of circular dots across the screen.

3. Generating Pseudo-Random Values

To prevent every grid cell from producing an identical pattern, I created a pseudo-random number generator.

First, I used Floor to obtain the integer coordinates of each grid cell.

I then used Dot Product to combine these coordinates with a fixed vector:

Cell ID → Dot Product (12.9898, 78.233)

Next, I passed the result through Sine and multiplied it by a large constant:

Dot → Sine → Multiply (43758.546875) → Frac

This generates a pseudo-random value between 0 and 1 for each grid cell.

Because the random values are calculated from the grid coordinates, the pattern remains stable when the screen coordinates remain unchanged.

I used these values to control whether individual dots appeared, creating a more irregular black-and-white pixel distribution.

Step 4: Pixel Density Control

After generating the dot patterns, the next step was to assign different pixel densities to different tonal regions.

I developed three main dithering patterns.

Pattern T1: White Dots on Black

This pattern was designed for darker regions.

I used the grayscale value to control the probability of white dots appearing, while BlackDotMaxDensity controlled the maximum density of the pattern.

The main nodes included:

Gray → Power → OneMinus → Multiply → If

The Power node adjusts the brightness response curve, OneMinus reverses the value, and Multiply controls the resulting density.

The calculated density is then compared with the procedural random value to determine which grid cells display white dots.

This allows darker regions to remain predominantly black while containing a small number of white pixels.

Pattern T2: Mixed Dithering

The middle tonal region required a more balanced distribution of black and white.

I used an If node to compare the random values against a brightness-dependent threshold, then combined the result with the circular Dot Mask generated earlier.

The two results were combined using Multiply.

Node connection:

Dot Mask × Random Distribution → Pattern T2

This creates a mixture of black-and-white dots in the middle tonal region.

Pattern T3: Black Dots on White

For brighter regions, I wanted the background to remain predominantly white, with a small number of black dots.

I used a similar procedural pattern and applied OneMinus to invert the black-and-white values.

Node connection:

Dot Pattern → Multiply → OneMinus → Pattern T3

This reverses the original pattern, producing black dots on a white background.

I also used WhiteDotMaxDensity to control the maximum density of dots in the brighter regions.

Step 5: Combining Tonal Regions

Finally, I used multiple Lerp nodes to combine the different dithering patterns with solid black and white regions.

The main outputs included:

* Solid Black

* Pattern T1

* Pattern T2

* Pattern T3

* Solid White

The transitions between these outputs were controlled by the tonal masks generated earlier, including Mask_M2, Mask_M3, and Mask_M4.

The overall workflow was:

Grayscale → Tonal Masks → Dithering Patterns → Lerp → Emissive Color

As a result, the grayscale values were no longer displayed directly. Instead, they were represented through different densities of black-and-white pixels.

3. Result & Reflection

Through this experiment, I was able to convert the tonal structure generated by the five-level Toon Shader into a black-and-white dithering effect.

Compared with my previous Halftone experiments, this material allowed different tonal regions to use independent pixel distribution rules, producing a visual style closer to Return of the Obra Dinn.

However, I encountered several challenges during development.

The first challenge was balancing the grayscale thresholds and dithering density.

Because each tonal region had its own control parameters, adjusting one threshold could affect the distribution of neighbouring regions. In particular, excessive dot density between the middle and lighter tonal regions made the image appear visually cluttered, while insufficient density caused some details to disappear.

To address this, I repeatedly adjusted parameters such as M2, M3, M4, BlackDotMaxDensity, and WhiteDotMaxDensity to find a suitable balance.

The second challenge was balancing dot size and image detail.

When GridDensity was low, the dots appeared larger, strengthening the retro pixel aesthetic but reducing surface detail.

When GridDensity was high, the dots became smaller and more closely packed, preserving more structural information. However, when viewed from a distance, the dense patterns could visually blend together and appear almost grey.

Therefore, I needed to adjust both GridDensity and DotSize to balance the visual style with image readability.

Overall, this experiment helped me better understand how procedural materials can control the tonal structure of an image rather than simply changing its surface colours.

By combining five-level toon shading, custom lighting calculations, and procedural dithering, I developed a stylised rendering system in which lighting, tonal thresholds, and pixel density could be adjusted independently.

This experiment also provided further possibilities for exploring the visual direction of Rushing Place.

Categories
FMP

FMP | Visual Style Test 04: Return of the Obra Dinn 2–Surface Material Development

1. Technical Challenges

After completing the visual analysis of Return of the Obra Dinn, I began developing the surface material in Unreal Engine 5.

Unlike a conventional Toon Shader, this experiment presented two main challenges: creating a more complex tonal structure and allowing the material to respond to lighting within the scene.

Challenge 01: Five-Level Toon Shading

Traditional Toon Shaders typically use two or three distinct tonal levels, separating illuminated and shadowed surfaces with hard boundaries.

For this experiment, however, I wanted to divide the surface shading into five tonal regions:

Black → Dark Grey → Mid Grey → Light Grey → White

Rather than using the same transition between every region, I wanted to combine smooth gradients with sharp boundaries.

Tonal Transition Expected Effect

Black → Dark Grey Smooth gradient

Dark Grey → Mid Grey Sharp boundary

Mid Grey → Light Grey Smooth gradient

Light Grey → White Sharp boundary

This design was intended to support the subsequent Post Process Material.

Since the final black-and-white dithering effect would use different pixel distributions for different tonal regions, the surface material needed to provide a controllable brightness structure.

If all transitions used hard boundaries, the image would appear too flat. However, using only smooth gradients would weaken the visual impact of large black-and-white shapes.

Therefore, I needed to combine both transition methods within a single material.

Challenge 02: Dynamic Lighting

The second challenge was making the Toon Shader respond to changes in light positions within the scene.

In UE5, when using an Unlit Material for custom toon shading, the material does not automatically respond to conventional scene lighting.

This means that moving a Point Light would not automatically change the shading on the object’s surface.

For Rushing Place, the environment contains multiple light sources and complex spatial structures. Without lighting interaction, the relationship between characters and their surroundings would lack visual consistency.

Therefore, I needed to develop a custom lighting calculation system that could read light positions from the scene and calculate brightness based on the orientation of each surface.

2. Technical Development

To create a five-level Toon Shader that could respond to scene lighting, I divided the development into two stages: first, building the five-level shading system, and then implementing custom lighting through Blueprint and a Material Parameter Collection.

Step 1: Five-Level Toon Shading

First, I created an Unlit Material in UE5 and used Emissive Color to output the final colour.

Unlike traditional Toon Shaders, I wanted different transitions between the five tonal regions. To achieve this, I combined Lerp, Step, Divide, and Saturate nodes to create both smooth gradients and sharp boundaries.

To make the different regions easier to identify during testing, I initially used five colours: blue, red, yellow, green, and white. These would later be converted into grayscale.

1. Setting Up Five Colour Regions

I created five Vector Parameters representing different tonal levels, along with five Scalar Parameters to control the brightness thresholds.

Parameter Value

M1 0.2

M2 0.4

M3 0.6

M4 0.8

M5 0.9

These parameters control the distribution and transition points of the different colour regions.

2. Creating Smooth Gradients

For regions requiring smooth transitions, I used Divide and Saturate to generate blending values between 0 and 1, then used Lerp to blend between two colours.

The first gradient was created using the following node connection:

LightValue → Divide (M1) → Saturate → Lerp (Colour 1 / Colour 2)

As the brightness increases, the material gradually transitions from the first colour to the second.

For another gradient, I used Subtract to define a specific brightness interval:

LightValue → Subtract (M4) → Divide (M5 – M4) → Saturate → Lerp

This allows the gradient to remain within a controlled brightness range without affecting other tonal regions.

3. Creating Sharp Tonal Boundaries

For regions requiring clear boundaries, I used Step nodes to compare LightValue against thresholds such as M2 and M3.

The node connection was:

LightValue + Threshold → Step → Lerp (Alpha)

When the brightness crosses a specified threshold, the Step node switches its output between 0 and 1, creating a sharp transition between two colours.

Finally, I combined the five colour regions using multiple Lerp nodes and connected the final result to Emissive Color.

This allowed me to control both smooth gradients and sharp tonal boundaries within a single material.

Step 2: Custom Lighting System

After completing the five-level Toon Shader, the next step was to make the tonal regions respond to light positions within the scene.

Since I was using an Unlit Material, the shader could not directly respond to UE5’s conventional lighting system. Therefore, I needed to manually calculate the directional relationship between the surface and each light source.

1. Creating a Material Parameter Collection

First, I created a Material Parameter Collection (MPC_ToonLight) to share lighting information between Blueprint and the material.

I added three Vector Parameters:

LightPos0 / LightPos1 / LightPos2

These parameters store the world positions of three Point Lights.

2. Passing Light Positions Through Blueprint

Next, I created BP_ToonLights3 and added three Point Light Components.

In the Construction Script, I used Get World Location to retrieve the position of each light, then used Set Vector Parameter Value to write these coordinates into MPC_ToonLight.

The node connection was:

Point Light → Get World Location → Set Vector Parameter Value

Each light was assigned to its corresponding parameter: LightPos0, LightPos1, or LightPos2.

This allowed the material to access the light positions without manually entering their coordinates.

3. Calculating Surface Brightness

Back in the Material Editor, I used Collection Parameter nodes to retrieve the three light positions.

First, I used Absolute World Position to obtain the world coordinates of the current pixel.

Then, I used Subtract to calculate the direction from the surface towards the light source, followed by Normalize to convert it into a unit vector.

The node connection was:

Light Position – Absolute World Position → Normalize

Next, I used PixelNormalWS to obtain the surface normal in world space and Dot Product to calculate the relationship between the surface orientation and the light direction.

PixelNormalWS + Light Direction → Dot Product

When the surface faces the light source, the Dot Product produces a higher value. When the surface faces away from the light, the value becomes lower.

I repeated this calculation for all three light sources.

4. Combining Multiple Light Sources

To allow the material to respond to three light sources, I used two Max nodes to combine the three Dot Product results.

The node connection was:

Dot 0 + Dot 1 → Max → Max (Dot 2)

This method selects the highest brightness value from the three light sources, preventing excessive brightness caused by directly adding their contributions together.

I then used ConstantBiasScale to adjust the brightness distribution and Saturate to clamp the result between 0 and 1.

The resulting LightValue was connected to the five-level Toon Shader developed earlier, controlling the distribution of the different tonal regions.

This allowed the surface shading to change when the light position data was updated.

It is important to note that this system calculates brightness primarily based on light direction. It does not fully simulate physically accurate lighting effects such as distance attenuation, occlusion, or shadows.

Step 3: Final Material Integration

Finally, I connected the custom lighting system to the five-level Toon Shader.

The overall material workflow was:

Point Light Position → Surface Normal Calculation → LightValue → Five-Level Shading → Emissive Color

Through this process, I developed a Toon Shader with five distinct tonal regions, different transition styles, and the ability to adjust its shading based on multiple light positions.

This material provided a controllable brightness structure for the subsequent Post Process Material, allowing me to further convert different grayscale regions into black-and-white dithering patterns.

3. Result

Through this experiment, I developed a five-level Toon Shader capable of calculating surface brightness based on multiple light positions.

Compared with a conventional Toon Shader, this material allows me to control not only the number of tonal regions but also the transition style between them.

By using a Material Parameter Collection and Blueprint, the material can also update its shading distribution according to the light position data provided by the scene.

The main goal of this stage was not to generate the final black-and-white dithering effect, but to establish a stable and controllable tonal structure for the subsequent Post Process Material.

Categories
FMP

FMP | Visual Style Test 04: Return of the Obra Dinn 1–Visual Analysis & Technical Planning

1. Visual Inspiration

Following my previous Halftone, Cross-Hatching, and Soft Two-Tone Shading experiments, I began exploring a more complex black-and-white rendering style. This time, my visual reference was the game Return of the Obra Dinn.

What attracted me most to this game was its distinctive monochrome aesthetic. The visuals are primarily composed of black and white, using large areas of solid colour and pixel patterns of varying densities to represent lighting and spatial structure.

When analysing the reference, I identified two key visual characteristics.

First, there is a clear separation between illuminated and shadowed surfaces. Large black-and-white regions emphasise the geometric structure of objects, creating strong visual contrast.

Second, instead of relying on traditional grayscale gradients, the image uses different densities of black-and-white pixels to represent intermediate brightness levels. I divided this visual approach into five main tonal regions:

Tonal Region Visual Representation

Darkest– Black background with a few white noise dots

Dark –Solid black

Mid-tone — Mixed black-and-white dithering

Light– White background with a few black noise dots

Brightest –Solid white

This approach maintains strong black-and-white contrast while preserving tonal variation through changes in pixel density.

Another important feature I wanted to preserve was the clarity of object silhouettes. In complex scenes, clear outlines help distinguish characters, buildings, and background elements, preventing objects with similar brightness values from blending together.

Therefore, I wanted to apply this combination of bold black-and-white shapes, procedural dithering, and clear outlines to Rushing Place.

2. Technical Planning

To achieve this effect, I planned to divide the rendering system into two parts: Surface Material and Post Process Material, responsible for object outlines and tonal representation respectively.

Surface Material | Adaptive Black-and-White Outlines

First, I planned to create adaptive black-and-white outlines using surface materials.

Since the final image would contain only black and white, outlines with a fixed colour could easily blend into the background. To address this, I wanted the outline colour to change automatically based on the surrounding brightness:

* Dark regions: White outlines.

* Light regions: Black outlines.

This approach would help characters and environmental objects maintain clear silhouettes under different lighting conditions.

Post Process Material | Grayscale Quantization & Procedural Dithering

The post-process material would handle three main stages.

Step 1: Grayscale Conversion

First, I would convert the original rendered scene into grayscale, extracting brightness information while preserving the original lighting relationships.

Step 2: Grayscale Quantization

Next, I planned to divide the continuous grayscale values into five stable tonal levels using different brightness thresholds:

Black / Dark Grey / Grey / Light Grey / White

Each tonal level would correspond to a different black-and-white pixel distribution.

Step 3: Procedural Dithering

Finally, I would represent the brightness of each pixel by adjusting the density of black-and-white patterns according to its tonal level.

The darkest regions would use a black background with a few white dots, while the dark regions would remain solid black. Mid-tones would use a mixture of black-and-white dots, lighter regions would have a white background with a few black dots, and the brightest regions would remain solid white.

I planned to use ScreenPosition and mathematical nodes to generate a procedural grid, then control the distribution of black-and-white pixels using pseudo-random values.

Rather than displaying grey directly, this method would create the perception of different brightness levels through the proportion of black and white pixels, producing a dithering effect similar to the visual reference.

Categories
FMP

FNP|Visual Style Test 03: Soft Two-Tone Shading

1. Visual Inspiration

Following my previous Halftone and Cross-Hatching experiments, I began exploring a simpler black-and-white rendering style: Soft Two-Tone Shading.

Unlike the previous tests, which relied on procedural patterns to represent light and shadow, this experiment focuses on tonal separation and smooth transitions. I wanted to enhance the contrast while preserving the original lighting, creating a visual style inspired by black-and-white photography and X-ray imagery.

For Rushing Place, this approach could reduce visual distractions caused by complex textures and strengthen the atmosphere through lighting and spatial depth.

2. Technical Development

This experiment was developed using a Post Process Material in Unreal Engine 5, combining grayscale conversion, two-tone shading, and depth-based masking.

Grayscale Conversion

First, I used SceneTexture (PostProcessInput0) to capture the rendered scene and connected its Color output to Desaturation, setting the Fraction to 1 to remove all colour.

I then used Component Mask (R) to extract the grayscale information for further brightness calculations.

Node connection:

SceneTexture → Desaturation → Component Mask (R)

Two-Tone Shading

To separate the image into light and dark regions, I created two grayscale calculations.

Dark Region:

Grayscale → Multiply (DarkRange: 0.4)

Light Region:

Grayscale → Multiply (LightRange: 0.18) → Add (LightMin: 0.8)

These operations remap the original grayscale values into two distinct brightness ranges, increasing the contrast between light and shadow.

I then used SplitThreshold (0.5) and TransitionSoftness (0.15) to control the boundary between these regions.

These parameters were connected to Subtract and Add nodes to calculate the minimum and maximum values for a SmoothStep node.

The grayscale value was connected to the SmoothStep Value input to generate a smooth brightness mask.

Finally, I used a Lerp node to blend the dark and light results, with the SmoothStep output controlling the Alpha input.

Node connection:

Grayscale → SmoothStep → Lerp (DarkResult / LightResult)

Unlike Step, which creates a sharp boundary, SmoothStep allows a gradual transition between the two tonal regions, maintaining strong contrast while producing softer shading.

Depth-Based Masking

To further control the appearance of foreground and background elements, I used SceneDepth to obtain depth information from the scene.

First, I connected ScreenPosition to the UVs input of SceneDepth.

I then used BackgroundDepth (5000) and BackgroundFade (1000) with Add and Subtract nodes to define the depth transition range.

These values were connected to SmoothStep to generate a BackgroundMask.

Node connection:

ScreenPosition → SceneDepth → SmoothStep → BackgroundMask

The BackgroundMask was then inverted using OneMinus (1-x) to create a ForegroundMask.

Based on these masks, I further experimented with Power, Subtract, and Multiply nodes to adjust the mask distribution and explore depth-based edge transitions.

X-Ray and Glow

To explore a more experimental visual appearance, I also developed an X-ray-inspired brightness processing branch.

First, I used a Power node with XRayContrast (1.6) to adjust the grayscale contrast.

The result was then multiplied by XRayOpacity (0.75) to control the intensity of the effect.

I also introduced GlowStrength and EdgeGlowStrength parameters to explore brightness enhancement and depth-based edge effects.

These adjustments provided additional possibilities for controlling contrast, spatial depth, and the overall visual atmosphere.

3. Visual Experiment

After building the material, I focused on adjusting several parameters to observe their influence on the final image:

* SplitThreshold: Controls the brightness level separating light and dark regions.

* TransitionSoftness: Controls the smoothness of the tonal transition. Lower values produce sharper boundaries.

* DarkRange / LightRange: Adjust the brightness distribution within the dark and light regions.

* BackgroundDepth / BackgroundFade: Control the depth boundary and transition between foreground and background elements.

By adjusting these parameters, I could explore different visual results, ranging from soft grayscale shading to stronger black-and-white contrast.

Compared to Halftone and Cross-Hatching, this technique reduces repetitive textures and places greater emphasis on the scene’s lighting and spatial structure.

4. Reflection

This experiment helped me better understand how grayscale remapping and SmoothStep nodes can be used to create stylised lighting effects in UE5.

One of the main challenges I encountered was balancing strong contrast with the preservation of visual details. Initially, the tonal separation was too strong, causing some details to disappear, particularly in darker areas. To address this, I repeatedly adjusted SplitThreshold and TransitionSoftness, aiming to maintain clear contrast while creating more natural transitions between light and shadow.

Another challenge was controlling the depth-based masks. Since objects were positioned at different distances from the camera, a fixed BackgroundDepth value did not work consistently across all scenes. I experimented with BackgroundFade and other mask parameters to reduce abrupt transitions between foreground and background elements.

Compared to my previous Halftone and Cross-Hatching experiments, this rendering approach produces a cleaner image with fewer complex textures, placing greater emphasis on lighting and spatial structure.

For Rushing Place, I believe this style could help create a sense of psychological pressure through strong tonal contrast. However, it is important to avoid excessive simplification that could reduce visual clarity.

Overall, this experiment showed me that stylised rendering is not only about creating a distinctive visual appearance, but also about finding a balance between artistic expression, technical control, and visual readability.

Categories
FMP

FMP | Visual Style Test 02: Cross-Hatching Effect

1. Visual Inspiration

Following my Halftone experiment, I began exploring another black-and-white visual style: Cross-Hatching.

The reference image uses overlapping lines in different directions to create tonal variations. Lighter areas contain fewer lines and more white space, while darker areas are built up through dense, intersecting strokes, creating a printmaking or pen-and-ink aesthetic.

Compared to the dot-based structure of Halftone, Cross-Hatching emphasises line direction and repetition. This structured and repetitive visual language connects with the themes of urban order, repetitive behaviour, and psychological pressure in Rushing Place.

I therefore experimented with recreating this traditional drawing technique in a 3D environment using UE5’s procedural material system.

2. Technical Development

This experiment uses a Post Process Material in Unreal Engine 5 to generate screen-space hatching patterns and control their distribution based on scene brightness.

Grayscale Conversion

First, I used SceneTexture (PostProcessInput0) to capture the rendered scene and connected its Color output to Desaturation, setting the Fraction to 1 to remove all colour.

I then used Component Mask (R) to extract the grayscale information for brightness calculations.

Node connection:

SceneTexture → Desaturation → Component Mask (R)

Procedural Hatching

I used ScreenPosition to obtain screen coordinates and applied different mathematical operations to generate three sets of lines.

First Layer: Diagonal Lines

ScreenPosition (R + G) → Add → Multiply → Frac → Step

Second Layer: Opposite Diagonal Lines

ScreenPosition (R − G) → Subtract → Multiply → Frac → Step

Third Layer: Horizontal Lines

ScreenPosition (G) → Multiply → Frac → Step

The main nodes control different aspects of the pattern:

* Multiply: Controls line density using HatchDensity (150).

* Frac: Creates repeating patterns from continuous screen coordinates.

* Step: Converts the patterns into black-and-white lines using HatchWidth (0.37).

* OneMinus (1-x): Inverts the black-and-white values of selected patterns.

Combining these three directional patterns creates the cross-hatching effect.

Layered Shading

To control the hatching based on scene brightness, I created three grayscale thresholds:

* Layer1Threshold: 0.25

* Layer2Threshold: 0.50

* Layer3Threshold: 0.90

The Step nodes compare the scene’s grayscale values with these thresholds. The results are then combined with the hatching patterns using Multiply nodes.

Multiple Lerp nodes blend white, light grey, and medium grey values, allowing different brightness regions to display different combinations of lines.

Finally, the combined result is connected to Emissive Color and applied to the scene through a Post Process Volume.

3. Visual Experiment

After building the material, I focused on testing three parameters:

HatchDensity: Controls the frequency of the lines. Higher values produce denser patterns and finer textures.

HatchWidth: Controls line thickness. Thicker lines create stronger black-and-white contrast but may obscure details.

LayerThreshold: Controls how different hatching patterns are combined across brightness levels, affecting the overall tonal distribution.

Adjusting these parameters allowed me to explore different results, from simple line patterns to more complex overlapping textures.

4. Reflection

This experiment helped me better understand how mathematical nodes in UE5 can recreate traditional drawing techniques through procedural rendering.

Compared to Halftone, Cross-Hatching offers stronger directional patterns and a more hand-drawn appearance. The repeated and overlapping lines can also create visual tension, which relates to the themes of Rushing Place.

However, the technique has some limitations. Since the lines are generated using screen coordinates, they do not naturally follow object surfaces. Dense hatching can also reduce the readability of complex scenes.

Additionally, the procedural lines appear highly regular, lacking the natural variation of hand-drawn strokes.

Overall, this experiment expanded my exploration of black-and-white NPR styles and encouraged me to consider how to balance visual expression, readability, and emotional impact.

Categories
FMP

FMP | Visual Style Test 01: Halftone Effect

1. Visual Inspiration

During the visual development of Rushing Place, I wanted to explore an experimental black-and-white style made entirely of dots.

This test was inspired by Halftone art, which uses dots of different sizes to represent light and shadow, creating a visual effect similar to newspaper printing.

My idea was to first convert the image into greyscale, then use variations in dot size to represent different brightness levels. Darker areas have larger dots, making them appear denser, while lighter areas have smaller dots with more white space.

Through this approach, I wanted to simplify the image into a more abstract and graphic style while still keeping the basic shapes and three-dimensional forms of the objects.

2. Technical Development

I created this effect in Unreal Engine 5 (UE5) using a Post Process Material. This allows me to change the appearance of the entire scene without having to modify each object’s material individually.

First, I used the SceneTexture node to capture the scene image. I then used HLSL code inside a Custom node to calculate the brightness of the image and convert the colour information into greyscale values.

Next, I used the Screen Position node to get the screen coordinates. The image was divided into a regular grid, with a circular dot generated inside each grid cell.

The size of each dot changes automatically based on the brightness of the original image:

* Darker areas: Larger dots cover more space, making these areas appear denser and darker.

* Lighter areas: Smaller dots leave more empty space, making these areas appear lighter.

In this way, smooth changes in brightness are replaced by dots of different sizes, creating a halftone effect similar to traditional printing.

To make the effect more flexible, I added two main adjustable parameters:

Dot Density

This controls the number and spacing of dots across the image. Increasing the value creates more dots with smaller gaps, allowing the image to show more detail. Lowering the value creates fewer dots and a more abstract appearance.

Contrast

This controls how strongly the image brightness affects the dot sizes. Higher contrast creates a clearer difference between light and dark areas, while lower contrast produces a softer transition.

I also used a Noise node, combined with Step and Lerp nodes, to add a subtle grainy texture. By adjusting the noise scale and strength, I can introduce small variations to the regular dot pattern, making the image feel more like a printed texture.

Finally, I adjusted the black-and-white output in the Custom node to create two versions: white dots on a black background and black dots on a white background.

Both versions use the same post-process material setup, allowing me to adjust the parameters and test different results directly in UE5.

3. Visual Tests

For this experiment, I created two different versions of the halftone effect.

Version 01: Black Background / White Dots

The first version uses a black background with white dots to represent the light and dark areas of the image.

This version has stronger visual contrast and creates a more abstract, digital appearance.

Version 02: White Background / Black Dots

The second version uses a white background with black dots to represent the objects.

Compared with the first version, this effect is closer to traditional newspaper printing and creates a cleaner, more minimal visual style.

Adjustable Parameters

To make future development easier, I added parameters that can be adjusted at any time.

Dot Density: Controls the number and spacing of dots, allowing the image to appear more detailed or abstract.

Contrast: Controls the variation in dot sizes, making the differences between light and dark areas stronger or softer.

By adjusting these parameters, I can change the dot sizes, visual density, and overall appearance to suit different scenes without rebuilding the material.

4. Reflection

Through this test, I successfully created a halftone effect that transforms a regular 3D scene into a black-and-white image made of dots.

This style keeps the basic shapes of the objects while creating a more graphic and abstract appearance, which fits the experimental visual direction of Rushing Place.