mirror of
https://codeberg.org/icewind/vbspview.git
synced 2026-06-03 18:24:09 +02:00
add lighting, debug ui and controlls from example
This commit is contained in:
parent
85da71634d
commit
3f651944b6
1 changed files with 210 additions and 20 deletions
226
src/main.rs
226
src/main.rs
|
|
@ -18,6 +18,12 @@ enum Error {
|
||||||
Other(&'static str),
|
Other(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
enum Pipeline {
|
||||||
|
Forward,
|
||||||
|
Deferred,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
miette::set_panic_hook();
|
miette::set_panic_hook();
|
||||||
|
|
||||||
|
|
@ -43,40 +49,223 @@ fn main() -> Result<(), Error> {
|
||||||
|
|
||||||
let context = window.gl().unwrap();
|
let context = window.gl().unwrap();
|
||||||
|
|
||||||
|
let mut cpu_mesh = model_to_mesh(world_model);
|
||||||
|
cpu_mesh.compute_normals();
|
||||||
|
let forward_pipeline = ForwardPipeline::new(&context).unwrap();
|
||||||
|
let mut deferred_pipeline = DeferredPipeline::new(&context).unwrap();
|
||||||
let mut camera = Camera::new_perspective(
|
let mut camera = Camera::new_perspective(
|
||||||
&context,
|
&context,
|
||||||
window.viewport().unwrap(),
|
window.viewport().unwrap(),
|
||||||
vec3(0.0, 0.0, 2.0),
|
vec3(2.0, 2.0, 5.0),
|
||||||
vec3(0.0, 0.0, 0.0),
|
vec3(0.0, 0.0, 0.0),
|
||||||
vec3(0.0, 1.0, 0.0),
|
vec3(0.0, 1.0, 0.0),
|
||||||
degrees(45.0),
|
degrees(45.0),
|
||||||
0.1,
|
0.1,
|
||||||
10.0,
|
30.0,
|
||||||
)?;
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut control = OrbitControl::new(*camera.target(), 1.0, 100.0);
|
||||||
|
let mut gui = three_d::GUI::new(&context).unwrap();
|
||||||
|
|
||||||
let cpu_mesh = model_to_mesh(world_model);
|
let material = PhysicalMaterial {
|
||||||
|
albedo: Color {
|
||||||
|
r: 128,
|
||||||
|
g: 128,
|
||||||
|
b: 128,
|
||||||
|
a: 255,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
// Construct a model, with a default color material, thereby transferring the mesh data to the GPU
|
let model = Model::new_with_material(&context, &cpu_mesh, material)?;
|
||||||
let mut model = Model::new(&context, &cpu_mesh)?;
|
|
||||||
|
|
||||||
// Start the main render loop
|
let mut lights = Lights {
|
||||||
window.render_loop(move |frame_input: FrameInput| // Begin a new frame with an updated frame input
|
ambient: Some(AmbientLight {
|
||||||
|
color: Color::WHITE,
|
||||||
|
intensity: 0.2,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
directional: vec![DirectionalLight::new(
|
||||||
|
&context,
|
||||||
|
1.0,
|
||||||
|
Color::WHITE,
|
||||||
|
&vec3(0.0, -1.0, 0.0),
|
||||||
|
)
|
||||||
|
.unwrap()],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// main loop
|
||||||
|
let mut shadows_enabled = true;
|
||||||
|
let mut directional_intensity = lights.directional[0].intensity();
|
||||||
|
|
||||||
|
let mut current_pipeline = Pipeline::Forward;
|
||||||
|
|
||||||
|
window.render_loop(move |mut frame_input| {
|
||||||
|
let mut change = frame_input.first_frame;
|
||||||
|
let mut panel_width = frame_input.viewport.width;
|
||||||
|
change |= gui
|
||||||
|
.update(&mut frame_input, |gui_context| {
|
||||||
|
use three_d::egui::*;
|
||||||
|
SidePanel::left("side_panel").show(gui_context, |ui| {
|
||||||
|
ui.heading("Debug Panel");
|
||||||
|
|
||||||
|
ui.label("Light options");
|
||||||
|
ui.add(
|
||||||
|
Slider::new(&mut lights.ambient.as_mut().unwrap().intensity, 0.0..=1.0)
|
||||||
|
.text("Ambient intensity"),
|
||||||
|
);
|
||||||
|
ui.add(
|
||||||
|
Slider::new(&mut directional_intensity, 0.0..=1.0)
|
||||||
|
.text("Directional intensity"),
|
||||||
|
);
|
||||||
|
lights.directional[0].set_intensity(directional_intensity);
|
||||||
|
if ui.checkbox(&mut shadows_enabled, "Shadows").clicked() {
|
||||||
|
if !shadows_enabled {
|
||||||
|
lights.directional[0].clear_shadow_map();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.label("Lighting model");
|
||||||
|
ui.radio_value(&mut lights.lighting_model, LightingModel::Phong, "Phong");
|
||||||
|
ui.radio_value(&mut lights.lighting_model, LightingModel::Blinn, "Blinn");
|
||||||
|
ui.radio_value(
|
||||||
|
&mut lights.lighting_model,
|
||||||
|
LightingModel::Cook(
|
||||||
|
NormalDistributionFunction::Blinn,
|
||||||
|
GeometryFunction::SmithSchlickGGX,
|
||||||
|
),
|
||||||
|
"Cook (Blinn)",
|
||||||
|
);
|
||||||
|
ui.radio_value(
|
||||||
|
&mut lights.lighting_model,
|
||||||
|
LightingModel::Cook(
|
||||||
|
NormalDistributionFunction::Beckmann,
|
||||||
|
GeometryFunction::SmithSchlickGGX,
|
||||||
|
),
|
||||||
|
"Cook (Beckmann)",
|
||||||
|
);
|
||||||
|
ui.radio_value(
|
||||||
|
&mut lights.lighting_model,
|
||||||
|
LightingModel::Cook(
|
||||||
|
NormalDistributionFunction::TrowbridgeReitzGGX,
|
||||||
|
GeometryFunction::SmithSchlickGGX,
|
||||||
|
),
|
||||||
|
"Cook (Trowbridge-Reitz GGX)",
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.label("Pipeline");
|
||||||
|
ui.radio_value(&mut current_pipeline, Pipeline::Forward, "Forward");
|
||||||
|
ui.radio_value(&mut current_pipeline, Pipeline::Deferred, "Deferred");
|
||||||
|
ui.label("Debug options");
|
||||||
|
ui.radio_value(&mut deferred_pipeline.debug_type, DebugType::NONE, "None");
|
||||||
|
ui.radio_value(
|
||||||
|
&mut deferred_pipeline.debug_type,
|
||||||
|
DebugType::POSITION,
|
||||||
|
"Position",
|
||||||
|
);
|
||||||
|
ui.radio_value(
|
||||||
|
&mut deferred_pipeline.debug_type,
|
||||||
|
DebugType::NORMAL,
|
||||||
|
"Normal",
|
||||||
|
);
|
||||||
|
ui.radio_value(&mut deferred_pipeline.debug_type, DebugType::COLOR, "Color");
|
||||||
|
ui.radio_value(&mut deferred_pipeline.debug_type, DebugType::UV, "UV");
|
||||||
|
ui.radio_value(&mut deferred_pipeline.debug_type, DebugType::DEPTH, "Depth");
|
||||||
|
ui.radio_value(&mut deferred_pipeline.debug_type, DebugType::ORM, "ORM");
|
||||||
|
});
|
||||||
|
panel_width = gui_context.used_size().x as u32;
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
x: panel_width as i32,
|
||||||
|
y: 0,
|
||||||
|
width: frame_input.viewport.width - panel_width,
|
||||||
|
height: frame_input.viewport.height,
|
||||||
|
};
|
||||||
|
change |= camera.set_viewport(viewport).unwrap();
|
||||||
|
change |= control
|
||||||
|
.handle_events(&mut camera, &mut frame_input.events)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Draw
|
||||||
{
|
{
|
||||||
// Ensure the viewport matches the current window viewport which changes if the window is resized
|
if shadows_enabled {
|
||||||
camera.set_viewport(frame_input.viewport).unwrap();
|
lights.directional[0]
|
||||||
|
.generate_shadow_map(4.0, 1024, 1024, &[&model])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Start writing to the screen and clears the color and depth
|
// Geometry pass
|
||||||
Screen::write(&context, ClearState::color_and_depth(0.8, 0.8, 0.8, 1.0, 1.0), || {
|
if change && current_pipeline == Pipeline::Deferred {
|
||||||
// Set the current transformation of the triangle
|
deferred_pipeline
|
||||||
model.set_transformation(Mat4::from_angle_y(radians((frame_input.accumulated_time * 0.005) as f32)));
|
.render_pass(
|
||||||
|
&camera,
|
||||||
|
&[(
|
||||||
|
&model,
|
||||||
|
DeferredPhysicalMaterial::from_physical_material(&model.material),
|
||||||
|
)],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// Render the triangle with the color material which uses the per vertex colors defined at construction
|
// Light pass
|
||||||
model.render(&camera, &Lights::default())?;
|
Screen::write(&context, ClearState::default(), || {
|
||||||
|
match current_pipeline {
|
||||||
|
Pipeline::Forward => {
|
||||||
|
match deferred_pipeline.debug_type {
|
||||||
|
DebugType::NORMAL => {
|
||||||
|
model.render_with_material(
|
||||||
|
&NormalMaterial::from_physical_material(&model.material),
|
||||||
|
&camera,
|
||||||
|
&lights,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DebugType::DEPTH => {
|
||||||
|
let depth_material = DepthMaterial::default();
|
||||||
|
model.render_with_material(&depth_material, &camera, &lights)?;
|
||||||
|
}
|
||||||
|
DebugType::ORM => {
|
||||||
|
model.render_with_material(
|
||||||
|
&ORMMaterial::from_physical_material(&model.material),
|
||||||
|
&camera,
|
||||||
|
&lights,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DebugType::POSITION => {
|
||||||
|
let position_material = PositionMaterial::default();
|
||||||
|
model.render_with_material(&position_material, &camera, &lights)?;
|
||||||
|
}
|
||||||
|
DebugType::UV => {
|
||||||
|
let uv_material = UVMaterial::default();
|
||||||
|
model.render_with_material(&uv_material, &camera, &lights)?;
|
||||||
|
}
|
||||||
|
DebugType::COLOR => {
|
||||||
|
model.render_with_material(
|
||||||
|
&ColorMaterial::from_physical_material(&model.material),
|
||||||
|
&camera,
|
||||||
|
&lights,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
DebugType::NONE => {
|
||||||
|
forward_pipeline.render_pass(&camera, &[&model], &lights)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Pipeline::Deferred => {
|
||||||
|
deferred_pipeline.lighting_pass(&camera, &lights)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gui.render()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}).unwrap();
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
FrameOutput::default()
|
FrameOutput::default()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +277,8 @@ fn model_to_mesh(model: Handle<vbsp::data::Model>) -> CPUMesh {
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.max_by(|a, b| a.partial_cmp(b).unwrap())
|
.max_by(|a, b| a.partial_cmp(b).unwrap())
|
||||||
.unwrap();
|
.unwrap()
|
||||||
|
/ 10.0;
|
||||||
let positions: Vec<f32> = model
|
let positions: Vec<f32> = model
|
||||||
.faces()
|
.faces()
|
||||||
.filter(|face| face.is_visible())
|
.filter(|face| face.is_visible())
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue