Skip to content

Commit

Permalink
Add support for WebGL2
Browse files Browse the repository at this point in the history
Pretty sure we're taking some shortcuts for supporting large numbers
of point lights, but I believe this gets us to a point where we can
run on WebGL2.
  • Loading branch information
jgayfer committed Jun 9, 2024
1 parent 284bc5b commit d4943ce
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 92 deletions.
23 changes: 13 additions & 10 deletions src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ use bevy::{
prelude::*,
render::{
extract_component::UniformComponentPlugin,
gpu_component_array_buffer::GpuComponentArrayBufferPlugin,
render_graph::{RenderGraphApp, ViewNodeRunner},
Render, RenderApp, RenderSet,
RenderApp,
},
};

use crate::{
light::{AmbientLight2d, PointLight2d},
render::{
extract::{extract_ambient_lights, extract_point_lights, ExtractedAmbientLight2d},
gpu::{prepare_point_lights, GpuPointLights},
extract::{
extract_ambient_lights, extract_point_lights, ExtractedAmbientLight2d,
ExtractedPointLight2d,
},
lighting::{LightingNode, LightingPass, LightingPipeline, LIGHTING_SHADER},
},
};
Expand All @@ -32,9 +35,12 @@ impl Plugin for Light2dPlugin {
Shader::from_wgsl
);

app.add_plugins(UniformComponentPlugin::<ExtractedAmbientLight2d>::default())
.register_type::<AmbientLight2d>()
.register_type::<PointLight2d>();
app.add_plugins((
UniformComponentPlugin::<ExtractedAmbientLight2d>::default(),
GpuComponentArrayBufferPlugin::<ExtractedPointLight2d>::default(),
))
.register_type::<AmbientLight2d>()
.register_type::<PointLight2d>();

let Ok(render_app) = app.get_sub_app_mut(RenderApp) else {
return;
Expand All @@ -45,7 +51,6 @@ impl Plugin for Light2dPlugin {
ExtractSchedule,
(extract_point_lights, extract_ambient_lights),
)
.add_systems(Render, (prepare_point_lights).in_set(RenderSet::Prepare))
.add_render_graph_node::<ViewNodeRunner<LightingNode>>(Core2d, LightingPass)
.add_render_graph_edge(Core2d, Node2d::MainPass, LightingPass);
}
Expand All @@ -55,8 +60,6 @@ impl Plugin for Light2dPlugin {
return;
};

render_app
.init_resource::<LightingPipeline>()
.init_resource::<GpuPointLights>();
render_app.init_resource::<LightingPipeline>();
}
}
18 changes: 5 additions & 13 deletions src/render/extract.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
use bevy::{
core_pipeline::core_2d::Camera2d,
ecs::{
component::Component,
entity::Entity,
query::{With, Without},
system::{Commands, Query},
},
math::Vec4,
render::{render_resource::ShaderType, view::ViewVisibility, Extract},
transform::components::GlobalTransform,
prelude::*,
render::{render_resource::ShaderType, Extract},
};

use crate::light::{AmbientLight2d, PointLight2d};

