Spaces:
Sleeping
Sleeping
File size: 6,346 Bytes
78475cb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | import Phaser from 'phaser';
const fragShader = `
precision mediump float;
uniform sampler2D uMainSampler;
uniform vec2 resolution;
uniform float time;
varying vec2 outTexCoord;
#define PI 3.14159265359
vec4 permute(vec4 t) {
return mod(((t * 34.0) + 1.0) * t, 289.0);
}
float noise3d(vec3 p) {
vec3 a = floor(p);
vec3 d = p - a;
d = d * d * (3.0 - 2.0 * d);
vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
vec4 k1 = permute(b.xyxy);
vec4 k2 = permute(k1.xyxy + b.zzww);
vec4 c = k2 + a.zzzz;
vec4 k3 = permute(c);
vec4 k4 = permute(c + 1.0);
vec4 o1 = fract(k3 * (1.0 / 41.0));
vec4 o2 = fract(k4 * (1.0 / 41.0));
vec4 o3_interp_z = o2 * d.z + o1 * (1.0 - d.z);
vec2 o4_interp_xy = o3_interp_z.yw * d.x + o3_interp_z.xz * (1.0 - d.x);
return o4_interp_xy.y * d.y + o4_interp_xy.x * (1.0 - d.y);
}
void main() {
float brightness = 2.5;
float red_balance = 1.0;
float green_balance = 0.85;
float blue_balance = 1.0;
float phosphorWidth = 2.50;
float phosphorHeight = 4.50;
float internalHorizontalGap = 1.0;
float columnGap = 0.2;
float verticalCellGap = 0.2;
float phosphorPower = 0.9;
float cell_noise_variation_amount = 0.025;
float cell_noise_scale_xy = 240.0;
float cell_noise_speed = 24.0;
float curvature_amount = 0.0;
vec2 fragCoord = gl_FragCoord.xy;
vec2 uv = outTexCoord;
vec2 centered_uv_output = uv - 0.5;
float r = length(centered_uv_output);
float distort_factor = 1.0 + curvature_amount * r * r;
vec2 centered_uv_source = centered_uv_output * distort_factor;
vec2 source_uv = centered_uv_source + 0.5;
vec2 fragCoord_warped = source_uv * resolution;
bool is_on_original_flat_screen = source_uv.x >= 0.0 && source_uv.x <= 1.0 &&
source_uv.y >= 0.0 && source_uv.y <= 1.0;
if (!is_on_original_flat_screen) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
float fullCellWidth = 3.0 * phosphorWidth + 3.0 * internalHorizontalGap + columnGap;
float fullRowHeight = phosphorHeight + verticalCellGap;
float logical_cell_index_x = floor(fragCoord_warped.x / fullCellWidth);
float shift_y_offset = 0.0;
if (mod(logical_cell_index_x, 2.0) != 0.0) {
shift_y_offset = fullRowHeight / 2.0;
}
float effective_y_warped = fragCoord_warped.y + shift_y_offset;
float logical_row_index = floor(effective_y_warped / fullRowHeight);
float uv_cell_x = mod(fragCoord_warped.x, fullCellWidth);
if (uv_cell_x < 0.0) {
uv_cell_x += fullCellWidth;
}
float uv_row_y = mod(effective_y_warped, fullRowHeight);
if (uv_row_y < 0.0) {
uv_row_y += fullRowHeight;
}
vec3 video_color = texture2D(uMainSampler, source_uv).rgb;
video_color.r *= red_balance;
video_color.g *= green_balance;
video_color.b *= blue_balance;
vec3 final_color = vec3(0.0);
bool in_column_gap = uv_cell_x >= (3.0 * phosphorWidth + 3.0 * internalHorizontalGap);
bool in_vertical_gap = uv_row_y >= phosphorHeight;
if (!in_column_gap && !in_vertical_gap) {
float uv_cell_x_within_block = uv_cell_x;
vec3 phosphor_base_color = vec3(0.0);
float video_component_intensity = 0.0;
float current_phosphor_startX_in_block = -1.0;
float current_x_tracker = 0.0;
if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {
phosphor_base_color = vec3(1.0, 0.0, 0.0);
video_component_intensity = video_color.r;
current_phosphor_startX_in_block = current_x_tracker;
}
current_x_tracker += phosphorWidth + internalHorizontalGap;
if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {
phosphor_base_color = vec3(0.0, 1.0, 0.0);
video_component_intensity = video_color.g;
current_phosphor_startX_in_block = current_x_tracker;
}
current_x_tracker += phosphorWidth + internalHorizontalGap;
if (uv_cell_x_within_block >= current_x_tracker && uv_cell_x_within_block < current_x_tracker + phosphorWidth) {
phosphor_base_color = vec3(0.0, 0.0, 1.0);
video_component_intensity = video_color.b;
current_phosphor_startX_in_block = current_x_tracker;
}
if (current_phosphor_startX_in_block >= 0.0) {
float x_in_phosphor = (uv_cell_x_within_block - current_phosphor_startX_in_block) / phosphorWidth;
float horizontal_intensity_factor = pow(sin(x_in_phosphor * PI), phosphorPower);
float y_in_phosphor_band = uv_row_y / phosphorHeight;
float vertical_intensity_factor = (phosphorHeight > 0.0) ? pow(sin(y_in_phosphor_band * PI), phosphorPower) : 1.0;
float total_intensity_factor = horizontal_intensity_factor * vertical_intensity_factor;
final_color = phosphor_base_color * video_component_intensity * total_intensity_factor;
}
}
vec3 noise_pos = vec3(logical_cell_index_x * cell_noise_scale_xy,
logical_row_index * cell_noise_scale_xy,
time * cell_noise_speed);
vec3 cell_noise_rgb;
cell_noise_rgb.r = noise3d(noise_pos);
cell_noise_rgb.g = noise3d(noise_pos + vec3(19.0, 0.0, 0.0));
cell_noise_rgb.b = noise3d(noise_pos + vec3(0.0, 13.0, 0.0));
cell_noise_rgb = cell_noise_rgb * 2.0 - 1.0;
final_color += cell_noise_rgb * cell_noise_variation_amount;
final_color *= brightness;
float edge_darken_strength = 0.1;
float vignette_factor = 1.0 - dot(centered_uv_output, centered_uv_output) * edge_darken_strength * 2.0;
vignette_factor = clamp(vignette_factor, 0.0, 1.0);
final_color *= vignette_factor;
final_color = clamp(final_color, 0.0, 1.0);
gl_FragColor = vec4(final_color, 1.0);
}
`;
export default class TrinitronPipeline extends Phaser.Renderer.WebGL.Pipelines.PostFXPipeline {
constructor(game) {
super({
name: 'TrinitronPipeline',
game: game,
renderTarget: true,
fragShader: fragShader,
uniforms: [
'uMainSampler',
'resolution',
'time'
]
});
}
onPreRender() {
// Use the actual canvas display size (after scaling), not the game resolution
const canvas = this.game.canvas;
const displayWidth = canvas.width;
const displayHeight = canvas.height;
this.set2f('resolution', displayWidth, displayHeight);
this.set1f('time', this.game.loop.time / 1000);
}
}
|