From 161224d32065ade5cb0a32ff5d41e960b456e374 Mon Sep 17 00:00:00 2001 From: EtaLoop Date: Mon, 23 Sep 2024 17:22:24 +0200 Subject: [PATCH] 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__()