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

Fix timestep, teleportation, and add model loading checks #66

Merged
merged 5 commits into from
Dec 17, 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
2 changes: 1 addition & 1 deletion blade-render/code/fill-gbuf.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let n_xy = textureSampleLevel(textures[entry.normal_texture], sampler_linear, tex_coords, lod).xy;
normal_local = vec3<f32>(n_xy, sqrt(max(0.0, 1.0 - dot(n_xy.xy, n_xy.xy))));
}
let normal = qrot(geo_to_world_rot, tangent_space_geo * normal_local);
var normal = qrot(geo_to_world_rot, tangent_space_geo * normal_local);
basis = shortest_arc_quat(vec3<f32>(0.0, 0.0, 1.0), normalize(normal));

let hit_position = camera.position + intersection.t * ray_dir;
Expand Down
24 changes: 20 additions & 4 deletions blade-render/src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
borrow::Cow,
collections::hash_map::{Entry, HashMap},

Check warning on line 3 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

unused imports: `Entry`, `HashMap`

Check warning on line 3 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

unused imports: `Entry`, `HashMap`

Check warning on line 3 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

unused imports: `Entry`, `HashMap`
fmt, hash, mem,
ops::Range,
ptr, str,
Expand All @@ -27,7 +27,9 @@
}

fn encode_normal(v: [f32; 3]) -> u32 {
pack4x8snorm([v[0], v[1], v[2], 0.0])
let raw = pack4x8snorm([v[0], v[1], v[2], 0.0]);
assert_ne!(raw, 0, "Zero normal detected");
raw
}

pub struct Geometry {
Expand Down Expand Up @@ -84,13 +86,23 @@
material_index: u32,
}

