looking good
							parent
							
								
									3aeced7c2f
								
							
						
					
					
						commit
						3c2f247167
					
				|  | @ -31,9 +31,33 @@ pub const | |||
| } | ||||
| } | ||||
| 
 | ||||
| #[derive (Default)] | ||||
| struct GameState { | ||||
| 	player: PhysicsBody, | ||||
| 	aabbs: Vec <opengl_rust::physics::Aabb>, | ||||
| } | ||||
| 
 | ||||
| impl Default for GameState { | ||||
| 	fn default () -> Self { | ||||
| 		let player = Default::default (); | ||||
| 		let aabbs = [ | ||||
| 			((-4.0, -4.0, -3.0), (4.0, 4.0, -1.0)), | ||||
| 			((-1.5, 1.0, -1.0), (-0.5, 2.0, 0.0)), | ||||
| 			((-0.5, 1.0, 0.0), (0.5, 2.0, 1.0)), | ||||
| 			((0.5, 1.0, 1.0), (1.5, 2.0, 2.0)), | ||||
| 		].into_iter () | ||||
| 		.map (|(min, max)| { | ||||
| 			opengl_rust::physics::Aabb { | ||||
| 				min: min.into (), | ||||
| 				max: max.into (), | ||||
| 			} | ||||
| 		}) | ||||
| 		.collect (); | ||||
| 		
 | ||||
| 		Self { | ||||
| 			player, | ||||
| 			aabbs, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct GameGraphics { | ||||
|  | @ -70,7 +94,9 @@ impl GameGraphics { | |||
| 		
 | ||||
| 		let screen_size = (1280.0, 720.0); | ||||
| 		
 | ||||
| 		let proj_mat = Mat4::perspective_rh_gl (30.0f32.to_radians (), screen_size.0 / screen_size.1, 0.125, 200.0); | ||||
| 		let fov = 30.0f32; | ||||
| 		
 | ||||
| 		let proj_mat = Mat4::perspective_rh_gl (fov.to_radians (), screen_size.0 / screen_size.1, 0.125, 200.0); | ||||
| 		
 | ||||
| 		let view_mat = proj_mat * 
 | ||||
| 		Mat4::from_translation ((0.0, 0.0, -20.0).into ()) * | ||||
|  | @ -98,10 +124,15 @@ impl GameGraphics { | |||
| 				}); | ||||
| 			} | ||||
| 			
 | ||||
| 			{ | ||||
| 			for aabb in &state.aabbs { | ||||
| 				let min = aabb.min; | ||||
| 				let max = aabb.max; | ||||
| 				let center = (min + max) / 2.0; | ||||
| 				let scale = (max - min) / 2.0; | ||||
| 				
 | ||||
| 				let mvp = view_mat * 
 | ||||
| 				Mat4::from_scale ((4.0, 4.0, 1.0).into ()) * | ||||
| 				Mat4::from_translation ((0.0, 0.0, -2.0).into ()); | ||||
| 				Mat4::from_translation (center) * | ||||
| 				Mat4::from_scale (scale); | ||||
| 				glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp); | ||||
| 				
 | ||||
| 				self.mesh_cube.draw_all (attrs, |_| { | ||||
|  | @ -257,32 +288,14 @@ async fn main () -> Result <()> { | |||
| 		gravity: (0.0, 0.0, -0.25).into (), | ||||
| 		margin: 0.00125, | ||||
| 	}; | ||||
| 	let phys_world: Vec <_> = vec! [ | ||||
| 		( | ||||
| 			(-4.0, -4.0, -1.0), | ||||
| 			(-4.0, 4.0, -1.0), | ||||
| 			(4.0, -4.0, -1.0), | ||||
| 		), | ||||
| 		( | ||||
| 			(4.0, 4.0, -1.0), | ||||
| 			(4.0, -4.0, -1.0), | ||||
| 			(-4.0, 4.0, -1.0), | ||||
| 		), | ||||
| 	].into_iter () | ||||
| 	.map (|(v0, v1, v2)| { | ||||
| 		opengl_rust::physics::Triangle { | ||||
| 			verts: [ | ||||
| 				v0.into (), | ||||
| 				v1.into (), | ||||
| 				v2.into (), | ||||
| 			], | ||||
| 		} | ||||
| 	}) | ||||
| 	.collect (); | ||||
| 	
 | ||||
| 	let player_speed = 2.0; | ||||
| 	let player_jump_speed = 8.0; | ||||
| 	let mut player_jump_vec: Option <Vec3> = None; | ||||
| 	
 | ||||
| 	'running: loop { | ||||
| 		let _frames_to_do = time_step.step (); | ||||
| 		let mut player_wants_to_jump = false; | ||||
| 		
 | ||||
| 		for event in event_pump.poll_iter () { | ||||
| 			match event { | ||||
|  | @ -293,14 +306,25 @@ async fn main () -> Result <()> { | |||
| 				Event::KeyDown { keycode: Some (Keycode::R), .. } => { | ||||
| 					game_state = Default::default (); | ||||
| 				}, | ||||
| 				Event::KeyDown { keycode: Some (Keycode::Space), .. } => { | ||||
| 					player_wants_to_jump = true; | ||||
| 				}, | ||||
| 				
 | ||||
| 				_ => (), | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		let kb_state = event_pump.keyboard_state (); | ||||
| 		game_state.player.vel.x = 0.0; | ||||
| 		game_state.player.vel.y = 0.0; | ||||
| 		
 | ||||
| 		let player_speed = if player_jump_vec.is_some () { | ||||
| 			game_state.player.vel.x = 0.0; | ||||
| 			game_state.player.vel.y = 0.0; | ||||
| 			player_speed | ||||
| 		} | ||||
| 		else { | ||||
| 			0.125 | ||||
| 		}; | ||||
| 		
 | ||||
| 		if kb_state.is_scancode_pressed (Scancode::Left) { | ||||
| 			game_state.player.vel.x -= player_speed; | ||||
| 		} | ||||
|  | @ -314,7 +338,32 @@ async fn main () -> Result <()> { | |||
| 			game_state.player.vel.y -= player_speed; | ||||
| 		} | ||||
| 		
 | ||||
| 		game_state.player = opengl_rust::physics::step (&phys_params, &phys_world, 0.5, &game_state.player).body; | ||||
| 		if player_wants_to_jump { | ||||
| 			if let Some (normal) = player_jump_vec.clone () { | ||||
| 				game_state.player.vel += normal * player_jump_speed; | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		let phys_result = opengl_rust::physics::step (&phys_params, &[], &game_state.aabbs, 0.5, &game_state.player); | ||||
| 		
 | ||||
| 		game_state.player = phys_result.body; | ||||
| 		// tracing::debug! ("player pos: {}", game_state.player.pos);
 | ||||
| 		dbg! (player_jump_vec); | ||||
| 		
 | ||||
| 		player_jump_vec = None; | ||||
| 		for normal in &phys_result.normals_hit { | ||||
| 			player_jump_vec = Some (match player_jump_vec { | ||||
| 				None => *normal, | ||||
| 				Some (old) => { | ||||
| 					if normal.z > old.z { | ||||
| 						*normal | ||||
| 					} | ||||
| 					else { | ||||
| 						old | ||||
| 					} | ||||
| 				}, | ||||
| 			}); | ||||
| 		} | ||||
| 		
 | ||||
| 		window.gl_make_current (&gl_ctx).unwrap (); | ||||
| 		
 | ||||
|  |  | |||
							
								
								
									
										154
									
								
								src/physics.rs
								
								
								
								
							
							
						
						
									
										154
									
								
								src/physics.rs
								
								
								
								
							|  | @ -10,7 +10,7 @@ pub struct PhysicsBody { | |||
| #[derive (Debug, PartialEq)] | ||||
| pub struct PhysicsResult { | ||||
| 	pub body: PhysicsBody, | ||||
| 	pub triangles_hit: Vec <usize>, | ||||
| 	pub normals_hit: Vec <Vec3>, | ||||
| 	pub kill: bool, | ||||
| } | ||||
| 
 | ||||
|  | @ -19,6 +19,12 @@ pub struct Triangle { | |||
| 	pub verts: [Vec3; 3], | ||||
| } | ||||
| 
 | ||||
| #[derive (Copy, Clone)] | ||||
| pub struct Aabb { | ||||
| 	pub min: Vec3, | ||||
| 	pub max: Vec3, | ||||
| } | ||||
| 
 | ||||
| fn vec_min (a: &Vec3, b: &Vec3) -> Vec3 { | ||||
| 	Vec3::from (( | ||||
| 		min (a.x, b.x), | ||||
|  | @ -103,7 +109,8 @@ pub struct Params { | |||
| } | ||||
| 
 | ||||
| pub fn step ( | ||||
| 	params: &Params, world: &[Triangle], 
 | ||||
| 	params: &Params, 
 | ||||
| 	tris: &[Triangle], aabbs: &[Aabb], | ||||
| 	radius: f32, input: &PhysicsBody, 
 | ||||
| ) -> PhysicsResult | ||||
| { | ||||
|  | @ -116,14 +123,14 @@ pub fn step ( | |||
| 	let mut new_vel = input.vel + params.gravity; | ||||
| 	let mut new_pos = old_pos + new_vel * dt * t_remaining; | ||||
| 	
 | ||||
| 	let mut triangles_hit = Vec::new (); | ||||
| 	let mut normals_hit = Vec::new (); | ||||
| 	
 | ||||
| 	// Do 5 iterations of the sub-step, trying to converge on a valid state
 | ||||
| 	for _ in 0..5 { | ||||
| 		let candidate = get_candidate (world, old_pos, new_pos, radius); | ||||
| 		let candidate = get_candidate (tris, aabbs, old_pos, new_pos, radius); | ||||
| 		
 | ||||
| 		if candidate.t <= 1.0 { | ||||
| 			tracing::debug! ("Tri {}, type {:?}", candidate.i, candidate.c_type); | ||||
| 			//tracing::debug! ("Tri {}, type {:?}", candidate.i, candidate.c_type);
 | ||||
| 			t_remaining *= 1.0 - candidate.t; | ||||
| 			let speed_towards_normal = -Vec3::dot (new_vel, candidate.normal); | ||||
| 			
 | ||||
|  | @ -139,7 +146,7 @@ pub fn step ( | |||
| 			// But also compensate for the slide distance it lost
 | ||||
| 			new_pos = push_out_pos + new_vel * dt * t_remaining; | ||||
| 			
 | ||||
| 			triangles_hit.push (candidate.i); | ||||
| 			normals_hit.push (candidate.normal); | ||||
| 		} | ||||
| 		else { | ||||
| 			t_remaining = 0.0; | ||||
|  | @ -153,12 +160,17 @@ pub fn step ( | |||
| 			pos: old_pos, | ||||
| 			vel: new_vel, | ||||
| 		}, | ||||
| 		triangles_hit, | ||||
| 		normals_hit, | ||||
| 		kill: false, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) | ||||
| pub fn get_candidate ( | ||||
| 	tris: &[Triangle], | ||||
| 	aabbs: &[Aabb], | ||||
| 	p0: Vec3, p1: Vec3, 
 | ||||
| 	radius: f32 | ||||
| ) | ||||
| -> Collision | ||||
| { | ||||
| 	let radius3 = Vec3::from (( | ||||
|  | @ -176,12 +188,106 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) | |||
| 		c_type: CollisionType::Face, | ||||
| 	}; | ||||
| 	
 | ||||
| 	for (i, tri) in world.iter ().enumerate () { | ||||
| 		let tri_min = tri.min () - radius3; | ||||
| 		let tri_max = tri.max () + radius3; | ||||
| 	let ray_min = p0.min (p1) - radius3; | ||||
| 	let ray_max = p0.max (p1) + radius3; | ||||
| 	
 | ||||
| 	for b in aabbs { | ||||
| 		if 
 | ||||
| 			ray_max.x < b.min.x || ray_min.x > b.max.x || | ||||
| 			ray_max.y < b.min.y || ray_min.y > b.max.y || | ||||
| 			ray_max.z < b.min.z || ray_min.z > b.max.z | ||||
| 		{ | ||||
| 			// AABB reject
 | ||||
| 			// tracing::trace! ("AABB reject");
 | ||||
| 			continue; | ||||
| 		} | ||||
| 		
 | ||||
| 		let ray_min = p0.min (p1); | ||||
| 		let ray_max = p0.max (p1); | ||||
| 		let verts = [ | ||||
| 			(b.min.x, b.min.y, b.min.z).into (), | ||||
| 			(b.max.x, b.min.y, b.min.z).into (), | ||||
| 			(b.max.x, b.max.y, b.min.z).into (), | ||||
| 			(b.min.x, b.max.y, b.min.z).into (), | ||||
| 			
 | ||||
| 			(b.min.x, b.min.y, b.max.z).into (), | ||||
| 			(b.max.x, b.min.y, b.max.z).into (), | ||||
| 			(b.max.x, b.max.y, b.max.z).into (), | ||||
| 			(b.min.x, b.max.y, b.max.z).into (), | ||||
| 		]; | ||||
| 		
 | ||||
| 		for (a, b, c, d) in [ | ||||
| 			(0, 1, 2, 3), | ||||
| 			(4, 7, 6, 5), | ||||
| 			
 | ||||
| 			(2, 1, 5, 6), | ||||
| 			(3, 2, 6, 7), | ||||
| 			
 | ||||
| 			(0, 3, 7, 4), | ||||
| 			(1, 0, 4, 5), | ||||
| 		] { | ||||
| 			let a = verts [a]; | ||||
| 			let b = verts [b]; | ||||
| 			let c = verts [c]; | ||||
| 			let d = verts [d]; | ||||
| 			
 | ||||
| 			let normal = Vec3::cross (c - b, b - a).normalize (); | ||||
| 			
 | ||||
| 			if let Some (c) = get_candidate_face (&[a, b, c, d], normal, p0, p1, radius) { | ||||
| 				candidate = candidate.take_if_closer (&Collision { | ||||
| 					t: c.t, | ||||
| 					p_impact: c.p_impact, | ||||
| 					normal: c.normal, | ||||
| 					i: 0, | ||||
| 					c_type: CollisionType::Face, | ||||
| 				}); | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		for (a, b) in [ | ||||
| 			(0, 1), | ||||
| 			(1, 2), | ||||
| 			(2, 3), | ||||
| 			(3, 0), | ||||
| 			
 | ||||
| 			(4, 5), | ||||
| 			(5, 6), | ||||
| 			(6, 7), | ||||
| 			(7, 4), | ||||
| 			
 | ||||
| 			(0, 4), | ||||
| 			(1, 5), | ||||
| 			(2, 6), | ||||
| 			(3, 7), | ||||
| 		] { | ||||
| 			let a = verts [a]; | ||||
| 			let b = verts [b]; | ||||
| 			
 | ||||
| 			if let Some (c) = get_candidate_edge (a, b, p0, p1, radius) { | ||||
| 				candidate = candidate.take_if_closer (&Collision { | ||||
| 					t: c.t, | ||||
| 					p_impact: c.p_impact, | ||||
| 					normal: c.normal, | ||||
| 					i: 0, | ||||
| 					c_type: CollisionType::Edge, | ||||
| 				}); | ||||
| 			} | ||||
| 		} | ||||
| 		
 | ||||
| 		for vert in &verts { | ||||
| 			if let Some (c) = get_candidate_vert (*vert, p0, p1, radius) { | ||||
| 				candidate = candidate.take_if_closer (&Collision { | ||||
| 					t: c.t, | ||||
| 					p_impact: c.p_impact, | ||||
| 					normal: c.normal, | ||||
| 					i: 0, | ||||
| 					c_type: CollisionType::Vert, | ||||
| 				}); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	
 | ||||
| 	for (i, tri) in tris.iter ().enumerate () { | ||||
| 		let tri_min = tri.min (); | ||||
| 		let tri_max = tri.max (); | ||||
| 		
 | ||||
| 		if 
 | ||||
| 			ray_max.x < tri_min.x || ray_min.x > tri_max.x || | ||||
|  | @ -198,7 +304,9 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) | |||
| 		// Edge collisions
 | ||||
| 		// Vertex collisions
 | ||||
| 		
 | ||||
| 		if let Some (c) = get_candidate_face (&tri, p0, p1, radius) { | ||||
| 		let normal = Vec3::cross (tri.verts [2] - tri.verts [1], tri.verts [1] - tri.verts [0]).normalize (); | ||||
| 		
 | ||||
| 		if let Some (c) = get_candidate_face (&tri.verts, normal, p0, p1, radius) { | ||||
| 			candidate = candidate.take_if_closer (&Collision { | ||||
| 				t: c.t, | ||||
| 				p_impact: c.p_impact, | ||||
|  | @ -245,7 +353,9 @@ pub fn get_candidate (world: &[Triangle], p0: Vec3, p1: Vec3, radius: f32) | |||
| 	candidate | ||||
| } | ||||
| 
 | ||||
| fn get_candidate_face (tri: &Triangle, p0: Vec3, p1: Vec3, radius: f32) 
 | ||||
| /// Collide a ray with a convex planar face, like a triangle or a rectangle.
 | ||||
| 
 | ||||
| fn get_candidate_face (verts: &[Vec3], normal: Vec3, p0: Vec3, p1: Vec3, radius: f32) 
 | ||||
| -> Option <PrimCollision> 
 | ||||
| { | ||||
| 	let radius3 = Vec3::from (( | ||||
|  | @ -255,13 +365,11 @@ fn get_candidate_face (tri: &Triangle, p0: Vec3, p1: Vec3, radius: f32) | |||
| 	)); | ||||
| 	let v = p1 - p0; | ||||
| 	
 | ||||
| 	let normal = Vec3::cross (tri.verts [2] - tri.verts [1], tri.verts [1] - tri.verts [0]).normalize (); | ||||
| 	
 | ||||
| 	let distance_to_face0 = Vec3::dot (normal, p0 - tri.verts [0]) - radius; | ||||
| 	let distance_to_face1 = Vec3::dot (normal, p1 - tri.verts [0]) - radius; | ||||
| 	let distance_to_face0 = Vec3::dot (normal, p0 - verts [0]) - radius; | ||||
| 	let distance_to_face1 = Vec3::dot (normal, p1 - verts [0]) - radius; | ||||
| 	
 | ||||
| 	if distance_to_face0 < 0.0 || distance_to_face1 > 0.0 { | ||||
| 		tracing::trace! ("passed_plane {} {}", distance_to_face0, distance_to_face1); | ||||
| 		// tracing::trace! ("passed_plane {} {}", distance_to_face0, distance_to_face1);
 | ||||
| 		return None; | ||||
| 	} | ||||
| 	
 | ||||
|  | @ -272,9 +380,9 @@ fn get_candidate_face (tri: &Triangle, p0: Vec3, p1: Vec3, radius: f32) | |||
| 	
 | ||||
| 	let p_impact_times_denom = p0 * (denom - t_times_denom) + p1 * (t_times_denom); | ||||
| 	
 | ||||
| 	for j in 0..3 { | ||||
| 		let a = tri.verts [j]; | ||||
| 		let b = tri.verts [(j + 1) % 3]; | ||||
| 	for j in 0..verts.len () { | ||||
| 		let a = verts [j]; | ||||
| 		let b = verts [(j + 1) % verts.len ()]; | ||||
| 		let tangent = Vec3::cross (b - a, normal); | ||||
| 		
 | ||||
| 		if Vec3::dot (tangent, p_impact_times_denom - a * denom) < 0.0 { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_