Gamasutra: Ravi Teja Sanampudi’s blog

The following blog post was written by members of the Gamasutra ?? s community, unless otherwise stated.
The ideas and opinions expressed are those of the writer, not Gamasutra or its parent company.

Mafia III is an action-adventure video game set in the fictional city of New Bordeaux. The main character, Lincoln Clay, fights to take power from the Italian mob. Mafia III: Developer-narrated gameplay: https: //

“Intel View” is one of the tools players have and will help them survive this hostile world. Certain types of characters and objects in the scene (enemy, cops, medicine racks, weapon lockers, etc.) are highlighted. Therefore, it is easier for players to find and track them and take appropriate actions. Demo of Intel View on Mafia III: https: //

This article describes how Intel View worked and how it was implemented (mainly about rendering).

Functional requirements
You can tag all objects in the game world, highlight them in this mode, and untagged them when you no longer need them. When mode is enabled, all tagged objects within a certain radius from the player will be rendered invisible (visible to other objects) and colored / highlighted / silhouetted to pop out of the scene. Must be

Except for these objects, the entire screen should be desaturated and darkened. Different types of objects have different contour colors. (For example, police officers are blue, enemies are red, etc.). The highlight intensity should decrease as the object moves away from the player.

The gameplay code maintains a list of “special objects” that need to be managed (tagged and untagged) for each game scenario. Set the object category.
0: Default (that is, not highlighted)
1,2,3: IntelView object. The highlight color can be set for each artist.

This is a screenshot of normal game view.

In this scene, we will mark four objects in Intel View. The player’s red car, a cop, and two gangsters on the street. The following describes the procedure that occurs in one frame of the game.
(Input: List of Intel View objects and their categories)

1. Calculate the screen space AABB for each object and the distance from the player.
2. Render AABB so that the color intensity represents the distance. (We don’t use per-pixel depth because we need a uniform color across the object.) This is used to fade highlights over distance.

(Note: The code sample is provided for more detail and can be skipped if you just want to understand the high level logic)

Code sample 1: Render highlight object AABB

// Fill Vertex buffer of Highlight Objects' screen space AABBs
for each object
    outlineColorDepthFadeFactor = (maxHighlightDistance - object.m_DistanceFromCamera) / (maxHighlightDistance - minHighlightDistance); // between 0 and 1
    for each corner of object's ScreenSpace AABB
// Render the screen space AABBs of objects with object depth as pixel color (just 1 channel: red). (Figure-1):
RenderScreenSpaceMaterial(vertexColorMaterial, vertexData);

Object AABB and Distance Texture (Figure 1):Object AABB and distance texture

3. Render the object to G-Buffer and set different stencil values ​​for each category of object. It is used to associate each pixel in the image with its IntelView category.

Code sample 2: Render highlight objects and silhouettes

primaryColors[NUM_HIGHLIGHT_OBJECT_CATEGORIES]  = { Red, Green, Blue };
stencilBitValues[NUM_HIGHLIGHT_OBJECT_CATEGORIES]   = { 01000000, 10000000, 11000000 };
for each category
    // Regular object shading
    Set stencil buffer value to stencilBitValues[category], for each pixel written (Figure-3)
    Render objects in category to G Buffer (Figure-2)
    // Render object mask
    Set stencil logic so rendering will update only pixels that have stencil value stencilBitValues[category] (i.e. selective drawing of color on objects of this category)
    Enable blend, to add pixel values of any previous existing color (to show intel objects even when overlapping)
    RenderScreenSpaceMaterial using singleColorMaterial to Highlight Object Mask (Figure-4)
// singleColorMaterial pixel shader
HighlightObjectColorFadeDepthFactor = Figure 1
FinalShading = HighlightObjectColorFadeDepthFactor * ShaderParam_objectColor; // (Figure-4)

Scene rendered with G-Buffer (Fig. 2):G-buffer rendering scene

Stencil buffer (Fig. 3):Stencil buffer

4. Generate a texture that combines the information in Figures 1 and 3. The primary colors (R, G, B) indicate each object category.
Object Mask Highlights (Figure 4):Highlight object mask

5. Blur the highlight object mask to make each object’s silhouette a little larger.
Blurred highlight object mask (Figure 5):Blurred highlight object mask

6. Subtract the texture (5-4) to the silhouette edge (5-4)Figure-6): Silhouette edge

7. Reduce the saturation and brightness of the G-Buffer image (Fig. 2)
8. Replace the primary colors (RGB) in Figure 6 with the artist-defined colors for each category and add them to get the final output. Intel View (Figure 7):Intel view

Code sample 3: Post-processing pseudo code

//These textures are RGBA8 at half the game resolution. RT = Render Target
DownSampleRT(innerHighlightMaskRT, innerHighlightMaskHalfRT); // innerHighlightMaskRT = (Figure-4);
BlurRTGaussianPixelSize(innerHighlightMaskHalfRT, tempRT, 1, blur parameters 1);
BlurRTGaussianHorizontal(innerHighlightMaskHalfRT, tempRT, blur parameters 2);
BlurRTGaussianVertical(tempRT, outerHighlightMaskRT, blur parameters 2); // outerHighlightMaskRT = (Figure-5)
// Object Highlight pixel shader
SceneColor = G-Buffer Texture (Figure-2)
InnerHighlightMask = Highlight Object Mask (Figure-4)
OuterHighlightMask = Blurred Highlight Object Mask (Figure-5)
highlightMask.rgb = ShaderParam_OuterHighlightScale * OuterHighlightMask.rgb - ShaderParam_InnerHighlightScale * InnerHighlightMask.rgb; // (Figure-6)
HighlightColor = (highlightMask.r * ShaderParam_MaterialColor1 + highlightMask.g * ShaderParam_MaterialColor2 + highlightMask.b * ShaderParam_MaterialColor3);
float3 sceneColorHsv = RGBtoHSV(SceneColor.rgb);
sceneColorHsv.y *= ShaderParam_SaturationScale;
sceneColorHsv.z *= ShaderParam_BrightnessScale;
ColorCorrection = HSVtoRGB(sceneColorHsv);
FinalShading = ColorCorrection + HighlightColor; // (Figure-7)

Reduced the texture size of the highlight mask and fine-tuned the blur parameters to speed up the shader.
Before: Rendering Post-processing: 4 blur + object_highlight = 2370 us (Microseconds)
After: Render Post Process: Render Target Downsampling + 4 Blur + object_highlight = 586 us

Other notes
The designer wanted to increase the category of objects (each with a different color), but the technique only allowed three. Supporting more categories slows performance and complicates the algorithm. So in the end the designers worked on what we could give them.

thank you for reading.Questions, comments and feedback are welcome :)

Back to top button