more built-in shader variables for lighting

- pass light info in forward rendering shader
- removed 2d renderer
This commit is contained in:
Dmitry Stepanov
2023-11-11 18:00:36 +03:00
parent 139b9e9043
commit 5eb84f4ceb
13 changed files with 170 additions and 606 deletions
+2 -8
View File
@@ -11,15 +11,9 @@ use fyrox::{
pool::Handle,
sstorage::ImmutableString,
},
engine::{executor::Executor, GraphicsContext, GraphicsContextParams},
engine::{executor::Executor, GraphicsContextParams},
event::{ElementState, Event, WindowEvent},
event_loop::EventLoop,
gui::{
message::MessageDirection,
text::{TextBuilder, TextMessage},
widget::WidgetBuilder,
UiNode,
},
material::{Material, PropertyValue, SharedMaterial},
plugin::{Plugin, PluginConstructor, PluginContext},
resource::texture::Texture,
@@ -59,7 +53,7 @@ impl SceneLoader {
.set_property(
&ImmutableString::new("diffuseTexture"),
PropertyValue::Sampler {
value: Some(resource_manager.request::<Texture, _>("Crate.png")),
value: Some(resource_manager.request::<Texture, _>("examples/Crate.png")),
fallback: Default::default(),
},
)
+15 -16
View File
@@ -45,7 +45,6 @@
r#"
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 2) in vec4 vertexColor;
uniform mat4 fyrox_worldViewProjection;
uniform mat4 fyrox_worldMatrix;
@@ -59,7 +58,7 @@
texCoord = vertexTexCoord;
fragmentPosition = (fyrox_worldMatrix * vec4(vertexPosition, 1.0)).xyz;
gl_Position = fyrox_worldViewProjection * vec4(vertexPosition, 1.0);
color = vertexColor;
color = vec4(1.0, 1.0, 1.0, 1.0);
}
"#,
@@ -67,12 +66,12 @@
r#"
uniform sampler2D diffuseTexture;
uniform int lightCount;
uniform vec4 lightColorRadius[16]; // xyz - color, w = radius
uniform vec3 lightPosition[16];
uniform vec3 lightDirection[16];
uniform vec2 lightParameters[16]; // x = hotspot angle, y - full cone angle delta
uniform vec3 ambientLightColor;
uniform int fyrox_lightCount;
uniform vec4 fyrox_lightsColorRadius[16]; // xyz - color, w = radius
uniform vec3 fyrox_lightsPosition[16];
uniform vec3 fyrox_lightsDirection[16];
uniform vec2 fyrox_lightsParameters[16]; // x = hotspot angle, y - full cone angle delta
uniform vec3 fyrox_ambientLightColor;
out vec4 FragColor;
@@ -82,15 +81,15 @@
void main()
{
vec3 lighting = ambientLightColor;
for(int i = 0; i < lightCount; ++i) {
vec3 lighting = fyrox_ambientLightColor;
for(int i = 0; i < fyrox_lightCount; ++i) {
// "Unpack" light parameters.
float halfHotspotAngleCos = lightParameters[i].x;
float halfConeAngleCos = lightParameters[i].y;
vec3 lightColor = lightColorRadius[i].xyz;
float radius = lightColorRadius[i].w;
vec3 lightPosition = lightPosition[i];
vec3 direction = lightDirection[i];
float halfHotspotAngleCos = fyrox_lightsParameters[i].x;
float halfConeAngleCos = fyrox_lightsParameters[i].y;
vec3 lightColor = fyrox_lightsColorRadius[i].xyz;
float radius = fyrox_lightsColorRadius[i].w;
vec3 lightPosition = fyrox_lightsPosition[i];
vec3 direction = fyrox_lightsDirection[i];
// Calculate lighting.
vec3 toFragment = fragmentPosition - lightPosition;
+69 -3
View File
@@ -7,7 +7,13 @@
//! path).
use crate::{
core::{math::Rect, scope_profile, sstorage::ImmutableString},
core::{
algebra::{Vector2, Vector4},
color::Color,
math::{frustum::Frustum, Rect},
scope_profile,
sstorage::ImmutableString,
},
renderer::{
apply_material,
batch::RenderDataBatchStorage,
@@ -17,9 +23,14 @@ use crate::{
state::PipelineState,
},
storage::MatrixStorageCache,
GeometryCache, MaterialContext, QualitySettings, RenderPassStatistics,
GeometryCache, LightData, MaterialContext, QualitySettings, RenderPassStatistics,
},
scene::{
camera::Camera,
graph::Graph,
light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
mesh::RenderPath,
},
scene::{camera::Camera, mesh::RenderPath},
};
use std::{cell::RefCell, rc::Rc};
@@ -29,6 +40,7 @@ pub(crate) struct ForwardRenderer {
pub(crate) struct ForwardRenderContext<'a, 'b> {
pub state: &'a mut PipelineState,
pub graph: &'b Graph,
pub camera: &'b Camera,
pub geom_cache: &'a mut GeometryCache,
pub texture_cache: &'a mut TextureCache,
@@ -42,6 +54,7 @@ pub(crate) struct ForwardRenderContext<'a, 'b> {
pub black_dummy: Rc<RefCell<GpuTexture>>,
pub volume_dummy: Rc<RefCell<GpuTexture>>,
pub matrix_storage: &'a mut MatrixStorageCache,
pub ambient_light: Color,
}
impl ForwardRenderer {
@@ -61,6 +74,7 @@ impl ForwardRenderer {
let ForwardRenderContext {
state,
graph,
camera,
geom_cache,
texture_cache,
@@ -74,10 +88,60 @@ impl ForwardRenderer {
black_dummy,
volume_dummy,
matrix_storage,
ambient_light,
} = args;
let initial_view_projection = camera.view_projection_matrix();
let frustum = Frustum::from_view_projection_matrix(camera.view_projection_matrix())
.unwrap_or_default();
let mut light_data = LightData::default();
for light in graph.linear_iter() {
if !light.global_visibility() || light_data.count == light_data.parameters.len() {
continue;
}
let (radius, half_cone_angle_cos, half_hotspot_angle_cos, color) =
if let Some(point) = light.cast::<PointLight>() {
(
point.radius(),
std::f32::consts::PI.cos(),
std::f32::consts::PI.cos(),
point.base_light_ref().color().as_frgb(),
)
} else if let Some(spot) = light.cast::<SpotLight>() {
(
spot.distance(),
(spot.hotspot_cone_angle() * 0.5).cos(),
(spot.full_cone_angle() * 0.5).cos(),
spot.base_light_ref().color().as_frgb(),
)
} else if let Some(directional) = light.cast::<DirectionalLight>() {
(
f32::INFINITY,
std::f32::consts::PI.cos(),
std::f32::consts::PI.cos(),
directional.base_light_ref().color().as_frgb(),
)
} else {
continue;
};
if frustum.is_intersects_aabb(&light.world_bounding_box()) {
let light_num = light_data.count;
light_data.position[light_num] = light.global_position();
light_data.direction[light_num] = light.up_vector();
light_data.color_radius[light_num] =
Vector4::new(color.x, color.y, color.z, radius);
light_data.parameters[light_num] =
Vector2::new(half_cone_angle_cos, half_hotspot_angle_cos);
light_data.count += 1;
}
}
for batch in batch_storage
.batches
.iter()
@@ -132,6 +196,8 @@ impl ForwardRenderer {
volume_dummy: volume_dummy.clone(),
matrix_storage,
persistent_identifier: instance.persistent_identifier,
light_data: Some(&light_data),
ambient_light,
});
},
)?;
+18 -1
View File
@@ -34,6 +34,12 @@ pub enum BuiltInUniform {
BlendShapesStorage,
BlendShapesWeights,
BlendShapesCount,
LightCount,
LightsColorRadius,
LightsPosition,
LightsDirection,
LightsParameters,
AmbientLight,
// Must be last.
Count,
}
@@ -438,7 +444,18 @@ fn fetch_built_in_uniform_locations(
fetch_uniform_location(state, program, "fyrox_blendShapesWeights");
locations[BuiltInUniform::BlendShapesCount as usize] =
fetch_uniform_location(state, program, "fyrox_blendShapesCount");
locations[BuiltInUniform::LightCount as usize] =
fetch_uniform_location(state, program, "fyrox_lightCount");
locations[BuiltInUniform::LightsColorRadius as usize] =
fetch_uniform_location(state, program, "fyrox_lightsColorRadius");
locations[BuiltInUniform::LightsPosition as usize] =
fetch_uniform_location(state, program, "fyrox_lightsPosition");
locations[BuiltInUniform::LightsDirection as usize] =
fetch_uniform_location(state, program, "fyrox_lightsDirection");
locations[BuiltInUniform::LightsParameters as usize] =
fetch_uniform_location(state, program, "fyrox_lightsParameters");
locations[BuiltInUniform::AmbientLight as usize] =
fetch_uniform_location(state, program, "fyrox_ambientLightColor");
locations
}
+2
View File
@@ -344,6 +344,8 @@ impl GBuffer {
black_dummy: black_dummy.clone(),
volume_dummy: volume_dummy.clone(),
persistent_identifier: instance.persistent_identifier,
light_data: None,
ambient_light: Color::WHITE, // TODO
});
};
+57 -18
View File
@@ -16,7 +16,6 @@ pub mod framework;
pub mod batch;
pub mod cache;
pub mod debug_renderer;
pub mod renderer2d;
pub mod storage;
pub mod ui_renderer;
@@ -77,7 +76,6 @@ use crate::{
hdr::HighDynamicRangeRenderer,
light::{DeferredLightRenderer, DeferredRendererContext, LightingStatistics},
particle_system_renderer::{ParticleSystemRenderContext, ParticleSystemRenderer},
renderer2d::Renderer2d,
sprite_renderer::{SpriteRenderContext, SpriteRenderer},
storage::MatrixStorageCache,
ui_renderer::{UiRenderContext, UiRenderer},
@@ -86,6 +84,7 @@ use crate::{
scene::{camera::Camera, mesh::surface::SurfaceData, Scene, SceneContainer},
};
use fxhash::FxHashMap;
use fyrox_core::algebra::Vector4;
use glow::HasContext;
#[cfg(not(target_arch = "wasm32"))]
use glutin::{
@@ -738,7 +737,6 @@ pub struct Renderer {
geometry_cache: GeometryCache,
forward_renderer: ForwardRenderer,
fxaa_renderer: FxaaRenderer,
renderer2d: Renderer2d,
texture_event_receiver: Receiver<ResourceEvent>,
shader_event_receiver: Receiver<ResourceEvent>,
matrix_storage: MatrixStorageCache,
@@ -946,6 +944,26 @@ fn blit_pixels(
)
}
pub(crate) struct LightData<const N: usize = 16> {
count: usize,
color_radius: [Vector4<f32>; N],
position: [Vector3<f32>; N],
direction: [Vector3<f32>; N],
parameters: [Vector2<f32>; N],
}
impl<const N: usize> Default for LightData<N> {
fn default() -> Self {
Self {
count: 0,
color_radius: [Default::default(); N],
position: [Default::default(); N],
direction: [Default::default(); N],
parameters: [Default::default(); N],
}
}
}
pub(crate) struct MaterialContext<'a, 'b, 'c> {
pub material: &'a Material,
pub program_binding: &'a mut GpuProgramBinding<'b, 'c>,
@@ -963,6 +981,8 @@ pub(crate) struct MaterialContext<'a, 'b, 'c> {
pub light_position: &'a Vector3<f32>,
pub blend_shapes_storage: Option<&'a TextureResource>,
pub blend_shapes_weights: &'a [f32],
pub light_data: Option<&'a LightData>,
pub ambient_light: Color,
// Fallback samplers.
pub normal_dummy: Rc<RefCell<GpuTexture>>,
@@ -1012,6 +1032,38 @@ pub(crate) fn apply_material(ctx: MaterialContext) {
.set_vector3(location, ctx.light_position);
}
if let Some(light_data) = ctx.light_data {
if let Some(location) = &built_in_uniforms[BuiltInUniform::LightCount as usize] {
ctx.program_binding
.set_i32(location, light_data.count as i32);
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::LightsColorRadius as usize] {
ctx.program_binding
.set_vector4_slice(location, &light_data.color_radius);
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::LightsPosition as usize] {
ctx.program_binding
.set_vector3_slice(location, &light_data.position);
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::LightsDirection as usize] {
ctx.program_binding
.set_vector3_slice(location, &light_data.direction);
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::LightsParameters as usize] {
ctx.program_binding
.set_vector2_slice(location, &light_data.parameters);
}
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::AmbientLight as usize] {
ctx.program_binding
.set_srgb_color(location, &ctx.ambient_light);
}
if let Some(location) = &built_in_uniforms[BuiltInUniform::BlendShapesStorage as usize] {
if let Some(texture) = ctx
.blend_shapes_storage
@@ -1258,7 +1310,6 @@ impl Renderer {
ui_frame_buffers: Default::default(),
fxaa_renderer: FxaaRenderer::new(&mut state)?,
statistics: Statistics::default(),
renderer2d: Renderer2d::new(&mut state)?,
shader_event_receiver,
texture_event_receiver,
shader_cache,
@@ -1365,7 +1416,6 @@ impl Renderer {
pub fn flush(&mut self) {
self.texture_cache.clear();
self.geometry_cache.clear();
self.renderer2d.flush();
}
/// Renders given UI into specified render target. This method is especially useful if you need
@@ -1491,7 +1541,6 @@ impl Renderer {
self.update_texture_cache(dt);
self.update_shader_cache(dt);
self.geometry_cache.update(dt);
self.renderer2d.update_caches(dt);
}
fn render_frame(
@@ -1708,21 +1757,10 @@ impl Renderer {
viewport,
textures: &mut self.texture_cache,
})?;
/*
self.statistics += self.renderer2d.render(
state,
camera,
&mut scene_associated_data.hdr_scene_framebuffer,
viewport,
graph,
&mut self.texture_cache,
self.white_dummy.clone(),
scene.rendering_options.ambient_lighting_color,
)?;
*/
self.statistics += self.forward_renderer.render(ForwardRenderContext {
state,
graph,
camera,
geom_cache: &mut self.geometry_cache,
texture_cache: &mut self.texture_cache,
@@ -1736,6 +1774,7 @@ impl Renderer {
black_dummy: self.black_dummy.clone(),
volume_dummy: self.volume_dummy.clone(),
matrix_storage: &mut self.matrix_storage,
ambient_light: scene.rendering_options.ambient_lighting_color,
})?;
for render_pass in self.scene_render_passes.iter() {
-175
View File
@@ -1,175 +0,0 @@
use crate::{
core::{
algebra::{Matrix4, Vector2},
color::Color,
math::TriangleDefinition,
scope_profile,
},
renderer::framework::{
geometry_buffer::{
AttributeDefinition, AttributeKind, BufferBuilder, ElementKind, GeometryBuffer,
GeometryBufferBuilder, GeometryBufferKind,
},
state::PipelineState,
},
};
use fxhash::FxHashMap;
use fyrox_core::algebra::{Vector3, Vector4};
use fyrox_resource::entry::TimedEntry;
#[repr(C)]
pub struct Vertex {
position: Vector3<f32>,
tex_coord: Vector2<f32>,
}
pub struct Mesh {
vertices: Vec<Vertex>,
triangles: Vec<TriangleDefinition>,
}
impl Mesh {
pub fn new_unit_quad() -> Self {
let vertices = vec![
Vertex {
position: Vector3::new(-0.5, 0.5, 0.0),
tex_coord: Vector2::new(1.0, 0.0),
},
Vertex {
position: Vector3::new(0.5, 0.5, 0.0),
tex_coord: Vector2::new(0.0, 0.0),
},
Vertex {
position: Vector3::new(0.5, -0.5, 0.0),
tex_coord: Vector2::new(0.0, 1.0),
},
Vertex {
position: Vector3::new(-0.5, -0.5, 0.0),
tex_coord: Vector2::new(1.0, 1.0),
},
];
let triangles = vec![TriangleDefinition([0, 1, 2]), TriangleDefinition([0, 2, 3])];
Self {
vertices,
triangles,
}
}
}
#[derive(Default)]
pub(crate) struct GeometryCache {
map: FxHashMap<usize, TimedEntry<GeometryBuffer>>,
}
#[derive(Clone)]
#[repr(C)]
pub(crate) struct InstanceData {
pub color: Color,
/// UV Transform of the instance, where:
/// - `x` - UV rect X offset
/// - `y` - UV rect Y offset
/// - `z` - UV rect X scale
/// - `w` - UV rect Y scale
pub uv_transform: Vector4<f32>,
pub world_matrix: Matrix4<f32>,
}
impl GeometryCache {
pub fn get(&mut self, state: &mut PipelineState, data: &Mesh) -> &mut GeometryBuffer {
scope_profile!();
let key = (data as *const _) as usize;
let geometry_buffer = self.map.entry(key).or_insert_with(|| {
let geometry_buffer = GeometryBufferBuilder::new(ElementKind::Triangle)
.with_buffer_builder(
BufferBuilder::new(
GeometryBufferKind::StaticDraw,
Some(data.vertices.as_slice()),
)
.with_attribute(AttributeDefinition {
location: 0,
divisor: 0,
kind: AttributeKind::Float3,
normalized: false,
})
.with_attribute(AttributeDefinition {
location: 1,
divisor: 0,
kind: AttributeKind::Float2,
normalized: false,
}),
)
// Buffer for instance data.
.with_buffer_builder(
BufferBuilder::new::<InstanceData>(GeometryBufferKind::DynamicDraw, None)
// Color
.with_attribute(AttributeDefinition {
location: 2,
kind: AttributeKind::UnsignedByte4,
normalized: true,
divisor: 1,
})
// Transform
.with_attribute(AttributeDefinition {
location: 3,
kind: AttributeKind::Float4,
normalized: false,
divisor: 1,
})
// World Matrix
.with_attribute(AttributeDefinition {
location: 4,
kind: AttributeKind::Float4,
normalized: false,
divisor: 1,
})
.with_attribute(AttributeDefinition {
location: 5,
kind: AttributeKind::Float4,
normalized: false,
divisor: 1,
})
.with_attribute(AttributeDefinition {
location: 6,
kind: AttributeKind::Float4,
normalized: false,
divisor: 1,
})
.with_attribute(AttributeDefinition {
location: 7,
kind: AttributeKind::Float4,
normalized: false,
divisor: 1,
}),
)
.build(state)
.unwrap();
geometry_buffer.bind(state).set_triangles(&data.triangles);
TimedEntry {
value: geometry_buffer,
time_to_live: 20.0,
}
});
geometry_buffer.time_to_live = 20.0;
geometry_buffer
}
pub fn update(&mut self, dt: f32) {
scope_profile!();
for entry in self.map.values_mut() {
entry.time_to_live -= dt;
}
self.map.retain(|_, v| v.time_to_live > 0.0);
}
pub fn clear(&mut self) {
self.map.clear();
}
}
-326
View File
@@ -1,326 +0,0 @@
//! A renderer responsible for drawing 2D scenes.
use crate::renderer::framework::framebuffer::BlendParameters;
use crate::{
core::{
algebra::{Vector2, Vector3, Vector4},
color::Color,
math::{aabb::AxisAlignedBoundingBox, frustum::Frustum, Rect},
sstorage::ImmutableString,
},
renderer::{
framework::{
error::FrameworkError,
framebuffer::{DrawParameters, FrameBuffer},
gpu_program::{GpuProgram, UniformLocation},
gpu_texture::GpuTexture,
state::{BlendFactor, BlendFunc, PipelineState},
},
renderer2d::cache::{GeometryCache, InstanceData, Mesh},
RenderPassStatistics, TextureCache,
},
scene::{
camera::Camera,
dim2::rectangle::Rectangle,
graph::Graph,
light::{directional::DirectionalLight, point::PointLight, spot::SpotLight},
},
utils::value_as_u8_slice,
};
use fxhash::{FxHashMap, FxHasher};
use std::{cell::RefCell, cmp::Ordering, hash::Hasher, rc::Rc};
mod cache;
struct SpriteShader {
program: GpuProgram,
wvp_matrix: UniformLocation,
diffuse_texture: UniformLocation,
light_count: UniformLocation,
light_color_radius: UniformLocation,
light_position: UniformLocation,
light_direction: UniformLocation,
light_parameters: UniformLocation,
ambient_light_color: UniformLocation,
}
impl SpriteShader {
pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
let fragment_source = include_str!("shaders/sprite_fs.glsl");
let vertex_source = include_str!("shaders/sprite_vs.glsl");
let program =
GpuProgram::from_source(state, "RectangleShader", vertex_source, fragment_source)?;
Ok(Self {
wvp_matrix: program.uniform_location(state, &ImmutableString::new("viewProjection"))?,
diffuse_texture: program
.uniform_location(state, &ImmutableString::new("diffuseTexture"))?,
light_count: program.uniform_location(state, &ImmutableString::new("lightCount"))?,
light_color_radius: program
.uniform_location(state, &ImmutableString::new("lightColorRadius"))?,
light_direction: program
.uniform_location(state, &ImmutableString::new("lightDirection"))?,
light_position: program
.uniform_location(state, &ImmutableString::new("lightPosition"))?,
light_parameters: program
.uniform_location(state, &ImmutableString::new("lightParameters"))?,
ambient_light_color: program
.uniform_location(state, &ImmutableString::new("ambientLightColor"))?,
program,
})
}
}
pub(crate) struct Renderer2d {
sprite_shader: SpriteShader,
quad: Mesh,
geometry_cache: GeometryCache,
batch_storage: SpriteBatchStorage,
instance_data_set: Vec<InstanceData>,
}
#[derive(Default)]
struct SpriteBatchStorage {
batches: Vec<Batch>,
index_map: FxHashMap<u64, usize>,
}
impl SpriteBatchStorage {
fn generate_batches(
&mut self,
state: &mut PipelineState,
graph: &Graph,
texture_cache: &mut TextureCache,
white_dummy: Rc<RefCell<GpuTexture>>,
) {
self.index_map.clear();
for batch in self.batches.iter_mut() {
batch.instances.clear();
}
let mut batch_index = 0;
for node in graph.linear_iter() {
if let Some(rectangle) = node.cast::<Rectangle>() {
if !rectangle.global_visibility() {
continue;
}
let texture = rectangle.texture().map_or_else(
|| white_dummy.clone(),
|t| {
texture_cache
.get(state, t)
.unwrap_or_else(|| white_dummy.clone())
},
);
let z = rectangle.global_position().z;
let mut hasher = FxHasher::default();
// Objects with different Z coordinate will go into separate batches.
hasher.write(value_as_u8_slice(&z));
// Objects with different textures will go into separate batches.
hasher.write_u64(&*texture.borrow() as *const _ as u64);
let batch_id = hasher.finish();
let index = *self.index_map.entry(batch_id).or_insert_with(|| {
let index = batch_index;
batch_index += 1;
index as usize
});
// Reuse old batches to prevent redundant memory allocations
let batch = if let Some(batch) = self.batches.get_mut(index) {
batch.texture = texture.clone();
batch.z = z;
batch
} else {
self.batches.push(Batch {
instances: Default::default(),
texture: texture.clone(),
z,
});
self.batches.last_mut().unwrap()
};
let uv_rect = rectangle.uv_rect();
let uv_transform = Vector4::new(uv_rect.x(), uv_rect.y(), uv_rect.w(), uv_rect.h());
batch.instances.push(Instance {
gpu_data: InstanceData {
color: rectangle.color().srgb_to_linear(),
uv_transform,
world_matrix: rectangle.global_transform(),
},
aabb: rectangle.world_bounding_box(),
});
}
}
// Sort back-to-front for correct blending.
self.batches.sort_by(|a, b| {
if a.z < b.z {
Ordering::Greater
} else if a.z > b.z {
Ordering::Less
} else {
Ordering::Equal
}
})
}
}
struct Instance {
gpu_data: InstanceData,
aabb: AxisAlignedBoundingBox,
}
struct Batch {
instances: Vec<Instance>,
texture: Rc<RefCell<GpuTexture>>,
z: f32,
}
impl Renderer2d {
pub(crate) fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
Ok(Self {
sprite_shader: SpriteShader::new(state)?,
quad: Mesh::new_unit_quad(),
geometry_cache: Default::default(),
batch_storage: Default::default(),
instance_data_set: Default::default(),
})
}
pub(crate) fn update_caches(&mut self, dt: f32) {
self.geometry_cache.update(dt);
}
pub(crate) fn render(
&mut self,
state: &mut PipelineState,
camera: &Camera,
frame_buffer: &mut FrameBuffer,
viewport: Rect<i32>,
graph: &Graph,
texture_cache: &mut TextureCache,
white_dummy: Rc<RefCell<GpuTexture>>,
ambient_color: Color,
) -> Result<RenderPassStatistics, FrameworkError> {
let mut stats = RenderPassStatistics::default();
let quad = self.geometry_cache.get(state, &self.quad);
self.batch_storage
.generate_batches(state, graph, texture_cache, white_dummy);
let view_projection = camera.view_projection_matrix();
let frustum = Frustum::from_view_projection_matrix(camera.view_projection_matrix())
.unwrap_or_default();
const MAX_LIGHTS: usize = 16;
let mut light_count = 0;
let mut light_color_radius = [Vector4::default(); MAX_LIGHTS];
let mut light_position = [Vector3::default(); MAX_LIGHTS];
let mut light_direction = [Vector3::default(); MAX_LIGHTS];
let mut light_parameters = [Vector2::default(); MAX_LIGHTS];
for light in graph.linear_iter() {
if !light.global_visibility() || light_count == MAX_LIGHTS {
continue;
}
let (radius, half_cone_angle_cos, half_hotspot_angle_cos, color) =
if let Some(point) = light.cast::<PointLight>() {
(
point.radius(),
std::f32::consts::PI.cos(),
std::f32::consts::PI.cos(),
point.base_light_ref().color().as_frgb(),
)
} else if let Some(spot) = light.cast::<SpotLight>() {
(
spot.distance(),
(spot.hotspot_cone_angle() * 0.5).cos(),
(spot.full_cone_angle() * 0.5).cos(),
spot.base_light_ref().color().as_frgb(),
)
} else if let Some(directional) = light.cast::<DirectionalLight>() {
(
f32::INFINITY,
std::f32::consts::PI.cos(),
std::f32::consts::PI.cos(),
directional.base_light_ref().color().as_frgb(),
)
} else {
continue;
};
if frustum.is_intersects_aabb(&light.world_bounding_box()) {
let light_num = light_count;
light_position[light_num] = light.global_position();
light_direction[light_num] = light.up_vector();
light_color_radius[light_num] = Vector4::new(color.x, color.y, color.z, radius);
light_parameters[light_num] =
Vector2::new(half_cone_angle_cos, half_hotspot_angle_cos);
light_count += 1;
}
}
for batch in self.batch_storage.batches.iter() {
self.instance_data_set.clear();
for instance in batch.instances.iter() {
if frustum.is_intersects_aabb(&instance.aabb) {
self.instance_data_set.push(instance.gpu_data.clone());
}
}
quad.set_buffer_data(state, 1, &self.instance_data_set);
if !self.instance_data_set.is_empty() {
let shader = &self.sprite_shader;
stats += frame_buffer.draw_instances(
self.instance_data_set.len(),
quad,
state,
viewport,
&shader.program,
&DrawParameters {
cull_face: None,
color_write: Default::default(),
depth_write: true,
stencil_test: None,
depth_test: true,
blend: Some(BlendParameters {
func: BlendFunc::new(
BlendFactor::SrcAlpha,
BlendFactor::OneMinusSrcAlpha,
),
..Default::default()
}),
stencil_op: Default::default(),
},
|mut program_binding| {
program_binding
.set_matrix4(&shader.wvp_matrix, &view_projection)
.set_texture(&shader.diffuse_texture, &batch.texture)
.set_i32(&shader.light_count, light_count as i32)
.set_vector4_slice(&shader.light_color_radius, &light_color_radius)
.set_vector3_slice(&shader.light_direction, &light_direction)
.set_vector3_slice(&shader.light_position, &light_position)
.set_vector2_slice(&shader.light_parameters, &light_parameters)
.set_vector3(&shader.ambient_light_color, &ambient_color.as_frgb());
},
);
}
}
Ok(stats)
}
pub fn flush(&mut self) {
self.geometry_cache.clear();
}
}
@@ -1,39 +0,0 @@
uniform sampler2D diffuseTexture;
uniform int lightCount;
uniform vec4 lightColorRadius[16]; // xyz - color, w = radius
uniform vec3 lightPosition[16];
uniform vec3 lightDirection[16];
uniform vec2 lightParameters[16]; // x = hotspot angle, y - full cone angle delta
uniform vec3 ambientLightColor;
out vec4 FragColor;
in vec2 texCoord;
in vec4 color;
in vec3 fragmentPosition;
void main()
{
vec3 lighting = ambientLightColor;
for(int i = 0; i < lightCount; ++i) {
// "Unpack" light parameters.
float halfHotspotAngleCos = lightParameters[i].x;
float halfConeAngleCos = lightParameters[i].y;
vec3 lightColor = lightColorRadius[i].xyz;
float radius = lightColorRadius[i].w;
vec3 lightPosition = lightPosition[i];
vec3 direction = lightDirection[i];
// Calculate lighting.
vec3 toFragment = fragmentPosition - lightPosition;
float distance = length(toFragment);
vec3 toFragmentNormalized = toFragment / distance;
float distanceAttenuation = S_LightDistanceAttenuation(distance, radius);
float spotAngleCos = dot(toFragmentNormalized, direction);
float directionalAttenuation = smoothstep(halfConeAngleCos, halfHotspotAngleCos, spotAngleCos);
lighting += lightColor * (distanceAttenuation * directionalAttenuation);
}
FragColor = vec4(lighting, 1.0) * color * S_SRGBToLinear(texture(diffuseTexture, texCoord));
}
@@ -1,20 +0,0 @@
layout(location = 0) in vec3 vertexPosition;
layout(location = 1) in vec2 vertexTexCoord;
layout(location = 2) in vec4 vertexColor;
layout(location = 3) in vec4 uvTransform;
layout(location = 4) in mat4 worldMatrix;
uniform mat4 viewProjection;
out vec2 texCoord;
out vec4 color;
out vec3 fragmentPosition;
void main()
{
texCoord = vertexTexCoord * uvTransform.zw + uvTransform.xy;
vec4 worldPosition = worldMatrix * vec4(vertexPosition, 1.0);
fragmentPosition = worldPosition.xyz;
gl_Position = viewProjection * worldPosition;
color = vertexColor;
}
+3
View File
@@ -25,6 +25,7 @@ use crate::{
light::directional::{DirectionalLight, FrustumSplitOptions, CSM_NUM_CASCADES},
},
};
use fyrox_core::color::Color;
use std::{cell::RefCell, rc::Rc};
pub struct Cascade {
@@ -307,6 +308,8 @@ impl CsmRenderer {
black_dummy: black_dummy.clone(),
volume_dummy: volume_dummy.clone(),
persistent_identifier: instance.persistent_identifier,
light_data: None, // TODO
ambient_light: Color::WHITE, // TODO
});
},
)?;
+2
View File
@@ -291,6 +291,8 @@ impl PointShadowMapRenderer {
black_dummy: black_dummy.clone(),
volume_dummy: volume_dummy.clone(),
persistent_identifier: instance.persistent_identifier,
light_data: None, // TODO
ambient_light: Color::WHITE, // TODO
});
},
)?;
+2
View File
@@ -208,6 +208,8 @@ impl SpotShadowMapRenderer {
black_dummy: black_dummy.clone(),
volume_dummy: volume_dummy.clone(),
persistent_identifier: instance.persistent_identifier,
light_data: None, // TODO
ambient_light: Color::WHITE, // TODO
});
},
)?;