Giter Club home page Giter Club logo

examples-image-loading's Introduction

VRChat Image Downloading Examples

This is a Unity Example Project that demonstrates some ways that remote images can be downloaded using Udon in VRChat Worlds.

Getting Started

Clone or Download this project and open it up in Unity 2019.4.31f1.

Gallery Example

image

Scene File: Assets/_Project/Gallery

This scene demonstrates a RemoteImageFrame which loads images from a web server at runtime.

TheFrame

image

TheFrame is a GameObject with a couple of important pieces:

  • SlideshowFrame UdonBehaviour to load the images and captions from a web server.
  • Mesh object to render the frame.
  • Picture mesh to render the downloaded textures.
  • UI world-space canvas to render the caption.

SlideshowFrame

This UdonBehaviour has all of the logic to download the images and captions from a web server.

image

It has these public variables:

  • Rgb Url - an array of all the VRCUrls for the images to download.
  • String Url - a single VRCUrl where the caption text can be downloaded.
  • Renderer - this renderer's sharedMaterial will have its texture set from the downloaded textures.
  • Field - this UI element's text property will be set from the downloaded caption for the matching texture.
  • Slide Duration Seconds - how long to show each image.

The basic logic flow of the script is this:

  • On Start, construct a VRCImageDownloader to reuse for downloading all the images. It's important to keep this around so the textures will persist. Download the string from the String Url.
    • If the String downloads successfully, split it up line-by-line into separate strings, and save those to a _captions array. If it doesn't download, log the error message.
  • Next, try to Load the next Image. Increment the _loadedIndex to keep track of our place, then call DownloadImage() on the downloader we saved earlier.
  • If the Image downloads successfully, save a reference to it and then load it up on the Renderer. If it fails, log the error message.
  • Call the function to Load the next Image again, delayed by SlideDurationSeconds. The _loadedIndex is incremented during each Load call, and starts over after reaching the last url in the array.
  • When each image is visited for the second+ time, it will be displayed from its saved Texture2D reference instead of loaded fresh, unless it failed to download the first time.

Known Issues

  • The first image doesn't have its caption loaded quickly enough, so it doesn't show until the first loop around.

Using GitHub to Host the Images and Captions

This repo publishes to GitHub Pages for free hosting of the images and captions. When the files in the "Web" directory are edited, the website is re-published. As long as the filenames stay the same (images are 1.jpg, 2.jpg, etc.) - the URLs in the world will point to the newly published files. Republishing happens automatically through an included GitHub Action.

examples-image-loading's People

Contributors

faxmashine avatar momo-the-monster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

examples-image-loading's Issues

Example is empty

There is no Exmple setup in the downloaded version on here!!!!

BUG: Negative server time and C# remainder results in negative index

The following line

_loadedIndex = (int)(Networking.GetServerTimeInMilliseconds() / 1000f / slideDurationSeconds) % imageUrls.Length;

Uses Networking.GetServerTimeInMilliseconds() as well as the remainder operator

This can create an edge case where _loadedIndex is a negative value, causing an out of bounds exception

  • Networking.GetServerTimeInMilliseconds() will return a signed integer (-2,147,483,648 to 2,147,483,647), however the photon call it depends on will return a value between 0 and 4,294,967.295, when the server timestamp is received, it has a chance of wrapping around to a negative number.
  • The remainder operator in C# is different than moduolo and has a tough time dealing with negative numbers, so something like -5 % 4 in C# will return -1, while -5 % 4 when using % as modulo should return 3

Attached is a stacktrace with some personal information removed and some extra logging I added when debugging

2023.03.18 18:56:21 Error      -  [UdonBehaviour] An exception occurred during Udon execution, this UdonBehaviour will be halted.
VRC.Udon.VM.UdonVMException: The VM encountered an error!
Exception Message:
  An exception occurred during EXTERN to 'SystemObjectArray.__Get__SystemInt32__SystemObject'.
      Parameter Addresses: 0x00000009, 0x00000006, 0x00000029
  
  Index was outside the bounds of the array.
----------------------
Program Counter was at: 668
----------------------
Stack Dump:
  0: 0x0000000A
  1: 0x0000000D
