In-Game Advertising (IGA) vs. In-App Advertising: Intrinsic 3D Billboards, Viewability, and OpenRTB Signaling
Projecting a dynamically fetched programmatic ad creative onto a three-dimensional polygon mesh inside a 60 frames-per-second (FPS) rendering pipeline

Projecting a dynamically fetched programmatic ad creative onto a three-dimensional polygon mesh inside a 60 frames-per-second (FPS) rendering pipeline operates under fundamentally different engineering constraints than rendering a two-dimensional HTML5 or VAST overlay inside an operating system WebView. In traditional mobile and desktop application monetization, the advertising layer is entirely extrinsic to the core software loop: the application state pauses, an operating-system-level view controller assumes window focus, and a flat viewport renders an isolated advertisement. In three-dimensional gaming environments, however, monetization increasingly splits into two distinct execution architectures: extrinsic In-App Advertising (IAA) and intrinsic In-Game Advertising (IGA).
While extrinsic IAA monetizes session transitions through full-screen breaks, intrinsic IGA embeds programmatic ad placements directly into the Euclidean geometry of the virtual world. Trackside LED ribbons in motorsport simulators, perimeter boards in soccer stadiums, bus-stop kiosks in open-world action titles, and arena jumbotrons all function as UV-mapped surfaces populated in real time via OpenRTB auctions. The player never leaves the active scene, the physics engine never halts, and the camera frustum moves freely relative to the ad surface.
For game studio technical directors and programmatic yield architects, bridging a real-time 3D engine with sub-200-millisecond programmatic exchanges requires solving three deeply connected systems challenges: computing spatial viewability telemetry without starving the CPU render thread, managing asynchronous GPU texture streaming within tight mobile VRAM budgets, and translating 3D surface attributes into standardized OpenRTB 2.6 bid requests that tier-1 DSPs can price accurately.
Intrinsic In-Game Ads vs. Extrinsic Interstitial/Rewarded Breaks
The architectural boundary between extrinsic IAA and intrinsic IGA begins at the application state machine and extends all the way to buy-side campaign objectives. Extrinsic IAA relies on discrete gameplay interruptions. When a user completes a level, fails a mission, or explicitly opts into a value-exchange prompt for virtual currency, the host application suspends the game loop, mutes background audio channels, and invokes a mediation layer such as the Google Mobile Ads (GMA) Next-Gen SDK or Prebid Mobile. The SDK instantiates a native UIViewController on iOS or an Activity dialog on Android to render a full-screen video interstitial, a rewarded video, or an interactive playable ad format unit.
Because extrinsic units command 100% share of voice on the device screen and pause player movement, they are engineered for direct user interaction. Touch events map directly to click-through URLs, SKAdNetwork or AdAttributionKit storekit overlays, and Google Play Install Referrer conversion flows. Consequently, extrinsic IAA inventory is dominated by performance and user acquisition (UA) demand, priced dynamically on effective cost-per-thousand-impressions (eCPM) models tied closely to downstream install and return-on-ad-spend (ROAS) conversion rates.
Intrinsic IGA inverts this model by executing asynchronously inside the active 3D scene graph. An intrinsic ad placement is a quad or curved mesh component attached to a parent game object inside the virtual level. It has no "close" button, does not interrupt frame execution, and does not capture screen-space touch inputs to redirect the player to an external app store. Attempting to force click-out behavior on a virtual billboard while a player is navigating a high-speed racing corner or aiming in a competitive multiplayer match degrades retention and generates accidental clicks that trigger DSP clawbacks. Instead, intrinsic IGA operates as an upper-funnel and mid-funnel brand awareness channel, structurally analogous to Digital Out-of-Home (DOOH) or live sports broadcast signage, transacted on viewable CPM (vCPM) guarantees.
| Architectural Dimension | Extrinsic In-App Advertising (IAA) | Intrinsic In-Game Advertising (IGA) |
|---|---|---|
| Game Loop State | Paused; physics and scene rendering suspended | Active; runs concurrently at 60-120 FPS |
| Rendering Surface | 2D OS WebView or native UI overlay container | 3D UV-mapped mesh material with shaders and mipmaps |
| Primary Demand Type | Performance UA, app install, direct response | Brand awareness, sponsorship, omnichannel video/display |
| Click Interaction | High CTR; StoreKit / Custom Tab / deep-link redirect | Non-clickable (0% CTR); measured on spatial attention |
| Viewability Standard | 2D OM SDK viewport pixel percentage (50% / 1s or 2s) | IAB/MRC 3D spatial frustum, angle (<=55°), and raycast rules |
| Retention Impact | High frequency increases session churn risk | Zero interruption; preserves core session length |
Rather than treating these two paradigms as mutually exclusive, mature studios architect hybrid mobile game monetization stacks. In a hybrid waterfall or unified auction setup, extrinsic rewarded video captures high-intent performance budgets during natural menu breaks, while intrinsic 3D billboards monetize the 85% to 95% of active session duration spent inside the core gameplay loop. This dual-track approach unlocks incremental yield from "ad-averse" cohorts and paying users who never engage with opt-in rewarded prompts, generating clean brand revenue without increasing interstitial frequency caps.
The IAB/MRC Intrinsic In-Game Measurement Guidelines
In standard two-dimensional web and mobile app environments, viewability measurement via the IAB Tech Lab Open Measurement SDK (OM SDK) relies on simple bounding-box geometry: an impression is counted as viewable when at least 50% of the ad container's pixels reside within the visible device viewport for one continuous second for display, or two continuous seconds for video. When applied to a three-dimensional Euclidean coordinate system with a perspective camera projection, 2D bounding-box rules break down completely.
Inside a 3D game world, a virtual billboard mesh may technically reside inside the camera's viewing frustum while positioned 800 meters away in the background, occupying only 0.05% of the screen's physical pixels. Alternatively, the player's camera might view the billboard from an extreme 80-degree oblique angle, compressing the creative texture horizontally through perspective foreshortening until the brand messaging is unreadable. Furthermore, dynamic 3D world geometry, such as passing vehicles, character models, foliage, particle smoke, or the game's own 2D heads-up display (HUD), can occlude the billboard even when its world-space coordinates lie directly in front of the camera.
To establish rigorous auditability for brand buyers, the IAB Tech Lab and MRC Intrinsic In-Game Advertising Measurement Guidelines standardize viewability for 3D virtual billboards inside gaming environments based on screen size percentage, camera viewing angle thresholds, occlusion, and continuous exposure duration. Under this specification, a 3D ad impression cannot be certified as viewable merely because its texture was loaded into level memory or entered the outer camera frustum. Instead, the client-side measurement runtime must continuously validate four simultaneous physical conditions at a minimum sampling frequency of 5 Hz (once every 200 milliseconds):
- Minimum Screen Size Coverage: The projected 2D screen-space pixel area of the 3D ad unit must occupy at least 1.5% of the total active display viewport resolution (
Screen.width * Screen.height). Measurement payloads also bucket relative screen coverage into granular tiers (such as 1.5% to 3%, 3% to 5%, 5% to 10%, and >10%) so DSPs can value prominent foreground placements above distant background signage. - Camera Viewing Angle Threshold: The relative angle between the surface normal vector of the 3D billboard mesh and the ray vector extending from the active virtual camera to the center of the billboard must not exceed 55 degrees on any axis (pitch, yaw, or roll).
- Pixel Visibility and Non-Occlusion: At least 50% of the ad unit's projected screen-space area must remain inside the viewport bounds and completely free of obstruction from intermediate 3D scene geometry, alpha-blended particle effects, or 2D UI canvas overlays.
- Continuous Exposure Duration: All spatial, angular, size, and occlusion conditions must pass consecutively for at least 1.0 continuous second for static display creatives, or 2.0 continuous seconds for streaming video creatives. If any single 200ms polling tick fails a threshold (for example, a passing truck blocks 60% of the billboard at the 800ms mark), the continuous viewability timer resets to zero.
Calculating Screen Coverage Percentage, Viewing Angle (<=55 Degrees), and Lighting Obstructions
Implementing the IAB/MRC spatial rules inside a live game engine requires deterministic linear algebra executed at fixed polling intervals. During each 200ms telemetry tick, the verification module transforms the four corner vertices of the billboard quad from local object space into world space, and then multiplies them by the active camera's view-projection matrix to obtain Normalized Device Coordinates (NDC). After clipping the resulting polygon against the near, far, left, right, top, and bottom frustum planes, the engine maps the surviving vertices into 2D screen-space pixel coordinates and computes the enclosed surface area using the shoelace theorem. Dividing this visible pixel area by the total viewport pixel count yields the exact screen coverage ratio. Concurrently, the runtime evaluates the viewing angle by calculating the dot product of the normalized billboard forward normal vector ($\vec{N}$) and the normalized vector pointing from the billboard center to the camera origin ($\vec{V}$). Because the cosine of 55 degrees is approximately 0.573576, any sample tick where $\vec{N} \cdot \vec{V} < 0.573576$ immediately registers as out of bounds.

