Fix extended-region scene rendering and delivery
This commit is contained in:
@@ -17,6 +17,7 @@ libremetaverse-imaging = { version = "0.0.1", path = "../libremetaverse-imaging"
|
||||
libremetaverse-rendering-simple = { version = "0.0.1", path = "../libremetaverse-rendering-simple", optional = true }
|
||||
libremetaverse-types = { version = "0.0.1", path = "../libremetaverse-types" }
|
||||
metacrate-lsl-tools = { version = "0.0.1", path = "../metacrate-lsl-tools" }
|
||||
metacrate-rendering-wgpu = { version = "0.0.1", path = "../metacrate-rendering-wgpu" }
|
||||
mentra = { version = "0.18.3", default-features = false }
|
||||
jpeg-encoder = "0.6.1"
|
||||
rustls = { version = "0.23.43", default-features = false, features = ["aws_lc_rs", "std", "tls12"] }
|
||||
@@ -28,7 +29,6 @@ tokio = { version = "1.53.1", features = ["macros", "rt", "sync", "time"] }
|
||||
tokio-rustls = { version = "0.26.4", default-features = false, features = ["aws_lc_rs", "tls12"] }
|
||||
url = "2.5.8"
|
||||
unicode-width = "0.2"
|
||||
wgpu = { version = "30.0.1", default-features = false, features = ["std", "dx12", "metal", "gles", "vulkan", "wgsl"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
jpeg-decoder = { version = "0.3.2", default-features = false }
|
||||
@@ -39,7 +39,7 @@ tokio = { version = "1.53.1", features = ["io-util", "net", "rt-multi-thread", "
|
||||
|
||||
[features]
|
||||
default = []
|
||||
live-grid = ["dep:libremetaverse", "dep:libremetaverse-imaging", "dep:libremetaverse-rendering-simple", "dep:wgpu"]
|
||||
live-grid = ["dep:libremetaverse", "dep:libremetaverse-imaging", "dep:libremetaverse-rendering-simple", "metacrate-rendering-wgpu/wgpu"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -94,6 +94,7 @@ impl OfflineGridBackend {
|
||||
#[cfg(feature = "live-grid")]
|
||||
pub struct LibremetaverseClientOwner {
|
||||
client: libremetaverse::GridClient,
|
||||
network: libremetaverse::NetworkManager,
|
||||
agent: Arc<libremetaverse::AgentManager>,
|
||||
delivery_generation: Arc<std::sync::RwLock<Option<u64>>>,
|
||||
}
|
||||
@@ -132,6 +133,7 @@ impl fmt::Debug for LibremetaverseClientOwner {
|
||||
pub struct LibremetaverseSessionBackend {
|
||||
network: libremetaverse::NetworkManager,
|
||||
agent: Arc<libremetaverse::AgentManager>,
|
||||
throttle: libremetaverse::AgentThrottle,
|
||||
login_url: String,
|
||||
first_name: String,
|
||||
last_name: String,
|
||||
@@ -168,7 +170,11 @@ impl LibremetaverseClientOwner {
|
||||
.map_err(|_| BackendError::Configuration {
|
||||
component: "libremetaverse client defaults",
|
||||
})?;
|
||||
// The compatibility client caches its network manager weakly. Retain the
|
||||
// composition root before managers register packet subscriptions on it.
|
||||
let network = client.network();
|
||||
let _grid = client.grid();
|
||||
let _terrain = client.terrain();
|
||||
let agent = Arc::new(
|
||||
libremetaverse::AgentManager::new(Some(Arc::new(client.clone()))).map_err(|_| {
|
||||
BackendError::Configuration {
|
||||
@@ -178,6 +184,7 @@ impl LibremetaverseClientOwner {
|
||||
);
|
||||
Ok(Self {
|
||||
client,
|
||||
network,
|
||||
agent,
|
||||
delivery_generation: Arc::new(std::sync::RwLock::new(None)),
|
||||
})
|
||||
@@ -273,8 +280,12 @@ impl LibremetaverseClientOwner {
|
||||
});
|
||||
}
|
||||
Ok(LibremetaverseSessionBackend {
|
||||
network: self.client.network(),
|
||||
network: self.network.clone(),
|
||||
agent: Arc::clone(&self.agent),
|
||||
throttle: libremetaverse::AgentThrottle::new_with_grid_client(self.client.clone())
|
||||
.map_err(|_| BackendError::Configuration {
|
||||
component: "libremetaverse agent throttle",
|
||||
})?,
|
||||
login_url: connection.login_url.expose_url().to_owned(),
|
||||
first_name: first_name.to_owned(),
|
||||
last_name: last_name.to_owned(),
|
||||
@@ -794,30 +805,7 @@ impl crate::behavior::EmbodimentSink for LibremetaverseEmbodimentSink {
|
||||
return Err(crate::behavior::BehaviorError::Cancelled);
|
||||
}
|
||||
self.ensure_generation(generation)?;
|
||||
let avatar = self.agent.sim_position();
|
||||
let forward = libremetaverse_types::Vector3::mul_with_vector3_quaternion(
|
||||
libremetaverse_types::Vector3::unit_x(),
|
||||
self.agent.sim_rotation(),
|
||||
);
|
||||
let position = libremetaverse_types::Vector3 {
|
||||
x: avatar.x,
|
||||
y: avatar.y,
|
||||
z: avatar.z + 1.6,
|
||||
};
|
||||
let target = libremetaverse_types::Vector3 {
|
||||
x: position.x + forward.x * 4.0,
|
||||
y: position.y + forward.y * 4.0,
|
||||
z: position.z + forward.z * 4.0,
|
||||
};
|
||||
self.agent
|
||||
.movement
|
||||
.camera
|
||||
.look_at_with_vector3_vector3(position, target)
|
||||
.and_then(|()| {
|
||||
self.agent
|
||||
.movement
|
||||
.set_fov_vertical_angle(60.0_f32.to_radians())
|
||||
})
|
||||
native_reset_camera(&self.agent)
|
||||
.and_then(|()| self.agent.movement.send_update_with_boolean(Some(true)))
|
||||
.map_err(|_| crate::behavior::BehaviorError::NativeOperation)
|
||||
})
|
||||
@@ -847,6 +835,30 @@ fn native_position(value: libremetaverse_types::Vector3) -> crate::perception::W
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
fn native_reset_camera(agent: &libremetaverse::AgentManager) -> Result<(), libremetaverse::Error> {
|
||||
let avatar = agent.sim_position();
|
||||
let forward = libremetaverse_types::Vector3::mul_with_vector3_quaternion(
|
||||
libremetaverse_types::Vector3::unit_x(),
|
||||
agent.sim_rotation(),
|
||||
);
|
||||
let position = libremetaverse_types::Vector3 {
|
||||
x: avatar.x,
|
||||
y: avatar.y,
|
||||
z: avatar.z + 1.6,
|
||||
};
|
||||
let target = libremetaverse_types::Vector3 {
|
||||
x: position.x + forward.x * 4.0,
|
||||
y: position.y + forward.y * 4.0,
|
||||
z: position.z + forward.z * 4.0,
|
||||
};
|
||||
agent
|
||||
.movement
|
||||
.camera
|
||||
.look_at_with_vector3_vector3(position, target)?;
|
||||
agent.movement.set_fov_vertical_angle(60.0_f32.to_radians())
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
fn native_inventory_metadata(
|
||||
client: &libremetaverse::GridClient,
|
||||
@@ -1089,6 +1101,23 @@ impl crate::session::GridSessionBackend for LibremetaverseSessionBackend {
|
||||
)
|
||||
})?;
|
||||
if logged_in {
|
||||
let simulator = self.network.current_sim().ok_or_else(|| {
|
||||
crate::session::SessionFailure::new(
|
||||
crate::session::SessionFailureKind::TransientTransport,
|
||||
)
|
||||
})?;
|
||||
self.throttle
|
||||
.set_with_simulator(Some(simulator))
|
||||
.map_err(|_| {
|
||||
crate::session::SessionFailure::new(
|
||||
crate::session::SessionFailureKind::TransientTransport,
|
||||
)
|
||||
})?;
|
||||
native_reset_camera(&self.agent).map_err(|_| {
|
||||
crate::session::SessionFailure::new(
|
||||
crate::session::SessionFailureKind::TransientTransport,
|
||||
)
|
||||
})?;
|
||||
break;
|
||||
}
|
||||
let error_key = self.network.native_login_error_key();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,9 +35,76 @@ fn uuid(value: u32) -> UUID {
|
||||
fn triangle(z: f32, color: [u8; 4]) -> SceneTriangle {
|
||||
SceneTriangle {
|
||||
vertices: [[-1.0, -1.0, z], [1.0, -1.0, z], [0.0, 1.0, z]],
|
||||
color_srgb: color,
|
||||
colors_srgb: [color; 3],
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[test]
|
||||
fn extended_terrain_layout_uses_received_patch_coordinates() {
|
||||
let mut terrain = (0..65_536)
|
||||
.map(|_| libremetaverse::TerrainPatch {
|
||||
data: Vec::new(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
terrain[33 * 256 + 42] = libremetaverse::TerrainPatch {
|
||||
data: vec![20.0; 256],
|
||||
x: 42,
|
||||
y: 33,
|
||||
};
|
||||
assert_eq!(terrain_layout(&terrain, (256.0, 256.0)), (688, 544, 256));
|
||||
assert_eq!(terrain_height(&terrain, 256, 675, 538), Some(20.0));
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[test]
|
||||
fn renderer_uses_the_camera_axis_that_points_at_the_requested_target() {
|
||||
let camera = libremetaverse::AgentManagerAgentMovementAgentCamera::new().unwrap();
|
||||
camera
|
||||
.look_at_with_vector3_vector3(
|
||||
libremetaverse_types::Vector3::zero(),
|
||||
libremetaverse_types::Vector3::unit_y(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
native_camera_forward(&camera),
|
||||
libremetaverse_types::Vector3::unit_y()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[test]
|
||||
fn scene_faces_are_shaded_without_changing_alpha() {
|
||||
let shade = triangle_shade([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]);
|
||||
let color = shade_color([200, 160, 120, 77], shade);
|
||||
assert!(color[0] < 200);
|
||||
assert_eq!(color[3], 77);
|
||||
}
|
||||
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[test]
|
||||
fn scene_broad_phase_rejects_object_centers_behind_the_camera() {
|
||||
assert!(scene_center_in_front(
|
||||
libremetaverse_types::Vector3 {
|
||||
x: 4.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
},
|
||||
[0.0; 3],
|
||||
[1.0, 0.0, 0.0]
|
||||
));
|
||||
assert!(!scene_center_in_front(
|
||||
libremetaverse_types::Vector3 {
|
||||
x: -4.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
},
|
||||
[0.0; 3],
|
||||
[1.0, 0.0, 0.0]
|
||||
));
|
||||
}
|
||||
fn scene() -> SceneSnapshot {
|
||||
SceneSnapshot {
|
||||
generation: 7,
|
||||
@@ -123,7 +190,7 @@ async fn golden_scene_is_deterministic_depth_ordered_and_privacy_marked() {
|
||||
#[cfg(feature = "live-grid")]
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn offscreen_wgpu_renders_depth_ordered_scene_when_an_adapter_is_available() {
|
||||
let Ok(renderer) = WgpuRenderer::new().await else {
|
||||
let Ok(renderer) = metacrate_rendering_wgpu::Renderer::new().await else {
|
||||
return;
|
||||
};
|
||||
let limits = VisionLimits {
|
||||
@@ -132,10 +199,28 @@ async fn offscreen_wgpu_renders_depth_ordered_scene_when_an_adapter_is_available
|
||||
minimum_interval: std::time::Duration::ZERO,
|
||||
..VisionLimits::default()
|
||||
};
|
||||
let rgba = tokio::task::spawn_blocking(move || renderer.render(&scene(), limits))
|
||||
.await
|
||||
.expect("render worker")
|
||||
.expect("offscreen render");
|
||||
let scene = scene();
|
||||
let triangles = scene
|
||||
.entities
|
||||
.iter()
|
||||
.flat_map(|entity| entity.triangles.iter().cloned())
|
||||
.collect::<Vec<_>>();
|
||||
let rgba = tokio::task::spawn_blocking(move || {
|
||||
renderer.render(
|
||||
scene.camera,
|
||||
&triangles,
|
||||
[72, 96, 120, 255],
|
||||
metacrate_rendering_wgpu::RenderLimits {
|
||||
width: limits.width,
|
||||
height: limits.height,
|
||||
max_triangles: limits.max_triangles,
|
||||
far_distance: 512,
|
||||
},
|
||||
)
|
||||
})
|
||||
.await
|
||||
.expect("render worker")
|
||||
.expect("offscreen render");
|
||||
assert_eq!(rgba.len(), 64 * 64 * 4);
|
||||
let center = (32 * 64 + 32) * 4;
|
||||
assert!(rgba[center + 1] > 180 && rgba[center] < 80 && rgba[center + 2] < 80);
|
||||
|
||||
@@ -10,6 +10,7 @@ const ALLOWED_DEPENDENCIES: [&str; 20] = [
|
||||
"libremetaverse-imaging",
|
||||
"libremetaverse-rendering-simple",
|
||||
"metacrate-lsl-tools",
|
||||
"metacrate-rendering-wgpu",
|
||||
"mentra",
|
||||
"jpeg-encoder",
|
||||
"libremetaverse-types",
|
||||
@@ -22,7 +23,6 @@ const ALLOWED_DEPENDENCIES: [&str; 20] = [
|
||||
"tokio-rustls",
|
||||
"url",
|
||||
"unicode-width",
|
||||
"wgpu",
|
||||
];
|
||||
|
||||
#[test]
|
||||
@@ -101,7 +101,10 @@ fn vision_path_selects_only_reviewed_rust_renderers_and_codec() {
|
||||
.expect("simple renderer manifest");
|
||||
assert!(!renderer.contains("imaging-skia"));
|
||||
assert!(!renderer.contains("openjpeg"));
|
||||
assert!(manifest.contains("wgpu = { version = \"30.0.1\""));
|
||||
assert!(manifest.contains("metacrate-rendering-wgpu ="));
|
||||
let renderer = fs::read_to_string(root.join("../metacrate-rendering-wgpu/Cargo.toml"))
|
||||
.expect("wgpu renderer manifest");
|
||||
assert!(renderer.contains("wgpu = { version = \"30.0.1\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user