Compare commits
15 Commits
ad9515d8d6
...
b59d0b1a10
| Author | SHA1 | Date | |
|---|---|---|---|
| b59d0b1a10 | |||
| 2b185c43da | |||
| 91fa161db9 | |||
| 211c0b921e | |||
| 06715b9797 | |||
| 127b7a4077 | |||
| 9576078f9c | |||
| 378511bedf | |||
| 786f1d6050 | |||
| 62fea44949 | |||
| abf5702fdd | |||
| 97cdbcff75 | |||
| 7ecbd50c05 | |||
| bd5a140c84 | |||
| 884ea5e15b |
99
Cargo.lock
generated
99
Cargo.lock
generated
|
|
@ -18,6 +18,12 @@ version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler2"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.11"
|
version = "0.8.11"
|
||||||
|
|
@ -180,6 +186,12 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder-lite"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
|
|
@ -316,6 +328,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.21"
|
version = "0.8.21"
|
||||||
|
|
@ -380,6 +401,25 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fdeflate"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
|
||||||
|
dependencies = [
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foldhash"
|
name = "foldhash"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
|
@ -547,6 +587,20 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.25.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder-lite",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
"zune-core",
|
||||||
|
"zune-jpeg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.7.0"
|
version = "2.7.0"
|
||||||
|
|
@ -715,6 +769,16 @@ dependencies = [
|
||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
|
||||||
|
dependencies = [
|
||||||
|
"adler2",
|
||||||
|
"simd-adler32",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "23.1.0"
|
version = "23.1.0"
|
||||||
|
|
@ -1109,6 +1173,19 @@ version = "0.3.31"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "png"
|
||||||
|
version = "0.17.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"crc32fast",
|
||||||
|
"fdeflate",
|
||||||
|
"flate2",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "3.7.4"
|
version = "3.7.4"
|
||||||
|
|
@ -1254,6 +1331,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"glam",
|
"glam",
|
||||||
|
"image",
|
||||||
"pollster",
|
"pollster",
|
||||||
"rand",
|
"rand",
|
||||||
"rand_distr",
|
"rand_distr",
|
||||||
|
|
@ -1365,6 +1443,12 @@ version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd-adler32"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
|
|
@ -2318,3 +2402,18 @@ dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-core"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-jpeg"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028"
|
||||||
|
dependencies = [
|
||||||
|
"zune-core",
|
||||||
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@
|
||||||
name = "raytracing3"
|
name = "raytracing3"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "raytracing3"
|
default-run = "minitracer"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytemuck = { version = "1.21.0", features = ["derive"] }
|
bytemuck = { version = "1.21.0", features = ["derive"] }
|
||||||
glam = { version = "0.29.2", features = ["bytemuck"] }
|
glam = { version = "0.29.2", features = ["bytemuck"] }
|
||||||
|
image = { version = "0.25.5", default-features = false, features = ["png", "jpeg"] }
|
||||||
pollster = "0.4.0"
|
pollster = "0.4.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rand_distr = { version = "0.4.3", features = ["std_math"] }
|
rand_distr = { version = "0.4.3", features = ["std_math"] }
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Ray tracing example
|
# Ray tracing example
|
||||||
|
|
||||||
Basic GPU-side ray tracing example. `cargo run` to see it moving!
|
Basic GPU-side ray tracing example. `cargo run --bin envmap` to prepare the sky, then `cargo run` to see it moving!
|
||||||
|
|
||||||

|

|
||||||
|
|
|
||||||
|
|
@ -5,24 +5,31 @@ struct Params {
|
||||||
scale: f32,
|
scale: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LookParams {
|
||||||
|
origin: vec3f,
|
||||||
|
radius: f32,
|
||||||
|
}
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
@location(0) screen: vec2f,
|
@location(0) screen: vec2f,
|
||||||
@location(1) world: vec3f,
|
@location(1) dir: vec3f,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Varying {
|
struct Varying {
|
||||||
@location(0) world: vec3f,
|
@location(0) dir: vec3f,
|
||||||
@builtin(position) screen: vec4f,
|
@builtin(position) screen: vec4f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var<uniform> params: LookParams;
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn on_vertex(in: Vertex) -> Varying {
|
fn on_vertex(in: Vertex) -> Varying {
|
||||||
return Varying(in.world, vec4(in.screen, 0.0, 1.0));
|
return Varying(in.dir, vec4(in.screen, 0.0, 1.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn on_fragment(in: Varying) -> @location(0) vec4f {
|
fn on_fragment(in: Varying) -> @location(0) vec4f {
|
||||||
let point = 30. * (normalize(in.world + vec3(0., 0., 30.)) - vec3(0., 0., 1.));
|
let point = params.origin + params.radius * normalize(in.dir);
|
||||||
let sharp_area = perlin_noise(Params(1, 3, 0.9, 2.0), 0.1 * point);
|
let sharp_area = perlin_noise(Params(1, 3, 0.9, 2.0), 0.1 * point);
|
||||||
let sharp_base = perlin_noise(Params(1, 6, 0.9, 2.0), 0.1 * point);
|
let sharp_base = perlin_noise(Params(1, 6, 0.9, 2.0), 0.1 * point);
|
||||||
let cloud_base = perlin_noise(Params(2, 8, 0.6, 2.0), 0.1 * point);
|
let cloud_base = perlin_noise(Params(2, 8, 0.6, 2.0), 0.1 * point);
|
||||||
|
|
@ -1,66 +1,45 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use glam::{vec2, vec3};
|
use glam::{vec2, vec3};
|
||||||
use trace::{Tracer, TracerData, Vertex};
|
use raytracing3::perlin::{self, Pipeline, Vertex};
|
||||||
use winit::{
|
use winit::{
|
||||||
event::{Event, WindowEvent},
|
event::{Event, WindowEvent},
|
||||||
event_loop::EventLoop,
|
event_loop::EventLoop,
|
||||||
window::{Window, WindowAttributes},
|
window::{Window, WindowAttributes},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod anim;
|
|
||||||
mod trace;
|
|
||||||
|
|
||||||
pub use trace::Sphere;
|
|
||||||
|
|
||||||
fn make_viewport(w: u32, h: u32) -> [Vertex; 4] {
|
fn make_viewport(w: u32, h: u32) -> [Vertex; 4] {
|
||||||
let w = w as f32;
|
let w = w as f32;
|
||||||
let h = h as f32;
|
let h = h as f32;
|
||||||
|
let d = 3.;
|
||||||
let (w, h) = (1.0f32.max(w / h), 1.0f32.max(h / w));
|
let (w, h) = (1.0f32.max(w / h), 1.0f32.max(h / w));
|
||||||
let r = 3.0f32;
|
let screen_coord = [vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)];
|
||||||
let screen_coord = [vec2(-h, -w), vec2(h, -w), vec2(-h, w), vec2(h, w)];
|
let world_coord = [vec3(-w, -h, d), vec3(w, -h, d), vec3(-w, h, d), vec3(w, h, d)];
|
||||||
let eye = vec3(-r, 0.0, 0.0);
|
|
||||||
let world_coord = [
|
|
||||||
vec3(0.0, -1.0, -1.0),
|
|
||||||
vec3(0.0, 1.0, -1.0),
|
|
||||||
vec3(0.0, -1.0, 1.0),
|
|
||||||
vec3(0.0, 1.0, 1.0),
|
|
||||||
];
|
|
||||||
[0, 1, 2, 3].map(|k| Vertex {
|
[0, 1, 2, 3].map(|k| Vertex {
|
||||||
eye,
|
dir: world_coord[k],
|
||||||
world: world_coord[k],
|
|
||||||
screen: screen_coord[k],
|
screen: screen_coord[k],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const N_SPHERES: u32 = 100;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
let window = &event_loop
|
let window = &event_loop
|
||||||
.create_window(WindowAttributes::new().with_title("Ray tracing reflection test"))
|
.create_window(WindowAttributes::new().with_title("Noise generation test"))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
||||||
|
|
||||||
let mut tracer = Tracer::new(&device);
|
let format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
tracer.set_params(
|
let mut noiser = Pipeline::new(&device, format);
|
||||||
|
noiser.set_params(
|
||||||
&queue,
|
&queue,
|
||||||
trace::Params {
|
perlin::Params {
|
||||||
max_reflections: 3,
|
origin: vec3(0., 0., -30.),
|
||||||
min_strength: 0.1,
|
radius: 30.,
|
||||||
sphere_count: N_SPHERES,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let sphere_params: Vec<_> = {
|
|
||||||
let mut rng = rand_pcg::Pcg32::new(42, 0);
|
|
||||||
let distr = anim::SphereParamsDistribution::default();
|
|
||||||
(0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut time = 0.0;
|
|
||||||
|
|
||||||
let mut surface_configured = false;
|
let mut surface_configured = false;
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
|
|
@ -73,7 +52,7 @@ fn main() {
|
||||||
&device,
|
&device,
|
||||||
&wgpu::SurfaceConfiguration {
|
&wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format,
|
||||||
width: physical_size.width,
|
width: physical_size.width,
|
||||||
height: physical_size.height,
|
height: physical_size.height,
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
|
|
@ -82,18 +61,13 @@ fn main() {
|
||||||
desired_maximum_frame_latency: 2,
|
desired_maximum_frame_latency: 2,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
tracer.set_view(&queue, &make_viewport(physical_size.width, physical_size.height));
|
noiser.set_view(&queue, &make_viewport(physical_size.width, physical_size.height));
|
||||||
surface_configured = true;
|
surface_configured = true;
|
||||||
}
|
}
|
||||||
WindowEvent::RedrawRequested => {
|
WindowEvent::RedrawRequested => {
|
||||||
window.request_redraw();
|
|
||||||
if !surface_configured {
|
if !surface_configured {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
time += 1. / 60.;
|
|
||||||
let spheres: Vec<_> = sphere_params.iter().map(|p| p.to_sphere(time)).collect();
|
|
||||||
let data = TracerData::new(&device, &tracer, &spheres);
|
|
||||||
|
|
||||||
let output = surface.get_current_texture().unwrap();
|
let output = surface.get_current_texture().unwrap();
|
||||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
|
@ -111,7 +85,8 @@ fn main() {
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
});
|
});
|
||||||
tracer.render(&mut render_pass, &data);
|
noiser.render(&mut render_pass);
|
||||||
|
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
queue.submit(std::iter::once(encoder.finish()));
|
queue.submit(std::iter::once(encoder.finish()));
|
||||||
output.present();
|
output.present();
|
||||||
|
|
@ -1,78 +1,70 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use glam::{vec2, vec3};
|
use glam::{mat3, vec2, vec3, Mat3, Vec3};
|
||||||
use perlin::{Pipeline, Vertex};
|
use image::buffer::ConvertBuffer;
|
||||||
use winit::{
|
use raytracing3::perlin::{self, Pipeline, Vertex};
|
||||||
event::{Event, WindowEvent},
|
|
||||||
event_loop::EventLoop,
|
|
||||||
window::{Window, WindowAttributes},
|
|
||||||
};
|
|
||||||
|
|
||||||
mod perlin;
|
const EXTENT: u32 = 1024;
|
||||||
|
|
||||||
fn make_viewport(w: u32, h: u32) -> [Vertex; 4] {
|
fn make_viewport(m: Mat3) -> [Vertex; 4] {
|
||||||
let w = w as f32;
|
|
||||||
let h = h as f32;
|
|
||||||
let (w, h) = (1.0f32.max(w / h), 1.0f32.max(h / w));
|
|
||||||
let screen_coord = [vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)];
|
let screen_coord = [vec2(-1., -1.), vec2(1., -1.), vec2(-1., 1.), vec2(1., 1.)];
|
||||||
let world_coord = [vec3(-w, -h, 0.), vec3(w, -h, 0.), vec3(-w, h, 0.), vec3(w, h, 0.)];
|
let world_coord = screen_coord.map(|s| m * vec3(s.x, s.y, 1.));
|
||||||
[0, 1, 2, 3].map(|k| Vertex {
|
[0, 1, 2, 3].map(|k| Vertex {
|
||||||
world: 10. * world_coord[k],
|
dir: world_coord[k],
|
||||||
screen: screen_coord[k],
|
screen: screen_coord[k],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let event_loop = EventLoop::new().unwrap();
|
let (device, queue) = pollster::block_on(init_gpu()).unwrap();
|
||||||
|
|
||||||
#[allow(deprecated)]
|
let format = wgpu::TextureFormat::Rgba8UnormSrgb;
|
||||||
let window = &event_loop
|
let mut noiser = Pipeline::new(&device, format);
|
||||||
.create_window(WindowAttributes::new().with_title("Noise generation test"))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
|
||||||
|
|
||||||
let mut noiser = Pipeline::new(&device);
|
|
||||||
noiser.set_params(
|
noiser.set_params(
|
||||||
&queue,
|
&queue,
|
||||||
perlin::Params {
|
perlin::Params {
|
||||||
seed: 42,
|
origin: vec3(0., 0., -30.),
|
||||||
layers: 8,
|
radius: 30.,
|
||||||
roughness: 0.9,
|
|
||||||
scale: 1.7,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
let faces = [
|
||||||
let mut surface_configured = false;
|
mat3(-Vec3::Z, -Vec3::Y, Vec3::X),
|
||||||
#[allow(deprecated)]
|
mat3(Vec3::Z, -Vec3::Y, -Vec3::X),
|
||||||
event_loop
|
mat3(Vec3::X, Vec3::Z, Vec3::Y),
|
||||||
.run(move |event, control_flow| match event {
|
mat3(Vec3::X, -Vec3::Z, -Vec3::Y),
|
||||||
Event::WindowEvent { ref event, window_id } if window_id == window.id() => match event {
|
mat3(Vec3::X, -Vec3::Y, Vec3::Z),
|
||||||
WindowEvent::CloseRequested => control_flow.exit(),
|
mat3(-Vec3::X, -Vec3::Y, -Vec3::Z),
|
||||||
WindowEvent::Resized(physical_size) => {
|
];
|
||||||
surface.configure(
|
let output = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
&device,
|
label: None,
|
||||||
&wgpu::SurfaceConfiguration {
|
size: wgpu::Extent3d {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
width: EXTENT,
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
height: EXTENT,
|
||||||
width: physical_size.width,
|
depth_or_array_layers: 6,
|
||||||
height: physical_size.height,
|
|
||||||
present_mode: wgpu::PresentMode::Fifo,
|
|
||||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
|
||||||
view_formats: vec![],
|
|
||||||
desired_maximum_frame_latency: 2,
|
|
||||||
},
|
},
|
||||||
);
|
mip_level_count: 1,
|
||||||
noiser.set_view(&queue, &make_viewport(physical_size.width, physical_size.height));
|
sample_count: 1,
|
||||||
surface_configured = true;
|
dimension: wgpu::TextureDimension::D2,
|
||||||
}
|
format,
|
||||||
WindowEvent::RedrawRequested => {
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||||
if !surface_configured {
|
view_formats: &[],
|
||||||
return;
|
});
|
||||||
}
|
let buffers = faces.map(|_| {
|
||||||
let output = surface.get_current_texture().unwrap();
|
device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
label: None,
|
||||||
|
size: (4 * EXTENT * EXTENT) as u64,
|
||||||
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
for (face, m) in faces.iter().enumerate() {
|
||||||
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
let buffer = &buffers[face];
|
||||||
|
let view = output.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::D2),
|
||||||
|
base_array_layer: face as u32,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
|
@ -87,29 +79,61 @@ fn main() {
|
||||||
occlusion_query_set: None,
|
occlusion_query_set: None,
|
||||||
timestamp_writes: None,
|
timestamp_writes: None,
|
||||||
});
|
});
|
||||||
|
noiser.set_view(&queue, &make_viewport(*m));
|
||||||
noiser.render(&mut render_pass);
|
noiser.render(&mut render_pass);
|
||||||
|
|
||||||
drop(render_pass);
|
drop(render_pass);
|
||||||
queue.submit(std::iter::once(encoder.finish()));
|
encoder.copy_texture_to_buffer(
|
||||||
output.present();
|
wgpu::ImageCopyTexture {
|
||||||
}
|
texture: &output,
|
||||||
_ => {}
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: face as u32,
|
||||||
},
|
},
|
||||||
_ => {}
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
wgpu::ImageCopyBuffer {
|
||||||
|
buffer: &buffer,
|
||||||
|
layout: wgpu::ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(4 * EXTENT),
|
||||||
|
rows_per_image: Some(EXTENT),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: EXTENT,
|
||||||
|
height: EXTENT,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
queue.submit([encoder.finish()]);
|
||||||
|
}
|
||||||
|
for buf in &buffers {
|
||||||
|
buf.slice(..).map_async(wgpu::MapMode::Read, |res| res.unwrap());
|
||||||
|
}
|
||||||
|
device.poll(wgpu::Maintain::Wait);
|
||||||
|
std::thread::scope(|s| {
|
||||||
|
for (face, buf) in buffers.iter().enumerate() {
|
||||||
|
s.spawn(move || {
|
||||||
|
let img =
|
||||||
|
image::RgbaImage::from_raw(EXTENT, EXTENT, buf.slice(..).get_mapped_range().to_vec()).unwrap();
|
||||||
|
let img: image::RgbImage = img.convert();
|
||||||
|
img.save(format!("textures/env{face}.jpeg")).unwrap();
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surface), Box<dyn Error>> {
|
async fn init_gpu() -> Result<(wgpu::Device, wgpu::Queue), Box<dyn Error>> {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: wgpu::Backends::PRIMARY,
|
backends: wgpu::Backends::PRIMARY,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
let surface = instance.create_surface(wnd)?;
|
|
||||||
let adapter = instance
|
let adapter = instance
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
power_preference: wgpu::PowerPreference::default(),
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
compatible_surface: Some(&surface),
|
compatible_surface: None,
|
||||||
force_fallback_adapter: false,
|
force_fallback_adapter: false,
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
|
@ -126,5 +150,5 @@ async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surf
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
Ok((device, queue, surface))
|
Ok((device, queue))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use glam::{vec3, Vec3};
|
use glam::{vec3, Vec3};
|
||||||
use rand_distr::{Distribution, LogNormal, Uniform};
|
use rand_distr::{Bernoulli, Distribution, Uniform};
|
||||||
|
|
||||||
pub struct SphereParams {
|
pub struct SphereParams {
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub color: Vec3,
|
pub color: Vec3,
|
||||||
pub alpha: f32,
|
pub alpha: f32,
|
||||||
|
pub glossiness: f32,
|
||||||
pub origin: Vec3,
|
pub origin: Vec3,
|
||||||
pub amplitudes: Vec3,
|
pub amplitudes: Vec3,
|
||||||
pub frequencies: Vec3,
|
pub frequencies: Vec3,
|
||||||
|
|
@ -15,10 +16,11 @@ pub struct SphereParamsDistribution {
|
||||||
pub drad: Uniform<f32>,
|
pub drad: Uniform<f32>,
|
||||||
pub dpos: Uniform<f32>,
|
pub dpos: Uniform<f32>,
|
||||||
pub dcol: Uniform<f32>,
|
pub dcol: Uniform<f32>,
|
||||||
pub demit: LogNormal<f32>,
|
pub demit: Bernoulli,
|
||||||
pub dampl: Uniform<f32>,
|
pub dampl: Uniform<f32>,
|
||||||
pub dfreq: Uniform<f32>,
|
pub dfreq: Uniform<f32>,
|
||||||
pub dphase: Uniform<f32>,
|
pub dphase: Uniform<f32>,
|
||||||
|
pub dgloss: Uniform<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SphereParamsDistribution {
|
impl Default for SphereParamsDistribution {
|
||||||
|
|
@ -27,10 +29,11 @@ impl Default for SphereParamsDistribution {
|
||||||
drad: Uniform::new(0.01, 0.10),
|
drad: Uniform::new(0.01, 0.10),
|
||||||
dpos: Uniform::new(-1.0, 1.0),
|
dpos: Uniform::new(-1.0, 1.0),
|
||||||
dcol: Uniform::new(0.0, 1.0),
|
dcol: Uniform::new(0.0, 1.0),
|
||||||
demit: LogNormal::new(-0.8, 2.0).unwrap(),
|
demit: Bernoulli::new(0.1).unwrap(),
|
||||||
dampl: Uniform::new(0.3, 0.8),
|
dampl: Uniform::new(0.3, 0.8),
|
||||||
dfreq: Uniform::new(0.2, 1.5),
|
dfreq: Uniform::new(0.2, 1.5),
|
||||||
dphase: Uniform::new(0., 2. * std::f32::consts::PI),
|
dphase: Uniform::new(0., 2. * std::f32::consts::PI),
|
||||||
|
dgloss: Uniform::new(0., 1.),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,7 +44,8 @@ impl SphereParamsDistribution {
|
||||||
origin: self.dpos.sample3(rgen),
|
origin: self.dpos.sample3(rgen),
|
||||||
radius: self.drad.sample(rgen),
|
radius: self.drad.sample(rgen),
|
||||||
color: self.dcol.sample3(rgen).normalize(),
|
color: self.dcol.sample3(rgen).normalize(),
|
||||||
alpha: self.demit.sample(rgen),
|
alpha: if self.demit.sample(rgen) { 10.0 } else { 0.0 },
|
||||||
|
glossiness: self.dgloss.sample(rgen),
|
||||||
amplitudes: self.dampl.sample3(rgen),
|
amplitudes: self.dampl.sample3(rgen),
|
||||||
frequencies: self.dfreq.sample3(rgen),
|
frequencies: self.dfreq.sample3(rgen),
|
||||||
phases: self.dphase.sample3(rgen),
|
phases: self.dphase.sample3(rgen),
|
||||||
|
|
@ -54,12 +58,14 @@ impl SphereParams {
|
||||||
let center = self.origin + self.amplitudes * (self.frequencies * time + self.phases).map(|x| x.sin());
|
let center = self.origin + self.amplitudes * (self.frequencies * time + self.phases).map(|x| x.sin());
|
||||||
let radius = self.radius;
|
let radius = self.radius;
|
||||||
let emit_color = self.alpha * self.color;
|
let emit_color = self.alpha * self.color;
|
||||||
|
let glossiness = self.glossiness;
|
||||||
let reflect_color = 0.6 * self.color + Vec3::splat(0.2);
|
let reflect_color = 0.6 * self.color + Vec3::splat(0.2);
|
||||||
crate::Sphere {
|
crate::Sphere {
|
||||||
center,
|
center,
|
||||||
radius,
|
radius,
|
||||||
emit_color,
|
emit_color,
|
||||||
reflect_color,
|
reflect_color,
|
||||||
|
glossiness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
272
src/bin/minitracer/main.rs
Normal file
272
src/bin/minitracer/main.rs
Normal file
|
|
@ -0,0 +1,272 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use glam::{vec2, vec3};
|
||||||
|
use image::ImageReader;
|
||||||
|
use present::Presenter;
|
||||||
|
use trace::{Tracer, TracerData, TracerEnv, Vertex};
|
||||||
|
use winit::{
|
||||||
|
event::{Event, WindowEvent},
|
||||||
|
event_loop::EventLoop,
|
||||||
|
window::{Window, WindowAttributes},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod anim;
|
||||||
|
mod present;
|
||||||
|
mod trace;
|
||||||
|
|
||||||
|
pub use trace::Sphere;
|
||||||
|
|
||||||
|
fn make_viewport(w: u32, h: u32) -> [Vertex; 4] {
|
||||||
|
let w = w as f32;
|
||||||
|
let h = h as f32;
|
||||||
|
let (w, h) = (1.0f32.max(w / h), 1.0f32.max(h / w));
|
||||||
|
let r = 1.0f32;
|
||||||
|
let screen_coord = [vec2(-h, -w), vec2(h, -w), vec2(-h, w), vec2(h, w)];
|
||||||
|
let eye = vec3(-r, 0.0, 0.0);
|
||||||
|
let world_coord = [
|
||||||
|
vec3(0.0, -1.0, -1.0),
|
||||||
|
vec3(0.0, 1.0, -1.0),
|
||||||
|
vec3(0.0, -1.0, 1.0),
|
||||||
|
vec3(0.0, 1.0, 1.0),
|
||||||
|
];
|
||||||
|
[0, 1, 2, 3].map(|k| Vertex {
|
||||||
|
eye,
|
||||||
|
world: world_coord[k],
|
||||||
|
screen: screen_coord[k],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const N_SPHERES: u32 = 100;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let event_loop = EventLoop::new().unwrap();
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
let window = &event_loop
|
||||||
|
.create_window(WindowAttributes::new().with_title("Ray tracing reflection test"))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let (device, queue, surface) = pollster::block_on(init_gpu(window)).unwrap();
|
||||||
|
let envmap = load_envmap(&device, &queue);
|
||||||
|
queue.submit([]);
|
||||||
|
|
||||||
|
let output_format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||||
|
let hdr_format = wgpu::TextureFormat::Rgba16Float;
|
||||||
|
let mut tracer = Tracer::new(&device, hdr_format);
|
||||||
|
let sphere_params: Vec<_> = {
|
||||||
|
let mut rng = rand_pcg::Pcg32::new(42, 0);
|
||||||
|
let distr = anim::SphereParamsDistribution::default();
|
||||||
|
(0..N_SPHERES).map(|_| distr.make_params(&mut rng)).collect()
|
||||||
|
};
|
||||||
|
let tracer_env = TracerEnv::new(&device, &tracer, &envmap);
|
||||||
|
|
||||||
|
let presenter = Presenter::new(&device, output_format);
|
||||||
|
|
||||||
|
let mut frame = 0;
|
||||||
|
let mut time = 0.0;
|
||||||
|
|
||||||
|
let mut surface_configured = false;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
event_loop
|
||||||
|
.run(move |event, control_flow| match event {
|
||||||
|
Event::WindowEvent { ref event, window_id } if window_id == window.id() => match event {
|
||||||
|
WindowEvent::CloseRequested => control_flow.exit(),
|
||||||
|
WindowEvent::Resized(physical_size) => {
|
||||||
|
surface.configure(
|
||||||
|
&device,
|
||||||
|
&wgpu::SurfaceConfiguration {
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
|
format: output_format,
|
||||||
|
width: physical_size.width,
|
||||||
|
height: physical_size.height,
|
||||||
|
present_mode: wgpu::PresentMode::Fifo,
|
||||||
|
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||||||
|
view_formats: vec![],
|
||||||
|
desired_maximum_frame_latency: 2,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
tracer.set_view(&queue, &make_viewport(physical_size.width, physical_size.height));
|
||||||
|
surface_configured = true;
|
||||||
|
}
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
window.request_redraw();
|
||||||
|
if !surface_configured {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
time += 1. / 60.;
|
||||||
|
frame += 1;
|
||||||
|
let spheres: Vec<_> = sphere_params.iter().map(|p| p.to_sphere(time)).collect();
|
||||||
|
let data = TracerData::new(&device, &tracer, &spheres);
|
||||||
|
tracer.set_params(
|
||||||
|
&queue,
|
||||||
|
trace::Params {
|
||||||
|
max_reflections: 3,
|
||||||
|
min_strength: 0.1,
|
||||||
|
sphere_count: N_SPHERES,
|
||||||
|
seed: frame,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = surface.get_current_texture().unwrap();
|
||||||
|
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
let size = output.texture.size();
|
||||||
|
let hdr = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: 2 * size.width,
|
||||||
|
height: 2 * size.height,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: hdr_format,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
let hdr = hdr.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
|
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
||||||
|
{
|
||||||
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &hdr,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
});
|
||||||
|
tracer.render(&mut render_pass, &data, &tracer_env);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
view: &view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
});
|
||||||
|
presenter.render(&device, &mut render_pass, &hdr);
|
||||||
|
}
|
||||||
|
queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
output.present();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init_gpu(wnd: &Window) -> Result<(wgpu::Device, wgpu::Queue, wgpu::Surface), Box<dyn Error>> {
|
||||||
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
|
backends: wgpu::Backends::PRIMARY,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let surface = instance.create_surface(wnd)?;
|
||||||
|
let adapter = instance
|
||||||
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: wgpu::PowerPreference::default(),
|
||||||
|
compatible_surface: Some(&surface),
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let (device, queue) = adapter
|
||||||
|
.request_device(
|
||||||
|
&wgpu::DeviceDescriptor {
|
||||||
|
label: None,
|
||||||
|
required_features: wgpu::Features::empty(),
|
||||||
|
required_limits: wgpu::Limits::default(),
|
||||||
|
memory_hints: Default::default(),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
Ok((device, queue, surface))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_envmap(device: &wgpu::Device, queue: &wgpu::Queue) -> wgpu::TextureView {
|
||||||
|
let imgs = std::thread::scope(|s| {
|
||||||
|
[0, 1, 2, 3, 4, 5]
|
||||||
|
.map(|face| {
|
||||||
|
s.spawn(move || {
|
||||||
|
let img = ImageReader::open(format!("textures/env{face}.jpeg"))
|
||||||
|
.unwrap()
|
||||||
|
.with_guessed_format()
|
||||||
|
.unwrap()
|
||||||
|
.decode()
|
||||||
|
.unwrap();
|
||||||
|
img.to_rgba8()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.map(|t| t.join().unwrap())
|
||||||
|
});
|
||||||
|
let size = imgs[0].width();
|
||||||
|
for img in &imgs {
|
||||||
|
assert!(img.width() == size);
|
||||||
|
assert!(img.height() == size);
|
||||||
|
}
|
||||||
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 6,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::Rgba8UnormSrgb,
|
||||||
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
for (face, img) in imgs.iter().enumerate() {
|
||||||
|
queue.write_texture(
|
||||||
|
wgpu::ImageCopyTexture {
|
||||||
|
texture: &texture,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: face as u32,
|
||||||
|
},
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
img.as_raw(),
|
||||||
|
wgpu::ImageDataLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(4 * size),
|
||||||
|
rows_per_image: Some(size),
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
texture.create_view(&wgpu::TextureViewDescriptor {
|
||||||
|
label: None,
|
||||||
|
format: None,
|
||||||
|
dimension: Some(wgpu::TextureViewDimension::Cube),
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
base_mip_level: 0,
|
||||||
|
mip_level_count: None,
|
||||||
|
base_array_layer: 0,
|
||||||
|
array_layer_count: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
103
src/bin/minitracer/present.rs
Normal file
103
src/bin/minitracer/present.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
use std::mem::offset_of;
|
||||||
|
|
||||||
|
use bytemuck::{bytes_of, Pod, Zeroable};
|
||||||
|
use glam::{vec2, Vec2};
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct Vertex {
|
||||||
|
pub screen: Vec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Presenter {
|
||||||
|
view_buf: wgpu::Buffer,
|
||||||
|
sampler: wgpu::Sampler,
|
||||||
|
pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
static SHADER: &str = include_str!("present.wgsl");
|
||||||
|
|
||||||
|
impl Presenter {
|
||||||
|
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||||
|
let view_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: None,
|
||||||
|
contents: bytes_of(&[(0., 0.), (1., 0.), (0., 1.), (1., 1.)].map(|(x, y)| Vertex { screen: vec2(x, y) })),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
});
|
||||||
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(SHADER.into()),
|
||||||
|
});
|
||||||
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
buffers: &[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: size_of::<Vertex>() as u64,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &[wgpu::VertexAttribute {
|
||||||
|
shader_location: 0,
|
||||||
|
offset: offset_of!(Vertex, screen) as u64,
|
||||||
|
format: wgpu::VertexFormat::Float32x2,
|
||||||
|
}],
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleStrip,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: 1,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: None,
|
||||||
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format,
|
||||||
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
||||||
|
min_filter: wgpu::FilterMode::Linear,
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
Self {
|
||||||
|
view_buf,
|
||||||
|
sampler,
|
||||||
|
pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, device: &wgpu::Device, pass: &mut wgpu::RenderPass, texture: &wgpu::TextureView) {
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &self.pipeline.get_bind_group_layout(0),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&self.sampler),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::TextureView(texture),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
pass.set_pipeline(&self.pipeline);
|
||||||
|
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
||||||
|
pass.set_bind_group(0, &bindings, &[]);
|
||||||
|
pass.draw(0..4, 0..1);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/bin/minitracer/present.wgsl
Normal file
25
src/bin/minitracer/present.wgsl
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
struct Vertex {
|
||||||
|
@location(0) screen: vec2f,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Varying {
|
||||||
|
@location(0) tex: vec2f,
|
||||||
|
@builtin(position) v: vec4f,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var smp: sampler;
|
||||||
|
@group(0) @binding(1) var tex: texture_2d<f32>;
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn on_vertex(in: Vertex) -> Varying {
|
||||||
|
return Varying(in.screen, vec4(2.0 * in.screen - 1.0, 0.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn on_fragment(in: Varying) -> @location(0) vec4f {
|
||||||
|
let hdr = textureSample(tex, smp, in.tex).xyz;
|
||||||
|
let luminosity = dot(hdr, vec3(0.2126, 0.7152, 0.0722));
|
||||||
|
let color = hdr / luminosity;
|
||||||
|
let luma = luminosity / (luminosity + 1.0);
|
||||||
|
return vec4(luma * color, 1.0);
|
||||||
|
}
|
||||||
|
|
@ -10,15 +10,16 @@ pub struct Params {
|
||||||
pub max_reflections: u32,
|
pub max_reflections: u32,
|
||||||
pub min_strength: f32,
|
pub min_strength: f32,
|
||||||
pub sphere_count: u32,
|
pub sphere_count: u32,
|
||||||
|
pub seed: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C)]
|
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
pub center: Vec3,
|
pub center: Vec3,
|
||||||
pub radius: f32,
|
pub radius: f32,
|
||||||
pub emit_color: Vec3,
|
pub emit_color: Vec3,
|
||||||
pub reflect_color: Vec3,
|
pub reflect_color: Vec3,
|
||||||
|
pub glossiness: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
|
|
@ -37,7 +38,7 @@ struct SphereData {
|
||||||
emit_color: Vec3,
|
emit_color: Vec3,
|
||||||
pad1: f32,
|
pad1: f32,
|
||||||
reflect_color: Vec3,
|
reflect_color: Vec3,
|
||||||
pad2: f32,
|
glossiness: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Tracer {
|
pub struct Tracer {
|
||||||
|
|
@ -50,10 +51,14 @@ pub struct TracerData {
|
||||||
bindings: wgpu::BindGroup,
|
bindings: wgpu::BindGroup,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TracerEnv {
|
||||||
|
bindings: wgpu::BindGroup,
|
||||||
|
}
|
||||||
|
|
||||||
static SHADER: &str = include_str!("trace.wgsl");
|
static SHADER: &str = include_str!("trace.wgsl");
|
||||||
|
|
||||||
impl Tracer {
|
impl Tracer {
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||||
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: (4 * mem::size_of::<Vertex>()) as u64,
|
size: (4 * mem::size_of::<Vertex>()) as u64,
|
||||||
|
|
@ -114,7 +119,7 @@ impl Tracer {
|
||||||
entry_point: None,
|
entry_point: None,
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: wgpu::TextureFormat::Bgra8Unorm,
|
format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
})],
|
})],
|
||||||
|
|
@ -137,10 +142,11 @@ impl Tracer {
|
||||||
queue.write_buffer(&self.view_buf, 0, bytes_of(vertices));
|
queue.write_buffer(&self.view_buf, 0, bytes_of(vertices));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(&self, pass: &mut wgpu::RenderPass, data: &TracerData) {
|
pub fn render(&self, pass: &mut wgpu::RenderPass, data: &TracerData, env: &TracerEnv) {
|
||||||
pass.set_pipeline(&self.pipeline);
|
pass.set_pipeline(&self.pipeline);
|
||||||
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
||||||
pass.set_bind_group(0, &data.bindings, &[]);
|
pass.set_bind_group(0, &data.bindings, &[]);
|
||||||
|
pass.set_bind_group(1, &env.bindings, &[]);
|
||||||
pass.draw(0..4, 0..1);
|
pass.draw(0..4, 0..1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +161,7 @@ impl TracerData {
|
||||||
emit_color: s.emit_color,
|
emit_color: s.emit_color,
|
||||||
pad1: 0.0,
|
pad1: 0.0,
|
||||||
reflect_color: s.reflect_color,
|
reflect_color: s.reflect_color,
|
||||||
pad2: 0.0,
|
glossiness: s.glossiness,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let spheres_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let spheres_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
|
@ -180,3 +186,24 @@ impl TracerData {
|
||||||
Self { bindings }
|
Self { bindings }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TracerEnv {
|
||||||
|
pub fn new(device: &wgpu::Device, tracer: &Tracer, view: &wgpu::TextureView) -> Self {
|
||||||
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &tracer.pipeline.get_bind_group_layout(1),
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&sampler),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::TextureView(view),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
Self { bindings }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ struct Params {
|
||||||
max_reflections: i32,
|
max_reflections: i32,
|
||||||
min_strength: f32,
|
min_strength: f32,
|
||||||
sphere_count: i32,
|
sphere_count: i32,
|
||||||
|
seed: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Sphere {
|
struct Sphere {
|
||||||
|
|
@ -9,6 +10,7 @@ struct Sphere {
|
||||||
radius: f32,
|
radius: f32,
|
||||||
emit_color: vec3f,
|
emit_color: vec3f,
|
||||||
reflect_color: vec3f,
|
reflect_color: vec3f,
|
||||||
|
glossiness: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
|
|
@ -25,6 +27,8 @@ struct Varying {
|
||||||
|
|
||||||
@group(0) @binding(0) var<uniform> params: Params;
|
@group(0) @binding(0) var<uniform> params: Params;
|
||||||
@group(0) @binding(1) var<storage, read> spheres: array<Sphere>;
|
@group(0) @binding(1) var<storage, read> spheres: array<Sphere>;
|
||||||
|
@group(1) @binding(0) var env_sampler: sampler;
|
||||||
|
@group(1) @binding(1) var env_texture: texture_cube<f32>;
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
fn on_vertex(in: Vertex) -> Varying {
|
fn on_vertex(in: Vertex) -> Varying {
|
||||||
|
|
@ -78,22 +82,24 @@ fn trace_fragment(in: Varying) -> vec4f {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sphere == -1) {
|
if (sphere == -1) {
|
||||||
|
let env = textureSampleLevel(env_texture, env_sampler, ray, 0.0);
|
||||||
|
result += vec4(3.0 * color * env.xyz, 0.0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let s = spheres[sphere];
|
let s = spheres[sphere];
|
||||||
pos += t * ray;
|
pos += t * ray;
|
||||||
let normal = (pos - s.center) / s.radius;
|
let normal = (pos - s.center) / s.radius;
|
||||||
result += vec4(color * s.emit_color * -dot(normal, ray), 0.0);
|
result += vec4(color * s.emit_color, 0.0);
|
||||||
color *= s.reflect_color;
|
color *= s.reflect_color;
|
||||||
let diffuse = normal + rand_sphere();
|
let diffuse = normal + rand_sphere();
|
||||||
let specular = reflect(ray, normal);
|
let specular = reflect(ray, normal);
|
||||||
ray = normalize(mix(diffuse, specular, 0.8));
|
ray = normalize(mix(diffuse, specular, s.glossiness));
|
||||||
if (length(color) < params.min_strength) {
|
if (length(color) < params.min_strength) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return clamp(result, vec4(0.0), vec4(1.0));
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash(key : u32) -> u32 {
|
fn hash(key : u32) -> u32 {
|
||||||
|
|
@ -108,7 +114,7 @@ var<private> rand_state: u32;
|
||||||
fn seed(key: vec4f) {
|
fn seed(key: vec4f) {
|
||||||
let x = bitcast<u32>(key.x);
|
let x = bitcast<u32>(key.x);
|
||||||
let y = bitcast<u32>(key.y);
|
let y = bitcast<u32>(key.y);
|
||||||
rand_state = hash(hash(x) ^ y);
|
rand_state = hash(hash(hash(params.seed) ^ x) ^ y);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rand_next() -> u32 {
|
fn rand_next() -> u32 {
|
||||||
|
|
@ -121,12 +127,12 @@ fn rand_float() -> f32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rand_sphere() -> vec3f {
|
fn rand_sphere() -> vec3f {
|
||||||
loop {
|
for (var k = 0; k < 16; k++) {
|
||||||
let v = vec3f(rand_float(), rand_float(), rand_float()) - 0.5;
|
let v = vec3f(rand_float(), rand_float(), rand_float()) - 0.5;
|
||||||
let l = length(v);
|
let l = length(v);
|
||||||
if (length(v) <= 0.5) {
|
if (length(v) <= 0.5) {
|
||||||
return v / l;
|
return v / l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vec3f(0.0); // unreachable
|
return vec3f(0.0); // safeguard
|
||||||
}
|
}
|
||||||
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod perlin;
|
||||||
|
|
@ -9,27 +9,26 @@ use glam::{Vec2, Vec3};
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub seed: u32,
|
pub origin: Vec3,
|
||||||
pub layers: u32,
|
pub radius: f32,
|
||||||
pub roughness: f32,
|
|
||||||
pub scale: f32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
pub world: Vec3,
|
pub dir: Vec3,
|
||||||
pub screen: Vec2,
|
pub screen: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
view_buf: wgpu::Buffer,
|
view_buf: wgpu::Buffer,
|
||||||
params_buf: wgpu::Buffer,
|
params_buf: wgpu::Buffer,
|
||||||
|
bindings: wgpu::BindGroup,
|
||||||
pipeline: wgpu::RenderPipeline,
|
pipeline: wgpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline {
|
impl Pipeline {
|
||||||
pub fn new(device: &wgpu::Device) -> Self {
|
pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
|
||||||
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
let view_buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: (4 * size_of::<Vertex>()) as u64,
|
size: (4 * size_of::<Vertex>()) as u64,
|
||||||
|
|
@ -43,7 +42,7 @@ impl Pipeline {
|
||||||
mapped_at_creation: false,
|
mapped_at_creation: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let shader = fs::read_to_string("src/bin/envmap/perlin.wgsl").unwrap();
|
let shader = fs::read_to_string("shaders/perlin.wgsl").unwrap();
|
||||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
source: wgpu::ShaderSource::Wgsl(shader.into()),
|
source: wgpu::ShaderSource::Wgsl(shader.into()),
|
||||||
|
|
@ -66,7 +65,7 @@ impl Pipeline {
|
||||||
},
|
},
|
||||||
wgpu::VertexAttribute {
|
wgpu::VertexAttribute {
|
||||||
shader_location: 1,
|
shader_location: 1,
|
||||||
offset: offset_of!(Vertex, world) as u64,
|
offset: offset_of!(Vertex, dir) as u64,
|
||||||
format: wgpu::VertexFormat::Float32x3,
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -87,7 +86,7 @@ impl Pipeline {
|
||||||
entry_point: None,
|
entry_point: None,
|
||||||
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
compilation_options: wgpu::PipelineCompilationOptions::default(),
|
||||||
targets: &[Some(wgpu::ColorTargetState {
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
format: wgpu::TextureFormat::Bgra8UnormSrgb,
|
format,
|
||||||
blend: Some(wgpu::BlendState::REPLACE),
|
blend: Some(wgpu::BlendState::REPLACE),
|
||||||
write_mask: wgpu::ColorWrites::ALL,
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
})],
|
})],
|
||||||
|
|
@ -95,9 +94,18 @@ impl Pipeline {
|
||||||
multiview: None,
|
multiview: None,
|
||||||
cache: None,
|
cache: None,
|
||||||
});
|
});
|
||||||
|
let bindings = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &pipeline.get_bind_group_layout(0),
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: params_buf.as_entire_binding(),
|
||||||
|
}],
|
||||||
|
});
|
||||||
Self {
|
Self {
|
||||||
view_buf,
|
view_buf,
|
||||||
params_buf,
|
params_buf,
|
||||||
|
bindings,
|
||||||
pipeline,
|
pipeline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +121,7 @@ impl Pipeline {
|
||||||
pub fn render(&self, pass: &mut wgpu::RenderPass) {
|
pub fn render(&self, pass: &mut wgpu::RenderPass) {
|
||||||
pass.set_pipeline(&self.pipeline);
|
pass.set_pipeline(&self.pipeline);
|
||||||
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
pass.set_vertex_buffer(0, self.view_buf.slice(..));
|
||||||
|
pass.set_bind_group(0, &self.bindings, &[]);
|
||||||
pass.draw(0..4, 0..1);
|
pass.draw(0..4, 0..1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user