Skip to content

Commit

Permalink
3dtiles: Add _FEATURE_ID_0 attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
ciscorn committed Feb 27, 2024
1 parent 46405a7 commit 6e19cca
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
51 changes: 43 additions & 8 deletions nusamai/src/sink/cesiumtiles/gltf.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use std::io::Write;

use super::material;
use ahash::HashMap;
use ahash::{HashMap, HashSet};
use byteorder::{ByteOrder, LittleEndian};
use indexmap::IndexSet;
use nusamai_gltf_json::extensions::mesh::ext_mesh_features;

pub type Primitives = HashMap<material::Material, Vec<u32>>;
#[derive(Default)]
pub struct PrimitiveInfo {
pub indices: Vec<u32>,
pub feature_ids: HashSet<u32>,
}

pub type Primitives = HashMap<material::Material, PrimitiveInfo>;

/// とりいそぎの実装
pub fn write_gltf_glb<W: Write>(
writer: W,
translation: [f64; 3],
vertices: impl IntoIterator<Item = [u32; 5]>,
vertices: impl IntoIterator<Item = [u32; 6]>,
primitives: Primitives,
) -> std::io::Result<()> {
use nusamai_gltf_json::*;
Expand All @@ -27,10 +34,12 @@ pub fn write_gltf_glb<W: Write>(
let mut position_max = [f64::MIN; 3];
let mut position_min = [f64::MAX; 3];

const VERTEX_BYTE_STRIDE: usize = 4 * 6; // 4-bytes (u32) x 6

let buffer_offset = bin_content.len();
let mut buf = [0; 4 * 5];
let mut buf = [0; VERTEX_BYTE_STRIDE];
for v in vertices {
let [x, y, z, u, v] = v;
let [x, y, z, u, v, feature_id] = v;
position_min = [
f64::min(position_min[0], f32::from_bits(x) as f64),
f64::min(position_min[1], f32::from_bits(y) as f64),
Expand All @@ -42,15 +51,15 @@ pub fn write_gltf_glb<W: Write>(
f64::max(position_max[2], f32::from_bits(z) as f64),
];

LittleEndian::write_u32_into(&[x, y, z, u, v], &mut buf);
LittleEndian::write_u32_into(&[x, y, z, u, v, feature_id], &mut buf);
bin_content.write_all(&buf)?;
vertices_count += 1;
}

gltf_buffer_views.push(BufferView {
byte_offset: buffer_offset as u32,
byte_length: (bin_content.len() - buffer_offset) as u32,
byte_stride: Some(4 * 5),
byte_stride: Some(VERTEX_BYTE_STRIDE as u8),
target: Some(BufferViewTarget::ArrayBuffer),
..Default::default()
});
Expand All @@ -75,6 +84,16 @@ pub fn write_gltf_glb<W: Write>(
type_: AccessorType::Vec2,
..Default::default()
});

// accessor (feature_id)
gltf_accessors.push(Accessor {
buffer_view: Some(gltf_buffer_views.len() as u32 - 1),
byte_offset: 4 * 5,
component_type: ComponentType::Float,
count: vertices_count,
type_: AccessorType::Scalar,
..Default::default()
});
}

let mut gltf_primitives = vec![];
Expand All @@ -86,7 +105,7 @@ pub fn write_gltf_glb<W: Write>(
let mut byte_offset = 0;
for (mat_i, (mat, primitive)) in primitives.iter().enumerate() {
let mut indices_count = 0;
for idx in primitive {
for idx in &primitive.indices {
bin_content.write_all(&idx.to_le_bytes())?;
indices_count += 1;
}
Expand All @@ -101,15 +120,30 @@ pub fn write_gltf_glb<W: Write>(
});

let mut attributes = vec![("POSITION".to_string(), 0)];
// TODO: It will be better for no-texture data to exclude u, v from the vertex buffer
if mat.base_texture.is_some() {
attributes.push(("TEXCOORD_0".to_string(), 1));
}
attributes.push(("_FEATURE_ID_0".to_string(), 2));

gltf_primitives.push(MeshPrimitive {
attributes: attributes.into_iter().collect(),
indices: Some(gltf_accessors.len() as u32 - 1),
material: Some(mat_i as u32), // TODO
mode: PrimitiveMode::Triangles,
extensions: extensions::mesh::MeshPrimitive {
ext_mesh_features: ext_mesh_features::ExtMeshFeatures {
feature_ids: vec![ext_mesh_features::FeatureId {
attribute: Some(0),
feature_count: primitive.feature_ids.len() as u32,
..Default::default()
}],
..Default::default()
}
.into(),
..Default::default()
}
.into(),
..Default::default()
});

Expand Down Expand Up @@ -171,6 +205,7 @@ pub fn write_gltf_glb<W: Write>(
accessors: gltf_accessors,
buffer_views: gltf_buffer_views,
buffers: gltf_buffers,
extensions_used: vec!["EXT_mesh_features".to_string()],
..Default::default()
};

Expand Down
10 changes: 6 additions & 4 deletions nusamai/src/sink/cesiumtiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,11 @@ fn tile_writing_stage(
let mut buf2d: Vec<f64> = Vec::new(); // 2d-projected [x, y]
let mut index_buf: Vec<u32> = Vec::new();

let mut vertices: IndexSet<[u32; 5], RandomState> = IndexSet::default();
let mut vertices: IndexSet<[u32; 6], RandomState> = IndexSet::default(); // [x, y, z, u, v, feature_id]
let mut primitives: gltf::Primitives = Default::default();

// make vertices and indices
for serialized_feat in serialized_feats {
for (feature_idx, serialized_feat) in serialized_feats.into_iter().enumerate() {
feedback.ensure_not_canceled()?;

let mut feature: SlicedFeature = bincode::deserialize(&serialized_feat.body)
Expand Down Expand Up @@ -292,14 +292,15 @@ fn tile_writing_stage(
};

let mat = feature.materials[*orig_mat_id as usize].clone();
let indices = primitives.entry(mat).or_default();
let primitive = primitives.entry(mat).or_default();
primitive.feature_ids.insert(feature_idx as u32);

if project3d_to_2d(poly.coords(), num_outer, 5, &mut buf2d) {
// earcut
earcutter.earcut(&buf2d, poly.hole_indices(), 2, &mut index_buf);

// collect triangles
indices.extend(index_buf.iter().map(|idx| {
primitive.indices.extend(index_buf.iter().map(|idx| {
let pos = *idx as usize * 5;
let [x, y, z, u, v] = poly.coords()[pos..pos + 5].try_into().unwrap();
let vbits = [
Expand All @@ -308,6 +309,7 @@ fn tile_writing_stage(
(z as f32).to_bits(),
(u as f32).to_bits(),
(v as f32).to_bits(),
(feature_idx as f32).to_bits(), // UNSIGNED_INT can't be used for vertex attribute
];
let (index, _) = vertices.insert_full(vbits);
index as u32
Expand Down

0 comments on commit 6e19cca

Please sign in to comment.