Skip to content

Commit

Permalink
Merge G-Buffer pass into the Main
Browse files Browse the repository at this point in the history
  • Loading branch information
kvark committed Sep 3, 2024
1 parent 7550510 commit 7cc23f2
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 338 deletions.
2 changes: 1 addition & 1 deletion blade-render/code/blur.wgsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "camera.inc.wgsl"
#include "gbuf.inc.wgsl"
#include "motion.inc.wgsl"
#include "quaternion.inc.wgsl"
#include "surface.inc.wgsl"

Expand Down
204 changes: 0 additions & 204 deletions blade-render/code/fill-gbuf.wgsl

This file was deleted.

2 changes: 0 additions & 2 deletions blade-render/code/gbuf.inc.wgsl

This file was deleted.

182 changes: 182 additions & 0 deletions blade-render/code/geometry.inc.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
//TODO: https://github.com/gfx-rs/wgpu/pull/5429
const RAY_FLAG_CULL_NO_OPAQUE: u32 = 0x80u;

// Has to match the host!
struct Vertex {
pos: vec3<f32>,
bitangent_sign: f32,
tex_coords: vec2<f32>,
normal: u32,
tangent: u32,
}
struct VertexBuffer {
data: array<Vertex>,
}
struct IndexBuffer {
data: array<u32>,
}
var<storage, read> vertex_buffers: binding_array<VertexBuffer>;
var<storage, read> index_buffers: binding_array<IndexBuffer>;
var textures: binding_array<texture_2d<f32>>;

struct HitEntry {
index_buf: u32,
vertex_buf: u32,
winding: f32,
// packed quaternion
geometry_to_world_rotation: u32,
geometry_to_object: mat4x3<f32>,
prev_object_to_world: mat4x3<f32>,
base_color_texture: u32,
// packed color factor
base_color_factor: u32,
normal_texture: u32,
}
var<storage, read> hit_entries: array<HitEntry>;

fn decode_normal(raw: u32) -> vec3<f32> {
return unpack4x8snorm(raw).xyz;
}

fn debug_raw_normal(pos: vec3<f32>, normal_raw: u32, rotation: vec4<f32>, debug_len: f32, color: u32) {
let nw = normalize(qrot(rotation, decode_normal(normal_raw)));
debug_line(pos, pos + debug_len * nw, color);
}

struct RichSurface {
inner: Surface,
position: vec3<f32>,
albedo: vec3<f32>,
motion: vec2<f32>,
}