#[derive(Clone, Default, PartialEq)]
#[derive(Clone, PartialEq)]
struct GltfVertex {
position: [f32; 3],
normal: [f32; 3],
tangent: [f32; 4],
tex_coords: [f32; 2],
}
impl Default for GltfVertex {
fn default() -> Self {
Self {
position: [0.0; 3],
normal: [0.0, 1.0, 0.0],
tangent: [1.0, 0.0, 0.0, 0.0],
tex_coords: [0.0; 2],
}
}
}
impl Eq for GltfVertex {}
impl hash::Hash for GltfVertex {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Expand Down Expand Up @@ -144,12 +156,13 @@
Entry::Occupied(e) => *e.get(),
Entry::Vacant(e) => {
let i = vertices.len() as u32;
let t = &v.tangent;
vertices.push(crate::Vertex {
position: v.position,
bitangent_sign: v.tangent[3],
bitangent_sign: t[3],
tex_coords: v.tex_coords,
normal: encode_normal(v.normal),
tangent: encode_normal([v.tangent[0], v.tangent[1], v.tangent[2]]),
tangent: encode_normal([t[0], t[1], t[2]]),
});
*e.insert(i)
}
Expand Down Expand Up @@ -225,6 +238,9 @@
.iter_mut()
.zip(reader.read_positions().unwrap())
{
for component in pos {
assert!(component.is_finite());
}
v.position = pos;
}
if let Some(iter) = reader.read_tex_coords(0) {
Expand Down Expand Up @@ -470,11 +486,11 @@

fn cook(
&self,
source: &[u8],

Check warning on line 489 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `source`

Check warning on line 489 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

unused variable: `source`

Check warning on line 489 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

unused variable: `source`
extension: &str,
meta: Meta,

Check warning on line 491 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `meta`

Check warning on line 491 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

unused variable: `meta`

Check warning on line 491 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

unused variable: `meta`
cooker: Arc<blade_asset::Cooker<Self>>,

Check warning on line 492 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `cooker`

Check warning on line 492 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

unused variable: `cooker`

Check warning on line 492 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

unused variable: `cooker`
exe_context: &choir::ExecutionContext,

Check warning on line 493 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

unused variable: `exe_context`

Check warning on line 493 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

unused variable: `exe_context`

Check warning on line 493 in blade-render/src/model/mod.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

unused variable: `exe_context`
) {
match extension {
#[cfg(feature = "asset")]
Expand Down
32 changes: 19 additions & 13 deletions examples/scene/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,13 +678,19 @@
);
});
ui.horizontal(|ui| {
let tc = &selection.tex_coords;
ui.label("Texture coords:");
ui.colored_label(
egui::Color32::WHITE,
format!(
"{:.2} {:.2}",
selection.tex_coords.x, selection.tex_coords.y
),
format!("{:.2} {:.2}", tc.x, tc.y),
);
});
ui.horizontal(|ui| {
let wp = &selection.position;
ui.label("World pos:");
ui.colored_label(
egui::Color32::WHITE,
format!("{:.2} {:.2} {:.2}", wp.x, wp.y, wp.z),
);
});
ui.horizontal(|ui| {
Expand Down Expand Up @@ -1035,7 +1041,7 @@
example.load_scene(Path::new(&path_to_scene));

struct Drag {
screen_pos: glam::IVec2,

Check warning on line 1044 in examples/scene/main.rs

View workflow job for this annotation

GitHub Actions / build (Linux, ubuntu-latest, x86_64-unknown-linux-gnu)

field `screen_pos` is never read

Check warning on line 1044 in examples/scene/main.rs

View workflow job for this annotation

GitHub Actions / build (Windows, windows-latest, x86_64-pc-windows-msvc)

field `screen_pos` is never read

Check warning on line 1044 in examples/scene/main.rs

View workflow job for this annotation

GitHub Actions / build (MacOS, macos-latest, x86_64-apple-darwin)

field `screen_pos` is never read
rotation: glam::Quat,
}
let mut drag_start = None::<Drag>;
Expand Down Expand Up @@ -1141,18 +1147,18 @@
example.is_point_selected = false;
}
winit::event::WindowEvent::CursorMoved { position, .. } => {
last_mouse_pos = [position.x as i32, position.y as i32];
if let Some(ref mut drag) = drag_start {
// This is rotation around the world UP, which is assumed to be Y
let qx = glam::Quat::from_rotation_y(
(drag.screen_pos.x - last_mouse_pos[0]) as f32 * rotate_speed,
if let Some(_) = drag_start {
let prev = glam::Quat::from(example.camera.rot);
let rotation = glam::Quat::from_euler(
glam::EulerRot::ZYX,
0.0,
(last_mouse_pos[0] as f32 - position.x as f32) * rotate_speed,
(last_mouse_pos[1] as f32 - position.y as f32) * rotate_speed,
);
let qy = glam::Quat::from_rotation_x(
(drag.screen_pos.y - last_mouse_pos[1]) as f32 * rotate_speed,
);
example.camera.rot = (qx * drag.rotation * qy).into();
example.camera.rot = (prev * rotation).into();
example.debug.mouse_pos = None;
}
last_mouse_pos = [position.x as i32, position.y as i32];
}
winit::event::WindowEvent::HoveredFile(_) => {
example.is_file_hovered = true;
Expand Down
6 changes: 6 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,14 @@ pub struct Object {
pub colliders: Vec<Collider>,
}

fn default_time_step() -> f32 {
0.01
}

#[derive(serde::Deserialize)]
pub struct Engine {
pub shader_path: String,
pub data_path: String,
#[serde(default = "default_time_step")]
pub time_step: f32,
}
49 changes: 40 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,12 @@ struct Physics {
gravity: rapier3d::math::Vector<f32>,
pipeline: rapier3d::pipeline::PhysicsPipeline,
debug_pipeline: rapier3d::pipeline::DebugRenderPipeline,
last_time: f32,
}

impl Physics {
fn step(&mut self, dt: f32) {
self.integration_params.dt = dt;
fn step(&mut self) {
let query_pipeline = None;
let physics_hooks = ();
let event_handler = ();
self.pipeline.step(
Expand All @@ -134,10 +135,11 @@ impl Physics {
&mut self.impulse_joints,
&mut self.multibody_joints,
&mut self.solver,
None, // query pipeline
query_pipeline,
&physics_hooks,
&event_handler,
);
self.last_time += self.integration_params.dt;
}
fn render_debug(&mut self) -> Vec<blade_render::DebugLine> {
let mut backend = DebugPhysicsRender::default();
Expand Down Expand Up @@ -197,6 +199,7 @@ pub struct Engine {
workers: Vec<choir::WorkerHandle>,
choir: Arc<choir::Choir>,
data_path: String,
time_ahead: f32,
}

impl ops::Index<JointHandle> for Engine {
Expand Down Expand Up @@ -290,6 +293,7 @@ impl Engine {
let gui_painter = blade_egui::GuiPainter::new(surface_format, &gpu_context);
let mut physics = Physics::default();
physics.debug_pipeline.mode = rapier3d::pipeline::DebugRenderMode::empty();
physics.integration_params.dt = config.time_step;

Self {
pacer,
Expand Down Expand Up @@ -328,6 +332,7 @@ impl Engine {
workers,
choir,
data_path: config.data_path.clone(),
time_ahead: 0.0,
}
}

Expand All @@ -342,7 +347,11 @@ impl Engine {
#[profiling::function]
pub fn update(&mut self, dt: f32) {
self.choir.check_panic();
self.physics.step(dt);
self.time_ahead += dt;
while self.time_ahead >= self.physics.integration_params.dt {
self.physics.step();
self.time_ahead -= self.physics.integration_params.dt;
}
}

#[profiling::function]
Expand Down Expand Up @@ -396,7 +405,8 @@ impl Engine {
.rigid_bodies
.get(object.rigid_body)
.unwrap()
.position();
.predict_position_using_velocity_and_forces(self.time_ahead);

for visual in object.visuals.iter() {
let mc = (isometry * visual.similarity).to_homogeneous().transpose();
let mp = (object.prev_isometry * visual.similarity)
Expand All @@ -416,7 +426,7 @@ impl Engine {
model: visual.model,
});
}
object.prev_isometry = *isometry;
object.prev_isometry = isometry;
}

// Rebuilding every frame
Expand Down Expand Up @@ -646,7 +656,7 @@ impl Engine {

let mut colliders = Vec::new();
for cc in config.colliders.iter() {
use rapier3d::geometry::ColliderBuilder;
use rapier3d::geometry::{ColliderBuilder, TriMeshFlags};

let isometry = nalgebra::geometry::Isometry3::from_parts(
nalgebra::Vector3::from(cc.pos).into(),
Expand Down Expand Up @@ -692,7 +702,12 @@ impl Engine {
.expect("Unable to build convex mesh")
} else {
assert_eq!(border_radius, 0.0);
ColliderBuilder::trimesh(trimesh.points, trimesh.triangles)
let flags = TriMeshFlags::empty();
ColliderBuilder::trimesh_with_flags(
trimesh.points,
trimesh.triangles,
flags,
)
}
}
};
Expand Down Expand Up @@ -748,7 +763,15 @@ impl Engine {
}
}

pub fn get_object_isometry(&self, handle: ObjectHandle) -> &nalgebra::Isometry3<f32> {
pub fn get_object_isometry(&self, handle: ObjectHandle) -> nalgebra::Isometry3<f32> {
let object = &self.objects[handle.0];
let body = &self.physics.rigid_bodies[object.rigid_body];
body.predict_position_using_velocity_and_forces(self.time_ahead)
}

/// Returns the position of the object within the "time_step" of precision.
/// Faster than the main `get_object_isometry`.
pub fn get_object_isometry_approx(&self, handle: ObjectHandle) -> &nalgebra::Isometry3<f32> {
let object = &self.objects[handle.0];
let body = &self.physics.rigid_bodies[object.rigid_body];
body.position()
Expand All @@ -760,6 +783,14 @@ impl Engine {
body.apply_impulse(impulse, false)
}

pub fn teleport_object(&mut self, handle: ObjectHandle, isometry: nalgebra::Isometry3<f32>) {
let object = &self.objects[handle.0];
let body = &mut self.physics.rigid_bodies[object.rigid_body];
body.set_linvel(Default::default(), false);
body.set_angvel(Default::default(), false);
body.set_position(isometry, true);
}

pub fn set_environment_map(&mut self, path: &str) {
if path.is_empty() {
self.environment_map = None;
Expand Down
Loading