struct VertexOutput { @location(0) world_space_position: vec4, @builtin(position) position: vec4, } struct Uniforms { camera_to_world_matrix: mat4x4, world_to_ndc_matrix: mat4x4, camera_position: vec4, dem_min_corner: vec2, dem_cell_size: vec2, dem_z_range: vec2 } @group(0) @binding(0) var uniforms: Uniforms; @group(0) @binding(1) var dem_texture: texture_2d; @group(0) @binding(2) var dembvh_texture: texture_2d; //#include ray_intersection.wgsl @vertex fn vs_main( @location(0) position: vec4, ) -> VertexOutput { var result: VertexOutput; result.position = uniforms.world_to_ndc_matrix * position; result.world_space_position = position; return result; } const RGSS_WIGGLE = array(vec2(0.125, 0.375), vec2(-0.125, -0.375), vec2(0.375, 0.125), vec2(-0.375, -0.125)); @fragment fn fs_solid(vertex: VertexOutput) -> @location(0) vec4 { var ray: Ray; ray.origin = vertex.world_space_position.xyz; ray.direction = normalize(vertex.world_space_position.xyz - uniforms.camera_position.xyz); // Spread rays into RGSS antialiasing pattern. let ray_dx = dpdy(ray.direction); let ray_dy = dpdy(ray.direction); //var ray_directions: array,4>; //ray_directions[0] = ray.direction + 0.125*ray_dx + 0.375*ray_dy; //ray_directions[1] = ray.direction - 0.125*ray_dx - 0.375*ray_dy; //ray_directions[2] = ray.direction + 0.375*ray_dx + 0.125*ray_dy; //ray_directions[3] = ray.direction - 0.375*ray_dx - 0.125*ray_dy; // Possibly these ray directions could be stored in a matrix and we could // evaluate them all at once instead of looping. let sun_direction = vec3(0.761904762, 0.380952381, 0.19047619); var color_accumulator = vec4(0); let rgss_value = vec2(0.125, 0.375); var wiggled_ray = ray; for(var i=0; i<4; i++) { let rgss_wiggle = select(rgss_value, rgss_value.yx, vec2(bool(i&2))) * select(1.0, -1.0, bool(i&1)); wiggled_ray.direction = ray.direction + rgss_wiggle.x * ray_dx + rgss_wiggle.y * ray_dy; var root_node: BoundingNode; root_node.index = vec2(0); root_node.level = textureNumLevels(dembvh_texture) - 1; var hit_location: vec3; var hit_normal: vec3; if intersect_ray_with_node(wiggled_ray, root_node, &hit_location, &hit_normal) { var shadow_value = 0.0f; var shadow_ray :Ray; shadow_ray.origin = hit_location + hit_normal * 0.1; for(var j=0; i<8; i++) { let shadow_sample = 0.02 * (vec3(1.0, 0.0, 0.0) * f32(bool((i*4+j)&1)) + vec3(0.0, 1.0, 0.0) * f32(bool((i*4+j)&2)) + vec3(-1.0, 0.0, 0.0) * f32(bool((i*4+j)&4)) + vec3(0.0, -1.0, 0.0) * f32(bool((i*4+j)&8)) + vec3(0.0, 0.0, 1.0) * f32(bool((i*4+j)&16))); // Calculate light let sun_direction = (uniforms.camera_to_world_matrix * vec4(sun_direction + shadow_sample, 0.0)).xyz; shadow_ray.direction = sun_direction; var dummy0: vec3; var dummy1: vec3; shadow_value += select(0.25, 0.0, intersect_ray_with_node(shadow_ray, root_node, &dummy0, &dummy1)); } let sun_direction = (uniforms.camera_to_world_matrix * vec4(sun_direction, 0.0)).xyz; let sun_lambertian_value = dot(hit_normal, sun_direction); let fill_lambertian_value = dot(hit_normal, sun_direction * vec3(1.0, -1.0, 1.0)); let fill_strength = 0.25; let l = fill_strength * fill_lambertian_value + (1.0 - fill_strength) * sun_lambertian_value * shadow_value; color_accumulator += 0.25 * vec4(vec3(l), 1.0); } } if color_accumulator.a == 0.0 { discard; } return color_accumulator; }