more words

Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
Cadey Ratio 2021-02-24 20:47:08 -05:00
parent f09331323d
commit 22fe8cb4b4
3 changed files with 459 additions and 1 deletions

View File

@ -59,4 +59,117 @@ was needed.
I did some digging and found a bit of software called
[ALVR](https://github.com/alvr-org/alvr#readme) that claimed to let me do VR
from my computer wirelessly.
from my computer wirelessly. So I set it up on the Quest and on my tower,
which brought up the dependency graph to this:
![](/static/blog/vrchat/alvr_graph.svg)
ALVR talks with its counterpart on the Quest. This allows you to stream the VR
video and audio bidirectionally. You also need to bring Virtual Audio Cable
into the setup so that you can hear stuff in the game and so that other people
can hear you using the headset mic. However, ALVR is not available on the Quest
store. You need to install [SideQuest](https://sidequestvr.com/setup-howto) for
that.
[SideQuest lets you sideload Android APK files to your Quest 2 because the
Quest 2 is basically an Android tablet that you strap to your face!](conversation://Mara/happy)
So I used SideQuest to install the ALVR client on my Quest 2, and then I opened
up VRChat and was able to do everything I was able to do with the wired cable.
It worked beautifully until it didn't. I started running into issues with the
video stream just dying. The foveated encoding (tl;dr: attempting to hack the
image quality based on how eyes work so you don't notice the artifacting as
much) could only do so much and it just ended up not working. Even when I was
only doing it for short amounts of time. There is a lot of WiFi noise in my
apartment or something and it was really interfering with ALVR's stream
encoding. The latency was also noticeable after a bit.
However, when it worked it worked beautifully. I had to upgrade to the nightly
build of ALVR in order to get game audio and the headset mic working, but once
it all worked it was really convenient. I could walk around my apartment and
I'd also walk around in-game.
A friend told me that the best experience I could have with wireless VR using a
Quest 2 would be to use [Virtual Desktop](https://www.vrdesktop.net). Apparently
Virtual Desktop has a
[patch that enables SteamVR support](https://sidequestvr.com/app/16), so I
purchased Virtual Desktop on a whim and decided to give it a go.
Virtual Desktop made ALVR look like a tech demo. All of the latency issues were
solved instantly. Virtual Desktop also made it convenient for me to access my
tower's monitors while in VR, and it has the best typing experience in VR that
I've ever used.
This brings the dependency graph up to this:
![](/static/blog/vrchat/total_graph.svg)
Now all that was left was to make the camera view look somewhat like it does
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.
I ended up with this image:
![](https://cdn.christine.website/file/christine-static/blog/2021-02-24-20-20-58.jpg)
Then with some clever use of the
[Chroma key filter in VRChat](https://docs.vrchat.com/docs/vrchat-201812)
I was able to get some basic compositing of my avatar onto the picture. I
fiddled with the placement of things and then I was able to declare success
with this image I posted to Twitter:
<center>
![](https://cdn.christine.website/file/christine-static/blog/Eu6iR6jXUAQH0iq.jpeg)
</center>
And it worked! I was able to make a call in Google Meet to myself and my
avatar's lip movements synchronized somewhat with the words I was saying. I
had waifu mode enabled!
[The avatar being used there is based on a character from Xenoblade Chronicles
2 named Pneuma.](conversation://Mara/hacker)
However, this setup was really janky. I didn't actually get the proper angle
for what my work laptop's camera would actually see. Everything was offset to
the side and it was at way the wrong angle in general. I'm also not sure if I
messed up the sizing of the background image in the OBS view, it looks kinda
stretched on my end as I'm writing this post.
So I decided that the best way to get the most accurate angle was to record a
video loop using my work laptop's webcam. After some googling I found
[webcamera.io](https://webcamera.io) which let me record some footage of my
office from my work laptop's camera angle. I got down under the desk (so I was
out of view of the camera) and then recorded a 45 second loop of my office
doing nothing (however the flag was slightly moving in the breeze from the desk
fan).
I also found a VRChat world that claimed to be as optimized as you could
possibly make a VRChat world. It was a blue cube about 30m by 30m. Checking
with SteamVR it brought my frame times down to 3 milliseconds with the stream
camera set up for OBS. It looks like this:
<center>
![Screenshot of the optimized world](https://cdn.christine.website/file/christine-static/blog/154306141_1368071216896631_2989259612329820447_o.jpg)
</center>
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.
[I'd heckin' love to get a new GPU but until the Bitcoin prices go down we may
be stuck with this setup for a while. An RTX 3070 would really be useful about
now.](conversation://Mara/hacker)
Anyways, with this minimal world incurring very little to no GPU load, I was
free to do video calls all I wanted. I even did a call with the CEO of the
company I work for with a setup like this. It was fun.
Now I had everything set up. I can pop on the headset, load up the world, open
OBS, VRChat, Virtual Desktop and get everything set up in about 5 minutes at
worst. Then I can use the seeing your desktop side of Virtual Desktop to
actually watch the meeting and be able to see screen sharing. They can hear me
because Virtual Desktop pipes the headset microphone audio back to my tower,
and the meeting audio comes over my headphones.
That is how I get a 3d avatar to show up instead of pictures of the meat golem
I am cursed inside for work meetings.

View File

@ -0,0 +1,172 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="661pt" height="308pt"
viewBox="0.00 0.00 661.01 308.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 304)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-304 657.0118,-304 657.0118,4 -4,4"/>
<g id="clust1" class="cluster">
<title>cluster_0</title>
<polygon fill="#d3d3d3" stroke="#d3d3d3" points="150.8243,-8 150.8243,-107 374.9943,-107 374.9943,-8 150.8243,-8"/>
<text text-anchor="middle" x="262.9093" y="-90.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text>
</g>
<g id="clust2" class="cluster">
<title>cluster_1</title>
<polygon fill="#d3d3d3" stroke="#d3d3d3" points="8,-115 8,-292 645.0118,-292 645.0118,-115 8,-115"/>
<text text-anchor="middle" x="326.5059" y="-275.4" font-family="Times,serif" font-size="14.00" fill="#000000">PC</text>
</g>
<!-- AVA -->
<g id="node1" class="node">
<title>AVA</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-45" rx="38.0139" ry="29.3315"/>
<text text-anchor="middle" x="328.7382" y="-49.2" font-family="Times,serif" font-size="14.00" fill="#000000">ALVR</text>
<text text-anchor="middle" x="328.7382" y="-32.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text>
</g>
<!-- AVR -->
<g id="node3" class="node">
<title>AVR</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-164" rx="42.2164" ry="29.3315"/>
<text text-anchor="middle" x="328.7382" y="-168.2" font-family="Times,serif" font-size="14.00" fill="#000000">ALVR</text>
<text text-anchor="middle" x="328.7382" y="-151.4" font-family="Times,serif" font-size="14.00" fill="#000000">desktop</text>
</g>
<!-- AVA&#45;&gt;AVR -->
<g id="edge7" class="edge">
<title>AVA&#45;&gt;AVR</title>
<path fill="none" stroke="#000000" d="M328.7382,-74.75C328.7382,-91.2066 328.7382,-107.6631 328.7382,-124.1197"/>
<polygon fill="#000000" stroke="#000000" points="325.2383,-124.3662 328.7382,-134.3662 332.2383,-124.3662 325.2383,-124.3662"/>
</g>
<!-- A -->
<g id="node2" class="node">
<title>A</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-50" rx="43.4415" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-45.8" font-family="Times,serif" font-size="14.00" fill="#000000">Android</text>
</g>
<!-- A&#45;&gt;AVA -->
<g id="edge1" class="edge">
<title>A&#45;&gt;AVA</title>
<path fill="none" stroke="#000000" d="M245.2909,-48.2933C256.4871,-47.8514 268.6178,-47.3727 280.071,-46.9207"/>
<polygon fill="#000000" stroke="#000000" points="280.4983,-50.4066 290.3525,-46.5149 280.2222,-43.4121 280.4983,-50.4066"/>
</g>
<!-- AVR&#45;&gt;AVA -->
<g id="edge6" class="edge">
<title>AVR&#45;&gt;AVA</title>
<path fill="none" stroke="#000000" d="M328.7382,-134.3662C328.7382,-117.9097 328.7382,-101.4531 328.7382,-84.9965"/>
<polygon fill="#000000" stroke="#000000" points="332.2383,-84.75 328.7382,-74.75 325.2383,-84.75 332.2383,-84.75"/>
</g>
<!-- VAC -->
<g id="node11" class="node">
<title>VAC</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="463.4742" cy="-164" rx="39.2066" ry="41.0911"/>
<text text-anchor="middle" x="463.4742" y="-176.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text>
<text text-anchor="middle" x="463.4742" y="-159.8" font-family="Times,serif" font-size="14.00" fill="#000000">Audio</text>
<text text-anchor="middle" x="463.4742" y="-143" font-family="Times,serif" font-size="14.00" fill="#000000">Cable</text>
</g>
<!-- AVR&#45;&gt;VAC -->
<g id="edge12" class="edge">
<title>AVR&#45;&gt;VAC</title>
<path fill="none" stroke="#000000" d="M370.9998,-164C384.6622,-164 399.9322,-164 414.0648,-164"/>
<polygon fill="#000000" stroke="#000000" points="414.1153,-167.5001 424.1152,-164 414.1152,-160.5001 414.1153,-167.5001"/>
</g>
<!-- SVR -->
<g id="node4" class="node">
<title>SVR</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-170" rx="48.6714" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-165.8" font-family="Times,serif" font-size="14.00" fill="#000000">SteamVR</text>
</g>
<!-- SVR&#45;&gt;AVR -->
<g id="edge5" class="edge">
<title>SVR&#45;&gt;AVR</title>
<path fill="none" stroke="#000000" d="M250.3034,-167.7145C258.7549,-167.3143 267.5869,-166.896 276.1488,-166.4905"/>
<polygon fill="#000000" stroke="#000000" points="276.5916,-169.9736 286.4148,-166.0044 276.2604,-162.9814 276.5916,-169.9736"/>
</g>
<!-- VRC -->
<g id="node5" class="node">
<title>VRC</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-206" rx="42.8751" ry="18"/>
<text text-anchor="middle" x="66.7294" y="-201.8" font-family="Times,serif" font-size="14.00" fill="#000000">VRChat</text>
</g>
<!-- VRC&#45;&gt;SVR -->
<g id="edge4" class="edge">
<title>VRC&#45;&gt;SVR</title>
<path fill="none" stroke="#000000" d="M102.9914,-196.3527C118.1616,-192.3167 136.0376,-187.5609 152.3981,-183.2082"/>
<polygon fill="#000000" stroke="#000000" points="153.5873,-186.5137 162.3513,-180.5602 151.7875,-179.749 153.5873,-186.5137"/>
</g>
<!-- DESK -->
<g id="node10" class="node">
<title>DESK</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-229" rx="43.4396" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-224.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text>
</g>
<!-- VRC&#45;&gt;DESK -->
<g id="edge10" class="edge">
<title>VRC&#45;&gt;DESK</title>
<path fill="none" stroke="#000000" d="M106.5966,-212.7764C120.7849,-215.188 136.9469,-217.9351 151.8865,-220.4745"/>
<polygon fill="#000000" stroke="#000000" points="151.5496,-223.9673 161.9947,-222.1926 152.7227,-217.0663 151.5496,-223.9673"/>
</g>
<!-- OBS -->
<g id="node6" class="node">
<title>OBS</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="328.7382" cy="-235" rx="29.6339" ry="18"/>
<text text-anchor="middle" x="328.7382" y="-230.8" font-family="Times,serif" font-size="14.00" fill="#000000">OBS</text>
</g>
<!-- VIRC -->
<g id="node7" class="node">
<title>VIRC</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="463.4742" cy="-241" rx="56.7561" ry="18"/>
<text text-anchor="middle" x="463.4742" y="-236.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualCam</text>
</g>
<!-- OBS&#45;&gt;VIRC -->
<g id="edge8" class="edge">
<title>OBS&#45;&gt;VIRC</title>
<path fill="none" stroke="#000000" d="M358.6405,-236.3316C370.0698,-236.8406 383.6086,-237.4435 397.0947,-238.044"/>
<polygon fill="#000000" stroke="#000000" points="397.2155,-241.5528 407.3614,-238.5012 397.527,-234.5597 397.2155,-241.5528"/>
</g>
<!-- GM -->
<g id="node8" class="node">
<title>GM</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="596.5569" cy="-197" rx="40.4098" ry="29.3315"/>
<text text-anchor="middle" x="596.5569" y="-201.2" font-family="Times,serif" font-size="14.00" fill="#000000">Google</text>
<text text-anchor="middle" x="596.5569" y="-184.4" font-family="Times,serif" font-size="14.00" fill="#000000">Meet</text>
</g>
<!-- VIRC&#45;&gt;GM -->
<g id="edge9" class="edge">
<title>VIRC&#45;&gt;GM</title>
<path fill="none" stroke="#000000" d="M503.043,-227.9177C517.7504,-223.0551 534.5739,-217.4929 549.8596,-212.4391"/>
<polygon fill="#000000" stroke="#000000" points="551.2489,-215.6662 559.6447,-209.204 549.0515,-209.02 551.2489,-215.6662"/>
</g>
<!-- SQ -->
<g id="node9" class="node">
<title>SQ</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-141" rx="50.9599" ry="18"/>
<text text-anchor="middle" x="66.7294" y="-136.8" font-family="Times,serif" font-size="14.00" fill="#000000">SideQuest</text>
</g>
<!-- SQ&#45;&gt;AVA -->
<g id="edge3" class="edge">
<title>SQ&#45;&gt;AVA</title>
<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"/>
<polygon fill="#000000" stroke="#000000" points="287.15,-66.3061 295.0628,-59.2607 284.4835,-59.8339 287.15,-66.3061"/>
</g>
<!-- SQ&#45;&gt;A -->
<g id="edge2" class="edge">
<title>SQ&#45;&gt;A</title>
<path fill="none" stroke="#000000" d="M90.6096,-124.9405C112.7736,-110.0351 145.9219,-87.7427 170.305,-71.3449"/>
<polygon fill="#000000" stroke="#000000" points="172.5102,-74.0798 178.8551,-65.595 168.6038,-68.2712 172.5102,-74.0798"/>
</g>
<!-- DESK&#45;&gt;OBS -->
<g id="edge11" class="edge">
<title>DESK&#45;&gt;OBS</title>
<path fill="none" stroke="#000000" d="M245.2909,-231.0481C259.3432,-231.7136 274.8677,-232.4488 288.6771,-233.1028"/>
<polygon fill="#000000" stroke="#000000" points="288.6958,-236.6075 298.8502,-233.5846 289.027,-229.6153 288.6958,-236.6075"/>
</g>
<!-- VAC&#45;&gt;GM -->
<g id="edge13" class="edge">
<title>VAC&#45;&gt;GM</title>
<path fill="none" stroke="#000000" d="M501.9672,-173.545C516.4509,-177.1364 533.1046,-181.266 548.3623,-185.0494"/>
<polygon fill="#000000" stroke="#000000" points="547.6019,-188.4668 558.1504,-187.4765 549.2867,-181.6725 547.6019,-188.4668"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.40.1 (20161225.0304)
-->
<!-- Title: G Pages: 1 -->
<svg width="671pt" height="332pt"
viewBox="0.00 0.00 670.88 332.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 328)">
<title>G</title>
<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-328 666.8816,-328 666.8816,4 -4,4"/>
<g id="clust1" class="cluster">
<title>cluster_0</title>
<polygon fill="#d3d3d3" stroke="#d3d3d3" points="150.8243,-8 150.8243,-131 525.6487,-131 525.6487,-8 150.8243,-8"/>
<text text-anchor="middle" x="338.2365" y="-114.4" font-family="Times,serif" font-size="14.00" fill="#000000">Quest</text>
</g>
<g id="clust2" class="cluster">
<title>cluster_1</title>
<polygon fill="#d3d3d3" stroke="#d3d3d3" points="8,-139 8,-316 654.8816,-316 654.8816,-139 8,-139"/>
<text text-anchor="middle" x="331.4408" y="-299.4" font-family="Times,serif" font-size="14.00" fill="#000000">PC</text>
</g>
<!-- VD -->
<g id="node1" class="node">
<title>VD</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="473.3439" cy="-63" rx="44.1104" ry="29.3315"/>
<text text-anchor="middle" x="473.3439" y="-67.2" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text>
<text text-anchor="middle" x="473.3439" y="-50.4" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text>
</g>
<!-- VDS -->
<g id="node4" class="node">
<title>VDS</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-188" rx="47.086" ry="41.0911"/>
<text text-anchor="middle" x="333.6731" y="-200.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text>
<text text-anchor="middle" x="333.6731" y="-183.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text>
<text text-anchor="middle" x="333.6731" y="-167" font-family="Times,serif" font-size="14.00" fill="#000000">Streamer</text>
</g>
<!-- VD&#45;&gt;VDS -->
<g id="edge4" class="edge">
<title>VD&#45;&gt;VDS</title>
<path fill="none" stroke="#000000" d="M450.736,-88.362C431.0544,-107.6122 401.9557,-134.0523 377.6943,-154.9249"/>
<polygon fill="#000000" stroke="#000000" points="375.3377,-152.3348 370.0053,-161.4899 379.8831,-157.6583 375.3377,-152.3348"/>
</g>
<!-- VDM -->
<g id="node2" class="node">
<title>VDM</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-57" rx="45.275" ry="41.0911"/>
<text text-anchor="middle" x="333.6731" y="-69.6" font-family="Times,serif" font-size="14.00" fill="#000000">Virtual</text>
<text text-anchor="middle" x="333.6731" y="-52.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text>
<text text-anchor="middle" x="333.6731" y="-36" font-family="Times,serif" font-size="14.00" fill="#000000">VR mod</text>
</g>
<!-- VDM&#45;&gt;VD -->
<g id="edge3" class="edge">
<title>VDM&#45;&gt;VD</title>
<path fill="none" stroke="#000000" d="M379.0202,-58.948C391.5906,-59.488 405.3731,-60.0801 418.4262,-60.6408"/>
<polygon fill="#000000" stroke="#000000" points="418.5601,-64.1497 428.7011,-61.0822 418.8606,-57.1562 418.5601,-64.1497"/>
</g>
<!-- A -->
<g id="node3" class="node">
<title>A</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-68" rx="43.4415" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-63.8" font-family="Times,serif" font-size="14.00" fill="#000000">Android</text>
</g>
<!-- A&#45;&gt;VDM -->
<g id="edge2" class="edge">
<title>A&#45;&gt;VDM</title>
<path fill="none" stroke="#000000" d="M244.7805,-64.4286C255.4706,-63.5353 267.0909,-62.5642 278.2968,-61.6277"/>
<polygon fill="#000000" stroke="#000000" points="278.7592,-65.1014 288.433,-60.7806 278.1762,-58.1257 278.7592,-65.1014"/>
</g>
<!-- VDS&#45;&gt;VD -->
<g id="edge5" class="edge">
<title>VDS&#45;&gt;VD</title>
<path fill="none" stroke="#000000" d="M363.2937,-155.8547C384.2099,-135.824 412.4271,-110.4172 435.0521,-91.1733"/>
<polygon fill="#000000" stroke="#000000" points="437.4099,-93.7634 442.8005,-84.6424 432.8986,-88.411 437.4099,-93.7634"/>
</g>
<!-- GM -->
<g id="node9" class="node">
<title>GM</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="606.4267" cy="-216" rx="40.4098" ry="29.3315"/>
<text text-anchor="middle" x="606.4267" y="-220.2" font-family="Times,serif" font-size="14.00" fill="#000000">Google</text>
<text text-anchor="middle" x="606.4267" y="-203.4" font-family="Times,serif" font-size="14.00" fill="#000000">Meet</text>
</g>
<!-- VDS&#45;&gt;GM -->
<g id="edge6" class="edge">
<title>VDS&#45;&gt;GM</title>
<path fill="none" stroke="#000000" d="M380.5611,-192.8134C429.5797,-197.8455 506.2147,-205.7126 556.3811,-210.8625"/>
<polygon fill="#000000" stroke="#000000" points="556.0498,-214.3468 566.355,-211.8864 556.7647,-207.3834 556.0498,-214.3468"/>
</g>
<!-- SVR -->
<g id="node5" class="node">
<title>SVR</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-188" rx="48.6714" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-183.8" font-family="Times,serif" font-size="14.00" fill="#000000">SteamVR</text>
</g>
<!-- SVR&#45;&gt;VDS -->
<g id="edge10" class="edge">
<title>SVR&#45;&gt;VDS</title>
<path fill="none" stroke="#000000" d="M250.6841,-188C259.0146,-188 267.7397,-188 276.273,-188"/>
<polygon fill="#000000" stroke="#000000" points="276.5472,-191.5001 286.5471,-188 276.5471,-184.5001 276.5472,-191.5001"/>
</g>
<!-- VRC -->
<g id="node6" class="node">
<title>VRC</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-230" rx="42.8751" ry="18"/>
<text text-anchor="middle" x="66.7294" y="-225.8" font-family="Times,serif" font-size="14.00" fill="#000000">VRChat</text>
</g>
<!-- VRC&#45;&gt;SVR -->
<g id="edge7" class="edge">
<title>VRC&#45;&gt;SVR</title>
<path fill="none" stroke="#000000" d="M101.2253,-219.293C117.6099,-214.2074 137.4417,-208.0518 155.1663,-202.5504"/>
<polygon fill="#000000" stroke="#000000" points="156.2483,-205.8793 164.7613,-199.5722 154.1732,-199.194 156.2483,-205.8793"/>
</g>
<!-- DESK -->
<g id="node11" class="node">
<title>DESK</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="202.0445" cy="-242" rx="43.4396" ry="18"/>
<text text-anchor="middle" x="202.0445" y="-237.8" font-family="Times,serif" font-size="14.00" fill="#000000">Desktop</text>
</g>
<!-- VRC&#45;&gt;DESK -->
<g id="edge12" class="edge">
<title>VRC&#45;&gt;DESK</title>
<path fill="none" stroke="#000000" d="M108.8022,-233.7311C121.6615,-234.8715 135.9668,-236.1401 149.4342,-237.3344"/>
<polygon fill="#000000" stroke="#000000" points="149.2616,-240.8328 159.5317,-238.2299 149.88,-233.8601 149.2616,-240.8328"/>
</g>
<!-- OBS -->
<g id="node7" class="node">
<title>OBS</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="333.6731" cy="-265" rx="29.6339" ry="18"/>
<text text-anchor="middle" x="333.6731" y="-260.8" font-family="Times,serif" font-size="14.00" fill="#000000">OBS</text>
</g>
<!-- VIRC -->
<g id="node8" class="node">
<title>VIRC</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="473.3439" cy="-255" rx="56.7561" ry="18"/>
<text text-anchor="middle" x="473.3439" y="-250.8" font-family="Times,serif" font-size="14.00" fill="#000000">VirtualCam</text>
</g>
<!-- OBS&#45;&gt;VIRC -->
<g id="edge8" class="edge">
<title>OBS&#45;&gt;VIRC</title>
<path fill="none" stroke="#000000" d="M363.2937,-262.8793C376.2998,-261.9481 392.129,-260.8147 407.6812,-259.7012"/>
<polygon fill="#000000" stroke="#000000" points="408.1043,-263.18 417.8288,-258.9747 407.6044,-256.1979 408.1043,-263.18"/>
</g>
<!-- VIRC&#45;&gt;GM -->
<g id="edge9" class="edge">
<title>VIRC&#45;&gt;GM</title>
<path fill="none" stroke="#000000" d="M515.087,-242.7672C529.0844,-238.6652 544.7902,-234.0626 559.1786,-229.8461"/>
<polygon fill="#000000" stroke="#000000" points="560.28,-233.1706 568.8921,-226.9995 558.3114,-226.4531 560.28,-233.1706"/>
</g>
<!-- SQ -->
<g id="node10" class="node">
<title>SQ</title>
<ellipse fill="#ffffff" stroke="#ffffff" cx="66.7294" cy="-165" rx="50.9599" ry="18"/>
<text text-anchor="middle" x="66.7294" y="-160.8" font-family="Times,serif" font-size="14.00" fill="#000000">SideQuest</text>
</g>
<!-- SQ&#45;&gt;A -->
<g id="edge1" class="edge">
<title>SQ&#45;&gt;A</title>
<path fill="none" stroke="#000000" d="M89.3781,-148.7644C111.9913,-132.5542 146.8811,-107.5436 171.8411,-89.6512"/>
<polygon fill="#000000" stroke="#000000" points="174.1309,-92.3162 180.2192,-83.6453 170.0526,-86.6269 174.1309,-92.3162"/>
</g>
<!-- DESK&#45;&gt;VDS -->
<g id="edge11" class="edge">
<title>DESK&#45;&gt;VDS</title>
<path fill="none" stroke="#000000" d="M232.9056,-229.3394C247.3882,-223.3979 265.0521,-216.1514 281.5218,-209.3948"/>
<polygon fill="#000000" stroke="#000000" points="283.1245,-212.5204 291.0478,-205.4868 280.4677,-206.0442 283.1245,-212.5204"/>
</g>
<!-- DESK&#45;&gt;OBS -->
<g id="edge13" class="edge">
<title>DESK&#45;&gt;OBS</title>
<path fill="none" stroke="#000000" d="M242.2526,-249.0257C259.0321,-251.9577 278.4424,-255.3493 295.05,-258.2512"/>
<polygon fill="#000000" stroke="#000000" points="294.5265,-261.7127 304.9797,-259.9863 295.7315,-254.8172 294.5265,-261.7127"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB