Presentation System
A turn-key solution for Virtual Conferences
UdonToolkit's Presentation system provides a fully-featured presentation solutions for creating VR Talks, Conferences, or just showing some slides to someone.
The system was originally built for the Prefabs TLX World Developer conference. You can see it in action in one of the many talks.

Features

    A solution to display your presentations with different slide durations, animations and videos
    Slide controls and counters
    Time remaining indicator
    Voice override for the speaker w/ support for extra override zones, e.g., for Q&A sessions or multiple speakers
    Material swap/object toggles for talk star/end
    Full late-joiner support
    Camera system for showing the speaker
    Stream system for capturing the presentation with talk info and speaker camera overlays
    Personal screen pickup for people to take a closer look
    Laser pointer for the speaker
    Callbacks for all major system events for easier extensibility with your own logic

Requirements

    TextMeshPro (from Package Manager)
    Cinemachine (from Package Manager)
    UdonSharp v0.19.2 or later
    VRChat SDK 2021.01.28.19.07 or later

Setup

    Drag & Drop the Presentation System prefab from UdonToolkit/Systems/Presentation System
    Make sure its in a 0,0,0 spot of the world, its important for some of the tracking objects
    Right click the prefab in the hierarchy and select "Unpack Prefab Completely (Udon does not work well with prefabs)
    Expand the Scene Objects in the hierarchy and move the following objects where you need them
      Screen: the presentation screen. Will display the current slide when the presentation is active
      Presentation UI: the speaker's and host's user interface, place it where your speakers will be talking from
      Laser Pointer: a simple laser pointer pickup to help with explaining the slides content, put near the Presentation UI for ease of use
      Presentation Audio Source: this source will play the presentation audio if it has any. It is a 3D source by default, and is best placed above and in front of where your audience will be sitting. You can make it 2D if you want
      Streamer Spot: a special box where the stream capture user will be teleported when pulling up the stream overlay. Best placed below the stage, slightly behind where the speaker is standing. More on that in the Setting Up Capture section
      CM Speaker Cam: a Cinemachine camera object that captures the speaker. Place somewhere in front of where the speaker will be standing. It will automatically track their head
    Build a test version
    Click Take Control on the UI and try starting a presentation!

UI Controls

    Take Control: takes ownership of the presentation system, shows the UI and removes any currently active voice boosts
    < and >: switch between the presentations in the presentations list, does not load the presentation unless Select is pressed
    Select: loads the selected presentation
    Start Talk: starts the presentation and boosts the speakers's voice (see below for voice settings)
    Stop: stops the presentation and removes the voice boost
    Next Slide: switches to the next slide
    Prev Slide: switches to the previous slide
    Play Video: unpauses an animated or video slide (one that has Auto checked, see below)
    Pause: pauses an animated or video slide
    Height Adjust + and -: moves the UI up and down for ease of use

Personal Screen Controls

    Desktop
      Press l to spawn a personal screen in front of you
    VR
      Press both triggers to spawn a personal screen pick up
This screen contains the presentation slides, the view of the speaker and the presentation info. This is helpful for getting a better look at the slides with small text or when generally being far away from the presentation

Stream Controls

Press k to pull up the stream and be teleported to the configured stream spot position. This will override your view with a special overlay that captures the current speaker and the slides.
Before using Stream Overlay - you need to configure the list of users who are allowed to open it up in the Presentation Stream Controller

Configuration

Creating Presentation Videos

Before adding presentations, we need to prepare them so they can be dynamically loaded in VRChat.
Most of the presentation software allows you to export a presentation as a video file (like an .mp4 video), exceptions are Web-Based solutions, like Google Slides, but you can still export them as PowerPoint presentations and use it to generate a video.
Presentation videos work best when they:
    Are exported with a fixed slide time of 3 seconds
    Have maximum of one video per slide
    Only have one animation sequence per slide
      e.g., if you have a slide where you want to animate things piece by piece - split them into different. Otherwise - they will all be played in a sequence without pauses, which might be undesirable
When you have your presentation files - upload them to YouTube or Vimeo and set them to be accessible via a link. If you are going to use Vimeo - please use their direct links to avoid any issues

