mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-29 09:08:58 +00:00
Debugging window/viewport scaling issues
This commit is contained in:
@@ -64,7 +64,7 @@ export class StudioElement extends LitElement {
|
|||||||
#onResize(): void {
|
#onResize(): void {
|
||||||
const { width, height } = this.getBoundingClientRect();
|
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", {
|
this.dispatchEvent(new CustomEvent("viewport-resized", {
|
||||||
detail: { width, height },
|
detail: { width, height },
|
||||||
@@ -83,6 +83,7 @@ export class StudioElement extends LitElement {
|
|||||||
canvasSelector: `#${this._canvasProvider?.canvasId}`,
|
canvasSelector: `#${this._canvasProvider?.canvasId}`,
|
||||||
canvasAlt: "Storyteller Studio",
|
canvasAlt: "Storyteller Studio",
|
||||||
viewportSize: new ViewportSize(width, height),
|
viewportSize: new ViewportSize(width, height),
|
||||||
|
scaleFactor: window.devicePixelRatio,
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+21
-2
@@ -10,9 +10,13 @@ use bevy::{
|
|||||||
math::vec2,
|
math::vec2,
|
||||||
pbr::ShadowFilteringMethod,
|
pbr::ShadowFilteringMethod,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
render::{camera::RenderTarget, primitives::Aabb},
|
render::{
|
||||||
|
camera::{RenderTarget, Viewport},
|
||||||
|
primitives::Aabb,
|
||||||
|
},
|
||||||
scene::InstanceId,
|
scene::InstanceId,
|
||||||
utils::HashSet,
|
utils::HashSet,
|
||||||
|
window::PrimaryWindow,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "wasm")]
|
#[cfg(feature = "wasm")]
|
||||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
@@ -310,11 +314,19 @@ pub struct SceneData {
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct SceneRoot;
|
pub struct SceneRoot;
|
||||||
|
|
||||||
fn initialize(mut cmd: Commands) {
|
fn initialize(mut cmd: Commands, q_window: Query<&Window, With<PrimaryWindow>>) {
|
||||||
// Camera, graphics settings
|
// Camera, graphics settings
|
||||||
let focus = Vec3::ZERO;
|
let focus = Vec3::ZERO;
|
||||||
let camera_xform = Transform::from_xyz(-2.5, 4.5, 5.0).looking_at(focus, Vec3::Y);
|
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((
|
cmd.spawn((
|
||||||
Name::new("Main Camera"),
|
Name::new("Main Camera"),
|
||||||
MainCamera,
|
MainCamera,
|
||||||
@@ -325,6 +337,13 @@ fn initialize(mut cmd: Commands) {
|
|||||||
tonemapping: Tonemapping::BlenderFilmic,
|
tonemapping: Tonemapping::BlenderFilmic,
|
||||||
camera: Camera {
|
camera: Camera {
|
||||||
hdr: true,
|
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()
|
||||||
},
|
},
|
||||||
..default()
|
..default()
|
||||||
|
|||||||
+22
-28
@@ -1,6 +1,5 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use bevy::window::WindowResolution;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
@@ -21,21 +20,9 @@ impl ViewportSize {
|
|||||||
|
|
||||||
impl Default for ViewportSize {
|
impl Default for ViewportSize {
|
||||||
fn default() -> Self {
|
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 {
|
Self {
|
||||||
width: value.width(),
|
width: 1280.,
|
||||||
height: value.height(),
|
height: 720.,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,11 +45,11 @@ pub mod wasm {
|
|||||||
|
|
||||||
use super::ViewportSize;
|
use super::ViewportSize;
|
||||||
|
|
||||||
static RESIZE_BUF: WasmMessageBuffer<ViewportSize> = WasmMessageBuffer::new();
|
static RESIZE_BUF: WasmMessageBuffer<(ViewportSize, f32)> = WasmMessageBuffer::new();
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn resize(viewport_size: ViewportSize) {
|
pub fn resize(viewport_size: ViewportSize, scale_factor: f32) {
|
||||||
RESIZE_BUF.write_message(viewport_size);
|
RESIZE_BUF.write_message((viewport_size, scale_factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ViewportPlugin;
|
pub struct ViewportPlugin;
|
||||||
@@ -77,30 +64,37 @@ pub mod wasm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Event, Clone, Copy)]
|
#[derive(Event, Clone, Copy)]
|
||||||
struct ViewportResizeEvent(ViewportSize);
|
struct ViewportResizeEvent {
|
||||||
|
pub size: ViewportSize,
|
||||||
|
pub scale_factor: f32,
|
||||||
|
}
|
||||||
|
|
||||||
fn sync_window_to_viewport(
|
fn sync_window_to_viewport(
|
||||||
mut events: EventReader<ViewportResizeEvent>,
|
mut events: EventReader<ViewportResizeEvent>,
|
||||||
mut window: Query<&mut Window>,
|
mut window: Query<&mut Window>,
|
||||||
mut q_camera: Query<&mut Camera, With<MainCamera>>,
|
mut q_camera: Query<&mut Camera, With<MainCamera>>,
|
||||||
) {
|
) {
|
||||||
if let Some(event) = events.read().last() {
|
if let Some(ViewportResizeEvent { size, scale_factor }) = events.read().last() {
|
||||||
let ViewportSize { width, height } = event.0;
|
let ViewportSize { width, height } = size;
|
||||||
window.single_mut().resolution.set(width, height);
|
|
||||||
|
window.single_mut().resolution.set(*width, *height);
|
||||||
q_camera.single_mut().viewport = Some(Viewport {
|
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()
|
..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>) {
|
fn dispatch_resize_events(mut events: EventWriter<ViewportResizeEvent>) {
|
||||||
if let Some(resize) = RESIZE_BUF.take_message() {
|
if let Some((size, scale_factor)) = RESIZE_BUF.take_message() {
|
||||||
events.send(ViewportResizeEvent(resize));
|
events.send(ViewportResizeEvent { size, scale_factor });
|
||||||
info!(
|
info!(
|
||||||
"Dispatch Viewport size: ({:.2}, {:.2})",
|
"Dispatch Viewport size: ({:.2}, {:.2}) [{scale_factor:.2}]",
|
||||||
resize.width, resize.height
|
size.width, size.height,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-11
@@ -1,4 +1,4 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, window::WindowResolution};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ export interface InitOptions {
|
|||||||
canvasSelector: string;
|
canvasSelector: string;
|
||||||
canvasAlt: string;
|
canvasAlt: string;
|
||||||
viewportSize: ViewportSize;
|
viewportSize: ViewportSize;
|
||||||
|
scaleFactor: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initFromLibrary(objectId: string, options: InitOptions): void;
|
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;
|
export function initFromStorytellerScene(scenePath: string, options: InitOptions): void;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
struct WasmInitOptions {
|
struct WasmInitOptions {
|
||||||
#[serde(rename = "skyboxId")]
|
|
||||||
skybox_id: Option<String>,
|
skybox_id: Option<String>,
|
||||||
mode: StudioMode,
|
mode: StudioMode,
|
||||||
#[serde(rename = "canvasSelector")]
|
|
||||||
canvas_selector: String,
|
canvas_selector: String,
|
||||||
#[serde(rename = "canvasAlt")]
|
|
||||||
canvas_alt: String,
|
canvas_alt: String,
|
||||||
#[serde(rename = "viewportSize")]
|
|
||||||
viewport_size: ViewportSize,
|
viewport_size: ViewportSize,
|
||||||
|
scale_factor: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen(skip_typescript, js_name = initFromLibrary)]
|
#[wasm_bindgen(skip_typescript, js_name = initFromLibrary)]
|
||||||
pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsValue> {
|
pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsValue> {
|
||||||
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
||||||
|
info!("wasm::init_from_library: {object_id} {options:#?}");
|
||||||
|
|
||||||
let skybox_id = options
|
let skybox_id = options
|
||||||
.skybox_id
|
.skybox_id
|
||||||
.expect("`skyboxId` is required for `initFromLibrary`");
|
.expect("`skyboxId` is required for `initFromLibrary`");
|
||||||
|
|
||||||
|
let ViewportSize { width, height } = options.viewport_size;
|
||||||
|
|
||||||
crate::start(
|
crate::start(
|
||||||
InitParams::FromAsset {
|
InitParams::FromAsset {
|
||||||
asset: InitAsset::LibraryObject(object_id),
|
asset: InitAsset::LibraryObject(object_id),
|
||||||
@@ -49,7 +52,8 @@ pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsVa
|
|||||||
},
|
},
|
||||||
options.mode,
|
options.mode,
|
||||||
Some(Window {
|
Some(Window {
|
||||||
resolution: options.viewport_size.into(),
|
resolution: WindowResolution::new(width, height)
|
||||||
|
.with_scale_factor_override(options.scale_factor),
|
||||||
title: options.canvas_alt,
|
title: options.canvas_alt,
|
||||||
canvas: Some(options.canvas_selector),
|
canvas: Some(options.canvas_selector),
|
||||||
..default()
|
..default()
|
||||||
@@ -63,10 +67,14 @@ pub fn init_from_library(object_id: String, options: JsValue) -> Result<(), JsVa
|
|||||||
#[wasm_bindgen(skip_typescript, js_name = initFromBvh)]
|
#[wasm_bindgen(skip_typescript, js_name = initFromBvh)]
|
||||||
pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue> {
|
pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue> {
|
||||||
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
||||||
|
info!("wasm::init_from_bvh: {anim_path} {options:#?}");
|
||||||
|
|
||||||
let skybox_id = options
|
let skybox_id = options
|
||||||
.skybox_id
|
.skybox_id
|
||||||
.expect("`skyboxId` is required for `initFromBvh`");
|
.expect("`skyboxId` is required for `initFromBvh`");
|
||||||
|
|
||||||
|
let ViewportSize { width, height } = options.viewport_size;
|
||||||
|
|
||||||
crate::start(
|
crate::start(
|
||||||
InitParams::FromAsset {
|
InitParams::FromAsset {
|
||||||
asset: InitAsset::BvhAnim(anim_path),
|
asset: InitAsset::BvhAnim(anim_path),
|
||||||
@@ -74,7 +82,8 @@ pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue>
|
|||||||
},
|
},
|
||||||
options.mode,
|
options.mode,
|
||||||
Some(Window {
|
Some(Window {
|
||||||
resolution: options.viewport_size.into(),
|
resolution: WindowResolution::new(width, height)
|
||||||
|
.with_scale_factor_override(options.scale_factor),
|
||||||
title: options.canvas_alt,
|
title: options.canvas_alt,
|
||||||
canvas: Some(options.canvas_selector),
|
canvas: Some(options.canvas_selector),
|
||||||
..default()
|
..default()
|
||||||
@@ -88,10 +97,14 @@ pub fn init_from_bvh(anim_path: String, options: JsValue) -> Result<(), JsValue>
|
|||||||
#[wasm_bindgen(skip_typescript, js_name = initFromMixamo)]
|
#[wasm_bindgen(skip_typescript, js_name = initFromMixamo)]
|
||||||
pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsValue> {
|
pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsValue> {
|
||||||
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
||||||
|
info!("wasm::init_from_mixamo: {anim_path} {options:#?}");
|
||||||
|
|
||||||
let skybox_id = options
|
let skybox_id = options
|
||||||
.skybox_id
|
.skybox_id
|
||||||
.expect("`skyboxId` is required for `initFromMixamo`");
|
.expect("`skyboxId` is required for `initFromMixamo`");
|
||||||
|
|
||||||
|
let ViewportSize { width, height } = options.viewport_size;
|
||||||
|
|
||||||
crate::start(
|
crate::start(
|
||||||
InitParams::FromAsset {
|
InitParams::FromAsset {
|
||||||
asset: InitAsset::MixamoAnim(anim_path),
|
asset: InitAsset::MixamoAnim(anim_path),
|
||||||
@@ -99,7 +112,8 @@ pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsVal
|
|||||||
},
|
},
|
||||||
options.mode,
|
options.mode,
|
||||||
Some(Window {
|
Some(Window {
|
||||||
resolution: options.viewport_size.into(),
|
resolution: WindowResolution::new(width, height)
|
||||||
|
.with_scale_factor_override(options.scale_factor),
|
||||||
title: options.canvas_alt,
|
title: options.canvas_alt,
|
||||||
canvas: Some(options.canvas_selector),
|
canvas: Some(options.canvas_selector),
|
||||||
..default()
|
..default()
|
||||||
@@ -113,10 +127,14 @@ pub fn init_from_mixamo(anim_path: String, options: JsValue) -> Result<(), JsVal
|
|||||||
#[wasm_bindgen(skip_typescript, js_name = initFromSceneImport)]
|
#[wasm_bindgen(skip_typescript, js_name = initFromSceneImport)]
|
||||||
pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<(), JsValue> {
|
pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<(), JsValue> {
|
||||||
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
||||||
|
info!("wasm::init_from_scene_import: {scene_path} {options:#?}");
|
||||||
|
|
||||||
let skybox_id = options
|
let skybox_id = options
|
||||||
.skybox_id
|
.skybox_id
|
||||||
.expect("`skyboxId` is required for `initFromSceneImport`");
|
.expect("`skyboxId` is required for `initFromSceneImport`");
|
||||||
|
|
||||||
|
let ViewportSize { width, height } = options.viewport_size;
|
||||||
|
|
||||||
crate::start(
|
crate::start(
|
||||||
InitParams::FromAsset {
|
InitParams::FromAsset {
|
||||||
asset: InitAsset::ImportedScene(scene_path),
|
asset: InitAsset::ImportedScene(scene_path),
|
||||||
@@ -124,7 +142,8 @@ pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<()
|
|||||||
},
|
},
|
||||||
options.mode,
|
options.mode,
|
||||||
Some(Window {
|
Some(Window {
|
||||||
resolution: options.viewport_size.into(),
|
resolution: WindowResolution::new(width, height)
|
||||||
|
.with_scale_factor_override(options.scale_factor),
|
||||||
title: options.canvas_alt,
|
title: options.canvas_alt,
|
||||||
canvas: Some(options.canvas_selector),
|
canvas: Some(options.canvas_selector),
|
||||||
..default()
|
..default()
|
||||||
@@ -138,12 +157,16 @@ pub fn init_from_scene_import(scene_path: String, options: JsValue) -> Result<()
|
|||||||
#[wasm_bindgen(skip_typescript, js_name = initFromStorytellerScene)]
|
#[wasm_bindgen(skip_typescript, js_name = initFromStorytellerScene)]
|
||||||
pub fn init_from_storyteller_scene(scene_path: String, options: JsValue) -> Result<(), JsValue> {
|
pub fn init_from_storyteller_scene(scene_path: String, options: JsValue) -> Result<(), JsValue> {
|
||||||
let options = serde_wasm_bindgen::from_value::<WasmInitOptions>(options)?;
|
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(
|
crate::start(
|
||||||
InitParams::FromScene(scene_path),
|
InitParams::FromScene(scene_path),
|
||||||
options.mode,
|
options.mode,
|
||||||
Some(Window {
|
Some(Window {
|
||||||
resolution: options.viewport_size.into(),
|
resolution: WindowResolution::new(width, height)
|
||||||
|
.with_scale_factor_override(options.scale_factor),
|
||||||
title: options.canvas_alt,
|
title: options.canvas_alt,
|
||||||
canvas: Some(options.canvas_selector),
|
canvas: Some(options.canvas_selector),
|
||||||
..default()
|
..default()
|
||||||
|
|||||||
Reference in New Issue
Block a user