bevy-magic-light-2d
bevy-magic-light-2d copied to clipboard
Camera zooming issues
Hi!
While zooming scene out the screen is being "split" into a "grid" and around each "grid cell" I observe black areas. The more I zoom out the larger black areas become.
Any ideas how to fix this?
Details provided below:
Here it is illustrated in krypta
demo app (I added zoom to fork https://github.com/zaycev/bevy-magic-light-2d/compare/main...morr:bevy-magic-light-2d:zoom-out-issue)
And this is how the issue looks in my bevy app where I try very large zoom.
Updated the description of the issue, removed unnecessary details.
Known issue. The problem is likely due to a bug in SDF. Thanks for putting all details.
@morr I would try something like this for your game.
- Change SDF to min operator instead of round merge. That would make walls completely black as no light can go into negative space:
@compute @workgroup_size(8, 8, 1)
fn main(@builtin(global_invocation_id) invocation_id: vec3<u32>) {
let texel_pos = vec2<i32>(invocation_id.xy);
let dims = textureDimensions(sdf_out);
let uv = (vec2<f32>(texel_pos) + 0.5) / vec2<f32>(dims);
let world_pose = sdf_uv_to_world(uv,
camera_params.inverse_view_proj,
camera_params.sdf_scale);
let r = 1.2;
var sdf_merged = sdf_aabb_occluder(world_pose.xy, 0);
for (var i: i32 = 1; i < i32(light_occluder_buffer.count); i++) {
sdf_merged = min(sdf_merged, sdf_aabb_occluder(world_pose.xy, i));
}
textureStore(sdf_out, texel_pos, vec4<f32>(sdf_merged, 0.0, 0.0, 0.0));
}
- To fix zero irradiance for walls, try to sample it from neighbor pixels (in
gi_post_processing.wgsl
):
@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
let position = in.position;
let uv = coords_to_viewport_uv(position.xy, view.viewport);
// Read diffuse textures.
let in_floor_diffuse = textureSample(in_floor_texture, in_floor_sampler, uv);
let in_walls_diffuse = textureSample(in_walls_texture, in_walls_sampler, uv);
let in_objects_diffuse = textureSample(in_objects_texture, in_objects_sampler, uv);
let in_irradiance = textureSample(in_irradiance_texture, in_irradiance_texture_sampler, uv).xyz;
// Calculate object irradiance.
// TODO: parametrize this filter.
// TODO: we don't really need to do this per pixel.
var object_irradiance = in_irradiance;
var walls_irradiance = in_irradiance;
var k_size = 3;
var k_width = 28;
for (var i = -k_size; i <= k_size; i++) {
for (var j = -k_size; j < 0; j++) {
let offset = vec2<f32>(f32(i * k_width), f32(j * k_width));
let irradiance_uv = coords_to_viewport_uv(position.xy - offset, view.viewport);
let sample_irradiance = textureSample(
in_irradiance_texture,
in_irradiance_texture_sampler,
irradiance_uv
).xyz;
// TODO: Might also need a visibility check here.
if any(irradiance_uv < vec2<f32>(0.0)) || any(irradiance_uv > vec2<f32>(1.0)) {
continue;
}
object_irradiance = max(object_irradiance, sample_irradiance);
}
}
k_size = 4;
k_width = 16;
for (var i = -k_size; i <= k_size; i++) {
for (var j = -k_size; j < k_size; j++) {
let offset = vec2<f32>(f32(i * k_width), f32(j * k_width));
let irradiance_uv = coords_to_viewport_uv(position.xy - offset, view.viewport);
let sample_irradiance = textureSample(
in_irradiance_texture,
in_irradiance_texture_sampler,
irradiance_uv
).xyz;
// TODO: Might also need a visibility check here.
if any(irradiance_uv < vec2<f32>(0.0)) || any(irradiance_uv > vec2<f32>(1.0)) {
continue;
}
walls_irradiance += sample_irradiance;
}
}
walls_irradiance /= 16.0;
let floor_irradiance_srgb = lin_to_srgb(in_irradiance);
let objects_irradiance_srgb = lin_to_srgb(object_irradiance);
let final_floor = in_floor_diffuse.xyz * floor_irradiance_srgb;
let final_walls = in_walls_diffuse.xyz * walls_irradiance;
let final_objects = in_objects_diffuse.xyz * objects_irradiance_srgb;
var out = vec4<f32>(final_floor, 1.0);
out = vec4<f32>(mix(out.xyz, final_walls.xyz, in_walls_diffuse.w), 1.0);
out = vec4<f32>(mix(out.xyz, final_objects.xyz, in_objects_diffuse.w), 1.0);
return out;
}
It's very hacky, but might work for you. This is what I've got:
@zaycev thanks for quick response! The demo looks better with such fixes.
In my app I started getting black screen after changed shaders code, but this looks like my own fault, probably I did set up something incorrectly.
In my app I started getting black screen after changed shaders code, but this looks like my own fault, probably I did set up something incorrectly.
Naga should tell you in the log if you have syntax error in shaders.
@morr were you able to fix this? I am experiencing the same issue.
@csandven the krypta example now supports zooming and I can't reproduce this issue - can you check if it's still available with 0.8.0 or 0.8.1?