initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
||||
2604
Cargo.lock
generated
Normal file
2604
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "rust-sponges"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.100"
|
||||
bytemuck = "1.24.0"
|
||||
cgmath = "0.18.0"
|
||||
crevice = {version = "0.18.0", features = ["cgmath"]}
|
||||
env_logger = "0.11.8"
|
||||
pollster = "0.4.0"
|
||||
wgpu = "27.0.1"
|
||||
winit = "0.30.12"
|
||||
187
shaders/ray_marching.wgsl
Normal file
187
shaders/ray_marching.wgsl
Normal file
@ -0,0 +1,187 @@
|
||||
struct RayMarchingPushConstants
|
||||
{
|
||||
inverse_proj: mat4x4<f32>,
|
||||
view_matrix: mat4x4<f32>,
|
||||
camera_pos: vec3<f32>,
|
||||
|
||||
scale: f32,
|
||||
translation: vec3<f32>,
|
||||
rotation: vec3<f32>,
|
||||
}
|
||||
|
||||
var<push_constant> constants: RayMarchingPushConstants;
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
@builtin(position) pos: vec4<f32>,
|
||||
@location(0) uv: vec2<f32>
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vertex(@builtin(vertex_index) i: u32) -> Vertex
|
||||
{
|
||||
let vertices = array<vec4<f32>, 4>(
|
||||
vec4<f32>(-1., -1., 0., 1.),
|
||||
vec4<f32>(1., -1., 0., 1.),
|
||||
vec4<f32>(-1., 1., 0., 1.),
|
||||
vec4<f32>(1., 1., 0., 1.),
|
||||
);
|
||||
|
||||
let uvs = array<vec2<f32>, 4>(
|
||||
vec2<f32>(0., 0.),
|
||||
vec2<f32>(1., 0.),
|
||||
vec2<f32>(0., 1.),
|
||||
vec2<f32>(1., 1.),
|
||||
);
|
||||
|
||||
let indices = array<u32, 6>(
|
||||
0, 1, 2,
|
||||
2, 1, 3
|
||||
);
|
||||
|
||||
var v: Vertex;
|
||||
v.pos = vertices[indices[i]];
|
||||
v.uv = uvs[indices[i]];
|
||||
return v;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragment(in: Vertex) -> @location(0) vec4<f32>
|
||||
{
|
||||
// Produce input ray
|
||||
let ndc_ray = vec4<f32>(in.uv.xy * 2. - vec2<f32>(1.), -1.0, 1.0);
|
||||
var unproj =constants.inverse_proj * ndc_ray;
|
||||
unproj.w = 0.;
|
||||
|
||||
|
||||
// Reproject into frustum
|
||||
var ray = (constants.view_matrix * unproj).xyz;
|
||||
ray /= length(ray);
|
||||
|
||||
//return vec4<f32>(ray, 1.);
|
||||
|
||||
// Ray march
|
||||
var t = 0.;
|
||||
var pos = constants.camera_pos;
|
||||
|
||||
loop
|
||||
{
|
||||
// Sample sdf
|
||||
let sdf = sdf(pos);
|
||||
|
||||
if sdf < 0.00001
|
||||
{
|
||||
let grad = sdf_gradient(pos);
|
||||
return vec4<f32>((dot(grad, normalize(vec3<f32>(1.))) + 1.) * 0.5);
|
||||
}
|
||||
if sdf > 1000
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
t += sdf;
|
||||
pos += ray * sdf;
|
||||
}
|
||||
|
||||
// Ray escaped, get skybox
|
||||
return skybox(ray);
|
||||
}
|
||||
|
||||
fn sdf(pos: vec3<f32>) -> f32
|
||||
{
|
||||
var x = pos;
|
||||
var t = 1.;
|
||||
|
||||
for(var i = 0u; i < 3; i++)
|
||||
{
|
||||
x *= 1.5;
|
||||
t *= 1.5;
|
||||
x = abs(x);
|
||||
x += vec3<f32>(0.01, 0.02, 0.08);
|
||||
x *= rot();
|
||||
}
|
||||
|
||||
return sdf_box(x, vec3<f32>(1.)) / t;
|
||||
}
|
||||
|
||||
fn rot() -> mat3x3<f32>
|
||||
{
|
||||
let rx = 0.6;
|
||||
let ry = 8.1;
|
||||
return mat3x3<f32>(
|
||||
cos(rx), sin(rx), 0.,
|
||||
-sin(rx), cos(rx), 0.,
|
||||
0., 0., 1.
|
||||
)*
|
||||
mat3x3<f32>(
|
||||
1., 0., 0.,
|
||||
0., cos(ry), sin(ry),
|
||||
0, -sin(ry), cos(ry)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
fn sdf_box(pos: vec3<f32>, b: vec3<f32>) -> f32
|
||||
{
|
||||
let q = abs(pos) - b;
|
||||
return length(max(q, vec3<f32>(0.))) + min(max(q.x, max(q.y, q.z)), 0.);
|
||||
}
|
||||
|
||||
fn sdf_gradient(p: vec3<f32>) -> vec3<f32>
|
||||
{
|
||||
let eps = 0.000001;
|
||||
let h = vec2<f32>(eps, 0);
|
||||
|
||||
return normalize(
|
||||
vec3<f32>(
|
||||
sdf(p + h.xyy) - sdf(p-h.xyy),
|
||||
sdf(p + h.yxy) - sdf(p-h.yxy),
|
||||
sdf(p + h.yyx) - sdf(p-h.yyx)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
fn skybox(dir: vec3<f32>) -> vec4<f32>
|
||||
{
|
||||
let sun_dir = normalize(vec3<f32>(1., 1., 1.));
|
||||
|
||||
let gnd_under = vec4<f32>(0.423, 0.450, 0.448, 1.0);
|
||||
let gnd_top = vec4<f32>(0.323, 0.350, 0.348, 1.0);
|
||||
let gnd = interpolate(gnd_top, gnd_under, map(dir.y, -0.7, 0, 0, 1));
|
||||
|
||||
let b = vec4<f32>(0.545, 0.874, 0.940, 1.0);
|
||||
let top: vec4<f32> = vec4<f32>(0.0891, 0.464, 0.990, 1.0);
|
||||
let sky: vec4<f32> = interpolate(b, top, dir.y);
|
||||
|
||||
|
||||
let height = map(dir.y, -0.01, 0.01, 0.0, 1.0);
|
||||
var res = interpolate(gnd, sky, height);
|
||||
|
||||
var dt = map( dot(dir, normalize(sun_dir)), 0.999, 1, 0, 1);
|
||||
if(dt < 0) {dt = 0;}
|
||||
res += dt * vec4(0.990, 0.973, 0.782, 1.0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
fn interpolate(a: vec4<f32>, b: vec4<f32>, x: f32) -> vec4<f32>
|
||||
{
|
||||
var t = x;
|
||||
if(t > 1.) {t = 1.;};
|
||||
if(t < 0.) {t = 0.;};
|
||||
let at = 1. - t;
|
||||
return vec4<f32>
|
||||
(
|
||||
a.x * at + b.x * t,
|
||||
a.y * at + b.y * t,
|
||||
a.z * at + b.z * t,
|
||||
a.w * at + b.w * t
|
||||
);
|
||||
}
|
||||
|
||||
fn map(x: f32, xmin: f32, xmax: f32, ymin: f32, ymax: f32) -> f32
|
||||
{
|
||||
return ((x - xmin) / (xmax - xmin)) * (ymax - ymin) + ymin;
|
||||
}
|
||||
0
src/app.rs
Normal file
0
src/app.rs
Normal file
115
src/lib.rs
Normal file
115
src/lib.rs
Normal file
@ -0,0 +1,115 @@
|
||||
pub mod state;
|
||||
|
||||
use std::{os::linux::raw::stat, sync::Arc};
|
||||
|
||||
use winit::{
|
||||
application::ApplicationHandler,
|
||||
dpi::{LogicalPosition, PhysicalPosition},
|
||||
event::{KeyEvent, RawKeyEvent, WindowEvent},
|
||||
event_loop::{self, EventLoop},
|
||||
keyboard::{Key, KeyCode, PhysicalKey},
|
||||
platform::modifier_supplement::KeyEventExtModifierSupplement,
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use crate::state::State;
|
||||
|
||||
pub fn run() -> anyhow::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
let event_loop = EventLoop::with_user_event().build()?;
|
||||
let mut app = RustSponges::default();
|
||||
event_loop.run_app(&mut app)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// App struct
|
||||
pub struct RustSponges {
|
||||
state: Option<State>,
|
||||
}
|
||||
|
||||
impl Default for RustSponges {
|
||||
fn default() -> Self {
|
||||
Self { state: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl ApplicationHandler for RustSponges {
|
||||
fn resumed(&mut self, event_loop: &event_loop::ActiveEventLoop) {
|
||||
// Create window
|
||||
let window = Arc::new(
|
||||
event_loop
|
||||
.create_window(
|
||||
Window::default_attributes()
|
||||
.with_title("Rust Sponges")
|
||||
.with_resizable(true),
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let state = pollster::block_on(State::new(window.clone()));
|
||||
self.state = Some(state);
|
||||
|
||||
window.request_redraw();
|
||||
}
|
||||
|
||||
fn window_event(
|
||||
&mut self,
|
||||
event_loop: &event_loop::ActiveEventLoop,
|
||||
window_id: winit::window::WindowId,
|
||||
event: winit::event::WindowEvent,
|
||||
) {
|
||||
let state = self.state.as_mut().unwrap();
|
||||
|
||||
match event {
|
||||
WindowEvent::CloseRequested => {
|
||||
event_loop.exit();
|
||||
}
|
||||
WindowEvent::RedrawRequested => {
|
||||
state.render();
|
||||
state.get_window().request_redraw();
|
||||
}
|
||||
|
||||
WindowEvent::Resized(size) => {
|
||||
state.resize(size);
|
||||
}
|
||||
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: _,
|
||||
event: key_event,
|
||||
is_synthetic: _,
|
||||
} => {
|
||||
state.key_event(key_event);
|
||||
}
|
||||
|
||||
WindowEvent::MouseInput {
|
||||
device_id: _,
|
||||
state: mouse_state,
|
||||
button,
|
||||
} => {
|
||||
state.mouse_event(mouse_state, button);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn device_event(
|
||||
&mut self,
|
||||
_event_loop: &event_loop::ActiveEventLoop,
|
||||
_device_id: winit::event::DeviceId,
|
||||
event: winit::event::DeviceEvent,
|
||||
) {
|
||||
let state = self.state.as_mut().unwrap();
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match event {
|
||||
winit::event::DeviceEvent::MouseMotion { delta } => {
|
||||
state.cursor_moved(delta.0 as f32, delta.1 as f32);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
src/main.rs
Normal file
3
src/main.rs
Normal file
@ -0,0 +1,3 @@
|
||||
fn main() -> anyhow::Result<()> {
|
||||
rust_sponges::run()
|
||||
}
|
||||
319
src/state.rs
Normal file
319
src/state.rs
Normal file
@ -0,0 +1,319 @@
|
||||
use std::{collections::HashSet, sync::Arc};
|
||||
|
||||
use cgmath::{Deg, Matrix4, SquareMatrix, Vector3};
|
||||
use crevice::std430::AsStd430;
|
||||
use wgpu::{
|
||||
ColorWrites, Features, FeaturesWGPU, FeaturesWebGPU, FragmentState, PipelineLayoutDescriptor,
|
||||
PushConstantRange, RenderPipeline, RenderPipelineDescriptor, ShaderStages, VertexState,
|
||||
include_wgsl,
|
||||
};
|
||||
use winit::{
|
||||
dpi::PhysicalPosition,
|
||||
event::{ElementState, KeyEvent, MouseButton, RawKeyEvent},
|
||||
keyboard::{KeyCode, PhysicalKey},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
pub struct State {
|
||||
window: Arc<Window>,
|
||||
device: wgpu::Device,
|
||||
queue: wgpu::Queue,
|
||||
size: winit::dpi::PhysicalSize<u32>,
|
||||
surface: wgpu::Surface<'static>,
|
||||
surface_format: wgpu::TextureFormat,
|
||||
|
||||
// World
|
||||
camera: Camera,
|
||||
|
||||
// Raymarching
|
||||
ray_marching_renderer: RenderPipeline,
|
||||
|
||||
// Controls
|
||||
pressed_set: HashSet<KeyCode>,
|
||||
mouse_inside: bool,
|
||||
}
|
||||
|
||||
pub struct Camera {
|
||||
position: cgmath::Vector3<f32>,
|
||||
pitch: f32,
|
||||
yaw: f32,
|
||||
fovy: f32,
|
||||
aspect: f32,
|
||||
|
||||
znear: f32,
|
||||
zfar: f32,
|
||||
}
|
||||
|
||||
impl Camera {
|
||||
fn get_proj(&self) -> Matrix4<f32> {
|
||||
cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar)
|
||||
}
|
||||
|
||||
fn get_view(&self) -> Matrix4<f32> {
|
||||
cgmath::Matrix4::from_angle_y(cgmath::Deg(-self.yaw))
|
||||
* cgmath::Matrix4::from_angle_x(cgmath::Deg(-self.pitch))
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub async fn new(window: Arc<Window>) -> State {
|
||||
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
|
||||
let adapter = instance
|
||||
.request_adapter(&wgpu::RequestAdapterOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let (device, queue) = adapter
|
||||
.request_device(&wgpu::DeviceDescriptor {
|
||||
required_features: Features {
|
||||
features_wgpu: FeaturesWGPU::PUSH_CONSTANTS,
|
||||
features_webgpu: FeaturesWebGPU::empty(),
|
||||
},
|
||||
required_limits: wgpu::Limits {
|
||||
max_push_constant_size: RayMarchingPushConstants::std430_size_static() as u32,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let size = window.inner_size();
|
||||
|
||||
let surface = instance.create_surface(window.clone()).unwrap();
|
||||
let cap = surface.get_capabilities(&adapter);
|
||||
let surface_format = cap.formats[0];
|
||||
|
||||
let ray_marching_renderer_layout =
|
||||
device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
||||
label: Some("ray_marching_compute_pipeline_layout"),
|
||||
bind_group_layouts: &[],
|
||||
push_constant_ranges: &[PushConstantRange {
|
||||
stages: ShaderStages::FRAGMENT,
|
||||
range: 0..RayMarchingPushConstants::std430_size_static() as u32,
|
||||
}],
|
||||
});
|
||||
|
||||
let ray_marching_renderer_shader_module =
|
||||
device.create_shader_module(include_wgsl!("../shaders/ray_marching.wgsl"));
|
||||
let ray_marching_renderer = device.create_render_pipeline(&RenderPipelineDescriptor {
|
||||
label: Some("ray_marching_renderer"),
|
||||
layout: Some(&ray_marching_renderer_layout),
|
||||
vertex: VertexState {
|
||||
module: &ray_marching_renderer_shader_module,
|
||||
entry_point: Some("vertex"),
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
buffers: &[],
|
||||
},
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
..Default::default()
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
module: &ray_marching_renderer_shader_module,
|
||||
entry_point: Some("fragment"),
|
||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: surface_format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: ColorWrites::all(),
|
||||
})],
|
||||
}),
|
||||
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let state = State {
|
||||
window,
|
||||
device,
|
||||
queue,
|
||||
size,
|
||||
surface,
|
||||
surface_format,
|
||||
|
||||
camera: Camera {
|
||||
position: Vector3::new(0., 0., 0.),
|
||||
pitch: 0.,
|
||||
yaw: 0.,
|
||||
fovy: 90.,
|
||||
aspect: size.width as f32 / size.height as f32,
|
||||
znear: 0.001,
|
||||
zfar: 1000.,
|
||||
},
|
||||
ray_marching_renderer,
|
||||
|
||||
pressed_set: HashSet::new(),
|
||||
mouse_inside: false,
|
||||
};
|
||||
|
||||
// Configure surface for the first time
|
||||
state.configure_surface();
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
pub fn get_window(&self) -> &Window {
|
||||
&self.window
|
||||
}
|
||||
|
||||
pub fn configure_surface(&self) {
|
||||
let surface_config = wgpu::SurfaceConfiguration {
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
format: self.surface_format,
|
||||
// Request compatibility with the sRGB-format texture view we‘re going to create later.
|
||||
view_formats: vec![self.surface_format.add_srgb_suffix()],
|
||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||||
width: self.size.width,
|
||||
height: self.size.height,
|
||||
desired_maximum_frame_latency: 2,
|
||||
present_mode: wgpu::PresentMode::AutoVsync,
|
||||
};
|
||||
self.surface.configure(&self.device, &surface_config);
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||
self.size = new_size;
|
||||
self.camera.aspect = new_size.width as f32 / new_size.height as f32;
|
||||
|
||||
// reconfigure the surface
|
||||
self.configure_surface();
|
||||
}
|
||||
|
||||
pub fn render(&mut self) {
|
||||
self.handle_movement();
|
||||
// Create texture view
|
||||
let surface_texture = self
|
||||
.surface
|
||||
.get_current_texture()
|
||||
.expect("failed to acquire next swapchain texture");
|
||||
let texture_view = surface_texture
|
||||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor {
|
||||
// Without add_srgb_suffix() the image we will be working with
|
||||
// might not be "gamma correct".
|
||||
format: Some(self.surface_format.add_srgb_suffix()),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
// Renders a GREEN screen
|
||||
let mut encoder = self.device.create_command_encoder(&Default::default());
|
||||
// Create the renderpass which will clear the screen.
|
||||
let mut renderpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: None,
|
||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||
view: &texture_view,
|
||||
depth_slice: None,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
|
||||
store: wgpu::StoreOp::Store,
|
||||
},
|
||||
})],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
occlusion_query_set: None,
|
||||
});
|
||||
|
||||
// If you wanted to call any drawing commands, they would go here.
|
||||
renderpass.set_pipeline(&self.ray_marching_renderer);
|
||||
renderpass.set_push_constants(
|
||||
ShaderStages::FRAGMENT,
|
||||
0,
|
||||
RayMarchingPushConstants {
|
||||
inverse_projection_matrix: self.camera.get_proj().invert().unwrap(),
|
||||
camera_pos: self.camera.position,
|
||||
view_matrix: self.camera.get_view(),
|
||||
}
|
||||
.as_std430()
|
||||
.as_bytes(),
|
||||
);
|
||||
renderpass.draw(0..6, 0..1);
|
||||
|
||||
// End the renderpass.
|
||||
drop(renderpass);
|
||||
|
||||
// Submit the command in the queue to execute
|
||||
self.queue.submit([encoder.finish()]);
|
||||
self.window.pre_present_notify();
|
||||
surface_texture.present();
|
||||
}
|
||||
|
||||
pub fn cursor_moved(&mut self, x: f32, y: f32) {
|
||||
const SENSIBILITY: f32 = 0.02;
|
||||
let position = cgmath::Vector2::new(x, y);
|
||||
let offset = position * SENSIBILITY;
|
||||
|
||||
if self.mouse_inside {
|
||||
self.camera.yaw += offset.x;
|
||||
self.camera.pitch += offset.y;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_event(&mut self, event: KeyEvent) {
|
||||
match (event.state, event.physical_key) {
|
||||
(ElementState::Pressed, PhysicalKey::Code(KeyCode::Escape)) => {
|
||||
self.window.set_cursor_visible(true);
|
||||
self.window
|
||||
.set_cursor_grab(winit::window::CursorGrabMode::None)
|
||||
.unwrap();
|
||||
self.mouse_inside = false;
|
||||
}
|
||||
(ElementState::Pressed, PhysicalKey::Code(c)) => {
|
||||
self.pressed_set.insert(c);
|
||||
}
|
||||
(ElementState::Released, PhysicalKey::Code(c)) => {
|
||||
self.pressed_set.remove(&c);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_event(&mut self, state: ElementState, button: MouseButton) {
|
||||
if state == ElementState::Pressed && button == MouseButton::Left {
|
||||
self.mouse_inside = true;
|
||||
self.window.set_cursor_visible(false);
|
||||
self.window
|
||||
.set_cursor_grab(winit::window::CursorGrabMode::Confined)
|
||||
.or_else(|_| {
|
||||
self.window
|
||||
.set_cursor_grab(winit::window::CursorGrabMode::Locked)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_movement(&mut self) {
|
||||
const SPEED: f32 = 0.1;
|
||||
// Forward-backward
|
||||
let mut movement = cgmath::Vector3::new(0., 0., 0.);
|
||||
if self.pressed_set.contains(&KeyCode::KeyW) {
|
||||
movement.z += SPEED;
|
||||
}
|
||||
if self.pressed_set.contains(&KeyCode::KeyS) {
|
||||
movement.z -= SPEED;
|
||||
}
|
||||
|
||||
// Left rigth
|
||||
if self.pressed_set.contains(&KeyCode::KeyA) {
|
||||
movement.x += SPEED;
|
||||
}
|
||||
if self.pressed_set.contains(&KeyCode::KeyD) {
|
||||
movement.x -= SPEED;
|
||||
}
|
||||
|
||||
let rot_movement = cgmath::Matrix3::from_angle_y(cgmath::Deg(-self.camera.yaw))
|
||||
* cgmath::Matrix3::from_angle_x(cgmath::Deg(-self.camera.pitch))
|
||||
* movement;
|
||||
self.camera.position -= rot_movement;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AsStd430)]
|
||||
pub struct RayMarchingPushConstants {
|
||||
inverse_projection_matrix: Matrix4<f32>,
|
||||
view_matrix: Matrix4<f32>,
|
||||
camera_pos: Vector3<f32>,
|
||||
}
|
||||
Reference in New Issue
Block a user