Validating occlusion without stalling the graphics pipeline is the most performance-sensitive step in the measurement loop. Reading back the GPU depth buffer or stencil buffer to main CPU memory (glReadPixels or ReadPixels) breaks asynchronous command buffer execution on mobile Tile-Based Deferred Rendering (TBDR) GPUs, introducing 4ms to 8ms frame hitches. To maintain zero-overhead measurement, production gaming ad SDKs implement a spatial raycast grid. The SDK generates a uniform $3 \times 3$ or $5 \times 5$ grid of sample coordinates across the UV surface of the billboard mesh. At each 200ms interval, it checks whether each sample point falls beneath a registered 2D HUD RectTransform mask, and then fires a physics raycast from the active camera position to each world-space grid point. If at least 50% of the rays strike the billboard collider first without intersecting environment geometry or player character colliders, the occlusion check passes.
Beyond geometry occlusion, the IAB/MRC guidelines require accounting for scene lighting, shadow maps, and post-processing shaders (such as heavy volumetric fog, bloom, or night-time ambient attenuation) that can render a texture visually indistinct. If a game engine binds an ad texture to a standard Physically Based Rendering (PBR) lit material and a dynamic cloud shadow drops surface luminance by 90%, the creative is no longer viewable in practice. Studio technical artists address this at the shader level by binding intrinsic ad quads to unlit or custom emissive material graphs with clamped exposure multipliers, ensuring the creative maintains consistent sRGB color fidelity regardless of scene lighting, while exposing fog-density parameters to the telemetry loop so heavy atmospheric obstruction suspends the viewability timer.
using UnityEngine;
public class IntrinsicBillboardViewabilityTracker : MonoBehaviour
{
private const float POLL_INTERVAL_SECONDS = 0.2f;
private const float MIN_SCREEN_COVERAGE_RATIO = 0.015f; // 1.5% minimum viewport area
private const float MAX_ANGLE_COSINE = 0.5735764f; // cos(55 degrees)
private const float REQUIRED_VISIBLE_RAY_RATIO = 0.50f; // >= 50% unoccluded
private const float REQUIRED_CONTINUOUS_DURATION = 1.0f; // 1.0s for static display
[SerializeField] private MeshFilter billboardMeshFilter;
[SerializeField] private Collider billboardCollider;
[SerializeField] private LayerMask occlusionMask;
private float pollTimer;
private float continuousViewableTime;
private bool impressionMeasured;
private Vector3[] localGridPoints;
private void Awake()
{
// Precompute a 3x3 UV-aligned sampling grid on the local quad (-0.5 to 0.5)
localGridPoints = new Vector3[9];
int idx = 0;
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
localGridPoints[idx++] = new Vector3(x * 0.33f, y * 0.33f, 0f);
}
}
}
private void Update()
{
if (impressionMeasured || Camera.main == null) return;
pollTimer += Time.unscaledDeltaTime;
if (pollTimer < POLL_INTERVAL_SECONDS) return;
float elapsedTick = pollTimer;
pollTimer = 0f;
if (EvaluateSpatialViewability(Camera.main))
{
continuousViewableTime += elapsedTick;
if (continuousViewableTime >= REQUIRED_CONTINUOUS_DURATION)
{
impressionMeasured = true;
FireViewableMeasurementBeacon();
}
}
else
{
continuousViewableTime = 0f;
}
}
private bool EvaluateSpatialViewability(Camera cam)
{
Transform t = transform;
Vector3 toCamera = (cam.transform.position - t.position).normalized;
// 1. Viewing Angle Check (Surface normal vs Camera vector <= 55 degrees)
float dot = Vector3.Dot(-t.forward, toCamera);
if (dot < MAX_ANGLE_COSINE) return false;
// 2. Screen Coverage Percentage Check (>= 1.5% of total viewport resolution)
float screenCoverage = CalculateProjectedScreenCoverage(cam, t);
if (screenCoverage < MIN_SCREEN_COVERAGE_RATIO) return false;
// 3. Multi-Point Raycast Occlusion Check (>= 50% rays unobstructed)
int unoccludedSamples = 0;
Vector3 camPos = cam.transform.position;
for (int i = 0; i < localGridPoints.Length; i++)
{
Vector3 worldPt = t.TransformPoint(localGridPoints[i]);
Vector3 vp = cam.WorldToViewportPoint(worldPt);
// Must lie in front of near clip plane and inside 0..1 screen bounds
if (vp.z <= cam.nearClipPlane || vp.x < 0f || vp.x > 1f || vp.y < 0f || vp.y > 1f)
continue;
Vector3 dir = worldPt - camPos;
float dist = dir.magnitude;
if (Physics.Raycast(camPos, dir / dist, out RaycastHit hit, dist + 0.05f, occlusionMask))
{
if (hit.collider == billboardCollider)
unoccludedSamples++;
}
}
float visibleRatio = (float)unoccludedSamples / localGridPoints.Length;
return visibleRatio >= REQUIRED_VISIBLE_RAY_RATIO;
}
private float CalculateProjectedScreenCoverage(Camera cam, Transform t)
{
Vector3[] corners = new Vector3[4]
{
t.TransformPoint(new Vector3(-0.5f, -0.5f, 0f)),
t.TransformPoint(new Vector3( 0.5f, -0.5f, 0f)),
t.TransformPoint(new Vector3( 0.5f, 0.5f, 0f)),
t.TransformPoint(new Vector3(-0.5f, 0.5f, 0f))
};
Vector2[] screenPts = new Vector2[4];
for (int i = 0; i < 4; i++)
{
Vector3 sp = cam.WorldToScreenPoint(corners[i]);
if (sp.z <= 0f) return 0f;
screenPts[i] = new Vector2(
Mathf.Clamp(sp.x, 0f, Screen.width),
Mathf.Clamp(sp.y, 0f, Screen.height)
);
}
// Shoelace formula for projected quad area in screen pixels
float area = 0f;
for (int i = 0; i < 4; i++)
{
int next = (i + 1) % 4;
area += (screenPts[i].x * screenPts[next].y) - (screenPts[next].x * screenPts[i].y);
}
float pixelArea = Mathf.Abs(area) * 0.5f;
float totalScreenPixels = (float)Screen.width * Screen.height;
return pixelArea / totalScreenPixels;
}
private void FireViewableMeasurementBeacon()
{
// Dispatch OMID / IAB viewability telemetry to SSP verification endpoint
}
}
Texture Streaming Latency and Memory Budgets in Unity and Unreal Engine
While browser-based programmatic wrappers delegate image decoding and compositing to multi-process OS browser engines with generous virtual memory paging, real-time 3D engines such as the Unity runtime and Unreal Engine operate under unforgiving frame-time and memory ceilings. At 60 FPS, the entire CPU and GPU frame budget is 16.67 milliseconds; at 120 FPS on modern flagship mobile displays and consoles, the budget shrinks to 8.33 milliseconds.
If an ad integration downloads a 2048x1024 PNG payload from a DSP's CDN and invokes a synchronous image decode (Texture2D.LoadImage(byte[])) on the main game thread, the CPU stalls for 15ms to 45ms while decompressing the byte stream and copying the uncompressed pixel buffer across the CPU-GPU memory bus. To the player, this manifests as a jarring frame hitch right as they enter a new section of the game map. Furthermore, retaining CPU-side readable copies of ad textures triggers managed heap fragmentation and garbage collection pauses.
To eliminate frame-time jitter and out-of-memory (OOM) crashes on 3 GB and 4 GB mobile devices, production rendering pipelines enforce four strict memory and streaming practices:
- Asynchronous Worker-Thread Decoding and Non-Readable GPU Uploads: In the Unity runtime, creative assets must be fetched via
UnityWebRequestTexture.GetTexture(url, nonReadable: true). Setting thenonReadableflag instructs the engine to decode the JPEG/PNG buffer on a background worker thread, upload the resulting texture directly to the GPU command queue, and immediately free the CPU-side system memory buffer. In Unreal Engine, engineers use asynchronous download tasks (UAsyncTaskDownloadImage) paired withUTexture2DDynamicresources bound to a pre-compiledUMaterialInstanceDynamicslot, avoiding runtime shader permutation compilation. - Runtime Mipmap Generation and Anisotropic Filtering: A flat 2D ad texture mapped directly onto a 3D polygon without mipmaps produces severe spatial aliasing (shimmering moire patterns) when viewed at oblique angles or medium distances. Upon texture upload, the rendering pipeline must generate a mipmap chain on the GPU and configure the material sampler state with 4x or 8x anisotropic filtering. This preserves crisp brand typography up to the 55-degree viewing angle boundary while reducing GPU texture-cache bandwidth when the billboard is far away.
- Strict VRAM Resolution Caps and Reference-Counted Pooling: An uncompressed RGBA32 texture at 2048x1024 resolution with mipmaps consumes roughly 11.1 MB of VRAM. Populating 20 unique stadium billboards at that resolution would consume over 220 MB of VRAM, exhausting the texture pool on mid-tier mobile System-on-Chips (SoCs). Studio pipelines enforce strict resolution caps mapped to the physical scale of the mesh (typically 1024x512 for large roadside boards and 512x256 for smaller kiosk surfaces) and immediately destroy or recycle GPU texture handles via reference-counted object pools as soon as the player transitions out of the spatial sector.
- Look-Ahead Spatial Pre-Fetching: An OpenRTB 2.6 auction combined with DSP creative CDN retrieval typically requires 150ms to 350ms end-to-end latency. If the client waits until a billboard enters the camera frustum to request an ad, the player will see a blank placeholder texture for the first half-second of exposure. High-yield implementations place invisible spatial trigger volumes (
BoxCollideror Octree proximity zones) 5 to 8 seconds ahead of the player's velocity vector, initiating the programmatic bid request and pre-warming the GPU texture buffer before the billboard rounds the corner into view.
How Intrinsic Inventory Is Signaled to Programmatic DSPs
Even the most optimized 3D rendering and measurement pipeline will suffer from low fill rates and aggressive bid shading if the sell-side platform fails to translate spatial inventory into OpenRTB 2.6 structures that buy-side bidding algorithms understand. Most tier-1 DSPs are trained on billions of daily 2D web, mobile app, and CTV bid requests. If an SSP transmits arbitrary aspect ratios (such as 812x340) or fails to declare the non-clickable nature of an intrinsic 3D surface, DSP pre-filters either drop the request for lacking matching creative sizes or penalize the placement ID because its historical click-through rate is 0.0%.
Our unified SSP and monetization platform bridges this gap by normalizing 3D canvas geometry and explicitly declaring spatial telemetry inside standard OpenRTB 2.6 bid requests:
- Standardized Aspect Ratios Mapped to IAB Display and Video Sizes: While a 3D billboard mesh may measure 8 meters by 4.5 meters in virtual world units, its UV render target is configured to match high-density IAB aspect ratios such as
16:9(mapped to1920x1080or1280x720video/display),6:1leaderboard proportions (728x90), or1.91:1native landscape (1200x627). By populatingimp.banner.formatwith these exact pixel dimensions, publishers unlock standard display, native, and VAST 4.3 video demand pools without requiring media agencies to traffic custom 3D creative files. - Explicit Viewability and Zero-Click Expectation Signaling (
imp.metric): To prevent DSP click-prediction models from devaluing non-clickable 3D billboards, the bid request includes animp.metricarray that explicitly declares historical MRC-verifiedviewabilityrates (for example,0.88) alongside aclick_through_ratemetric of0.0. Simultaneously, the impression extension signals the intrinsic in-game context so brand bidding algorithms optimize for viewable duration, screen coverage, and attention rather than click probability. - VAST 4.3 Spatial Verification for Video Billboards: For animated LED stadium ribbons and video screens, the SSP emits an
imp.videoobject specifyingplcmt: 4(Standalone / In-Game environment),playbackmethod: [2, 6](auto-play sound off), andapi: [7](OMID-1). The VAST 4.3 response injects<AdVerification>tracking nodes that bind video quartile events (firstQuartile,midpoint,thirdQuartile,complete) directly to the 3D frustum evaluator, ensuring quartiles only fire while the player maintains a valid <=55-degree line of sight. - Supply Chain Transparency and IVT Hygiene: Because intrinsic IGA commands premium brand CPMs, headless emulator spoofing and unauthorized reselling are primary buy-side concerns. Every outbound bid request from Sky Boosts carries strict
app-ads.txtauthorization, a completesource.ext.schainnode, and pre-bid filtering verified against HUMAN and Pixalate invalid traffic (IVT) detection engines. We pair this technical enforcement with a 100% Google-friendly brand safety policy (zero alcohol, gambling, adult, or restricted categories) and reliable Net-30 and Net-60 publisher payout cycles.
{
"id": "8f92a7d1-4c11-4e9a-b831-09a1e472c501",
"tmax": 220,
"imp": [
{
"id": "1",
"tagid": "stadium_turn4_billboard_north",
"instl": 0,
"clickbrowser": 0,
"banner": {
"w": 1200,
"h": 627,
"format": [
{ "w": 1200, "h": 627 },
{ "w": 1920, "h": 1080 }
],
"pos": 1,
"api": [7]
},
"metric": [
{
"type": "viewability",
"value": 0.89,
"vendor": "iabtechlab.com-omid"
},
{
"type": "click_through_rate",
"value": 0.00,
"vendor": "EXCHANGE"
}
],
"bidfloor": 4.50,
"bidfloorcur": "USD",
"ext": {
"iga": {
"placement_type": "intrinsic_3d_billboard",
"clickable": 0,
"min_screen_coverage_pct": 3.5,
"max_viewing_angle_deg": 55,
"lighting_shader": "unlit_clamped_srgb"
}
}
}
],
"app": {
"id": "104928",
"name": "Apex GT Motorsport Simulator",
"bundle": "com.studio.apexgt",
"storeurl": "https://play.google.com/store/apps/details?id=com.studio.apexgt",
"cat": ["IAB9", "IAB9-30"],
"publisher": {
"id": "pub-7821",
"name": "Apex Interactive Studios"
}
},
"device": {
"ua": "Mozilla/5.0 (Linux; Android 14; SM-S928U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36",
"ip": "198.51.100.42",
"os": "Android",
"osv": "14",
"w": 3120,
"h": 1440,
"ifa": "38400000-8cf0-11bd-b23e-10b96e40000d"
},
"source": {
"fd": 1,
"tid": "c72e9910-51a2-4091-80e1-772b12e4f110",
"ext": {
"schain": {
"complete": 1,
"ver": "1.0",
"nodes": [
{
"asi": "skyboosts.com",
"sid": "pub-7821",
"hp": 1,
"rid": "8f92a7d1-4c11-4e9a-b831-09a1e472c501"
}
]
}
}
}
}
When deploying or auditing an intrinsic in-game monetization pipeline, engineering and AdOps teams should validate four production checkpoints before scaling traffic:
- Enforce Standard UV Aspect Ratios in Level Design: Standardize all 3D billboard meshes to
16:9,1.91:1, or6:1UV proportions so your SSP can map requests directly to high-liquidity OpenRTB display, native, and VAST 4.3 video demand pools. - Decouple Texture Decoding from the Main Render Thread: Always execute network downloads and image decompression on background worker threads with non-readable GPU uploads, mipmap generation, and strict per-scene VRAM pools.
- Implement 5 Hz Spatial Raycast and Angle Telemetry: Verify that your measurement layer enforces the
<=55degree normal-to-camera angle,>=1.5%screen coverage, and multi-point raycast occlusion checks for 1.0 continuous second (display) or 2.0 continuous seconds (video). - Signal Non-Clickability and Viewability Metrics in OpenRTB 2.6: Populate
imp.metricand placement extensions to inform DSP algorithms that the unit is an intrinsic 3D brand placement, protecting your inventory from CTR-based bid shading while capturing premium vCPM clearing prices.