diff --git a/src/material.rs b/src/material.rs index 87fa1e0..07fd059 100644 --- a/src/material.rs +++ b/src/material.rs @@ -1,4 +1,5 @@ use std::path::PathBuf; +use rand::Rng; use bevy::prelude::*; @@ -17,6 +18,8 @@ impl Plugin for ZeroverseMaterialPlugin { app.init_resource::(); app.add_systems(PreStartup, load_materials); + + // TODO: add event to load next material batch } } @@ -59,6 +62,8 @@ fn load_materials( mut materials: ResMut>, mut zeroverse_materials: ResMut, ) { + let rng = &mut rand::thread_rng(); + let roots = get_material_roots(); for root in roots { @@ -81,6 +86,10 @@ fn load_materials( depth_map: depth_map_handle.into(), double_sided: true, cull_mode: None, + // specular_transmission: (rng.gen_range(0.0..1.0) as f32).powf(2.0), + // ior: rng.gen_range(1.0..2.0), + perceptual_roughness: rng.gen_range(0.3..0.7), + reflectance: rng.gen_range(0.3..0.7), ..Default::default() }); @@ -89,4 +98,3 @@ fn load_materials( info!("loaded {} materials", zeroverse_materials.materials.len()); } - diff --git a/src/primitive.rs b/src/primitive.rs index be0774f..abac121 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -37,6 +37,8 @@ use crate::{ pub struct ZeroversePrimitivePlugin; impl Plugin for ZeroversePrimitivePlugin { fn build(&self, app: &mut App) { + app.register_type::(); + #[cfg(not(target_family = "wasm"))] // note: web does not handle `POLYGON_MODE_LINE`, so we skip wireframes app.add_plugins(bevy::pbr::wireframe::WireframePlugin); @@ -58,13 +60,17 @@ pub enum ZeroversePrimitives { Torus, } -#[derive(Clone, Component, Debug, Reflect)] +#[derive(Clone, Component, Debug, Reflect, Resource)] +#[reflect(Resource)] pub struct PrimitiveSettings { pub components: usize, pub available_types: Vec, pub available_operations: Vec, pub wireframe_probability: f32, - pub scale_bound: Vec3, + pub rotation_lower_bound: Vec3, + pub rotation_upper_bound: Vec3, + pub scale_lower_bound: Vec3, + pub scale_upper_bound: Vec3, pub position_bound: Vec3, } @@ -80,12 +86,15 @@ impl PrimitiveSettings { impl Default for PrimitiveSettings { fn default() -> PrimitiveSettings { PrimitiveSettings { - components: 1, + components: 25, available_types: ZeroversePrimitives::iter().collect(), available_operations: ManifoldOperations::iter().collect(), - wireframe_probability: 0.2, - scale_bound: Vec3::splat(1.0), - position_bound: Vec3::splat(2.0), + wireframe_probability: 0.1, + rotation_lower_bound: Vec3::splat(0.0), + rotation_upper_bound: Vec3::splat(std::f32::consts::PI), + scale_lower_bound: Vec3::splat(0.05), + scale_upper_bound: Vec3::splat(1.0), + position_bound: Vec3::splat(1.5), } } } @@ -122,9 +131,9 @@ fn process_primitives( let scales = (0..settings.components) .map(|_| Vec3::new( - rng.gen_range(0.0..settings.scale_bound.x), - rng.gen_range(0.0..settings.scale_bound.y), - rng.gen_range(0.0..settings.scale_bound.z), + rng.gen_range(settings.scale_lower_bound.x..settings.scale_upper_bound.x), + rng.gen_range(settings.scale_lower_bound.y..settings.scale_upper_bound.y), + rng.gen_range(settings.scale_lower_bound.z..settings.scale_upper_bound.z), )) .collect::>(); @@ -138,9 +147,9 @@ fn process_primitives( let rotations = (0..settings.components) .map(|_| Quat::from_scaled_axis(Vec3::new( - rng.gen_range(0.0..std::f32::consts::PI), - rng.gen_range(0.0..std::f32::consts::PI), - rng.gen_range(0.0..std::f32::consts::PI), + rng.gen_range(settings.rotation_lower_bound.x..settings.rotation_upper_bound.x), + rng.gen_range(settings.rotation_lower_bound.y..settings.rotation_upper_bound.y), + rng.gen_range(settings.rotation_lower_bound.z..settings.rotation_upper_bound.z), ))) .collect::>(); @@ -157,15 +166,15 @@ fn process_primitives( rotation, )| { let mesh = match primitive_type { - ZeroversePrimitives::Capsule => Capsule3d::new(scale.x, scale.y) + ZeroversePrimitives::Capsule => Capsule3d::default() .mesh() .latitudes(rng.gen_range(4..64)) .longitudes(rng.gen_range(4..64)) .rings(rng.gen_range(4..32)) .build(), - ZeroversePrimitives::Cuboid => Cuboid::from_size(scale) + ZeroversePrimitives::Cuboid => Cuboid::default() .mesh(), - ZeroversePrimitives::Cylinder => Cylinder::new(scale.x, scale.y) + ZeroversePrimitives::Cylinder => Cylinder::default() .mesh() .resolution(rng.gen_range(4..64)) .segments(rng.gen_range(3..64)) @@ -174,22 +183,29 @@ fn process_primitives( .mesh() .size(scale.x, scale.y) .build(), - ZeroversePrimitives::Sphere => Sphere::new(scale.x) + ZeroversePrimitives::Sphere => Sphere::default() .mesh() .uv( rng.gen_range(24..64), rng.gen_range(12..32), ), - ZeroversePrimitives::Torus => Torus::new(scale.x, scale.y) - .mesh() - .major_resolution(rng.gen_range(4..64)) - .minor_resolution(rng.gen_range(4..64)) - .build(), + ZeroversePrimitives::Torus => { + let inner_radius = rng.gen_range(0.01..1.0); + let outer_radius = inner_radius + rng.gen_range(0.01..1.0); + + Torus::new(inner_radius, outer_radius) + .mesh() + .major_resolution(rng.gen_range(3..64)) + .minor_resolution(rng.gen_range(3..64)) + .build() + }, }; - let transform = Transform::from_translation(position).with_rotation(rotation); - let mut mesh = mesh.transformed_by(transform); - mesh.generate_tangents().unwrap(); + let transform = Transform::from_translation(position) + .with_rotation(rotation) + .with_scale(scale); + + let mesh = mesh.transformed_by(transform); // TODO: optionally spawn the base primitive (no manifold operations) for debugging diff --git a/tools/viewer.rs b/tools/viewer.rs index 51bf4a6..9bdd957 100644 --- a/tools/viewer.rs +++ b/tools/viewer.rs @@ -70,9 +70,6 @@ struct BevyZeroverseViewer { /// move to the next scene after `regenerate_ms` milliseconds #[arg(long, default_value = "0")] regenerate_ms: u32, - - #[arg(long, default_value = "10")] - primitive_count: usize, } impl Default for BevyZeroverseViewer { @@ -85,15 +82,14 @@ impl Default for BevyZeroverseViewer { height: 1080.0, name: "bevy_zeroverse".to_string(), regenerate_ms: 0, - primitive_count: 10, } } } fn viewer_app() { - let config = parse_args::(); - info!("{:?}", config); + let args = parse_args::(); + info!("{:?}", args); let mut app = App::new(); @@ -103,7 +99,7 @@ fn viewer_app() { canvas: Some("#bevy".to_string()), mode: bevy::window::WindowMode::Windowed, prevent_default_event_handling: true, - title: config.name.clone(), + title: args.name.clone(), #[cfg(feature = "perftest")] present_mode: bevy::window::PresentMode::AutoNoVsync, @@ -117,8 +113,8 @@ fn viewer_app() { let primary_window = Some(Window { mode: bevy::window::WindowMode::Windowed, prevent_default_event_handling: false, - resolution: (config.width, config.height).into(), - title: config.name.clone(), + resolution: (args.width, args.height).into(), + title: args.name.clone(), #[cfg(feature = "perftest")] present_mode: bevy::window::PresentMode::AutoNoVsync, @@ -144,16 +140,18 @@ fn viewer_app() { app.insert_resource(Msaa::Off) .add_plugins(TemporalAntiAliasPlugin); - if config.editor { + if args.editor { app.register_type::(); app.add_plugins(WorldInspectorPlugin::new()); } - if config.press_esc_close { + if args.press_esc_close { app.add_systems(Update, press_esc_close); } app.add_plugins(BevyZeroversePlugin); + app.init_resource::(); + app.add_systems(Startup, setup_camera); app.add_systems(Startup, setup_primitives); app.add_systems(PostUpdate, regenerate_scene_system); @@ -271,10 +269,9 @@ fn setup_camera( fn setup_primitives( mut commands: Commands, - args: Res, + primitive_settings: Res, ) { - // TODO: spawn primitive settings from the global resource template - commands.spawn(PrimitiveSettings::count(args.primitive_count)); + commands.spawn(primitive_settings.clone()); } fn regenerate_scene_system( @@ -283,6 +280,7 @@ fn regenerate_scene_system( keys: Res>, clear_meshes: Query>>, clear_zeroverse_primitives: Query>, + primitive_settings: Res, time: Res