Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
705 changes: 701 additions & 4 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ auto_ops = "0.3.0"
bytemuck = "1.25.0"
downcast-rs = "2.0.2"
env_logger = "0.11.9"
image = "0.25.10"
pollster = "0.4.0"
rand = "0.10.0"
softbuffer = "0.4.8"
Expand Down
24 changes: 21 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,15 @@ impl ApplicationHandler for App {
window.set_cursor_visible(false);

// wgpu init is async but resumed() isn't — use pollster to block
pollster::block_on(self.gpu.init(window.clone(), WIDTH as u32, HEIGHT as u32));
pollster::block_on(
self.gpu.init(
window.clone(),
WIDTH as u32,
HEIGHT as u32,
vec!["textures/dirt.png", "textures/grass_side.png", "textures/grass_top.png"])
);

std::thread::sleep(std::time::Duration::from_millis(1000));

self.window = Some(window);
}
Expand Down Expand Up @@ -359,13 +367,23 @@ fn main() {
//
Box::new(object::Sphere::new(&ds::Vector3::new(-3.25, -0.8, 6.0), 0.5, GpuMaterial::new(0x0000FF00, 0, 0))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.75, -0.8, 6.0), 0.5, GpuMaterial::new(0x000000FF, 0, 0))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.0, 0.0, 6.0), 0.5, GpuMaterial::new(0x00FF0000, 50, 0))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.0, 1.0, 6.0), 0.49, GpuMaterial::new(0x00000000, 0, 50))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.0, 0.0, 6.0), 0.5, GpuMaterial::new(0x00FF69B4, 50, 0))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.0, 1.0, 6.0), 0.49, GpuMaterial::new(0x00FF69B4, 0, 50))),
Box::new(object::Sphere::new(&ds::Vector3::new(-4.0, 2.0, 6.0), 0.49, GpuMaterial::new(0x00FF0000, 0, 0))),

// mirror sphere
Box::new(object::Sphere::new(&ds::Vector3::new(4.0, 0.0, 3.0), 2.0, GpuMaterial::new(0x00AAAAAA, 90, 0))),
Box::new(object::Sphere::new(&ds::Vector3::new(4.0, 0.3, 3.0), 0.25, GpuMaterial::new(0x000000FF, 0, 0))),

// grass block
Box::new(object::Quad::new(&ds::Vector3::new(1.0, 0.0, 5.0), &ds::Vector3::new(0.0, 0.0, 1.0), &ds::Vector3::new(0.0, 1.0, 0.0), GpuMaterial::texture(1, 0, 0))),
Box::new(object::Quad::new(&ds::Vector3::new(1.0, 0.0, 6.0), &ds::Vector3::new(1.0, 0.0, 0.0), &ds::Vector3::new(0.0, 1.0, 0.0), GpuMaterial::texture(1, 0, 0))),
Box::new(object::Quad::new(&ds::Vector3::new(2.0, 0.0, 6.0), &ds::Vector3::new(0.0, 0.0,-1.0), &ds::Vector3::new(0.0, 1.0, 0.0), GpuMaterial::texture(1, 0, 0))),
Box::new(object::Quad::new(&ds::Vector3::new(2.0, 0.0, 5.0), &ds::Vector3::new(-1.0,0.0, 0.0), &ds::Vector3::new(0.0, 1.0, 0.0), GpuMaterial::texture(1, 0, 0))),

Box::new(object::Quad::new(&ds::Vector3::new(1.0, 1.0, 5.0), &ds::Vector3::new(1.0, 0.0, 0.0), &ds::Vector3::new(0.0, 0.0, 1.0), GpuMaterial::texture(2, 0, 0))),
Box::new(object::Quad::new(&ds::Vector3::new(1.0, 0.0, 5.0), &ds::Vector3::new(1.0, 0.0, 0.0), &ds::Vector3::new(0.0, 0.0, 1.0), GpuMaterial::texture(0, 0, 0))),

];