Adding Presentations

    Expand the hierarchy of the Presentation Player object
    Click on the provided example presentation to see its Udon Behaviour
    The core of the presentation object consists of the 5 main elements
      1.
      Talk Url: the url of the video file with the presentation, YouTube or Vimeo direct link works best
      2.
      Talk Title: the title of the presentation that will be used when selecting a talk, and also displayed for the stream capture
      3.
      Talk Author: the name of the speaker, will also be shown on the stream capture
      4.
      Talk Length: this is only displayed to the speaker to help manage time
      5.
      Slides: a list of slide durations that allow the system to switch between slides
So, to add your own presentations - you need to
    Fill out the fields
    Expand the Configuration Wizard dropdown
    Set the Slide Count to the amount of slides in your presentation
    Set the Slide Duration to the time per slide you set when exporting the video
    Click Configure Talk
    Duplicate the object and repeat for each presentation
When you're done creating individual presentation objects - do the following
    Click on the Presentation Player
    Click Populate Talks button
    This should fill the Talks List with all of your talk objects (they must be parented to the Presentation Player)
    You can expand the Talks list by clicking on the dropdown to see all of your talks. You can move them around to change their order in the presentation UI
If you do not have any videos or animations - you're done! You should be able to make a test build and try out your presentations in game!
If you DO have animations - look below

If you have videos or animations on your slides

    1.
    Expand the slides dropdown on the individual presentation and check Auto checkbox near all slides that have animations or videos.
    2.
    Edit the Slide Durations for those slides as follows:
    For videos
      PowerPoint will export slides with videos exactly the matching the length of the videos, so just set those slide durations to the lengths of the included videos
    For animations
      This one is a bit more manual. Open the video you exported and see how much time the slide takes with all the animations included. Most time 3 seconds will be just enough. Otherwise - set the Slide Duration of that slide to the appropriate amount

Customizing the Screen

The Presentation System allows you perform a couple of actions when the presentation starts and ends. This is also where you can adjust the default placeholder material for the screen
Presentation Screen Controller allows you to swap materials on your screen mesh (or any other mesh) when the talk starts and ends
If you don't want to swap any materials - uncheck the Swap Materials option.
You can configure Presentation Placeholder material however you like, or you can swap it to a different material entirely: just drag the new material onto your screen and into the Default Mats column for the Screen mesh in the list - and you're done!
You can also toggle some objects on and off when the presentation Starts or Ends. For example, you can disable your screen object, and drop it into the OnTalkStart and OnTalkEnd lists to be enabled and disabled respectively. This will make it so the screen with the slides is only visible when the presentation is going. That would look something like this
If you do not want any objects to toggle - you can uncheck Toggle Objects, note that it will also stop the Speaker Camera from being turned on when the presentation starts starts.

Adjusting Voice Settings

By default the Presentation System will boost the voice range of the speaker up to 250 units of distance. It will only boost the person who is currently in control of the presentation UI and clicked the Start button.
Most of the configuration is meant to be done by simply sliding the Range Boost slider left and right. You can also use the Gain Tweak parameter to directly affect the volume boost without affecting range, but that can make the speaker too loud when up close, so be careful with it.
You can restrict the voice boost only to a set of particular players by clicking Restrict Access button and adding the player names to the Allowed Users list.
Another way of boosting someone's voice is by using Presentation Voice Zones, which will boost the volume of anyone who enters its trigger collider. One zone is provided as an example inside Scene Objects. It is disabled by default and will not affect anything unless enabled. You also need to check the Use Zones checkbox on the Presentation Voice Controller for zones to work.
A good use case for zones might be a Q&A spot where people can come up to and ask their questions to the speaker. That way everyone in the room can hear them

Stream and Video Capture

A big part of creating a presentation is providing a good recording / stream for the people who cannot attend the event personally. UdonToolkit's presentaiton system is fully outfitted to handle that with a Stream/Capture overlay system
The system works as follows: when a users presses the stream overlay key, provided they are in the whitelist, they will be teleported to a special streamer spot and get their desktop view overtaken by a special stream overlay. They can press the hotkey again to exit that view.
Default hotkey: k