#[derive(Component, Default, Clone)]
#[derive(Component, Default, Clone, ShaderType)]
pub struct ExtractedPointLight2d {
pub transform: GlobalTransform,
pub transform: Vec2,
pub radius: f32,
pub color: Vec4,
pub intensity: f32,
Expand All @@ -37,7 +29,7 @@ pub fn extract_point_lights(
}
commands.get_or_spawn(entity).insert(ExtractedPointLight2d {
color: point_light.color.rgba_linear_to_vec4(),
transform: *global_transform,
transform: global_transform.translation().xy(),
radius: point_light.radius,
intensity: point_light.intensity,
falloff: point_light.falloff,
Expand Down
48 changes: 0 additions & 48 deletions src/render/gpu.rs

This file was deleted.

17 changes: 14 additions & 3 deletions src/render/lighting/lighting.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ var texture_sampler: sampler;
@group(0) @binding(2)
var<uniform> view: View;

@group(0) @binding(3)
var<storage> point_lights: array<PointLight2d>;
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
@group(0) @binding(3)
var<storage> point_lights: array<PointLight2d>;
#else
@group(0) @binding(3)
var<uniform> point_lights: array<PointLight2d, 64u>;
#endif

@group(0) @binding(4)
var<uniform> ambient_light: AmbientLight2d;
Expand All @@ -56,8 +61,14 @@ fn fragment(vo: FullscreenVertexOutput) -> @location(0) vec4<f32> {
// Setup aggregate color from light sources to multiply the main texture by.
var light_color = vec3(1.0);

#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 6
let point_light_count = arrayLength(&point_lights);
#else
let point_light_count = 64u;
#endif

// For each light, determine its illumination if we're within range of it.
for (var i = 0u; i < arrayLength(&point_lights); i++) {
for (var i = 0u; i < point_light_count; i++) {

let point_light = point_lights[i];

Expand Down
38 changes: 29 additions & 9 deletions src/render/lighting/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ use bevy::render::extract_component::{ComponentUniforms, DynamicUniformIndex};
use bevy::render::render_graph::ViewNode;

use bevy::render::render_resource::{
BindGroupEntries, Operations, PipelineCache, RenderPassColorAttachment, RenderPassDescriptor,
BindGroupEntries, GpuArrayBuffer, Operations, PipelineCache, RenderPassColorAttachment,
RenderPassDescriptor,
};
use bevy::render::renderer::RenderDevice;
use bevy::render::view::{ViewTarget, ViewUniformOffset, ViewUniforms};
use bevy::utils::smallvec::{smallvec, SmallVec};

use crate::render::extract::ExtractedAmbientLight2d;
use crate::render::gpu::GpuPointLights;
use crate::render::extract::{ExtractedAmbientLight2d, ExtractedPointLight2d};

use super::LightingPipeline;

Expand Down Expand Up @@ -45,10 +47,6 @@ impl ViewNode for LightingNode {
return Ok(());
};

let Some(point_light_buffer) = world.resource::<GpuPointLights>().buffer.binding() else {
return Ok(());
};

let Some(ambient_light_uniform) = world
.resource::<ComponentUniforms<ExtractedAmbientLight2d>>()
.uniforms()
Expand All @@ -57,6 +55,13 @@ impl ViewNode for LightingNode {
return Ok(());
};

let Some(point_light_binding) = world
.resource::<GpuArrayBuffer<ExtractedPointLight2d>>()
.binding()
else {
return Ok(());
};

let post_process = view_target.post_process_write();

let bind_group = render_context.render_device().create_bind_group(
Expand All @@ -66,7 +71,7 @@ impl ViewNode for LightingNode {
post_process.source,
&lighting_pipeline.sampler,
view_uniform_binding,
point_light_buffer,
point_light_binding,
ambient_light_uniform,
)),
);
Expand All @@ -83,8 +88,23 @@ impl ViewNode for LightingNode {
occlusion_query_set: None,
});

let mut dynamic_offsets: SmallVec<[u32; 3]> = smallvec![];

dynamic_offsets.push(view_offset.offset);

if world
.resource::<RenderDevice>()
.limits()
.max_storage_buffers_per_shader_stage
== 0
{
dynamic_offsets.push(0);
}

dynamic_offsets.push(ambient_index.index());

render_pass.set_render_pipeline(pipeline);
render_pass.set_bind_group(0, &bind_group, &[view_offset.offset, ambient_index.index()]);
render_pass.set_bind_group(0, &bind_group, &dynamic_offsets);
render_pass.draw(0..3, 0..1);

Ok(())
Expand Down
14 changes: 6 additions & 8 deletions src/render/lighting/pipeline.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
use bevy::core_pipeline::fullscreen_vertex_shader::fullscreen_shader_vertex_state;
use bevy::prelude::*;
use bevy::render::render_resource::binding_types::{
sampler, storage_buffer_read_only, texture_2d, uniform_buffer,
};
use bevy::render::render_resource::binding_types::{sampler, texture_2d, uniform_buffer};
use bevy::render::render_resource::{
BindGroupLayout, BindGroupLayoutEntries, CachedRenderPipelineId, ColorTargetState, ColorWrites,
FragmentState, MultisampleState, PipelineCache, PrimitiveState, RenderPipelineDescriptor,
Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, TextureFormat, TextureSampleType,
FragmentState, GpuArrayBuffer, MultisampleState, PipelineCache, PrimitiveState,
RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages,
TextureFormat, TextureSampleType,
};
use bevy::render::renderer::RenderDevice;
use bevy::render::texture::BevyDefault;
use bevy::render::view::ViewUniform;

use crate::render::extract::ExtractedAmbientLight2d;
use crate::render::gpu::GpuPointLight2d;
use crate::render::extract::{ExtractedAmbientLight2d, ExtractedPointLight2d};

use super::LIGHTING_SHADER;

Expand All @@ -39,7 +37,7 @@ impl FromWorld for LightingPipeline {
texture_2d(TextureSampleType::Float { filterable: true }),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<ViewUniform>(true),
storage_buffer_read_only::<Vec<GpuPointLight2d>>(false),
GpuArrayBuffer::<ExtractedPointLight2d>::binding_layout(render_device),
uniform_buffer::<ExtractedAmbientLight2d>(true),
),
),
Expand Down
1 change: 0 additions & 1 deletion src/render/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
pub mod extract;
pub mod gpu;
pub mod lighting;

0 comments on commit d4943ce

Please sign in to comment.