Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow overriding albedo color on Asset3D #7458

Merged
merged 12 commits into from
Oct 24, 2024
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5320,6 +5320,7 @@ dependencies = [
"re_log",
"re_math",
"re_tracing",
"re_types",
"re_video",
"serde",
"slotmap",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,12 @@ 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 ---

/// An optional color for each vertex.
vertex_colors: [rerun.components.Color] ("attr.rerun.component_optional", nullable, order: 3100);
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved

/// A color multiplier applied to the whole asset.
albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3200);
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
}
90 changes: 82 additions & 8 deletions crates/store/re_types/src/archetypes/asset3d.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/store/re_types/src/archetypes/asset3d_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ impl Asset3D {
#[inline]
pub fn from_file_contents(contents: Vec<u8>, media_type: Option<impl Into<MediaType>>) -> Self {
let media_type = media_type.map(Into::into);
let media_type = MediaType::or_guess_from_data(media_type, &contents);
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
Self {
blob: contents.into(),
media_type,
vertex_colors: None,
albedo_factor: None,
}
}
}
11 changes: 9 additions & 2 deletions crates/store/re_types/tests/types/asset3d.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use re_types::{
archetypes::Asset3D,
components::{Blob, MediaType},
datatypes::Utf8,
datatypes::{Rgba32, Utf8},
Archetype as _, AsComponents as _,
};

Expand All @@ -12,9 +12,16 @@ 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()));
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);

// let expected_extensions: HashMap<_, _> = [
Expand Down
1 change: 1 addition & 0 deletions crates/viewer/re_renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ re_log.workspace = true
re_math.workspace = true
re_tracing.workspace = true
re_video.workspace = true
re_types.workspace = true
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved

ahash.workspace = true
anyhow.workspace = true
Expand Down
33 changes: 19 additions & 14 deletions crates/viewer/re_renderer/src/importer/obj.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use re_types::components::{AlbedoFactor, Color};
use smallvec::smallvec;

use crate::{
Expand All @@ -8,6 +9,8 @@ use crate::{
RenderContext, Rgba32Unmul,
};

use super::stl::clamped_vec_or_empty_color;

#[derive(thiserror::Error, Debug)]
pub enum ObjImportError {
#[error(transparent)]
Expand All @@ -22,6 +25,8 @@ pub enum ObjImportError {
pub fn load_obj_from_buffer(
buffer: &[u8],
ctx: &RenderContext,
vertex_colors: &Option<Vec<Color>>,
albedo_factor: &Option<AlbedoFactor>,
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<Vec<MeshInstance>, ObjImportError> {
re_tracing::profile_function!();

Expand Down Expand Up @@ -54,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<Rgba32Unmul> = 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<glam::Vec3> = mesh
.normals
Expand Down Expand Up @@ -97,7 +102,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()),
}],
};

Expand Down
61 changes: 55 additions & 6 deletions crates/viewer/re_renderer/src/importer/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use tinystl::StlData;
use crate::{
mesh::{self, GpuMesh},
renderer::MeshInstance,
RenderContext,
RenderContext, Rgba32Unmul,
};
use re_types::{archetypes::Asset3D, components::Color};

#[derive(thiserror::Error, Debug)]
pub enum StlImportError {
Expand All @@ -21,11 +22,21 @@ 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,
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
ctx: &RenderContext,
_texture_key: u64,
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<Vec<MeshInstance>, StlImportError> {
re_tracing::profile_function!();

let Asset3D {
blob,
vertex_colors,
albedo_factor,
..
} = asset3d;

let buffer = blob.as_slice();

let cursor = std::io::Cursor::new(buffer);
let StlData {
name,
Expand All @@ -35,12 +46,26 @@ 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: "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 {
Expand All @@ -61,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],
Expand All @@ -75,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<Color> {
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()
}
}
2 changes: 1 addition & 1 deletion crates/viewer/re_renderer_examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ pub fn load_rerun_mesh(re_ctx: &RenderContext) -> Vec<re_renderer::renderer::Mes
let mut zipped_obj = zip.by_name("rerun.obj").unwrap();
let mut obj_data = Vec::new();
std::io::Read::read_to_end(&mut zipped_obj, &mut obj_data).unwrap();
re_renderer::importer::obj::load_obj_from_buffer(&obj_data, re_ctx).unwrap()
re_renderer::importer::obj::load_obj_from_buffer(&obj_data, re_ctx, &None, &None).unwrap()
}

struct WrapApp<E: Example + 'static> {
Expand Down
Loading
Loading