fn fetch_geometry(pixel_coord: vec2<i32>, enable_debug: bool, is_primary: bool) -> RichSurface {
var rq: ray_query;
let ray_dir = get_ray_direction(camera, pixel_coord);
rayQueryInitialize(&rq, acc_struct, RayDesc(RAY_FLAG_CULL_NO_OPAQUE, 0xFFu, 0.0, camera.depth, camera.position, ray_dir));
rayQueryProceed(&rq);
let intersection = rayQueryGetCommittedIntersection(&rq);

var rs = RichSurface();
rs.albedo = vec3<f32>(1.0);

if (intersection.kind == RAY_QUERY_INTERSECTION_NONE) {
if (enable_debug) {
debug_buf.entry = DebugEntry();
}
return rs;
}

let entry = hit_entries[intersection.instance_custom_index + intersection.geometry_index];

var indices = intersection.primitive_index * 3u + vec3<u32>(0u, 1u, 2u);
if (entry.index_buf != ~0u) {
let iptr = &index_buffers[entry.index_buf].data;
indices = vec3<u32>((*iptr)[indices.x], (*iptr)[indices.y], (*iptr)[indices.z]);
}

let vptr = &vertex_buffers[entry.vertex_buf].data;
let vertices = array<Vertex, 3>(
(*vptr)[indices.x],
(*vptr)[indices.y],
(*vptr)[indices.z],
);

let positions_object = entry.geometry_to_object * mat3x4(
vec4<f32>(vertices[0].pos, 1.0), vec4<f32>(vertices[1].pos, 1.0), vec4<f32>(vertices[2].pos, 1.0)
);
let positions = intersection.object_to_world * mat3x4(
vec4<f32>(positions_object[0], 1.0), vec4<f32>(positions_object[1], 1.0), vec4<f32>(positions_object[2], 1.0)
);
let flat_normal = entry.winding * normalize(cross(positions[1].xyz - positions[0].xyz, positions[2].xyz - positions[0].xyz));

let barycentrics = vec3<f32>(1.0 - intersection.barycentrics.x - intersection.barycentrics.y, intersection.barycentrics);
let position_object = vec4<f32>(positions_object * barycentrics, 1.0);
let tex_coords = mat3x2(vertices[0].tex_coords, vertices[1].tex_coords, vertices[2].tex_coords) * barycentrics;
let normal_geo = normalize(mat3x3(decode_normal(vertices[0].normal), decode_normal(vertices[1].normal), decode_normal(vertices[2].normal)) * barycentrics);
let tangent_geo = normalize(mat3x3(decode_normal(vertices[0].tangent), decode_normal(vertices[1].tangent), decode_normal(vertices[2].tangent)) * barycentrics);
let bitangent_geo = normalize(cross(normal_geo, tangent_geo)) * vertices[0].bitangent_sign;

let lod = 0.0; //TODO: this is actually complicated

let geo_to_world_rot = normalize(unpack4x8snorm(entry.geometry_to_world_rotation));
let tangent_space_geo = mat3x3(tangent_geo, bitangent_geo, normal_geo);
var normal_local: vec3<f32>;
if ((debug.texture_flags & DebugTextureFlags_NORMAL) != 0u) {
normal_local = vec3<f32>(0.0, 0.0, 1.0); // ignore normal map
} else {
let n_xy = textureSampleLevel(textures[entry.normal_texture], sampler_linear, tex_coords, lod).xy;
normal_local = vec3<f32>(n_xy, sqrt(max(0.0, 1.0 - dot(n_xy.xy, n_xy.xy))));
}
let normal = qrot(geo_to_world_rot, tangent_space_geo * normal_local);
let basis = shortest_arc_quat(vec3<f32>(0.0, 0.0, 1.0), normalize(normal));

let hit_position = camera.position + intersection.t * ray_dir;
if (enable_debug && is_primary) {
debug_buf.entry.custom_index = intersection.instance_custom_index;
debug_buf.entry.depth = intersection.t;
debug_buf.entry.tex_coords = tex_coords;
debug_buf.entry.base_color_texture = entry.base_color_texture;
debug_buf.entry.normal_texture = entry.normal_texture;
debug_buf.entry.position = hit_position;
debug_buf.entry.flat_normal = flat_normal;
}
if (enable_debug && (debug.draw_flags & DebugDrawFlags_SPACE) != 0u) {
let normal_len = 0.15 * intersection.t;
let side = 0.05 * intersection.t;
debug_line(hit_position, hit_position + normal_len * qrot(geo_to_world_rot, normal_geo), 0xFFFFFFu);
debug_line(hit_position - side * tangent_geo, hit_position + side * tangent_geo, 0x808080u);
debug_line(hit_position - side * bitangent_geo, hit_position + side * bitangent_geo, 0x808080u);
}
if (enable_debug && (debug.draw_flags & DebugDrawFlags_GEOMETRY) != 0u) {
let debug_len = intersection.t * 0.2;
debug_line(positions[0].xyz, positions[1].xyz, 0x00FFFFu);
debug_line(positions[1].xyz, positions[2].xyz, 0x00FFFFu);
debug_line(positions[2].xyz, positions[0].xyz, 0x00FFFFu);
let poly_center = (positions[0].xyz + positions[1].xyz + positions[2].xyz) / 3.0;
debug_line(poly_center, poly_center + 0.2 * debug_len * flat_normal, 0xFF00FFu);
// note: dynamic indexing into positions isn't allowed by WGSL yet
debug_raw_normal(positions[0].xyz, vertices[0].normal, geo_to_world_rot, 0.5*debug_len, 0xFFFF00u);
debug_raw_normal(positions[1].xyz, vertices[1].normal, geo_to_world_rot, 0.5*debug_len, 0xFFFF00u);
debug_raw_normal(positions[2].xyz, vertices[2].normal, geo_to_world_rot, 0.5*debug_len, 0xFFFF00u);
// draw tangent space
debug_line(hit_position, hit_position + debug_len * qrot(basis, vec3<f32>(1.0, 0.0, 0.0)), 0x0000FFu);
debug_line(hit_position, hit_position + debug_len * qrot(basis, vec3<f32>(0.0, 1.0, 0.0)), 0x00FF00u);
debug_line(hit_position, hit_position + debug_len * qrot(basis, vec3<f32>(0.0, 0.0, 1.0)), 0xFF0000u);
}

rs.albedo = unpack4x8unorm(entry.base_color_factor).xyz;
if ((debug.texture_flags & DebugTextureFlags_ALBEDO) == 0u) {
let base_color_sample = textureSampleLevel(textures[entry.base_color_texture], sampler_linear, tex_coords, lod);
rs.albedo *= base_color_sample.xyz;
}

if (is_primary) {
if (debug.view_mode == DebugMode_Depth) {
textureStore(out_debug, pixel_coord, vec4<f32>(intersection.t / camera.depth));
}
if (debug.view_mode == DebugMode_Normal) {
textureStore(out_debug, pixel_coord, vec4<f32>(normal, 0.0));
}
if (debug.view_mode == DebugMode_HitConsistency) {
let reprojected = get_projected_pixel(camera, hit_position);
let barycentrics_pos_diff = (intersection.object_to_world * position_object).xyz - hit_position;
let camera_projection_diff = vec2<f32>(pixel_coord - reprojected);
let consistency = vec4<f32>(length(barycentrics_pos_diff), length(camera_projection_diff), 0.0, 0.0);
textureStore(out_debug, pixel_coord, consistency);
}
}

let prev_position = (entry.prev_object_to_world * position_object).xyz;
let prev_screen = get_projected_pixel_float(prev_camera, prev_position);
//TODO: consider just storing integers here?
//TODO: technically this "0.5" is just a waste compute on both packing and unpacking
rs.motion = prev_screen - vec2<f32>(pixel_coord) - 0.5;
rs.position = hit_position;

// Write down the Surface
rs.inner.basis = basis;
rs.inner.flat_normal = flat_normal;
rs.inner.depth = intersection.t;
return rs;
}
Loading

0 comments on commit 7cc23f2

Please sign in to comment.