ADR-400: Render to Texture

More details about this document
Latest published version:
https://adr.decentraland.org/adr/ADR-400
Authors:
robtfm
Feedback:
GitHub decentraland/adr (pull requests, new issue, open issues)
Edit this documentation:
GitHub View commits View commits on githistory.xyz

Abstract

This document describes an approach for allowing scenes to render alternative world views to textures, for use in UI and in-world displays.

This allows creating UIs with rendered 3d objects like an inventory display, custom map displays, video screens viewing other parts of a scene, and many other use cases.

Render to Texture

The heart of the approach is to define multiple "rendering layers", which are like distinct visual worlds. We add 3 new components, CameraLayer for layer specification, CameraLayers for layer membership, and TextureCamera for rendering.

Layer 0 is the main world, and is the layer viewed by the default camera. The explorer MUST support at least 3 layers (the main layer and additional layers 1 and 2). It MAY support further layers.

Entities can belong to multiple layers, cameras can only render a single layer, but multiple cameras may render the same layer:

LayersDiagram

Layers are used for rendering (entities with GltfContainers, MeshRenderers or light components, and any future types of rendered entities), and spatial audio components (PbAudioSource, AvatarShape). All other entity properties (collisions, etc) will not make any use of layer information.

Managing Layer Properties

Layer properties are managed via the CameraLayer component. This component can be added to any entity. There should not be more than 1 such component for each layer: if multiple components exist specifying the same layer the results are undefined.

layer 0, the main world, cannot be modified by scenes, and a CameraLayer affecting layer 0 will be ignored. Additional layers are managed fully by scenes. Various properties of the layer (lighting, avatar rendering, etc) can be managed via this component.

option (common.ecs_component_id) = 1210;
message PBCameraLayer {
    // layer to which these settings apply. must be > 0
    // Layer 0 is the default "real world" layer viewed by the player and cannot be modified.
    uint32 layer = 1;

    // should the sun light affect this layer? default false
    optional bool directional_light = 2;

    // should this layer show player avatars? default false
    optional bool show_avatars = 3;

    // should this layer show the sky? default false
    optional bool show_skybox = 4;

    // should this layer show distance fog? default false
    optional bool show_fog = 5;

    // ambient light overrides for this layer. default -> use same as main camera
    optional decentraland.common.Color3 ambient_color_override = 6;
    optional float ambient_brightness_override = 7;
}

Assigning Objects to Layers

The CameraLayers component is used to assign entities to layers. Like Visibility it is propagated to children automatically until overridden by a child with a defined CameraLayers of its own.

option (common.ecs_component_id) = 1208;
message PBCameraLayers {
    repeated uint32 layers = 1;
}

Entities can belong to multiple layers, and will be visible in cameras rendering any layer that they are in.

Rendering

The TextureCamera component creates a new texture, and renders all meshes with intersecting layers, from the viewpoint of this entity, into that texture. The texture can then be used via a VideoTexture with video_player_entity set to the camera entity.

If the volume field is non-zero, the camera entity should also act as an audio receiver for audio sources with an intersecting layer.

option (common.ecs_component_id) = 1207;
message PBTextureCamera {
    // rendered texture width
    optional uint32 width = 1;
    // rendered texture height
    optional uint32 height = 2;
    // which layer of entities to render. entity layers can be specified by adding PBCameraLayers to target entities.
    // defaults to 0
    optional uint32 layer = 3;

    // default black
    optional decentraland.common.Color4 clear_color = 6;
    // default infinity
    optional float far_plane = 7;

    oneof mode {
        Perspective perspective = 8;
        Orthographic orthographic = 9;
        /* Portal portal = 10; */ 
    };

    // controls whether this camera acts as a receiver for audio on sources with matching `PBCameraLayers`.
    // range: 0 (off) - 1 (full volume)
    // default: 0
    optional float volume = 10;    
}

message Perspective {
    // vertical field of view in radians
    // defaults to pi/4 = 45 degrees
    optional float field_of_view = 1;
}

message Orthographic {
    // vertical extent of the visible range in meters
    // defaults to 4m
    optional float vertical_range = 1;
}

Rendering MUST be active while the avatar is within the scene. It MAY be active at other times, depending on explorer implementation.

Limits

Explorers SHOULD limit the number of TextureCameras which can be active, to avoid bad performance or crashes in case of scene authors creating cameras in a loop.

Implementation Notes

We limit the minimum required number of layers to 3 so that engines (such as unity) with limited layers, and in which objects are constrained to a single layer, can support the layers fully. We expect unity to designate a layer for 0, a layer for 1, a layer for 2, and layers for each combination of 0+1, 0+2, 1+2, 0+1+2. This allows objects to exist on multiple layers using only 2^n-1 unity layers.

Following unity's native layer definition (1 layer per object, cameras target multiple layers) was considered, but we find that many scenarios would require duplicating the entire scene, which is a very high overhead. For example a top-down map view which removes the roof of the building the avatar is in, would require duplicating the entire scene (except the roof) to a second layer (it could also be accomplished by allowing scenes to set multiple layers on the primary camera, but this has introduces complexity for viewing other scenes from within a scene which modifies the primary camera).

Additional supporting changes

License

Copyright and related rights waived via CC0-1.0. DRAFT Draft