let event_loop = EventLoop::new().expect("Failed to create event loop");
Expand Down
17 changes: 14 additions & 3 deletions src/material/material_interface.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
pub struct GpuMaterial {
color: [f32; 3],
color: [f32; 3],
reflective: u32,
translucent: u32,
_pad0: u32,
texture_id: i32,
_pad1: u32,
_pad2: u32,
}
Expand All @@ -20,7 +20,18 @@ impl GpuMaterial {
],
reflective: reflective_pct,
translucent: translucent_pct,
_pad0: 0,
texture_id: -1,
_pad1: 0,
_pad2: 0,
}
}
pub fn texture(texture_id: i32, reflective_pct: u32, translucent_pct: u32) -> Self {
assert!(reflective_pct + translucent_pct <= 100);
Self {
color: [0.0, 0.0, 0.0],
reflective: reflective_pct,
translucent: translucent_pct,
texture_id: texture_id,
_pad1: 0,
_pad2: 0,
}
Expand Down
2 changes: 1 addition & 1 deletion src/shaders/intersection.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,4 @@ fn closest_hit(origin: vec3<f32>, dir: vec3<f32>) -> HitRecord {
}

return rec;
}
}
2 changes: 1 addition & 1 deletion src/shaders/main.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
vec2(-1.0, 3.0),
);
return vec4(positions[idx], 0.0, 1.0);
}
}
35 changes: 32 additions & 3 deletions src/shaders/material.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ fn ray_color(ray_pos: vec3<f32>, ray_dir: vec3<f32>, tid: u32) -> u32 {
pushed_to_stack = true;
}

var lit_color = material.color;
var lit_color = vec3<f32>(0.0, 0.0, 0.0);
if material.texture_id != -1 {
lit_color = get_texture_color(record);
} else {
lit_color = material.color;
}

if material.reflect + material.translucent < 100 {
let light = max(dot(record.normal, light_dir), 0.0);
Expand All @@ -106,7 +111,10 @@ fn ray_color(ray_pos: vec3<f32>, ray_dir: vec3<f32>, tid: u32) -> u32 {

if !pushed_to_stack {
call = callstack[tid][index];
var color = f32(material.translucent) * call.outputs[0] + f32(material.reflect) * call.outputs[1] + f32(100 - material.translucent - material.reflect) * lit_color;
var color = f32(material.translucent) * call.outputs[0] +
f32(material.reflect) * call.outputs[1] +
f32(100 - material.translucent - material.reflect) * lit_color;

color = color / 100.0;

if call.caller != -1 {
Expand All @@ -116,8 +124,29 @@ fn ray_color(ray_pos: vec3<f32>, ray_dir: vec3<f32>, tid: u32) -> u32 {
return (u32(color.x) << 16) | (u32(color.y) << 8) | (u32(color.z));
}
}

}

return 0x00BADBEDu;
}

fn get_texture_color(record: HitRecord) -> vec3<f32> {
var material: Material;
var quad: Quad;

switch record.obj_type {
case 0u: {
material = spheres[record.obj_index].material;
return material.color; // only works on quads for now
}
case 1u: {
material = quads[record.obj_index].material;
quad = quads[record.obj_index];
}
default: {}
}

let pct_across = u32(abs((dot(cross(quad.v, record.normal), record.position - quad.q))*16 / length(quad.v)));
let pct_up = u32(abs((dot(cross(quad.u, record.normal), record.position - quad.q))*16 / length(quad.u)));

return textureLoad(textures, vec2u(pct_across, (15-pct_up) + 16 * u32(material.texture_id)), 0).rgb * 255.0;
}
5 changes: 3 additions & 2 deletions src/shaders/types.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@ struct Material {
color: vec3<f32>,
reflect: u32,
translucent: u32,
texture_id: i32,
}

@group(0) @binding(0) var<uniform> uniforms: Uniform;
@group(0) @binding(1) var<storage, read_write> output: array<u32>;
@group(0) @binding(2) var<storage, read> spheres: array<Sphere>;
@group(0) @binding(3) var<storage, read> quads: array<Quad>;

@group(0) @binding(4) var textures: texture_2d<f32>;

fn ray_at(ray_pos: vec3<f32>, ray_dir: vec3<f32>, t: f32) -> vec3<f32> {
return ray_pos + t * ray_dir;
}
}
75 changes: 72 additions & 3 deletions src/wgpu_handler.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::sync::Arc;

use image::ImageReader;
use wgpu::{Texture, TextureView};
use winit::window::{Window};