Configuration

    Move the Streamer Spot object to be positioned below and behind the speaker in such a way that the Streamer Spot Spawn is orientated towards the speaker to provide the best audio capture experience
    Put the Presentation Stream Controller somewhere far from your main world area, by default it is put all the way at x: 1000 y: 1000 to not interfere with the main location
    Inside of the Presentation Stream Controller configure the following parameters
      Set the Reset Position to your world spawn point, the user will be teleported there when exiting the stream view
      Set the Engage Key to whatever you like
      Populated the Allowed Users list with the usernames of people who should be able to enable stream overlay, or uncheck Restrict Access to allow everyone to do that (not recommended)
    Inside of the Presentation Stream Controller - find the Stream object and customize the stream overlay UI to your liking
For the best viewing experience - record the video with the audio capture set to mono, as spatialization sounds very odd when re-watching the recordings

Full Reference

The Configuration guide above includes the core information that should let you configure everything and get started with the presentation system. But if you want to extend it or learn about every single exposed parameter, here's a full reference

Presentation Player

The top-level behaviour that controls the general flow and sends events to everything else

Parameters

    Talks: a list of TLXTalk objects that contain the individual talks data
    Main Player: the PresentationVideoPlayer object that will be active for everyone in the room, responsible for loading and displaying the slides
    Lookahead Player: the PresentationVideoPlayer object that is only active for the current speaker and is taking care of the Next Slide preview
    Restrict Access: specifies whether only particular users will be able to control the Presentation Player
    Allowed Users: Contains the list of users that can take control of the Presentation Player. Only visible when Restrict Access is checked, does not have any effect otherwise
    Callbacks: a set of callbacks that will be called when a particular event is handled by a Presentation Player
      OnTakenControl: will fire only for the user that just took control of the Presentation Player, you can set the Target to All to fire the event on all the clients
      OnLostControl: will fire for every user in the instance when someone takes control of the Presentation Player (does not fire on the new owner of the Presentation Player)
      OnTalkStart: will fire for every user in the instance when the presentation starts
      OnTalkEnd: will fire for every user in the instance when the presentation ends
      OnNextSlide: will fire for the current owner of the Presentation Player when they click Next Slide
      OnPrevSlide: will fire for the current owner of the Presentation Player when they click Prev Slide
Callbacks allow you to specify a network target: Local, Owner or All. If the event can be seen by everyone (based on the description above) you DO NOT want to use All, as that will cause the event to oversync and fire an extra time for each single user in the instance.
So in this case you only want to use All on events that only fire for the owner of the Presentation Player. Others should only use Owner or Local

Events

    TakeControl: takes ownership of the Presentation Player, fires OnTakenControl for the initiator and OnLostControl for everyone else
    StartTalk: starts the currently selected presentation, fires OnTalkStart for everyone
    StopTalk: stops the currently active presentation, fires OnTalkEnd for everyone
    PrevSlide: goes back a slide, fires OnPrevSlide for the current owner
    NextSlide: goes forward a slide, fires OnNextSlide for the current owner
    NextTalk: selects next presentation from the Talks list and loads it up
    PrevTalk: selects previous presentation from the Talks list and loads it up
    PauseTalkVideo: pauses an autoplaying presentation slide for everyone
    PlayTalkVideo: resumes the autoplaying presentation slide for everyone
    SelectTalk(int newIndex): selects the presentation with the specified index and loads it up

Presentation Talk

The presentation description class, contains the information about a single presentation and the list of slides

Parameters

    Talk Url: the url of the presentation video file, you generally want this to point to a YouTube or Vimeo url
    Talk Title: the title of the presentation, will be used in the talk selector UI and the stream capture overlay
    Talk Author: the name of the speaker, will be used in the stream capture overlay
    Talk Length: the length of the presentation in minutes, will only be used for a timer that is shown to the speaker to help them manage the presentation time
    Slides: the list of the presentation slides, internally consists of two arrays
      Slide Duration: the length of a specific slide, if you have a video or an animation within a slide - you will most likely need to adjust this number
      Auto: whether the slide should be autoplayed, this should be checked for all the slides that contain videos or animations
When using Vimeo for video hosting - it is recommended to use direct file links in Talk Url. You can also use your own hosting for the video files and use the direct links inside of the Talk URL. Be weary that event attendees will need to click Allow Untrusted URLs in VRChat settings.

Events

