This document is about: FUSION 2
SWITCH TO

Line Drawing

Fusion XR prototyping addons

This addon demonstrate how to use the DataSyncHelpers add-on to create 3D drawings, that later joiner can receive too.

Feature

This add-on creates 3D drawing, made of several line renderers.

Once finished, in the demo scene those drawings can be grabbed and moved.

Those drawing should be edited by only one user. For multi-user editing, please see the TextureDrawing addon add-on, which handle this kind of use cases.

The add-on provide a basic implentation, with no supposition on how a drawer will be used (grabbed, automatic drawing, ...), as well as basic drawers examples relying on grabbing (for actual "pens").

Principle

Drawing points synchronisation

A drawer (NetworkLineDrawer) will spawn a drawing networked object, with a NetworkLineDrawing component on it.

The drawer will then request the drawing to store additional lines and points. Those line and points are shared over the network with a ring buffer structure, allowing to store several points that should be transmitted at the same time. This data structure also allows late joiners to receive the whole drawing through Fusion streaming API.

For details on this lossless ring buffer logic, please see the RingBufferLossLessSyncBehaviour class in the DataSyncHelpers add-on

Drawing interpolation

The NetworkLineDrawing will then ask a LineDrawing to actually creates the line renderers and fill them.

The NetworkLineDrawing applies the following drawing logic during Render.

For the state authority (the drawing user), all added drawing points are drawn immediatly

For remote users, we determine the amount of points to display by interpolating the point count between the point counts in the 2 (from and to) ticks around the current interpolation time.

This is done with the NetworkBehaviour's TryGetSnapshotsBuffers method (See Network Buffer documentation), which provides the from and to data, as well as the current alpha progression between the 2.

C#

if (lastDrawnPoint < (drawingPoints.Count - 1))
{
    if (Object.HasStateAuthority || drawPointsOnProxiesAsSoonAsAvailable) {
        DrawAllPoints();
    } 
    else
    {
        bool proxyDrawingAuthorized = lossRanges.Count == 0;
        // Find the from and to state of the drawing data (byte array),
        //  find the entry count in each state (from drawing point count, to drawing point count),
        //  and interpolate the current max point to draw with the interpolation alpha (between from and to point count)
        if (proxyDrawingAuthorized && TryGetSnapshotsBuffers(out var fromBuffer, out var toBuffer, out var alpha))
        {
            var reader = GetArrayReader<byte>(nameof(Data));
            var toData = reader.Read(toBuffer);
            var fromData = reader.Read(fromBuffer);
            RingBuffer.PositionInfo fromPositionInfo = RingBuffer.PositionInfo.ExtractPositionInfo(fromData);
            var fromGlobalByteIndex = fromPositionInfo.totalData - 1;
            RingBuffer.PositionInfo toPositionInfo = RingBuffer.PositionInfo.ExtractPositionInfo(toData);
            var toGlobalByteIndex = toPositionInfo.totalData - 1;
            var fromGlobalIndex = RingBuffer.EntryIndexAtDataSourcePosition<LineDrawingPoint>(fromGlobalByteIndex);
            var toGlobalIndex = RingBuffer.EntryIndexAtDataSourcePosition<LineDrawingPoint>(toGlobalByteIndex);

            var currentIndex = (int)Mathf.Lerp(fromGlobalIndex, toGlobalIndex, alpha);
            DrawPointsUpTo(currentIndex);
        }
    }
}

Finished handler

When a drawing is finished, the IsFinished networked var synchronise it to all users.

To be able to display a grabbing handle when the drawing is finished, a NetworkLineDrawing can have a finishedHandler gameObject, which is activated only when the drawing is finished.

If this gameObject has a component implementing the INetworkLineDrawingListener, it is also possible to trigger the DrawingFinished callback, for instance to adapt the handle position and rotation to the actual finished drawing.

NetworkLineDrawer API

A NetworkLineDrawer won't draw anything by itself, but its methods can be called by other components or sublcasses to createe the drawing.

  • StartDrawing: spawns thrpugh the network runner the drawingPrefab prefab, which has to contain a NetworkLineDrawing component
  • StopDrawing: stop the current drawing
  • StartLine(Color color): start a line of the provided color. Cannot be changed for this line
  • AddPoint([Color color], float pressure): add a point (changing the color to a new one creates a new line)
  • StopLine(): forces the next added point to start a new line

LineDrawingPoint data structure

A drawing point (LineDrawingPoint) contains 2 information: its local position relatively to the drawing origin, and a pressure level (to customize the width of the line at this position).

The data structure is also used for a special case: to describe a new line start. A NEW_LINE_PRESSURE(aka -1) pressure value describes a new line. In this case, the position Vector3 contains the RGB value of the starting line.

Dependencies

Demo

Demo scenes can be found in the Assets\Photon\FusionAddons\LineDrawing\Demo\ folder.

Please note that to test the DemoLineDrawingMeta demo scene, the Meta packages must be installed in the project.
Alternatively, you can use the Meta XR integration project (which includes the Meta packages) to test it directly.

Download

This addon latest version is included into the free XR addon project

Supported topologies

  • shared mode

Changelog

  • Version 2.0.5: Compatibility with DataSyncHelper 2.0.8 (add ByteArraySize attriute usage)
  • Version 2.0.4: Fix to provide haptic feedback during 3D draw
  • Version 2.0.3: Allow to change inputs for NetworkGrabbableLineDrawer
  • Version 2.0.2: Add check to only support MetaGrabbableLineDrawer if the Meta interaction SDK is installed
  • Version 2.0.1: Add drawing interpolation
  • Version 2.0.0: First release
Back to top