The code and data behind xeiaso.net
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

Vrchat writeup (#333)

* first part of the VRChat for gmeets writeup

Signed-off-by: Christine Dodrill <me@christine.website>

* more words

Signed-off-by: Christine Dodrill <me@christine.website>

* polishing touches

Signed-off-by: Christine Dodrill <me@christine.website>

authored by

Christine Dodrill and committed by
GitHub
f8c28977 c6482fe2

+642
+10
.vscode/settings.json
··· 1 + { 2 + "editor.wordWrap": "wordWrapColumn", 3 + "editor.wordWrapColumn": 80, 4 + "editor.wordBasedSuggestions": false, 5 + "[markdown]":{ 6 + "editor.wordWrap": "wordWrapColumn", 7 + "editor.wordWrapColumn": 80, 8 + "vim.textwidth": 80, 9 + }, 10 + }
+214
blog/convoluted-vrchat-gchat-setup-2021-02-24.markdown
··· 1 + --- 2 + title: "My Convoluted VRChat Google Meet Setup" 3 + date: 2021-02-24 4 + tags: 5 + - oculusquest2 6 + - vr 7 + - vrchat 8 + --- 9 + 10 + # My Convoluted VRChat Google Meet Setup 11 + 12 + Recently the place I work for sent us all VR headsets. I decided to see what it 13 + would take to use that headset to make my camera show a virtual avatar instead 14 + of my meat body face. This is the story of my journey through chaining things 15 + together to make work meetings a bit more fun by using a 3D avatar instead of 16 + myself in some of them. 17 + 18 + [This post uses SVG for diagrams to help explain what's going on here. You may 19 + need to use a browser with SVG support in order to get the best experience with 20 + this article. All the diagrams will be explained after the fact so that people 21 + using screen readers are not left out.](conversation://Mara/hacker) 22 + 23 + <center> 24 + 25 + <blockquote class="twitter-tweet"><p lang="en" dir="ltr">Working at <a href="https://twitter.com/Tailscale?ref_src=twsrc%5Etfw">@Tailscale</a> is great. They sent us all an Oculus Quest 2! <a href="https://t.co/dDhbwO9cFd">pic.twitter.com/dDhbwO9cFd</a></p>&mdash; Cadey A. Ratio (@theprincessxena) <a href="https://twitter.com/theprincessxena/status/1362871906597224456?ref_src=twsrc%5Etfw">February 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 26 + 27 + </center> 28 + 29 + So, let's cover the basics from a high level. At a high level a webcam is just 30 + a video source that may or may not have a microphone attached to it. So in 31 + order to get my avatar to show up in a video call, I need some way to make some 32 + window on my computer act as a webcam. This will make the overall dependency 33 + list look like this (for those of you using screen readers I will describe 34 + this diagram below): 35 + 36 + <center> 37 + 38 + ![](/static/blog/vrchat/simple_graph.svg) 39 + 40 + </center> 41 + 42 + VRChat renders to the Desktop which is picked up by OBS which has the ability 43 + to pretend to be a webcam, which is finally picked up by Google Meet. 44 + 45 + If the VR headset that I got from work was a tethered to the PC kind of VR 46 + headset like the Valve Index or HTC Vive, the next steps would involve full 47 + body tracking or something so that I could have my movements in real life 48 + transfer into movements that my avatar makes. 49 + 50 + However, the VR headset we got sent was an Oculus Quest 2. This is a 51 + _standalone_ VR headset that is basically an Android tablet that you strap 52 + to your face. This makes things a bit more technically challenging because 53 + now you need some way to get the video to the headset and the motion tracking 54 + data from the headset and to the computer at 90 times per second. This requires 55 + a bit more cleverness. 56 + 57 + The Oculus desktop software ships with a feature called Oculus Link that allows 58 + you to use a gaming PC to render the VR data to your headset by sending the 59 + video streams over USB. I had to dig around for a compatible cable (It needs to 60 + be a specific kind of USB-3 to USB-C-3 cable with at least 5 gigabits per 61 + second of transfer capacity) since the ones that 62 + [Oculus sells](https://www.oculus.com/accessories/oculus-link/) are both at 63 + least CAD$110 and out of stock anywhere I can find them in Canada. The 0.75 64 + meter long cable I had been using was good enough to get me through the first 65 + couple days of experimenting with VR, but it was clear that a better solution 66 + was needed. 67 + 68 + I did some digging and found a bit of software called 69 + [ALVR](https://github.com/alvr-org/alvr#readme) that claimed to let me do VR 70 + from my computer wirelessly. So I set it up on the Quest and on my tower, 71 + which brought up the dependency graph to this: 72 + 73 + <center> 74 + 75 + ![](/static/blog/vrchat/alvr_graph.svg) 76 + 77 + </center> 78 + 79 + ALVR talks with its counterpart on the Quest. This allows you to stream the VR 80 + video and audio bidirectionally. You also need to bring Virtual Audio Cable 81 + into the setup so that you can hear stuff in the game and so that other people 82 + can hear you using the headset mic. However, ALVR is not available on the Quest 83 + store. You need to install [SideQuest](https://sidequestvr.com/setup-howto) for 84 + that. 85 + 86 + [SideQuest lets you sideload Android APK files to your Quest 2 because the 87 + Quest 2 is basically an Android tablet that you strap to your face!](conversation://Mara/happy) 88 + 89 + So I used SideQuest to install the ALVR client on my Quest 2, and then I opened 90 + up VRChat and was able to do everything I was able to do with the wired cable. 91 + It worked beautifully until it didn't. I started running into issues with the 92 + video stream just dying. The foveated encoding (tl;dr: attempting to hack the 93 + image quality based on how eyes work so you don't notice the artifacting as 94 + much) could only do so much and it just ended up not working. Even when I was 95 + only doing it for short amounts of time. There is a lot of WiFi noise in my 96 + apartment or something and it was really interfering with ALVR's stream 97 + encoding. The latency was also noticeable after a bit. 98 + 99 + However, when it worked it worked beautifully. I had to upgrade to the nightly 100 + build of ALVR in order to get game audio and the headset mic working, but once 101 + it all worked it was really convenient. I could walk around my apartment and 102 + I'd also walk around in-game. 103 + 104 + A friend told me that the best experience I could have with wireless VR using a 105 + Quest 2 would be to use [Virtual Desktop](https://www.vrdesktop.net). Apparently 106 + Virtual Desktop has a 107 + [patch that enables SteamVR support](https://sidequestvr.com/app/16), so I 108 + purchased Virtual Desktop on a whim and decided to give it a go. 109 + 110 + Virtual Desktop made ALVR look like a tech demo. All of the latency issues were 111 + solved instantly. Virtual Desktop also made it convenient for me to access my 112 + tower's monitors while in VR, and it has the best typing experience in VR that 113 + I've ever used. 114 + 115 + This brings the dependency graph up to this: 116 + 117 + <center> 118 + 119 + ![](/static/blog/vrchat/total_graph.svg) 120 + 121 + </center> 122 + 123 + Now all that was left was to make the camera view look somewhat like it does 124 + when I'm using my work laptop's webcam to make video calls. I started out by taking a picture of my office from about the angle that my laptop sits at. 125 + I ended up with this image: 126 + 127 + <center> 128 + 129 + ![](https://cdn.christine.website/file/christine-static/blog/2021-02-24-20-20-58.jpg) 130 + 131 + </center> 132 + 133 + Then with some clever use of the 134 + [Chroma key filter in VRChat](https://docs.vrchat.com/docs/vrchat-201812) 135 + I was able to get some basic compositing of my avatar onto the picture. I 136 + fiddled with the placement of things and then I was able to declare success 137 + with this image I posted to Twitter: 138 + 139 + <center> 140 + 141 + ![](https://cdn.christine.website/file/christine-static/blog/Eu6iR6jXUAQH0iq.jpeg) 142 + 143 + </center> 144 + 145 + And it worked! I was able to make a call in Google Meet to myself and my 146 + avatar's lip movements synchronized somewhat with the words I was saying. I 147 + had waifu mode enabled! 148 + 149 + [The avatar being used there is based on a character from Xenoblade Chronicles 150 + 2 named Pneuma.](conversation://Mara/hacker) 151 + 152 + However, this setup was really janky. I didn't actually get the proper angle 153 + for what my work laptop's camera would actually see. Everything was offset to 154 + the side and it was at way the wrong angle in general. I'm also not sure if I 155 + messed up the sizing of the background image in the OBS view, it looks kinda 156 + stretched on my end as I'm writing this post. 157 + 158 + So I decided that the best way to get the most accurate angle was to record a 159 + video loop using my work laptop's webcam. After some googling I found 160 + [webcamera.io](https://webcamera.io) which let me record some footage of my 161 + office from my work laptop's camera angle. I got down under the desk (so I was 162 + out of view of the camera) and then recorded a 45 second loop of my office 163 + doing nothing (however the flag was slightly moving in the breeze from the desk 164 + fan). 165 + 166 + I also found a VRChat world that claimed to be as optimized as you could 167 + possibly make a VRChat world. It was a blue cube about 30m by 30m. Checking 168 + with SteamVR it brought my frame times down to 3 milliseconds with the stream 169 + camera set up for OBS. It looks like this: 170 + 171 + <center> 172 + 173 + ![Screenshot of the optimized world](https://cdn.christine.website/file/christine-static/blog/154306141_1368071216896631_2989259612329820447_o.jpg) 174 + 175 + </center> 176 + 177 + It's very minimal. You can make the walls go away if you want, which somehow makes it render faster on my RX5700. I'm not sure what's going on there. 178 + 179 + [I'd heckin' love to get a new GPU but until the Bitcoin prices go down we may 180 + be stuck with this setup for a while. An RTX 3070 would really be useful about 181 + now.](conversation://Mara/hacker) 182 + 183 + Anyways, with this minimal world incurring very little to no GPU load, I was 184 + free to do video calls all I wanted. I even did a call with the CEO of the 185 + company I work for with a setup like this. It was fun. 186 + 187 + Now I had everything set up. I can pop on the headset, load up the world, open 188 + OBS, VRChat, Virtual Desktop and get everything set up in about 5 minutes at 189 + worst. Then I can use the seeing your desktop side of Virtual Desktop to 190 + actually watch the meeting and be able to see screen sharing. They can hear me 191 + because Virtual Desktop pipes the headset microphone audio back to my tower, 192 + and the meeting audio comes over my headphones. 193 + 194 + Also at some point I needed to bring AutoHotKey into the mix, so I borrowed 195 + this AutoHotKey script from [SuperUser](https://superuser.com/a/429845) to 196 + resize the VRChat window so that it would fit perfectly into the OBS view: 197 + 198 + ```ahk 199 + #=:: ; [Win]+[=] 200 + WinGet, window, ID, A 201 + InputBox, width, Resize, Width:, , 140, 130 202 + InputBox, height, Resize, Height:, , 140, 130 203 + WinMove, ahk_id %window%, , , , width, height 204 + return 205 + ``` 206 + 207 + Making the VRChat window smaller also helped with the frame times, because it 208 + needed to render less detail per frame. This helped push the framerate 209 + comfortably above 72 FPS in my VR view. 210 + 211 + That is how I get a 3d avatar to show up instead of pictures of the meat golem 212 + I am cursed inside of for work meetings. I will also use this for streaming 213 + coding in the future, so you can all witness the power of a VTube coding stream 214 + where I write Rust or something.
+172
static/blog/vrchat/alvr_graph.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 + <!-- Generated by graphviz version 2.40.1 (20161225.0304) 5 + --> 6 + <!-- Title: G Pages: 1 --> 7 + <svg width="661pt" height="308pt" 8 + viewBox="0.00 0.00 661.01 308.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 9 + <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 304)"> 10 + <title>G</title> 11 + <polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-304 657.0118,-304 657.0118,4 -4,4"/> 12 + <g id="clust1" class="cluster"> 13 + <title>cluster_0</title> 14 + <polygon fill="#d3d3d3" stroke="#d3d3d3" points="150.8243,-8 150.8243,-107 374.9943,-107 374.9943,-8 150.8243,-8"/> 15 + <text text-anchor="middle" x="262.9093" y="-90.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text> 16 + </g> 17 + <g id="clust2" class="cluster"> 18 + <title>cluster_1</title> 19 + <polygon fill="#d3d3d3" stroke="#d3d3d3" points="8,-115 8,-292 645.0118,-292 645.0118,-115 8,-115"/> 20 + <text text-anchor="middle" x="326.5059" y="-275.4" font-family="Times,serif" font-size="14.00" fill="#000000">PC</text> 21 + </g> 22 + <!-- AVA --> 23 + <g id="node1" class="node"> 24 + <title>AVA</title> 25 + <ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-45" rx="38.0139" ry="29.3315"/> 26 + <text text-anchor="middle" x="328.7382" y="-49.2" font-family="Times,serif" font-size="14.00" fill="#000000">ALVR</text> 27 + <text text-anchor="middle" x="328.7382" y="-32.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text> 28 + </g> 29 + <!-- AVR --> 30 + <g id="node3" class="node"> 31 + <title>AVR</title> 32 + <ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-164" rx="42.2164" ry="29.3315"/> 33 + <text text-anchor="middle" x="328.7382" y="-168.2" font-family="Times,serif" font-size="14.00" fill="#000000">ALVR</text> 34 + <text text-anchor="middle" x="328.7382" y="-151.4" font-family="Times,serif" font-size="14.00" fill="#000000">desktop</text> 35 + </g> 36 + <!-- AVA&#45;&gt;AVR --> 37 + <g id="edge7" class="edge"> 38 + <title>AVA&#45;&gt;AVR</title> 39 + <path fill="none" stroke="#000000" d="M328.7382,-74.75C328.7382,-91.2066 328.7382,-107.6631 328.7382,-124.1197"/> 40 + <polygon fill="#000000" stroke="#000000" points="325.2383,-124.3662 328.7382,-134.3662 332.2383,-124.3662 325.2383,-124.3662"/> 41 + </g> 42 + <!-- A --> 43 + <g id="node2" class="node"> 44 + <title>A</title> 45 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-50" rx="43.4415" ry="18"/> 46 + <text text-anchor="middle" x="202.0445" y="-45.8" font-family="Times,serif" font-size="14.00" fill="#000000">Android</text> 47 + </g> 48 + <!-- A&#45;&gt;AVA --> 49 + <g id="edge1" class="edge"> 50 + <title>A&#45;&gt;AVA</title> 51 + <path fill="none" stroke="#000000" d="M245.2909,-48.2933C256.4871,-47.8514 268.6178,-47.3727 280.071,-46.9207"/> 52 + <polygon fill="#000000" stroke="#000000" points="280.4983,-50.4066 290.3525,-46.5149 280.2222,-43.4121 280.4983,-50.4066"/> 53 + </g> 54 + <!-- AVR&#45;&gt;AVA --> 55 + <g id="edge6" class="edge"> 56 + <title>AVR&#45;&gt;AVA</title> 57 + <path fill="none" stroke="#000000" d="M328.7382,-134.3662C328.7382,-117.9097 328.7382,-101.4531 328.7382,-84.9965"/> 58 + <polygon fill="#000000" stroke="#000000" points="332.2383,-84.75 328.7382,-74.75 325.2383,-84.75 332.2383,-84.75"/> 59 + </g> 60 + <!-- VAC --> 61 + <g id="node11" class="node"> 62 + <title>VAC</title> 63 + <ellipse fill="#ffffff" stroke="#ffffff" cx="463.4742" cy="-164" rx="39.2066" ry="41.0911"/> 64 + <text text-anchor="middle" x="463.4742" y="-176.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text> 65 + <text text-anchor="middle" x="463.4742" y="-159.8" font-family="Times,serif" font-size="14.00" fill="#000000">Audio</text> 66 + <text text-anchor="middle" x="463.4742" y="-143" font-family="Times,serif" font-size="14.00" fill="#000000">Cable</text> 67 + </g> 68 + <!-- AVR&#45;&gt;VAC --> 69 + <g id="edge12" class="edge"> 70 + <title>AVR&#45;&gt;VAC</title> 71 + <path fill="none" stroke="#000000" d="M370.9998,-164C384.6622,-164 399.9322,-164 414.0648,-164"/> 72 + <polygon fill="#000000" stroke="#000000" points="414.1153,-167.5001 424.1152,-164 414.1152,-160.5001 414.1153,-167.5001"/> 73 + </g> 74 + <!-- SVR --> 75 + <g id="node4" class="node"> 76 + <title>SVR</title> 77 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-170" rx="48.6714" ry="18"/> 78 + <text text-anchor="middle" x="202.0445" y="-165.8" font-family="Times,serif" font-size="14.00" fill="#000000">SteamVR</text> 79 + </g> 80 + <!-- SVR&#45;&gt;AVR --> 81 + <g id="edge5" class="edge"> 82 + <title>SVR&#45;&gt;AVR</title> 83 + <path fill="none" stroke="#000000" d="M250.3034,-167.7145C258.7549,-167.3143 267.5869,-166.896 276.1488,-166.4905"/> 84 + <polygon fill="#000000" stroke="#000000" points="276.5916,-169.9736 286.4148,-166.0044 276.2604,-162.9814 276.5916,-169.9736"/> 85 + </g> 86 + <!-- VRC --> 87 + <g id="node5" class="node"> 88 + <title>VRC</title> 89 + <ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-206" rx="42.8751" ry="18"/> 90 + <text text-anchor="middle" x="66.7294" y="-201.8" font-family="Times,serif" font-size="14.00" fill="#000000">VRChat</text> 91 + </g> 92 + <!-- VRC&#45;&gt;SVR --> 93 + <g id="edge4" class="edge"> 94 + <title>VRC&#45;&gt;SVR</title> 95 + <path fill="none" stroke="#000000" d="M102.9914,-196.3527C118.1616,-192.3167 136.0376,-187.5609 152.3981,-183.2082"/> 96 + <polygon fill="#000000" stroke="#000000" points="153.5873,-186.5137 162.3513,-180.5602 151.7875,-179.749 153.5873,-186.5137"/> 97 + </g> 98 + <!-- DESK --> 99 + <g id="node10" class="node"> 100 + <title>DESK</title> 101 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-229" rx="43.4396" ry="18"/> 102 + <text text-anchor="middle" x="202.0445" y="-224.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 103 + </g> 104 + <!-- VRC&#45;&gt;DESK --> 105 + <g id="edge10" class="edge"> 106 + <title>VRC&#45;&gt;DESK</title> 107 + <path fill="none" stroke="#000000" d="M106.5966,-212.7764C120.7849,-215.188 136.9469,-217.9351 151.8865,-220.4745"/> 108 + <polygon fill="#000000" stroke="#000000" points="151.5496,-223.9673 161.9947,-222.1926 152.7227,-217.0663 151.5496,-223.9673"/> 109 + </g> 110 + <!-- OBS --> 111 + <g id="node6" class="node"> 112 + <title>OBS</title> 113 + <ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-235" rx="29.6339" ry="18"/> 114 + <text text-anchor="middle" x="328.7382" y="-230.8" font-family="Times,serif" font-size="14.00" fill="#000000">OBS</text> 115 + </g> 116 + <!-- VIRC --> 117 + <g id="node7" class="node"> 118 + <title>VIRC</title> 119 + <ellipse fill="#ffffff" stroke="#ffffff" cx="463.4742" cy="-241" rx="56.7561" ry="18"/> 120 + <text text-anchor="middle" x="463.4742" y="-236.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualCam</text> 121 + </g> 122 + <!-- OBS&#45;&gt;VIRC --> 123 + <g id="edge8" class="edge"> 124 + <title>OBS&#45;&gt;VIRC</title> 125 + <path fill="none" stroke="#000000" d="M358.6405,-236.3316C370.0698,-236.8406 383.6086,-237.4435 397.0947,-238.044"/> 126 + <polygon fill="#000000" stroke="#000000" points="397.2155,-241.5528 407.3614,-238.5012 397.527,-234.5597 397.2155,-241.5528"/> 127 + </g> 128 + <!-- GM --> 129 + <g id="node8" class="node"> 130 + <title>GM</title> 131 + <ellipse fill="#ffffff" stroke="#ffffff" cx="596.5569" cy="-197" rx="40.4098" ry="29.3315"/> 132 + <text text-anchor="middle" x="596.5569" y="-201.2" font-family="Times,serif" font-size="14.00" fill="#000000">Google</text> 133 + <text text-anchor="middle" x="596.5569" y="-184.4" font-family="Times,serif" font-size="14.00" fill="#000000">Meet</text> 134 + </g> 135 + <!-- VIRC&#45;&gt;GM --> 136 + <g id="edge9" class="edge"> 137 + <title>VIRC&#45;&gt;GM</title> 138 + <path fill="none" stroke="#000000" d="M503.043,-227.9177C517.7504,-223.0551 534.5739,-217.4929 549.8596,-212.4391"/> 139 + <polygon fill="#000000" stroke="#000000" points="551.2489,-215.6662 559.6447,-209.204 549.0515,-209.02 551.2489,-215.6662"/> 140 + </g> 141 + <!-- SQ --> 142 + <g id="node9" class="node"> 143 + <title>SQ</title> 144 + <ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-141" rx="50.9599" ry="18"/> 145 + <text text-anchor="middle" x="66.7294" y="-136.8" font-family="Times,serif" font-size="14.00" fill="#000000">SideQuest</text> 146 + </g> 147 + <!-- SQ&#45;&gt;AVA --> 148 + <g id="edge3" class="edge"> 149 + <title>SQ&#45;&gt;AVA</title> 150 + <path fill="none" stroke="#000000" d="M103.9261,-128.7112C141.2245,-116.2351 200.2025,-96.0887 250.6301,-77 262.0869,-72.6632 274.3899,-67.7466 285.765,-63.0913"/> 151 + <polygon fill="#000000" stroke="#000000" points="287.15,-66.3061 295.0628,-59.2607 284.4835,-59.8339 287.15,-66.3061"/> 152 + </g> 153 + <!-- SQ&#45;&gt;A --> 154 + <g id="edge2" class="edge"> 155 + <title>SQ&#45;&gt;A</title> 156 + <path fill="none" stroke="#000000" d="M90.6096,-124.9405C112.7736,-110.0351 145.9219,-87.7427 170.305,-71.3449"/> 157 + <polygon fill="#000000" stroke="#000000" points="172.5102,-74.0798 178.8551,-65.595 168.6038,-68.2712 172.5102,-74.0798"/> 158 + </g> 159 + <!-- DESK&#45;&gt;OBS --> 160 + <g id="edge11" class="edge"> 161 + <title>DESK&#45;&gt;OBS</title> 162 + <path fill="none" stroke="#000000" d="M245.2909,-231.0481C259.3432,-231.7136 274.8677,-232.4488 288.6771,-233.1028"/> 163 + <polygon fill="#000000" stroke="#000000" points="288.6958,-236.6075 298.8502,-233.5846 289.027,-229.6153 288.6958,-236.6075"/> 164 + </g> 165 + <!-- VAC&#45;&gt;GM --> 166 + <g id="edge13" class="edge"> 167 + <title>VAC&#45;&gt;GM</title> 168 + <path fill="none" stroke="#000000" d="M501.9672,-173.545C516.4509,-177.1364 533.1046,-181.266 548.3623,-185.0494"/> 169 + <polygon fill="#000000" stroke="#000000" points="547.6019,-188.4668 558.1504,-187.4765 549.2867,-181.6725 547.6019,-188.4668"/> 170 + </g> 171 + </g> 172 + </svg>
+73
static/blog/vrchat/simple_graph.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 + <!-- Generated by graphviz version 2.40.1 (20161225.0304) 5 + --> 6 + <!-- Title: G Pages: 1 --> 7 + <svg width="610pt" height="123pt" 8 + viewBox="0.00 0.00 609.61 123.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 9 + <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 119)"> 10 + <title>G</title> 11 + <polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-119 605.611,-119 605.611,4 -4,4"/> 12 + <g id="clust1" class="cluster"> 13 + <title>cluster_1</title> 14 + <polygon fill="#d3d3d3" stroke="#d3d3d3" points="8,-8 8,-107 593.611,-107 593.611,-8 8,-8"/> 15 + <text text-anchor="middle" x="300.8055" y="-90.4" font-family="Times,serif" font-size="14.00" fill="#000000">PC</text> 16 + </g> 17 + <!-- VRC --> 18 + <g id="node1" class="node"> 19 + <title>VRC</title> 20 + <ellipse fill="#ffffff" stroke="#ffffff" cx="58.6871" cy="-45" rx="42.8751" ry="18"/> 21 + <text text-anchor="middle" x="58.6871" y="-40.8" font-family="Times,serif" font-size="14.00" fill="#000000">VRChat</text> 22 + </g> 23 + <!-- DESK --> 24 + <g id="node5" class="node"> 25 + <title>DESK</title> 26 + <ellipse fill="#ffffff" stroke="#ffffff" cx="180.5935" cy="-45" rx="43.4396" ry="18"/> 27 + <text text-anchor="middle" x="180.5935" y="-40.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 28 + </g> 29 + <!-- VRC&#45;&gt;DESK --> 30 + <g id="edge3" class="edge"> 31 + <title>VRC&#45;&gt;DESK</title> 32 + <path fill="none" stroke="#000000" d="M101.6668,-45C109.8542,-45 118.5168,-45 126.9873,-45"/> 33 + <polygon fill="#000000" stroke="#000000" points="127.1794,-48.5001 137.1794,-45 127.1793,-41.5001 127.1794,-48.5001"/> 34 + </g> 35 + <!-- OBS --> 36 + <g id="node2" class="node"> 37 + <title>OBS</title> 38 + <ellipse fill="#ffffff" stroke="#ffffff" cx="289.6291" cy="-45" rx="29.6339" ry="18"/> 39 + <text text-anchor="middle" x="289.6291" y="-40.8" font-family="Times,serif" font-size="14.00" fill="#000000">OBS</text> 40 + </g> 41 + <!-- VIRC --> 42 + <g id="node3" class="node"> 43 + <title>VIRC</title> 44 + <ellipse fill="#ffffff" stroke="#ffffff" cx="412.0734" cy="-45" rx="56.7561" ry="18"/> 45 + <text text-anchor="middle" x="412.0734" y="-40.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualCam</text> 46 + </g> 47 + <!-- OBS&#45;&gt;VIRC --> 48 + <g id="edge1" class="edge"> 49 + <title>OBS&#45;&gt;VIRC</title> 50 + <path fill="none" stroke="#000000" d="M319.5824,-45C327.4013,-45 336.1504,-45 345.0646,-45"/> 51 + <polygon fill="#000000" stroke="#000000" points="345.1584,-48.5001 355.1584,-45 345.1584,-41.5001 345.1584,-48.5001"/> 52 + </g> 53 + <!-- GM --> 54 + <g id="node4" class="node"> 55 + <title>GM</title> 56 + <ellipse fill="#ffffff" stroke="#ffffff" cx="545.1562" cy="-45" rx="40.4098" ry="29.3315"/> 57 + <text text-anchor="middle" x="545.1562" y="-49.2" font-family="Times,serif" font-size="14.00" fill="#000000">Google</text> 58 + <text text-anchor="middle" x="545.1562" y="-32.4" font-family="Times,serif" font-size="14.00" fill="#000000">Meet</text> 59 + </g> 60 + <!-- VIRC&#45;&gt;GM --> 61 + <g id="edge2" class="edge"> 62 + <title>VIRC&#45;&gt;GM</title> 63 + <path fill="none" stroke="#000000" d="M468.8985,-45C477.4369,-45 486.1935,-45 494.5894,-45"/> 64 + <polygon fill="#000000" stroke="#000000" points="494.6128,-48.5001 504.6128,-45 494.6128,-41.5001 494.6128,-48.5001"/> 65 + </g> 66 + <!-- DESK&#45;&gt;OBS --> 67 + <g id="edge4" class="edge"> 68 + <title>DESK&#45;&gt;OBS</title> 69 + <path fill="none" stroke="#000000" d="M224.0006,-45C232.4355,-45 241.241,-45 249.5623,-45"/> 70 + <polygon fill="#000000" stroke="#000000" points="249.7795,-48.5001 259.7795,-45 249.7795,-41.5001 249.7795,-48.5001"/> 71 + </g> 72 + </g> 73 + </svg>
+173
static/blog/vrchat/total_graph.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 3 + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 4 + <!-- Generated by graphviz version 2.40.1 (20161225.0304) 5 + --> 6 + <!-- Title: G Pages: 1 --> 7 + <svg width="671pt" height="332pt" 8 + viewBox="0.00 0.00 670.88 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 9 + <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)"> 10 + <title>G</title> 11 + <polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-328 666.8816,-328 666.8816,4 -4,4"/> 12 + <g id="clust1" class="cluster"> 13 + <title>cluster_0</title> 14 + <polygon fill="#d3d3d3" stroke="#d3d3d3" points="150.8243,-8 150.8243,-131 525.6487,-131 525.6487,-8 150.8243,-8"/> 15 + <text text-anchor="middle" x="338.2365" y="-114.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text> 16 + </g> 17 + <g id="clust2" class="cluster"> 18 + <title>cluster_1</title> 19 + <polygon fill="#d3d3d3" stroke="#d3d3d3" points="8,-139 8,-316 654.8816,-316 654.8816,-139 8,-139"/> 20 + <text text-anchor="middle" x="331.4408" y="-299.4" font-family="Times,serif" font-size="14.00" fill="#000000">PC</text> 21 + </g> 22 + <!-- VD --> 23 + <g id="node1" class="node"> 24 + <title>VD</title> 25 + <ellipse fill="#ffffff" stroke="#ffffff" cx="473.3439" cy="-63" rx="44.1104" ry="29.3315"/> 26 + <text text-anchor="middle" x="473.3439" y="-67.2" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text> 27 + <text text-anchor="middle" x="473.3439" y="-50.4" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 28 + </g> 29 + <!-- VDS --> 30 + <g id="node4" class="node"> 31 + <title>VDS</title> 32 + <ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-188" rx="47.086" ry="41.0911"/> 33 + <text text-anchor="middle" x="333.6731" y="-200.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text> 34 + <text text-anchor="middle" x="333.6731" y="-183.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 35 + <text text-anchor="middle" x="333.6731" y="-167" font-family="Times,serif" font-size="14.00" fill="#000000">Streamer</text> 36 + </g> 37 + <!-- VD&#45;&gt;VDS --> 38 + <g id="edge4" class="edge"> 39 + <title>VD&#45;&gt;VDS</title> 40 + <path fill="none" stroke="#000000" d="M450.736,-88.362C431.0544,-107.6122 401.9557,-134.0523 377.6943,-154.9249"/> 41 + <polygon fill="#000000" stroke="#000000" points="375.3377,-152.3348 370.0053,-161.4899 379.8831,-157.6583 375.3377,-152.3348"/> 42 + </g> 43 + <!-- VDM --> 44 + <g id="node2" class="node"> 45 + <title>VDM</title> 46 + <ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-57" rx="45.275" ry="41.0911"/> 47 + <text text-anchor="middle" x="333.6731" y="-69.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text> 48 + <text text-anchor="middle" x="333.6731" y="-52.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 49 + <text text-anchor="middle" x="333.6731" y="-36" font-family="Times,serif" font-size="14.00" fill="#000000">VR mod</text> 50 + </g> 51 + <!-- VDM&#45;&gt;VD --> 52 + <g id="edge3" class="edge"> 53 + <title>VDM&#45;&gt;VD</title> 54 + <path fill="none" stroke="#000000" d="M379.0202,-58.948C391.5906,-59.488 405.3731,-60.0801 418.4262,-60.6408"/> 55 + <polygon fill="#000000" stroke="#000000" points="418.5601,-64.1497 428.7011,-61.0822 418.8606,-57.1562 418.5601,-64.1497"/> 56 + </g> 57 + <!-- A --> 58 + <g id="node3" class="node"> 59 + <title>A</title> 60 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-68" rx="43.4415" ry="18"/> 61 + <text text-anchor="middle" x="202.0445" y="-63.8" font-family="Times,serif" font-size="14.00" fill="#000000">Android</text> 62 + </g> 63 + <!-- A&#45;&gt;VDM --> 64 + <g id="edge2" class="edge"> 65 + <title>A&#45;&gt;VDM</title> 66 + <path fill="none" stroke="#000000" d="M244.7805,-64.4286C255.4706,-63.5353 267.0909,-62.5642 278.2968,-61.6277"/> 67 + <polygon fill="#000000" stroke="#000000" points="278.7592,-65.1014 288.433,-60.7806 278.1762,-58.1257 278.7592,-65.1014"/> 68 + </g> 69 + <!-- VDS&#45;&gt;VD --> 70 + <g id="edge5" class="edge"> 71 + <title>VDS&#45;&gt;VD</title> 72 + <path fill="none" stroke="#000000" d="M363.2937,-155.8547C384.2099,-135.824 412.4271,-110.4172 435.0521,-91.1733"/> 73 + <polygon fill="#000000" stroke="#000000" points="437.4099,-93.7634 442.8005,-84.6424 432.8986,-88.411 437.4099,-93.7634"/> 74 + </g> 75 + <!-- GM --> 76 + <g id="node9" class="node"> 77 + <title>GM</title> 78 + <ellipse fill="#ffffff" stroke="#ffffff" cx="606.4267" cy="-216" rx="40.4098" ry="29.3315"/> 79 + <text text-anchor="middle" x="606.4267" y="-220.2" font-family="Times,serif" font-size="14.00" fill="#000000">Google</text> 80 + <text text-anchor="middle" x="606.4267" y="-203.4" font-family="Times,serif" font-size="14.00" fill="#000000">Meet</text> 81 + </g> 82 + <!-- VDS&#45;&gt;GM --> 83 + <g id="edge6" class="edge"> 84 + <title>VDS&#45;&gt;GM</title> 85 + <path fill="none" stroke="#000000" d="M380.5611,-192.8134C429.5797,-197.8455 506.2147,-205.7126 556.3811,-210.8625"/> 86 + <polygon fill="#000000" stroke="#000000" points="556.0498,-214.3468 566.355,-211.8864 556.7647,-207.3834 556.0498,-214.3468"/> 87 + </g> 88 + <!-- SVR --> 89 + <g id="node5" class="node"> 90 + <title>SVR</title> 91 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-188" rx="48.6714" ry="18"/> 92 + <text text-anchor="middle" x="202.0445" y="-183.8" font-family="Times,serif" font-size="14.00" fill="#000000">SteamVR</text> 93 + </g> 94 + <!-- SVR&#45;&gt;VDS --> 95 + <g id="edge10" class="edge"> 96 + <title>SVR&#45;&gt;VDS</title> 97 + <path fill="none" stroke="#000000" d="M250.6841,-188C259.0146,-188 267.7397,-188 276.273,-188"/> 98 + <polygon fill="#000000" stroke="#000000" points="276.5472,-191.5001 286.5471,-188 276.5471,-184.5001 276.5472,-191.5001"/> 99 + </g> 100 + <!-- VRC --> 101 + <g id="node6" class="node"> 102 + <title>VRC</title> 103 + <ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-230" rx="42.8751" ry="18"/> 104 + <text text-anchor="middle" x="66.7294" y="-225.8" font-family="Times,serif" font-size="14.00" fill="#000000">VRChat</text> 105 + </g> 106 + <!-- VRC&#45;&gt;SVR --> 107 + <g id="edge7" class="edge"> 108 + <title>VRC&#45;&gt;SVR</title> 109 + <path fill="none" stroke="#000000" d="M101.2253,-219.293C117.6099,-214.2074 137.4417,-208.0518 155.1663,-202.5504"/> 110 + <polygon fill="#000000" stroke="#000000" points="156.2483,-205.8793 164.7613,-199.5722 154.1732,-199.194 156.2483,-205.8793"/> 111 + </g> 112 + <!-- DESK --> 113 + <g id="node11" class="node"> 114 + <title>DESK</title> 115 + <ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-242" rx="43.4396" ry="18"/> 116 + <text text-anchor="middle" x="202.0445" y="-237.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text> 117 + </g> 118 + <!-- VRC&#45;&gt;DESK --> 119 + <g id="edge12" class="edge"> 120 + <title>VRC&#45;&gt;DESK</title> 121 + <path fill="none" stroke="#000000" d="M108.8022,-233.7311C121.6615,-234.8715 135.9668,-236.1401 149.4342,-237.3344"/> 122 + <polygon fill="#000000" stroke="#000000" points="149.2616,-240.8328 159.5317,-238.2299 149.88,-233.8601 149.2616,-240.8328"/> 123 + </g> 124 + <!-- OBS --> 125 + <g id="node7" class="node"> 126 + <title>OBS</title> 127 + <ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-265" rx="29.6339" ry="18"/> 128 + <text text-anchor="middle" x="333.6731" y="-260.8" font-family="Times,serif" font-size="14.00" fill="#000000">OBS</text> 129 + </g> 130 + <!-- VIRC --> 131 + <g id="node8" class="node"> 132 + <title>VIRC</title> 133 + <ellipse fill="#ffffff" stroke="#ffffff" cx="473.3439" cy="-255" rx="56.7561" ry="18"/> 134 + <text text-anchor="middle" x="473.3439" y="-250.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualCam</text> 135 + </g> 136 + <!-- OBS&#45;&gt;VIRC --> 137 + <g id="edge8" class="edge"> 138 + <title>OBS&#45;&gt;VIRC</title> 139 + <path fill="none" stroke="#000000" d="M363.2937,-262.8793C376.2998,-261.9481 392.129,-260.8147 407.6812,-259.7012"/> 140 + <polygon fill="#000000" stroke="#000000" points="408.1043,-263.18 417.8288,-258.9747 407.6044,-256.1979 408.1043,-263.18"/> 141 + </g> 142 + <!-- VIRC&#45;&gt;GM --> 143 + <g id="edge9" class="edge"> 144 + <title>VIRC&#45;&gt;GM</title> 145 + <path fill="none" stroke="#000000" d="M515.087,-242.7672C529.0844,-238.6652 544.7902,-234.0626 559.1786,-229.8461"/> 146 + <polygon fill="#000000" stroke="#000000" points="560.28,-233.1706 568.8921,-226.9995 558.3114,-226.4531 560.28,-233.1706"/> 147 + </g> 148 + <!-- SQ --> 149 + <g id="node10" class="node"> 150 + <title>SQ</title> 151 + <ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-165" rx="50.9599" ry="18"/> 152 + <text text-anchor="middle" x="66.7294" y="-160.8" font-family="Times,serif" font-size="14.00" fill="#000000">SideQuest</text> 153 + </g> 154 + <!-- SQ&#45;&gt;A --> 155 + <g id="edge1" class="edge"> 156 + <title>SQ&#45;&gt;A</title> 157 + <path fill="none" stroke="#000000" d="M89.3781,-148.7644C111.9913,-132.5542 146.8811,-107.5436 171.8411,-89.6512"/> 158 + <polygon fill="#000000" stroke="#000000" points="174.1309,-92.3162 180.2192,-83.6453 170.0526,-86.6269 174.1309,-92.3162"/> 159 + </g> 160 + <!-- DESK&#45;&gt;VDS --> 161 + <g id="edge11" class="edge"> 162 + <title>DESK&#45;&gt;VDS</title> 163 + <path fill="none" stroke="#000000" d="M232.9056,-229.3394C247.3882,-223.3979 265.0521,-216.1514 281.5218,-209.3948"/> 164 + <polygon fill="#000000" stroke="#000000" points="283.1245,-212.5204 291.0478,-205.4868 280.4677,-206.0442 283.1245,-212.5204"/> 165 + </g> 166 + <!-- DESK&#45;&gt;OBS --> 167 + <g id="edge13" class="edge"> 168 + <title>DESK&#45;&gt;OBS</title> 169 + <path fill="none" stroke="#000000" d="M242.2526,-249.0257C259.0321,-251.9577 278.4424,-255.3493 295.05,-258.2512"/> 170 + <polygon fill="#000000" stroke="#000000" points="294.5265,-261.7127 304.9797,-259.9863 295.7315,-254.8172 294.5265,-261.7127"/> 171 + </g> 172 + </g> 173 + </svg>