----------------------
Heap Dump:
  0x00000000: -7774693031578337865
  0x00000001: SlideshowFrame
  0x00000002: 4294967295
  0x00000003: VRC.SDKBase.VRCUrl[]
  0x00000004: Weather Displays Screens (UnityEngine.MeshRenderer)
  0x00000005: 15
  0x00000006: -4
  0x00000007: VRC.SDK3.Image.VRCImageDownloader
  0x00000008: Weather Displays Screens (VRC.Udon.UdonBehaviour)
  0x00000009: UnityEngine.Texture2D[]
  0x0000000A: 4294967295
  0x0000000B: Weather Displays Screens (VRC.Udon.UdonBehaviour)
  0x0000000C: 108
  0x0000000D: 152
  0x0000000E: Weather Displays Screens (VRC.Udon.UdonBehaviour)
  0x0000000F: LoadNextRecursive
  0x00000010: Update
  0x00000011: 1000
  0x00000012: Loading index {0}
  0x00000013: imageUrls.Length {0}
  0x00000014: _downloadedTextures.Length {0}
  0x00000015: null
  0x00000016: True
  0x00000017: VRC.SDK3.Image.VRCImageDownloader+ImageDownloader
  0x00000018: Image loaded: {0} bytes.
  0x00000019: null
  0x0000001A: Image not loaded: {0}: {1}.
  0x0000001B: 5
  0x0000001C: -878843116
  0x0000001D: -8.788431E+08
  0x0000001E: -878843.1
  0x0000001F: -58589.54
  0x00000020: -58589
  0x00000021: -58589.54296875
  0x00000022: -58589
  0x00000023: 5
  0x00000024: Loading index -4
  0x00000025: 5
  0x00000026: imageUrls.Length 5
  0x00000027: 5
  0x00000028: _downloadedTextures.Length 5
  0x00000029: null
  0x0000002A: null
  0x0000002B: null
  0x0000002C: False
  0x0000002D: Weather Screens LED (Instance) (UnityEngine.Material)
  0x0000002E: null
  0x0000002F: VRC.SDK3.Image.TextureInfo
  0x00000030: [removed]
  0x00000031: VRC.SDK3.Image.VRCImageDownloader+ImageDownloader
  0x00000032: 4194303
  0x00000033: Image loaded: 4194303 bytes.
  0x00000034:  (UnityEngine.Texture2D)
  0x00000035: Unknown
  0x00000036: null
  0x00000037: null
  0x00000038: null
  0x00000039: SystemArray.__get_Length__SystemInt32
  0x0000003A: UnityEngineTexture2DArray.__ctor__SystemInt32__UnityEngineTexture2DArray
  0x0000003B: VRCSDK3ImageVRCImageDownloader.__ctor____VRCSDK3ImageVRCImageDownloader
  0x0000003C: VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomEventDelayedSeconds__SystemString_SystemSingle_VRCUdonCommonEnumsEventTiming__SystemVoid
  0x0000003D: VRCSDKBaseNetworking.__GetServerTimeInMilliseconds__SystemInt32
  0x0000003E: SystemConvert.__ToSingle__SystemInt32__SystemSingle
  0x0000003F: SystemSingle.__op_Division__SystemSingle_SystemSingle__SystemSingle
  0x00000040: SystemConvert.__ToDouble__SystemSingle__SystemDouble
  0x00000041: SystemMath.__Truncate__SystemDouble__SystemDouble
  0x00000042: SystemConvert.__ToInt32__SystemDouble__SystemInt32
  0x00000043: SystemInt32.__op_Remainder__SystemInt32_SystemInt32__SystemInt32
  0x00000044: SystemString.__Format__SystemString_SystemObject__SystemString
  0x00000045: UnityEngineDebug.__Log__SystemObject__SystemVoid
  0x00000046: SystemObjectArray.__Get__SystemInt32__SystemObject
  0x00000047: UnityEngineObject.__op_Inequality__UnityEngineObject_UnityEngineObject__SystemBoolean
  0x00000048: UnityEngineRenderer.__get_sharedMaterial__UnityEngineMaterial
  0x00000049: UnityEngineMaterial.__set_mainTexture__UnityEngineTexture__SystemVoid
  0x0000004A: VRCSDK3ImageTextureInfo.__ctor____VRCSDK3ImageTextureInfo
  0x0000004B: VRCSDK3ImageTextureInfo.__set_GenerateMipMaps__SystemBoolean
  0x0000004C: VRCSDKBaseVRCUrlArray.__Get__SystemInt32__VRCSDKBaseVRCUrl
  0x0000004D: UnityEngineRenderer.__get_material__UnityEngineMaterial
  0x0000004E: VRCSDK3ImageVRCImageDownloader.__DownloadImage__VRCSDKBaseVRCUrl_UnityEngineMaterial_VRCUdonCommonInterfacesIUdonEventReceiver_VRCSDK3ImageTextureInfo__VRCSDK3ImageIVRCImageDownload
  0x0000004F: VRCSDK3ImageIVRCImageDownload.__get_SizeInMemoryBytes__SystemInt32
  0x00000050: VRCSDK3ImageIVRCImageDownload.__get_Result__UnityEngineTexture2D
  0x00000051: SystemObjectArray.__Set__SystemInt32_SystemObject__SystemVoid
  0x00000052: VRCSDK3ImageIVRCImageDownload.__get_Error__VRCSDK3ImageVRCImageDownloadError
  0x00000053: SystemObject.__ToString__SystemString
  0x00000054: VRCSDK3ImageIVRCImageDownload.__get_ErrorMessage__SystemString
  0x00000055: SystemString.__Format__SystemString_SystemObject_SystemObject__SystemString
  0x00000056: VRCSDK3ImageVRCImageDownloader.__Dispose__SystemVoid
