2022-02-20 20:40:42 +00:00
|
|
|
use bevy::{
|
|
|
|
prelude::{shape::Icosphere, *},
|
|
|
|
render::mesh::Indices,
|
|
|
|
};
|
2022-03-13 00:06:36 +00:00
|
|
|
use bevy_rapier3d::prelude::*;
|
2022-02-20 20:40:42 +00:00
|
|
|
use hexasphere::shapes::IcoSphere;
|
2022-02-25 21:18:44 +00:00
|
|
|
use noise::{HybridMulti, NoiseFn, SuperSimplex};
|
2022-02-20 20:40:42 +00:00
|
|
|
use wgpu::PrimitiveTopology;
|
2022-01-12 08:18:13 +00:00
|
|
|
|
2022-02-08 21:27:57 +00:00
|
|
|
use crate::Label;
|
2022-01-14 06:05:51 +00:00
|
|
|
|
2022-03-21 23:04:06 +00:00
|
|
|
pub const PLANET_RADIUS: f32 = 6000.0;
|
2022-01-12 08:18:13 +00:00
|
|
|
|
2022-01-14 00:14:08 +00:00
|
|
|
#[derive(Component)]
|
2022-03-02 06:31:44 +00:00
|
|
|
pub struct CyberPlanet;
|
2022-01-14 00:14:08 +00:00
|
|
|
|
2022-03-02 06:31:44 +00:00
|
|
|
fn spawn_planet(
|
2022-01-12 08:18:13 +00:00
|
|
|
mut commands: Commands,
|
|
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
|
|
) {
|
2022-02-25 22:53:00 +00:00
|
|
|
let color = Color::rgb(0.2, 0.1, 0.2);
|
2022-03-13 00:06:36 +00:00
|
|
|
let isphere = Icosphere {
|
2022-02-20 20:40:42 +00:00
|
|
|
radius: PLANET_RADIUS,
|
2022-03-21 23:04:06 +00:00
|
|
|
subdivisions: 88,
|
2022-02-20 20:40:42 +00:00
|
|
|
};
|
|
|
|
|
2022-03-13 00:06:36 +00:00
|
|
|
let (mesh, shape) = gen_planet(isphere);
|
|
|
|
|
|
|
|
let pbody = RigidBodyBundle {
|
|
|
|
body_type: RigidBodyType::Static.into(),
|
2022-03-13 22:54:33 +00:00
|
|
|
ccd: RigidBodyCcd {
|
|
|
|
ccd_enabled: true,
|
|
|
|
ccd_thickness: 0.5,
|
|
|
|
ccd_max_dist: PLANET_RADIUS * 1.05,
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
.into(),
|
2022-03-13 00:06:36 +00:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let pcollide = ColliderBundle {
|
|
|
|
shape: shape.into(),
|
|
|
|
material: ColliderMaterial {
|
|
|
|
friction: 0.05,
|
|
|
|
restitution: 0.00,
|
|
|
|
..Default::default()
|
|
|
|
}
|
|
|
|
.into(),
|
|
|
|
..Default::default()
|
|
|
|
};
|
2022-02-20 20:40:42 +00:00
|
|
|
|
2022-01-12 08:18:13 +00:00
|
|
|
commands
|
|
|
|
.spawn_bundle(PbrBundle {
|
2022-03-13 00:06:36 +00:00
|
|
|
mesh: meshes.add(mesh),
|
2022-01-12 08:18:13 +00:00
|
|
|
material: materials.add(StandardMaterial {
|
2022-02-08 04:28:06 +00:00
|
|
|
base_color: color,
|
2022-02-21 21:08:49 +00:00
|
|
|
metallic: 0.1,
|
2022-02-09 06:27:41 +00:00
|
|
|
perceptual_roughness: 0.3,
|
2022-02-24 01:38:24 +00:00
|
|
|
alpha_mode: AlphaMode::Opaque,
|
2022-01-12 08:18:13 +00:00
|
|
|
..Default::default()
|
|
|
|
}),
|
|
|
|
|
|
|
|
..Default::default()
|
|
|
|
})
|
2022-03-13 00:06:36 +00:00
|
|
|
.insert_bundle(pbody)
|
|
|
|
.insert_bundle(pcollide)
|
2022-03-02 06:31:44 +00:00
|
|
|
.insert(CyberPlanet);
|
2022-01-12 08:18:13 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 22:54:33 +00:00
|
|
|
pub struct CyberPlanetPlugin;
|
|
|
|
impl Plugin for CyberPlanetPlugin {
|
2022-01-14 00:14:08 +00:00
|
|
|
fn build(&self, app: &mut App) {
|
2022-03-13 00:06:36 +00:00
|
|
|
app.add_startup_system(spawn_planet.label(Label::Geometry));
|
2022-01-14 00:14:08 +00:00
|
|
|
}
|
2022-01-12 08:18:13 +00:00
|
|
|
}
|
2022-02-20 20:40:42 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
// utils
|
|
|
|
//---------------------------------------------------------------------
|
|
|
|
|
2022-03-13 00:06:36 +00:00
|
|
|
fn gen_planet(sphere: Icosphere) -> (Mesh, ColliderShape) {
|
2022-02-20 20:40:42 +00:00
|
|
|
// straight-up stolen from Bevy's impl of Mesh from Icosphere, so I can do the
|
|
|
|
// displacement before normals are calculated.
|
|
|
|
let generated = IcoSphere::new(sphere.subdivisions, |point| {
|
|
|
|
let inclination = point.y.acos();
|
|
|
|
let azimuth = point.z.atan2(point.x);
|
|
|
|
|
|
|
|
let norm_inclination = inclination / std::f32::consts::PI;
|
|
|
|
let norm_azimuth = 0.5 - (azimuth / std::f32::consts::TAU);
|
|
|
|
|
|
|
|
[norm_azimuth, norm_inclination]
|
|
|
|
});
|
|
|
|
|
2022-02-25 21:18:44 +00:00
|
|
|
let noise = HybridMulti::<SuperSimplex>::default();
|
2022-02-20 20:40:42 +00:00
|
|
|
|
2022-03-02 04:52:31 +00:00
|
|
|
let noisy_points = generated
|
2022-02-21 21:08:49 +00:00
|
|
|
.raw_points()
|
2022-02-20 20:40:42 +00:00
|
|
|
.iter()
|
|
|
|
.map(|&p| {
|
2022-02-24 01:38:24 +00:00
|
|
|
let disp = noise.get(p.as_dvec3().into()) as f32 * 0.05;
|
2022-03-01 02:18:23 +00:00
|
|
|
let pt = p + (p.normalize() * disp);
|
2022-02-20 20:40:42 +00:00
|
|
|
pt.into()
|
|
|
|
})
|
|
|
|
.collect::<Vec<[f32; 3]>>();
|
|
|
|
|
2022-03-02 04:52:31 +00:00
|
|
|
let points = noisy_points
|
2022-02-21 21:08:49 +00:00
|
|
|
.iter()
|
|
|
|
.map(|&p| (Vec3::from_slice(&p) * sphere.radius).into())
|
|
|
|
.collect::<Vec<[f32; 3]>>();
|
|
|
|
|
2022-02-20 20:40:42 +00:00
|
|
|
let uvs = generated.raw_data().to_owned();
|
|
|
|
|
|
|
|
let mut indices = Vec::with_capacity(generated.indices_per_main_triangle() * 20);
|
|
|
|
|
|
|
|
for i in 0..20 {
|
|
|
|
generated.get_indices(i, &mut indices);
|
|
|
|
}
|
|
|
|
|
2022-03-13 00:06:36 +00:00
|
|
|
let mut idxs = Vec::new();
|
|
|
|
for idx in indices.chunks_exact(3) {
|
|
|
|
idxs.push([idx[0], idx[1], idx[2]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
let shape = ColliderShape::trimesh(points.iter().map(|p| Point::from_slice(p)).collect(), idxs);
|
|
|
|
|
2022-02-20 20:40:42 +00:00
|
|
|
let indices = Indices::U32(indices);
|
|
|
|
|
|
|
|
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList);
|
|
|
|
mesh.set_indices(Some(indices));
|
|
|
|
mesh.set_attribute(Mesh::ATTRIBUTE_POSITION, points);
|
|
|
|
mesh.set_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
|
2022-03-13 00:06:36 +00:00
|
|
|
(mesh, shape)
|
2022-02-20 20:40:42 +00:00
|
|
|
}
|