lowenware / dotrix

A 3D engine with ECS and Vulkan renderer for Rust developers
https://dotrix.rs
MIT License
292 stars 11 forks source link

Postprocessing #189

Open voxelias opened 1 year ago

voxelias commented 1 year ago

Check two tasks:

  1. dotrix_pbr::EncodeTask -> it provides following output: type Output = gpu::Commands;
  2. dotrix_gpu::SubmitCommands -> it takes gpu::Commands from all tasks, sorts them according to priority and executes. As an output, there will be type Output = FrameOutput that has already the ready frame texture.

The gpu::Commands are important. They cover different rendering parts:

  1. Clear up the frame
  2. Render skybox/skydome
  3. Render terrain
  4. Render all PBR objects
  5. Optional post-processing of the 3D scene
  6. Render overlay (UI)
  7. Optional post-processing that will affect UI too

Each task that provides gpu::Commands also defines their priority:

encoder.finish(self.priority)

Using the priority you can affect the order of commands.

In other words, post-processing could be just a new task, that will encode appropriate commands with selected effects.

pub struct PlayerDrunkEffect {
    post_processing: PostProcessing,
}

impl PlayerDrunkEffect {
  pub fn new(render_priority: u32) -> Self {
    Self {
      post_processing: PostProcessing { 
        render_priority,
         ...configure the drunk effect
      }
    }
  }
}

impl dotrix::Task for UiTask {
    type Context = (dotrix::Any<dotrix::Gpu>, dotrix::Any<dotrix::Frame>);
    type Output = gpu::Commands;
    fn run(&mut self, (gpu, frame): Self::Context) -> Self::Output {
      self.post_processing.encode(gpu, frame)
    }
}

The only technical complication that is left to solve is double frame buffer. Current frame texture is stored in dotrix_gpu::Gpu::frame_texture. We will need to solve where we render what and when and which one we display in the end :)