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

feat(primitives): New torus primitive #376

Merged
2 commits merged into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions crates/meshes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod torus;
pub mod capsule;
pub mod cube;
pub mod cuboid;
Expand All @@ -11,6 +12,7 @@ use ambient_std::{
asset_cache::{AssetCache, SyncAssetKey},
mesh::Mesh,
};
pub use torus::*;
pub use capsule::*;
pub use cube::*;
use glam::*;
Expand Down Expand Up @@ -67,6 +69,14 @@ impl SyncAssetKey<Arc<GpuMesh>> for SphereMeshKey {
}
}

#[derive(Debug, Clone, Default)]
pub struct TorusMeshKey(pub TorusMesh);
impl SyncAssetKey<Arc<GpuMesh>> for TorusMeshKey {
fn load(&self, assets: AssetCache) -> Arc<GpuMesh> {
GpuMesh::from_mesh(assets, &Mesh::from(self.0))
}
}

#[derive(Debug, Clone, Default)]
pub struct CapsuleMeshKey(pub CapsuleMesh);
impl SyncAssetKey<Arc<GpuMesh>> for CapsuleMeshKey {
Expand Down
98 changes: 98 additions & 0 deletions crates/meshes/src/torus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use ambient_std::mesh::Mesh;
use glam::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct TorusMesh {
pub inner_radius: f32,
pub outer_radius: f32,
pub slices: u32,
pub loops: u32,
}

impl Default for TorusMesh {
fn default() -> Self {
TorusMesh {
inner_radius: 0.25,
outer_radius: 1.0,
slices: 16,
loops: 16,
}
}
}

impl From<TorusMesh> for Mesh {
fn from(torus: TorusMesh) -> Self {
let TorusMesh {
inner_radius,
outer_radius,
slices,
loops,
} = torus;

let vertex_count = ((slices + 1) * (loops + 1)) as usize;
let mut vertices = Vec::with_capacity(vertex_count);
let mut normals = Vec::with_capacity(vertex_count);
let mut texcoords = Vec::with_capacity(vertex_count);

let ring_factor = std::f32::consts::PI * 2.0 / slices as f32;
let loop_factor = std::f32::consts::PI * 2.0 / loops as f32;

for i in 0..=loops {
let u = i as f32 * loop_factor;
let cos_u = u.cos();
let sin_u = u.sin();

for j in 0..=slices {
let v = j as f32 * ring_factor;
let cos_v = v.cos();
let sin_v = v.sin();

let r = outer_radius + inner_radius * cos_v;
let x = r * cos_u;
let y = r * sin_u;
let z = outer_radius * sin_v / 2.0;

vertices.push(Vec3::new(x, y, z));

let nv = Vec3::new(cos_v * cos_u, cos_v * sin_u, sin_v);
normals.push(nv.normalize());

texcoords.push(Vec2::new(v / ring_factor, 1.0 - u / loop_factor));
}
}

let index_count = (slices * loops * 6) as usize;
let mut indices = Vec::with_capacity(index_count);

for i in 0..loops {
for j in 0..slices {
let a = i * (slices + 1) + j;
let b = a + slices + 1;

indices.push(a as u32);
indices.push(b as u32);
indices.push((a + 1) as u32);

indices.push(b as u32);
indices.push((b + 1) as u32);
indices.push((a + 1) as u32);
}
}

let mut mesh = Mesh {
name: "torus".into(),
positions: Some(vertices),
colors: None,
normals: Some(normals),
tangents: None,
texcoords: vec![texcoords],
joint_indices: None,
joint_weights: None,
indices: Some(indices),
};
mesh.create_tangents();
mesh

}
}
57 changes: 55 additions & 2 deletions crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use ambient_ecs::{components, query, Entity, EntityId, Networked, Store, SystemG
use ambient_element::{Element, ElementComponent, ElementComponentExt, Hooks};
pub use ambient_meshes::UVSphereMesh;
use ambient_meshes::{
CapsuleMesh, CapsuleMeshKey, SphereMeshKey, UnitCubeMeshKey, UnitQuadMeshKey,
CapsuleMesh, CapsuleMeshKey, SphereMeshKey, TorusMesh, TorusMeshKey, UnitCubeMeshKey,
UnitQuadMeshKey,
};
use ambient_renderer::{
color, gpu_primitives_lod, gpu_primitives_mesh, material,
Expand All @@ -24,7 +25,8 @@ use glam::{vec3, Mat4, Quat, Vec3, Vec4};

pub use ambient_ecs::generated::components::core::primitives::{
capsule, capsule_half_height, capsule_latitudes, capsule_longitudes, capsule_radius,
capsule_rings, cube, quad, sphere, sphere_radius, sphere_sectors, sphere_stacks,
capsule_rings, cube, quad, sphere, sphere_radius, sphere_sectors, sphere_stacks, torus,
torus_inner_radius, torus_loops, torus_outer_radius, torus_slices,
};

components!("primitives", {
Expand Down Expand Up @@ -95,6 +97,36 @@ pub fn sphere_data(assets: &AssetCache, sphere: &UVSphereMesh) -> Entity {
.with(world_bounding_sphere(), bound_sphere)
}

pub fn torus_data(assets: &AssetCache, torus: &TorusMesh) -> Entity {
let aabb = AABB {
min: vec3(
-torus.outer_radius - torus.inner_radius,
-torus.outer_radius - torus.inner_radius,
-torus.inner_radius,
),
max: vec3(
torus.outer_radius + torus.inner_radius,
torus.outer_radius + torus.inner_radius,
torus.inner_radius,
),
};
Entity::new()
.with(mesh(), TorusMeshKey(*torus).get(assets))
.with_default(local_to_world())
.with_default(mesh_to_world())
.with_default(translation())
.with(renderer_shader(), cb(get_flat_shader))
.with(material(), FlatMaterialKey::white().get(assets))
.with(primitives(), vec![])
.with_default(gpu_primitives_mesh())
.with_default(gpu_primitives_lod())
.with(color(), Vec4::ONE)
.with(main_scene(), ())
.with(local_bounding_aabb(), aabb)
.with(world_bounding_aabb(), aabb)
.with(world_bounding_sphere(), aabb.to_sphere())
}

This conversation was marked as resolved.
Show resolved Hide resolved
pub fn capsule_data(assets: &AssetCache, capsule: &CapsuleMesh) -> Entity {
let aabb = AABB {
min: vec3(-capsule.radius, -capsule.radius, -capsule.half_height),
Expand Down Expand Up @@ -189,6 +221,27 @@ pub fn systems() -> SystemGroup {
extend(world, id, data);
}
}),
query((
torus_inner_radius().changed(),
torus_outer_radius().changed(),
torus_slices().changed(),
torus_loops().changed(),
))
.incl(torus())
.spawned()
.to_system(|q, world, qs, _| {
for (id, (inner_radius, outer_radius, loops, slices)) in q.collect_cloned(world, qs) {
let mesh = TorusMesh {
inner_radius,
outer_radius,
slices,
loops,
..Default::default()
};
let data = torus_data(world.resource(asset_cache()), &mesh);
extend(world, id, data);
}
}),
],
)
}
Expand Down
Binary file modified guest/rust/examples/basics/primitives/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion guest/rust/examples/basics/primitives/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use ambient_api::{
app::main_scene,
camera::aspect_ratio_from_window,
primitives::{
torus_inner_radius, torus_loops, torus_outer_radius, torus_slices,
capsule_half_height, capsule_latitudes, capsule_longitudes, capsule_radius,
capsule_rings, cube, quad, sphere_radius, sphere_sectors, sphere_stacks,
},
rendering::color,
transform::{lookat_target, scale, translation},
},
concepts::{
make_capsule, make_perspective_infinite_reverse_camera, make_sphere, make_transformable,
make_torus, make_capsule, make_perspective_infinite_reverse_camera, make_sphere, make_transformable,
},
prelude::*,
};
Expand Down Expand Up @@ -75,4 +76,15 @@ pub fn main() {
.with(translation(), vec3(-2.0, 0.0, 0.5))
.with(color(), vec4(1.0, 0.0, 0.25, 1.0))
.spawn();

Entity::new()
.with_merge(make_transformable())
.with_merge(make_torus())
.with(torus_inner_radius(), 0.25)
.with(torus_outer_radius(), 0.5)
.with(torus_slices(), 32)
.with(torus_loops(), 16)
.with(translation(), vec3(0.0, -2.0, 0.5))
.with(color(), vec4(0.0, 1.0, 0.25, 1.0))
.spawn();
}
45 changes: 44 additions & 1 deletion shared_crates/schema/src/schema/primitives.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,38 @@ description = "Set the latitudinal stacks of a `sphere` entity."
default = 18
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::torus"]
type = "Empty"
name = "Torus"
description = """
If attached to an entity alongside the other `torus_*` components, the entity will be converted to a torus primitive.
To easily instantiate a default `torus`, consider using the `torus` concept (e.g. `make_torus`)."""
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::torus_inner_radius"]
type = "F32"
name = "Torus inner radius"
description = "Set the inner radius of a `torus` entity, spanning XY-plane."
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::torus_outer_radius"]
type = "F32"
name = "Torus outer radius"
description = "Set the outer radius of a `torus` entity, spanning XY-plane."
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::torus_loops"]
type = "U32"
name = "Torus loops"
description = "Set the loops of a `torus` entity, spanning XY-plane."
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::torus_slices"]
type = "U32"
name = "Torus slices"
description = "Set the slices of a `torus` entity, spanning XY-plane."
attributes = ["Debuggable", "Networked", "Store"]

[components."core::primitives::capsule"]
type = "Empty"
name = "Capsule"
Expand Down Expand Up @@ -115,4 +147,15 @@ description = "A primitive capsule. Defined as a cylinder capped by hemispheres.
"core::primitives::capsule_half_height" = 0.5
"core::primitives::capsule_rings" = 0
"core::primitives::capsule_latitudes" = 16
"core::primitives::capsule_longitudes" = 32
"core::primitives::capsule_longitudes" = 32

[concepts.torus]
name = "Torus"
description = "A primitive Torus, surface of revolution generated by revolving a circle in three-dimensional space one full revolution."

[concepts.torus.components]
"core::primitives::torus" = {}
"core::primitives::torus_inner_radius" = 0.25
"core::primitives::torus_outer_radius" = 0.35
"core::primitives::torus_slices" = 32
"core::primitives::torus_loops" = 16