Presentation Talk is not built to handle incoming events from anything but the Presentation Player, these are provided solely for reference
    Prepare(int slideIndex): loads up the presentation video in both main and lookahead players and seeks them to the provided slide index
    Play: plays the first slide of the presentation
    SeekToSlide(int slideIndex): seeks main and lookahead players to the provided slide inde
    Stop: stops both main and lookahead players
    NextSlide: goes forward a slide
    PrevSlide: goes back a slide
    PlayContinuous: resumes autoplaying slide playback
    PauseContinuous: pauses autoplaying slide playback

Presentation UI Controller

Drives the Presentation UI functionality

Parameters

    Presentation Player: the reference to the main Presentation Player behaviour
    Presentation UI: the Presentation UI root Canvas game object
    Owner Objects: these objects will be enabled for the new owner when they Take Control of the Presentation Player
    Public Objects: these objects will shown to everyone but the owner of the Presentation Player
    Owner Collider: the collider that covers the whole of the Presentation UI canvas to provide proper UI detection
    Public Collider: the collider that covers only the Take Control button to minimize the player's laser showing up randomly when they're watching the talk
    Talk Selector Title: the TextMeshPro component which displays the presentation title in the Presentation Selector on top of the Presentaiton UI
    Slide Index Text: the TextMeshPro component which displays the current slide index to the speaker
    Time Left Text: the TextMeshPro component which displays the remaining presentation time to the speaker

Events

    SelectorPrev: selects the previous presentation in the selector and displays its title to the current owner
    SelectorNext: selects the next presentation in the selector and displays its title to the current owner
    SelectorConfirm: confirms the presentation selection and tells Presentation Player to load it
    HandleTakeControl: enables the Owner Objects and disables the Public Objects, meant to be used in the OnTakenControl callback of the Presentation Player
    HandleLoseControl: disables the Owner Objects and enables the Public Objects, meant to be used in the OnLostControl callback of the Presentation Player
    LowerUi: lowers the Presentaiton UI panel by 0.05, only allows to go down by 2 units maximum
    RaiseUi: raises the Presentation UI panel by 0.05, only allows to go up by 2 units maximum
    HandleTalkStart: sets the slide index in the Presentation UI and starts the presentation timer, meant to be used in the OnTalkStart callback of the Presentation Player
    HandleTalkEnd: resets the slide index and the presentation timer in the Presentation UI, meant to be used in the OnTalkEnd callback of the Presentation Player
    HandleNextSlide: sets the slide index in the Presentation UI to the next slide, meant to be used in the OnNextSlide callback of the Presentation Player
    HandlePrevSlide: sets the slide index in the Presentation UI to the previous slide, meant to be used in the OnPrevSlide callback of the Presentation Player
As you can see, events that start with Handle usually meant to be used inside of a Presentation Player callback, and that is the general naming scheme I'm trying to establish

Presentation Screen Controller

Reacts to the Presentation Start/End events to swap screen materials or toggle game objects

Parameters

    Swap Materials: specifies whether to swap materials inside Material Swap Targets
    Material Swap Targets: defines a list of meshes which will have their materials swapped when the Presentation Starts and Ends
      Meshes: meshes to swap materials on
      Default Mats: materials to apply when the presentation is stopped
      Active Mats: materials to apply when the presentation starts
    Toggle Objects: specifies whether to toggle game objects on presentation start / end
    OnTalkStart: list of objects to be affected when the presentation starts
    OnTalkEnd: list of objects to be affected when the presentation ends

Events

    HandleTalkStart: performs the selected actions in the Behaviour parameters, meant to be used in the OnTalkStart callback of the Presentation Player
    HandleTalkEnd: performs the selected actions in the Behaviour parameters, meant to be used in the OnTalkEnd callback of the Presentation Player

Presentation Voice Controller

Applies voice adjustments to the players

Parameters

    Restrict Access: specifies whether only particular users will be able to receive a voice boost
    Allowed Users: contains the list of users that can receive the voice boost. Only visible when Restrict Access is checked, does not have any effect otherwise
    Range Boost: sets the amount of extra range added to the player's voice
    Gain Tweak: sets the amount of gain adjustment for the player's voice. Be careful not to overuse this setting, it can make players really loud up close
    Use Zones: allows usage of the Presentation Voice Zone behaviours. They will boost the volume of anyone who enters their trigger area
    Adjust On Presentation Start: adjusts the voice of the speaker when they start the presentation, and removes the voice boost when they stop or lose ownership of the Presentation Player

