Yellow-Dog-Man / Resonite-Issues

Issue repository for Resonite.
https://resonite.com
135 stars 2 forks source link

FOV of default stream camera is not in sync when spawned even though it is driven by same value. #1536

Open mpmxyz opened 6 months ago

mpmxyz commented 6 months ago

Describe the bug?

A freshly spawned stream camera shows different previews for the spawning user and everyone else. The driven FOV value of the camera has not been updated to match the value of its source for the user who spawned the camera.

To Reproduce

  1. Be in a session with another user.
  2. Spawn the camera using "Camera/Streaming" in the dashboard
  3. Set camera mode "Manual", enable "Render Preview For Everyone"
  4. Align an object in front of the camera so that it touches the edge of the preview image.
  5. Compare what you see with the other user.
  6. Compare the driven FOV value of the internally used camera component with the other user.

Expected behavior

The FOV setting should be equal for both users from the start. ValueCopy should not fail to copy a value.

Screenshots

Spawning user: Cam_Self_View Others: Cam_Other_View Spawning user: Cam_Self_Inspector_1 Others: Cam_Other_Inspector_1 Spawning user: Cam_Self_Inspector_2 Others: Cam_Other_Inspector_2

Resonite Version Number

2024.3.12.1169

What Platforms does this occur on?

Windows

What headset if any do you use?

Varjo Aero

Log Files

ANONYMOUS - 2024.3.12.1169 - 2024-03-24 20_22_27.log Note: The log file does not match the screenshots since the world I took them in bloated the logfile with unrelated error messages.

Additional Context

No response

Reporters

Discovered together with @JackTheFoxOtter and replicated with 30 seconds of assistance from Nordwick. (for the simplified log recording)

shiftyscales commented 6 months ago

I believe this to be a content issue in how the FOV slider was implemented. I didn't need other users in the session to observe a discrepancy between the camera's FOV on the camera component compared to the interface/boolean value driver component.

When the camera is spawned out from the camera control panel- the control panel and its slider controls the FOV. Previously there was a similar related bug I'd mentioned in this comment where the camera FOV was previously being driven without writeback causing the camera control panel to be unable to control the FOV because it was being driven.

I'd recommend the content team to modify this portion of the camera's functionality by making use of writes instead of drives, or otherwise adding a mechanism to fetch the camera's FOV and write it back to the slider when the values don't match. The reason this is probably happening is because when the stream camera is being saved by the content team- it has a particular FOV it was saved at which is different to whatever the user might have set in their camera control panel.

By writing from the camera component's FOV value back to the slider/interface, this should ensure these values stay in sync.

JackTheFoxOtter commented 6 months ago

Hello! Since I was working on a modified version of the default camera and this bug got in my way, I found a suitable fix for it, and thought I'd share it here so it can be integrated into the official camera as well.

Deep dive into the problem: There are two ways of changing the FOV on the default camera, either using the UIX slider on the viewport display, or using the slider on the Interactive Camera Control Panel in userspace. The latter causes the updated value to be directly written into the FOV field on the main / secondary Camera components, which is handled by the InteractiveCamera component.

The issue arrises through the way this value is processed. The default camera has a feature to automatically adjust the FOV when you switch from portrait to landscape mode. The way this is implemented is using a BooleanValueDriver on the "MainCamera" slot. Since BooleanValueDriver doesn't support writeback functionality however, its output is first driven into a ValueField, which is when copied using ValueCopy with writeback enabled into the FOV field on the Camera component.

When the FOV is changed by the InteractiveCamera component, it directly updates the driven FOV value on the Camera component, which works, since that drive has writeback enabled. This writeback fails however, since the source field is the one driven by the BooleanValueDriver, which doesn't support writeback. This causes the value of the FOV field to be a different one than the value in the value field it's driven from, which does originate (after some conversion) from the value field of the UIX slider component, which is the only non-driven field in the chain, and therefore the only one that's networked. Since that value never changes, updating the FOV through the Interactive Camera control panel doesn't actually result in the updated value being networked to other clients.

My solution: I've tried a couple different approaches to resolve this issue without harming functionality of the default camera or introducing unwanted delay / network conflicts which would result in glitchy zooming behavior. The solution I came up with is implementing the aspect ratio based FOV switching entirely in ProtoFlux, using FieldHook to enable write-back functionality. This results in a little bit additional complexity, since the aspect ratio FOV determination math needs to be undone on writeback, since this is a pretty simple operation however I don't think that ends up being a problem.

This solution preserves all of the functionality of the default camera, resolves the synchronization problem (since the synchronized value - the one on the UIX slider - is properly updated to reflect the new value the FOV is changed directly on the Camera component), and also has the added benefit of making the frame-delay between updating the value in the interactive camera control dialog identical to the one when changing the value on the UIX canvas directly, which wasn't the case with the previous solution. I also think it's a bit more readable.

My code if you want to use it (I can also give it to you in-game if you poke me): 20240331153338_1