mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
Debugging window/viewport scaling issues
This commit is contained in:
@@ -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 {
|
||||
|
||||
+21
-2
@@ -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<PrimaryWindow>>) {
|
||||
// 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()
|
||||
|
||||
+22
-28
@@ -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<ViewportSize> for WindowResolution {
|
||||
fn from(value: ViewportSize) -> Self {
|
||||
Self::new(value.width, value.height)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WindowResolution> 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<ViewportSize> = 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<ViewportResizeEvent>,
|
||||
mut window: Query<&mut Window>,
|
||||
mut q_camera: Query<&mut Camera, With<MainCamera>>,
|
||||
) {
|
||||
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<ViewportResizeEvent>) {
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+34
-11
@@ -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<String>,
|
||||
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::<WasmInitOptions>(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::<WasmInitOptions>(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::<WasmInitOptions>(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::<WasmInitOptions>(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::<WasmInitOptions>(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()
|
||||
|
||||
Reference in New Issue
Block a user