use crate::object;
Expand All @@ -17,6 +19,9 @@ pub struct GpuHandler {
pub spheres_buf: Option<wgpu::Buffer>,
pub quads_buf: Option<wgpu::Buffer>,
pub output_buf_size: Option<u64>,

texture: Option<Texture>,
view: Option<TextureView>
}

#[allow(unused)]
Expand Down Expand Up @@ -49,6 +54,7 @@ pub struct GpuStateMut<'a> { // makes my life infinitely easier
pub spheres_buf: &'a mut wgpu::Buffer,
pub quads_buf: &'a mut wgpu::Buffer,
pub output_buf_size: &'a mut u64,
pub view: &'a mut TextureView,
}

impl GpuHandler {
Expand All @@ -69,6 +75,7 @@ impl GpuHandler {
spheres_buf: self.spheres_buf.as_mut()?,
quads_buf: self.quads_buf.as_mut()?,
output_buf_size: self.output_buf_size.as_mut()?,
view: self.view.as_mut()?,
}
)
}
Expand Down Expand Up @@ -120,6 +127,7 @@ impl GpuHandler {
wgpu::BindGroupEntry { binding: 1, resource: gpu.output_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 2, resource: gpu.spheres_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 3, resource: gpu.quads_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 4, resource: wgpu::BindingResource::TextureView(gpu.view)},
],
});

Expand All @@ -128,7 +136,7 @@ impl GpuHandler {
}

// vibecoded but man thats a lot
pub async fn init(&mut self, window: Arc<Window>, width: u32, height: u32) {
pub async fn init(&mut self, window: Arc<Window>, width: u32, height: u32, texture_paths: Vec<&str>) {
// --- get a handle to the graphics card ---
let instance = wgpu::Instance::default();
let surface = instance.create_surface(window).unwrap();
Expand All @@ -150,7 +158,7 @@ impl GpuHandler {

let surface_config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8Unorm,
format: wgpu::TextureFormat::Rgba8Unorm,
width: width,
height: height,
present_mode: wgpu::PresentMode::Mailbox,
Expand All @@ -161,6 +169,51 @@ impl GpuHandler {

surface.configure(&device, &surface_config);

// --- textures ---

let mut rgba_data: Vec<u8> = vec![];

for path in &texture_paths {
rgba_data.extend_from_slice(
&ImageReader::open(path).expect("No image").decode().expect("Bad decode").to_rgba8().into_raw()
);
}

let texture_size = wgpu::Extent3d {
width: 16,
height: 16*texture_paths.len() as u32,
depth_or_array_layers: 1,
};

self.texture = Some(device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dirt"),
size: texture_size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
}));

queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: self.texture.as_ref().expect(""),
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
&rgba_data, // Your pixel bytes
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4 * 16), // 4 bytes per pixel * width
rows_per_image: Some(16 * texture_paths.len() as u32),
},
texture_size,
);

self.view = Some(self.texture.as_ref().expect("").create_view(&wgpu::TextureViewDescriptor::default()));

// --- buffers ---

let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
Expand Down Expand Up @@ -254,6 +307,17 @@ impl GpuHandler {
},
count: None,
},
// textures
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::FRAGMENT | wgpu::ShaderStages::COMPUTE, // Usually read in fragment shaders
ty: wgpu::BindingType::Texture {
multisampled: false,
view_dimension: wgpu::TextureViewDimension::D2,
sample_type: wgpu::TextureSampleType::Float { filterable: false },
},
count: None,
}
],
});

Expand All @@ -265,6 +329,7 @@ impl GpuHandler {
wgpu::BindGroupEntry { binding: 1, resource: output_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 2, resource: spheres_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 3, resource: quads_buf.as_entire_binding() },
wgpu::BindGroupEntry { binding: 4, resource: wgpu::BindingResource::TextureView(self.view.as_ref().expect(""))},
],
});

Expand Down Expand Up @@ -310,6 +375,8 @@ impl GpuHandler {
cache: None,
});

queue.submit([]);

// i opted to set them all at the end so im not wrapping everything in Some() and .unwrap()
self.device = Some(device);
self.queue = Some(queue);
Expand Down Expand Up @@ -341,6 +408,8 @@ impl Default for GpuHandler {
spheres_buf: None,
quads_buf: None,
output_buf_size: None,
texture: None,
view: None
}
}
}
}
Binary file added textures/dirt.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added textures/grass_side.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added textures/grass_top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading