mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
implemented gamma correction
- every input texture considered as sRGB - resolve #153
This commit is contained in:
@@ -28,6 +28,7 @@ pub mod shared;
|
||||
|
||||
use crate::shared::{create_ui, fix_shadows_distance, Game, GameScene};
|
||||
use rg3d::core::algebra::Vector2;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
event::{Event, VirtualKeyCode, WindowEvent},
|
||||
event_loop::ControlFlow,
|
||||
@@ -170,7 +171,12 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
game.engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = game.engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
|
||||
// Root UI node should be resized too, otherwise progress bar will stay
|
||||
// in wrong position after resize.
|
||||
|
||||
@@ -12,6 +12,7 @@ pub mod shared;
|
||||
use crate::shared::create_camera;
|
||||
use rg3d::core::futures;
|
||||
use rg3d::engine::resource_manager::MaterialSearchOptions;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector2, Vector3},
|
||||
@@ -535,7 +536,12 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
|
||||
// Root UI node should be resized too, otherwise progress bar will stay
|
||||
// in wrong position after resize.
|
||||
|
||||
+4
-1
@@ -11,6 +11,7 @@ pub mod shared;
|
||||
use crate::shared::create_camera;
|
||||
|
||||
use rg3d::core::algebra::{UnitQuaternion, Vector3};
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
core::{color::Color, pool::Handle},
|
||||
engine::resource_manager::{MaterialSearchOptions, ResourceManager},
|
||||
@@ -247,7 +248,9 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(MessageKind::Error, format!("Unable to set frame size: {:?}", e));
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(key_code) = input.virtual_keycode {
|
||||
|
||||
+7
-1
@@ -10,6 +10,7 @@ pub mod shared;
|
||||
|
||||
use crate::shared::create_camera;
|
||||
use rg3d::engine::resource_manager::MaterialSearchOptions;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
core::{
|
||||
algebra::{Matrix4, UnitQuaternion, Vector2, Vector3},
|
||||
@@ -285,7 +286,12 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
// Handle key input events via `WindowEvent`, not via `DeviceEvent` (#32)
|
||||
|
||||
@@ -21,6 +21,7 @@ pub mod shared;
|
||||
|
||||
use crate::shared::{create_ui, fix_shadows_distance, Game, GameScene, LocomotionMachine, Player};
|
||||
use rg3d::core::algebra::Vector2;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
core::{
|
||||
visitor::VisitResult,
|
||||
@@ -255,7 +256,9 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
game.engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = game.engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(MessageKind::Error, format!("Unable to set frame size: {:?}", e));
|
||||
}
|
||||
|
||||
// Root UI node should be resized too, otherwise progress bar will stay
|
||||
// in wrong position after resize.
|
||||
|
||||
+7
-1
@@ -13,6 +13,7 @@ pub mod shared;
|
||||
use crate::shared::create_camera;
|
||||
use rg3d::engine::resource_manager::MaterialSearchOptions;
|
||||
use rg3d::scene::base::BaseBuilder;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
core::{
|
||||
algebra::{UnitQuaternion, Vector3},
|
||||
@@ -190,7 +191,12 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
// Handle key input events via `WindowEvent`, not via `DeviceEvent` (#32)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
+4
-1
@@ -12,6 +12,7 @@ pub mod shared;
|
||||
|
||||
use crate::shared::{create_ui, fix_shadows_distance, Game, GameScene};
|
||||
use rg3d::core::algebra::Vector2;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
animation::AnimationSignal,
|
||||
event::{Event, VirtualKeyCode, WindowEvent},
|
||||
@@ -232,7 +233,9 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
game.engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = game.engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(MessageKind::Error, format!("Unable to set frame size: {:?}", e));
|
||||
}
|
||||
|
||||
// Root UI node should be resized too, otherwise progress bar will stay
|
||||
// in wrong position after resize.
|
||||
|
||||
+14
-3
@@ -12,6 +12,7 @@ pub mod shared;
|
||||
|
||||
use crate::shared::create_camera;
|
||||
use rg3d::engine::resource_manager::MaterialSearchOptions;
|
||||
use rg3d::utils::log::{Log, MessageKind};
|
||||
use rg3d::{
|
||||
animation::Animation,
|
||||
core::{
|
||||
@@ -472,10 +473,15 @@ fn main() {
|
||||
));
|
||||
|
||||
// Due to some weird bug in winit it does not send Resized event.
|
||||
engine.renderer.set_frame_size((
|
||||
if let Err(e) = engine.renderer.set_frame_size((
|
||||
video_mode.size().width,
|
||||
video_mode.size().height,
|
||||
));
|
||||
)) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -498,7 +504,12 @@ fn main() {
|
||||
// It is very important to handle Resized event from window, because
|
||||
// renderer knows nothing about window size - it must be notified
|
||||
// directly when window size has changed.
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { input, .. } => {
|
||||
if let Some(key_code) = input.virtual_keycode {
|
||||
|
||||
@@ -192,6 +192,30 @@ impl Color {
|
||||
Self { r, g, b, a }
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn srgb_to_linear(self) -> Self {
|
||||
let r = ((self.r as f32 / 255.0).powf(2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
let g = ((self.g as f32 / 255.0).powf(2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
let b = ((self.b as f32 / 255.0).powf(2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
Self::from_rgba(r, g, b, self.a)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn srgb_to_linear_f32(self) -> Vector4<f32> {
|
||||
let r = (self.r as f32 / 255.0).powf(2.2).clamp(0.0, 1.0);
|
||||
let g = (self.g as f32 / 255.0).powf(2.2).clamp(0.0, 1.0);
|
||||
let b = (self.b as f32 / 255.0).powf(2.2).clamp(0.0, 1.0);
|
||||
Vector4::new(r, g, b, self.a as f32 / 255.0)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn linear_to_srgb(self) -> Self {
|
||||
let r = ((self.r as f32 / 255.0).powf(1.0 / 2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
let g = ((self.g as f32 / 255.0).powf(1.0 / 2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
let b = ((self.b as f32 / 255.0).powf(1.0 / 2.2).clamp(0.0, 1.0) * 255.0) as u8;
|
||||
Self::from_rgba(r, g, b, self.a)
|
||||
}
|
||||
|
||||
pub fn as_frgba(self) -> Vector4<f32> {
|
||||
Vector4::new(
|
||||
f32::from(self.r) / 255.0,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
//! Once you get familiar with the engine, you should **not** use the framework because it is too
|
||||
//! limiting and may slow you down.
|
||||
|
||||
use crate::utils::log::{Log, MessageKind};
|
||||
use crate::{
|
||||
core::instant::Instant,
|
||||
engine::{error::EngineError, Engine},
|
||||
@@ -134,7 +135,12 @@ impl<State: GameState> Framework<State> {
|
||||
match event {
|
||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||
WindowEvent::Resized(size) => {
|
||||
engine.renderer.set_frame_size(size.into());
|
||||
if let Err(e) = engine.renderer.set_frame_size(size.into()) {
|
||||
Log::writeln(
|
||||
MessageKind::Error,
|
||||
format!("Unable to set frame size: {:?}", e),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -569,7 +569,7 @@ impl DeferredLightRenderer {
|
||||
|program_binding| {
|
||||
program_binding
|
||||
.set_matrix4(&self.ambient_light_shader.wvp_matrix, &frame_matrix)
|
||||
.set_color(&self.ambient_light_shader.ambient_color, &ambient_color)
|
||||
.set_linear_color(&self.ambient_light_shader.ambient_color, &ambient_color)
|
||||
.set_texture(
|
||||
&self.ambient_light_shader.diffuse_texture,
|
||||
&gbuffer_diffuse_map,
|
||||
@@ -833,7 +833,7 @@ impl DeferredLightRenderer {
|
||||
.set_vector3(&shader.light_direction, &emit_direction)
|
||||
.set_f32(&shader.light_radius, light_radius)
|
||||
.set_matrix4(&shader.inv_view_proj_matrix, &inv_view_projection)
|
||||
.set_color(&shader.light_color, &light.color())
|
||||
.set_linear_color(&shader.light_color, &light.color())
|
||||
.set_f32(
|
||||
&shader.half_hotspot_cone_angle_cos,
|
||||
(spot_light.hotspot_cone_angle() * 0.5).cos(),
|
||||
@@ -880,7 +880,7 @@ impl DeferredLightRenderer {
|
||||
.set_vector3(&shader.light_position, &light_position)
|
||||
.set_f32(&shader.light_radius, light_radius)
|
||||
.set_matrix4(&shader.inv_view_proj_matrix, &inv_view_projection)
|
||||
.set_color(&shader.light_color, &light.color())
|
||||
.set_linear_color(&shader.light_color, &light.color())
|
||||
.set_matrix4(&shader.wvp_matrix, &frame_matrix)
|
||||
.set_vector3(&shader.camera_position, &camera_global_position)
|
||||
.set_f32(&shader.shadow_bias, point_light.shadow_bias())
|
||||
@@ -919,7 +919,7 @@ impl DeferredLightRenderer {
|
||||
program_binding
|
||||
.set_vector3(&shader.light_direction, &emit_direction)
|
||||
.set_matrix4(&shader.inv_view_proj_matrix, &inv_view_projection)
|
||||
.set_color(&shader.light_color, &light.color())
|
||||
.set_linear_color(&shader.light_color, &light.color())
|
||||
.set_matrix4(&shader.wvp_matrix, &frame_matrix)
|
||||
.set_vector3(&shader.camera_position, &camera_global_position)
|
||||
.set_texture(&shader.depth_sampler, &gbuffer_depth_map)
|
||||
|
||||
@@ -124,7 +124,7 @@ impl ForwardRenderer {
|
||||
&(view_projection * instance.world_transform),
|
||||
)
|
||||
.set_bool(&self.shader.use_skeletal_animation, batch.is_skinned)
|
||||
.set_color(&self.shader.color, &instance.color)
|
||||
.set_linear_color(&self.shader.color, &instance.color)
|
||||
.set_matrix4_array(
|
||||
&self.shader.bone_matrices,
|
||||
instance.bone_matrices.as_slice(),
|
||||
|
||||
@@ -251,7 +251,18 @@ impl<'a> GpuProgramBinding<'a> {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_color(self, location: &UniformLocation, value: &Color) -> Self {
|
||||
pub fn set_linear_color(self, location: &UniformLocation, value: &Color) -> Self {
|
||||
unsafe {
|
||||
let srgb_a = value.srgb_to_linear_f32();
|
||||
self.state
|
||||
.gl
|
||||
.uniform_4_f32(Some(&location.id), srgb_a.x, srgb_a.y, srgb_a.z, srgb_a.w);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set_srgb_color(self, location: &UniformLocation, value: &Color) -> Self {
|
||||
unsafe {
|
||||
let rgba = value.as_frgba();
|
||||
self.state
|
||||
|
||||
@@ -75,7 +75,9 @@ pub enum PixelKind {
|
||||
D16,
|
||||
D24S8,
|
||||
RGBA8,
|
||||
SRGBA8,
|
||||
RGB8,
|
||||
SRGB8,
|
||||
BGRA8,
|
||||
BGR8,
|
||||
RG8,
|
||||
@@ -92,6 +94,8 @@ pub enum PixelKind {
|
||||
RGBA32F,
|
||||
R8RGTC,
|
||||
RG8RGTC,
|
||||
R11G11B10F,
|
||||
RGB10A2,
|
||||
}
|
||||
|
||||
impl From<TexturePixelKind> for PixelKind {
|
||||
@@ -129,14 +133,18 @@ impl PixelKind {
|
||||
match self {
|
||||
Self::RGBA16 | Self::RGB16 | Self::RGBA32F => 8,
|
||||
Self::RGBA8
|
||||
| Self::SRGBA8
|
||||
| Self::RGB8
|
||||
| Self::SRGB8
|
||||
| Self::BGRA8
|
||||
| Self::BGR8
|
||||
| Self::RG16
|
||||
| Self::R16
|
||||
| Self::D24S8
|
||||
| Self::D32F
|
||||
| Self::F32 => 4,
|
||||
| Self::F32
|
||||
| Self::R11G11B10F
|
||||
| Self::RGB10A2 => 4,
|
||||
Self::RG8 | Self::D16 | Self::F16 => 2,
|
||||
Self::R8 | Self::R8UI => 1,
|
||||
Self::DXT1RGB
|
||||
@@ -161,7 +169,9 @@ impl PixelKind {
|
||||
Self::RGBA16
|
||||
| Self::RGB16
|
||||
| Self::RGBA8
|
||||
| Self::SRGBA8
|
||||
| Self::RGB8
|
||||
| Self::SRGB8
|
||||
| Self::BGRA8
|
||||
| Self::BGR8
|
||||
| Self::RG16
|
||||
@@ -174,34 +184,39 @@ impl PixelKind {
|
||||
| Self::F16
|
||||
| Self::R8
|
||||
| Self::R8UI
|
||||
| Self::RGBA32F => false,
|
||||
| Self::RGBA32F
|
||||
| Self::R11G11B10F
|
||||
| Self::RGB10A2 => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn element_kind(self) -> PixelElementKind {
|
||||
match self {
|
||||
PixelKind::F32 | PixelKind::F16 | PixelKind::RGBA32F | PixelKind::D32F => {
|
||||
Self::F32 | Self::F16 | Self::RGBA32F | Self::D32F | Self::R11G11B10F => {
|
||||
PixelElementKind::Float
|
||||
}
|
||||
PixelKind::D16
|
||||
| PixelKind::D24S8
|
||||
| PixelKind::RGBA8
|
||||
| PixelKind::RGB8
|
||||
| PixelKind::BGRA8
|
||||
| PixelKind::BGR8
|
||||
| PixelKind::RG8
|
||||
| PixelKind::RG16
|
||||
| PixelKind::R8
|
||||
| PixelKind::R16
|
||||
| PixelKind::RGB16
|
||||
| PixelKind::RGBA16
|
||||
| PixelKind::DXT1RGB
|
||||
| PixelKind::DXT1RGBA
|
||||
| PixelKind::DXT3RGBA
|
||||
| PixelKind::DXT5RGBA
|
||||
| PixelKind::R8RGTC
|
||||
| PixelKind::RG8RGTC => PixelElementKind::NormalizedUnsignedInteger,
|
||||
PixelKind::R8UI => PixelElementKind::UnsignedInteger,
|
||||
Self::D16
|
||||
| Self::D24S8
|
||||
| Self::RGBA8
|
||||
| Self::SRGBA8
|
||||
| Self::RGB8
|
||||
| Self::SRGB8
|
||||
| Self::BGRA8
|
||||
| Self::BGR8
|
||||
| Self::RG8
|
||||
| Self::RG16
|
||||
| Self::R8
|
||||
| Self::R16
|
||||
| Self::RGB16
|
||||
| Self::RGBA16
|
||||
| Self::DXT1RGB
|
||||
| Self::DXT1RGBA
|
||||
| Self::DXT3RGBA
|
||||
| Self::DXT5RGBA
|
||||
| Self::R8RGTC
|
||||
| Self::RG8RGTC
|
||||
| Self::RGB10A2 => PixelElementKind::NormalizedUnsignedInteger,
|
||||
Self::R8UI => PixelElementKind::UnsignedInteger,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,12 +247,15 @@ fn image_3d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize, depth
|
||||
PixelKind::RGBA16 => 8 * pixel_count,
|
||||
PixelKind::RGB16 => 6 * pixel_count,
|
||||
PixelKind::RGBA8
|
||||
| PixelKind::SRGBA8
|
||||
| PixelKind::BGRA8
|
||||
| PixelKind::RG16
|
||||
| PixelKind::D24S8
|
||||
| PixelKind::D32F
|
||||
| PixelKind::F32 => 4 * pixel_count,
|
||||
PixelKind::RGB8 | PixelKind::BGR8 => 3 * pixel_count,
|
||||
| PixelKind::F32
|
||||
| PixelKind::R11G11B10F
|
||||
| PixelKind::RGB10A2 => 4 * pixel_count,
|
||||
PixelKind::RGB8 | PixelKind::SRGB8 | PixelKind::BGR8 => 3 * pixel_count,
|
||||
PixelKind::RG8 | PixelKind::R16 | PixelKind::D16 | PixelKind::F16 => 2 * pixel_count,
|
||||
PixelKind::R8 | PixelKind::R8UI => pixel_count,
|
||||
PixelKind::DXT1RGB | PixelKind::DXT1RGBA | PixelKind::R8RGTC => {
|
||||
@@ -258,12 +276,15 @@ fn image_2d_size_bytes(pixel_kind: PixelKind, width: usize, height: usize) -> us
|
||||
PixelKind::RGBA16 => 8 * pixel_count,
|
||||
PixelKind::RGB16 => 6 * pixel_count,
|
||||
PixelKind::RGBA8
|
||||
| PixelKind::SRGBA8
|
||||
| PixelKind::BGRA8
|
||||
| PixelKind::RG16
|
||||
| PixelKind::D24S8
|
||||
| PixelKind::D32F
|
||||
| PixelKind::F32 => 4 * pixel_count,
|
||||
PixelKind::RGB8 | PixelKind::BGR8 => 3 * pixel_count,
|
||||
| PixelKind::F32
|
||||
| PixelKind::R11G11B10F
|
||||
| PixelKind::RGB10A2 => 4 * pixel_count,
|
||||
PixelKind::RGB8 | PixelKind::SRGB8 | PixelKind::BGR8 => 3 * pixel_count,
|
||||
PixelKind::RG8 | PixelKind::R16 | PixelKind::D16 | PixelKind::F16 => 2 * pixel_count,
|
||||
PixelKind::R8 | PixelKind::R8UI => pixel_count,
|
||||
PixelKind::DXT1RGB | PixelKind::DXT1RGBA | PixelKind::R8RGTC => {
|
||||
@@ -283,12 +304,15 @@ fn image_1d_size_bytes(pixel_kind: PixelKind, length: usize) -> usize {
|
||||
PixelKind::RGBA16 => 8 * length,
|
||||
PixelKind::RGB16 => 6 * length,
|
||||
PixelKind::RGBA8
|
||||
| PixelKind::SRGBA8
|
||||
| PixelKind::BGRA8
|
||||
| PixelKind::RG16
|
||||
| PixelKind::D24S8
|
||||
| PixelKind::D32F
|
||||
| PixelKind::F32 => 4 * length,
|
||||
PixelKind::RGB8 | PixelKind::BGR8 => 3 * length,
|
||||
| PixelKind::F32
|
||||
| PixelKind::R11G11B10F
|
||||
| PixelKind::RGB10A2 => 4 * length,
|
||||
PixelKind::RGB8 | PixelKind::SRGB8 | PixelKind::BGR8 => 3 * length,
|
||||
PixelKind::RG8 | PixelKind::R16 | PixelKind::D16 | PixelKind::F16 => 2 * length,
|
||||
PixelKind::R8 | PixelKind::R8UI => length,
|
||||
PixelKind::DXT1RGB | PixelKind::DXT1RGBA | PixelKind::R8RGTC => {
|
||||
@@ -612,7 +636,9 @@ impl<'a> TextureBinding<'a> {
|
||||
glow::DEPTH24_STENCIL8,
|
||||
),
|
||||
PixelKind::RGBA8 => (glow::UNSIGNED_BYTE, glow::RGBA, glow::RGBA8),
|
||||
PixelKind::SRGBA8 => (glow::UNSIGNED_BYTE, glow::RGBA, glow::SRGB8_ALPHA8),
|
||||
PixelKind::RGB8 => (glow::UNSIGNED_BYTE, glow::RGB, glow::RGB8),
|
||||
PixelKind::SRGB8 => (glow::UNSIGNED_BYTE, glow::RGB, glow::SRGB8),
|
||||
PixelKind::RG8 => (glow::UNSIGNED_BYTE, glow::RG, glow::RG8),
|
||||
PixelKind::R8 => (glow::UNSIGNED_BYTE, glow::RED, glow::R8),
|
||||
PixelKind::R8UI => (glow::UNSIGNED_BYTE, glow::RED_INTEGER, glow::R8UI),
|
||||
@@ -622,6 +648,7 @@ impl<'a> TextureBinding<'a> {
|
||||
PixelKind::R16 => (glow::UNSIGNED_SHORT, glow::RED, glow::R16),
|
||||
PixelKind::RGB16 => (glow::UNSIGNED_SHORT, glow::RGB, glow::RGB16),
|
||||
PixelKind::RGBA16 => (glow::UNSIGNED_SHORT, glow::RGBA, glow::RGBA16),
|
||||
PixelKind::RGB10A2 => (glow::UNSIGNED_BYTE, glow::RGBA, glow::RGB10_A2),
|
||||
PixelKind::DXT1RGB => (0, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT),
|
||||
PixelKind::DXT1RGBA => (0, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT),
|
||||
PixelKind::DXT3RGBA => (0, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT),
|
||||
@@ -629,6 +656,7 @@ impl<'a> TextureBinding<'a> {
|
||||
PixelKind::R8RGTC => (0, 0, COMPRESSED_RED_RGTC1),
|
||||
PixelKind::RG8RGTC => (0, 0, COMPRESSED_RG_RGTC2),
|
||||
PixelKind::RGBA32F => (glow::FLOAT, glow::RGBA, glow::RGBA32F),
|
||||
PixelKind::R11G11B10F => (glow::FLOAT, glow::RGB, glow::R11F_G11F_B10F),
|
||||
};
|
||||
|
||||
let is_compressed = pixel_kind.is_compressed();
|
||||
|
||||
@@ -287,4 +287,14 @@ vec2 S_ComputeParallaxTextureCoordinates(in sampler2D heightTexture, vec3 eyeVec
|
||||
float weight = nextH / (nextH - prevH);
|
||||
|
||||
return prev * weight + currentTexCoords * (1.0 - weight);
|
||||
}
|
||||
|
||||
vec4 S_LinearToSRGB(vec4 color) {
|
||||
vec3 rgb = pow(color.rgb, vec3(1.0 / 2.2));
|
||||
return vec4(rgb, color.a);
|
||||
}
|
||||
|
||||
vec4 S_SRGBToLinear(vec4 color) {
|
||||
vec3 rgb = pow(color.rgb, vec3(2.2));
|
||||
return vec4(rgb, color.a);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
use crate::renderer::framework::framebuffer::FrameBuffer;
|
||||
use crate::{
|
||||
core::{
|
||||
algebra::{Matrix4, Vector3},
|
||||
math::Rect,
|
||||
},
|
||||
renderer::framework::{
|
||||
error::FrameworkError,
|
||||
framebuffer::{CullFace, DrawParameters},
|
||||
gpu_program::{GpuProgram, UniformLocation},
|
||||
gpu_texture::GpuTexture,
|
||||
state::PipelineState,
|
||||
},
|
||||
renderer::{GeometryCache, RenderPassStatistics},
|
||||
scene::mesh::surface::SurfaceData,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
struct Shader {
|
||||
pub program: GpuProgram,
|
||||
pub wvp_matrix: UniformLocation,
|
||||
pub screen_texture: UniformLocation,
|
||||
}
|
||||
|
||||
impl Shader {
|
||||
pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
|
||||
let fragment_source = include_str!("shaders/gamma_fs.glsl");
|
||||
let vertex_source = include_str!("shaders/flat_vs.glsl");
|
||||
|
||||
let program =
|
||||
GpuProgram::from_source(state, "GammaShader", vertex_source, fragment_source)?;
|
||||
Ok(Self {
|
||||
wvp_matrix: program.uniform_location(state, "worldViewProjection")?,
|
||||
screen_texture: program.uniform_location(state, "screenTexture")?,
|
||||
program,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GammaCorrectionPass {
|
||||
shader: Shader,
|
||||
quad: SurfaceData,
|
||||
}
|
||||
|
||||
impl GammaCorrectionPass {
|
||||
pub fn new(state: &mut PipelineState) -> Result<Self, FrameworkError> {
|
||||
Ok(Self {
|
||||
shader: Shader::new(state)?,
|
||||
quad: SurfaceData::make_unit_xy_quad(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(in crate) fn render(
|
||||
&self,
|
||||
state: &mut PipelineState,
|
||||
viewport: Rect<i32>,
|
||||
frame_texture: Rc<RefCell<GpuTexture>>,
|
||||
frame_buffer: &mut FrameBuffer,
|
||||
geom_cache: &mut GeometryCache,
|
||||
) -> RenderPassStatistics {
|
||||
let mut statistics = RenderPassStatistics::default();
|
||||
|
||||
let quad = geom_cache.get(state, &self.quad);
|
||||
|
||||
let frame_matrix = Matrix4::new_orthographic(
|
||||
0.0,
|
||||
viewport.w() as f32,
|
||||
viewport.h() as f32,
|
||||
0.0,
|
||||
-1.0,
|
||||
1.0,
|
||||
) * Matrix4::new_nonuniform_scaling(&Vector3::new(
|
||||
viewport.w() as f32,
|
||||
viewport.h() as f32,
|
||||
0.0,
|
||||
));
|
||||
|
||||
statistics += frame_buffer.draw(
|
||||
quad,
|
||||
state,
|
||||
viewport,
|
||||
&self.shader.program,
|
||||
&DrawParameters {
|
||||
cull_face: CullFace::Back,
|
||||
culling: false,
|
||||
color_write: Default::default(),
|
||||
depth_write: false,
|
||||
stencil_test: false,
|
||||
depth_test: false,
|
||||
blend: false,
|
||||
},
|
||||
|program_binding| {
|
||||
program_binding
|
||||
.set_matrix4(&self.shader.wvp_matrix, &frame_matrix)
|
||||
.set_texture(&self.shader.screen_texture, &frame_texture);
|
||||
},
|
||||
);
|
||||
|
||||
statistics
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,10 @@
|
||||
//! GBuffer Layout:
|
||||
//!
|
||||
//! RT0: sRGBA8 - Diffuse color.
|
||||
//! RT1: RGBA8 - Normal (xyz) + specular (w)
|
||||
//! RT2: RGBA8 - Ambient light + emission
|
||||
//! RT3: R8UI - Decal mask
|
||||
|
||||
use crate::{
|
||||
core::{
|
||||
algebra::{Matrix4, Vector2, Vector4},
|
||||
@@ -87,7 +94,7 @@ impl GBuffer {
|
||||
let mut diffuse_texture = GpuTexture::new(
|
||||
state,
|
||||
GpuTextureKind::Rectangle { width, height },
|
||||
PixelKind::RGBA8,
|
||||
PixelKind::SRGBA8,
|
||||
MinificationFilter::Nearest,
|
||||
MagnificationFilter::Nearest,
|
||||
1,
|
||||
@@ -187,7 +194,7 @@ impl GBuffer {
|
||||
let frame_texture = GpuTexture::new(
|
||||
state,
|
||||
GpuTextureKind::Rectangle { width, height },
|
||||
PixelKind::RGBA8,
|
||||
PixelKind::RGB10A2,
|
||||
MinificationFilter::Linear,
|
||||
MagnificationFilter::Linear,
|
||||
1,
|
||||
@@ -434,7 +441,10 @@ impl GBuffer {
|
||||
initial_view_projection
|
||||
};
|
||||
program_binding
|
||||
.set_color(shader.diffuse_color.as_ref().unwrap(), &instance.color)
|
||||
.set_linear_color(
|
||||
shader.diffuse_color.as_ref().unwrap(),
|
||||
&instance.color,
|
||||
)
|
||||
.set_matrix4(
|
||||
shader.wvp_matrix.as_ref().unwrap(),
|
||||
&(view_projection * instance.world_transform),
|
||||
@@ -535,7 +545,7 @@ impl GBuffer {
|
||||
.set_texture(&shader.normal_texture, &normal_texture)
|
||||
.set_texture(&shader.decal_mask, &decal_mask)
|
||||
.set_u32(&shader.layer_index, decal.layer() as u32)
|
||||
.set_color(&shader.color, &decal.color());
|
||||
.set_linear_color(&shader.color, &decal.color());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -240,7 +240,10 @@ impl LightVolumeRenderer {
|
||||
.set_vector3(&shader.light_position, &position)
|
||||
.set_vector3(&shader.light_direction, &direction)
|
||||
.set_texture(&shader.depth_sampler, &depth_map)
|
||||
.set_vector3(&shader.light_color, &light.color().as_frgba().xyz())
|
||||
.set_vector3(
|
||||
&shader.light_color,
|
||||
&light.color().srgb_to_linear_f32().xyz(),
|
||||
)
|
||||
.set_vector3(&shader.scatter_factor, &light.scatter());
|
||||
},
|
||||
)
|
||||
@@ -321,7 +324,10 @@ impl LightVolumeRenderer {
|
||||
.set_vector3(&shader.light_position, &position)
|
||||
.set_texture(&shader.depth_sampler, &depth_map)
|
||||
.set_f32(&shader.light_radius, point.radius())
|
||||
.set_vector3(&shader.light_color, &light.color().as_frgba().xyz())
|
||||
.set_vector3(
|
||||
&shader.light_color,
|
||||
&light.color().srgb_to_linear_f32().xyz(),
|
||||
)
|
||||
.set_vector3(&shader.scatter_factor, &light.scatter());
|
||||
},
|
||||
)
|
||||
|
||||
+112
-8
@@ -19,6 +19,7 @@ mod deferred_light_renderer;
|
||||
mod flat_shader;
|
||||
mod forward_renderer;
|
||||
mod fxaa;
|
||||
mod gamma;
|
||||
mod gbuffer;
|
||||
mod light_volume;
|
||||
mod particle_system_renderer;
|
||||
@@ -29,6 +30,7 @@ mod ssao;
|
||||
mod ui_renderer;
|
||||
|
||||
use crate::renderer::cache::CacheEntry;
|
||||
use crate::renderer::gamma::GammaCorrectionPass;
|
||||
use crate::scene::camera::Camera;
|
||||
use crate::{
|
||||
core::{
|
||||
@@ -416,6 +418,71 @@ impl TextureUploadSender {
|
||||
}
|
||||
}
|
||||
|
||||
struct PostProcessingChain {
|
||||
framebuffers: [FrameBuffer; 2],
|
||||
swap: bool,
|
||||
}
|
||||
|
||||
struct PostProcessingPair<'a> {
|
||||
screen_texture: Rc<RefCell<GpuTexture>>,
|
||||
framebuffer: &'a mut FrameBuffer,
|
||||
}
|
||||
|
||||
impl PostProcessingChain {
|
||||
fn new(state: &mut PipelineState, width: usize, height: usize) -> Result<Self, FrameworkError> {
|
||||
fn make_framebuffer(
|
||||
state: &mut PipelineState,
|
||||
width: usize,
|
||||
height: usize,
|
||||
) -> Result<FrameBuffer, FrameworkError> {
|
||||
let frame_texture = GpuTexture::new(
|
||||
state,
|
||||
GpuTextureKind::Rectangle { width, height },
|
||||
PixelKind::RGB10A2,
|
||||
MinificationFilter::Nearest,
|
||||
MagnificationFilter::Nearest,
|
||||
1,
|
||||
None,
|
||||
)?;
|
||||
|
||||
FrameBuffer::new(
|
||||
state,
|
||||
None,
|
||||
vec![Attachment {
|
||||
kind: AttachmentKind::Color,
|
||||
texture: Rc::new(RefCell::new(frame_texture)),
|
||||
}],
|
||||
)
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
framebuffers: [
|
||||
make_framebuffer(state, width, height)?,
|
||||
make_framebuffer(state, width, height)?,
|
||||
],
|
||||
swap: false,
|
||||
})
|
||||
}
|
||||
|
||||
fn begin_pass(&mut self) -> PostProcessingPair {
|
||||
let out = if self.swap {
|
||||
PostProcessingPair {
|
||||
screen_texture: self.framebuffers[0].color_attachments()[0].texture.clone(),
|
||||
framebuffer: &mut self.framebuffers[1],
|
||||
}
|
||||
} else {
|
||||
PostProcessingPair {
|
||||
screen_texture: self.framebuffers[1].color_attachments()[0].texture.clone(),
|
||||
framebuffer: &mut self.framebuffers[0],
|
||||
}
|
||||
};
|
||||
|
||||
self.swap = !self.swap;
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
/// See module docs.
|
||||
pub struct Renderer {
|
||||
backbuffer: FrameBuffer,
|
||||
@@ -453,6 +520,8 @@ pub struct Renderer {
|
||||
renderer2d: Renderer2d,
|
||||
texture_upload_receiver: Receiver<Texture>,
|
||||
texture_upload_sender: Sender<Texture>,
|
||||
post_processing_chain: PostProcessingChain,
|
||||
gamma_correction_pass: GammaCorrectionPass,
|
||||
// TextureId -> FrameBuffer mapping. This mapping is used for temporal frame buffers
|
||||
// like ones used to render UI instances.
|
||||
ui_frame_buffers: HashMap<usize, FrameBuffer>,
|
||||
@@ -694,6 +763,12 @@ impl Renderer {
|
||||
fxaa_renderer: FxaaRenderer::new(&mut state)?,
|
||||
statistics: Statistics::default(),
|
||||
renderer2d: Renderer2d::new(&mut state)?,
|
||||
gamma_correction_pass: GammaCorrectionPass::new(&mut state)?,
|
||||
post_processing_chain: PostProcessingChain::new(
|
||||
&mut state,
|
||||
frame_size.0 as usize,
|
||||
frame_size.1 as usize,
|
||||
)?,
|
||||
texture_upload_receiver,
|
||||
texture_upload_sender,
|
||||
state,
|
||||
@@ -738,12 +813,20 @@ impl Renderer {
|
||||
///
|
||||
/// Input values will be set to 1 pixel if new size is 0. Rendering cannot
|
||||
/// be performed into 0x0 texture.
|
||||
pub fn set_frame_size(&mut self, new_size: (u32, u32)) {
|
||||
self.deferred_light_renderer
|
||||
.set_frame_size(&mut self.state, new_size)
|
||||
.unwrap();
|
||||
pub fn set_frame_size(&mut self, new_size: (u32, u32)) -> Result<(), FrameworkError> {
|
||||
self.frame_size.0 = new_size.0.max(1);
|
||||
self.frame_size.1 = new_size.1.max(1);
|
||||
|
||||
self.deferred_light_renderer
|
||||
.set_frame_size(&mut self.state, new_size)?;
|
||||
|
||||
self.post_processing_chain = PostProcessingChain::new(
|
||||
&mut self.state,
|
||||
self.frame_size.0 as usize,
|
||||
self.frame_size.1 as usize,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns current (width, height) pair of back buffer size.
|
||||
@@ -906,6 +989,15 @@ impl Renderer {
|
||||
let backbuffer_width = self.frame_size.0 as f32;
|
||||
let backbuffer_height = self.frame_size.1 as f32;
|
||||
|
||||
let post_processing_pair = self.post_processing_chain.begin_pass();
|
||||
post_processing_pair.framebuffer.clear(
|
||||
&mut self.state,
|
||||
window_viewport,
|
||||
Some(Color::BLACK),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
for (scene_handle, scene) in scenes.pair_iter().filter(|(_, s)| s.enabled) {
|
||||
let graph = &scene.graph;
|
||||
|
||||
@@ -1086,12 +1178,12 @@ impl Renderer {
|
||||
state,
|
||||
viewport,
|
||||
gbuffer.frame_texture(),
|
||||
&mut self.backbuffer,
|
||||
post_processing_pair.framebuffer,
|
||||
&mut self.geometry_cache,
|
||||
);
|
||||
} else {
|
||||
let shader = &self.flat_shader;
|
||||
self.statistics.geometry += self.backbuffer.draw(
|
||||
self.statistics.geometry += post_processing_pair.framebuffer.draw(
|
||||
self.geometry_cache.get(state, &self.quad),
|
||||
state,
|
||||
viewport,
|
||||
@@ -1131,14 +1223,26 @@ impl Renderer {
|
||||
|
||||
self.statistics += self.renderer2d.render(
|
||||
&mut self.state,
|
||||
&mut self.backbuffer,
|
||||
post_processing_pair.framebuffer,
|
||||
Vector2::new(backbuffer_width, backbuffer_height),
|
||||
scenes2d,
|
||||
&mut self.texture_cache,
|
||||
self.white_dummy.clone(),
|
||||
)?;
|
||||
|
||||
// Render UI on top of everything.
|
||||
drop(post_processing_pair);
|
||||
|
||||
let post_processing_pair = self.post_processing_chain.begin_pass();
|
||||
|
||||
self.statistics += self.gamma_correction_pass.render(
|
||||
&mut self.state,
|
||||
window_viewport,
|
||||
post_processing_pair.screen_texture,
|
||||
&mut self.backbuffer,
|
||||
&mut self.geometry_cache,
|
||||
);
|
||||
|
||||
// Render UI on top of everything without gamma correction.
|
||||
self.statistics += self.ui_renderer.render(UiRenderContext {
|
||||
state: &mut self.state,
|
||||
viewport: window_viewport,
|
||||
|
||||
@@ -165,7 +165,7 @@ impl BatchStorage {
|
||||
|
||||
batch.instances.push(Instance {
|
||||
gpu_data: InstanceData {
|
||||
color: sprite.color(),
|
||||
color: sprite.color().srgb_to_linear(),
|
||||
world_matrix: sprite.global_transform()
|
||||
* Matrix4::new_scaling(sprite.size()),
|
||||
},
|
||||
@@ -307,7 +307,7 @@ impl Renderer2d {
|
||||
|
||||
if viewport_f32.intersects_circle(position, radius) {
|
||||
let light_num = light_count as usize;
|
||||
let color = light.color().as_frgb();
|
||||
let color = light.color().srgb_to_linear().as_frgb();
|
||||
|
||||
light_position_direction[light_num] =
|
||||
Vector4::new(position.x, position.y, direction.x, direction.y);
|
||||
|
||||
@@ -36,5 +36,5 @@ void main()
|
||||
lighting += lightColor * (distanceAttenuation * directionalAttenuation);
|
||||
}
|
||||
|
||||
FragColor = vec4(lighting, 1.0) * color * texture(diffuseTexture, texCoord);
|
||||
FragColor = vec4(lighting, 1.0) * color * S_SRGBToLinear(texture(diffuseTexture, texCoord));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#version 330 core
|
||||
|
||||
uniform sampler2D screenTexture;
|
||||
|
||||
in vec2 texCoord;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = S_LinearToSRGB(texture(screenTexture, texCoord));
|
||||
}
|
||||
@@ -22,6 +22,6 @@ void main()
|
||||
float sceneDepth = toProjSpace(texture(depthBufferTexture, gl_FragCoord.xy * invScreenSize).r);
|
||||
float fragmentDepth = toProjSpace(gl_FragCoord.z);
|
||||
float depthOpacity = smoothstep((sceneDepth - fragmentDepth) * softBoundarySharpnessFactor, 0.0, 1.0);
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
FragColor = color * S_SRGBToLinear(texture(diffuseTexture, texCoord)).r;
|
||||
FragColor.a *= depthOpacity;
|
||||
}
|
||||
@@ -35,5 +35,5 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
FragColor = vec4(lightColor * scatter, 1.0);
|
||||
FragColor = vec4(lightColor * pow(scatter, vec3(2.2)), 1.0);
|
||||
}
|
||||
@@ -8,5 +8,5 @@ in vec3 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(cubemapTexture, texCoord);
|
||||
FragColor = S_SRGBToLinear(texture(cubemapTexture, texCoord));
|
||||
}
|
||||
|
||||
@@ -59,5 +59,5 @@ void main()
|
||||
}
|
||||
}
|
||||
|
||||
FragColor = vec4(lightColor * scatter, 1.0);
|
||||
FragColor = vec4(lightColor * pow(scatter, vec3(2.2)), 1.0);
|
||||
}
|
||||
@@ -9,5 +9,5 @@ in vec2 texCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = color * texture(diffuseTexture, texCoord).r;
|
||||
FragColor = color * S_SRGBToLinear(texture(diffuseTexture, texCoord)).r;
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
#version 330 core
|
||||
|
||||
// IMPORTANT: UI is rendered in sRGB color space!
|
||||
|
||||
uniform sampler2D diffuseTexture;
|
||||
uniform bool isRenderTarget;
|
||||
|
||||
uniform bool isFont;
|
||||
uniform vec4 solidColor;
|
||||
uniform float opacity;
|
||||
@@ -71,13 +75,18 @@ void main()
|
||||
fragColor = mix(gradientColors[current], gradientColors[next], mix_factor);
|
||||
}
|
||||
|
||||
vec4 diffuseColor = texture(diffuseTexture, texCoord);
|
||||
if (isRenderTarget) {
|
||||
diffuseColor = S_LinearToSRGB(diffuseColor);
|
||||
}
|
||||
|
||||
if (isFont)
|
||||
{
|
||||
fragColor.a *= texture(diffuseTexture, texCoord).r;
|
||||
fragColor.a *= diffuseColor.r;
|
||||
}
|
||||
else
|
||||
{
|
||||
fragColor *= texture(diffuseTexture, texCoord);
|
||||
fragColor *= diffuseColor;
|
||||
}
|
||||
|
||||
fragColor.a *= opacity;
|
||||
|
||||
@@ -29,7 +29,8 @@ 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, "FlatShader", vertex_source, fragment_source)?;
|
||||
let program =
|
||||
GpuProgram::from_source(state, "SpriteShader", vertex_source, fragment_source)?;
|
||||
Ok(Self {
|
||||
view_projection_matrix: program.uniform_location(state, "viewProjectionMatrix")?,
|
||||
world_matrix: program.uniform_location(state, "worldMatrix")?,
|
||||
@@ -147,7 +148,7 @@ impl SpriteRenderer {
|
||||
.set_vector3(&self.shader.camera_up_vector, &camera_up)
|
||||
.set_vector3(&self.shader.camera_side_vector, &camera_side)
|
||||
.set_f32(&self.shader.size, sprite.size())
|
||||
.set_color(&self.shader.color, &sprite.color())
|
||||
.set_linear_color(&self.shader.color, &sprite.color())
|
||||
.set_f32(&self.shader.rotation, sprite.rotation());
|
||||
},
|
||||
);
|
||||
|
||||
@@ -48,6 +48,7 @@ struct UiShader {
|
||||
bounds_min: UniformLocation,
|
||||
bounds_max: UniformLocation,
|
||||
opacity: UniformLocation,
|
||||
is_render_target: UniformLocation,
|
||||
}
|
||||
|
||||
impl UiShader {
|
||||
@@ -70,6 +71,7 @@ impl UiShader {
|
||||
bounds_max: program.uniform_location(state, "boundsMax")?,
|
||||
resolution: program.uniform_location(state, "resolution")?,
|
||||
opacity: program.uniform_location(state, "opacity")?,
|
||||
is_render_target: program.uniform_location(state, "isRenderTarget")?,
|
||||
program,
|
||||
})
|
||||
}
|
||||
@@ -179,6 +181,9 @@ impl UiRenderer {
|
||||
for cmd in drawing_context.get_commands() {
|
||||
let mut diffuse_texture = white_dummy.clone();
|
||||
let mut is_font_texture = false;
|
||||
// Render targets are in linear color space, so we must convert them to sRGB
|
||||
// before drawing on screen.
|
||||
let mut is_render_target = false;
|
||||
|
||||
let mut clip_bounds = cmd.clip_bounds;
|
||||
clip_bounds.position.x = clip_bounds.position.x.floor();
|
||||
@@ -287,9 +292,9 @@ impl UiRenderer {
|
||||
}
|
||||
CommandTexture::Texture(texture) => {
|
||||
if let Ok(texture) = texture.clone().0.downcast::<Mutex<TextureState>>() {
|
||||
if let Some(texture) =
|
||||
texture_cache.get(state, &Texture(Resource::from(texture)))
|
||||
{
|
||||
let resource = Resource::from(texture);
|
||||
is_render_target = resource.data_ref().is_render_target();
|
||||
if let Some(texture) = texture_cache.get(state, &Texture(resource)) {
|
||||
diffuse_texture = texture;
|
||||
}
|
||||
}
|
||||
@@ -334,6 +339,7 @@ impl UiRenderer {
|
||||
.set_vector2(&shader.bounds_min, &cmd.bounds.position)
|
||||
.set_vector2(&shader.bounds_max, &bounds_max)
|
||||
.set_bool(&shader.is_font, is_font_texture)
|
||||
.set_bool(&shader.is_render_target, is_render_target)
|
||||
.set_i32(
|
||||
&shader.brush_type,
|
||||
match cmd.brush {
|
||||
@@ -342,7 +348,7 @@ impl UiRenderer {
|
||||
Brush::RadialGradient { .. } => 2,
|
||||
},
|
||||
)
|
||||
.set_color(
|
||||
.set_srgb_color(
|
||||
&shader.solid_color,
|
||||
&match cmd.brush {
|
||||
Brush::Solid(color) => color,
|
||||
|
||||
@@ -158,6 +158,7 @@ pub struct TextureData {
|
||||
anisotropy: f32,
|
||||
serialize_content: bool,
|
||||
data_hash: u64,
|
||||
is_render_target: bool,
|
||||
}
|
||||
|
||||
impl ResourceData for TextureData {
|
||||
@@ -223,6 +224,7 @@ impl Default for TextureData {
|
||||
anisotropy: 16.0,
|
||||
serialize_content: false,
|
||||
data_hash: 0,
|
||||
is_render_target: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,6 +256,7 @@ impl Texture {
|
||||
anisotropy: 1.0,
|
||||
serialize_content: false,
|
||||
data_hash: 0,
|
||||
is_render_target: true,
|
||||
})))
|
||||
}
|
||||
|
||||
@@ -966,6 +969,11 @@ impl TextureData {
|
||||
&self.bytes
|
||||
}
|
||||
|
||||
/// Returns true if the texture is used as render target.
|
||||
pub fn is_render_target(&self) -> bool {
|
||||
self.is_render_target
|
||||
}
|
||||
|
||||
/// Max samples for anisotropic filtering. Default value is 16.0 (max).
|
||||
/// However real value passed to GPU will be clamped to maximum supported
|
||||
/// by current GPU. To disable anisotropic filtering set this to 1.0.
|
||||
|
||||
@@ -235,6 +235,12 @@ impl BaseLight {
|
||||
self.scatter
|
||||
}
|
||||
|
||||
/// Returns current scatter factor in linear color space.
|
||||
#[inline]
|
||||
pub fn scatter_linear(&self) -> Vector3<f32> {
|
||||
self.scatter.map(|v| v.powf(2.2))
|
||||
}
|
||||
|
||||
/// Enables or disables light scattering.
|
||||
#[inline]
|
||||
pub fn enable_scatter(&mut self, state: bool) {
|
||||
|
||||
@@ -334,12 +334,14 @@ impl ParticleSystem {
|
||||
for (i, particle_index) in sorted_particles.iter().enumerate() {
|
||||
let particle = self.particles.get(*particle_index as usize).unwrap();
|
||||
|
||||
let linear_color = particle.color.srgb_to_linear();
|
||||
|
||||
draw_data.vertices.push(Vertex {
|
||||
position: particle.position,
|
||||
tex_coord: Vector2::default(),
|
||||
size: particle.size,
|
||||
rotation: particle.rotation,
|
||||
color: particle.color,
|
||||
color: linear_color,
|
||||
});
|
||||
|
||||
draw_data.vertices.push(Vertex {
|
||||
@@ -347,7 +349,7 @@ impl ParticleSystem {
|
||||
tex_coord: Vector2::new(1.0, 0.0),
|
||||
size: particle.size,
|
||||
rotation: particle.rotation,
|
||||
color: particle.color,
|
||||
color: linear_color,
|
||||
});
|
||||
|
||||
draw_data.vertices.push(Vertex {
|
||||
@@ -355,7 +357,7 @@ impl ParticleSystem {
|
||||
tex_coord: Vector2::new(1.0, 1.0),
|
||||
size: particle.size,
|
||||
rotation: particle.rotation,
|
||||
color: particle.color,
|
||||
color: linear_color,
|
||||
});
|
||||
|
||||
draw_data.vertices.push(Vertex {
|
||||
@@ -363,7 +365,7 @@ impl ParticleSystem {
|
||||
tex_coord: Vector2::new(0.0, 1.0),
|
||||
size: particle.size,
|
||||
rotation: particle.rotation,
|
||||
color: particle.color,
|
||||
color: linear_color,
|
||||
});
|
||||
|
||||
let base_index = (i * 4) as u32;
|
||||
|
||||
@@ -277,7 +277,7 @@ impl Lightmap {
|
||||
.up_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::y),
|
||||
color: light.color().as_frgb(),
|
||||
color: light.color().srgb_to_linear().as_frgb(),
|
||||
}))
|
||||
}
|
||||
Light::Spot(spot) => lights.push(LightDefinition::Spot(SpotLightDefinition {
|
||||
@@ -285,7 +285,7 @@ impl Lightmap {
|
||||
intensity: 1.0,
|
||||
edge0: ((spot.hotspot_cone_angle() + spot.falloff_angle_delta()) * 0.5).cos(),
|
||||
edge1: (spot.hotspot_cone_angle() * 0.5).cos(),
|
||||
color: light.color().as_frgb(),
|
||||
color: light.color().srgb_to_linear().as_frgb(),
|
||||
direction: light
|
||||
.up_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
@@ -298,7 +298,7 @@ impl Lightmap {
|
||||
handle,
|
||||
intensity: 1.0,
|
||||
position: light.global_position(),
|
||||
color: light.color().as_frgb(),
|
||||
color: light.color().srgb_to_linear().as_frgb(),
|
||||
radius: point.radius(),
|
||||
sqr_radius: point.radius() * point.radius(),
|
||||
})),
|
||||
|
||||
Reference in New Issue
Block a user