From 989b75f54d29afdaada90869daa54c6e211de35a Mon Sep 17 00:00:00 2001 From: Piotrek Date: Fri, 7 May 2021 15:41:08 +0200 Subject: [PATCH] Fonts, glyphs, displaying fps --- Cargo.lock | 125 +++++++++++++++++++++++- Cargo.toml | 2 + assets/font.ttf | Bin 0 -> 58088 bytes src/main.rs | 10 +- src/renderer/buffers/content.rs | 9 -- src/renderer/buffers/materials.rs | 46 ++++----- src/renderer/buffers/uniform.rs | 43 ++++---- src/renderer/mod.rs | 25 +++-- src/renderer/passes/ui.rs | 9 ++ src/renderer/ui.rs | 56 +++++++++++ src/shaders/raytrace/.bin/main.frag.spv | Bin 13692 -> 13632 bytes src/shaders/raytrace/main.frag | 2 +- 12 files changed, 252 insertions(+), 75 deletions(-) create mode 100644 assets/font.ttf create mode 100644 src/renderer/passes/ui.rs create mode 100644 src/renderer/ui.rs diff --git a/Cargo.lock b/Cargo.lock index 7d23ffd..7766202 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "ab_glyph" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a933731feda8b460bdad9a9e43bb386baba6ec593d2bc19716ef3c75c09085c" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser 0.12.0", +] + [[package]] name = "ab_glyph_rasterizer" version = "0.1.4" @@ -816,6 +826,45 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glyph_brush" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e3f00b8574a76fb6c50890c48da03946ca50e4372a2778737922666a2238221" +dependencies = [ + "glyph_brush_draw_cache", + "glyph_brush_layout", + "log", + "ordered-float", + "rustc-hash", + "twox-hash", +] + +[[package]] +name = "glyph_brush_draw_cache" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2c82074cafb68b9e459c50c655f7eedcb92d6ee7166813802934bc6fc29fa3" +dependencies = [ + "ab_glyph", + "crossbeam-channel", + "crossbeam-deque", + "linked-hash-map", + "rayon", + "rustc-hash", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bc06d530bf20c1902f1b02799ab7372ff43f6119770c49b0bc3f21bd148820" +dependencies = [ + "ab_glyph", + "approx", + "xi-unicode", +] + [[package]] name = "gpu-alloc" version = "0.3.0" @@ -1025,6 +1074,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "lock_api" version = "0.4.3" @@ -1373,13 +1428,31 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +[[package]] +name = "ordered-float" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8919aecb97e5ee9aceef27e24f39c46b11831130f4a6b7b091ec5de0de12" +dependencies = [ + "num-traits", +] + [[package]] name = "owned_ttf_parser" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "ttf-parser", + "ttf-parser 0.6.2", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3c7a20e3f122223e68eef6ca58e39bc1ea8a1d83418ba4c2c1ba189d2ee355" +dependencies = [ + "ttf-parser 0.12.0", ] [[package]] @@ -1637,6 +1710,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rusttype" version = "0.9.2" @@ -1644,7 +1723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser", + "owned_ttf_parser 0.6.0", ] [[package]] @@ -1758,6 +1837,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "storage-map" version = "0.3.0" @@ -1868,6 +1953,23 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "ttf-parser" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e00391c1f3d171490a3f8bd79999b0002ae38d3da0d6a3a306c754b053d71b" + +[[package]] +name = "twox-hash" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59" +dependencies = [ + "cfg-if 0.1.10", + "rand 0.7.3", + "static_assertions", +] + [[package]] name = "unicode-xid" version = "0.2.1" @@ -2117,6 +2219,18 @@ dependencies = [ "bitflags", ] +[[package]] +name = "wgpu_glyph" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354c1f79e09923724a6006a6953c3946522b84f7a9ec202b7e8001f274fd4bd5" +dependencies = [ + "bytemuck", + "glyph_brush", + "log", + "wgpu", +] + [[package]] name = "wgpufun" version = "0.1.0" @@ -2133,6 +2247,7 @@ dependencies = [ "rand 0.8.3", "shaderc", "wgpu", + "wgpu_glyph", "winit", ] @@ -2256,6 +2371,12 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57" +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + [[package]] name = "xml-rs" version = "0.8.3" diff --git a/Cargo.toml b/Cargo.toml index f2aec99..6ce601b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] winit = "0.24" wgpu = "0.7" +wgpu_glyph = "0.11" futures = "0.3" bytemuck = { version = "1.5", features = [ "derive" ] } byteorder = "1.4" @@ -17,6 +18,7 @@ cgmath = "0.18" rand = "0.8" noise = "0.7" + [build-dependencies] anyhow = "1.0" fs_extra = "1.1" diff --git a/assets/font.ttf b/assets/font.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9d6519685ea5279857034c8a01a59c2cdbd2b5db GIT binary patch literal 58088 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 literal 0 HcmV?d00001 diff --git a/src/main.rs b/src/main.rs index 7093130..4e220ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,7 +23,7 @@ fn main() { .build(&events) .expect("Failed to create window"); - let mut renderer = futures::executor::block_on(Renderer::new(&window)); + let mut renderer = Renderer::new(&window); let mut app = App::new(&mut renderer); // Stats @@ -84,9 +84,11 @@ fn main() { // Display FPS let elapsed = fps_timer.elapsed().as_secs_f64(); - if elapsed >= 1.5 { - let fps = (fps_counter as f64) / elapsed; - println!("FPS: {}", (fps*100.0_f64).floor()/100.0); + if elapsed >= 0.5 { + let mut fps = (fps_counter as f64) / elapsed; + fps = (fps*100.0_f64).floor() / 100.0; + renderer.ui.set_fps(fps as f32); + fps_timer = std::time::Instant::now(); fps_counter = 0; } diff --git a/src/renderer/buffers/content.rs b/src/renderer/buffers/content.rs index 9fcdc0d..032fd52 100644 --- a/src/renderer/buffers/content.rs +++ b/src/renderer/buffers/content.rs @@ -20,7 +20,6 @@ pub struct Content { impl Content { pub fn new(device: &wgpu::Device) -> Self { - // Create node buffer let node_buffer = vec![0_u32; (NODE_TEX_SIZE*NODE_TEX_SIZE*NODE_TEX_SIZE) as usize].into_boxed_slice(); @@ -43,10 +42,6 @@ impl Content { ); // Bind layout - // let sampler_entry = wgpu::BindGroupLayoutEntry { - // binding: 0,visibility: wgpu::ShaderStage::FRAGMENT, count: None, - // ty: wgpu::BindingType::Sampler { comparison: false, filtering: false }, - // }; let texture_entry = wgpu::BindGroupLayoutEntry { binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, ty: wgpu::BindingType::Texture { multisampled: false, view_dimension: wgpu::TextureViewDimension::D3, sample_type: wgpu::TextureSampleType::Uint }, @@ -56,8 +51,6 @@ impl Content { label: None, entries: &[ wgpu::BindGroupLayoutEntry { binding: 0, ..texture_entry }, wgpu::BindGroupLayoutEntry { binding: 1, ..texture_entry }, - //wgpu::BindGroupLayoutEntry { binding: 2, ..sampler_entry }, - //wgpu::BindGroupLayoutEntry { binding: 3, ..sampler_entry }, ], } ); @@ -69,8 +62,6 @@ impl Content { entries: &[ wgpu::BindGroupEntry { binding: 0, resource: wgpu::BindingResource::TextureView(&node_texture.create_view(&wgpu::TextureViewDescriptor::default())) }, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::TextureView(&block_texture.create_view(&wgpu::TextureViewDescriptor::default())) }, - //wgpu::BindGroupEntry { binding: 2, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) }, - //wgpu::BindGroupEntry { binding: 3, resource: wgpu::BindingResource::Sampler(&device.create_sampler(&Default::default())) } ], } ); diff --git a/src/renderer/buffers/materials.rs b/src/renderer/buffers/materials.rs index b960050..51edbfe 100644 --- a/src/renderer/buffers/materials.rs +++ b/src/renderer/buffers/materials.rs @@ -37,39 +37,33 @@ impl Materials { // Create buffer let buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor { - label: Some("Materials buffer"), - contents: bytemuck::cast_slice(&materials), + label: Some("Materials buffer"), contents: bytemuck::cast_slice(&materials), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, } ); - // Create bind group - let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - } + // Bind layout + let buffer_entry = wgpu::BindGroupLayoutEntry { + binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, + ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None }, + }; + let bind_layout = device.create_bind_group_layout( + &wgpu::BindGroupLayoutDescriptor { + label: None, entries: &[ + wgpu::BindGroupLayoutEntry { binding: 0, ..buffer_entry }, ], - label: Some("Materials buffer layout"), - }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - } - ], - label: Some("Materials buffer group"), }); + // Bind group + let bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + label: Some("Materials buffer group"),layout: &bind_layout, + entries: &[ + wgpu::BindGroupEntry { binding: 0, resource: buffer.as_entire_binding() } + ], + } + ); + // Done Materials { buffer, materials, bind_layout, bind_group } } diff --git a/src/renderer/buffers/uniform.rs b/src/renderer/buffers/uniform.rs index 3889c51..78b57d4 100644 --- a/src/renderer/buffers/uniform.rs +++ b/src/renderer/buffers/uniform.rs @@ -47,39 +47,32 @@ impl Uniform { // Create buffer let buffer = device.create_buffer_init( &wgpu::util::BufferInitDescriptor { - label: Some("Uniform buffer"), - contents: bytemuck::cast_slice(&[values]), + label: Some("Uniform buffer"), contents: bytemuck::cast_slice(&[values]), usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, } ); - // Create bind group + // Bind layout + let buffer_entry = wgpu::BindGroupLayoutEntry { + binding: 0, visibility: wgpu::ShaderStage::FRAGMENT, count: None, + ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: None }, + }; let bind_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[ - wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - } + label: None, entries: &[ + wgpu::BindGroupLayoutEntry { binding: 0, ..buffer_entry } ], - label: Some("Uniform buffer layout"), - }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_layout, - entries: &[ - wgpu::BindGroupEntry { - binding: 0, - resource: buffer.as_entire_binding(), - } - ], - label: Some("Uniform buffer group"), }); + // Bind group + let bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + label: None, layout: &bind_layout, + entries: &[ + wgpu::BindGroupEntry { binding: 0, resource: buffer.as_entire_binding(), } + ], + } + ); + // Done Uniform { buffer, values, bind_layout, bind_group } } diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 169bf4c..13e473c 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -1,3 +1,4 @@ +use wgpu_glyph::Text; use winit::{window::Window, dpi::PhysicalSize}; pub mod buffers; use buffers::Buffers; @@ -6,6 +7,8 @@ use passes::{RaytracePass, PostprocessPass}; pub mod camera; use camera::Camera; pub mod content_view; +mod ui; +use ui::UserInterface; pub struct Renderer { surface: wgpu::Surface, @@ -17,6 +20,7 @@ pub struct Renderer { texture: wgpu::TextureView, raytrace_pass: RaytracePass, postprocess_pass: PostprocessPass, + pub ui: UserInterface, // Buffers buffers: Buffers, // Other @@ -29,18 +33,21 @@ impl Renderer { /* * Initializes renderer and all buffers */ - pub async fn new(window: &Window) -> Self { + pub fn new(window: &Window) -> Self { // Create surface let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); let surface = unsafe { instance.create_surface(window) }; // Pick and initialize device - let adapter_options = wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface) }; - let adapter = instance.request_adapter(&adapter_options).await.unwrap(); - let device_desc = wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: wgpu::Limits::default(), label: None }; - let (device, queue) = adapter.request_device(&device_desc, None).await.unwrap(); - + let (adapter, mut device, queue) = futures::executor::block_on(async { + let adapter_options = wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::HighPerformance, compatible_surface: Some(&surface) }; + let adapter = instance.request_adapter(&adapter_options).await.unwrap(); + let device_desc = wgpu::DeviceDescriptor { features: wgpu::Features::empty(), limits: wgpu::Limits::default(), label: None }; + let (device, queue) = adapter.request_device(&device_desc, None).await.unwrap(); + (adapter, device, queue) + }); + // Create swapchain let window_size = window.inner_size(); let swapchain_desc = wgpu::SwapChainDescriptor { @@ -75,12 +82,13 @@ impl Renderer { let buffers = Buffers::new(&device); let raytrace_pass = RaytracePass::new(&device, &swapchain_desc, &buffers); let postprocess_pass = PostprocessPass::new(&device, &swapchain_desc, &texture); + let ui = UserInterface::new(&mut device, swapchain_desc.format); // Other let start = std::time::Instant::now(); println!("Renderer initialized"); - Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, buffers, camera, start } + Self { surface, device, queue, swapchain_desc, swapchain, texture, raytrace_pass, postprocess_pass, ui, buffers, camera, start } } /* @@ -114,12 +122,13 @@ impl Renderer { // Create encoder that will build command buffer for us let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder"),}); - self.raytrace_pass.render(&mut encoder, &mut self.buffers, &self.texture);//&frame.view); self.postprocess_pass.render(&mut encoder, &frame.view); + self.ui.render(&self.device, &mut encoder, &frame.view, 1280, 720); // Submit encoder (command buffer) self.queue.submit(std::iter::once(encoder.finish())); + self.ui.recall(); // Return ok Ok(()) diff --git a/src/renderer/passes/ui.rs b/src/renderer/passes/ui.rs new file mode 100644 index 0000000..4112dfe --- /dev/null +++ b/src/renderer/passes/ui.rs @@ -0,0 +1,9 @@ +use crate::renderer::buffers::Buffers; + +pub struct UserInterfacePass { + pub pipeline: wgpu::RenderPipeline +} + +impl UserInterfacePass { + +} \ No newline at end of file diff --git a/src/renderer/ui.rs b/src/renderer/ui.rs new file mode 100644 index 0000000..a1c6614 --- /dev/null +++ b/src/renderer/ui.rs @@ -0,0 +1,56 @@ +use wgpu_glyph::{GlyphBrush, ab_glyph::FontArc, GlyphBrushBuilder, Section, Text}; +use wgpu::util::StagingBelt; +use futures::executor::LocalPool; +use futures::task::SpawnExt; + +const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; + +pub struct UserInterface { + // Glyph drawing + staging_belt: StagingBelt, + local_pool: LocalPool, + brush: GlyphBrush<()>, + // Texts + fps_text: String +} + +impl UserInterface { + + pub fn new(device: &mut wgpu::Device, render_format: wgpu::TextureFormat) -> Self { + let font = FontArc::try_from_slice(include_bytes!("../../assets/font.ttf")).unwrap(); + Self { + staging_belt: StagingBelt::new(1024), + local_pool: LocalPool::new(), + brush: GlyphBrushBuilder::using_font(font).build(device, render_format), + fps_text: "-".to_string() + } + } + + fn print(&mut self, x: u32, y: u32, msg: &str) { + let text = Text::new(msg).with_color(WHITE); + self.brush.queue(Section { + screen_position: (x as f32, y as f32), + bounds: (text.scale.x * text.text.len() as f32, text.scale.y), + text: vec![text], + ..Section::default() + }); + } + + pub fn set_fps(&mut self, fps: f32) { + self.fps_text = format!("FPS: {}", fps); + } + + pub fn render(&mut self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, width: u32, height: u32) { + // Print texts + self.print(5, 5, &self.fps_text.clone()); + // Draw + self.brush.draw_queued(&device, &mut self.staging_belt, encoder, target, width, height).expect("Draw queued"); + self.staging_belt.finish(); + } + + pub fn recall(&mut self) { + // Reset staging belt after drawing + self.local_pool.spawner().spawn(self.staging_belt.recall()).expect("Recall staging belt"); + self.local_pool.run_until_stalled(); + } +} \ No newline at end of file diff --git a/src/shaders/raytrace/.bin/main.frag.spv b/src/shaders/raytrace/.bin/main.frag.spv index bbac1344331fec940201d1da9f8e9865cf1d47bd..c7c65e87503bd2eae8774921d15f0f798b217c59 100644 GIT binary patch delta 2083 zcmZ9N&u>&!6vyvOr&EelkQypzbp#P~kjk{ejMx?ei7|~~N?d3(!HKN_LK!lJ5LPe5 zxNxDS8CUL%3u5BN^dE3x!p6AJ1%X(9|5g-ZB8Z57KCkcM(3jkt@ArGoJ@?%E&VBFN z;r9>sb>%nogpdo%Lthx1>zl|`-+N}F_{5jF5RSDD%`{r4LU$;HujP$aVUFZ@yPFiUpn*R zc+6AEha@=3K%FHP+=xvVCGpOTyCJohXcIhykM|hA8BD!t;nBZEf9cF#`7m%Bynv1V z5&gT~+*=9*g|GwC1%Hm=g7Rv6?aEDwsUKjRCI2UQNAY?-4`%wyoUFVIwM_|PU^Vv^lWhl^P~RAv z^c>Y{Y{VB?1DCOr+2W7tWB5#liN)RR%tQ}420oT)#@0hmdUm4_6Bw`G?r>2%Z*=~Z zRp$nGdyTkW=`r7j^%_O4^%_OK8tygfTg%fbe=hNOrDCL+y;704^>uLlUZ?2S zdYvMlgs++3Hgq=EThBUvq5amzf#fq1eacv1_!>OI&%qxt>Kx$)_!nT~)ZP7gteWxq zzX7Z1bNh0!TlXH;SaBV3-+?z{jnPL;5o*V8@x={;^*bzmr zk?Ll#HPy^wM=S@c>9Z~6Vq4NLZ|sN_U^~JXea6_<>Q>-U_xaUO?CgkJ;W%z|#7eMQ z?1C4^6o&7#bxM(`l#0~~S}6u}kjhY@m#5!cEAzheH zVocnqG2=#euGqLSvo>*I;>NJhh0*vg{)<3NL=e&E`R2Q1pv}#F-}jt*?z!jQ^UeE* zE*vWK_Kf$3kPE9rA6dA(U*3L)h`U%^ko zpKLtcXtqw~cPHnru>K1_aPZk$W7*aG_k^%~puX5R@=$#xi@5rd*4beVynDyN%Xn|N z0sh?KPQ2T|&H6Kojio1+_wQfKr<+vTZ}zuyxk~$if!F#TU&S_Gl12zG%xw$#FaY`r zuJ&+dD{|00_y@E_X1VKn2!G_GVkz3MhL_M|oDHp^!I5MP^^x-AOk8yfy!OgSHS$gH z)5o5w##Q5R*XXBhjNP^}n}NGlGVbBjVw~IIA$)wV{zWj!>VN+whY20Vj_q;5PT(ZG zk2wa|t$p^bJqEZN+zWk-;fC@`>&)Pm#L(Lq9}@o)tkYOc>yAu+i6YCl!%azj4$XCU zGF-Q-Yu%1akLyZsGgUvD#o7rr9=0S6HcNoJ5cV;9jF`kOuzCzO1y=KDF<2RFKy5P| z(mJY@If%D^54gy@kZnE8?LUFhlGJFu6m+y!c4?U;MsfTFyp>rWZTeVmbxx6<=2x)VBz|sS zPyGg0e+Qor;J<^_eDG(9@dr4BEg_s|fyR>z#lJ&OiVf}+ok2U%8Y)fXJwr9L?kjCt zui>l)#^;Q*46Wx&BT3BZd}i&==^r$8&)`kV%e0yWya2wQ`84yN3}1#m`uYjh9#gsq zcIPVo@dEyXqj#Fi^f<=l=^^FN)L-RnZrTf0^E3EjruBghrp?WLf@*Q2JXp_T;e`i|8M>T@W7)wKDBTbOTFa2(Y6Def! diff --git a/src/shaders/raytrace/main.frag b/src/shaders/raytrace/main.frag index 5aaffbd..5bef744 100644 --- a/src/shaders/raytrace/main.frag +++ b/src/shaders/raytrace/main.frag @@ -36,7 +36,7 @@ vec3 solve() // Calculate ray direction vec3 view_dir = (_ProjMatrixInv * vec4(_InUV, 0, 1)).xyz; vec3 rayDir = normalize(_ViewMatrix * vec4(view_dir,0)).xyz; - Ray primaryRay = Ray((_CamPos + vec3(16, 0, 16)) / SCALE, rayDir); + Ray primaryRay = Ray(_CamPos / SCALE, rayDir); // Raycast HitResult primary = castNodes(primaryRay, 100);