Skip to content

Commit

Permalink
Update to latest three-d
Browse files Browse the repository at this point in the history
We shouldn't merge until asny/three-d#251 is fixed
  • Loading branch information
emilk committed May 21, 2022
1 parent ebf1675 commit d5eac9b
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 127 deletions.
6 changes: 2 additions & 4 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions viewer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ rand = { version = "0.8", features = ["small_rng"] }
rfd = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# We use bleeding edge three-d from 2022-04-12
three-d = { git = "https://github.com/asny/three-d", rev = "4cd766c1d5672ce02d444dc475684e24cc42e68b", default-features = false, features = [
# We use bleeding edge three-d from 2022-05-21
three-d = { git = "https://github.com/asny/three-d", rev = "8263eb240c98cff6dcfd6832c0c2572e4bf032e8", default-features = false, features = [
"gltf-io",
"obj-io",
] }
Expand Down
14 changes: 12 additions & 2 deletions viewer/src/misc/mesh_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,18 @@ impl CpuMesh {
.context("missing material")?
.clone();

let m =
InstancedModel::new_with_material(three_d, &[], m, material).map_err(to_anyhow)?;
let m = InstancedModel::new_with_material(
three_d,
&three_d::Instances {
translations: vec![],
rotations: Some(vec![]),
scales: Some(vec![]),
..Default::default()
},
m,
material,
)
.map_err(to_anyhow)?;
aabb.expand_with_aabb(&m.aabb());
models.push(m);
}
Expand Down
4 changes: 1 addition & 3 deletions viewer/src/ui/view3d/mesh_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ impl MeshCache {
pub fn set_instances(
&mut self,
mesh_id: u64,
render_states: three_d::RenderStates,
instances: &[three_d::Instance],
instances: &three_d::Instances,
) -> three_d::ThreeDResult<()> {
if let Some(Some(gpu_mesh)) = self.0.get_mut(&mesh_id) {
for model in &mut gpu_mesh.models {
model.material.render_states = render_states;
model.set_instances(instances)?;
}
}
Expand Down
224 changes: 108 additions & 116 deletions viewer/src/ui/view3d/rendering.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::scene::*;
use super::{camera::Camera, MeshCache};
use egui::Color32;

type LineMaterial = three_d::ColorMaterial;

Expand All @@ -13,12 +12,9 @@ pub struct RenderingContext {

mesh_cache: MeshCache,

sphere_mesh: three_d::CpuMesh,
line_mesh: three_d::CpuMesh,

/// So we don't need to re-allocate them.
points_cache: Vec<three_d::InstancedModel<three_d::PhysicalMaterial>>,
lines_cache: Vec<three_d::InstancedModel<LineMaterial>>,
points_cache: three_d::InstancedModel<three_d::PhysicalMaterial>,
lines_cache: three_d::InstancedModel<LineMaterial>,
}

impl RenderingContext {
Expand Down Expand Up @@ -46,17 +42,46 @@ impl RenderingContext {
)
.unwrap();

let sphere_mesh = three_d::CpuMesh::sphere(24);
let points_cache = three_d::InstancedModel::new_with_material(
&three_d,
&three_d::Instances {
// we must declare what we intend to use:
translations: vec![],
scales: Some(vec![]),
colors: Some(vec![]),
..Default::default()
},
&sphere_mesh,
default_material(),
)
.unwrap();

let line_mesh = three_d::CpuMesh::cylinder(10);
let lines_cache = three_d::InstancedModel::new_with_material(
&three_d,
&three_d::Instances {
// we must declare what we intend to use:
translations: vec![],
rotations: Some(vec![]),
scales: Some(vec![]),
colors: Some(vec![]),
..Default::default()
},
&line_mesh,
Default::default(),
)
.unwrap();

Ok(Self {
three_d,
skybox_dark,
skybox_light,
ambient_dark,
ambient_light,
sphere_mesh: three_d::CpuMesh::sphere(24),
line_mesh: three_d::CpuMesh::cylinder(10),
mesh_cache: Default::default(),
points_cache: Default::default(),
lines_cache: Default::default(),
points_cache,
lines_cache,
})
}
}
Expand Down Expand Up @@ -143,99 +168,68 @@ fn default_material() -> three_d::PhysicalMaterial {
}
}

fn allocate_points<'a>(
three_d: &'a three_d::Context,
sphere_mesh: &'a three_d::CpuMesh,
points_cache: &'a mut Vec<three_d::InstancedModel<three_d::PhysicalMaterial>>,
render_states: three_d::RenderStates,
points: &'a [Point],
) -> &'a [three_d::InstancedModel<three_d::PhysicalMaterial>] {
fn allocate_points(points: &[Point]) -> three_d::Instances {
crate::profile_function!();
use three_d::*;

let mut per_color_instances: ahash::AHashMap<Color32, Vec<Instance>> = Default::default();
let mut translations = vec![];
let mut scales = vec![];
let mut colors = vec![];

for point in points {
let p = point.pos;
let geometry_transform =
Mat4::from_translation(vec3(p[0], p[1], p[2])) * Mat4::from_scale(point.radius);
per_color_instances
.entry(point.color)
.or_default()
.push(Instance {
geometry_transform,
..Default::default()
});
translations.push(vec3(p[0], p[1], p[2]));
scales.push(vec3(point.radius, point.radius, point.radius));
colors.push(color_to_three_d(point.color));
}

if points_cache.len() < per_color_instances.len() {
points_cache.resize_with(per_color_instances.len(), || {
InstancedModel::new_with_material(three_d, &[], sphere_mesh, default_material())
.unwrap()
});
}

for ((color, instances), points) in per_color_instances.iter().zip(points_cache.iter_mut()) {
points.material.albedo = color_to_three_d(*color);
points.material.render_states = render_states;
points.set_instances(instances).unwrap();
three_d::Instances {
translations,
scales: Some(scales),
colors: Some(colors),
..Default::default()
}

&points_cache[..per_color_instances.len()]
}

fn allocate_line_segments<'a>(
three_d: &'a three_d::Context,
line_mesh: &'a three_d::CpuMesh,
lines_cache: &'a mut Vec<three_d::InstancedModel<LineMaterial>>,
render_states: three_d::RenderStates,
line_segments: &'a [LineSegments],
) -> &'a [three_d::InstancedModel<LineMaterial>] {
fn allocate_line_segments(line_segments: &[LineSegments]) -> three_d::Instances {
crate::profile_function!();
use three_d::*;

if lines_cache.len() < line_segments.len() {
lines_cache.resize_with(line_segments.len(), || {
// let material = default_material();
let material = Default::default();
InstancedModel::new_with_material(three_d, &[], line_mesh, material).unwrap()
});
}
let mut translations = vec![];
let mut rotations = vec![];
let mut scales = vec![];
let mut colors = vec![];

for (line_segments, model) in line_segments.iter().zip(lines_cache.iter_mut()) {
for line_segments in line_segments {
let LineSegments {
segments,
radius,
color,
} = line_segments;

let line_instances: Vec<Instance> = segments
.iter()
.map(|&[p0, p1]| {
let p0 = vec3(p0[0], p0[1], p0[2]);
let p1 = vec3(p1[0], p1[1], p1[2]);
let scale = Mat4::from_nonuniform_scale((p0 - p1).magnitude(), 1.0, 1.0);
let rotation =
rotation_matrix_from_dir_to_dir(vec3(1.0, 0.0, 0.0), (p1 - p0).normalize());
let translation = Mat4::from_translation(p0);
let geometry_transform = translation
* rotation
* scale
* Mat4::from_nonuniform_scale(1.0, *radius, *radius);
Instance {
geometry_transform,
..Default::default()
}
})
.collect();

model.material.render_states = render_states;
model.material.color = color_to_three_d(*color);
model.material.is_transparent = model.material.color.a < 255;

model.set_instances(&line_instances).unwrap();
for &[p0, p1] in segments {
rotations.push(three_d::Quat::from(mint::Quaternion::from(
glam::Quat::from_rotation_arc(
glam::Vec3::X,
(glam::Vec3::from(p1) - glam::Vec3::from(p0)).normalize(),
),
)));

let p0 = vec3(p0[0], p0[1], p0[2]);
let p1 = vec3(p1[0], p1[1], p1[2]);
translations.push(p0);
scales.push(vec3((p0 - p1).magnitude(), *radius, *radius));
colors.push(color_to_three_d(*color));
}
}

&lines_cache[..line_segments.len()]
three_d::Instances {
translations,
scales: Some(scales),
rotations: Some(rotations),
colors: Some(colors),
..Default::default()
}
}

pub fn paint_with_three_d(
Expand All @@ -259,15 +253,12 @@ pub fn paint_with_three_d(

// Respect the egui clip region (e.g. if we are inside an `egui::ScrollArea`).
let clip_rect = info.clip_rect_in_pixels();
let render_states = RenderStates {
clip: Clip::Enabled {
x: clip_rect.left_px.round() as _,
y: clip_rect.from_bottom_px.round() as _,
width: clip_rect.width_px.round() as _,
height: clip_rect.height_px.round() as _,
},
..Default::default()
};
three_d.set_scissor(ScissorBox {
x: clip_rect.left_px.round() as _,
y: clip_rect.from_bottom_px.round() as _,
width: clip_rect.width_px.round() as _,
height: clip_rect.height_px.round() as _,
});

let position = camera.world_from_view.translation();
let target = camera.world_from_view.transform_point3(-glam::Vec3::Z);
Expand Down Expand Up @@ -302,26 +293,36 @@ pub fn paint_with_three_d(
meshes,
} = scene;

let mut mesh_instances: std::collections::HashMap<u64, Vec<Instance>> = Default::default();
let mut mesh_instances: std::collections::HashMap<u64, Instances> = Default::default();

for mesh in meshes {
mesh_instances
let instances = mesh_instances
.entry(mesh.mesh_id)
.or_default()
.push(Instance {
geometry_transform: mint::ColumnMatrix4::from(mesh.world_from_mesh).into(),
.or_insert_with(|| Instances {
translations: vec![],
..Default::default()
});

let (scale, rotation, translation) = mesh.world_from_mesh.to_scale_rotation_translation();
instances
.translations
.push(mint::Vector3::from(translation).into());
instances
.rotations
.get_or_insert_with(Default::default)
.push(mint::Quaternion::from(rotation).into());
instances
.scales
.get_or_insert_with(Default::default)
.push(mint::Vector3::from(scale).into());

rendering
.mesh_cache
.load(three_d, mesh.mesh_id, &mesh.name, &mesh.mesh_data);
}

for (mesh_id, instances) in &mesh_instances {
rendering
.mesh_cache
.set_instances(*mesh_id, render_states, instances)?;
rendering.mesh_cache.set_instances(*mesh_id, instances)?;
}

let mut objects: Vec<&dyn Object> = vec![];
Expand All @@ -343,24 +344,15 @@ pub fn paint_with_three_d(
}
}

for obj in allocate_points(
&rendering.three_d,
&rendering.sphere_mesh,
&mut rendering.points_cache,
render_states,
points,
) {
objects.push(obj);
}
for obj in allocate_line_segments(
&rendering.three_d,
&rendering.line_mesh,
&mut rendering.lines_cache,
render_states,
line_segments,
) {
objects.push(obj);
}
rendering
.points_cache
.set_instances(&allocate_points(points))?;
objects.push(&rendering.points_cache);

rendering
.lines_cache
.set_instances(&allocate_line_segments(line_segments))?;
objects.push(&rendering.lines_cache);

crate::profile_scope!("render_pass");
render_pass(&camera, &objects, lights)?;
Expand Down

0 comments on commit d5eac9b

Please sign in to comment.