Add transportable chunk artifacts
This commit is contained in:
parent
cfbbad7033
commit
82d341be5f
3 changed files with 201 additions and 6 deletions
135
src/domain.rs
135
src/domain.rs
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
Aabb, BrushOp, BuildReport, CsgBranchOp, CsgNodeId, CsgOperationType, CsgTreeArena, MaterialId,
|
||||
Primitive, TriangleMesh,
|
||||
Primitive, TriangleMesh, TriangleMeshDocument,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
@ -597,6 +597,110 @@ pub struct TriangleChunkManifest {
|
|||
pub transition_hint: ChunkTransitionHint,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TriangleChunkDocument {
|
||||
pub manifest: TriangleChunkManifest,
|
||||
pub mesh: TriangleMeshDocument,
|
||||
pub collider_mesh: Option<TriangleMeshDocument>,
|
||||
}
|
||||
|
||||
impl TriangleChunkDocument {
|
||||
pub fn from_chunk(chunk: &TriangleChunk) -> Self {
|
||||
Self {
|
||||
manifest: chunk.manifest(),
|
||||
mesh: TriangleMeshDocument::from_mesh(&chunk.mesh),
|
||||
collider_mesh: chunk
|
||||
.collider_mesh
|
||||
.as_ref()
|
||||
.map(TriangleMeshDocument::from_mesh),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json(&self) -> Result<String, serde_json::Error> {
|
||||
serde_json::to_string(self)
|
||||
}
|
||||
|
||||
pub fn from_json(source: &str) -> Result<Self, serde_json::Error> {
|
||||
serde_json::from_str(source)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SelectedCutManifest {
|
||||
pub id: String,
|
||||
pub selected_nodes: Vec<String>,
|
||||
pub deferred_child_requests: Vec<String>,
|
||||
pub parent_fallback_nodes: Vec<String>,
|
||||
pub diagnostics: Vec<ContributionManifest>,
|
||||
pub chunks: Vec<TriangleChunkManifest>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ContributionManifest {
|
||||
pub domain_key: String,
|
||||
pub kind: DomainKind,
|
||||
pub contribution: f32,
|
||||
pub projected_screen_error: f32,
|
||||
pub semantic_priority: f32,
|
||||
pub estimated_triangle_cost: usize,
|
||||
pub child_cost: usize,
|
||||
pub remaining_triangle_budget: usize,
|
||||
pub requested: bool,
|
||||
pub dirty: bool,
|
||||
pub selected: bool,
|
||||
pub used_fallback: bool,
|
||||
pub deferred_by_budget: bool,
|
||||
}
|
||||
|
||||
impl SelectedCut {
|
||||
pub fn manifest(&self, chunks: &[TriangleChunk]) -> SelectedCutManifest {
|
||||
SelectedCutManifest {
|
||||
id: self.id.clone(),
|
||||
selected_nodes: self
|
||||
.selected_nodes
|
||||
.iter()
|
||||
.map(|key| key.0.clone())
|
||||
.collect(),
|
||||
deferred_child_requests: self
|
||||
.deferred_children
|
||||
.iter()
|
||||
.map(|key| key.0.clone())
|
||||
.collect(),
|
||||
parent_fallback_nodes: self
|
||||
.fallback_nodes
|
||||
.iter()
|
||||
.map(|key| key.0.clone())
|
||||
.collect(),
|
||||
diagnostics: self
|
||||
.diagnostics
|
||||
.iter()
|
||||
.map(ContributionManifest::from_row)
|
||||
.collect(),
|
||||
chunks: chunks.iter().map(TriangleChunk::manifest).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContributionManifest {
|
||||
pub fn from_row(row: &ContributionRow) -> Self {
|
||||
Self {
|
||||
domain_key: row.domain_key.0.clone(),
|
||||
kind: row.kind,
|
||||
contribution: row.contribution,
|
||||
projected_screen_error: row.projected_screen_error,
|
||||
semantic_priority: row.semantic_priority,
|
||||
estimated_triangle_cost: row.estimated_triangle_cost,
|
||||
child_cost: row.child_cost,
|
||||
remaining_triangle_budget: row.remaining_triangle_budget,
|
||||
requested: row.requested,
|
||||
dirty: row.dirty,
|
||||
selected: row.selected,
|
||||
used_fallback: row.used_fallback,
|
||||
deferred_by_budget: row.deferred_by_budget,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ChunkTransitionHint {
|
||||
pub stable_clip_seed: u64,
|
||||
|
|
@ -1521,6 +1625,35 @@ mod tests {
|
|||
assert_ne!(manifest.transition_hint.stable_clip_seed, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn triangle_chunk_document_round_trips_transport_mesh() {
|
||||
let fixture = ragnarok_column_fixture();
|
||||
let cut = select_domain_cut(&fixture, &query(0.01, 10_000));
|
||||
let chunks = lower_selected_cut_chunks(&cut);
|
||||
let document = TriangleChunkDocument::from_chunk(&chunks[0]);
|
||||
let json = document.to_json().unwrap();
|
||||
let decoded = TriangleChunkDocument::from_json(&json).unwrap();
|
||||
let mesh = decoded.mesh.to_mesh();
|
||||
assert_eq!(decoded.manifest.key, chunks[0].key.0);
|
||||
assert_eq!(mesh.indices, chunks[0].mesh.indices);
|
||||
assert_eq!(
|
||||
decoded.collider_mesh.unwrap().to_mesh().triangle_count(),
|
||||
chunks[0].collider_mesh.as_ref().unwrap().triangle_count()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selected_cut_manifest_carries_worker_artifact_context() {
|
||||
let fixture = ragnarok_column_fixture();
|
||||
let cut = select_domain_cut(&fixture, &query(0.01, 10_000));
|
||||
let chunks = lower_selected_cut_chunks(&cut);
|
||||
let manifest = cut.manifest(&chunks);
|
||||
assert_eq!(manifest.id, cut.id);
|
||||
assert_eq!(manifest.chunks.len(), chunks.len());
|
||||
assert_eq!(manifest.selected_nodes.len(), cut.selected_nodes.len());
|
||||
assert!(!manifest.diagnostics.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn requested_chunk_bypasses_frustum_and_budget() {
|
||||
let fixture = ragnarok_column_fixture();
|
||||
|
|
|
|||
11
src/lib.rs
11
src/lib.rs
|
|
@ -21,16 +21,17 @@ pub use assembler::{Assembler, BuildOutput, BuildReport, BuildWarning};
|
|||
pub use brush::{Aabb, Brush, BrushId, BrushOp, MaterialId, PolygonCategory, Primitive};
|
||||
pub use convex::{CategorizedPolygons, ConvexPolygon, ConvexSolid, Plane, PolygonRouteScratch};
|
||||
pub use domain::{
|
||||
ClaimLoweringTarget, ContributionRow, CsgClaimLowering, DomainFrame, DomainKey, DomainKind,
|
||||
DomainNode, DomainNodeDocument, DomainNodeSpec, DomainQuery, DomainSpecDocument, DomainSummary,
|
||||
FeatureClaim, FeatureClaimDocument, FeatureClaimKind, FeatureClaimSpec, FeatureLoweringPolicy,
|
||||
FieldEncoding, FieldLayer, SelectedCut, TriangleChunk, TriangleChunkManifest,
|
||||
ClaimLoweringTarget, ContributionManifest, ContributionRow, CsgClaimLowering, DomainFrame,
|
||||
DomainKey, DomainKind, DomainNode, DomainNodeDocument, DomainNodeSpec, DomainQuery,
|
||||
DomainSpecDocument, DomainSummary, FeatureClaim, FeatureClaimDocument, FeatureClaimKind,
|
||||
FeatureClaimSpec, FeatureLoweringPolicy, FieldEncoding, FieldLayer, SelectedCut,
|
||||
SelectedCutManifest, TriangleChunk, TriangleChunkDocument, TriangleChunkManifest,
|
||||
lower_feature_claims_to_csg_tree, lower_selected_cut, lower_selected_cut_chunks,
|
||||
ragnarok_column_fixture, ragnarok_column_spec, select_domain_cut,
|
||||
};
|
||||
pub use dsl::LevelDsl;
|
||||
pub use frontier::{DemandFrontier, DemandPair, DirtyDemandFrontier};
|
||||
pub use mesh::TriangleMesh;
|
||||
pub use mesh::{TriangleMesh, TriangleMeshDocument};
|
||||
pub use primitives::{
|
||||
DomeCapZSpec, FloretArmSpec, append_cylinder_z, append_dome_cap_z, append_floret_arm,
|
||||
};
|
||||
|
|
|
|||
61
src/mesh.rs
61
src/mesh.rs
|
|
@ -1,4 +1,5 @@
|
|||
use bevy_math::{Vec2, Vec3};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Aabb, MaterialId};
|
||||
|
||||
|
|
@ -100,3 +101,63 @@ impl TriangleMesh {
|
|||
self.triangle_materials.push(material);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TriangleMeshDocument {
|
||||
pub positions: Vec<[f32; 3]>,
|
||||
pub normals: Vec<[f32; 3]>,
|
||||
pub uvs: Vec<[f32; 2]>,
|
||||
pub indices: Vec<u32>,
|
||||
pub triangle_materials: Vec<u32>,
|
||||
}
|
||||
|
||||
impl TriangleMeshDocument {
|
||||
pub fn from_mesh(mesh: &TriangleMesh) -> Self {
|
||||
Self {
|
||||
positions: mesh
|
||||
.positions
|
||||
.iter()
|
||||
.map(|value| [value.x, value.y, value.z])
|
||||
.collect(),
|
||||
normals: mesh
|
||||
.normals
|
||||
.iter()
|
||||
.map(|value| [value.x, value.y, value.z])
|
||||
.collect(),
|
||||
uvs: mesh.uvs.iter().map(|value| [value.x, value.y]).collect(),
|
||||
indices: mesh.indices.clone(),
|
||||
triangle_materials: mesh
|
||||
.triangle_materials
|
||||
.iter()
|
||||
.map(|material| material.0)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_mesh(&self) -> TriangleMesh {
|
||||
TriangleMesh {
|
||||
positions: self
|
||||
.positions
|
||||
.iter()
|
||||
.map(|value| Vec3::new(value[0], value[1], value[2]))
|
||||
.collect(),
|
||||
normals: self
|
||||
.normals
|
||||
.iter()
|
||||
.map(|value| Vec3::new(value[0], value[1], value[2]))
|
||||
.collect(),
|
||||
uvs: self
|
||||
.uvs
|
||||
.iter()
|
||||
.map(|value| Vec2::new(value[0], value[1]))
|
||||
.collect(),
|
||||
indices: self.indices.clone(),
|
||||
triangle_materials: self
|
||||
.triangle_materials
|
||||
.iter()
|
||||
.copied()
|
||||
.map(MaterialId)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue