Implemented CRT shader
This commit is contained in:
parent
d70d183861
commit
8ace32102b
5
game/assets/configs/final_shader.json
Normal file
5
game/assets/configs/final_shader.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"pixel_scale": 1.0,
|
||||
"warp_factor": 0.35,
|
||||
"scanline_darkness": 0.15
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* This shader is the last piece of the graphics pipeline. EVERYTHING is passed through it.
|
||||
*/
|
||||
|
||||
#version 330
|
||||
|
||||
// Fragment texture UV coordinate
|
||||
@ -13,22 +17,41 @@ uniform vec2 viewport;
|
||||
out vec4 finalColor;
|
||||
|
||||
// Pixel scaling factor (pixels per pixel)
|
||||
const vec2 pixelScale = vec2(1.0, 1.0);
|
||||
uniform vec2 pixelScale;
|
||||
|
||||
// CRT effect parameters
|
||||
uniform float warpFactor;
|
||||
uniform float scanlineDarkness;
|
||||
|
||||
void main() {
|
||||
// Calculate the distance to merge pixels
|
||||
float dx = pixelScale.x * (1.0 / viewport.x);
|
||||
float dy = pixelScale.y * (1.0 / viewport.y);
|
||||
|
||||
// Calculate the squared distance from the center
|
||||
vec2 dist_center_sq = abs(0.5 - fragTexCoord);
|
||||
dist_center_sq *= dist_center_sq;
|
||||
|
||||
// Get the base UV coordinate of the pixel
|
||||
vec2 baseUV = fragTexCoord;
|
||||
|
||||
// Calculate a UV for this new blocky pixel
|
||||
vec2 pixelatedUV = vec2(dx * floor(baseUV.x / dx), dy * floor(baseUV.y / dy));
|
||||
|
||||
// Rebuild the texture with the new UVs
|
||||
vec3 tc = texture(texture0, pixelatedUV).rgb;
|
||||
// Warp the UVs of the pixelated texture
|
||||
vec2 warpedUV = pixelatedUV;
|
||||
warpedUV.x -= 0.5; warpedUV.x *= 1.0+(dist_center_sq.y * (0.3 * warpFactor)); warpedUV.x += 0.5;
|
||||
warpedUV.y -= 0.5; warpedUV.y *= 1.0+(dist_center_sq.x * (0.4 * warpFactor)); warpedUV.y += 0.5;
|
||||
|
||||
// If the UV is outside the texture, return black
|
||||
if (warpedUV.x < 0.0 || warpedUV.x > 1.0 || warpedUV.y < 0.0 || warpedUV.y > 1.0) {
|
||||
finalColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine factor of if we are rendering on a scanline
|
||||
float scanlineFactor = abs(sin(fragTexCoord.y * viewport.y) * 0.5 * scanlineDarkness);
|
||||
|
||||
// Build the final pixel
|
||||
finalColor = vec4(tc, 1.0);
|
||||
}
|
||||
finalColor = vec4(mix(texture(texture0, warpedUV).rgb, vec3(0.0), scanlineFactor), 1.0);
|
||||
}
|
||||
|
@ -80,9 +80,12 @@ use crate::{
|
||||
context::GameContext,
|
||||
discord_rpc::{maybe_set_discord_presence, try_connect_to_local_discord},
|
||||
scenes::{build_screen_state_machine, Scenes},
|
||||
utilities::shaders::{
|
||||
shader::ShaderWrapper,
|
||||
util::{dynamic_screen_texture::DynScreenTexture, render_texture::render_to_texture},
|
||||
utilities::{
|
||||
game_config::FinalShaderConfig,
|
||||
shaders::{
|
||||
shader::ShaderWrapper,
|
||||
util::{dynamic_screen_texture::DynScreenTexture, render_texture::render_to_texture},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -166,16 +169,20 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
|
||||
.unwrap();
|
||||
|
||||
// Create a dynamic texture to draw to for processing by shaders
|
||||
info!("Allocating a SNOWZ7Zresizable texture for the screen");
|
||||
info!("Allocating a resizable texture for the screen");
|
||||
let mut dynamic_texture =
|
||||
DynScreenTexture::new(&mut context.renderer.borrow_mut(), &raylib_thread)?;
|
||||
|
||||
// Load the pixel art shader
|
||||
info!("Loading the pixel art shader");
|
||||
let pixel_shader_config = FinalShaderConfig::load(
|
||||
StaticGameData::get("configs/final_shader.json").expect("Failed to load final_shader.json"),
|
||||
)
|
||||
.unwrap();
|
||||
let mut pixel_shader = ShaderWrapper::new(
|
||||
None,
|
||||
Some(StaticGameData::get("shaders/pixelart.fs")).expect("Failed to load pixelart.fs"),
|
||||
vec!["viewport"],
|
||||
vec!["viewport", "pixelScale", "warpFactor", "scanlineDarkness"],
|
||||
&mut context.renderer.borrow_mut(),
|
||||
&raylib_thread,
|
||||
)?;
|
||||
@ -202,6 +209,15 @@ pub async fn game_begin(game_config: &GameConfig) -> Result<(), Box<dyn std::err
|
||||
|
||||
// Update the pixel shader to correctly handle the screen size
|
||||
pixel_shader.set_variable("viewport", screen_size)?;
|
||||
pixel_shader.set_variable(
|
||||
"pixelScale",
|
||||
Vector2::new(
|
||||
pixel_shader_config.pixel_scale,
|
||||
pixel_shader_config.pixel_scale,
|
||||
),
|
||||
)?;
|
||||
pixel_shader.set_variable("warpFactor", pixel_shader_config.warp_factor)?;
|
||||
pixel_shader.set_variable("scanlineDarkness", pixel_shader_config.scanline_darkness)?;
|
||||
|
||||
// Render the game via the pixel shader
|
||||
render_to_texture(&mut dynamic_texture, || {
|
||||
|
@ -8,7 +8,7 @@ use rust_embed::EmbeddedFile;
|
||||
pub struct Author {
|
||||
pub name: String,
|
||||
pub url: Option<String>,
|
||||
pub roles: Vec<String>
|
||||
pub roles: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
@ -16,7 +16,7 @@ pub struct GameConfig {
|
||||
pub name: String,
|
||||
// pub authors: Vec<Author>,
|
||||
pub base_window_size: (i32, i32),
|
||||
pub sentry_dsn: String
|
||||
pub sentry_dsn: String,
|
||||
}
|
||||
|
||||
impl GameConfig {
|
||||
@ -25,3 +25,17 @@ impl GameConfig {
|
||||
serde_json::from_slice(&file.data)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct FinalShaderConfig {
|
||||
pub pixel_scale: f32,
|
||||
pub warp_factor: f32,
|
||||
pub scanline_darkness: f32,
|
||||
}
|
||||
|
||||
impl FinalShaderConfig {
|
||||
/// Load from a file
|
||||
pub fn load(file: EmbeddedFile) -> Result<Self, serde_json::Error> {
|
||||
serde_json::from_slice(&file.data)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user