Skip to content

Configuration

RemotePhotoSystem consists of four types of components:

ComponentCapability
RemotePhotoManagerManages the gallery, play mode, loading mode, preload cache, and managed groups
RemotePhotoGroupManages a group of frames and provides photo-changing events
RemotePhotoFrameDisplays remote images on a mesh material
RemotePhotoButtonForwards button operations to Group events

RemotePhotoSystem moves photos from the world file to remote URLs, but at runtime you still pay download, Texture, VRAM, material instance, draw call, and sync costs.

Use only one RemotePhotoManager in one scene. Multiple Managers have not been tested and may cause fatal bugs.

RemotePhotoManager centrally manages the gallery, playback, loading, Group order, and Shader checks.

FeatureDescription
LanguageSwitches this project’s Inspector text language. It does not affect in-game display
Gallery Config JSONReceives the gallery JSON exported by WebTool
Import JSON Into GalleryBakes the JSON into runtime URL arrays
Play ModeControls how URLs are selected when a Group is triggered
Loading ModeControls whether images enter the preload cache
Load Once On StartAutomatically triggers all managed Groups once after the world starts
Managed GroupsThe list of Groups managed by the Manager

Unity only records url and orientation to save memory. id, tags, note, and metadata in the JSON are read by WebTool to make gallery management easier.

Creating a larger gallery mainly increases the baked JSON arrays, Unity serialized data, and maintenance cost.

Images currently displayed and images cached by Preload have the largest performance cost.

WebTool capabilityDescription
Import URLsAccepts a small amount of manual input or large batches of URLs
Tags / NotesOnly used for gallery maintenance and not included in runtime arrays
Probe image sizesCan help determine Landscape / Portrait
Export Unity JSONUsed by the Manager’s Gallery Config JSON

Detailed WebTool documentation can be viewed here.

Image URLs must meet VRChat image loading requirements. See the official documentation for related limits:
https://creators.vrchat.com/worlds/udon/image-loading/

Personal image hosting content can be viewed in detail here.

Each Frame only takes images from the gallery matching its orientation:

Frame orientationGallery used
LandscapeLandscape gallery
PortraitPortrait gallery

Do not rely on rotating Landscape images to solve Portrait frames. Portrait images in the gallery should be marked as Portrait, and the Frame should also be set to Portrait.

When converting a Landscape frame into a Portrait frame, rotate the frame object 90° counterclockwise to get the correct image orientation.

If the gallery for an orientation is empty, Frames of that orientation have no available images.

Play Mode decides how URLs are selected when a Group is triggered.

ModeCapabilityAvailable event
RandomRandomly assigns images to Frames in the Group, avoiding repeats in the same orientation within one batch as much as possibleTriggerRandom()
SequenceForward/ SequenceReversePages through the gallery in forward/reverse orderTriggerPrevious() / TriggerNext()

Random mode and sequence mode are mutually exclusive.

In sequence mode, Landscape Frames only advance the Landscape queue, and Portrait Frames only advance the Portrait queue. One Group can mix Landscape and Portrait Frames.

Loading Mode controls the image download path.

ModeCapability
NonPreloadDownloads directly when images are needed, without maintaining a preload cache
PreloadDownloads some images into cache in advance. Cache hits can display faster

Preload trades memory, VRAM, and download queue pressure for display speed. The larger the cache, the higher the runtime resource usage.

NonPreload does not maintain cache. Only the number and resolution of displayed images affect performance

Rough Texture cost:

ResolutionApproximate RGBA texture cost
1024 x 1024About 4 MB
2048 x 2048About 16 MB
4096 x 4096About 64 MB

Oversized images combined with a large cache will quickly increase memory and VRAM pressure. The risk is higher on Android.

When Load Once On Start is enabled, all managed Groups are triggered once in Managed Groups order after Load Once Delay Seconds.

Retry Attempts and Retry Delay Seconds are global retry settings for failed downloads.

RemotePhotoGroup defines a frame area that can be refreshed independently.

FeatureDescription
Permission ModeControls who can trigger this Group
Trigger Cooldown SecondsLimits the shortest interval between successful triggers
FramesThe list of Frames controlled by this Group

Groups and Frames both request URLs and load images according to the order of their parent management lists.

If clicking one button refreshes frames that players cannot see from their current position, that is wasteful. After all, VRChat only allows us to load at most one image every 5 seconds. Dividing Groups by area is a good choice.

Repeated multiplayer triggers increase sync state and download queue pressure. Cooldown is used to limit successful trigger frequency. 5 seconds is a good choice.

RemotePhotoFrame is responsible for writing remote images into the current object’s MeshRenderer material.

FeatureDescription
OrientationDecides whether the Frame uses the Landscape or Portrait gallery
Material SlotSpecifies which material slot to write to
Texture PropertySpecifies which texture property to write to. The project shader usually keeps _MainTex
Default TextureDefault texture displayed on start
Use Fallback TextureControls whether Fallback is displayed when loading fails
Fallback TextureFallback texture displayed when loading fails
Background ColorFill color for Contain padding and Box side faces

When Use Fallback Texture is off, loading failure does not overwrite the current display; when it is on, loading failure displays Fallback Texture.

Photo Fit ModeEffect
CropCrops the image to the frame ratio so the image fills the frame
ContainKeeps the full image, and uses Background Color for empty areas
StretchDirectly stretches the image to the frame ratio
TileRepeats the image as tiles
Projection ModeEffect
Mesh UVUses the model’s own UVs to display the image
BoxTreats the shortest side as thickness, projects the image onto front/back faces, and uses Background Color on side faces

Horizontal Flip only affects Box, and is used to horizontally flip the Box projection result.

FeatureDescription
ManualUses Manual Aspect Ratio as a fixed width-height ratio
AutoAutomatically calculates the width-height ratio from the current mesh
Reference BoxUses a custom Reference Box to calculate the width-height ratio
Photo Rotation OffsetAdds rotation compensation to the final image display result, supporting both Mesh UV and Box

The photo display material must use the project shader:

ShaderPurpose
RemotePhotoSystem/Photo Frame Display UnlitDoes not calculate scene lighting, displays like a screen, and is performance-friendly
RemotePhotoSystem/Photo Frame Display LitCalculates scene lighting, blends better into the environment, and has more draw calls

Each RemotePhotoFrame needs an independent material instance at runtime to display a different image.

Increasing the number of frames increases draw calls

Manager scans frames covered by Managed Groups -> Frames. If a frame material does not use the project shader, the Inspector shows a warning.

The warning area provides two quick setup buttons These two buttons only process Frame materials connected to the current Manager through Managed Groups.

RemotePhotoButton maps Button Action to the target Group event.

Button ActionCalled eventAvailable play mode
RandomTriggerRandom()Random
PreviousTriggerPrevious()SequenceForward / SequenceReverse
NextTriggerNext()SequenceForward / SequenceReverse

External VRC button, switch, menu, and trigger assets can directly connect to public events on RemotePhotoGroup:

OperationEvent
Random photo changeTriggerRandom()
Go to previous pageTriggerPrevious()
Go to next pageTriggerNext()