Skip to content

Commit

Permalink
- add new tests and update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
polymonster committed Jul 13, 2024
1 parent 4c1e366 commit 8c15811
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 60 deletions.
2 changes: 1 addition & 1 deletion hotline-data
160 changes: 102 additions & 58 deletions plugins/ecs_examples/src/omni_shadow_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub fn omni_shadow_map(client: &mut Client<gfx_platform::Device, os_platform::Ap
],
update: systems![
"animate_omni_shadow",
"animate_meshes",
"batch_lights"
],
render_graph: "mesh_lit_omni_shadow_map",
Expand All @@ -32,24 +33,23 @@ pub fn setup_omni_shadow_map(
mut commands: Commands) -> Result<(), hotline_rs::Error> {

let cube_mesh = hotline_rs::primitives::create_cube_mesh(&mut device.0);
let tourus_mesh = hotline_rs::primitives::create_tourus_mesh(&mut device.0, 32);
let helix_mesh = hotline_rs::primitives::create_helix_mesh(&mut device.0, 32, 4);
let tube_mesh = hotline_rs::primitives::create_tube_prism_mesh(&mut device.0, 32, 0, 32, true, true, 1.0, 0.66, 1.0);
let triangle_mesh = hotline_rs::primitives::create_tube_prism_mesh(&mut device.0, 3, 0, 3, false, true, 0.33, 0.66, 1.0);

let dim = 32;
let dim2 = dim / 2;
let tile_size = 10.0;
let height = 100.0;
let spacing = 16.0;
let extent = dim as f32 * tile_size * spacing;
let half_extent = extent / 2.0;
let bounds = 100.0;

let sm = pmfx.get_texture("single_omni_shadow_map").unwrap();

// spot light
let light_pos = vec3f(0.0, height * 0.5, 0.0);
// point light
let light_bounds = bounds * 0.75;
let light_pos = vec3f(light_bounds, light_bounds, 0.0);
let light_radius = 256.0;
commands.spawn((
Position(light_pos),
Velocity(Vec3f::unit_z()),
Colour(vec4f(0.5, 0.25, 0.125, 1.0)),
Colour(vec4f(0.125, 0.5, 0.25, 1.0)),
LightComponent {
light_type: LightType::Point,
radius: light_radius,
Expand All @@ -68,37 +68,88 @@ pub fn setup_omni_shadow_map(
..Default::default()
});

let offset = (tile_size + spacing) * 3.0;
let start = vec3f(-half_extent, height, -half_extent) + vec3f(offset, 0.0, offset);
let mut pos = start;

for y in 0..dim {
pos.x = start.x;
for x in 0..dim {
commands.spawn((
Position(pos),
Scale(vec3f(tile_size, height, tile_size)),
Rotation(Quatf::identity()),
MeshComponent(cube_mesh.clone()),
WorldMatrix(Mat34f::identity())
));

pos.x += tile_size * spacing;
}
let shape_bounds = bounds * 0.6;

pos.z += tile_size * spacing
}
// tourus
let tourus_size = bounds * 0.1;
commands.spawn((
Position(vec3f(shape_bounds * -0.75, shape_bounds * 0.7, -shape_bounds * 0.1)),
Scale(splat3f(tourus_size)),
Rotation(Quatf::identity()),
MeshComponent(tourus_mesh.clone()),
WorldMatrix(Mat34f::identity())
));

// ground plane
let plane_mesh = hotline_rs::primitives::create_plane_mesh(&mut device.0, 1);
// helix
commands.spawn((
Position(vec3f(shape_bounds * -0.3, shape_bounds * -0.6, shape_bounds * 0.8)),
Scale(splat3f(tourus_size * 2.0)),
Rotation(Quatf::identity()),
MeshComponent(helix_mesh.clone()),
WorldMatrix(Mat34f::identity())
));

// tube
commands.spawn((
Position(vec3f(shape_bounds * 1.0, shape_bounds * 0.1, shape_bounds * -1.0)),
Scale(splat3f(tourus_size)),
Rotation(Quatf::identity()),
MeshComponent(tube_mesh.clone()),
WorldMatrix(Mat34f::identity())
));

// tri prsim
commands.spawn((
Position(Vec3f::zero()),
Scale(vec3f(half_extent, 1.0, half_extent)),
Position(vec3f(shape_bounds * 0.123, shape_bounds * -0.6, shape_bounds * -0.8)),
Scale(splat3f(tourus_size * 2.0)),
Rotation(Quatf::identity()),
MeshComponent(plane_mesh.clone()),
MeshComponent(triangle_mesh.clone()),
WorldMatrix(Mat34f::identity())
));

// walls
let thickness = bounds * 0.1;
let face_size = bounds * 2.0;

// -y
commands.spawn((
Position(vec3f(0.0, -bounds, 0.0)),
Scale(vec3f(face_size, thickness, face_size)),
Rotation(Quatf::identity()),
MeshComponent(cube_mesh.clone()),
WorldMatrix(Mat34f::identity()),
Billboard
));

// + y
commands.spawn((
Position(vec3f(0.0, bounds, 0.0)),
Scale(vec3f(face_size, thickness, face_size)),
Rotation(Quatf::identity()),
MeshComponent(cube_mesh.clone()),
WorldMatrix(Mat34f::identity()),
Billboard
));

// -z
commands.spawn((
Position(vec3f(0.0, 0.0, -bounds)),
Scale(vec3f(face_size, face_size, thickness)),
Rotation(Quatf::identity()),
MeshComponent(cube_mesh.clone()),
WorldMatrix(Mat34f::identity()),
Billboard
));

// -x
commands.spawn((
Position(vec3f(-bounds, 0.0, 0.0)),
Scale(vec3f(thickness, face_size, face_size)),
Rotation(Quatf::identity()),
MeshComponent(cube_mesh.clone()),
WorldMatrix(Mat34f::identity()),
Billboard
));

pmfx.update_cubemap_camera_constants("omni_shadow_camera", light_pos, 0.1, light_radius * 2.0);

Expand All @@ -112,35 +163,28 @@ pub fn animate_omni_shadow (
mut pmfx: ResMut<PmfxRes>,
mut light_query: Query<(&mut Position, &mut Velocity, &LightComponent)>) -> Result<(), hotline_rs::Error> {

let dim = 32;
let dim2 = dim / 2;
let tile_size = 10.0;
let spacing = 16.0;

let extent = (tile_size + spacing) * 3.0 * 6.0;
let extent = 60.0;

for (mut position, mut velocity, component) in &mut light_query {

position.0 += velocity.0 * time.delta * 400.0;

if position.z > extent {
velocity.0 = Vec3f::unit_x();
}

if position.x > extent {
velocity.0 = -Vec3f::unit_z();
}

if position.z < -extent {
velocity.0 = -Vec3f::unit_x();
}

if position.x < -extent {
velocity.0 = Vec3f::unit_z();
}
position.0 = vec3f(sin(time.accumulated), cos(time.accumulated), cos(time.accumulated)) * extent;

pmfx.update_cubemap_camera_constants("omni_shadow_camera", position.0, 0.1, component.radius * 2.0);
}

Ok(())
}
}

#[no_mangle]
#[export_update_fn]
pub fn animate_meshes (
time: Res<TimeRes>,
mut pmfx: ResMut<PmfxRes>,
mut mesh_query: Query<(&mut Rotation, &MeshComponent), Without<Billboard>>) -> Result<(), hotline_rs::Error> {

for (mut rotation, component) in &mut mesh_query {
rotation.0 *= Quat::from_euler_angles(f32::pi() * time.delta, f32::pi() * time.delta, f32::pi() * time.delta);
}

Ok(())
}
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,18 @@ A sample to demonstrate how to configure a single shadow map with a vertex shade

Demonstrates how multiple cubemap faces can be rendered using cubemap cameras and then sampled from to create dynamic environment mapped reflections. A single `pmfx` view is created with the `cubemap` flag set to true, this will automatically create 6 child views for each face of the cubemap.

### Omni Shadow Map

<img src="https://raw.githubusercontent.com/polymonster/polymonster.github.io/master/images/hotline/ecs_examples/omni_shadow_map.png" width="100%"/>

Demonstrates how multiple cubemap faces can be rendered using cubemap cameras and comparison sampled with PCF to create a point light shadow. A single `pmfx` depth only view is created with the `cubemap` flag set to true, this will automatically create 6 child views for each face of the cubemap.

### PBR

<img src="https://raw.githubusercontent.com/polymonster/polymonster.github.io/master/images/hotline/ecs_examples/pbr.png" width="100%"/>

An implementation of physically based rendering with image based lighting. Note that currently the cubemap pre-filtering is just using the mip levels, in time there will be an improved pipeline to properly pre-filter.

## Tests

There are standalone tests and client/plugin tests to test graphics API features. This requires a test runner which has a GPU and is not headless, so I am using my home machine as a self-hosted actions runner. You can run the tests yourself but because of the requirement of a GPU device and plugin loading the tests need to be ran single threaded.
Expand Down
10 changes: 10 additions & 0 deletions tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,4 +766,14 @@ fn shadow_map() -> Result<(), hotline_rs::Error> {
#[test]
fn dynamic_cubemap() -> Result<(), hotline_rs::Error> {
boot_client_ecs_plugin_demo("dynamic_cubemap")
}

#[test]
fn pbr() -> Result<(), hotline_rs::Error> {
boot_client_ecs_plugin_demo("pbr")
}

#[test]
fn omni_shadow_maps() -> Result<(), hotline_rs::Error> {
boot_client_ecs_plugin_demo("omni_shadow_map")
}
12 changes: 11 additions & 1 deletion todo.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// TODO:

// samples
// - omni shadow map

// - clear buffer (uav)
// - buffers in pmfx
// - clear buffers for compute
Expand All @@ -12,8 +12,15 @@
// - area light
// - disney brdf

// platforms
// - integrate macos changes and fixup win32/d3d12
// - test shader compilation with mac changes

// engine
// - reverse depth
// - visibility buffer
// - mesh shader
// - hello triangle (ray tracing)
// - HDR pipeline
// - glft
// - set name on resources
Expand All @@ -31,6 +38,9 @@
// - view menu + saving state
// - imgui not tracked within draw call stats

// build
// - update pmbuild

// DONE:
// x texture formats (BC etc)
// x texture load image from file into pmfx
Expand Down

0 comments on commit 8c15811

Please sign in to comment.