From 1efa6a95a1831dceb953cd819de09d3cec28b933 Mon Sep 17 00:00:00 2001 From: Danny McGee Date: Thu, 4 Apr 2024 15:47:16 -0400 Subject: [PATCH] Debugging window/viewport scaling issues --- studio-web/src/lib/studio.element.ts | 3 +- studio/src/scene/mod.rs | 23 +++++++++++-- studio/src/viewport.rs | 50 ++++++++++++---------------- studio/src/wasm/init.rs | 45 +++++++++++++++++++------ 4 files changed, 79 insertions(+), 42 deletions(-) diff --git a/studio-web/src/lib/studio.element.ts b/studio-web/src/lib/studio.element.ts index 2759275..2b189dd 100644 --- a/studio-web/src/lib/studio.element.ts +++ b/studio-web/src/lib/studio.element.ts @@ -64,7 +64,7 @@ export class StudioElement extends LitElement { #onResize(): void { const { width, height } = this.getBoundingClientRect(); - studio.resize(new ViewportSize(width, height)); + studio.resize(new ViewportSize(width, height), window.devicePixelRatio); this.dispatchEvent(new CustomEvent("viewport-resized", { detail: { width, height }, @@ -83,6 +83,7 @@ export class StudioElement extends LitElement { canvasSelector: `#${this._canvasProvider?.canvasId}`, canvasAlt: "Storyteller Studio", viewportSize: new ViewportSize(width, height), + scaleFactor: window.devicePixelRatio, }; try { diff --git a/studio/src/scene/mod.rs b/studio/src/scene/mod.rs index 7e24e74..0a5e2e3 100644 --- a/studio/src/scene/mod.rs +++ b/studio/src/scene/mod.rs @@ -10,9 +10,13 @@ use bevy::{ math::vec2, pbr::ShadowFilteringMethod, prelude::*, - render::{camera::RenderTarget, primitives::Aabb}, + render::{ + camera::{RenderTarget, Viewport}, + primitives::Aabb, + }, scene::InstanceId, utils::HashSet, + window::PrimaryWindow, }; #[cfg(feature = "wasm")] use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -310,11 +314,19 @@ pub struct SceneData { #[derive(Component)] pub struct SceneRoot; -fn initialize(mut cmd: Commands) { +fn initialize(mut cmd: Commands, q_window: Query<&Window, With>) { // Camera, graphics settings let focus = Vec3::ZERO; let camera_xform = Transform::from_xyz(-2.5, 4.5, 5.0).looking_at(focus, Vec3::Y); + let window = q_window.single(); + info!( + "Window: ({:.2} x {:.2}) [{:.2}]", + window.width(), + window.height(), + window.scale_factor(), + ); + cmd.spawn(( Name::new("Main Camera"), MainCamera, @@ -325,6 +337,13 @@ fn initialize(mut cmd: Commands) { tonemapping: Tonemapping::BlenderFilmic, camera: Camera { hdr: true, + viewport: Some(Viewport { + physical_size: UVec2::new( + (window.width() * window.scale_factor()) as u32, + (window.height() * window.scale_factor()) as u32, + ), + ..default() + }), ..default() }, ..default() diff --git a/studio/src/viewport.rs b/studio/src/viewport.rs index 735928a..15bf799 100644 --- a/studio/src/viewport.rs +++ b/studio/src/viewport.rs @@ -1,6 +1,5 @@ use core::fmt; -use bevy::window::WindowResolution; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -21,21 +20,9 @@ impl ViewportSize { impl Default for ViewportSize { fn default() -> Self { - WindowResolution::default().into() - } -} - -impl From for WindowResolution { - fn from(value: ViewportSize) -> Self { - Self::new(value.width, value.height) - } -} - -impl From for ViewportSize { - fn from(value: WindowResolution) -> Self { Self { - width: value.width(), - height: value.height(), + width: 1280., + height: 720., } } } @@ -58,11 +45,11 @@ pub mod wasm { use super::ViewportSize; - static RESIZE_BUF: WasmMessageBuffer = WasmMessageBuffer::new(); + static RESIZE_BUF: WasmMessageBuffer<(ViewportSize, f32)> = WasmMessageBuffer::new(); #[wasm_bindgen] - pub fn resize(viewport_size: ViewportSize) { - RESIZE_BUF.write_message(viewport_size); + pub fn resize(viewport_size: ViewportSize, scale_factor: f32) { + RESIZE_BUF.write_message((viewport_size, scale_factor)); } pub struct ViewportPlugin; @@ -77,30 +64,37 @@ pub mod wasm { } #[derive(Event, Clone, Copy)] - struct ViewportResizeEvent(ViewportSize); + struct ViewportResizeEvent { + pub size: ViewportSize, + pub scale_factor: f32, + } fn sync_window_to_viewport( mut events: EventReader, mut window: Query<&mut Window>, mut q_camera: Query<&mut Camera, With>, ) { - if let Some(event) = events.read().last() { - let ViewportSize { width, height } = event.0; - window.single_mut().resolution.set(width, height); + if let Some(ViewportResizeEvent { size, scale_factor }) = events.read().last() { + let ViewportSize { width, height } = size; + + window.single_mut().resolution.set(*width, *height); q_camera.single_mut().viewport = Some(Viewport { - physical_size: UVec2::new(width as u32, height as u32), + physical_size: UVec2::new( + (width * scale_factor) as u32, + (height * scale_factor) as u32, + ), ..Default::default() }); - info!("Viewport size: ({:.2}, {:.2})", width, height); + info!("Viewport size: ({width:.2}, {height:.2}) [{scale_factor:.2}]"); } } fn dispatch_resize_events(mut events: EventWriter) { - if let Some(resize) = RESIZE_BUF.take_message() { - events.send(ViewportResizeEvent(resize)); + if let Some((size, scale_factor)) = RESIZE_BUF.take_message() { + events.send(ViewportResizeEvent { size, scale_factor }); info!( - "Dispatch Viewport size: ({:.2}, {:.2})", - resize.width, resize.height + "Dispatch Viewport size: ({:.2}, {:.2}) [{scale_factor:.2}]", + size.width, size.height, ); } } diff --git a/studio/src/wasm/init.rs b/studio/src/wasm/init.rs index c3850f1..f3bdf8d 100644 --- a/studio/src/wasm/init.rs +++ b/studio/src/wasm/init.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{prelude::*, window::WindowResolution}; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -13,6 +13,7 @@ export interface InitOptions { canvasSelector: string; canvasAlt: string; viewportSize: ViewportSize; + scaleFactor: number; } export function initFromLibrary(objectId: string, options: InitOptions): void; @@ -22,26 +23,28 @@ export function initFromSceneImport(scenePath: string, options: InitOptions): vo export function initFromStorytellerScene(scenePath: string, options: InitOptions): void; "#; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] struct WasmInitOptions { - #[serde(rename = "skyboxId")] skybox_id: Option, mode: StudioMode, - #[serde(rename = "canvasSelector")] canvas_selector: String, - #[serde(rename = "canvasAlt")] canvas_alt: String, - #[serde(rename = "viewportSize")] viewport_size: ViewportSize, + scale_factor: f32, } #[wasm_bindgen(skip_typescript, js_name = initFromLibrary)] pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsValue> { let options = serde_wasm_bindgen::from_value::(options)?; + info!("wasm::init_from_library: {object_id} {options:#?}"); + let skybox_id = options .skybox_id .expect("`skyboxId` is required for `initFromLibrary`"); + let ViewportSize { width, height } = options.viewport_size; + crate::start( InitParams::FromAsset { asset: InitAsset::LibraryObject(object_id), @@ -49,7 +52,8 @@ pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsVa }, options.mode, Some(Window { - resolution: options.viewport_size.into(), + resolution: WindowResolution::new(width, height) + .with_scale_factor_override(options.scale_factor), title: options.canvas_alt, canvas: Some(options.canvas_selector), ..default() @@ -63,10 +67,14 @@ pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsVa #[wasm_bindgen(skip_typescript, js_name = initFromBvh)] pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue> { let options = serde_wasm_bindgen::from_value::(options)?; + info!("wasm::init_from_bvh: {anim_path} {options:#?}"); + let skybox_id = options .skybox_id .expect("`skyboxId` is required for `initFromBvh`"); + let ViewportSize { width, height } = options.viewport_size; + crate::start( InitParams::FromAsset { asset: InitAsset::BvhAnim(anim_path), @@ -74,7 +82,8 @@ pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue> }, options.mode, Some(Window { - resolution: options.viewport_size.into(), + resolution: WindowResolution::new(width, height) + .with_scale_factor_override(options.scale_factor), title: options.canvas_alt, canvas: Some(options.canvas_selector), ..default() @@ -88,10 +97,14 @@ pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue> #[wasm_bindgen(skip_typescript, js_name = initFromMixamo)] pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsValue> { let options = serde_wasm_bindgen::from_value::(options)?; + info!("wasm::init_from_mixamo: {anim_path} {options:#?}"); + let skybox_id = options .skybox_id .expect("`skyboxId` is required for `initFromMixamo`"); + let ViewportSize { width, height } = options.viewport_size; + crate::start( InitParams::FromAsset { asset: InitAsset::MixamoAnim(anim_path), @@ -99,7 +112,8 @@ pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsVal }, options.mode, Some(Window { - resolution: options.viewport_size.into(), + resolution: WindowResolution::new(width, height) + .with_scale_factor_override(options.scale_factor), title: options.canvas_alt, canvas: Some(options.canvas_selector), ..default() @@ -113,10 +127,14 @@ pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsVal #[wasm_bindgen(skip_typescript, js_name = initFromSceneImport)] pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<(), JsValue> { let options = serde_wasm_bindgen::from_value::(options)?; + info!("wasm::init_from_scene_import: {scene_path} {options:#?}"); + let skybox_id = options .skybox_id .expect("`skyboxId` is required for `initFromSceneImport`"); + let ViewportSize { width, height } = options.viewport_size; + crate::start( InitParams::FromAsset { asset: InitAsset::ImportedScene(scene_path), @@ -124,7 +142,8 @@ pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<() }, options.mode, Some(Window { - resolution: options.viewport_size.into(), + resolution: WindowResolution::new(width, height) + .with_scale_factor_override(options.scale_factor), title: options.canvas_alt, canvas: Some(options.canvas_selector), ..default() @@ -138,12 +157,16 @@ pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<() #[wasm_bindgen(skip_typescript, js_name = initFromStorytellerScene)] pub fn init_from_storyteller_scene(scene_path: String, options: JsValue) -> Result<(), JsValue> { let options = serde_wasm_bindgen::from_value::(options)?; + info!("wasm::init_from_storyteller_scene: {scene_path} {options:#?}"); + + let ViewportSize { width, height } = options.viewport_size; crate::start( InitParams::FromScene(scene_path), options.mode, Some(Window { - resolution: options.viewport_size.into(), + resolution: WindowResolution::new(width, height) + .with_scale_factor_override(options.scale_factor), title: options.canvas_alt, canvas: Some(options.canvas_selector), ..default()