Events

    HandleTalkStart: boosts the current speaker's voice if the Adjust On Presentation Start is checked, meant to be used in the OnTalkStart callback of the Presentation Player
    HandleTalkEnd: removes the current's speaker's voice boost if the Adjust On Presentation Start is checked, meant to be used in the OnTalkEnd callback of the Presentation Player
    NormalizeVolume: same as HandleTalkEnd, but is meant to be used in the OnTakenControl callback of the Presentation Player
    EnterZone(VRCPlayerApi player): boosts the voice of the provided player if Use Zones is checked
    ExitZone(VRCPlayerApi player): removes the voice boost of the provided player if Use Zones is checked

Presentation voice Zone

Detects players entering / exiting the zone and calls voice adjustment events on the PresentationVoiceController
This behaviour requires a trigger collider, and is recommended to be put on a MirrorReflection layer. It will warn you about those things, so you don't miss it

Parameters

    Presentation Voice Controller: a reference to the PresentationVoiceController in your scene

Presentation Stream Controller

Provides functionality for capturing the presentation

Parameters

    Restrict Access: specifies whether only particular users will be able to toggle the stream overlay
    Allowed Users: contains the list of users that can open the stream overlay. Only visible when Restrict Access is checked, does not have any effect otherwise
    Engage Key: defines the hotkey for opening the stream overlay
    Stream Objects: these objects will be toggled when users presses the Engage Key
    Stream Camera: the camera that captures the stream UI
    Stream Animator: the stream UI animator which controls Idle/Active states
    Stream Spot: the position to which the capture player will be teleported to provide best audio capture position
    Reset Position: the position to which the capture player will be teleported when they click the Engage Key again - closing the stream overlay
    Talk Title: the UI text element with the presentation title on the stream overlay
    Talk Author: the UI text element with the presentation author on the stream overlay

Events

    HandleTalkStart: sets the presentation title and author, and sets the stream UI animator params, meant to be used in the OnTalkStart callback of the Presentation Player
    HandleTalkEnd: sets the stream UI animator params, meant to be used in the OnTalkEnd callback of the Presentation Player
    ToggleStreamObjects: toggles the objects specified in the Stream Objects list and teleports the local player to the Stream Spot

Presentation Personal Screen

Controls the spawnable screen attendees can use to get a better view of the presentation slides and the speaker

Parameters

    Screen Objects: a list of objects to be enabled or disabled when user executes the personal screen hotkey / toggle
    Main Screen: the personal screen object which will be moved to the Desktop / VR Spawn Ref defined below
    Stream Controller: the Presentation Stream Controller that ensures that the correct animator state is set (personal screen shares the same UI capture as the stream overlay)
    Screen Collider: the collider on the personal screen, it will get disabled if the user isn't in VR, as it is not a pickup unless the player is in VR
    Desktop Button: defines the desktop hotkey used to spawn the personal screen
    Desktop Spawn Ref: the position at which to spawn the personal screen on desktop. Should be attached to a player-tracked object somewhere in front of the player so they can easily see it
    VR Spawn Ref: the position at which to spawn the personal screen in VR. Should be attached to a player-tracker object somewhere in front of the player so they can easily pick it up

Laser Pointer

Provides a basic laser pointing functionality that will project a laser dot onto a surface

Parameters

    Laser Line: the liner renderer to be used for the laser line
    Laser Dot: the object to be placed on the surface of the hit object
    Active: whether the laser pointer is enabled (mostly used internally)
    Hit Layers: the list of layers to be considered for collision
The following components are purely internal and are not meant to be modified by the user

Presentation Video Player

Controls the VRCUnityVideoPlayer

Parameters

    V Player: the VRCUnityVideoPlayer to control
    Curr Url: the currently loaded video url

Events

    LoadAndSeek(float time): loads the video on the Curr Url, retries if fails or gets rate limited, then seeks the video to the specified time

Presentation Camera Target

Tracks the current speaker's position to serve as a camera target

Parameters

    Source: specifies which tracking source to use

Events

    TakeOwnership: takes ownership of the camera target, the owner will then be used as a tracking target
    HandleTalkStart: sets the target of the PersentationCameraTarget to the current owner and enables tracking, meant to used in the OnTalkStart callback of the Presentation Player
    HandleTalkEnd: stops the tracking, meant to be used in the OnTalkEnd callback of the Presentation Player
Last modified 7mo ago