Wow, ECS is really amazing for this kind of work. Physics are attached to renderable entities and render as expected!
This commit is contained in:
10
resources/ball.mtl
Normal file
10
resources/ball.mtl
Normal file
@@ -0,0 +1,10 @@
|
||||
# Blender MTL File: 'None'
|
||||
# Material Count: 1
|
||||
|
||||
newmtl None
|
||||
Ns 0
|
||||
Ka 0.000000 0.000000 0.000000
|
||||
Kd 0.8 0.8 0.8
|
||||
Ks 0.8 0.8 0.8
|
||||
d 1
|
||||
illum 2
|
||||
1991
resources/ball.obj
Normal file
1991
resources/ball.obj
Normal file
File diff suppressed because it is too large
Load Diff
250
src/main.rs
250
src/main.rs
@@ -1,4 +1,3 @@
|
||||
|
||||
extern crate tobj;
|
||||
extern crate winit;
|
||||
|
||||
@@ -9,26 +8,32 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use bytemuck::__core::ops::Range;
|
||||
use cgmath::{Decomposed, Deg, InnerSpace, Quaternion, Rotation3, SquareMatrix};
|
||||
use cgmath::{Decomposed, Deg, Euler, InnerSpace, Quaternion, Rotation3, SquareMatrix};
|
||||
use futures::task::LocalSpawn;
|
||||
use legion::*;
|
||||
use rapier3d::dynamics::{
|
||||
IntegrationParameters, JointSet, RigidBody, RigidBodyBuilder, RigidBodyHandle, RigidBodySet,
|
||||
};
|
||||
use rapier3d::geometry::Collider as r3dCollider;
|
||||
use rapier3d::geometry::{BroadPhase, ColliderBuilder, ColliderHandle, ColliderSet, NarrowPhase};
|
||||
use rapier3d::math;
|
||||
use rapier3d::na::{Isometry, Isometry3, Vector, Vector3};
|
||||
use rapier3d::pipeline::PhysicsPipeline;
|
||||
use wgpu::{BindGroup, Buffer, TextureView};
|
||||
use wgpu_subscriber;
|
||||
use winit::event::DeviceEvent::MouseMotion;
|
||||
use winit::platform::unix::x11::ffi::Time;
|
||||
use winit::{
|
||||
event::{self, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
};
|
||||
use winit::event::DeviceEvent::MouseMotion;
|
||||
use winit::platform::unix::x11::ffi::Time;
|
||||
use rapier3d::math;
|
||||
|
||||
use crate::physics::PhysicsState;
|
||||
use crate::render::Renderer;
|
||||
use rapier3d::pipeline::PhysicsPipeline;
|
||||
use rapier3d::dynamics::{IntegrationParameters, RigidBodySet, JointSet, RigidBodyBuilder};
|
||||
use rapier3d::geometry::{BroadPhase, NarrowPhase, ColliderSet, ColliderBuilder};
|
||||
use rapier3d::na::{Isometry, Isometry3, Vector, Vector3};
|
||||
|
||||
mod geometry;
|
||||
mod light;
|
||||
mod physics;
|
||||
mod render;
|
||||
|
||||
/*
|
||||
@@ -75,7 +80,8 @@ pub struct Position {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
mx: cgmath::Matrix4<f32>,
|
||||
rot: cgmath::Quaternion<f32>,
|
||||
//mx: cgmath::Matrix4<f32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
@@ -116,6 +122,17 @@ pub struct Mesh {
|
||||
bind_group: Arc<BindGroup>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Physics {
|
||||
rigid_body: RigidBody,
|
||||
rigid_body_handle: Option<RigidBodyHandle>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Collider {
|
||||
collider: r3dCollider,
|
||||
collider_handle: Option<ColliderHandle>,
|
||||
}
|
||||
//log::info!("");
|
||||
|
||||
fn main() {
|
||||
@@ -133,6 +150,11 @@ fn main() {
|
||||
.build();
|
||||
|
||||
// TODO schedule for the update system and others
|
||||
let mut update_schedule = Schedule::builder()
|
||||
.add_system(physics::run_physics_system())
|
||||
.add_system(physics::update_models_system())
|
||||
// next system here, gamelogic update system?
|
||||
.build();
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let mut builder = winit::window::WindowBuilder::new();
|
||||
@@ -159,6 +181,11 @@ fn main() {
|
||||
let mut resources = Resources::default();
|
||||
resources.insert(renderer);
|
||||
|
||||
let (physics_state, physics_pipeline) =
|
||||
PhysicsState::build(rapier3d::math::Vector::new(0.0, 0.0, -9.81));
|
||||
resources.insert(physics_state);
|
||||
resources.insert(physics_pipeline);
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Artificially slows the loop rate to 10 millis
|
||||
// This is called after redraw events cleared
|
||||
@@ -171,7 +198,7 @@ fn main() {
|
||||
window.request_redraw();
|
||||
last_update_inst = Instant::now();
|
||||
}
|
||||
physics();
|
||||
update_schedule.execute(&mut world, &mut resources);
|
||||
pool.run_until_stalled();
|
||||
}
|
||||
event::Event::DeviceEvent {
|
||||
@@ -227,124 +254,8 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn physics() {
|
||||
|
||||
/* // let mut mechanical_world = DefaultMechanicalWorld::new(Vector3::new(0.0, -9.81, 0.0));
|
||||
// let mut geometrical_world = DefaultGeometricalWorld::new();
|
||||
//
|
||||
// let mut bodies = DefaultBodySet::new();
|
||||
// let mut colliders = DefaultColliderSet::new();
|
||||
// let mut joint_constraints = DefaultJointConstraintSet::new();
|
||||
// let mut force_generators = DefaultForceGeneratorSet::new();
|
||||
//
|
||||
// // Run the simulation.
|
||||
// mechanical_world.step(
|
||||
// &mut geometrical_world,
|
||||
// &mut bodies,
|
||||
// &mut colliders,
|
||||
// &mut joint_constraints,
|
||||
// &mut force_generators
|
||||
// );
|
||||
//
|
||||
// let ground_handle = bodies.insert(Ground::new());
|
||||
// let ground_shape = ShapeHandle::new(Cuboid::new(Vector3::new(3.0, 0.2, 3.0)
|
||||
// ));
|
||||
//
|
||||
// let main_floor = ColliderDesc::new(ground_shape)
|
||||
// .translation(Vector3::y() * -0.2)
|
||||
// .build(BodyPartHandle(ground_handle, 0));
|
||||
// colliders.insert(main_floor);
|
||||
//
|
||||
// // Build the rigid body.
|
||||
// let rb = RigidBodyDesc::new()
|
||||
// .translation(Vector3::new(1.0, 1.0, 1.0))
|
||||
// .build();
|
||||
// let rb_handle = bodies.insert(rb);
|
||||
//
|
||||
// // Build the collider.
|
||||
// let cuboid = ShapeHandle::new(Cuboid::new(Vector3::new(1.0, 1.0, 1.0)));
|
||||
// let co = ColliderDesc::new(cuboid.clone())
|
||||
// .density(1.0)
|
||||
// .build(BodyPartHandle(rb_handle, 0));
|
||||
// colliders.insert(co);
|
||||
//
|
||||
// //testbed.set_body_color(rb_handle, color);
|
||||
//
|
||||
// let rigid_body =
|
||||
// RigidBodyDesc::new()
|
||||
// // The rigid body position. Will override `.translation(...)` and `.rotation(...)`.
|
||||
// .position(Isometry3::new(
|
||||
// Vector3::new(1.0, 2.0, 3.0),
|
||||
// Vector3::y() * PI,
|
||||
// ))
|
||||
// .gravity_enabled(true)
|
||||
// .status(BodyStatus::Dynamic)
|
||||
// .velocity(VelocityN::linear(1.0, 2.0, 3.0))
|
||||
// .linear_damping(10.0)
|
||||
// .angular_damping(5.0)
|
||||
// .max_linear_velocity(10.0)
|
||||
// .max_angular_velocity(1.7)
|
||||
// .mass(1.2)
|
||||
// // Arbitrary user-defined data associated to the rigid body to be built.
|
||||
// .user_data(10)
|
||||
// .build();
|
||||
//
|
||||
// let parent_handle = bodies.insert(rigid_body);
|
||||
//
|
||||
// let shape = ShapeHandle::new(Ball::new(1.5));
|
||||
// let collider = ColliderDesc::new(shape)
|
||||
// .density(1.0)
|
||||
// .translation(Vector3::y() * 5.0)
|
||||
// .build(BodyPartHandle(parent_handle, 0));
|
||||
// let collider_handle = colliders.insert(collider);*/
|
||||
|
||||
// Here the gravity is -9.81 along the y axis.
|
||||
let mut pipeline = PhysicsPipeline::new();
|
||||
let gravity = rapier3d::math::Vector::new(0.0, -9.81, 0.0);
|
||||
let integration_parameters = IntegrationParameters::default();
|
||||
let mut broad_phase = BroadPhase::new();
|
||||
let mut narrow_phase = NarrowPhase::new();
|
||||
let mut bodies = RigidBodySet::new();
|
||||
let mut colliders = ColliderSet::new();
|
||||
let mut joints = JointSet::new();
|
||||
// We ignore contact events for now.
|
||||
let event_handler = ();
|
||||
|
||||
let mut dynamic_ball_body = RigidBodyBuilder::new_dynamic().build();
|
||||
let mut dynamic_ball_body_handle = bodies.insert(dynamic_ball_body);
|
||||
|
||||
let mut static_floor_body = RigidBodyBuilder::new_static().position(Isometry3::new(
|
||||
Vector3::new(1.0, 2.0, 3.0),
|
||||
Vector::y() * PI,
|
||||
)).build();
|
||||
let mut static_floor_body_handle = bodies.insert(static_floor_body);
|
||||
|
||||
|
||||
let ball_collider = ColliderBuilder::ball(0.5).build();
|
||||
let floor_collider = ColliderBuilder::cuboid(0.5, 0.2, 0.1).build();
|
||||
|
||||
let ball_collider_handle = colliders.insert(ball_collider, dynamic_ball_body_handle, &mut bodies);
|
||||
let floor_collider_handle = colliders.insert(floor_collider, dynamic_ball_body_handle, &mut bodies);
|
||||
|
||||
// Run the simulation in the game loop.
|
||||
loop {
|
||||
pipeline.step(
|
||||
&gravity,
|
||||
&integration_parameters,
|
||||
&mut broad_phase,
|
||||
&mut narrow_phase,
|
||||
&mut bodies,
|
||||
&mut colliders,
|
||||
&mut joints,
|
||||
None,
|
||||
None,
|
||||
&event_handler
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
|
||||
let untitled_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj");
|
||||
let monkey_mesh = renderer.load_mesh_to_buffer("./resources/monkey.obj");
|
||||
|
||||
// This could be used for relationships between entities...???
|
||||
let light_entity: Entity = world.push((
|
||||
@@ -372,14 +283,18 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
|
||||
scale: 1.0,
|
||||
};
|
||||
|
||||
let mesh_entity: Entity = world.push((
|
||||
let monkey_entity: Entity = world.push((
|
||||
Position {
|
||||
x: 17.0,
|
||||
y: 15.0,
|
||||
z: 10.0,
|
||||
mx: cgmath::Matrix4::from(transform),
|
||||
x: 1.0,
|
||||
y: 2.0,
|
||||
z: 2.0,
|
||||
rot: Quaternion::from(Euler {
|
||||
x: Deg(90.0),
|
||||
y: Deg(45.0),
|
||||
z: Deg(15.0),
|
||||
}), //mx: cgmath::Matrix4::from(transform),
|
||||
},
|
||||
untitled_mesh,
|
||||
monkey_mesh,
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 0.5,
|
||||
@@ -388,6 +303,29 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
|
||||
},
|
||||
));
|
||||
|
||||
let mut dynamic_ball_body = RigidBodyBuilder::new_dynamic()
|
||||
.position(Isometry3::new(
|
||||
Vector3::new(0.0, 0.0, 5.0),
|
||||
Vector::y() * PI,
|
||||
))
|
||||
.build();
|
||||
|
||||
let mut static_floor_body = RigidBodyBuilder::new_static()
|
||||
.position(Isometry3::new(
|
||||
Vector3::new(0.0, 0.0, 0.0),
|
||||
Vector::y() * PI,
|
||||
))
|
||||
.build();
|
||||
|
||||
let ball_collider = ColliderBuilder::ball(1.5).build();
|
||||
let floor_collider = ColliderBuilder::cuboid(0.5, 0.2, 0.1).build();
|
||||
|
||||
//let mut dynamic_ball_body_handle = bodies.insert(dynamic_ball_body);
|
||||
//let mut static_floor_body_handle = bodies.insert(static_floor_body.clone());
|
||||
|
||||
// let ball_collider_handle = colliders.insert(ball_collider, dynamic_ball_body_handle, &mut bodies);
|
||||
// let floor_collider_handle = colliders.insert(floor_collider, dynamic_ball_body_handle, &mut bodies);
|
||||
|
||||
let plane_mesh = renderer.create_plane(7.0);
|
||||
|
||||
let plane_entity: Entity = world.push((
|
||||
@@ -395,7 +333,11 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0,
|
||||
mx: cgmath::Matrix4::identity(),
|
||||
rot: Quaternion::from(Euler {
|
||||
x: Deg(0.0),
|
||||
y: Deg(0.0),
|
||||
z: Deg(0.0),
|
||||
}),
|
||||
},
|
||||
plane_mesh,
|
||||
Color {
|
||||
@@ -404,5 +346,43 @@ pub fn entity_loading(world: &mut World, renderer: &mut Renderer) {
|
||||
b: 0.5,
|
||||
a: 1.0,
|
||||
},
|
||||
Physics {
|
||||
rigid_body: static_floor_body,
|
||||
rigid_body_handle: None,
|
||||
},
|
||||
Collider {
|
||||
collider: floor_collider,
|
||||
collider_handle: None,
|
||||
},
|
||||
));
|
||||
|
||||
let ball_mesh = renderer.load_mesh_to_buffer("./resources/ball.obj");
|
||||
|
||||
let ball_mesh: Entity = world.push((
|
||||
Position {
|
||||
x: 2.0,
|
||||
y: 2.0,
|
||||
z: 3.0,
|
||||
rot: Quaternion::from(Euler {
|
||||
x: Deg(25.0),
|
||||
y: Deg(45.0),
|
||||
z: Deg(15.0),
|
||||
}),
|
||||
},
|
||||
ball_mesh,
|
||||
Color {
|
||||
r: 1.0,
|
||||
g: 0.5,
|
||||
b: 0.5,
|
||||
a: 1.0,
|
||||
},
|
||||
Physics {
|
||||
rigid_body: dynamic_ball_body,
|
||||
rigid_body_handle: None,
|
||||
},
|
||||
Collider {
|
||||
collider: ball_collider,
|
||||
collider_handle: None,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
113
src/physics.rs
Normal file
113
src/physics.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use legion::world::SubWorld;
|
||||
use legion::IntoQuery;
|
||||
use rapier3d::dynamics::{IntegrationParameters, JointSet, RigidBodySet};
|
||||
use rapier3d::geometry::{BroadPhase, ColliderSet, NarrowPhase};
|
||||
use rapier3d::pipeline::PhysicsPipeline;
|
||||
use legion::*;
|
||||
|
||||
use crate::render::{EntityUniforms, Renderer};
|
||||
use crate::{Collider, Mesh, RigidBody, Physics, Position};
|
||||
use cgmath::Quaternion;
|
||||
|
||||
pub struct PhysicsState {
|
||||
gravity: rapier3d::math::Vector<f32>,
|
||||
integration_parameters: IntegrationParameters,
|
||||
broad_phase: BroadPhase,
|
||||
narrow_phase: NarrowPhase,
|
||||
bodies: RigidBodySet,
|
||||
colliders: ColliderSet,
|
||||
joints: JointSet,
|
||||
}
|
||||
|
||||
impl PhysicsState {
|
||||
pub fn build(gravity: rapier3d::math::Vector<f32>) -> (PhysicsPipeline, PhysicsState) {
|
||||
(
|
||||
PhysicsPipeline::new(),
|
||||
PhysicsState {
|
||||
gravity,
|
||||
integration_parameters: IntegrationParameters::default(),
|
||||
broad_phase: BroadPhase::new(),
|
||||
narrow_phase: NarrowPhase::new(),
|
||||
bodies: RigidBodySet::new(),
|
||||
colliders: ColliderSet::new(),
|
||||
joints: JointSet::new(),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[system]
|
||||
#[write_component(Collider)]
|
||||
#[write_component(Physics)]
|
||||
#[write_component(Mesh)]
|
||||
pub fn run_physics(
|
||||
world: &mut SubWorld,
|
||||
#[resource] physics_state: &mut PhysicsState,
|
||||
#[resource] physics_pipeline: &mut PhysicsPipeline,
|
||||
) {
|
||||
|
||||
// Make sure all the entities we care about are added to the system
|
||||
let mut query = <(&mut Collider, &mut Physics, &mut Mesh)>::query();
|
||||
for (collider, physics, mesh) in query.iter_mut(world) {
|
||||
let rigid_body_handle = match physics.rigid_body_handle {
|
||||
None => {
|
||||
let handle = physics_state.bodies.insert(physics.rigid_body.clone());
|
||||
physics.rigid_body_handle = Some(handle);
|
||||
physics.rigid_body_handle.unwrap()
|
||||
},
|
||||
Some(handle) => handle,
|
||||
};
|
||||
if collider.collider_handle == None {
|
||||
let handle = physics_state.colliders.insert(collider.collider.clone(), rigid_body_handle, &mut physics_state.bodies);
|
||||
collider.collider_handle = Some(handle);
|
||||
}
|
||||
}
|
||||
|
||||
// run the physics step
|
||||
let event_handler = ();
|
||||
physics_pipeline.step(
|
||||
&physics_state.gravity,
|
||||
&physics_state.integration_parameters,
|
||||
&mut physics_state.broad_phase,
|
||||
&mut physics_state.narrow_phase,
|
||||
&mut physics_state.bodies,
|
||||
&mut physics_state.colliders,
|
||||
&mut physics_state.joints,
|
||||
None,
|
||||
None,
|
||||
&event_handler
|
||||
);
|
||||
}
|
||||
|
||||
#[system]
|
||||
#[write_component(Collider)]
|
||||
#[write_component(Physics)]
|
||||
#[write_component(Mesh)]
|
||||
#[write_component(Position)]
|
||||
pub fn update_models(
|
||||
world: &mut SubWorld,
|
||||
#[resource] physics_state: &mut PhysicsState,
|
||||
#[resource] physics_pipeline: &mut PhysicsPipeline,
|
||||
) {
|
||||
|
||||
// Make sure all the entities we care about are added to the system
|
||||
let mut query = <(&mut Collider, &mut Physics, &mut Mesh, &mut Position)>::query();
|
||||
for (collider, physics, mesh, position) in query.iter_mut(world) {
|
||||
let pos = physics_state.bodies.get(physics.rigid_body_handle.unwrap()).unwrap().position();
|
||||
position.x = pos.translation.x;
|
||||
position.y = pos.translation.y;
|
||||
position.z = pos.translation.z;
|
||||
|
||||
position.rot.s = pos.rotation.w;
|
||||
position.rot.v.x = pos.rotation.i;
|
||||
position.rot.v.y = pos.rotation.j;
|
||||
position.rot.v.z = pos.rotation.k;
|
||||
|
||||
// mx.x = pos.rotation.i;
|
||||
// mx.y = pos.rotation.j;
|
||||
// mx.z = pos.rotation.k;
|
||||
// mx.w = pos.rotation.w;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use std::{iter, num::NonZeroU32, ops::Range, rc::Rc};
|
||||
|
||||
use bytemuck::__core::mem;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use cgmath::{Point3, Matrix4, Transform, vec3};
|
||||
use cgmath::{Point3, Matrix4, Transform, vec3, Vector3};
|
||||
use futures::executor::LocalPool;
|
||||
use legion::world::SubWorld;
|
||||
use legion::*;
|
||||
@@ -19,6 +19,7 @@ use winit::window::Window;
|
||||
use crate::geometry::{create_plane, import_mesh, vertex, Vertex};
|
||||
use crate::light::LightRaw;
|
||||
use crate::{Color, DirectionalLight, Mesh, Position, RangeCopy, Velocity, OPENGL_TO_WGPU_MATRIX};
|
||||
use rapier3d::parry::motion::RigidMotionComposition;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -128,8 +129,13 @@ pub fn render_test(world: &mut SubWorld, #[resource] renderer: &mut Renderer) {
|
||||
// let rotation = cgmath::Matrix4::from_angle_x(cgmath::Deg(2.0));
|
||||
// pos.mx = pos.mx * rotation;
|
||||
|
||||
//let p = cgmath::Matrix4::from(pos.rot);
|
||||
let q = cgmath::Matrix4::from_translation(Vector3::new(pos.x, pos.y, pos.z));
|
||||
|
||||
let z = q; // p + q;
|
||||
|
||||
let data = EntityUniforms {
|
||||
model: pos.mx.into(),
|
||||
model: z.into(),
|
||||
color: [
|
||||
color.r as f32,
|
||||
color.g as f32,
|
||||
|
||||
Reference in New Issue
Block a user