feat: finish line impl and switch to bevy bounds

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-06-28 11:34:09 +02:00
committed by Nova King
parent 2bf244bb6e
commit 85bb21414d
6 changed files with 142 additions and 118 deletions

View File

@@ -16,6 +16,9 @@ use bevy::app::{App, TerminalCtrlCHandlerPlugin};
use bevy::asset::{AssetMetaCheck, UnapprovedPathMode}; use bevy::asset::{AssetMetaCheck, UnapprovedPathMode};
use bevy::audio::AudioPlugin; use bevy::audio::AudioPlugin;
use bevy::core_pipeline::CorePipelinePlugin; use bevy::core_pipeline::CorePipelinePlugin;
use bevy::core_pipeline::oit::{
OrderIndependentTransparencyPlugin, OrderIndependentTransparencySettings,
};
use bevy::diagnostic::DiagnosticsPlugin; use bevy::diagnostic::DiagnosticsPlugin;
use bevy::ecs::schedule::{ExecutorKind, ScheduleLabel}; use bevy::ecs::schedule::{ExecutorKind, ScheduleLabel};
use bevy::gizmos::GizmoPlugin; use bevy::gizmos::GizmoPlugin;
@@ -38,6 +41,7 @@ use bevy_mod_openxr::reference_space::OxrReferenceSpacePlugin;
use bevy_mod_openxr::render::{OxrRenderPlugin, OxrWaitFrameSystem}; use bevy_mod_openxr::render::{OxrRenderPlugin, OxrWaitFrameSystem};
use bevy_mod_openxr::resources::{OxrFrameState, OxrFrameWaiter, OxrSessionConfig}; use bevy_mod_openxr::resources::{OxrFrameState, OxrFrameWaiter, OxrSessionConfig};
use bevy_mod_openxr::types::AppInfo; use bevy_mod_openxr::types::AppInfo;
use bevy_mod_xr::camera::XrProjection;
use bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin; use bevy_mod_xr::hand_debug_gizmos::HandGizmosPlugin;
use bevy_mod_xr::session::{XrFirst, XrHandleEvents}; use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use clap::Parser; use clap::Parser;
@@ -56,6 +60,7 @@ use openxr::{EnvironmentBlendMode, ReferenceSpaceType};
use session::{launch_start, save_session}; use session::{launch_start, save_session};
use stardust_xr::schemas::dbus::object_registry::ObjectRegistry; use stardust_xr::schemas::dbus::object_registry::ObjectRegistry;
use stardust_xr::server; use stardust_xr::server;
use std::ops::DerefMut as _;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock};
use std::time::Duration; use std::time::Duration;
@@ -359,7 +364,7 @@ fn bevy_loop(
.disable::<OxrActionAttachingPlugin>() .disable::<OxrActionAttachingPlugin>()
.disable::<OxrActionSyncingPlugin>(), .disable::<OxrActionSyncingPlugin>(),
); );
// font size is in meters
app.add_plugins(( app.add_plugins((
bevy_sk::hand::HandPlugin, bevy_sk::hand::HandPlugin,
bevy_sk::vr_materials::SkMaterialPlugin { bevy_sk::vr_materials::SkMaterialPlugin {
@@ -403,6 +408,7 @@ fn bevy_loop(
app.add_systems(PostStartup, move || { app.add_systems(PostStartup, move || {
ready_notifier.notify_waiters(); ready_notifier.notify_waiters();
}); });
app.add_systems(Update, update_cameras);
app.add_systems( app.add_systems(
XrFirst, XrFirst,
xr_step xr_step
@@ -412,6 +418,30 @@ fn bevy_loop(
app.run(); app.run();
} }
fn update_cameras(
mut camera: Query<
&mut Projection,
(
With<Camera3d>,
),
>,
) {
for mut projection in &mut camera {
match projection.deref_mut() {
Projection::Perspective(perspective_projection) => perspective_projection.near = 0.003,
Projection::Orthographic(orthographic_projection) => {
orthographic_projection.near = 0.003
}
Projection::Custom(custom_projection) => {
if let Some(xr) = custom_projection.get_mut::<XrProjection>() {
xr.near = 0.003
} else {
error_once!("unknown custom camera projection");
}
}
}
}
}
fn xr_step(world: &mut World) { fn xr_step(world: &mut World) {
// camera::update(token); // camera::update(token);

View File

@@ -9,20 +9,17 @@ use crate::{
use bevy::{ use bevy::{
asset::RenderAssetUsages, asset::RenderAssetUsages,
prelude::*, prelude::*,
render::mesh::{Indices, PrimitiveTopology}, render::{
}; mesh::{Indices, MeshAabb, PrimitiveTopology},
use bevy_sk::vr_materials::PbrMaterial; primitives::Aabb,
use glam::{FloatExt, Vec3};
use parking_lot::Mutex;
use std::{
collections::VecDeque,
sync::{
Arc, OnceLock,
atomic::{AtomicBool, Ordering},
}, },
}; };
use stereokit_rust::{ use bevy_sk::vr_materials::PbrMaterial;
maths::Bounds, sk::MainThreadToken, system::LinePoint as SkLinePoint, util::Color128, use glam::Vec3;
use parking_lot::Mutex;
use std::sync::{
Arc, OnceLock,
atomic::{AtomicBool, Ordering},
}; };
pub struct LinesNodePlugin; pub struct LinesNodePlugin;
@@ -32,16 +29,6 @@ impl Plugin for LinesNodePlugin {
app.add_systems(Update, build_line_mesh); app.add_systems(Update, build_line_mesh);
} }
} }
const POINTS: [Vec3; 8] = [
Vec3::X,
Vec3::new(1., 0., 1.),
Vec3::Z,
Vec3::new(-1., 0., 1.),
Vec3::NEG_X,
Vec3::new(-1., 0., -1.),
Vec3::NEG_Z,
Vec3::new(1., 0., -1.),
];
fn build_line_mesh( fn build_line_mesh(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
@@ -62,25 +49,30 @@ fn build_line_mesh(
if lines_data.is_empty() { if lines_data.is_empty() {
continue; continue;
} }
let mut idk = 0; let mut indecies_set = 0;
for line in lines_data.iter() { for line in lines_data.iter() {
let start_set = indecies_set;
let optional_points = { let optional_points = {
let mut out = Vec::new(); let mut out = Vec::new();
let mut last = line.cyclic.then(|| line.points.last()).flatten(); let mut last = line.cyclic.then(|| line.points.last()).flatten();
let mut peekable = line.points.iter().peekable(); let mut peekable = line.points.iter().peekable();
while let Some(curr) = peekable.next() { while let Some(curr) = peekable.next() {
let mut end = false;
let next = match peekable.peek() { let next = match peekable.peek() {
Some(v) => Some(*v), Some(v) => Some(*v),
None => line.cyclic.then(|| line.points.first()).flatten(), None => {
end = true;
line.cyclic.then(|| line.points.first()).flatten()
}
}; };
out.push((last, curr, next)); out.push((last, curr, next, end));
last = Some(curr); last = Some(curr);
} }
out out
}; };
for (last, curr, next) in optional_points { for (last, curr, next, end) in optional_points {
let last_quat = last.map(|v| { let last_quat = last.map(|v| {
Quat::from_rotation_arc( Quat::from_rotation_arc(
Vec3::Y, Vec3::Y,
@@ -115,10 +107,18 @@ fn build_line_mesh(
vertex_normals.extend(normals); vertex_normals.extend(normals);
vertex_positions.extend(points); vertex_positions.extend(points);
vertex_colors.extend([curr.color.to_bevy().to_srgba().to_f32_array(); 8]); vertex_colors.extend([curr.color.to_bevy().to_srgba().to_f32_array(); 8]);
idk += 1; if !end {
vertex_indecies.extend(indecies(indecies_set));
}
indecies_set += 1;
}
if line.cyclic {
vertex_indecies.extend(cyclic_indecies(start_set, indecies_set - 1));
} else {
vertex_indecies.extend(cap_indecies(start_set, false));
vertex_indecies.extend(cap_indecies(indecies_set - 1, true));
} }
} }
let vertex_indecies = (0..idk - 1).flat_map(indecies).collect::<Vec<_>>();
let mut mesh = Mesh::new( let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList, PrimitiveTopology::TriangleList,
RenderAssetUsages::RENDER_WORLD, RenderAssetUsages::RENDER_WORLD,
@@ -126,7 +126,10 @@ fn build_line_mesh(
mesh.insert_indices(Indices::U32(vertex_indecies)); mesh.insert_indices(Indices::U32(vertex_indecies));
mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_colors); mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, vertex_colors);
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_normals); mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, vertex_normals);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertex_positions); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertex_positions.clone());
if let Some(aabb) = mesh.compute_aabb() {
*lines.bounds.lock() = aabb;
}
match lines.entity.get() { match lines.entity.get() {
Some(e) => cmds.entity(*e), Some(e) => cmds.entity(*e),
@@ -137,23 +140,38 @@ fn build_line_mesh(
MeshMaterial3d(materials.add(PbrMaterial { MeshMaterial3d(materials.add(PbrMaterial {
color: Color::WHITE, color: Color::WHITE,
roughness: 1.0, roughness: 1.0,
alpha_mode: AlphaMode::Blend, alpha_mode: AlphaMode::Opaque,
..default() ..default()
})), })),
)); ));
} }
} }
const END_CAP_INDECIES: [u32; 18] = [0, 1, 7, 7, 1, 2, 7, 2, 6, 6, 2, 3, 6, 3, 5, 5, 3, 4];
fn cap_indecies(set: u32, flip: bool) -> [u32; END_CAP_INDECIES.len()] {
let mut out = END_CAP_INDECIES.map(|v| v + (set * 8));
if flip {
out.reverse();
}
out
}
// const BASE: [u16; 6] = [0, 8, 1, 8, 9, 1]; // const BASE: [u16; 6] = [0, 8, 1, 8, 9, 1];
const INDECIES: [u32; 48] = [ const INDECIES: [u32; 48] = [
0, 8, 1, 8, 9, 1, 1, 9, 2, 9, 10, 2, 2, 10, 3, 10, 11, 3, 3, 11, 4, 11, 12, 4, 4, 12, 5, 12, 0, 8, 1, 8, 9, 1, 1, 9, 2, 9, 10, 2, 2, 10, 3, 10, 11, 3, 3, 11, 4, 11, 12, 4, 4, 12, 5, 12,
13, 5, 5, 13, 6, 13, 14, 6, 6, 14, 7, 14, 15, 7, 7, 15, 0, 15, 8, 0, 13, 5, 5, 13, 6, 13, 14, 6, 6, 14, 7, 14, 15, 7, 7, 15, 0, 15, 8, 0,
]; ];
fn indecies(base: u32) -> [u32; INDECIES.len()] { fn indecies(set: u32) -> [u32; INDECIES.len()] {
INDECIES.map(|v| v + (base * 8)) INDECIES.map(|v| v + (set * 8))
} }
fn cyclic_indecies(base: u32) -> [u32; INDECIES.len()] { fn cyclic_indecies(start_set: u32, end_set: u32) -> [u32; INDECIES.len()] {
let mut out = INDECIES.map(|v| if v >= 8 { v + (base * 8) } else { v }); let mut out = INDECIES.map(|v| {
if v < 8 {
v + ((start_set) * 8)
} else {
v + ((end_set - 1) * 8)
}
});
out.reverse(); out.reverse();
out out
} }
@@ -165,6 +183,7 @@ pub struct Lines {
data: Mutex<Vec<Line>>, data: Mutex<Vec<Line>>,
gen_mesh: AtomicBool, gen_mesh: AtomicBool,
entity: OnceLock<Entity>, entity: OnceLock<Entity>,
bounds: Mutex<Aabb>,
} }
impl Lines { impl Lines {
pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> { pub fn add_to(node: &Arc<Node>, lines: Vec<Line>) -> Result<Arc<Lines>> {
@@ -173,15 +192,10 @@ impl Lines {
.unwrap() .unwrap()
.bounding_box_calc .bounding_box_calc
.set(|node| { .set(|node| {
let mut bounds = Bounds::default(); node.get_aspect::<Lines>()
if let Ok(lines) = node.get_aspect::<Lines>() { .ok()
for line in &*lines.data.lock() { .map(|v| v.bounds.lock().clone())
for point in &line.points { .unwrap_or_default()
bounds.grown_point(Vec3::from(point.point));
}
}
}
bounds
}); });
info!("line::add_to"); info!("line::add_to");
@@ -190,48 +204,12 @@ impl Lines {
data: Mutex::new(lines), data: Mutex::new(lines),
gen_mesh: AtomicBool::new(true), gen_mesh: AtomicBool::new(true),
entity: OnceLock::new(), entity: OnceLock::new(),
bounds: Mutex::new(Aabb::default()),
}); });
node.add_aspect_raw(lines.clone()); node.add_aspect_raw(lines.clone());
Ok(lines) Ok(lines)
} }
fn draw(&self, token: &MainThreadToken) {
let transform_mat = self.spatial.global_transform();
let data = self.data.lock().clone();
for line in &data {
let mut points: VecDeque<SkLinePoint> = line
.points
.iter()
.map(|p| SkLinePoint {
pt: transform_mat.transform_point3(Vec3::from(p.point)).into(),
thickness: p.thickness,
color: Color128::new(p.color.c.r, p.color.c.g, p.color.c.b, p.color.a).into(),
})
.collect();
if line.cyclic && !points.is_empty() {
let first = line.points.first().unwrap();
let last = line.points.last().unwrap();
let color = Color128 {
r: first.color.c.r.lerp(last.color.c.r, 0.5),
g: first.color.c.g.lerp(last.color.c.g, 0.5),
b: first.color.c.b.lerp(last.color.c.b, 0.5),
a: first.color.a.lerp(last.color.a, 0.5),
};
let connect_point = SkLinePoint {
pt: transform_mat
.transform_point3(Vec3::from(first.point).lerp(Vec3::from(last.point), 0.5))
.into(),
thickness: (first.thickness + last.thickness) * 0.5,
color: color.into(),
};
points.push_front(connect_point);
points.push_back(connect_point);
}
stereokit_rust::system::Lines::add_list(token, points.make_contiguous());
}
}
} }
impl LinesAspect for Lines { impl LinesAspect for Lines {
fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> { fn set_lines(node: Arc<Node>, _calling_client: Arc<Client>, lines: Vec<Line>) -> Result<()> {
@@ -247,13 +225,3 @@ impl Drop for Lines {
LINES_REGISTRY.remove(self); LINES_REGISTRY.remove(self);
} }
} }
pub fn draw_all(token: &MainThreadToken) {
for lines in LINES_REGISTRY.get_valid_contents() {
if let Some(node) = lines.spatial.node() {
if node.enabled() {
lines.draw(token);
}
}
}
}

View File

@@ -22,7 +22,6 @@ use stereokit_rust::{sk::MainThreadToken, system::Renderer, tex::SHCubemap};
// #[instrument(level = "debug", skip(sk))] // #[instrument(level = "debug", skip(sk))]
pub fn draw(token: &MainThreadToken) { pub fn draw(token: &MainThreadToken) {
lines::draw_all(token);
match QUEUED_SKYTEX.lock().take() { match QUEUED_SKYTEX.lock().take() {
Some(Some(skytex)) => { Some(Some(skytex)) => {
if let Ok(skytex) = SHCubemap::from_cubemap(skytex, true, 100) { if let Ok(skytex) = SHCubemap::from_cubemap(skytex, true, 100) {

View File

@@ -9,6 +9,7 @@ use crate::nodes::Node;
use crate::nodes::alias::{Alias, AliasList}; use crate::nodes::alias::{Alias, AliasList};
use crate::nodes::spatial::{Spatial, SpatialNode}; use crate::nodes::spatial::{Spatial, SpatialNode};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::primitives::Aabb;
use bevy_sk::vr_materials::PbrMaterial; use bevy_sk::vr_materials::PbrMaterial;
use color_eyre::eyre::eyre; use color_eyre::eyre::eyre;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -18,7 +19,6 @@ use std::ffi::OsStr;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{Arc, OnceLock, Weak}; use std::sync::{Arc, OnceLock, Weak};
use stereokit_rust::maths::Bounds;
use tokio::sync::mpsc; use tokio::sync::mpsc;
static LOAD_MODEL: OnceLock<mpsc::UnboundedSender<(Arc<Model>, PathBuf)>> = OnceLock::new(); static LOAD_MODEL: OnceLock<mpsc::UnboundedSender<(Arc<Model>, PathBuf)>> = OnceLock::new();
@@ -121,6 +121,7 @@ fn gen_model_parts(
query: Query<(Entity, &SceneRoot, &ModelNode, &Children)>, query: Query<(Entity, &SceneRoot, &ModelNode, &Children)>,
children_query: Query<&Children>, children_query: Query<&Children>,
part_query: Query<(&Name, Option<&Children>, &Transform), Without<Mesh3d>>, part_query: Query<(&Name, Option<&Children>, &Transform), Without<Mesh3d>>,
part_mesh_query: Query<(&Transform, &Aabb), With<Mesh3d>>,
has_mesh: Query<Has<Mesh3d>>, has_mesh: Query<Has<Mesh3d>>,
mut cmds: Commands, mut cmds: Commands,
) { ) {
@@ -145,7 +146,7 @@ fn gen_model_parts(
entity, entity,
&part_query, &part_query,
None, None,
&mut |entity, name, transform, parent| { &mut |entity, name, transform, parent, children| {
let path = parent let path = parent
.as_ref() .as_ref()
.map(|p| format!("{}/{}", &p.path, name.as_str())) .map(|p| format!("{}/{}", &p.path, name.as_str()))
@@ -175,6 +176,7 @@ fn gen_model_parts(
pending_material_parameters: Mutex::default(), pending_material_parameters: Mutex::default(),
pending_material_replacement: Mutex::default(), pending_material_replacement: Mutex::default(),
aliases: AliasList::default(), aliases: AliasList::default(),
bounds: OnceLock::new(),
}); });
(spatial, model_part) (spatial, model_part)
} }
@@ -185,9 +187,24 @@ fn gen_model_parts(
(part.space.clone(), part.clone()) (part.space.clone(), part.clone())
} }
}; };
_ = spatial.bounding_box_calc.set(|_| { let aabb = Aabb::enclosing(
// TODO: actually impl aabb children
Bounds::default() .iter()
.flat_map(|v| v.iter())
.filter_map(|e| part_mesh_query.get(e).ok())
.flat_map(|(transform, aabb)| {
[
transform.transform_point(aabb.min().into()),
transform.transform_point(aabb.max().into()),
]
}),
)
.unwrap_or_default();
_ = spatial.bounding_box_calc.set(move |n| {
n.get_aspect::<ModelPart>()
.ok()
.and_then(|v| v.bounds.get().copied())
.unwrap_or_default()
}); });
cmds.entity(entity) cmds.entity(entity)
.insert(SpatialNode(Arc::downgrade(&spatial))); .insert(SpatialNode(Arc::downgrade(&spatial)));
@@ -196,6 +213,7 @@ fn gen_model_parts(
.iter() .iter()
.flat_map(|v| v.iter()) .flat_map(|v| v.iter())
.find(|e| has_mesh.get(*e).unwrap_or(false))?; .find(|e| has_mesh.get(*e).unwrap_or(false))?;
_ = model_part.bounds.set(aabb);
_ = model_part.entity.set(entity); _ = model_part.entity.set(entity);
_ = model_part.mesh_entity.set(mesh_entity); _ = model_part.mesh_entity.set(mesh_entity);
parts.push(model_part.clone()); parts.push(model_part.clone());
@@ -216,12 +234,13 @@ fn gen_path(
&Name, &Name,
&Transform, &Transform,
Option<Arc<ModelPart>>, Option<Arc<ModelPart>>,
Option<&Children>,
) -> Option<Arc<ModelPart>>, ) -> Option<Arc<ModelPart>>,
) { ) {
let Ok((name, children, transform)) = part_query.get(current_entity) else { let Ok((name, children, transform)) = part_query.get(current_entity) else {
return; return;
}; };
let Some(parent) = func(current_entity, name, transform, parent) else { let Some(parent) = func(current_entity, name, transform, parent, children) else {
return; return;
}; };
for e in children.iter().flat_map(|c| c.iter()) { for e in children.iter().flat_map(|c| c.iter()) {
@@ -449,6 +468,7 @@ pub struct ModelPart {
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>, pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Material>>, pending_material_replacement: Mutex<Option<Material>>,
aliases: AliasList, aliases: AliasList,
bounds: OnceLock<Aabb>,
} }
impl ModelPart { impl ModelPart {
pub fn replace_material(&self, replacement: Material) { pub fn replace_material(&self, replacement: Material) {
@@ -589,6 +609,7 @@ impl Model {
pending_material_parameters: Mutex::default(), pending_material_parameters: Mutex::default(),
pending_material_replacement: Mutex::default(), pending_material_replacement: Mutex::default(),
aliases: AliasList::default(), aliases: AliasList::default(),
bounds: OnceLock::new(),
}); });
self.pre_bound_parts.lock().push(part.clone()); self.pre_bound_parts.lock().push(part.clone());
part part

View File

@@ -11,6 +11,7 @@ use crate::core::registry::Registry;
use crate::nodes::{Node, OWNED_ASPECT_ALIAS_INFO}; use crate::nodes::{Node, OWNED_ASPECT_ALIAS_INFO};
use bevy::prelude::Transform as BevyTransform; use bevy::prelude::Transform as BevyTransform;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::primitives::Aabb;
use color_eyre::eyre::OptionExt; use color_eyre::eyre::OptionExt;
use glam::{Mat4, Quat, Vec3, vec3a}; use glam::{Mat4, Quat, Vec3, vec3a};
use mint::Vector3; use mint::Vector3;
@@ -19,7 +20,6 @@ use rustc_hash::FxHashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, OnceLock, Weak}; use std::sync::{Arc, OnceLock, Weak};
use std::{f32, ptr}; use std::{f32, ptr};
use stereokit_rust::maths::Bounds;
pub struct SpatialNodePlugin; pub struct SpatialNodePlugin;
impl Plugin for SpatialNodePlugin { impl Plugin for SpatialNodePlugin {
@@ -102,7 +102,7 @@ pub struct Spatial {
transform: Mutex<Mat4>, transform: Mutex<Mat4>,
zone: Mutex<Weak<Zone>>, zone: Mutex<Weak<Zone>>,
children: Registry<Spatial>, children: Registry<Spatial>,
pub bounding_box_calc: OnceLock<fn(&Node) -> Bounds>, pub bounding_box_calc: OnceLock<fn(&Node) -> Aabb>,
} }
impl Spatial { impl Spatial {
@@ -146,9 +146,9 @@ impl Spatial {
} }
// the output bounds are probably way bigger than they need to be // the output bounds are probably way bigger than they need to be
pub fn get_bounding_box(&self) -> Bounds { pub fn get_bounding_box(&self) -> Aabb {
let Some(node) = self.node() else { let Some(node) = self.node() else {
return Bounds::default(); return Aabb::default();
}; };
let mut bounds = self let mut bounds = self
.bounding_box_calc .bounding_box_calc
@@ -156,7 +156,15 @@ impl Spatial {
.map(|b| (b)(&node)) .map(|b| (b)(&node))
.unwrap_or_default(); .unwrap_or_default();
for child in self.children.get_valid_contents() { for child in self.children.get_valid_contents() {
bounds.grown_box(child.get_bounding_box(), child.local_transform()); let mat = child.local_transform();
let child_aabb = child.get_bounding_box();
bounds = Aabb::enclosing([
bounds.min().into(),
bounds.max().into(),
mat.transform_point3(child_aabb.min().into()),
mat.transform_point3(child_aabb.max().into()),
])
.unwrap();
} }
bounds bounds
} }
@@ -382,7 +390,7 @@ impl SpatialRefAspect for SpatialRef {
Ok(BoundingBox { Ok(BoundingBox {
center: Vec3::from(bounds.center).into(), center: Vec3::from(bounds.center).into(),
size: Vec3::from(bounds.dimensions).into(), size: Vec3::from(bounds.half_extents * 2.0).into(),
}) })
} }
@@ -393,20 +401,17 @@ impl SpatialRefAspect for SpatialRef {
) -> Result<BoundingBox> { ) -> Result<BoundingBox> {
let this_spatial = node.get_aspect::<Spatial>()?; let this_spatial = node.get_aspect::<Spatial>()?;
let relative_spatial = relative_to.get_aspect::<Spatial>()?; let relative_spatial = relative_to.get_aspect::<Spatial>()?;
let center = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial)) let mat = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial));
.transform_point3([0.0; 3].into()); let bb = this_spatial.get_bounding_box();
let mut bounds = Bounds { let bounds = Aabb::enclosing([
center: center.into(), mat.transform_point3(bb.min().into()),
dimensions: [0.0; 3].into(), mat.transform_point3(bb.max().into()),
}; ])
bounds.grown_box( .unwrap();
this_spatial.get_bounding_box(),
Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial)),
);
Ok(BoundingBox { Ok(BoundingBox {
center: Vec3::from(bounds.center).into(), center: Vec3::from(bounds.center).into(),
size: Vec3::from(bounds.dimensions).into(), size: Vec3::from(bounds.half_extents * 2.0).into(),
}) })
} }

View File

@@ -307,6 +307,9 @@ impl SkController {
}) })
} }
pub fn set_enabled(&self, enabled: bool) { pub fn set_enabled(&self, enabled: bool) {
if let Some(node) = self.input.spatial.node() {
node.set_enabled(enabled);
}
tokio::spawn({ tokio::spawn({
// this is suboptimal since it probably allocates a fresh string every frame // this is suboptimal since it probably allocates a fresh string every frame
let handle = self.tracked.clone(); let handle = self.tracked.clone();
@@ -342,8 +345,6 @@ impl SkController {
let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose())); let world_transform = Mat4::from(Affine3A::from(location.pose.to_xr_pose()));
self.model_part self.model_part
.set_material_parameter("roughness".to_string(), MaterialParameter::Float(1.0)); .set_material_parameter("roughness".to_string(), MaterialParameter::Float(1.0));
// self.model_part
// .set_material_parameter("metallic".to_string(), MaterialParameter::Float(0.0));
self.model_part.set_material_parameter( self.model_part.set_material_parameter(
"color".to_string(), "color".to_string(),
MaterialParameter::Color(stardust_xr::values::Color::new( MaterialParameter::Color(stardust_xr::values::Color::new(