Implement PBR
This commit is contained in:
parent
f34a9b01a0
commit
3503fc15d2
14 changed files with 659 additions and 10 deletions
|
|
@ -14,7 +14,7 @@ use raidillon_core::engine::EngineTrait;
|
|||
use raidillon_core::time;
|
||||
use raidillon_core::time::Time;
|
||||
use crate::render::debug_ui::ImguiBridge;
|
||||
use crate::render::BasicMeshRenderingSystem;
|
||||
use crate::render::PbrMeshRenderingSystem;
|
||||
use crate::GliumAssetManager;
|
||||
|
||||
pub struct GliumPlatform<E: EngineTrait<PlatformCtx = PlatformContext>> {
|
||||
|
|
@ -45,7 +45,7 @@ impl<E: EngineTrait<PlatformCtx = PlatformContext>> Platform<E> for GliumPlatfor
|
|||
let time = time::Time::new(time_cfg);
|
||||
|
||||
// Install rendering systems
|
||||
rendering_system_manager.add::<BasicMeshRenderingSystem>(&display, &window);
|
||||
rendering_system_manager.add::<PbrMeshRenderingSystem>(&display, &window);
|
||||
rendering_system_manager.add::<ImguiBridge>(&display, &window);
|
||||
|
||||
Self {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
mod basic;
|
||||
mod pbr;
|
||||
pub mod debug_ui;
|
||||
|
||||
pub use basic::BasicMeshRenderingSystem;
|
||||
pub use pbr::PbrMeshRenderingSystem;
|
||||
|
|
|
|||
192
glium_platform/src/render/pbr.rs
Normal file
192
glium_platform/src/render/pbr.rs
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
// AI Generated
|
||||
|
||||
use glium::{uniform, Display, Program, Surface};
|
||||
use glium::glutin::surface::WindowSurface;
|
||||
use glium::texture::{RawImage2d, SrgbTexture2d, Texture2d};
|
||||
use glium::uniforms::{MagnifySamplerFilter, MinifySamplerFilter, SamplerWrapFunction};
|
||||
use glam::{Vec3, Vec4, Mat4};
|
||||
use crate::RenderingSystem;
|
||||
use crate::system::RenderingContext;
|
||||
use raidillon_assets::include_shader;
|
||||
pub use raidillon_platform::Camera;
|
||||
use raidillon_ecs::components::{ModelHandle, PointLight};
|
||||
use raidillon_ecs::Transform;
|
||||
use crate::model::Model;
|
||||
|
||||
pub struct PbrMeshRenderingSystem {
|
||||
program: Program,
|
||||
white_srgb: SrgbTexture2d,
|
||||
black_srgb: SrgbTexture2d,
|
||||
white_linear: Texture2d,
|
||||
params: glium::DrawParameters<'static>,
|
||||
}
|
||||
|
||||
impl RenderingSystem for PbrMeshRenderingSystem {
|
||||
fn initialize(display: &Display<WindowSurface>, _window: &glium::winit::window::Window) -> Self {
|
||||
const VERT_SRC: &str = include_shader!("pbr.vert");
|
||||
const FRAG_SRC: &str = include_shader!("pbr.frag");
|
||||
|
||||
let program = Program::from_source(display, VERT_SRC, FRAG_SRC, None).unwrap();
|
||||
|
||||
let white_srgb = {
|
||||
let data = vec![255u8, 255u8, 255u8, 255u8];
|
||||
let raw = RawImage2d::from_raw_rgba(data, (1, 1));
|
||||
SrgbTexture2d::new(display, raw).unwrap()
|
||||
};
|
||||
let black_srgb = {
|
||||
let data = vec![0u8, 0u8, 0u8, 255u8];
|
||||
let raw = RawImage2d::from_raw_rgba(data, (1, 1));
|
||||
SrgbTexture2d::new(display, raw).unwrap()
|
||||
};
|
||||
let white_linear = {
|
||||
let data = vec![255u8, 255u8, 255u8, 255u8];
|
||||
let raw = RawImage2d::from_raw_rgba(data, (1, 1));
|
||||
Texture2d::new(display, raw).unwrap()
|
||||
};
|
||||
|
||||
let params = glium::DrawParameters {
|
||||
depth: glium::Depth {
|
||||
test: glium::draw_parameters::DepthTest::IfLess,
|
||||
write: true,
|
||||
.. Default::default()
|
||||
},
|
||||
.. Default::default()
|
||||
};
|
||||
|
||||
Self {
|
||||
program,
|
||||
white_srgb,
|
||||
black_srgb,
|
||||
white_linear,
|
||||
params,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, ctx: &mut RenderingContext) {
|
||||
// Acquire camera
|
||||
let cam = match ctx.scene.world.query::<&Camera>().iter().next() {
|
||||
Some((_, cam)) => *cam,
|
||||
None => {
|
||||
eprintln!("[renderer] No camera component found. Skipping frame");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let view: Mat4 = cam.view();
|
||||
let projection: Mat4 = cam.projection();
|
||||
|
||||
// Directional light setup
|
||||
let dir_light_dir_world: Vec3 = Vec3::new(-0.5, 3.0, -0.25).normalize();
|
||||
let dir_light_dir_view: Vec3 = (view * Vec4::new(dir_light_dir_world.x, dir_light_dir_world.y, dir_light_dir_world.z, 0.0)).truncate().normalize();
|
||||
let dir_light_color: Vec3 = Vec3::splat(1.0);
|
||||
let dir_light_intensity: f32 = 3.5;
|
||||
|
||||
// Collect point lights
|
||||
const MAX_POINT_LIGHTS: usize = 3;
|
||||
let mut pl_pos = [[0.0f32; 3]; MAX_POINT_LIGHTS];
|
||||
let mut pl_col = [[0.0f32; 3]; MAX_POINT_LIGHTS];
|
||||
let mut pl_int = [0.0f32; MAX_POINT_LIGHTS];
|
||||
let mut pl_range = [0.0f32; MAX_POINT_LIGHTS];
|
||||
let mut pl_count: i32 = 0;
|
||||
|
||||
for (_, (tr, pl)) in ctx.scene.world.query::<(&Transform, &PointLight)>().iter() {
|
||||
if (pl_count as usize) >= MAX_POINT_LIGHTS { break; }
|
||||
let pos_view = (view * Vec4::new(tr.translation.x, tr.translation.y, tr.translation.z, 1.0)).truncate();
|
||||
pl_pos[pl_count as usize] = [pos_view.x, pos_view.y, pos_view.z];
|
||||
pl_col[pl_count as usize] = [pl.color.x, pl.color.y, pl.color.z];
|
||||
pl_int[pl_count as usize] = pl.intensity;
|
||||
pl_range[pl_count as usize] = pl.range;
|
||||
pl_count += 1;
|
||||
}
|
||||
|
||||
let asset_manager = ctx.asset_manager.borrow();
|
||||
|
||||
for (_, (tr, mh)) in ctx.scene.world.query::<(&Transform, &ModelHandle)>().iter() {
|
||||
let model_any = match asset_manager.get_model(&mh.0) { Some(m) => m, _ => continue };
|
||||
let model = match model_any.downcast_ref::<Model>() { Some(m) => m, None => continue };
|
||||
|
||||
let mesh = &model.mesh;
|
||||
let mat = &model.material;
|
||||
|
||||
// Base color texture (sRGB)
|
||||
let base_color_tex: &SrgbTexture2d = mat.base_color.as_ref().unwrap_or(&self.white_srgb);
|
||||
let mut base_sampler = base_color_tex.sampled();
|
||||
base_sampler = base_sampler.wrap_function(SamplerWrapFunction::Repeat);
|
||||
base_sampler = base_sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
base_sampler = base_sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
let has_base_color_map: i32 = if mat.base_color.is_some() { 1 } else { 0 };
|
||||
|
||||
// MR map (linear)
|
||||
let mr_tex: &Texture2d = mat.metallic_roughness.as_ref().unwrap_or(&self.white_linear);
|
||||
let mut mr_sampler = mr_tex.sampled();
|
||||
mr_sampler = mr_sampler.wrap_function(SamplerWrapFunction::Repeat);
|
||||
mr_sampler = mr_sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
mr_sampler = mr_sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
let has_mr_map: i32 = if mat.metallic_roughness.is_some() { 1 } else { 0 };
|
||||
|
||||
// Occlusion map (linear, R)
|
||||
let occlusion_tex: &Texture2d = mat.occlusion.as_ref().unwrap_or(&self.white_linear);
|
||||
let mut occl_sampler = occlusion_tex.sampled();
|
||||
occl_sampler = occl_sampler.wrap_function(SamplerWrapFunction::Repeat);
|
||||
occl_sampler = occl_sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
occl_sampler = occl_sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
let has_occlusion_map: i32 = if mat.occlusion.is_some() { 1 } else { 0 };
|
||||
|
||||
// Emissive map (sRGB)
|
||||
let emissive_tex: &SrgbTexture2d = mat.emissive.as_ref().unwrap_or(&self.black_srgb);
|
||||
let mut emissive_sampler = emissive_tex.sampled();
|
||||
emissive_sampler = emissive_sampler.wrap_function(SamplerWrapFunction::Repeat);
|
||||
emissive_sampler = emissive_sampler.minify_filter(MinifySamplerFilter::Linear);
|
||||
emissive_sampler = emissive_sampler.magnify_filter(MagnifySamplerFilter::Linear);
|
||||
let has_emissive_map: i32 = if mat.emissive.is_some() { 1 } else { 0 };
|
||||
|
||||
let bc = mat.base_color_factor;
|
||||
let ef = mat.emissive_factor;
|
||||
|
||||
let uniforms = uniform! {
|
||||
model: tr.matrix().to_cols_array_2d(),
|
||||
view: view.to_cols_array_2d(),
|
||||
projection: projection.to_cols_array_2d(),
|
||||
uv_offset: [mat.uv_offset.x, mat.uv_offset.y],
|
||||
uv_scale: [mat.uv_scale.x, mat.uv_scale.y],
|
||||
|
||||
// Material
|
||||
u_base_color_map: base_sampler,
|
||||
u_has_base_color_map: has_base_color_map,
|
||||
u_base_color_factor: [bc[0], bc[1], bc[2], bc[3]],
|
||||
|
||||
u_metallic_roughness_map: mr_sampler,
|
||||
u_has_metallic_roughness_map: has_mr_map,
|
||||
u_metallic_factor: mat.metal_factor,
|
||||
u_roughness_factor: mat.roughness_factor,
|
||||
|
||||
u_occlusion_map: occl_sampler,
|
||||
u_has_occlusion_map: has_occlusion_map,
|
||||
|
||||
u_emissive_map: emissive_sampler,
|
||||
u_has_emissive_map: has_emissive_map,
|
||||
u_emissive_factor: [ef[0], ef[1], ef[2]],
|
||||
|
||||
// Directional light (view-space)
|
||||
u_dir_light_dir: [dir_light_dir_view.x, dir_light_dir_view.y, dir_light_dir_view.z],
|
||||
u_dir_light_color: [dir_light_color.x, dir_light_color.y, dir_light_color.z],
|
||||
u_dir_light_intensity: dir_light_intensity,
|
||||
|
||||
// Point lights (view-space)
|
||||
u_point_light_count: pl_count,
|
||||
u_point_light_pos: pl_pos,
|
||||
u_point_light_color: pl_col,
|
||||
u_point_light_intensity: pl_int,
|
||||
u_point_light_range: pl_range,
|
||||
};
|
||||
|
||||
ctx.target.draw(
|
||||
&mesh.vbuf,
|
||||
&mesh.ibuf,
|
||||
&self.program,
|
||||
&uniforms,
|
||||
&self.params,
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue