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 color specification on Asset3D #7458

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 ---

/// 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).
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
albedo_factor: rerun.components.AlbedoFactor ("attr.rerun.component_optional", nullable, order: 3100);
}
58 changes: 50 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.

2 changes: 1 addition & 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,10 @@ 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,
albedo_factor: None,
}
}
}
6 changes: 4 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,11 @@ fn roundtrip() {
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()),
};

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);
similar_asserts::assert_eq!(expected, arch);

// let expected_extensions: HashMap<_, _> = [
Expand Down
3 changes: 2 additions & 1 deletion crates/viewer/re_renderer/src/importer/stl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum StlImportError {
pub fn load_stl_from_buffer(
buffer: &[u8],
ctx: &RenderContext,
_texture_key: u64,
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<Vec<MeshInstance>, StlImportError> {
re_tracing::profile_function!();

Expand All @@ -37,7 +38,7 @@ 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,
Expand Down
14 changes: 14 additions & 0 deletions crates/viewer/re_renderer/src/renderer/mesh_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ pub struct MeshInstance {
pub picking_layer_id: PickingLayerId,
}

impl Clone for MeshInstance {
Wumpf marked this conversation as resolved.
Show resolved Hide resolved
#[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<GpuMesh>) -> Self {
Expand Down
8 changes: 7 additions & 1 deletion crates/viewer/re_space_view_spatial/src/mesh_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,13 @@ pub struct MeshCache(HashMap<RowId, HashMap<MeshCacheKey, Option<Arc<LoadedMesh>
/// 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,
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved
},
Mesh {
mesh: &'a re_types::archetypes::Mesh3D,

Expand Down
78 changes: 67 additions & 11 deletions crates/viewer/re_space_view_spatial/src/mesh_loader.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -27,7 +33,9 @@ impl LoadedMesh {
) -> anyhow::Result<Self> {
// 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)?)
}
Expand All @@ -37,41 +45,58 @@ impl LoadedMesh {
pub fn load_asset3d_parts(
name: String,
media_type: &MediaType,
bytes: &[u8],
asset3d: &Asset3D,
render_ctx: &RenderContext,
texture_key: u64,
) -> anyhow::Result<Self> {
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::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)?,
MediaType::STL => {
re_renderer::importer::stl::load_stl_from_buffer(bytes, render_ctx, texture_key)?
}
_ => 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);
Wumpf marked this conversation as resolved.
Show resolved Hide resolved

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,
})
}

fn load_asset3d(
name: String,
asset3d: &Asset3D,
texture_key: u64,
render_ctx: &RenderContext,
) -> anyhow::Result<Self> {
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)
}
Expand Down Expand Up @@ -193,6 +218,37 @@ impl LoadedMesh {
}
}

fn add_albedo_factor_to_mesh(
mesh_instances: Vec<MeshInstance>,
asset3d: &Asset3D,
render_ctx: &RenderContext,
) -> Result<Vec<MeshInstance>, 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)
}
}
EtaLoop marked this conversation as resolved.
Show resolved Hide resolved

fn try_get_or_create_albedo_texture(
albedo_texture_buffer: &Option<re_types::components::ImageBuffer>,
albedo_texture_format: &Option<re_types::components::ImageFormat>,
Expand Down
Loading
Loading