Files
gods-eye-view/src/styles/noir.js
T

58 lines
1.9 KiB
JavaScript

/**
* Noir Style — Desaturation + High Contrast + Vignette
* Classic film noir / detective movie look
*/
export const noirShader = {
name: 'noir',
uniforms: {
contrastAmt: { default: 1.2, min: 0, max: 2, label: 'Contrast' },
grainAmt: { default: 0.5, min: 0, max: 1, label: 'Grain' },
vignetteAmt: { default: 0.5, min: 0, max: 1, label: 'Vignette' },
},
fragmentShader: /* glsl */ `
uniform sampler2D colorTexture;
uniform vec2 colorTextureDimensions;
uniform float intensity;
uniform float contrastAmt;
uniform float grainAmt;
uniform float vignetteAmt;
in vec2 v_textureCoordinates;
void main() {
vec2 uv = v_textureCoordinates;
vec4 color = texture(colorTexture, uv);
// Desaturate
float luma = dot(color.rgb, vec3(0.299, 0.587, 0.114));
vec3 gray = vec3(luma);
vec3 desaturated = mix(color.rgb, gray, intensity);
// High contrast with S-curve (driven by contrastAmt uniform)
float contrast = 1.0 + contrastAmt * intensity;
vec3 contrasted = (desaturated - 0.5) * contrast + 0.5;
contrasted = clamp(contrasted, 0.0, 1.0);
// Film grain (driven by grainAmt uniform)
float grain = fract(sin(dot(uv * colorTextureDimensions, vec2(12.9898, 78.233))) * 43758.5453);
grain = (grain - 0.5) * 0.08 * grainAmt * intensity;
contrasted += grain;
// Vignette (driven by vignetteAmt uniform)
vec2 vigUV = uv * (1.0 - uv);
float vig = vigUV.x * vigUV.y * 16.0;
vig = pow(vig, 0.3 + 0.4 * vignetteAmt * intensity);
// Slight sepia tint for warmth
vec3 sepia = vec3(
dot(contrasted, vec3(0.393, 0.769, 0.189)),
dot(contrasted, vec3(0.349, 0.686, 0.168)),
dot(contrasted, vec3(0.272, 0.534, 0.131))
);
vec3 tinted = mix(contrasted, sepia, 0.15 * intensity);
vec3 result = tinted * vig;
out_FragColor = vec4(mix(color.rgb, result, intensity), color.a);
}
`,
};