From a62cb2b6ad23d1d25f3e855964055803f5d3ec9b Mon Sep 17 00:00:00 2001 From: Keyvan Goddard Date: Mon, 16 Sep 2024 11:19:34 +0200 Subject: [PATCH 01/11] Add `albedo_factor` to stl/obj `Asset3D` (Rust) - add attribute `albedo_factor` and method `with_albedo_factor` to archetype `Asset3D`. - update stl/obj loader : `load_stl_from_buffer` and `load_obj_from_buffer` to process `albedo_factor`. --- Cargo.lock | 1 + .../definitions/rerun/archetypes/asset3d.fbs | 16 +++ .../store/re_types/src/archetypes/asset3d.rs | 130 ++++++++++++++++-- .../re_types/src/archetypes/asset3d_ext.rs | 25 +++- crates/store/re_types/tests/types/asset3d.rs | 12 +- crates/viewer/re_renderer/Cargo.toml | 1 + crates/viewer/re_renderer/src/importer/obj.rs | 4 +- crates/viewer/re_renderer/src/importer/stl.rs | 16 ++- .../viewer/re_renderer_examples/framework.rs | 7 +- .../re_space_view_spatial/src/mesh_cache.rs | 8 +- .../re_space_view_spatial/src/mesh_loader.rs | 35 +++-- .../src/visualizers/assets3d.rs | 75 +++++++--- .../reference/types/archetypes/asset3d.md | 2 + .../types/components/albedo_factor.md | 1 + .../types/components/image_buffer.md | 1 + .../types/components/image_format.md | 1 + rerun_cpp/src/rerun/archetypes/asset3d.cpp | 17 ++- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 45 ++++++ .../rerun_sdk/rerun/archetypes/asset3d.py | 35 +++++ 19 files changed, 383 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 962d25303729..4aba4065c846 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5320,6 +5320,7 @@ dependencies = [ "re_log", "re_math", "re_tracing", + "re_types", "re_video", "serde", "slotmap", diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index 2018e21dcdfa..16a61464e296 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -33,4 +33,20 @@ table Asset3D ( /// If omitted, the viewer will try to guess from the data blob. /// If it cannot guess, it won't be able to render the asset. media_type: rerun.components.MediaType ("attr.rerun.component_recommended", nullable, order: 2000); + + // --- Optional --- + + /// A color multiplier applied to the whole asset. + albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); + + /// Optional albedo texture. + /// + /// Used with the [components.Texcoord2D] of the mesh. + /// + /// Currently supports only sRGB(A) textures, ignoring alpha. + /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + albedo_texture_buffer: rerun.components.ImageBuffer ("attr.rerun.component_optional", nullable, order: 3400); + + /// The format of the `albedo_texture_buffer`, if any. + albedo_texture_format: rerun.components.ImageFormat ("attr.rerun.component_optional", nullable, order: 3450); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index ab48155cc121..d084dffa79e5 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -70,17 +70,39 @@ pub struct Asset3D { /// If omitted, the viewer will try to guess from the data blob. /// If it cannot guess, it won't be able to render the asset. pub media_type: Option, + + /// A color multiplier applied to the whole asset. + pub albedo_factor: Option, + + /// Optional albedo texture. + /// + /// Used with the [`components::Texcoord2D`][crate::components::Texcoord2D] of the mesh. + /// + /// Currently supports only sRGB(A) textures, ignoring alpha. + /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + pub albedo_texture_buffer: Option, + + /// The format of the `albedo_texture_buffer`, if any. + pub albedo_texture_format: Option, } impl ::re_types_core::SizeBytes for Asset3D { #[inline] fn heap_size_bytes(&self) -> u64 { - self.blob.heap_size_bytes() + self.media_type.heap_size_bytes() + self.blob.heap_size_bytes() + + self.media_type.heap_size_bytes() + + self.albedo_factor.heap_size_bytes() + + self.albedo_texture_buffer.heap_size_bytes() + + self.albedo_texture_format.heap_size_bytes() } #[inline] fn is_pod() -> bool { - ::is_pod() && >::is_pod() + ::is_pod() + && >::is_pod() + && >::is_pod() + && >::is_pod() + && >::is_pod() } } @@ -95,21 +117,30 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 0usize]> = - once_cell::sync::Lazy::new(|| []); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.components.AlbedoFactor".into(), + "rerun.components.ImageBuffer".into(), + "rerun.components.ImageFormat".into(), + ] + }); -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 6usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.components.Blob".into(), "rerun.components.MediaType".into(), "rerun.components.Asset3DIndicator".into(), + "rerun.components.AlbedoFactor".into(), + "rerun.components.ImageBuffer".into(), + "rerun.components.ImageFormat".into(), ] }); impl Asset3D { - /// The total number of components in the archetype: 1 required, 2 recommended, 0 optional - pub const NUM_COMPONENTS: usize = 3usize; + /// The total number of components in the archetype: 1 required, 2 recommended, 3 optional + pub const NUM_COMPONENTS: usize = 6usize; } /// Indicator component for the [`Asset3D`] [`::re_types_core::Archetype`] @@ -186,7 +217,43 @@ impl ::re_types_core::Archetype for Asset3D { } else { None }; - Ok(Self { blob, media_type }) + let albedo_factor = if let Some(array) = arrays_by_name.get("rerun.components.AlbedoFactor") + { + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Asset3D#albedo_factor")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let albedo_texture_buffer = + if let Some(array) = arrays_by_name.get("rerun.components.ImageBuffer") { + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Asset3D#albedo_texture_buffer")? + .into_iter() + .next() + .flatten() + } else { + None + }; + let albedo_texture_format = + if let Some(array) = arrays_by_name.get("rerun.components.ImageFormat") { + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Asset3D#albedo_texture_format")? + .into_iter() + .next() + .flatten() + } else { + None + }; + Ok(Self { + blob, + media_type, + albedo_factor, + albedo_texture_buffer, + albedo_texture_format, + }) } } @@ -200,6 +267,15 @@ impl ::re_types_core::AsComponents for Asset3D { self.media_type .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), + self.albedo_factor + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.albedo_texture_buffer + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), + self.albedo_texture_format + .as_ref() + .map(|comp| (comp as &dyn ComponentBatch).into()), ] .into_iter() .flatten() @@ -216,6 +292,9 @@ impl Asset3D { Self { blob: blob.into(), media_type: None, + albedo_factor: None, + albedo_texture_buffer: None, + albedo_texture_format: None, } } @@ -234,4 +313,39 @@ impl Asset3D { self.media_type = Some(media_type.into()); self } + + /// A color multiplier applied to the whole asset. + #[inline] + pub fn with_albedo_factor( + mut self, + albedo_factor: impl Into, + ) -> Self { + self.albedo_factor = Some(albedo_factor.into()); + self + } + + /// Optional albedo texture. + /// + /// Used with the [`components::Texcoord2D`][crate::components::Texcoord2D] of the mesh. + /// + /// Currently supports only sRGB(A) textures, ignoring alpha. + /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + #[inline] + pub fn with_albedo_texture_buffer( + mut self, + albedo_texture_buffer: impl Into, + ) -> Self { + self.albedo_texture_buffer = Some(albedo_texture_buffer.into()); + self + } + + /// The format of the `albedo_texture_buffer`, if any. + #[inline] + pub fn with_albedo_texture_format( + mut self, + albedo_texture_format: impl Into, + ) -> Self { + self.albedo_texture_format = Some(albedo_texture_format.into()); + self + } } diff --git a/crates/store/re_types/src/archetypes/asset3d_ext.rs b/crates/store/re_types/src/archetypes/asset3d_ext.rs index 78fd8a78f998..255d32b7fbb8 100644 --- a/crates/store/re_types/src/archetypes/asset3d_ext.rs +++ b/crates/store/re_types/src/archetypes/asset3d_ext.rs @@ -1,4 +1,6 @@ -use crate::components::MediaType; +use crate::components::{self, MediaType}; + +use crate::archetypes; use super::Asset3D; @@ -32,10 +34,29 @@ impl Asset3D { #[inline] pub fn from_file_contents(contents: Vec, media_type: Option>) -> Self { let media_type = media_type.map(Into::into); - let media_type = MediaType::or_guess_from_data(media_type, &contents); Self { blob: contents.into(), media_type, + albedo_factor: None, + albedo_texture_buffer: None, + albedo_texture_format: None, } } + + /// Use this image as the albedo texture. + pub fn with_albedo_texture_image(self, image: impl Into) -> Self { + let image = image.into(); + self.with_albedo_texture_format(image.format) + .with_albedo_texture_buffer(image.buffer) + } + + /// Use this image as the albedo texture. + pub fn with_albedo_texture( + self, + image_format: impl Into, + image_buffer: impl Into, + ) -> Self { + self.with_albedo_texture_format(image_format) + .with_albedo_texture_buffer(image_buffer) + } } diff --git a/crates/store/re_types/tests/types/asset3d.rs b/crates/store/re_types/tests/types/asset3d.rs index 415ea3b81ea5..963f974885dc 100644 --- a/crates/store/re_types/tests/types/asset3d.rs +++ b/crates/store/re_types/tests/types/asset3d.rs @@ -1,7 +1,7 @@ use re_types::{ archetypes::Asset3D, components::{Blob, MediaType}, - datatypes::Utf8, + datatypes::{Rgba32, Utf8}, Archetype as _, AsComponents as _, }; @@ -9,12 +9,20 @@ use re_types::{ fn roundtrip() { const BYTES: &[u8] = &[1, 2, 3, 4, 5, 6]; + let texture_format = re_types::components::ImageFormat::rgb8([2, 3]); + let texture_buffer = re_types::components::ImageBuffer::from(vec![0x42_u8; 2 * 3 * 3]); + let expected = Asset3D { blob: Blob(BYTES.to_vec().into()), media_type: Some(MediaType(Utf8(MediaType::GLTF.into()))), + albedo_factor: Some(Rgba32::from_unmultiplied_rgba(0xEE, 0x11, 0x22, 0x33).into()), + albedo_texture_format: Some(texture_format), + albedo_texture_buffer: Some(texture_buffer.clone()), }; - let arch = Asset3D::from_file_contents(BYTES.to_vec(), Some(MediaType::gltf())); + let arch = Asset3D::from_file_contents(BYTES.to_vec(), Some(MediaType::gltf())) + .with_albedo_factor(0xEE112233) + .with_albedo_texture(texture_format, texture_buffer); similar_asserts::assert_eq!(expected, arch); // let expected_extensions: HashMap<_, _> = [ diff --git a/crates/viewer/re_renderer/Cargo.toml b/crates/viewer/re_renderer/Cargo.toml index 0ee4ef3e6537..9edee6969e5a 100644 --- a/crates/viewer/re_renderer/Cargo.toml +++ b/crates/viewer/re_renderer/Cargo.toml @@ -53,6 +53,7 @@ re_log.workspace = true re_math.workspace = true re_tracing.workspace = true re_video.workspace = true +re_types.workspace = true ahash.workspace = true anyhow.workspace = true diff --git a/crates/viewer/re_renderer/src/importer/obj.rs b/crates/viewer/re_renderer/src/importer/obj.rs index 88414dd16782..ff3bfe3b25cf 100644 --- a/crates/viewer/re_renderer/src/importer/obj.rs +++ b/crates/viewer/re_renderer/src/importer/obj.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use re_types::components::AlbedoFactor; use smallvec::smallvec; use crate::{ @@ -22,6 +23,7 @@ pub enum ObjImportError { pub fn load_obj_from_buffer( buffer: &[u8], ctx: &RenderContext, + albedo_factor: Option, ) -> Result, ObjImportError> { re_tracing::profile_function!(); @@ -97,7 +99,7 @@ pub fn load_obj_from_buffer( label: "default material".into(), index_range: 0..mesh.indices.len() as u32, albedo: texture.clone(), - albedo_factor: crate::Rgba::WHITE, + albedo_factor: albedo_factor.map_or(crate::Rgba::WHITE, |c| c.0.into()), }], }; diff --git a/crates/viewer/re_renderer/src/importer/stl.rs b/crates/viewer/re_renderer/src/importer/stl.rs index a78994aef386..400a753d51cf 100644 --- a/crates/viewer/re_renderer/src/importer/stl.rs +++ b/crates/viewer/re_renderer/src/importer/stl.rs @@ -9,6 +9,7 @@ use crate::{ renderer::MeshInstance, RenderContext, }; +use re_types::archetypes::Asset3D; #[derive(thiserror::Error, Debug)] pub enum StlImportError { @@ -21,11 +22,20 @@ pub enum StlImportError { /// Load a [STL .stl file](https://en.wikipedia.org/wiki/STL_(file_format)) into the mesh manager. pub fn load_stl_from_buffer( - buffer: &[u8], + asset3d: &Asset3D, ctx: &RenderContext, + _texture_key: u64, ) -> Result, StlImportError> { re_tracing::profile_function!(); + let Asset3D { + blob, + albedo_factor, + .. + } = asset3d; + + let buffer = blob.as_slice(); + let cursor = std::io::Cursor::new(buffer); let StlData { name, @@ -37,10 +47,10 @@ pub fn load_stl_from_buffer( let num_vertices = triangles.len() * 3; let material = mesh::Material { - label: "default material".into(), + label: name.clone().into(), index_range: 0..num_vertices as u32, albedo: ctx.texture_manager_2d.white_texture_unorm_handle().clone(), - albedo_factor: crate::Rgba::WHITE, + albedo_factor: albedo_factor.map_or(crate::Rgba::WHITE, |c| c.0.into()), }; let mesh = mesh::Mesh { diff --git a/crates/viewer/re_renderer_examples/framework.rs b/crates/viewer/re_renderer_examples/framework.rs index a034242c9143..7d6679b8cf11 100644 --- a/crates/viewer/re_renderer_examples/framework.rs +++ b/crates/viewer/re_renderer_examples/framework.rs @@ -332,7 +332,12 @@ pub fn load_rerun_mesh(re_ctx: &RenderContext) -> Vec { diff --git a/crates/viewer/re_space_view_spatial/src/mesh_cache.rs b/crates/viewer/re_space_view_spatial/src/mesh_cache.rs index 3aeb3d10d957..9c919932ba7a 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_cache.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_cache.rs @@ -36,7 +36,13 @@ pub struct MeshCache(HashMap /// Either a [`re_types::archetypes::Asset3D`] or [`re_types::archetypes::Mesh3D`] to be cached. #[derive(Debug, Clone, Copy)] pub enum AnyMesh<'a> { - Asset(&'a re_types::archetypes::Asset3D), + Asset { + asset: &'a re_types::archetypes::Asset3D, + + /// If there are any textures associated with that asset (albedo etc), they use this + /// hash for texture manager lookup. + texture_key: u64, + }, Mesh { mesh: &'a re_types::archetypes::Mesh3D, diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index 304685ec10d1..c396d2123bbb 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -27,7 +27,9 @@ impl LoadedMesh { ) -> anyhow::Result { // TODO(emilk): load CpuMesh in background thread. match mesh { - AnyMesh::Asset(asset3d) => Self::load_asset3d(name, asset3d, render_ctx), + AnyMesh::Asset { asset, texture_key } => { + Ok(Self::load_asset3d(name, asset, texture_key, render_ctx)?) + } AnyMesh::Mesh { mesh, texture_key } => { Ok(Self::load_mesh3d(name, mesh, texture_key, render_ctx)?) } @@ -37,17 +39,28 @@ impl LoadedMesh { pub fn load_asset3d_parts( name: String, media_type: &MediaType, - bytes: &[u8], + asset3d: &Asset3D, render_ctx: &RenderContext, + texture_key: u64, ) -> anyhow::Result { re_tracing::profile_function!(); + let bytes = asset3d.blob.as_slice(); + let mesh_instances = match media_type.as_str() { - MediaType::GLTF | MediaType::GLB => { - re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? + MediaType::GLTF | MediaType::GLB => re_renderer::importer::gltf::load_gltf_from_buffer( + &name, + bytes, + render_ctx, + )?, + MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer( + bytes, + render_ctx, + asset3d.albedo_factor, + )?, + MediaType::STL => { + re_renderer::importer::stl::load_stl_from_buffer(asset3d, render_ctx, texture_key)? } - MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer(bytes, render_ctx)?, - MediaType::STL => re_renderer::importer::stl::load_stl_from_buffer(bytes, render_ctx)?, _ => anyhow::bail!("{media_type} files are not supported"), }; @@ -63,15 +76,15 @@ impl LoadedMesh { fn load_asset3d( name: String, asset3d: &Asset3D, + texture_key: u64, render_ctx: &RenderContext, ) -> anyhow::Result { re_tracing::profile_function!(); - let Asset3D { blob, media_type } = asset3d; - - let media_type = MediaType::or_guess_from_data(media_type.clone(), blob.as_slice()) - .ok_or_else(|| anyhow::anyhow!("couldn't guess media type"))?; - let slf = Self::load_asset3d_parts(name, &media_type, blob.as_slice(), render_ctx)?; + let media_type = + MediaType::or_guess_from_data(asset3d.media_type.clone(), asset3d.blob.as_slice()) + .ok_or_else(|| anyhow::anyhow!("couldn't guess media type"))?; + let slf = Self::load_asset3d_parts(name, &media_type, asset3d, render_ctx, texture_key)?; Ok(slf) } diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs index 444c24210293..fc5abc9a7b1d 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs @@ -4,7 +4,7 @@ use re_renderer::renderer::MeshInstance; use re_renderer::RenderContext; use re_types::{ archetypes::Asset3D, - components::{Blob, MediaType}, + components::{AlbedoFactor, Blob, ImageBuffer, ImageFormat, MediaType}, ArrowBuffer, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -32,32 +32,31 @@ impl Default for Asset3DVisualizer { } } -struct Asset3DComponentData { +struct Asset3DComponentData<'a> { index: (TimeInt, RowId), + query_result_hash: Hash64, blob: ArrowBuffer, media_type: Option, + albedo_factor: Option<&'a AlbedoFactor>, + albedo_buffer: Option, + albedo_format: Option, } // NOTE: Do not put profile scopes in these methods. They are called for all entities and all // timestamps within a time range -- it's _a lot_. impl Asset3DVisualizer { - fn process_data( + fn process_data<'a>( &mut self, ctx: &QueryContext<'_>, render_ctx: &RenderContext, instances: &mut Vec, ent_context: &SpatialSceneEntityContext<'_>, - data: impl Iterator, + data: impl Iterator>, ) { let entity_path = ctx.target_entity_path; for data in data { - let mesh = Asset3D { - blob: data.blob.clone().into(), - media_type: data.media_type.clone().map(Into::into), - }; - let primary_row_id = data.index.1; let picking_instance_hash = re_entity_db::InstancePathHash::entity_all(entity_path); let outline_mask_ids = ent_context.highlight.index_outline_mask(Instance::ALL); @@ -65,15 +64,25 @@ impl Asset3DVisualizer { // TODO(#5974): this is subtly wrong, the key should actually be a hash of everything that got // cached, which includes the media type… let mesh = ctx.viewer_ctx.cache.entry(|c: &mut MeshCache| { + let key = MeshCacheKey { + versioned_instance_path_hash: picking_instance_hash.versioned(primary_row_id), + query_result_hash: data.query_result_hash, + media_type: data.media_type.clone().map(Into::into), + }; + c.entry( &entity_path.to_string(), - MeshCacheKey { - versioned_instance_path_hash: picking_instance_hash - .versioned(primary_row_id), - query_result_hash: Hash64::ZERO, - media_type: data.media_type.clone().map(Into::into), + key.clone(), + AnyMesh::Asset { + asset: &Asset3D { + blob: data.blob.clone().into(), + media_type: data.media_type.clone().map(Into::into), + albedo_factor: data.albedo_factor.copied(), + albedo_texture_buffer: data.albedo_buffer.clone(), // shallow clone, + albedo_texture_format: data.albedo_format, + }, + texture_key: re_log_types::hash::Hash64::hash(&key).hash64(), }, - AnyMesh::Asset(&mesh), render_ctx, ) }); @@ -155,16 +164,44 @@ impl VisualizerSystem for Asset3DVisualizer { let timeline = ctx.query.timeline(); let all_blobs_indexed = iter_buffer::(&all_blob_chunks, timeline, Blob::name()); let all_media_types = results.iter_as(timeline, MediaType::name()); - - let data = re_query::range_zip_1x1(all_blobs_indexed, all_media_types.string()) - .filter_map(|(index, blobs, media_types)| { + let all_albedo_factors = results.iter_as(timeline, AlbedoFactor::name()); + let all_albedo_buffers = results.iter_as(timeline, ImageBuffer::name()); + let all_albedo_formats = results.iter_as(timeline, ImageFormat::name()); + + let query_result_hash = results.query_result_hash(); + + let data = re_query::range_zip_1x4( + all_blobs_indexed, + all_media_types.string(), + all_albedo_factors.primitive::(), + all_albedo_buffers.component::(), + all_albedo_formats.component::(), + ) + .filter_map( + |( + index, + blobs, + media_types, + albedo_factors, + albedo_buffers, + albedo_formats, + )| { blobs.first().map(|blob| Asset3DComponentData { index, + query_result_hash, blob: blob.clone(), media_type: media_types .and_then(|media_types| media_types.first().cloned()), + albedo_factor: albedo_factors + .map_or(&[] as &[AlbedoFactor], |albedo_factors| { + bytemuck::cast_slice(albedo_factors) + }) + .first(), + albedo_buffer: albedo_buffers.unwrap_or_default().first().cloned(), // shallow clone + albedo_format: albedo_formats.unwrap_or_default().first().copied(), }) - }); + }, + ); self.process_data(ctx, render_ctx, &mut instances, spatial_ctx, data); diff --git a/docs/content/reference/types/archetypes/asset3d.md b/docs/content/reference/types/archetypes/asset3d.md index e15d67cc3740..a50835544af2 100644 --- a/docs/content/reference/types/archetypes/asset3d.md +++ b/docs/content/reference/types/archetypes/asset3d.md @@ -16,6 +16,8 @@ an instance of the mesh will be drawn for each transform. **Recommended**: [`MediaType`](../components/media_type.md) +**Optional**: [`AlbedoFactor`](../components/albedo_factor.md), [`ImageBuffer`](../components/image_buffer.md), [`ImageFormat`](../components/image_format.md) + ## Shown in * [Spatial3DView](../views/spatial3d_view.md) * [Spatial2DView](../views/spatial2d_view.md) (if logged above active projection) diff --git a/docs/content/reference/types/components/albedo_factor.md b/docs/content/reference/types/components/albedo_factor.md index 179ee779f786..ff8200054a4f 100644 --- a/docs/content/reference/types/components/albedo_factor.md +++ b/docs/content/reference/types/components/albedo_factor.md @@ -17,4 +17,5 @@ A color multiplier, usually applied to a whole entity, e.g. a mesh. ## Used by +* [`Asset3D`](../archetypes/asset3d.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/docs/content/reference/types/components/image_buffer.md b/docs/content/reference/types/components/image_buffer.md index 05956c98a3b2..9d908e7c022e 100644 --- a/docs/content/reference/types/components/image_buffer.md +++ b/docs/content/reference/types/components/image_buffer.md @@ -19,6 +19,7 @@ To interpret the contents of this buffer, see, [`components.ImageFormat`](https: ## Used by +* [`Asset3D`](../archetypes/asset3d.md) * [`DepthImage`](../archetypes/depth_image.md) * [`Image`](../archetypes/image.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/docs/content/reference/types/components/image_format.md b/docs/content/reference/types/components/image_format.md index 43b84c94f226..fa056cfc2195 100644 --- a/docs/content/reference/types/components/image_format.md +++ b/docs/content/reference/types/components/image_format.md @@ -17,6 +17,7 @@ The metadata describing the contents of a [`components.ImageBuffer`](https://rer ## Used by +* [`Asset3D`](../archetypes/asset3d.md) * [`DepthImage`](../archetypes/depth_image.md) * [`Image`](../archetypes/image.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.cpp b/rerun_cpp/src/rerun/archetypes/asset3d.cpp index 4466eb0eb17b..4ca4fa927a48 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.cpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(3); + cells.reserve(6); { auto result = ComponentBatch::from_loggable(archetype.blob); @@ -26,6 +26,21 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } + if (archetype.albedo_factor.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.albedo_factor.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.albedo_texture_buffer.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.albedo_texture_buffer.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } + if (archetype.albedo_texture_format.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.albedo_texture_format.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } { auto indicator = Asset3D::IndicatorComponent(); auto result = ComponentBatch::from_loggable(indicator); diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index 812cf71eacb9..60c3b0d04a2a 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -6,7 +6,10 @@ #include "../collection.hpp" #include "../compiler_utils.hpp" #include "../component_batch.hpp" +#include "../components/albedo_factor.hpp" #include "../components/blob.hpp" +#include "../components/image_buffer.hpp" +#include "../components/image_format.hpp" #include "../components/media_type.hpp" #include "../indicator_component.hpp" #include "../result.hpp" @@ -66,6 +69,20 @@ namespace rerun::archetypes { /// If it cannot guess, it won't be able to render the asset. std::optional media_type; + /// A color multiplier applied to the whole asset. + std::optional albedo_factor; + + /// Optional albedo texture. + /// + /// Used with the `components::Texcoord2D` of the mesh. + /// + /// Currently supports only sRGB(A) textures, ignoring alpha. + /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + std::optional albedo_texture_buffer; + + /// The format of the `albedo_texture_buffer`, if any. + std::optional albedo_texture_format; + public: static constexpr const char IndicatorComponentName[] = "rerun.components.Asset3DIndicator"; @@ -118,6 +135,34 @@ namespace rerun::archetypes { // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } + + /// A color multiplier applied to the whole asset. + Asset3D with_albedo_factor(rerun::components::AlbedoFactor _albedo_factor) && { + albedo_factor = std::move(_albedo_factor); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// Optional albedo texture. + /// + /// Used with the `components::Texcoord2D` of the mesh. + /// + /// Currently supports only sRGB(A) textures, ignoring alpha. + /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + Asset3D with_albedo_texture_buffer(rerun::components::ImageBuffer _albedo_texture_buffer + ) && { + albedo_texture_buffer = std::move(_albedo_texture_buffer); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + + /// The format of the `albedo_texture_buffer`, if any. + Asset3D with_albedo_texture_format(rerun::components::ImageFormat _albedo_texture_format + ) && { + albedo_texture_format = std::move(_albedo_texture_format); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } }; } // namespace rerun::archetypes diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 834a7cb2b4ed..ba19893a4d9b 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -62,6 +62,9 @@ def __attrs_clear__(self) -> None: self.__attrs_init__( blob=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] + albedo_factor=None, # type: ignore[arg-type] + albedo_texture_buffer=None, # type: ignore[arg-type] + albedo_texture_format=None, # type: ignore[arg-type] ) @classmethod @@ -97,5 +100,37 @@ def _clear(cls) -> Asset3D: # # (Docstring intentionally commented out to hide this field from the docs) + albedo_factor: components.AlbedoFactorBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.AlbedoFactorBatch._optional, # type: ignore[misc] + ) + # A color multiplier applied to the whole asset. + # + # (Docstring intentionally commented out to hide this field from the docs) + + albedo_texture_buffer: components.ImageBufferBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.ImageBufferBatch._optional, # type: ignore[misc] + ) + # Optional albedo texture. + # + # Used with the [`components.Texcoord2D`][rerun.components.Texcoord2D] of the mesh. + # + # Currently supports only sRGB(A) textures, ignoring alpha. + # (meaning that the tensor must have 3 or 4 channels and use the `u8` format) + # + # (Docstring intentionally commented out to hide this field from the docs) + + albedo_texture_format: components.ImageFormatBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.ImageFormatBatch._optional, # type: ignore[misc] + ) + # The format of the `albedo_texture_buffer`, if any. + # + # (Docstring intentionally commented out to hide this field from the docs) + __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ # type: ignore[assignment] From 7eddd5babf86afb4bf6509695b6e0a83b6bdf5a1 Mon Sep 17 00:00:00 2001 From: Keyvan Goddard Date: Thu, 19 Sep 2024 17:05:36 +0200 Subject: [PATCH 02/11] Allow logging `Asset3D` with `albedo_factor` as in `Mesh3D` (Python/C++) Remove `albedo_texture_buffer`, `albedo_texture_format` from `Asset3D` --- .../definitions/rerun/archetypes/asset3d.fbs | 11 --- .../store/re_types/src/archetypes/asset3d.rs | 88 ++----------------- .../re_types/src/archetypes/asset3d_ext.rs | 23 +---- crates/store/re_types/tests/types/asset3d.rs | 8 +- .../src/visualizers/assets3d.rs | 49 ++++------- crates/viewer/re_viewer/src/reflection/mod.rs | 6 +- .../reference/types/archetypes/asset3d.md | 2 +- .../types/components/image_buffer.md | 1 - .../types/components/image_format.md | 1 - rerun_cpp/src/rerun/archetypes/asset3d.cpp | 12 +-- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 34 ------- .../rerun_sdk/rerun/archetypes/asset3d.py | 25 ------ .../rerun_sdk/rerun/archetypes/asset3d_ext.py | 5 +- 13 files changed, 33 insertions(+), 232 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index 16a61464e296..a20c7aec601a 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -38,15 +38,4 @@ table Asset3D ( /// A color multiplier applied to the whole asset. albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); - - /// Optional albedo texture. - /// - /// Used with the [components.Texcoord2D] of the mesh. - /// - /// Currently supports only sRGB(A) textures, ignoring alpha. - /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - albedo_texture_buffer: rerun.components.ImageBuffer ("attr.rerun.component_optional", nullable, order: 3400); - - /// The format of the `albedo_texture_buffer`, if any. - albedo_texture_format: rerun.components.ImageFormat ("attr.rerun.component_optional", nullable, order: 3450); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index d084dffa79e5..1db6fd535b58 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -73,17 +73,6 @@ pub struct Asset3D { /// A color multiplier applied to the whole asset. pub albedo_factor: Option, - - /// Optional albedo texture. - /// - /// Used with the [`components::Texcoord2D`][crate::components::Texcoord2D] of the mesh. - /// - /// Currently supports only sRGB(A) textures, ignoring alpha. - /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - pub albedo_texture_buffer: Option, - - /// The format of the `albedo_texture_buffer`, if any. - pub albedo_texture_format: Option, } impl ::re_types_core::SizeBytes for Asset3D { @@ -92,8 +81,6 @@ impl ::re_types_core::SizeBytes for Asset3D { self.blob.heap_size_bytes() + self.media_type.heap_size_bytes() + self.albedo_factor.heap_size_bytes() - + self.albedo_texture_buffer.heap_size_bytes() - + self.albedo_texture_format.heap_size_bytes() } #[inline] @@ -101,8 +88,6 @@ impl ::re_types_core::SizeBytes for Asset3D { ::is_pod() && >::is_pod() && >::is_pod() - && >::is_pod() - && >::is_pod() } } @@ -117,30 +102,22 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 3usize]> = - once_cell::sync::Lazy::new(|| { - [ - "rerun.components.AlbedoFactor".into(), - "rerun.components.ImageBuffer".into(), - "rerun.components.ImageFormat".into(), - ] - }); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.AlbedoFactor".into()]); -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 6usize]> = +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.components.Blob".into(), "rerun.components.MediaType".into(), "rerun.components.Asset3DIndicator".into(), "rerun.components.AlbedoFactor".into(), - "rerun.components.ImageBuffer".into(), - "rerun.components.ImageFormat".into(), ] }); impl Asset3D { - /// The total number of components in the archetype: 1 required, 2 recommended, 3 optional - pub const NUM_COMPONENTS: usize = 6usize; + /// The total number of components in the archetype: 1 required, 2 recommended, 1 optional + pub const NUM_COMPONENTS: usize = 4usize; } /// Indicator component for the [`Asset3D`] [`::re_types_core::Archetype`] @@ -227,32 +204,10 @@ impl ::re_types_core::Archetype for Asset3D { } else { None }; - let albedo_texture_buffer = - if let Some(array) = arrays_by_name.get("rerun.components.ImageBuffer") { - ::from_arrow_opt(&**array) - .with_context("rerun.archetypes.Asset3D#albedo_texture_buffer")? - .into_iter() - .next() - .flatten() - } else { - None - }; - let albedo_texture_format = - if let Some(array) = arrays_by_name.get("rerun.components.ImageFormat") { - ::from_arrow_opt(&**array) - .with_context("rerun.archetypes.Asset3D#albedo_texture_format")? - .into_iter() - .next() - .flatten() - } else { - None - }; Ok(Self { blob, media_type, albedo_factor, - albedo_texture_buffer, - albedo_texture_format, }) } } @@ -270,12 +225,6 @@ impl ::re_types_core::AsComponents for Asset3D { self.albedo_factor .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), - self.albedo_texture_buffer - .as_ref() - .map(|comp| (comp as &dyn ComponentBatch).into()), - self.albedo_texture_format - .as_ref() - .map(|comp| (comp as &dyn ComponentBatch).into()), ] .into_iter() .flatten() @@ -293,8 +242,6 @@ impl Asset3D { blob: blob.into(), media_type: None, albedo_factor: None, - albedo_texture_buffer: None, - albedo_texture_format: None, } } @@ -323,29 +270,4 @@ impl Asset3D { self.albedo_factor = Some(albedo_factor.into()); self } - - /// Optional albedo texture. - /// - /// Used with the [`components::Texcoord2D`][crate::components::Texcoord2D] of the mesh. - /// - /// Currently supports only sRGB(A) textures, ignoring alpha. - /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - #[inline] - pub fn with_albedo_texture_buffer( - mut self, - albedo_texture_buffer: impl Into, - ) -> Self { - self.albedo_texture_buffer = Some(albedo_texture_buffer.into()); - self - } - - /// The format of the `albedo_texture_buffer`, if any. - #[inline] - pub fn with_albedo_texture_format( - mut self, - albedo_texture_format: impl Into, - ) -> Self { - self.albedo_texture_format = Some(albedo_texture_format.into()); - self - } } diff --git a/crates/store/re_types/src/archetypes/asset3d_ext.rs b/crates/store/re_types/src/archetypes/asset3d_ext.rs index 255d32b7fbb8..07e66bfa158e 100644 --- a/crates/store/re_types/src/archetypes/asset3d_ext.rs +++ b/crates/store/re_types/src/archetypes/asset3d_ext.rs @@ -1,6 +1,4 @@ -use crate::components::{self, MediaType}; - -use crate::archetypes; +use crate::components::MediaType; use super::Asset3D; @@ -38,25 +36,6 @@ impl Asset3D { blob: contents.into(), media_type, albedo_factor: None, - albedo_texture_buffer: None, - albedo_texture_format: None, } } - - /// Use this image as the albedo texture. - pub fn with_albedo_texture_image(self, image: impl Into) -> Self { - let image = image.into(); - self.with_albedo_texture_format(image.format) - .with_albedo_texture_buffer(image.buffer) - } - - /// Use this image as the albedo texture. - pub fn with_albedo_texture( - self, - image_format: impl Into, - image_buffer: impl Into, - ) -> Self { - self.with_albedo_texture_format(image_format) - .with_albedo_texture_buffer(image_buffer) - } } diff --git a/crates/store/re_types/tests/types/asset3d.rs b/crates/store/re_types/tests/types/asset3d.rs index 963f974885dc..bfc4e64e8f38 100644 --- a/crates/store/re_types/tests/types/asset3d.rs +++ b/crates/store/re_types/tests/types/asset3d.rs @@ -9,20 +9,14 @@ use re_types::{ fn roundtrip() { const BYTES: &[u8] = &[1, 2, 3, 4, 5, 6]; - let texture_format = re_types::components::ImageFormat::rgb8([2, 3]); - let texture_buffer = re_types::components::ImageBuffer::from(vec![0x42_u8; 2 * 3 * 3]); - let expected = Asset3D { blob: Blob(BYTES.to_vec().into()), media_type: Some(MediaType(Utf8(MediaType::GLTF.into()))), albedo_factor: Some(Rgba32::from_unmultiplied_rgba(0xEE, 0x11, 0x22, 0x33).into()), - albedo_texture_format: Some(texture_format), - albedo_texture_buffer: Some(texture_buffer.clone()), }; let arch = Asset3D::from_file_contents(BYTES.to_vec(), Some(MediaType::gltf())) - .with_albedo_factor(0xEE112233) - .with_albedo_texture(texture_format, texture_buffer); + .with_albedo_factor(0xEE112233); similar_asserts::assert_eq!(expected, arch); // let expected_extensions: HashMap<_, _> = [ diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs index fc5abc9a7b1d..0c2a0559b0e5 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs @@ -4,7 +4,7 @@ use re_renderer::renderer::MeshInstance; use re_renderer::RenderContext; use re_types::{ archetypes::Asset3D, - components::{AlbedoFactor, Blob, ImageBuffer, ImageFormat, MediaType}, + components::{AlbedoFactor, Blob, MediaType}, ArrowBuffer, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -39,8 +39,6 @@ struct Asset3DComponentData<'a> { blob: ArrowBuffer, media_type: Option, albedo_factor: Option<&'a AlbedoFactor>, - albedo_buffer: Option, - albedo_format: Option, } // NOTE: Do not put profile scopes in these methods. They are called for all entities and all @@ -78,8 +76,6 @@ impl Asset3DVisualizer { blob: data.blob.clone().into(), media_type: data.media_type.clone().map(Into::into), albedo_factor: data.albedo_factor.copied(), - albedo_texture_buffer: data.albedo_buffer.clone(), // shallow clone, - albedo_texture_format: data.albedo_format, }, texture_key: re_log_types::hash::Hash64::hash(&key).hash64(), }, @@ -165,43 +161,28 @@ impl VisualizerSystem for Asset3DVisualizer { let all_blobs_indexed = iter_buffer::(&all_blob_chunks, timeline, Blob::name()); let all_media_types = results.iter_as(timeline, MediaType::name()); let all_albedo_factors = results.iter_as(timeline, AlbedoFactor::name()); - let all_albedo_buffers = results.iter_as(timeline, ImageBuffer::name()); - let all_albedo_formats = results.iter_as(timeline, ImageFormat::name()); let query_result_hash = results.query_result_hash(); - let data = re_query::range_zip_1x4( + let data = re_query::range_zip_1x2( all_blobs_indexed, all_media_types.string(), all_albedo_factors.primitive::(), - all_albedo_buffers.component::(), - all_albedo_formats.component::(), ) - .filter_map( - |( + .filter_map(|(index, blobs, media_types, albedo_factors)| { + blobs.first().map(|blob| Asset3DComponentData { index, - blobs, - media_types, - albedo_factors, - albedo_buffers, - albedo_formats, - )| { - blobs.first().map(|blob| Asset3DComponentData { - index, - query_result_hash, - blob: blob.clone(), - media_type: media_types - .and_then(|media_types| media_types.first().cloned()), - albedo_factor: albedo_factors - .map_or(&[] as &[AlbedoFactor], |albedo_factors| { - bytemuck::cast_slice(albedo_factors) - }) - .first(), - albedo_buffer: albedo_buffers.unwrap_or_default().first().cloned(), // shallow clone - albedo_format: albedo_formats.unwrap_or_default().first().copied(), - }) - }, - ); + query_result_hash, + blob: blob.clone(), + media_type: media_types + .and_then(|media_types| media_types.first().cloned()), + albedo_factor: albedo_factors + .map_or(&[] as &[AlbedoFactor], |albedo_factors| { + bytemuck::cast_slice(albedo_factors) + }) + .first(), + }) + }); self.process_data(ctx, render_ctx, &mut instances, spatial_ctx, data); diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 12842c1e4ae7..8742dfe6487c 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -801,7 +801,11 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { "rerun.components.MediaType".into(), display_name : "Media type", docstring_md : "The Media Type of the asset.\n\nSupported values:\n* `model/gltf-binary`\n* `model/gltf+json`\n* `model/obj` (.mtl material files are not supported yet, references are silently ignored)\n* `model/stl`\n\nIf omitted, the viewer will try to guess from the data blob.\nIf it cannot guess, it won't be able to render the asset.", - is_required : false, }, + is_required : false, }, ArchetypeFieldReflection { component_name : + "rerun.components.AlbedoFactor".into(), display_name : + "Albedo factor", docstring_md : + "A color multiplier applied to the whole asset.", is_required : + false, }, ], }, ), diff --git a/docs/content/reference/types/archetypes/asset3d.md b/docs/content/reference/types/archetypes/asset3d.md index a50835544af2..fb60d25a220b 100644 --- a/docs/content/reference/types/archetypes/asset3d.md +++ b/docs/content/reference/types/archetypes/asset3d.md @@ -16,7 +16,7 @@ an instance of the mesh will be drawn for each transform. **Recommended**: [`MediaType`](../components/media_type.md) -**Optional**: [`AlbedoFactor`](../components/albedo_factor.md), [`ImageBuffer`](../components/image_buffer.md), [`ImageFormat`](../components/image_format.md) +**Optional**: [`AlbedoFactor`](../components/albedo_factor.md) ## Shown in * [Spatial3DView](../views/spatial3d_view.md) diff --git a/docs/content/reference/types/components/image_buffer.md b/docs/content/reference/types/components/image_buffer.md index 9d908e7c022e..05956c98a3b2 100644 --- a/docs/content/reference/types/components/image_buffer.md +++ b/docs/content/reference/types/components/image_buffer.md @@ -19,7 +19,6 @@ To interpret the contents of this buffer, see, [`components.ImageFormat`](https: ## Used by -* [`Asset3D`](../archetypes/asset3d.md) * [`DepthImage`](../archetypes/depth_image.md) * [`Image`](../archetypes/image.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/docs/content/reference/types/components/image_format.md b/docs/content/reference/types/components/image_format.md index fa056cfc2195..43b84c94f226 100644 --- a/docs/content/reference/types/components/image_format.md +++ b/docs/content/reference/types/components/image_format.md @@ -17,7 +17,6 @@ The metadata describing the contents of a [`components.ImageBuffer`](https://rer ## Used by -* [`Asset3D`](../archetypes/asset3d.md) * [`DepthImage`](../archetypes/depth_image.md) * [`Image`](../archetypes/image.md) * [`Mesh3D`](../archetypes/mesh3d.md) diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.cpp b/rerun_cpp/src/rerun/archetypes/asset3d.cpp index 4ca4fa927a48..99f9341f8359 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.cpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(6); + cells.reserve(4); { auto result = ComponentBatch::from_loggable(archetype.blob); @@ -31,16 +31,6 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } - if (archetype.albedo_texture_buffer.has_value()) { - auto result = ComponentBatch::from_loggable(archetype.albedo_texture_buffer.value()); - RR_RETURN_NOT_OK(result.error); - cells.push_back(std::move(result.value)); - } - if (archetype.albedo_texture_format.has_value()) { - auto result = ComponentBatch::from_loggable(archetype.albedo_texture_format.value()); - RR_RETURN_NOT_OK(result.error); - cells.push_back(std::move(result.value)); - } { auto indicator = Asset3D::IndicatorComponent(); auto result = ComponentBatch::from_loggable(indicator); diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index 60c3b0d04a2a..7a854ab61b17 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -8,8 +8,6 @@ #include "../component_batch.hpp" #include "../components/albedo_factor.hpp" #include "../components/blob.hpp" -#include "../components/image_buffer.hpp" -#include "../components/image_format.hpp" #include "../components/media_type.hpp" #include "../indicator_component.hpp" #include "../result.hpp" @@ -72,17 +70,6 @@ namespace rerun::archetypes { /// A color multiplier applied to the whole asset. std::optional albedo_factor; - /// Optional albedo texture. - /// - /// Used with the `components::Texcoord2D` of the mesh. - /// - /// Currently supports only sRGB(A) textures, ignoring alpha. - /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - std::optional albedo_texture_buffer; - - /// The format of the `albedo_texture_buffer`, if any. - std::optional albedo_texture_format; - public: static constexpr const char IndicatorComponentName[] = "rerun.components.Asset3DIndicator"; @@ -142,27 +129,6 @@ namespace rerun::archetypes { // See: https://github.com/rerun-io/rerun/issues/4027 RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - - /// Optional albedo texture. - /// - /// Used with the `components::Texcoord2D` of the mesh. - /// - /// Currently supports only sRGB(A) textures, ignoring alpha. - /// (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - Asset3D with_albedo_texture_buffer(rerun::components::ImageBuffer _albedo_texture_buffer - ) && { - albedo_texture_buffer = std::move(_albedo_texture_buffer); - // See: https://github.com/rerun-io/rerun/issues/4027 - RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) - } - - /// The format of the `albedo_texture_buffer`, if any. - Asset3D with_albedo_texture_format(rerun::components::ImageFormat _albedo_texture_format - ) && { - albedo_texture_format = std::move(_albedo_texture_format); - // See: https://github.com/rerun-io/rerun/issues/4027 - RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) - } }; } // namespace rerun::archetypes diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index ba19893a4d9b..ef0845415bea 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -63,8 +63,6 @@ def __attrs_clear__(self) -> None: blob=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] albedo_factor=None, # type: ignore[arg-type] - albedo_texture_buffer=None, # type: ignore[arg-type] - albedo_texture_format=None, # type: ignore[arg-type] ) @classmethod @@ -109,28 +107,5 @@ def _clear(cls) -> Asset3D: # # (Docstring intentionally commented out to hide this field from the docs) - albedo_texture_buffer: components.ImageBufferBatch | None = field( - metadata={"component": "optional"}, - default=None, - converter=components.ImageBufferBatch._optional, # type: ignore[misc] - ) - # Optional albedo texture. - # - # Used with the [`components.Texcoord2D`][rerun.components.Texcoord2D] of the mesh. - # - # Currently supports only sRGB(A) textures, ignoring alpha. - # (meaning that the tensor must have 3 or 4 channels and use the `u8` format) - # - # (Docstring intentionally commented out to hide this field from the docs) - - albedo_texture_format: components.ImageFormatBatch | None = field( - metadata={"component": "optional"}, - default=None, - converter=components.ImageFormatBatch._optional, # type: ignore[misc] - ) - # The format of the `albedo_texture_buffer`, if any. - # - # (Docstring intentionally commented out to hide this field from the docs) - __str__ = Archetype.__str__ __repr__ = Archetype.__repr__ # type: ignore[assignment] diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py index 390aeb25e719..92fd5074c200 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py @@ -16,6 +16,7 @@ def __init__( path: str | pathlib.Path | None = None, contents: datatypes.BlobLike | None = None, media_type: datatypes.Utf8Like | None = None, + albedo_factor: datatypes.Rgba32Like | None = None, ): """ Create a new instance of the Asset3D archetype. @@ -42,6 +43,8 @@ def __init__( If omitted, it will be guessed from the `path` (if any), or the viewer will try to guess from the contents (magic header). If the media type cannot be guessed, the viewer won't be able to render the asset. + albedo_factor: + Optional color multiplier for the whole mesh """ @@ -58,7 +61,7 @@ def __init__( if media_type is None: media_type = MediaType.guess_from_path(path) - self.__attrs_init__(blob=blob, media_type=media_type) + self.__attrs_init__(blob=blob, media_type=media_type, albedo_factor=albedo_factor) return self.__attrs_clear__() From 161224d32065ade5cb0a32ff5d41e960b456e374 Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Mon, 23 Sep 2024 17:22:24 +0200 Subject: [PATCH 03/11] Add `vertex_colors` to stl/obj `Asset3D` (Rust/Python/C++) - add attribute `vertex_colors` and method `with_vertex_colors` to archetype `Asset3D`. - update stl/obj loader : `load_stl_from_buffer` and `load_obj_from_buffer` to process `vertex_colors`. --- .../definitions/rerun/archetypes/asset3d.fbs | 5 +- .../store/re_types/src/archetypes/asset3d.rs | 48 +++++++++++++++++-- .../re_types/src/archetypes/asset3d_ext.rs | 1 + crates/store/re_types/tests/types/asset3d.rs | 5 ++ crates/viewer/re_renderer/src/importer/obj.rs | 33 +++++++------ crates/viewer/re_renderer/src/importer/stl.rs | 47 ++++++++++++++++-- .../viewer/re_renderer_examples/framework.rs | 7 +-- .../re_space_view_spatial/src/mesh_loader.rs | 11 ++--- .../src/visualizers/assets3d.rs | 40 +++++++++------- crates/viewer/re_viewer/src/reflection/mod.rs | 3 ++ .../reference/types/archetypes/asset3d.md | 2 +- .../reference/types/components/color.md | 1 + rerun_cpp/src/rerun/archetypes/asset3d.cpp | 7 ++- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 11 +++++ .../rerun_sdk/rerun/archetypes/asset3d.py | 10 ++++ .../rerun_sdk/rerun/archetypes/asset3d_ext.py | 8 +++- 16 files changed, 183 insertions(+), 56 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index a20c7aec601a..484df2efe861 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -36,6 +36,9 @@ table Asset3D ( // --- Optional --- + /// An optional color for each vertex. + vertex_colors: [rerun.components.Color] ("attr.rerun.component_optional", nullable, order: 3100); + /// A color multiplier applied to the whole asset. - albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); + albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3200); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index 1db6fd535b58..963bf5f19cb4 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -71,6 +71,9 @@ pub struct Asset3D { /// If it cannot guess, it won't be able to render the asset. pub media_type: Option, + /// An optional color for each vertex. + pub vertex_colors: Option>, + /// A color multiplier applied to the whole asset. pub albedo_factor: Option, } @@ -80,6 +83,7 @@ impl ::re_types_core::SizeBytes for Asset3D { fn heap_size_bytes(&self) -> u64 { self.blob.heap_size_bytes() + self.media_type.heap_size_bytes() + + self.vertex_colors.heap_size_bytes() + self.albedo_factor.heap_size_bytes() } @@ -87,6 +91,7 @@ impl ::re_types_core::SizeBytes for Asset3D { fn is_pod() -> bool { ::is_pod() && >::is_pod() + && >>::is_pod() && >::is_pod() } } @@ -102,22 +107,28 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = - once_cell::sync::Lazy::new(|| ["rerun.components.AlbedoFactor".into()]); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = + once_cell::sync::Lazy::new(|| { + [ + "rerun.components.Color".into(), + "rerun.components.AlbedoFactor".into(), + ] + }); -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.components.Blob".into(), "rerun.components.MediaType".into(), "rerun.components.Asset3DIndicator".into(), + "rerun.components.Color".into(), "rerun.components.AlbedoFactor".into(), ] }); impl Asset3D { - /// The total number of components in the archetype: 1 required, 2 recommended, 1 optional - pub const NUM_COMPONENTS: usize = 4usize; + /// The total number of components in the archetype: 1 required, 2 recommended, 2 optional + pub const NUM_COMPONENTS: usize = 5usize; } /// Indicator component for the [`Asset3D`] [`::re_types_core::Archetype`] @@ -194,6 +205,18 @@ impl ::re_types_core::Archetype for Asset3D { } else { None }; + let vertex_colors = if let Some(array) = arrays_by_name.get("rerun.components.Color") { + Some({ + ::from_arrow_opt(&**array) + .with_context("rerun.archetypes.Asset3D#vertex_colors")? + .into_iter() + .map(|v| v.ok_or_else(DeserializationError::missing_data)) + .collect::>>() + .with_context("rerun.archetypes.Asset3D#vertex_colors")? + }) + } else { + None + }; let albedo_factor = if let Some(array) = arrays_by_name.get("rerun.components.AlbedoFactor") { ::from_arrow_opt(&**array) @@ -207,6 +230,7 @@ impl ::re_types_core::Archetype for Asset3D { Ok(Self { blob, media_type, + vertex_colors, albedo_factor, }) } @@ -222,6 +246,9 @@ impl ::re_types_core::AsComponents for Asset3D { self.media_type .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), + self.vertex_colors + .as_ref() + .map(|comp_batch| (comp_batch as &dyn ComponentBatch).into()), self.albedo_factor .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), @@ -241,6 +268,7 @@ impl Asset3D { Self { blob: blob.into(), media_type: None, + vertex_colors: None, albedo_factor: None, } } @@ -261,6 +289,16 @@ impl Asset3D { self } + /// An optional color for each vertex. + #[inline] + pub fn with_vertex_colors( + mut self, + vertex_colors: impl IntoIterator>, + ) -> Self { + self.vertex_colors = Some(vertex_colors.into_iter().map(Into::into).collect()); + self + } + /// A color multiplier applied to the whole asset. #[inline] pub fn with_albedo_factor( diff --git a/crates/store/re_types/src/archetypes/asset3d_ext.rs b/crates/store/re_types/src/archetypes/asset3d_ext.rs index 07e66bfa158e..15bfdc744b90 100644 --- a/crates/store/re_types/src/archetypes/asset3d_ext.rs +++ b/crates/store/re_types/src/archetypes/asset3d_ext.rs @@ -35,6 +35,7 @@ impl Asset3D { Self { blob: contents.into(), media_type, + vertex_colors: None, albedo_factor: None, } } diff --git a/crates/store/re_types/tests/types/asset3d.rs b/crates/store/re_types/tests/types/asset3d.rs index bfc4e64e8f38..86ce4c8f3147 100644 --- a/crates/store/re_types/tests/types/asset3d.rs +++ b/crates/store/re_types/tests/types/asset3d.rs @@ -12,10 +12,15 @@ fn roundtrip() { let expected = Asset3D { blob: Blob(BYTES.to_vec().into()), media_type: Some(MediaType(Utf8(MediaType::GLTF.into()))), + vertex_colors: Some(vec![ + Rgba32::from_unmultiplied_rgba(0xAA, 0x00, 0x00, 0xCC).into(), // + Rgba32::from_unmultiplied_rgba(0x00, 0xBB, 0x00, 0xDD).into(), + ]), albedo_factor: Some(Rgba32::from_unmultiplied_rgba(0xEE, 0x11, 0x22, 0x33).into()), }; let arch = Asset3D::from_file_contents(BYTES.to_vec(), Some(MediaType::gltf())) + .with_vertex_colors([0xAA0000CC, 0x00BB00DD]) .with_albedo_factor(0xEE112233); similar_asserts::assert_eq!(expected, arch); diff --git a/crates/viewer/re_renderer/src/importer/obj.rs b/crates/viewer/re_renderer/src/importer/obj.rs index ff3bfe3b25cf..0008a84579d3 100644 --- a/crates/viewer/re_renderer/src/importer/obj.rs +++ b/crates/viewer/re_renderer/src/importer/obj.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use re_types::components::AlbedoFactor; +use re_types::components::{AlbedoFactor, Color}; use smallvec::smallvec; use crate::{ @@ -9,6 +9,8 @@ use crate::{ RenderContext, Rgba32Unmul, }; +use super::stl::clamped_vec_or_empty_color; + #[derive(thiserror::Error, Debug)] pub enum ObjImportError { #[error(transparent)] @@ -23,7 +25,8 @@ pub enum ObjImportError { pub fn load_obj_from_buffer( buffer: &[u8], ctx: &RenderContext, - albedo_factor: Option, + vertex_colors: &Option>, + albedo_factor: &Option, ) -> Result, ObjImportError> { re_tracing::profile_function!(); @@ -56,19 +59,19 @@ pub fn load_obj_from_buffer( .map(|p| glam::uvec3(p[0], p[1], p[2])) .collect(); - let mut vertex_colors: Vec = mesh - .vertex_color - .chunks_exact(3) - .map(|c| { - Rgba32Unmul::from_rgb( - // It is not specified if the color is in linear or gamma space, but gamma seems a safe bet. - (c[0] * 255.0).round() as u8, - (c[1] * 255.0).round() as u8, - (c[2] * 255.0).round() as u8, - ) - }) - .collect(); - vertex_colors.resize(vertex_positions.len(), Rgba32Unmul::WHITE); + let num_positions = vertex_positions.len(); + + let vertex_colors = if let Some(vertex_colors) = vertex_colors { + let vertex_colors_arr = + clamped_vec_or_empty_color(vertex_colors.as_slice(), vertex_positions.len()); + re_tracing::profile_scope!("copy_colors"); + vertex_colors_arr + .iter() + .map(|c| Rgba32Unmul::from_rgba_unmul_array(c.to_array())) + .collect() + } else { + vec![Rgba32Unmul::WHITE; num_positions] + }; let mut vertex_normals: Vec = mesh .normals diff --git a/crates/viewer/re_renderer/src/importer/stl.rs b/crates/viewer/re_renderer/src/importer/stl.rs index 400a753d51cf..f071b8511234 100644 --- a/crates/viewer/re_renderer/src/importer/stl.rs +++ b/crates/viewer/re_renderer/src/importer/stl.rs @@ -7,9 +7,9 @@ use tinystl::StlData; use crate::{ mesh::{self, GpuMesh}, renderer::MeshInstance, - RenderContext, + RenderContext, Rgba32Unmul, }; -use re_types::archetypes::Asset3D; +use re_types::{archetypes::Asset3D, components::Color}; #[derive(thiserror::Error, Debug)] pub enum StlImportError { @@ -30,6 +30,7 @@ pub fn load_stl_from_buffer( let Asset3D { blob, + vertex_colors, albedo_factor, .. } = asset3d; @@ -45,6 +46,20 @@ pub fn load_stl_from_buffer( } = StlData::read_buffer(std::io::BufReader::new(cursor)).map_err(StlImportError::TinyStl)?; let num_vertices = triangles.len() * 3; + let vertex_positions: &[glam::Vec3] = bytemuck::cast_slice(&triangles); + let num_positions = vertex_positions.len(); + + let vertex_colors = if let Some(vertex_colors) = vertex_colors { + let vertex_colors_arr = + clamped_vec_or_empty_color(vertex_colors.as_slice(), vertex_positions.len()); + re_tracing::profile_scope!("copy_colors"); + vertex_colors_arr + .iter() + .map(|c| Rgba32Unmul::from_rgba_unmul_array(c.to_array())) + .collect() + } else { + vec![Rgba32Unmul::WHITE; num_positions] + }; let material = mesh::Material { label: name.clone().into(), @@ -71,8 +86,8 @@ pub fn load_stl_from_buffer( }) .collect(), - // STL has neither colors nor texcoords. - vertex_colors: vec![crate::Rgba32Unmul::WHITE; num_vertices], + vertex_colors, + // STL has no texcoords. vertex_texcoords: vec![glam::Vec2::ZERO; num_vertices], materials: smallvec![material], @@ -85,3 +100,27 @@ pub fn load_stl_from_buffer( Some(Arc::new(mesh)), )]) } + +pub fn clamped_vec_or_empty_color(values: &[Color], clamped_len: usize) -> Vec { + if values.len() == clamped_len { + // Happy path + values.to_vec() // TODO(emilk): return a slice reference instead, in a `Cow` or similar + } else if let Some(last) = values.last() { + if values.len() == 1 { + // Commo happy path + return vec![*last; clamped_len]; + } else if values.len() < clamped_len { + // Clamp + let mut vec = Vec::with_capacity(clamped_len); + vec.extend(values.iter()); + vec.extend(std::iter::repeat(last).take(clamped_len - values.len())); + vec + } else { + // Trim + values.iter().take(clamped_len).copied().collect() + } + } else { + // Empty input + Vec::new() + } +} diff --git a/crates/viewer/re_renderer_examples/framework.rs b/crates/viewer/re_renderer_examples/framework.rs index 7d6679b8cf11..112953fc0416 100644 --- a/crates/viewer/re_renderer_examples/framework.rs +++ b/crates/viewer/re_renderer_examples/framework.rs @@ -332,12 +332,7 @@ pub fn load_rerun_mesh(re_ctx: &RenderContext) -> Vec { diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index c396d2123bbb..ca22295aacdb 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -48,15 +48,14 @@ impl LoadedMesh { let bytes = asset3d.blob.as_slice(); let mesh_instances = match media_type.as_str() { - MediaType::GLTF | MediaType::GLB => re_renderer::importer::gltf::load_gltf_from_buffer( - &name, - bytes, - render_ctx, - )?, + MediaType::GLTF | MediaType::GLB => { + re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? + } MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer( bytes, render_ctx, - asset3d.albedo_factor, + &asset3d.vertex_colors, + &asset3d.albedo_factor, )?, MediaType::STL => { re_renderer::importer::stl::load_stl_from_buffer(asset3d, render_ctx, texture_key)? diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs index 0c2a0559b0e5..361320ead17c 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs @@ -4,7 +4,7 @@ use re_renderer::renderer::MeshInstance; use re_renderer::RenderContext; use re_types::{ archetypes::Asset3D, - components::{AlbedoFactor, Blob, MediaType}, + components::{AlbedoFactor, Blob, Color, MediaType}, ArrowBuffer, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -38,6 +38,7 @@ struct Asset3DComponentData<'a> { blob: ArrowBuffer, media_type: Option, + vertex_colors: &'a [Color], albedo_factor: Option<&'a AlbedoFactor>, } @@ -75,6 +76,7 @@ impl Asset3DVisualizer { asset: &Asset3D { blob: data.blob.clone().into(), media_type: data.media_type.clone().map(Into::into), + vertex_colors: Some(data.vertex_colors.to_vec()), albedo_factor: data.albedo_factor.copied(), }, texture_key: re_log_types::hash::Hash64::hash(&key).hash64(), @@ -160,29 +162,35 @@ impl VisualizerSystem for Asset3DVisualizer { let timeline = ctx.query.timeline(); let all_blobs_indexed = iter_buffer::(&all_blob_chunks, timeline, Blob::name()); let all_media_types = results.iter_as(timeline, MediaType::name()); + let all_vertex_colors = results.iter_as(timeline, Color::name()); let all_albedo_factors = results.iter_as(timeline, AlbedoFactor::name()); let query_result_hash = results.query_result_hash(); - let data = re_query::range_zip_1x2( + let data = re_query::range_zip_1x3( all_blobs_indexed, all_media_types.string(), + all_vertex_colors.primitive::(), all_albedo_factors.primitive::(), ) - .filter_map(|(index, blobs, media_types, albedo_factors)| { - blobs.first().map(|blob| Asset3DComponentData { - index, - query_result_hash, - blob: blob.clone(), - media_type: media_types - .and_then(|media_types| media_types.first().cloned()), - albedo_factor: albedo_factors - .map_or(&[] as &[AlbedoFactor], |albedo_factors| { - bytemuck::cast_slice(albedo_factors) - }) - .first(), - }) - }); + .filter_map( + |(index, blobs, media_types, vertex_colors, albedo_factors)| { + blobs.first().map(|blob| Asset3DComponentData { + index, + query_result_hash, + blob: blob.clone(), + media_type: media_types + .and_then(|media_types| media_types.first().cloned()), + vertex_colors: vertex_colors + .map_or(&[], |vertex_colors| bytemuck::cast_slice(vertex_colors)), + albedo_factor: albedo_factors + .map_or(&[] as &[AlbedoFactor], |albedo_factors| { + bytemuck::cast_slice(albedo_factors) + }) + .first(), + }) + }, + ); self.process_data(ctx, render_ctx, &mut instances, spatial_ctx, data); diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 8742dfe6487c..49a39dd00758 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -802,6 +802,9 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { docstring_md : "The Media Type of the asset.\n\nSupported values:\n* `model/gltf-binary`\n* `model/gltf+json`\n* `model/obj` (.mtl material files are not supported yet, references are silently ignored)\n* `model/stl`\n\nIf omitted, the viewer will try to guess from the data blob.\nIf it cannot guess, it won't be able to render the asset.", is_required : false, }, ArchetypeFieldReflection { component_name : + "rerun.components.Color".into(), display_name : "Vertex colors", + docstring_md : "An optional color for each vertex.", is_required : + false, }, ArchetypeFieldReflection { component_name : "rerun.components.AlbedoFactor".into(), display_name : "Albedo factor", docstring_md : "A color multiplier applied to the whole asset.", is_required : diff --git a/docs/content/reference/types/archetypes/asset3d.md b/docs/content/reference/types/archetypes/asset3d.md index fb60d25a220b..29e3b8dc98d8 100644 --- a/docs/content/reference/types/archetypes/asset3d.md +++ b/docs/content/reference/types/archetypes/asset3d.md @@ -16,7 +16,7 @@ an instance of the mesh will be drawn for each transform. **Recommended**: [`MediaType`](../components/media_type.md) -**Optional**: [`AlbedoFactor`](../components/albedo_factor.md) +**Optional**: [`Color`](../components/color.md), [`AlbedoFactor`](../components/albedo_factor.md) ## Shown in * [Spatial3DView](../views/spatial3d_view.md) diff --git a/docs/content/reference/types/components/color.md b/docs/content/reference/types/components/color.md index c5703e66ea2f..05fa736033ab 100644 --- a/docs/content/reference/types/components/color.md +++ b/docs/content/reference/types/components/color.md @@ -22,6 +22,7 @@ byte is `R` and the least significant byte is `A`. * [`Arrows2D`](../archetypes/arrows2d.md) * [`Arrows3D`](../archetypes/arrows3d.md) +* [`Asset3D`](../archetypes/asset3d.md) * [`BarChart`](../archetypes/bar_chart.md) * [`Boxes2D`](../archetypes/boxes2d.md) * [`Boxes3D`](../archetypes/boxes3d.md) diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.cpp b/rerun_cpp/src/rerun/archetypes/asset3d.cpp index 99f9341f8359..32885a35e4cf 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.cpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(4); + cells.reserve(5); { auto result = ComponentBatch::from_loggable(archetype.blob); @@ -26,6 +26,11 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } + if (archetype.vertex_colors.has_value()) { + auto result = ComponentBatch::from_loggable(archetype.vertex_colors.value()); + RR_RETURN_NOT_OK(result.error); + cells.push_back(std::move(result.value)); + } if (archetype.albedo_factor.has_value()) { auto result = ComponentBatch::from_loggable(archetype.albedo_factor.value()); RR_RETURN_NOT_OK(result.error); diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index 7a854ab61b17..f715ca69002b 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -8,6 +8,7 @@ #include "../component_batch.hpp" #include "../components/albedo_factor.hpp" #include "../components/blob.hpp" +#include "../components/color.hpp" #include "../components/media_type.hpp" #include "../indicator_component.hpp" #include "../result.hpp" @@ -67,6 +68,9 @@ namespace rerun::archetypes { /// If it cannot guess, it won't be able to render the asset. std::optional media_type; + /// An optional color for each vertex. + std::optional> vertex_colors; + /// A color multiplier applied to the whole asset. std::optional albedo_factor; @@ -123,6 +127,13 @@ namespace rerun::archetypes { RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } + /// An optional color for each vertex. + Asset3D with_vertex_colors(Collection _vertex_colors) && { + vertex_colors = std::move(_vertex_colors); + // See: https://github.com/rerun-io/rerun/issues/4027 + RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) + } + /// A color multiplier applied to the whole asset. Asset3D with_albedo_factor(rerun::components::AlbedoFactor _albedo_factor) && { albedo_factor = std::move(_albedo_factor); diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index ef0845415bea..2d99e06c3e4d 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -62,6 +62,7 @@ def __attrs_clear__(self) -> None: self.__attrs_init__( blob=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] + vertex_colors=None, # type: ignore[arg-type] albedo_factor=None, # type: ignore[arg-type] ) @@ -98,6 +99,15 @@ def _clear(cls) -> Asset3D: # # (Docstring intentionally commented out to hide this field from the docs) + vertex_colors: components.ColorBatch | None = field( + metadata={"component": "optional"}, + default=None, + converter=components.ColorBatch._optional, # type: ignore[misc] + ) + # An optional color for each vertex. + # + # (Docstring intentionally commented out to hide this field from the docs) + albedo_factor: components.AlbedoFactorBatch | None = field( metadata={"component": "optional"}, default=None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py index 92fd5074c200..5969df543c56 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py @@ -16,6 +16,7 @@ def __init__( path: str | pathlib.Path | None = None, contents: datatypes.BlobLike | None = None, media_type: datatypes.Utf8Like | None = None, + vertex_colors: datatypes.Rgba32ArrayLike | None = None, albedo_factor: datatypes.Rgba32Like | None = None, ): """ @@ -43,6 +44,9 @@ def __init__( If omitted, it will be guessed from the `path` (if any), or the viewer will try to guess from the contents (magic header). If the media type cannot be guessed, the viewer won't be able to render the asset. + + vertex_colors: + An optional color for each vertex. albedo_factor: Optional color multiplier for the whole mesh @@ -61,7 +65,9 @@ def __init__( if media_type is None: media_type = MediaType.guess_from_path(path) - self.__attrs_init__(blob=blob, media_type=media_type, albedo_factor=albedo_factor) + self.__attrs_init__( + blob=blob, media_type=media_type, vertex_colors=vertex_colors, albedo_factor=albedo_factor + ) return self.__attrs_clear__() From 10a58e0326bef0fb3d376e0c5a35a69b6becf6de Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Wed, 2 Oct 2024 09:53:24 +0200 Subject: [PATCH 04/11] Add post-loader `albedo_factor` - remove `albedo_factor` from loader --- crates/viewer/re_renderer/src/importer/obj.rs | 5 +- crates/viewer/re_renderer/src/importer/stl.rs | 3 +- .../re_renderer/src/renderer/mesh_renderer.rs | 14 +++++ .../viewer/re_renderer_examples/framework.rs | 2 +- .../re_space_view_spatial/src/mesh_loader.rs | 56 +++++++++++++++++-- 5 files changed, 70 insertions(+), 10 deletions(-) diff --git a/crates/viewer/re_renderer/src/importer/obj.rs b/crates/viewer/re_renderer/src/importer/obj.rs index 0008a84579d3..c051edc88a01 100644 --- a/crates/viewer/re_renderer/src/importer/obj.rs +++ b/crates/viewer/re_renderer/src/importer/obj.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use re_types::components::{AlbedoFactor, Color}; +use re_types::components::Color; use smallvec::smallvec; use crate::{ @@ -26,7 +26,6 @@ pub fn load_obj_from_buffer( buffer: &[u8], ctx: &RenderContext, vertex_colors: &Option>, - albedo_factor: &Option, ) -> Result, ObjImportError> { re_tracing::profile_function!(); @@ -102,7 +101,7 @@ pub fn load_obj_from_buffer( label: "default material".into(), index_range: 0..mesh.indices.len() as u32, albedo: texture.clone(), - albedo_factor: albedo_factor.map_or(crate::Rgba::WHITE, |c| c.0.into()), + albedo_factor: crate::Rgba::WHITE, }], }; diff --git a/crates/viewer/re_renderer/src/importer/stl.rs b/crates/viewer/re_renderer/src/importer/stl.rs index f071b8511234..a29bd553b2d5 100644 --- a/crates/viewer/re_renderer/src/importer/stl.rs +++ b/crates/viewer/re_renderer/src/importer/stl.rs @@ -31,7 +31,6 @@ pub fn load_stl_from_buffer( let Asset3D { blob, vertex_colors, - albedo_factor, .. } = asset3d; @@ -65,7 +64,7 @@ pub fn load_stl_from_buffer( label: name.clone().into(), index_range: 0..num_vertices as u32, albedo: ctx.texture_manager_2d.white_texture_unorm_handle().clone(), - albedo_factor: albedo_factor.map_or(crate::Rgba::WHITE, |c| c.0.into()), + albedo_factor: crate::Rgba::WHITE, }; let mesh = mesh::Mesh { diff --git a/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs b/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs index 9b8be32f863a..f5724677f0fa 100644 --- a/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs +++ b/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs @@ -131,6 +131,20 @@ pub struct MeshInstance { pub picking_layer_id: PickingLayerId, } +impl Clone for MeshInstance { + #[inline] + fn clone(&self) -> Self { + Self { + gpu_mesh: self.gpu_mesh.clone(), + mesh: self.mesh.clone(), + world_from_mesh: self.world_from_mesh, + additive_tint: self.additive_tint, + outline_mask_ids: self.outline_mask_ids, + picking_layer_id: self.picking_layer_id, + } + } +} + impl MeshInstance { /// Creates a new instance of a mesh with all fields set to default except for required ones. pub fn new(gpu_mesh: Arc) -> Self { diff --git a/crates/viewer/re_renderer_examples/framework.rs b/crates/viewer/re_renderer_examples/framework.rs index 112953fc0416..3f9f8d5c9e32 100644 --- a/crates/viewer/re_renderer_examples/framework.rs +++ b/crates/viewer/re_renderer_examples/framework.rs @@ -332,7 +332,7 @@ pub fn load_rerun_mesh(re_ctx: &RenderContext) -> Vec { diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index ca22295aacdb..79b6bd3b8e68 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -1,11 +1,17 @@ use itertools::Itertools; use re_chunk_store::RowId; -use re_renderer::{mesh::GpuMesh, RenderContext, Rgba32Unmul}; +use re_renderer::{ + mesh::{self, GpuMesh, MeshError}, + renderer::MeshInstance, + RenderContext, Rgba32Unmul, +}; use re_types::{ archetypes::{Asset3D, Mesh3D}, components::MediaType, }; use re_viewer_context::{gpu_bridge::texture_creation_desc_from_color_image, ImageInfo}; +use smallvec::smallvec; +use std::sync::Arc; use crate::mesh_cache::AnyMesh; @@ -55,7 +61,6 @@ impl LoadedMesh { bytes, render_ctx, &asset3d.vertex_colors, - &asset3d.albedo_factor, )?, MediaType::STL => { re_renderer::importer::stl::load_stl_from_buffer(asset3d, render_ctx, texture_key)? @@ -63,12 +68,24 @@ impl LoadedMesh { _ => anyhow::bail!("{media_type} files are not supported"), }; - let bbox = re_renderer::importer::calculate_bounding_box(&mesh_instances); + let prev_mesh_instances = mesh_instances.clone(); + let mesh_instances = add_albedo_factor_to_mesh(mesh_instances, asset3d, render_ctx); + + if let Ok(mesh_instances) = mesh_instances { + let bbox = re_renderer::importer::calculate_bounding_box(&mesh_instances); + + return Ok(Self { + name, + bbox, + mesh_instances, + }); + } + let bbox = re_renderer::importer::calculate_bounding_box(&prev_mesh_instances); Ok(Self { name, bbox, - mesh_instances, + mesh_instances: prev_mesh_instances, }) } @@ -205,6 +222,37 @@ impl LoadedMesh { } } +fn add_albedo_factor_to_mesh( + mesh_instances: Vec, + asset3d: &Asset3D, + render_ctx: &RenderContext, +) -> Result, MeshError> { + if let Some(m) = &mesh_instances[0].mesh { + // Create new material from mesh_instance, add Asset3D's albedo_factor + let material = mesh::Material { + albedo_factor: asset3d + .albedo_factor + .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()), + ..m.materials[0].clone() + }; + + let mesh_inst = Arc::clone(m); + + // Create new mesh with albedo_factor + let mesh = mesh::Mesh { + materials: smallvec![material], + ..(*mesh_inst).clone() + }; + + Ok(vec![MeshInstance::new_with_cpu_mesh( + Arc::new(GpuMesh::new(render_ctx, &mesh)?), + Some(Arc::new(mesh)), + )]) + } else { + Ok(mesh_instances) + } +} + fn try_get_or_create_albedo_texture( albedo_texture_buffer: &Option, albedo_texture_format: &Option, From 26fc9d7dc39d2350ad192e09ab09c3e4d6091835 Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Thu, 3 Oct 2024 13:59:57 +0200 Subject: [PATCH 05/11] Remove vertex_colors from Asset3D --- Cargo.lock | 1 - .../definitions/rerun/archetypes/asset3d.fbs | 5 +- .../store/re_types/src/archetypes/asset3d.rs | 51 +++-------------- .../re_types/src/archetypes/asset3d_ext.rs | 1 - crates/store/re_types/tests/types/asset3d.rs | 5 -- crates/viewer/re_renderer/Cargo.toml | 1 - crates/viewer/re_renderer/src/importer/obj.rs | 30 +++++----- crates/viewer/re_renderer/src/importer/stl.rs | 55 ++----------------- .../viewer/re_renderer_examples/framework.rs | 2 +- .../re_space_view_spatial/src/mesh_loader.rs | 8 +-- .../src/visualizers/assets3d.rs | 40 ++++++-------- crates/viewer/re_viewer/src/reflection/mod.rs | 3 - .../reference/types/archetypes/asset3d.md | 2 +- .../reference/types/components/color.md | 1 - rerun_cpp/src/rerun/archetypes/asset3d.cpp | 7 +-- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 11 ---- .../rerun_sdk/rerun/archetypes/asset3d.py | 10 ---- .../rerun_sdk/rerun/archetypes/asset3d_ext.py | 7 +-- 18 files changed, 48 insertions(+), 192 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4aba4065c846..962d25303729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5320,7 +5320,6 @@ dependencies = [ "re_log", "re_math", "re_tracing", - "re_types", "re_video", "serde", "slotmap", diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index 484df2efe861..a20c7aec601a 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -36,9 +36,6 @@ table Asset3D ( // --- Optional --- - /// An optional color for each vertex. - vertex_colors: [rerun.components.Color] ("attr.rerun.component_optional", nullable, order: 3100); - /// A color multiplier applied to the whole asset. - albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3200); + albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index 963bf5f19cb4..c4c86d4edf6a 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -71,10 +71,10 @@ pub struct Asset3D { /// If it cannot guess, it won't be able to render the asset. pub media_type: Option, - /// An optional color for each vertex. - pub vertex_colors: Option>, - /// A color multiplier applied to the whole asset. + /// + /// For mesh who already have albedo_factor in materials, + /// it will be overwritten by actual albedo_factor of Asset3D (if specified). pub albedo_factor: Option, } @@ -83,7 +83,6 @@ impl ::re_types_core::SizeBytes for Asset3D { fn heap_size_bytes(&self) -> u64 { self.blob.heap_size_bytes() + self.media_type.heap_size_bytes() - + self.vertex_colors.heap_size_bytes() + self.albedo_factor.heap_size_bytes() } @@ -91,7 +90,6 @@ impl ::re_types_core::SizeBytes for Asset3D { fn is_pod() -> bool { ::is_pod() && >::is_pod() - && >>::is_pod() && >::is_pod() } } @@ -107,28 +105,22 @@ static RECOMMENDED_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = ] }); -static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 2usize]> = - once_cell::sync::Lazy::new(|| { - [ - "rerun.components.Color".into(), - "rerun.components.AlbedoFactor".into(), - ] - }); +static OPTIONAL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 1usize]> = + once_cell::sync::Lazy::new(|| ["rerun.components.AlbedoFactor".into()]); -static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 5usize]> = +static ALL_COMPONENTS: once_cell::sync::Lazy<[ComponentName; 4usize]> = once_cell::sync::Lazy::new(|| { [ "rerun.components.Blob".into(), "rerun.components.MediaType".into(), "rerun.components.Asset3DIndicator".into(), - "rerun.components.Color".into(), "rerun.components.AlbedoFactor".into(), ] }); impl Asset3D { - /// The total number of components in the archetype: 1 required, 2 recommended, 2 optional - pub const NUM_COMPONENTS: usize = 5usize; + /// The total number of components in the archetype: 1 required, 2 recommended, 1 optional + pub const NUM_COMPONENTS: usize = 4usize; } /// Indicator component for the [`Asset3D`] [`::re_types_core::Archetype`] @@ -205,18 +197,6 @@ impl ::re_types_core::Archetype for Asset3D { } else { None }; - let vertex_colors = if let Some(array) = arrays_by_name.get("rerun.components.Color") { - Some({ - ::from_arrow_opt(&**array) - .with_context("rerun.archetypes.Asset3D#vertex_colors")? - .into_iter() - .map(|v| v.ok_or_else(DeserializationError::missing_data)) - .collect::>>() - .with_context("rerun.archetypes.Asset3D#vertex_colors")? - }) - } else { - None - }; let albedo_factor = if let Some(array) = arrays_by_name.get("rerun.components.AlbedoFactor") { ::from_arrow_opt(&**array) @@ -230,7 +210,6 @@ impl ::re_types_core::Archetype for Asset3D { Ok(Self { blob, media_type, - vertex_colors, albedo_factor, }) } @@ -246,9 +225,6 @@ impl ::re_types_core::AsComponents for Asset3D { self.media_type .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), - self.vertex_colors - .as_ref() - .map(|comp_batch| (comp_batch as &dyn ComponentBatch).into()), self.albedo_factor .as_ref() .map(|comp| (comp as &dyn ComponentBatch).into()), @@ -268,7 +244,6 @@ impl Asset3D { Self { blob: blob.into(), media_type: None, - vertex_colors: None, albedo_factor: None, } } @@ -289,16 +264,6 @@ impl Asset3D { self } - /// An optional color for each vertex. - #[inline] - pub fn with_vertex_colors( - mut self, - vertex_colors: impl IntoIterator>, - ) -> Self { - self.vertex_colors = Some(vertex_colors.into_iter().map(Into::into).collect()); - self - } - /// A color multiplier applied to the whole asset. #[inline] pub fn with_albedo_factor( diff --git a/crates/store/re_types/src/archetypes/asset3d_ext.rs b/crates/store/re_types/src/archetypes/asset3d_ext.rs index 15bfdc744b90..07e66bfa158e 100644 --- a/crates/store/re_types/src/archetypes/asset3d_ext.rs +++ b/crates/store/re_types/src/archetypes/asset3d_ext.rs @@ -35,7 +35,6 @@ impl Asset3D { Self { blob: contents.into(), media_type, - vertex_colors: None, albedo_factor: None, } } diff --git a/crates/store/re_types/tests/types/asset3d.rs b/crates/store/re_types/tests/types/asset3d.rs index 86ce4c8f3147..bfc4e64e8f38 100644 --- a/crates/store/re_types/tests/types/asset3d.rs +++ b/crates/store/re_types/tests/types/asset3d.rs @@ -12,15 +12,10 @@ fn roundtrip() { let expected = Asset3D { blob: Blob(BYTES.to_vec().into()), media_type: Some(MediaType(Utf8(MediaType::GLTF.into()))), - vertex_colors: Some(vec![ - Rgba32::from_unmultiplied_rgba(0xAA, 0x00, 0x00, 0xCC).into(), // - Rgba32::from_unmultiplied_rgba(0x00, 0xBB, 0x00, 0xDD).into(), - ]), albedo_factor: Some(Rgba32::from_unmultiplied_rgba(0xEE, 0x11, 0x22, 0x33).into()), }; let arch = Asset3D::from_file_contents(BYTES.to_vec(), Some(MediaType::gltf())) - .with_vertex_colors([0xAA0000CC, 0x00BB00DD]) .with_albedo_factor(0xEE112233); similar_asserts::assert_eq!(expected, arch); diff --git a/crates/viewer/re_renderer/Cargo.toml b/crates/viewer/re_renderer/Cargo.toml index 9edee6969e5a..0ee4ef3e6537 100644 --- a/crates/viewer/re_renderer/Cargo.toml +++ b/crates/viewer/re_renderer/Cargo.toml @@ -53,7 +53,6 @@ re_log.workspace = true re_math.workspace = true re_tracing.workspace = true re_video.workspace = true -re_types.workspace = true ahash.workspace = true anyhow.workspace = true diff --git a/crates/viewer/re_renderer/src/importer/obj.rs b/crates/viewer/re_renderer/src/importer/obj.rs index c051edc88a01..88414dd16782 100644 --- a/crates/viewer/re_renderer/src/importer/obj.rs +++ b/crates/viewer/re_renderer/src/importer/obj.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use re_types::components::Color; use smallvec::smallvec; use crate::{ @@ -9,8 +8,6 @@ use crate::{ RenderContext, Rgba32Unmul, }; -use super::stl::clamped_vec_or_empty_color; - #[derive(thiserror::Error, Debug)] pub enum ObjImportError { #[error(transparent)] @@ -25,7 +22,6 @@ pub enum ObjImportError { pub fn load_obj_from_buffer( buffer: &[u8], ctx: &RenderContext, - vertex_colors: &Option>, ) -> Result, ObjImportError> { re_tracing::profile_function!(); @@ -58,19 +54,19 @@ pub fn load_obj_from_buffer( .map(|p| glam::uvec3(p[0], p[1], p[2])) .collect(); - let num_positions = vertex_positions.len(); - - let vertex_colors = if let Some(vertex_colors) = vertex_colors { - let vertex_colors_arr = - clamped_vec_or_empty_color(vertex_colors.as_slice(), vertex_positions.len()); - re_tracing::profile_scope!("copy_colors"); - vertex_colors_arr - .iter() - .map(|c| Rgba32Unmul::from_rgba_unmul_array(c.to_array())) - .collect() - } else { - vec![Rgba32Unmul::WHITE; num_positions] - }; + let mut vertex_colors: Vec = mesh + .vertex_color + .chunks_exact(3) + .map(|c| { + Rgba32Unmul::from_rgb( + // It is not specified if the color is in linear or gamma space, but gamma seems a safe bet. + (c[0] * 255.0).round() as u8, + (c[1] * 255.0).round() as u8, + (c[2] * 255.0).round() as u8, + ) + }) + .collect(); + vertex_colors.resize(vertex_positions.len(), Rgba32Unmul::WHITE); let mut vertex_normals: Vec = mesh .normals diff --git a/crates/viewer/re_renderer/src/importer/stl.rs b/crates/viewer/re_renderer/src/importer/stl.rs index a29bd553b2d5..fad815c7c250 100644 --- a/crates/viewer/re_renderer/src/importer/stl.rs +++ b/crates/viewer/re_renderer/src/importer/stl.rs @@ -7,9 +7,8 @@ use tinystl::StlData; use crate::{ mesh::{self, GpuMesh}, renderer::MeshInstance, - RenderContext, Rgba32Unmul, + RenderContext, }; -use re_types::{archetypes::Asset3D, components::Color}; #[derive(thiserror::Error, Debug)] pub enum StlImportError { @@ -22,20 +21,12 @@ pub enum StlImportError { /// Load a [STL .stl file](https://en.wikipedia.org/wiki/STL_(file_format)) into the mesh manager. pub fn load_stl_from_buffer( - asset3d: &Asset3D, + buffer: &[u8], ctx: &RenderContext, _texture_key: u64, ) -> Result, StlImportError> { re_tracing::profile_function!(); - let Asset3D { - blob, - vertex_colors, - .. - } = asset3d; - - let buffer = blob.as_slice(); - let cursor = std::io::Cursor::new(buffer); let StlData { name, @@ -45,20 +36,6 @@ pub fn load_stl_from_buffer( } = StlData::read_buffer(std::io::BufReader::new(cursor)).map_err(StlImportError::TinyStl)?; let num_vertices = triangles.len() * 3; - let vertex_positions: &[glam::Vec3] = bytemuck::cast_slice(&triangles); - let num_positions = vertex_positions.len(); - - let vertex_colors = if let Some(vertex_colors) = vertex_colors { - let vertex_colors_arr = - clamped_vec_or_empty_color(vertex_colors.as_slice(), vertex_positions.len()); - re_tracing::profile_scope!("copy_colors"); - vertex_colors_arr - .iter() - .map(|c| Rgba32Unmul::from_rgba_unmul_array(c.to_array())) - .collect() - } else { - vec![Rgba32Unmul::WHITE; num_positions] - }; let material = mesh::Material { label: name.clone().into(), @@ -85,8 +62,8 @@ pub fn load_stl_from_buffer( }) .collect(), - vertex_colors, - // STL has no texcoords. + // STL has neither colors nor texcoords. + vertex_colors: vec![crate::Rgba32Unmul::WHITE; num_vertices], vertex_texcoords: vec![glam::Vec2::ZERO; num_vertices], materials: smallvec![material], @@ -99,27 +76,3 @@ pub fn load_stl_from_buffer( Some(Arc::new(mesh)), )]) } - -pub fn clamped_vec_or_empty_color(values: &[Color], clamped_len: usize) -> Vec { - if values.len() == clamped_len { - // Happy path - values.to_vec() // TODO(emilk): return a slice reference instead, in a `Cow` or similar - } else if let Some(last) = values.last() { - if values.len() == 1 { - // Commo happy path - return vec![*last; clamped_len]; - } else if values.len() < clamped_len { - // Clamp - let mut vec = Vec::with_capacity(clamped_len); - vec.extend(values.iter()); - vec.extend(std::iter::repeat(last).take(clamped_len - values.len())); - vec - } else { - // Trim - values.iter().take(clamped_len).copied().collect() - } - } else { - // Empty input - Vec::new() - } -} diff --git a/crates/viewer/re_renderer_examples/framework.rs b/crates/viewer/re_renderer_examples/framework.rs index 3f9f8d5c9e32..a034242c9143 100644 --- a/crates/viewer/re_renderer_examples/framework.rs +++ b/crates/viewer/re_renderer_examples/framework.rs @@ -332,7 +332,7 @@ pub fn load_rerun_mesh(re_ctx: &RenderContext) -> Vec { diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index 79b6bd3b8e68..3758cc5920f1 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -57,13 +57,9 @@ impl LoadedMesh { MediaType::GLTF | MediaType::GLB => { re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? } - MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer( - bytes, - render_ctx, - &asset3d.vertex_colors, - )?, + MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer(bytes, render_ctx)?, MediaType::STL => { - re_renderer::importer::stl::load_stl_from_buffer(asset3d, render_ctx, texture_key)? + re_renderer::importer::stl::load_stl_from_buffer(bytes, render_ctx, texture_key)? } _ => anyhow::bail!("{media_type} files are not supported"), }; diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs index 361320ead17c..0c2a0559b0e5 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs @@ -4,7 +4,7 @@ use re_renderer::renderer::MeshInstance; use re_renderer::RenderContext; use re_types::{ archetypes::Asset3D, - components::{AlbedoFactor, Blob, Color, MediaType}, + components::{AlbedoFactor, Blob, MediaType}, ArrowBuffer, ArrowString, Loggable as _, }; use re_viewer_context::{ @@ -38,7 +38,6 @@ struct Asset3DComponentData<'a> { blob: ArrowBuffer, media_type: Option, - vertex_colors: &'a [Color], albedo_factor: Option<&'a AlbedoFactor>, } @@ -76,7 +75,6 @@ impl Asset3DVisualizer { asset: &Asset3D { blob: data.blob.clone().into(), media_type: data.media_type.clone().map(Into::into), - vertex_colors: Some(data.vertex_colors.to_vec()), albedo_factor: data.albedo_factor.copied(), }, texture_key: re_log_types::hash::Hash64::hash(&key).hash64(), @@ -162,35 +160,29 @@ impl VisualizerSystem for Asset3DVisualizer { let timeline = ctx.query.timeline(); let all_blobs_indexed = iter_buffer::(&all_blob_chunks, timeline, Blob::name()); let all_media_types = results.iter_as(timeline, MediaType::name()); - let all_vertex_colors = results.iter_as(timeline, Color::name()); let all_albedo_factors = results.iter_as(timeline, AlbedoFactor::name()); let query_result_hash = results.query_result_hash(); - let data = re_query::range_zip_1x3( + let data = re_query::range_zip_1x2( all_blobs_indexed, all_media_types.string(), - all_vertex_colors.primitive::(), all_albedo_factors.primitive::(), ) - .filter_map( - |(index, blobs, media_types, vertex_colors, albedo_factors)| { - blobs.first().map(|blob| Asset3DComponentData { - index, - query_result_hash, - blob: blob.clone(), - media_type: media_types - .and_then(|media_types| media_types.first().cloned()), - vertex_colors: vertex_colors - .map_or(&[], |vertex_colors| bytemuck::cast_slice(vertex_colors)), - albedo_factor: albedo_factors - .map_or(&[] as &[AlbedoFactor], |albedo_factors| { - bytemuck::cast_slice(albedo_factors) - }) - .first(), - }) - }, - ); + .filter_map(|(index, blobs, media_types, albedo_factors)| { + blobs.first().map(|blob| Asset3DComponentData { + index, + query_result_hash, + blob: blob.clone(), + media_type: media_types + .and_then(|media_types| media_types.first().cloned()), + albedo_factor: albedo_factors + .map_or(&[] as &[AlbedoFactor], |albedo_factors| { + bytemuck::cast_slice(albedo_factors) + }) + .first(), + }) + }); self.process_data(ctx, render_ctx, &mut instances, spatial_ctx, data); diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 49a39dd00758..8742dfe6487c 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -802,9 +802,6 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { docstring_md : "The Media Type of the asset.\n\nSupported values:\n* `model/gltf-binary`\n* `model/gltf+json`\n* `model/obj` (.mtl material files are not supported yet, references are silently ignored)\n* `model/stl`\n\nIf omitted, the viewer will try to guess from the data blob.\nIf it cannot guess, it won't be able to render the asset.", is_required : false, }, ArchetypeFieldReflection { component_name : - "rerun.components.Color".into(), display_name : "Vertex colors", - docstring_md : "An optional color for each vertex.", is_required : - false, }, ArchetypeFieldReflection { component_name : "rerun.components.AlbedoFactor".into(), display_name : "Albedo factor", docstring_md : "A color multiplier applied to the whole asset.", is_required : diff --git a/docs/content/reference/types/archetypes/asset3d.md b/docs/content/reference/types/archetypes/asset3d.md index 29e3b8dc98d8..fb60d25a220b 100644 --- a/docs/content/reference/types/archetypes/asset3d.md +++ b/docs/content/reference/types/archetypes/asset3d.md @@ -16,7 +16,7 @@ an instance of the mesh will be drawn for each transform. **Recommended**: [`MediaType`](../components/media_type.md) -**Optional**: [`Color`](../components/color.md), [`AlbedoFactor`](../components/albedo_factor.md) +**Optional**: [`AlbedoFactor`](../components/albedo_factor.md) ## Shown in * [Spatial3DView](../views/spatial3d_view.md) diff --git a/docs/content/reference/types/components/color.md b/docs/content/reference/types/components/color.md index 05fa736033ab..c5703e66ea2f 100644 --- a/docs/content/reference/types/components/color.md +++ b/docs/content/reference/types/components/color.md @@ -22,7 +22,6 @@ byte is `R` and the least significant byte is `A`. * [`Arrows2D`](../archetypes/arrows2d.md) * [`Arrows3D`](../archetypes/arrows3d.md) -* [`Asset3D`](../archetypes/asset3d.md) * [`BarChart`](../archetypes/bar_chart.md) * [`Boxes2D`](../archetypes/boxes2d.md) * [`Boxes3D`](../archetypes/boxes3d.md) diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.cpp b/rerun_cpp/src/rerun/archetypes/asset3d.cpp index 32885a35e4cf..99f9341f8359 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.cpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.cpp @@ -14,7 +14,7 @@ namespace rerun { ) { using namespace archetypes; std::vector cells; - cells.reserve(5); + cells.reserve(4); { auto result = ComponentBatch::from_loggable(archetype.blob); @@ -26,11 +26,6 @@ namespace rerun { RR_RETURN_NOT_OK(result.error); cells.push_back(std::move(result.value)); } - if (archetype.vertex_colors.has_value()) { - auto result = ComponentBatch::from_loggable(archetype.vertex_colors.value()); - RR_RETURN_NOT_OK(result.error); - cells.push_back(std::move(result.value)); - } if (archetype.albedo_factor.has_value()) { auto result = ComponentBatch::from_loggable(archetype.albedo_factor.value()); RR_RETURN_NOT_OK(result.error); diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index f715ca69002b..7a854ab61b17 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -8,7 +8,6 @@ #include "../component_batch.hpp" #include "../components/albedo_factor.hpp" #include "../components/blob.hpp" -#include "../components/color.hpp" #include "../components/media_type.hpp" #include "../indicator_component.hpp" #include "../result.hpp" @@ -68,9 +67,6 @@ namespace rerun::archetypes { /// If it cannot guess, it won't be able to render the asset. std::optional media_type; - /// An optional color for each vertex. - std::optional> vertex_colors; - /// A color multiplier applied to the whole asset. std::optional albedo_factor; @@ -127,13 +123,6 @@ namespace rerun::archetypes { RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) } - /// An optional color for each vertex. - Asset3D with_vertex_colors(Collection _vertex_colors) && { - vertex_colors = std::move(_vertex_colors); - // See: https://github.com/rerun-io/rerun/issues/4027 - RR_WITH_MAYBE_UNINITIALIZED_DISABLED(return std::move(*this);) - } - /// A color multiplier applied to the whole asset. Asset3D with_albedo_factor(rerun::components::AlbedoFactor _albedo_factor) && { albedo_factor = std::move(_albedo_factor); diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index 2d99e06c3e4d..ef0845415bea 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -62,7 +62,6 @@ def __attrs_clear__(self) -> None: self.__attrs_init__( blob=None, # type: ignore[arg-type] media_type=None, # type: ignore[arg-type] - vertex_colors=None, # type: ignore[arg-type] albedo_factor=None, # type: ignore[arg-type] ) @@ -99,15 +98,6 @@ def _clear(cls) -> Asset3D: # # (Docstring intentionally commented out to hide this field from the docs) - vertex_colors: components.ColorBatch | None = field( - metadata={"component": "optional"}, - default=None, - converter=components.ColorBatch._optional, # type: ignore[misc] - ) - # An optional color for each vertex. - # - # (Docstring intentionally commented out to hide this field from the docs) - albedo_factor: components.AlbedoFactorBatch | None = field( metadata={"component": "optional"}, default=None, diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py index 5969df543c56..9499c6dd6f04 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d_ext.py @@ -16,7 +16,6 @@ def __init__( path: str | pathlib.Path | None = None, contents: datatypes.BlobLike | None = None, media_type: datatypes.Utf8Like | None = None, - vertex_colors: datatypes.Rgba32ArrayLike | None = None, albedo_factor: datatypes.Rgba32Like | None = None, ): """ @@ -45,8 +44,6 @@ def __init__( or the viewer will try to guess from the contents (magic header). If the media type cannot be guessed, the viewer won't be able to render the asset. - vertex_colors: - An optional color for each vertex. albedo_factor: Optional color multiplier for the whole mesh @@ -65,9 +62,7 @@ def __init__( if media_type is None: media_type = MediaType.guess_from_path(path) - self.__attrs_init__( - blob=blob, media_type=media_type, vertex_colors=vertex_colors, albedo_factor=albedo_factor - ) + self.__attrs_init__(blob=blob, media_type=media_type, albedo_factor=albedo_factor) return self.__attrs_clear__() From f8ff7659bb98ed43a34f90db656256720a01f65b Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Thu, 3 Oct 2024 15:50:22 +0200 Subject: [PATCH 06/11] Specify interactions between albedo_factor and existing materials --- .../store/re_types/definitions/rerun/archetypes/asset3d.fbs | 3 +++ crates/store/re_types/src/archetypes/asset3d.rs | 3 +++ crates/viewer/re_viewer/src/reflection/mod.rs | 4 ++-- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 6 ++++++ rerun_py/rerun_sdk/rerun/archetypes/asset3d.py | 3 +++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index a20c7aec601a..bb7d26ce3816 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -37,5 +37,8 @@ table Asset3D ( // --- Optional --- /// A color multiplier applied to the whole asset. + /// + /// For mesh who already have albedo_factor in materials, + /// it will be overwritten by actual albedo_factor of Asset3D (if specified). albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index c4c86d4edf6a..f0eab8649d4c 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -265,6 +265,9 @@ impl Asset3D { } /// A color multiplier applied to the whole asset. + /// + /// For mesh who already have albedo_factor in materials, + /// it will be overwritten by actual albedo_factor of Asset3D (if specified). #[inline] pub fn with_albedo_factor( mut self, diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 8742dfe6487c..ac51d680ae41 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -804,8 +804,8 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { is_required : false, }, ArchetypeFieldReflection { component_name : "rerun.components.AlbedoFactor".into(), display_name : "Albedo factor", docstring_md : - "A color multiplier applied to the whole asset.", is_required : - false, }, + "A color multiplier applied to the whole asset.\n\nFor mesh who already have albedo_factor in materials,\nit will be overwritten by actual albedo_factor of Asset3D (if specified).", + is_required : false, }, ], }, ), diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index 7a854ab61b17..33442f36f97d 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -68,6 +68,9 @@ namespace rerun::archetypes { std::optional media_type; /// A color multiplier applied to the whole asset. + /// + /// For mesh who already have albedo_factor in materials, + /// it will be overwritten by actual albedo_factor of Asset3D (if specified). std::optional albedo_factor; public: @@ -124,6 +127,9 @@ namespace rerun::archetypes { } /// A color multiplier applied to the whole asset. + /// + /// For mesh who already have albedo_factor in materials, + /// it will be overwritten by actual albedo_factor of Asset3D (if specified). Asset3D with_albedo_factor(rerun::components::AlbedoFactor _albedo_factor) && { albedo_factor = std::move(_albedo_factor); // See: https://github.com/rerun-io/rerun/issues/4027 diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index ef0845415bea..cf887f3d6dd0 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -105,6 +105,9 @@ def _clear(cls) -> Asset3D: ) # A color multiplier applied to the whole asset. # + # For mesh who already have albedo_factor in materials, + # it will be overwritten by actual albedo_factor of Asset3D (if specified). + # # (Docstring intentionally commented out to hide this field from the docs) __str__ = Archetype.__str__ From f634de5413f6aed359c0a4e4ea960ede02c690c4 Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Fri, 11 Oct 2024 11:19:40 +0200 Subject: [PATCH 07/11] Restore media_type guessing in from_file_contents --- crates/store/re_types/src/archetypes/asset3d_ext.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/store/re_types/src/archetypes/asset3d_ext.rs b/crates/store/re_types/src/archetypes/asset3d_ext.rs index 07e66bfa158e..985ecfcb738f 100644 --- a/crates/store/re_types/src/archetypes/asset3d_ext.rs +++ b/crates/store/re_types/src/archetypes/asset3d_ext.rs @@ -32,6 +32,7 @@ impl Asset3D { #[inline] pub fn from_file_contents(contents: Vec, media_type: Option>) -> Self { let media_type = media_type.map(Into::into); + let media_type = MediaType::or_guess_from_data(media_type, &contents); Self { blob: contents.into(), media_type, From 38f40447ac6559b35e6a26b95f24c03877d5f8be Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Fri, 11 Oct 2024 14:51:11 +0200 Subject: [PATCH 08/11] Remove texture_key from AnyMesh::Asset - Add #derive[(Clone)] instead of impl Clone for MeshInstance --- crates/viewer/re_renderer/src/importer/stl.rs | 1 - .../re_renderer/src/renderer/mesh_renderer.rs | 15 +-------------- .../re_space_view_spatial/src/mesh_cache.rs | 4 ---- .../re_space_view_spatial/src/mesh_loader.rs | 12 +++--------- .../src/visualizers/assets3d.rs | 1 - 5 files changed, 4 insertions(+), 29 deletions(-) diff --git a/crates/viewer/re_renderer/src/importer/stl.rs b/crates/viewer/re_renderer/src/importer/stl.rs index fad815c7c250..30b1ad98a677 100644 --- a/crates/viewer/re_renderer/src/importer/stl.rs +++ b/crates/viewer/re_renderer/src/importer/stl.rs @@ -23,7 +23,6 @@ pub enum StlImportError { pub fn load_stl_from_buffer( buffer: &[u8], ctx: &RenderContext, - _texture_key: u64, ) -> Result, StlImportError> { re_tracing::profile_function!(); diff --git a/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs b/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs index f5724677f0fa..230dc552809b 100644 --- a/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs +++ b/crates/viewer/re_renderer/src/renderer/mesh_renderer.rs @@ -110,6 +110,7 @@ impl DrawData for MeshDrawData { type Renderer = MeshRenderer; } +#[derive(Clone)] pub struct MeshInstance { /// Gpu mesh used by this instance pub gpu_mesh: Arc, @@ -131,20 +132,6 @@ pub struct MeshInstance { pub picking_layer_id: PickingLayerId, } -impl Clone for MeshInstance { - #[inline] - fn clone(&self) -> Self { - Self { - gpu_mesh: self.gpu_mesh.clone(), - mesh: self.mesh.clone(), - world_from_mesh: self.world_from_mesh, - additive_tint: self.additive_tint, - outline_mask_ids: self.outline_mask_ids, - picking_layer_id: self.picking_layer_id, - } - } -} - impl MeshInstance { /// Creates a new instance of a mesh with all fields set to default except for required ones. pub fn new(gpu_mesh: Arc) -> Self { diff --git a/crates/viewer/re_space_view_spatial/src/mesh_cache.rs b/crates/viewer/re_space_view_spatial/src/mesh_cache.rs index 9c919932ba7a..0baafbc4bb4d 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_cache.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_cache.rs @@ -38,10 +38,6 @@ pub struct MeshCache(HashMap pub enum AnyMesh<'a> { Asset { asset: &'a re_types::archetypes::Asset3D, - - /// If there are any textures associated with that asset (albedo etc), they use this - /// hash for texture manager lookup. - texture_key: u64, }, Mesh { mesh: &'a re_types::archetypes::Mesh3D, diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index 3758cc5920f1..a4d9076545a2 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -33,9 +33,7 @@ impl LoadedMesh { ) -> anyhow::Result { // TODO(emilk): load CpuMesh in background thread. match mesh { - AnyMesh::Asset { asset, texture_key } => { - Ok(Self::load_asset3d(name, asset, texture_key, render_ctx)?) - } + AnyMesh::Asset { asset } => Ok(Self::load_asset3d(name, asset, render_ctx)?), AnyMesh::Mesh { mesh, texture_key } => { Ok(Self::load_mesh3d(name, mesh, texture_key, render_ctx)?) } @@ -47,7 +45,6 @@ impl LoadedMesh { media_type: &MediaType, asset3d: &Asset3D, render_ctx: &RenderContext, - texture_key: u64, ) -> anyhow::Result { re_tracing::profile_function!(); @@ -58,9 +55,7 @@ impl LoadedMesh { re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? } MediaType::OBJ => re_renderer::importer::obj::load_obj_from_buffer(bytes, render_ctx)?, - MediaType::STL => { - re_renderer::importer::stl::load_stl_from_buffer(bytes, render_ctx, texture_key)? - } + MediaType::STL => re_renderer::importer::stl::load_stl_from_buffer(bytes, render_ctx)?, _ => anyhow::bail!("{media_type} files are not supported"), }; @@ -88,7 +83,6 @@ impl LoadedMesh { fn load_asset3d( name: String, asset3d: &Asset3D, - texture_key: u64, render_ctx: &RenderContext, ) -> anyhow::Result { re_tracing::profile_function!(); @@ -96,7 +90,7 @@ impl LoadedMesh { let media_type = MediaType::or_guess_from_data(asset3d.media_type.clone(), asset3d.blob.as_slice()) .ok_or_else(|| anyhow::anyhow!("couldn't guess media type"))?; - let slf = Self::load_asset3d_parts(name, &media_type, asset3d, render_ctx, texture_key)?; + let slf = Self::load_asset3d_parts(name, &media_type, asset3d, render_ctx)?; Ok(slf) } diff --git a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs index 0c2a0559b0e5..67dc144fde9a 100644 --- a/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs +++ b/crates/viewer/re_space_view_spatial/src/visualizers/assets3d.rs @@ -77,7 +77,6 @@ impl Asset3DVisualizer { media_type: data.media_type.clone().map(Into::into), albedo_factor: data.albedo_factor.copied(), }, - texture_key: re_log_types::hash::Hash64::hash(&key).hash64(), }, render_ctx, ) From 2e5d279eb1a706684bb9e76204cf26832d02e4cc Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Mon, 14 Oct 2024 09:31:41 +0200 Subject: [PATCH 09/11] Add mesh_instance modification --- .../re_space_view_spatial/src/mesh_loader.rs | 117 ++++++++++++------ 1 file changed, 78 insertions(+), 39 deletions(-) diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index a4d9076545a2..f9819193f56c 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -1,3 +1,4 @@ +use egui::Rgba; use itertools::Itertools; use re_chunk_store::RowId; use re_renderer::{ @@ -11,7 +12,7 @@ use re_types::{ }; use re_viewer_context::{gpu_bridge::texture_creation_desc_from_color_image, ImageInfo}; use smallvec::smallvec; -use std::sync::Arc; +use std::{borrow::BorrowMut, sync::Arc}; use crate::mesh_cache::AnyMesh; @@ -50,7 +51,7 @@ impl LoadedMesh { let bytes = asset3d.blob.as_slice(); - let mesh_instances = match media_type.as_str() { + let mut mesh_instances = match media_type.as_str() { MediaType::GLTF | MediaType::GLB => { re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? } @@ -59,24 +60,44 @@ impl LoadedMesh { _ => anyhow::bail!("{media_type} files are not supported"), }; - let prev_mesh_instances = mesh_instances.clone(); - let mesh_instances = add_albedo_factor_to_mesh(mesh_instances, asset3d, render_ctx); - - if let Ok(mesh_instances) = mesh_instances { - let bbox = re_renderer::importer::calculate_bounding_box(&mesh_instances); + if let Some(a) = &mesh_instances[0].mesh { + println!( + "before function albedo : {:?}", + a.materials[0].albedo_factor + ); + } - return Ok(Self { - name, - bbox, - mesh_instances, - }); + // let prev_mesh_instances = mesh_instances.clone(); + // let mesh_instances = add_albedo_factor_to_mesh(mesh_instances, asset3d, render_ctx); + add_albedo_factor_to_mesh(&mut mesh_instances, asset3d, render_ctx); + + // if let Ok(mesh_instances) = mesh_instances { + // if let Some(m) = &mesh_instances[0].mesh { + // println!("after function albedo : {:?}", m.materials[0].albedo_factor); + // } + // let bbox = re_renderer::importer::calculate_bounding_box(&mesh_instances); + + // return Ok(Self { + // name, + // bbox, + // mesh_instances, + // }); + // } + let bbox = re_renderer::importer::calculate_bounding_box(&mesh_instances); + + for instance in &mesh_instances { + if let Some(mesh) = &instance.mesh { + println!( + "Mesh after function albedo : {:?}", + mesh.materials[0].albedo_factor + ); + } } - let bbox = re_renderer::importer::calculate_bounding_box(&prev_mesh_instances); Ok(Self { name, bbox, - mesh_instances: prev_mesh_instances, + mesh_instances, }) } @@ -213,34 +234,52 @@ impl LoadedMesh { } fn add_albedo_factor_to_mesh( - mesh_instances: Vec, + mesh_instances: &mut Vec, asset3d: &Asset3D, render_ctx: &RenderContext, -) -> Result, MeshError> { - if let Some(m) = &mesh_instances[0].mesh { - // Create new material from mesh_instance, add Asset3D's albedo_factor - let material = mesh::Material { - albedo_factor: asset3d - .albedo_factor - .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()), - ..m.materials[0].clone() - }; - - let mesh_inst = Arc::clone(m); - - // Create new mesh with albedo_factor - let mesh = mesh::Mesh { - materials: smallvec![material], - ..(*mesh_inst).clone() - }; - - Ok(vec![MeshInstance::new_with_cpu_mesh( - Arc::new(GpuMesh::new(render_ctx, &mesh)?), - Some(Arc::new(mesh)), - )]) - } else { - Ok(mesh_instances) + // ) -> Result, MeshError> { +) { + for instance in mesh_instances { + if let Some(mesh) = &mut instance.mesh { + if let Some(mutable_mesh) = Arc::get_mut(mesh) { + mutable_mesh.materials[0].albedo_factor = asset3d + .albedo_factor + .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()); + + println!( + "mesh : {:?} | albedo {:?}", + mutable_mesh.materials[0].albedo_factor, asset3d.albedo_factor + ); + } else { + println!("arc is none"); + } + } } + + // if let Some(m) = &mesh_instances[0].mesh { + // // Create new material from mesh_instance, add Asset3D's albedo_factor + // let material = mesh::Material { + // albedo_factor: asset3d + // .albedo_factor + // .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()), + // ..m.materials[0].clone() + // }; + + // let mesh_inst = Arc::clone(m); + + // // Create new mesh with albedo_factor + // let mesh = mesh::Mesh { + // materials: smallvec![material], + // ..(*mesh_inst).clone() + // }; + + // Ok(vec![MeshInstance::new_with_cpu_mesh( + // Arc::new(GpuMesh::new(render_ctx, &mesh)?), + // Some(Arc::new(mesh)), + // )]) + // } else { + // Ok(mesh_instances) + // } } fn try_get_or_create_albedo_texture( From d46215e2005e7c503904296426885be3073aadce Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Tue, 22 Oct 2024 17:12:03 +0200 Subject: [PATCH 10/11] fix CpuMesh albedo_factor modification --- .../re_space_view_spatial/src/mesh_loader.rs | 90 ++++++------------- 1 file changed, 26 insertions(+), 64 deletions(-) diff --git a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs index 902a3de44fd5..737ca00317ff 100644 --- a/crates/viewer/re_space_view_spatial/src/mesh_loader.rs +++ b/crates/viewer/re_space_view_spatial/src/mesh_loader.rs @@ -1,18 +1,11 @@ -use egui::Rgba; use itertools::Itertools; use re_chunk_store::RowId; -use re_renderer::{ - mesh::{self, GpuMesh, MeshError}, - renderer::MeshInstance, - RenderContext, Rgba32Unmul, -}; +use re_renderer::{mesh::GpuMesh, RenderContext, Rgba32Unmul}; use re_types::{ archetypes::{Asset3D, Mesh3D}, - components::MediaType, + components::{AlbedoFactor, MediaType}, }; use re_viewer_context::{gpu_bridge::texture_creation_desc_from_color_image, ImageInfo}; -use smallvec::smallvec; -use std::{borrow::BorrowMut, sync::Arc}; use crate::mesh_cache::AnyMesh; @@ -44,12 +37,13 @@ impl LoadedMesh { pub fn load_asset3d_parts( name: String, media_type: &MediaType, - asset3d: &Asset3D, + bytes: &[u8], render_ctx: &RenderContext, + albedo_factor: &Option, ) -> anyhow::Result { re_tracing::profile_function!(); - let cpu_model = match media_type.as_str() { + let mut cpu_model = match media_type.as_str() { MediaType::GLTF | MediaType::GLB => { re_renderer::importer::gltf::load_gltf_from_buffer(&name, bytes, render_ctx)? } @@ -58,6 +52,12 @@ impl LoadedMesh { _ => anyhow::bail!("{media_type} files are not supported"), }; + // Overwriting albedo_factor of CpuMesh in specified in the Asset3D + cpu_model.instances.iter().for_each(|instance| { + cpu_model.meshes[instance.mesh].materials[0].albedo_factor = + albedo_factor.map_or(re_renderer::Rgba::WHITE, |c| c.0.into()); + }); + let bbox = cpu_model.calculate_bounding_box(); let mesh_instances = cpu_model.into_gpu_meshes(render_ctx)?; @@ -75,10 +75,21 @@ impl LoadedMesh { ) -> anyhow::Result { re_tracing::profile_function!(); - let media_type = - MediaType::or_guess_from_data(asset3d.media_type.clone(), asset3d.blob.as_slice()) - .ok_or_else(|| anyhow::anyhow!("couldn't guess media type"))?; - let slf = Self::load_asset3d_parts(name, &media_type, asset3d, render_ctx)?; + let Asset3D { + blob, + media_type, + albedo_factor, + } = asset3d; + + let media_type = MediaType::or_guess_from_data(media_type.clone(), blob.as_slice()) + .ok_or_else(|| anyhow::anyhow!("couldn't guess media type"))?; + let slf = Self::load_asset3d_parts( + name, + &media_type, + blob.as_slice(), + render_ctx, + albedo_factor, + )?; Ok(slf) } @@ -200,55 +211,6 @@ impl LoadedMesh { } } -fn add_albedo_factor_to_mesh( - mesh_instances: &mut Vec, - asset3d: &Asset3D, - render_ctx: &RenderContext, - // ) -> Result, MeshError> { -) { - for instance in mesh_instances { - if let Some(mesh) = &mut instance.mesh { - if let Some(mutable_mesh) = Arc::get_mut(mesh) { - mutable_mesh.materials[0].albedo_factor = asset3d - .albedo_factor - .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()); - - println!( - "mesh : {:?} | albedo {:?}", - mutable_mesh.materials[0].albedo_factor, asset3d.albedo_factor - ); - } else { - println!("arc is none"); - } - } - } - - // if let Some(m) = &mesh_instances[0].mesh { - // // Create new material from mesh_instance, add Asset3D's albedo_factor - // let material = mesh::Material { - // albedo_factor: asset3d - // .albedo_factor - // .map_or(re_renderer::Rgba::WHITE, |c| c.0.into()), - // ..m.materials[0].clone() - // }; - - // let mesh_inst = Arc::clone(m); - - // // Create new mesh with albedo_factor - // let mesh = mesh::Mesh { - // materials: smallvec![material], - // ..(*mesh_inst).clone() - // }; - - // Ok(vec![MeshInstance::new_with_cpu_mesh( - // Arc::new(GpuMesh::new(render_ctx, &mesh)?), - // Some(Arc::new(mesh)), - // )]) - // } else { - // Ok(mesh_instances) - // } -} - fn try_get_or_create_albedo_texture( albedo_texture_buffer: &Option, albedo_texture_format: &Option, From 8da0990e5f187ca86131ab309a90825de67450db Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 23 Oct 2024 15:18:25 +0200 Subject: [PATCH 11/11] doc fixes --- .../re_types/definitions/rerun/archetypes/asset3d.fbs | 4 ++-- crates/store/re_types/src/archetypes/asset3d.rs | 8 ++++---- crates/viewer/re_viewer/src/reflection/mod.rs | 2 +- rerun_cpp/src/rerun/archetypes/asset3d.hpp | 8 ++++---- rerun_py/rerun_sdk/rerun/archetypes/asset3d.py | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs index bb7d26ce3816..b0625fbf2ff6 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/asset3d.fbs @@ -38,7 +38,7 @@ table Asset3D ( /// A color multiplier applied to the whole asset. /// - /// For mesh who already have albedo_factor in materials, - /// it will be overwritten by actual albedo_factor of Asset3D (if specified). + /// For mesh who already have `albedo_factor` in materials, + /// it will be overwritten by actual `albedo_factor` of [archetypes.Asset3D] (if specified). albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100); } diff --git a/crates/store/re_types/src/archetypes/asset3d.rs b/crates/store/re_types/src/archetypes/asset3d.rs index f0eab8649d4c..5983dff798c7 100644 --- a/crates/store/re_types/src/archetypes/asset3d.rs +++ b/crates/store/re_types/src/archetypes/asset3d.rs @@ -73,8 +73,8 @@ pub struct Asset3D { /// A color multiplier applied to the whole asset. /// - /// For mesh who already have albedo_factor in materials, - /// it will be overwritten by actual albedo_factor of Asset3D (if specified). + /// For mesh who already have `albedo_factor` in materials, + /// it will be overwritten by actual `albedo_factor` of [`archetypes::Asset3D`][crate::archetypes::Asset3D] (if specified). pub albedo_factor: Option, } @@ -266,8 +266,8 @@ impl Asset3D { /// A color multiplier applied to the whole asset. /// - /// For mesh who already have albedo_factor in materials, - /// it will be overwritten by actual albedo_factor of Asset3D (if specified). + /// For mesh who already have `albedo_factor` in materials, + /// it will be overwritten by actual `albedo_factor` of [`archetypes::Asset3D`][crate::archetypes::Asset3D] (if specified). #[inline] pub fn with_albedo_factor( mut self, diff --git a/crates/viewer/re_viewer/src/reflection/mod.rs b/crates/viewer/re_viewer/src/reflection/mod.rs index 67d5962b7eb4..245825156a81 100644 --- a/crates/viewer/re_viewer/src/reflection/mod.rs +++ b/crates/viewer/re_viewer/src/reflection/mod.rs @@ -811,7 +811,7 @@ fn generate_archetype_reflection() -> ArchetypeReflectionMap { is_required : false, }, ArchetypeFieldReflection { component_name : "rerun.components.AlbedoFactor".into(), display_name : "Albedo factor", docstring_md : - "A color multiplier applied to the whole asset.\n\nFor mesh who already have albedo_factor in materials,\nit will be overwritten by actual albedo_factor of Asset3D (if specified).", + "A color multiplier applied to the whole asset.\n\nFor mesh who already have `albedo_factor` in materials,\nit will be overwritten by actual `albedo_factor` of [`archetypes.Asset3D`](https://rerun.io/docs/reference/types/archetypes/asset3d) (if specified).", is_required : false, }, ], }, diff --git a/rerun_cpp/src/rerun/archetypes/asset3d.hpp b/rerun_cpp/src/rerun/archetypes/asset3d.hpp index 33442f36f97d..05ee83b58192 100644 --- a/rerun_cpp/src/rerun/archetypes/asset3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/asset3d.hpp @@ -69,8 +69,8 @@ namespace rerun::archetypes { /// A color multiplier applied to the whole asset. /// - /// For mesh who already have albedo_factor in materials, - /// it will be overwritten by actual albedo_factor of Asset3D (if specified). + /// For mesh who already have `albedo_factor` in materials, + /// it will be overwritten by actual `albedo_factor` of `archetypes::Asset3D` (if specified). std::optional albedo_factor; public: @@ -128,8 +128,8 @@ namespace rerun::archetypes { /// A color multiplier applied to the whole asset. /// - /// For mesh who already have albedo_factor in materials, - /// it will be overwritten by actual albedo_factor of Asset3D (if specified). + /// For mesh who already have `albedo_factor` in materials, + /// it will be overwritten by actual `albedo_factor` of `archetypes::Asset3D` (if specified). Asset3D with_albedo_factor(rerun::components::AlbedoFactor _albedo_factor) && { albedo_factor = std::move(_albedo_factor); // See: https://github.com/rerun-io/rerun/issues/4027 diff --git a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py index cf887f3d6dd0..2f0d74c87bcc 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/asset3d.py @@ -105,8 +105,8 @@ def _clear(cls) -> Asset3D: ) # A color multiplier applied to the whole asset. # - # For mesh who already have albedo_factor in materials, - # it will be overwritten by actual albedo_factor of Asset3D (if specified). + # For mesh who already have `albedo_factor` in materials, + # it will be overwritten by actual `albedo_factor` of [`archetypes.Asset3D`][rerun.archetypes.Asset3D] (if specified). # # (Docstring intentionally commented out to hide this field from the docs)