Kinda working

This commit is contained in:
2025-12-14 13:40:07 +01:00
parent 4249326355
commit 7b97b5c526
6 changed files with 1090 additions and 65 deletions

850
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,9 @@ anyhow = "1.0.100"
bytemuck = "1.24.0"
cgmath = "0.18.0"
crevice = {version = "0.18.0", features = ["cgmath"]}
egui = "0.33.3"
egui-wgpu = "0.33.3"
egui-winit = "0.33.3"
env_logger = "0.11.8"
pollster = "0.4.0"
wgpu = "27.0.1"

View File

@ -1,14 +1,20 @@
struct FractalParameters
{
translation: vec3<f32>,
rotation: vec3<f32>,
scale: f32,
iterations: u32
}
struct RayMarchingPushConstants
{
inverse_proj: mat4x4<f32>,
view_matrix: mat4x4<f32>,
camera_pos: vec3<f32>,
scale: f32,
translation: vec3<f32>,
rotation: vec3<f32>,
fractal_parameters: FractalParameters
}
var<push_constant> constants: RayMarchingPushConstants;
struct Vertex
@ -92,31 +98,39 @@ fn sdf(pos: vec3<f32>) -> f32
var x = pos;
var t = 1.;
for(var i = 0u; i < 3; i++)
for(var i = 0u; i < constants.fractal_parameters.iterations; i++)
{
x *= 1.5;
t *= 1.5;
x *= constants.fractal_parameters.scale;
t *= constants.fractal_parameters.scale;
x = abs(x);
x += vec3<f32>(0.01, 0.02, 0.08);
x += constants.fractal_parameters.translation;
x *= rot();
}
return sdf_box(x, vec3<f32>(1.)) / t;
return sdf_octahedron(x, 1.) / t;
}
fn rot() -> mat3x3<f32>
{
let rx = 0.6;
let ry = 8.1;
let rx = constants.fractal_parameters.rotation.x;
let ry = constants.fractal_parameters.rotation.y;
let rz = constants.fractal_parameters.rotation.z;
return mat3x3<f32>(
cos(rx), sin(rx), 0.,
-sin(rx), cos(rx), 0.,
0., 0., 1.
)*
)
*
mat3x3<f32>(
cos(ry), 0., sin(ry),
0., 1., 0.,
-sin(ry), 0., cos(ry)
)
*
mat3x3<f32>(
1., 0., 0.,
0., cos(ry), sin(ry),
0, -sin(ry), cos(ry)
0., cos(rz), sin(rz),
0, -sin(rz), cos(rz)
);
}
@ -127,9 +141,15 @@ fn sdf_box(pos: vec3<f32>, b: vec3<f32>) -> f32
return length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.);
}
fn sdf_octahedron(pos: vec3<f32>, s: f32) -> f32
{
let p = abs(pos);
return (p.x + p.y + p.z - s) *0.57735;
}
fn sdf_gradient(p: vec3<f32>) -> vec3<f32>
{
let eps = 0.000001;
let eps = 0.0001;
let h = vec2<f32>(eps, 0);
return normalize(

137
src/egui_renderer.rs Normal file
View File

@ -0,0 +1,137 @@
use egui::{Context, PaintCallbackInfo};
use egui_wgpu::{CallbackResources, CallbackTrait, Renderer, RendererOptions, ScreenDescriptor};
use egui_winit::State;
use wgpu::{CommandEncoder, Device, Queue, RenderPass, TextureFormat, TextureView};
use winit::{event::WindowEvent, window::Window};
pub struct EguiState {
pub state: State,
pub renderer: Renderer,
pub frame_started: bool,
//pub msaa_texture: TextureView,
pub color_format: TextureFormat,
}
impl EguiState {
pub fn context(&self) -> &Context {
self.state.egui_ctx()
}
pub fn new(device: &Device, output_color_format: TextureFormat, window: &Window) -> EguiState {
let egui_context = Context::default();
let egui_state = egui_winit::State::new(
egui_context,
egui::ViewportId::ROOT,
&window,
Some(window.scale_factor() as f32),
None,
Some(2 * 1024),
);
let options = RendererOptions {
//msaa_samples: SAMPLE_COUNT,
//depth_stencil_format: Some(TextureFormat::Depth24PlusStencil8),
..Default::default()
};
let egui_renderer = Renderer::new(device, output_color_format, options);
EguiState {
state: egui_state,
renderer: egui_renderer,
frame_started: false,
color_format: output_color_format,
}
}
pub fn resize(&mut self, _device: &Device, _width: u32, _height: u32) {}
pub fn handle_event(&mut self, window: &Window, event: &WindowEvent) {
let _ = self.state.on_window_event(window, event);
}
pub fn begin_frame(&mut self, window: &Window) {
let input = self.state.take_egui_input(window);
self.state.egui_ctx().begin_pass(input);
self.frame_started = true;
}
pub fn end_frame_and_draw(
&mut self,
device: &Device,
queue: &Queue,
encoder: &mut CommandEncoder,
window: &Window,
window_surface_view: &TextureView,
screen_descriptor: ScreenDescriptor,
) {
if !self.frame_started {
panic!("begin_frame must be called before end_frame_and_draw can be called!");
}
//self.ppp(screen_descriptor.pixels_per_point);
let full_output = self.state.egui_ctx().end_pass();
self.state
.handle_platform_output(window, full_output.platform_output);
let tris = self
.state
.egui_ctx()
.tessellate(full_output.shapes, self.state.egui_ctx().pixels_per_point());
for (id, image_delta) in &full_output.textures_delta.set {
self.renderer
.update_texture(device, queue, *id, image_delta);
}
self.renderer
.update_buffers(device, queue, encoder, &tris, &screen_descriptor);
let rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: window_surface_view,
resolve_target: None,
ops: egui_wgpu::wgpu::Operations {
load: egui_wgpu::wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
label: Some("egui main render pass"),
timestamp_writes: None,
occlusion_query_set: None,
});
self.renderer
.render(&mut rpass.forget_lifetime(), &tris, &screen_descriptor);
for x in &full_output.textures_delta.free {
self.renderer.free_texture(x)
}
self.frame_started = false;
}
}
pub struct CallbackFn<P>
where
P: Fn(PaintCallbackInfo, &mut RenderPass<'static>, &CallbackResources),
{
//pub : FnOnce(&Device, &Queue, &ScreenDescriptor, &mut CommandEncoder, &mut CallbackResources) -> Vec<>
pub paint_fn: P,
}
impl<P> CallbackTrait for CallbackFn<P>
where
P: Fn(PaintCallbackInfo, &mut RenderPass<'static>, &CallbackResources)
+ std::marker::Sync
+ std::marker::Send,
{
fn paint(
&self,
info: egui::PaintCallbackInfo,
render_pass: &mut wgpu::RenderPass<'static>,
callback_resources: &egui_wgpu::CallbackResources,
) {
(self.paint_fn)(info, render_pass, callback_resources)
}
}

View File

@ -1,14 +1,12 @@
pub mod egui_renderer;
pub mod state;
use std::{os::linux::raw::stat, sync::Arc};
use std::sync::Arc;
use winit::{
application::ApplicationHandler,
dpi::{LogicalPosition, PhysicalPosition},
event::{KeyEvent, RawKeyEvent, WindowEvent},
event::WindowEvent,
event_loop::{self, EventLoop},
keyboard::{Key, KeyCode, PhysicalKey},
platform::modifier_supplement::KeyEventExtModifierSupplement,
window::Window,
};
@ -57,10 +55,11 @@ impl ApplicationHandler for RustSponges {
fn window_event(
&mut self,
event_loop: &event_loop::ActiveEventLoop,
window_id: winit::window::WindowId,
_window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
let state = self.state.as_mut().unwrap();
state.handle_event(&event);
match event {
WindowEvent::CloseRequested => {

View File

@ -1,19 +1,21 @@
use std::{collections::HashSet, sync::Arc};
use cgmath::{Deg, Matrix4, SquareMatrix, Vector3};
use cgmath::{Matrix4, SquareMatrix, Vector3};
use crevice::std430::AsStd430;
use egui_wgpu::ScreenDescriptor;
use wgpu::{
ColorWrites, Features, FeaturesWGPU, FeaturesWebGPU, FragmentState, PipelineLayoutDescriptor,
PushConstantRange, RenderPipeline, RenderPipelineDescriptor, ShaderStages, VertexState,
include_wgsl,
};
use winit::{
dpi::PhysicalPosition,
event::{ElementState, KeyEvent, MouseButton, RawKeyEvent},
event::{ElementState, KeyEvent, MouseButton, WindowEvent},
keyboard::{KeyCode, PhysicalKey},
window::Window,
};
use crate::egui_renderer::EguiState;
pub struct State {
window: Arc<Window>,
device: wgpu::Device,
@ -21,16 +23,20 @@ pub struct State {
size: winit::dpi::PhysicalSize<u32>,
surface: wgpu::Surface<'static>,
surface_format: wgpu::TextureFormat,
egui_state: EguiState,
// World
camera: Camera,
fractal_parameters: FractalParameters,
// Raymarching
ray_marching_renderer: RenderPipeline,
// Controls
pressed_set: HashSet<KeyCode>,
mouse_inside: bool,
mouse_over_gui: bool,
}
pub struct Camera {
@ -44,6 +50,14 @@ pub struct Camera {
zfar: f32,
}
#[derive(Clone, Copy, AsStd430)]
pub struct FractalParameters {
translation: Vector3<f32>,
rotation: Vector3<f32>,
scale: f32,
iteations: u32,
}
impl Camera {
fn get_proj(&self) -> Matrix4<f32> {
cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar)
@ -126,6 +140,8 @@ impl State {
});
let state = State {
egui_state: EguiState::new(&device, surface_format, &window),
window,
device,
queue,
@ -142,10 +158,18 @@ impl State {
znear: 0.001,
zfar: 1000.,
},
fractal_parameters: FractalParameters {
translation: Vector3::new(0., 0., 0.),
rotation: Vector3::new(0., 0., 0.),
scale: 1.,
iteations: 1,
},
ray_marching_renderer,
pressed_set: HashSet::new(),
mouse_inside: false,
mouse_over_gui: false,
};
// Configure surface for the first time
@ -181,6 +205,10 @@ impl State {
self.configure_surface();
}
pub fn handle_event(&mut self, event: &WindowEvent) {
self.egui_state.handle_event(&self.window, event);
}
pub fn render(&mut self) {
self.handle_movement();
// Create texture view
@ -225,6 +253,7 @@ impl State {
inverse_projection_matrix: self.camera.get_proj().invert().unwrap(),
camera_pos: self.camera.position,
view_matrix: self.camera.get_view(),
fractal_parameters: self.fractal_parameters,
}
.as_std430()
.as_bytes(),
@ -233,6 +262,72 @@ impl State {
// End the renderpass.
drop(renderpass);
// Egui
{
let screen_descriptor = ScreenDescriptor {
size_in_pixels: [self.size.width, self.size.height],
pixels_per_point: 1.,
};
self.egui_state.begin_frame(&self.window);
egui::Window::new("Controls")
.resizable(true)
.show(self.egui_state.context(), |ui| {
ui.label("Translation");
ui.add(
egui::Slider::new(&mut self.fractal_parameters.translation.x, -0.9..=0.9)
.text("X"),
);
ui.add(
egui::Slider::new(&mut self.fractal_parameters.translation.y, -0.9..=0.9)
.text("Y"),
);
ui.add(
egui::Slider::new(&mut self.fractal_parameters.translation.z, -0.9..=0.9)
.text("Z"),
);
ui.add_space(6.);
ui.label("Rotation");
ui.add(
egui::Slider::new(&mut self.fractal_parameters.rotation.x, -1.9..=1.9)
.text("X"),
);
ui.add(
egui::Slider::new(&mut self.fractal_parameters.rotation.y, -1.9..=1.9)
.text("Y"),
);
ui.add(
egui::Slider::new(&mut self.fractal_parameters.rotation.z, -1.9..=1.9)
.text("Z"),
);
ui.add_space(6.);
ui.label("Scale");
ui.add(
egui::Slider::new(&mut self.fractal_parameters.scale, 1.0..=2.)
.text("scale"),
);
ui.add_space(6.);
ui.label("Iterations");
ui.add(
egui::Slider::new(&mut self.fractal_parameters.iteations, 0..=30)
.text("iteations"),
);
});
self.mouse_over_gui = self.egui_state.context().is_pointer_over_area();
self.egui_state.end_frame_and_draw(
&self.device,
&self.queue,
&mut encoder,
&self.window,
&texture_view,
screen_descriptor,
);
}
// Submit the command in the queue to execute
self.queue.submit([encoder.finish()]);
@ -272,7 +367,7 @@ impl State {
}
pub fn mouse_event(&mut self, state: ElementState, button: MouseButton) {
if state == ElementState::Pressed && button == MouseButton::Left {
if state == ElementState::Pressed && button == MouseButton::Left && !self.mouse_over_gui {
self.mouse_inside = true;
self.window.set_cursor_visible(false);
self.window
@ -316,4 +411,5 @@ pub struct RayMarchingPushConstants {
inverse_projection_matrix: Matrix4<f32>,
view_matrix: Matrix4<f32>,
camera_pos: Vector3<f32>,
fractal_parameters: FractalParameters,
}