----------------------
Inner Exception:
 ---> VRC.Udon.VM.UdonVMException: An exception occurred during EXTERN to 'SystemObjectArray.__Get__SystemInt32__SystemObject'.
    Parameter Addresses: 0x00000009, 0x00000006, 0x00000029
 ---> System.IndexOutOfRangeException: Index was outside the bounds of the array.
  at VRC.Udon.Wrapper.Modules.ExternSystemObjectArray.__Get__SystemInt32__SystemObject (VRC.Udon.Common.Interfaces.IUdonHeap heap, System.Span`1[T] parameterAddresses) [0x00000] in <00000000000000000000000000000000>:0 
  at ÏÍÌÌÎÌÏÎÎÏÍÏÏÏÍÏÌÍÏÎÍÍÍ.Invoke (System.Object ÌÍÏÌÏÍÍÌÌÌÏÎÍÎÏÍÏÍÌÍÏÏÌ, ÏÌÍÍÎÏÌÎÏÍÌÌÍÏÍÎÍÍÌÏÎÍÏ ÌÍÏÌÏÏÏÎÌÎÏÌÌÏÌÌÏÏÍÍÎÌÎ) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.VM.UdonVM.Interpret () [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.UInt32 entryPoint) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.String eventName) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.ClientBindings.UdonEventScheduler.RunScheduledEvents (VRC.Udon.Common.Enums.EventTiming eventTiming) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonManager.Update () [0x00000] in <00000000000000000000000000000000>:0 
   --- End of inner exception stack trace ---
  at VRC.Udon.VM.UdonVM.Interpret () [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.UInt32 entryPoint) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.String eventName) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.ClientBindings.UdonEventScheduler.RunScheduledEvents (VRC.Udon.Common.Enums.EventTiming eventTiming) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonManager.Update () [0x00000] in <00000000000000000000000000000000>:0 
   --- End of inner exception stack trace ---
  at VRC.Udon.VM.UdonVM.Interpret () [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.UInt32 entryPoint) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonBehaviour.RunProgram (System.String eventName) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.ClientBindings.UdonEventScheduler.RunScheduledEvents (VRC.Udon.Common.Enums.EventTiming eventTiming) [0x00000] in <00000000000000000000000000000000>:0 
  at VRC.Udon.UdonManager.Update () [0x00000] in <00000000000000000000000000000000>:0 

This issue will occur occasionally given enough time

As a potential fix one could try to implement a modulo function that can handle negative numbers

    public int Mod(int a, int b)
    {
        return ((a % b) + b) % b;
    }

I'm not immediately sure how to handle Networking.GetServerTimeInMilliseconds() returning negative values occasionally

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.