compliance / index.html
jbilcke-hf's picture
jbilcke-hf HF staff
Upload 39 files
2b96520 verified
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Compliance</title>
<link rel="preload" href="fonts/MrEavesXLModOT-Book.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModNarOT-Thin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModOT-Bold.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModNarOT-Bold.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModNarOT-Reg.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModOT-Thin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModOT-Light.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModNarOT-Book.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModNarOT-Light.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="fonts/MrEavesXLModOT-Reg.woff2" as="font" type="font/woff2" crossorigin>
<script src="libs/dat.gui.min.js"></script>
<script src="libs/ammo.js"></script>
<script src="libs/cannon.js"></script>
<script src="libs/Oimo.js"></script>
<script src="libs/earcut.min.js"></script>
<script src="libs/babylon.js"></script>
<script src="libs/babylonjs.materials.min.js"></script>
<script src="libs/babylonjs.proceduralTextures.min.js"></script>
<script src="libs/babylonjs.postProcess.min.js"></script>
<script src="libs/babylonjs.loaders.js"></script>
<script src="libs/babylonjs.serializers.min.js"></script>
<script src="libs/babylon.gui.min.js"></script>
<script src="libs/babylon.inspector.bundle.js"></script>
<link href="fonts/stylesheet.css" rel="stylesheet">
<style>
/*
all this CSS is just quick & dirty, support of multiple resolutions is not a focus right now
also it is pretty difficult to do, since we use a virtual resolution to replicate a CRT,
so some resolutions will display a moiré effect and similar weird other patterns
*/
html,
body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: rgb(0, 11, 31);
background-image: url(./background.jpg);
background-position-y: -200px;
background-position-x: -392px;
background-size: 2980px;
font-family: 'MrEavesXLModNarOT-Reg';
font-weight: normal;
font-style: normal;
}
.wrapper {
position: fixed;
top: 0px;
left: 135px;
overflow: hidden;
/* width: 100%;
height: 100%;
*/
margin: 0;
padding: 0;
outline: none;
}
#renderCanvas {
/* screen ratio is 4:3 (1.33)
width: 426px;
height: 320px;
width: 1024px;
height: 820px;
*/
width: 1280px;
height: 1024px;
touch-action: none;
outline: none;
border-radius: 120px;
/* transform: scale(0.8); */
}
/*
@media only screen and (max-width: 600px) {
#renderCanvas {
width: 511px;
height: 384px;
}
}
@media only screen and (min-width: 600px) {
#renderCanvas {
width: 640px;
height: 480px;
}
}
@media only screen and (min-width: 800px) {
#renderCanvas {
width: 800px;
height: 640px;
}
}
@media only screen and (min-width: 1024px) {
#renderCanvas {
width: 1024px;
height: 820px;
}
}
*/
</style>
</head>
<body>
<div class="wrapper"><canvas id="renderCanvas"></canvas></div>
<script>
const config = {
// CRET screen resolution needs to be half of the actual resolution
crt: {
screenResolution: {
width: 800, // 486, 512, 640
height: 800, // 320, 480, 512, 640
}
},
window: {
width: 1280,
height: 1024
}
};
function toggleFullScreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
}
}
}
document.addEventListener("keydown", function(e) {
if (e.keyCode == 13) {
toggleFullScreen();
}
}, false);
const randomMutation = (value, probability = 1) => {
const r = Math.random();
return (r < probability || typeof value !== 'number') ? r : value;
}
const newRandomDigit = (digit) => {
digit.randomWobbleAmplitudeX = Math.random();
digit.randomWobbleAmplitudeY = Math.random();
digit.randomTimeShiftX = Math.random();
digit.randomTimeShiftY = Math.random();
digit.randomWobbleSpeedX = Math.random();
digit.randomWobbleSpeedY = Math.random();
}
const randomDigitMutation = (digit, probability) => {
digit.randomWobbleSpeedX = randomMutation(digit.randomWobbleSpeedX, probability);
digit.randomWobbleSpeedY = randomMutation(digit.randomWobbleSpeedY, probability);
}
var canvas = document.getElementById("renderCanvas");
var startRenderLoop = function (engine, canvas) {
engine.runRenderLoop(function () {
if (sceneToRender && sceneToRender.activeCamera) {
sceneToRender.render();
}
});
};
// get an "ajusted" size in pixel
// eg. if we want 9 "virtual pixels" we will need to have a larger size
const getFontSize = (size) => {
return Math.round(size * (window.innerHeight / config.crt.screenResolution.height));
}
// get an "ajusted" size in pixel
// eg. if we want 9 "virtual pixels" we will need to have a larger size
const getSize = (x, y) => {
var wRatio = window.innerWidth / config.crt.screenResolution.width;
var hRatio = window.innerHeight / config.crt.screenResolution.height;
return {
x: Math.round(x * wRatio),
y: Math.round(y * hRatio),
};
}
var engine = null;
var scene = null;
var sceneToRender = null;
var createDefaultEngine = function () {
return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, disableWebGL2Support: false });
};
var createScene = function () {
// engine.setHardwareScalingLevel(1);
var scene = new BABYLON.Scene(engine);
var gl = new BABYLON.GlowLayer("glow", scene);
gl.intensity = 0.5;
const backgroundBlue = new BABYLON.Color3(0, 0.04, 0.07);
const darkBlue = new BABYLON.Color3(0, 0.16, 0.28);
const deepBlue = new BABYLON.Color3(0, 0.156, 0.313);
const lightBlue = new BABYLON.Color3(0.062, 0.564, 0.690);
const brightBlue = new BABYLON.Color3(0.360, 0.768, 0.823);
scene.clearColor = backgroundBlue;
// This creates and positions a free camera (non-mesh)
var camera = new BABYLON.UniversalCamera("UniversalCamera", new BABYLON.Vector3(0, 0, -10), scene);
camera.lowerRadiusLimit = camera.radius;
camera.upperRadiusLimit = camera.radius;
// This targets the camera to scene origin
camera.setTarget(BABYLON.Vector3.Zero());
// This attaches the camera to the canvas
camera.attachControl(canvas, true);
// This creates a light, aiming 0,1,0 - to the sky (non-mesh)
var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount
light.intensity = 1;
// Our built-in 'ground' shape.
// var ground = BABYLON.MeshBuilder.CreateGround("ground", { width: 6, height: 6 }, scene);
// Ground
const width = 100;
const height = 100;
const subdivisions = 100;
var ground = BABYLON.MeshBuilder.CreateGround("ground", { width, height, subdivisions }, scene, false);
var groundMaterial = new BABYLON.GridMaterial("ground", scene);
ground.material = groundMaterial;
ground.updateFacetData();
// GUI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");
/*
var button = BABYLON.GUI.Button.CreateImageButton("but", "Click Me");
button.width = 0.2;
button.height = "80px";
button.color = "white";
button.background = "green";
advancedTexture.addControl(button);
*/
const matrix = [];
const matrixSize = 28;
let matrixTop = -500;
let matrixLeft = -500;
const matrixSpacing = 24;
let isDragging = false;
let isSelecting = false;
let lastMouseX = 0;
let lastMouseY = 0;
// speed of the wobble effect
const minWobbleAmplitude = 0;
const maxWobbleAmplitude = 10;
const lowFreqWobbleTimeMin = 0.001;
const lowFreqWobbleTimeMax = 0.005;
// speed of the wobble effect
const minWobbleSpeed = 0.0005;
const maxWobbleSpeed = 0.0010;
// we want to "desync" wobble effect by giving them different time periods (not just different speeds)
const minTimeShift = 5000; // may individual shift for animation
const maxTimeShift = 7000; // may individual shift for animation
let scale = 2; // between 0 and 200
for (let i = 0; i < matrixSize; i++) {
const row = [];
for (let j = 0; j < matrixSize; j++) {
var digit = new BABYLON.GUI.TextBlock();
row.push(digit);
digit.value = Math.round(Math.random() * 9);
digit.color = "rgb(50, 253, 254)";
digit.height = `${Math.round(scale * 128)}px`;
// Style
const style = advancedTexture.createStyle();
style.fontSize = getFontSize(12);
style.fontFamily = 'MrEavesXLModOT-Book';
// style.fontStyle = "bold";
digit.style = style;
digit.top = `${Math.round(scale * (matrixTop + i * matrixSpacing))}px`;
digit.left = `${Math.round(scale * (matrixLeft + j * matrixSpacing))}px`;
digit.text = `${digit.value}`;
// digit.text = `(${digit.left}, ${digit.top})`;
digit.selected = false;
// force random mutation upon all digit variable fields
newRandomDigit(digit);
advancedTexture.addControl(digit);
}
matrix.push(row);
}
const bgColor = "rgb(0, 10, 17)";
const fgColor = "rgb(50, 253, 254)";
const dbgColor = "rgb(200, 80, 20)";
const engineWidth = engine.getRenderWidth();
const engineHeight = engine.getRenderHeight();
const header = new BABYLON.GUI.Rectangle();
// header.left = 0;
// header.top = 0;
header.width = "100%";
header.height = `${Math.round(engineHeight * 0.20)}px`;
header.thickness = 0;
header.background = bgColor; // "rgb(0, 10, 17)"; // "transparent";
// header.paddingBottom = 5;
// header.paddingRight = 5;
header.horizontalAlignment = 0;
header.verticalAlignment = 0;
advancedTexture.addControl(header);
const titleBox = new BABYLON.GUI.Rectangle();
titleBox.left = "-5%";
titleBox.top = `${70}px`;
titleBox.width = "90%";
titleBox.height = `${70}px`;
titleBox.color = fgColor;
titleBox.thickness = 2;
titleBox.background = "transparent";
titleBox.horizontalAlignment = 1;
titleBox.verticalAlignment = 0; // 3;
header.addControl(titleBox);
var titleText = new BABYLON.GUI.TextBlock();
titleText.color = fgColor;
titleText.height = `${100}px`;
// Style
const titleStyle = advancedTexture.createStyle();
titleStyle.fontSize = getFontSize(45);
titleStyle.fontFamily = 'MrEavesXLModOT-Book';
// titleStyle.fontStyle = "bold";
titleText.style = titleStyle;
titleText.top = `2px`;
titleText.left = `-43%`;
titleText.text = `Siena`;
titleBox.addControl(titleText);
const headerDoubleBorder = new BABYLON.GUI.Rectangle();
headerDoubleBorder.left = "-5%";
headerDoubleBorder.top = `${Math.round((engineHeight * 0.185))}px`;
headerDoubleBorder.width = "110%";
headerDoubleBorder.height = "10px";
headerDoubleBorder.color = fgColor;
headerDoubleBorder.thickness = 2;
headerDoubleBorder.background = "transparent";
headerDoubleBorder.horizontalAlignment = 0;
headerDoubleBorder.verticalAlignment = 3; // 3;
header.addControl(headerDoubleBorder);
const footer = new BABYLON.GUI.Rectangle();
footer.left = 0;
footer.top = `${Math.round(engineHeight * 0.82)}px`;
footer.width = "100%";
footer.height = engineHeight * 0.40;
footer.thickness = 0;
footer.background = bgColor; // "rgb(0, 10, 17)"; // "transparent";
// rect1.paddingBottom = 5;
// rect1.paddingRight = 5;
footer.horizontalAlignment = 0;
footer.verticalAlignment = 0;
advancedTexture.addControl(footer);
const footerDoubleBorder = new BABYLON.GUI.Rectangle();
footerDoubleBorder.left = "-5%";
footerDoubleBorder.top = 0;
footerDoubleBorder.width = "110%";
footerDoubleBorder.height = "12px";
footerDoubleBorder.color = fgColor;
footerDoubleBorder.thickness = 2;
footerDoubleBorder.background = "transparent";
footerDoubleBorder.horizontalAlignment = 0;
footerDoubleBorder.verticalAlignment = 0; // 3;
footer.addControl(footerDoubleBorder);
const dropzones = [];
const completions = [];
const boxesMarginL = engineWidth * 0.06;
const boxWidth = engineWidth * 0.18;
const boxSpacingL = engineWidth * 0.008;
for (let i = 0; i < 5; i++) {
const left = boxesMarginL + (i * (boxWidth + boxSpacingL));
const width = "15%";
const thickness = 3;
const dropzone = new BABYLON.GUI.Rectangle();
dropzone.left = left;
dropzone.top = 23;
dropzone.width = width;
dropzone.height = `51px`;
dropzone.cornerRadius = 2;
dropzone.color = fgColor;
dropzone.thickness = thickness;
dropzone.background = "transparent";
// rect1.paddingBottom = 5;
// rect1.paddingRight = 5;
dropzone.horizontalAlignment = 0;
dropzone.verticalAlignment = 0;
footer.addControl(dropzone);
dropzones.push(dropzone);
var category = new BABYLON.GUI.TextBlock();
category.color = fgColor;
category.height = `${100}px`;
// Style
const categoryStyle = advancedTexture.createStyle();
categoryStyle.fontSize = getFontSize(31);
categoryStyle.fontFamily = 'Arial';
// categoryStyle.fontStyle = "bold";
category.style = categoryStyle;
category.top = `2px`;
category.left = `0px`;
category.text = `0${i + 1}`;
dropzone.addControl(category);
const completion = new BABYLON.GUI.Rectangle();
completion.left = left;
completion.top = 86;
completion.width = width;
completion.height = `40px`;
completion.cornerRadius = 2;
completion.color = fgColor;
completion.thickness = thickness;
completion.background = "transparent";
// rect1.paddingBottom = 5;
// rect1.paddingRight = 5;
completion.horizontalAlignment = 0;
completion.verticalAlignment = 0;
footer.addControl(completion);
completions.push(completion);
var completionRate = new BABYLON.GUI.TextBlock();
completionRate.color = fgColor;
completionRate.height = `${Math.round(scale * 100)}px`;
// Style
const completionStyle = advancedTexture.createStyle();
completionStyle.fontSize = getFontSize(32);
completionStyle.fontFamily = 'MrEavesXLModOT-Book';
// completionStyle.fontStyle = "bold";
completionRate.style = completionStyle;
completionRate.top = `2px`;
completionRate.left = `-${Math.round(engineWidth * 0.048)}px`;
completionRate.text = `${0}%`;
completion.addControl(completionRate);
}
const footerSeparator = new BABYLON.GUI.Rectangle();
footerSeparator.left = "-5%";
footerSeparator.top = 137;
footerSeparator.width = "110%";
footerSeparator.height = "2px";
// rect1.cornerRadius = 20;
footerSeparator.color = fgColor;
footerSeparator.thickness = 6;
footerSeparator.background = "transparent";
// rect1.paddingBottom = 5;
// rect1.paddingRight = 5;
footerSeparator.horizontalAlignment = 0;
footerSeparator.verticalAlignment = 0;
footer.addControl(footerSeparator);
scene.onPointerObservable.add((pointerInfo) => {
switch (pointerInfo.type) {
case BABYLON.PointerEventTypes.POINTERDOWN:
console.log("POINTER DOWN", pointerInfo.event);
if (pointerInfo.event.button === 0) {
isSelecting = true;
isDragging = false;
} else if (pointerInfo.event.button === 2) {
isDragging = true;
isSelecting = false;
}
lastMouseX = scene.pointerX;
lastMouseY = scene.pointerY;
break;
case BABYLON.PointerEventTypes.POINTERUP:
console.log("POINTER UP");
isSelecting = false;
isDragging = false;
break;
case BABYLON.PointerEventTypes.POINTERMOVE:
console.log("POINTER MOVE");
/*
var pickingInfo = scene.pick(scene.pointerX, scene.pointerY);
console.log('pointer:', {
pointerX: scene.pointerX,
pointerY: scene.pointerY
});
*/
if (isDragging) {
matrixLeft += (scene.pointerX - lastMouseX) / scale;
matrixTop += (scene.pointerY - lastMouseY) / scale;
lastMouseX = scene.pointerX;
lastMouseY = scene.pointerY;
}
break;
case BABYLON.PointerEventTypes.POINTERWHEEL:
console.log("POINTER WHEEL");
break;
case BABYLON.PointerEventTypes.POINTERPICK:
console.log("POINTER PICK");
break;
case BABYLON.PointerEventTypes.POINTERTAP:
console.log("POINTER TAP");
break;
case BABYLON.PointerEventTypes.POINTERDOUBLETAP:
console.log("POINTER DOUBLE-TAP");
break;
}
});
document.querySelector('#renderCanvas').onwheel = (event) => {
event.preventDefault();
scale += event.deltaY * -0.0005;
// Restrict scale
scale = Math.min(Math.max(2, scale), 6);
}
// TODO should implement virtualization to give the feeling of infinite array
scene.onBeforeRenderObservable.add(() => {
const ts = new Date().getTime();
// console.log('pop');
for (let i = 0; i < matrixSize; i++) {
const row = [];
for (let j = 0; j < matrixSize; j++) {
const digit = matrix[i][j];
// from time to time, we randomize some of the digit parameters
// EDIT: disabled, doesn't work like I would like it to be
// randomDigitMutation(digit, 0.001);
// some kind of "CRT" like jitter
// EDIT: disabled
const highFreqJitterX = 0; // Math.random() * 1;
const highFreqJitterY = 0; // Math.random() * 1;
// we want to "unsync" digits
const timeShiftX = minTimeShift + digit.randomTimeShiftX * maxTimeShift;
const timeShiftY = minTimeShift + digit.randomTimeShiftY * maxTimeShift;
// wobble speed
const wobbleSpeedX = minWobbleSpeed + digit.randomWobbleSpeedX * maxWobbleSpeed;
const wobbleSpeedY = minWobbleSpeed + digit.randomWobbleSpeedY * maxWobbleSpeed;
const wobbleAmplitudeX = minWobbleAmplitude + (digit.randomWobbleAmplitudeX - 0.5) * maxWobbleAmplitude;
const wobbleAmplitudeY = minWobbleAmplitude + (digit.randomWobbleAmplitudeY - 0.5) * maxWobbleAmplitude;
const lowFreqWobbleX = (wobbleAmplitudeX) * Math.cos((timeShiftX + ts) * wobbleSpeedX);
const lowFreqWobbleY = (wobbleAmplitudeY) * Math.cos((timeShiftY + ts) * wobbleSpeedY);
const randomX = highFreqJitterX + lowFreqWobbleX;
const randomY = highFreqJitterY + lowFreqWobbleY;
const newTop = scale * (matrixTop + i * matrixSpacing + randomY);
const newLeft = scale * (matrixLeft + j * matrixSpacing + randomX);
digit.top = `${Math.round(newTop)}px`;
digit.left = `${Math.round(newLeft)}px`;
const screenMouseX = scene.pointerX - engine.getRenderWidth() / 2;
const screenMouseY = scene.pointerY - engine.getRenderHeight() / 2;
const dx = screenMouseX - newLeft;
const dy = screenMouseY - newTop;
const screenDistance = Math.sqrt(dx * dx + dy * dy);
// we need to adjust cutoff for the current zoom level
const cutoff = 40 * scale;
// compute the adjusted distance (based on zoom)
let distance = 1 - (Math.max(1, Math.min(cutoff, screenDistance)) / cutoff);
if (isSelecting && (distance > 0.7)) {
digit.selected = true;
}
// hold selected items
distance = digit.selected ? 1 : distance;
// an hover effect based on mouse distance
const minHover = 62;
const maxHover = 74;
const hoverAmount = minHover + distance * maxHover;
digit.height = `${Math.round(scale * (120))}px`;
digit.style.fontSize = getFontSize(scale * 0.12 * (hoverAmount));
}
}
});
BABYLON.Effect.ShadersStore["crtFragmentShader"] = `
#ifdef GL_ES
precision highp float;
#endif
#define PI 3.1415926538
// Samplers
varying vec2 vUV;
uniform sampler2D textureSampler;
// Parameters
uniform vec2 curvature;
uniform vec2 screenResolution;
uniform vec2 scanLineOpacity;
uniform float vignetteOpacity;
uniform float brightness;
uniform float vignetteRoundness;
vec2 curveRemapUV(vec2 uv)
{
// as we near the edge of our screen apply greater distortion using a sinusoid.
uv = uv * 2.0 - 1.0;
vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y);
uv = uv + uv * offset * offset;
uv = uv * 0.5 + 0.5;
return uv;
}
vec4 scanLineIntensity(float uv, float resolution, float opacity)
{
float intensity = sin(uv * resolution * PI * 2.0);
intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1;
return vec4(vec3(pow(intensity, opacity)), 1.0);
}
vec4 vignetteIntensity(vec2 uv, vec2 resolution, float opacity, float roundness)
{
float intensity = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);
return vec4(vec3(clamp(pow((resolution.x / roundness) * intensity, opacity), 0.0, 1.0)), 1.0);
}
void main(void)
{
vec2 remappedUV = curveRemapUV(vec2(vUV.x, vUV.y));
vec4 baseColor = texture2D(textureSampler, remappedUV);
baseColor *= vignetteIntensity(remappedUV, screenResolution, vignetteOpacity, vignetteRoundness);
baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x);
baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y);
baseColor *= vec4(vec3(brightness), 1.0);
if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = baseColor;
}
}
`;
var postProcess1 = new BABYLON.PostProcess("CRTShaderPostProcess", "crt", ["curvature", "screenResolution", "scanLineOpacity", "vignetteOpacity", "brightness", "vignetteRoundness"], null, 0.25, camera);
postProcess1.onApply = function (effect) {
// having a curvature is nice, but this should happen AFTER the pixelation and blur effect
effect.setFloat2("curvature", 255.0, 255.0);
effect.setFloat2("screenResolution", config.crt.screenResolution.width, config.crt.screenResolution.height);
effect.setFloat2("scanLineOpacity", 0.1, 0.1);
effect.setFloat("vignetteOpacity", 0.2); // was 0.3
effect.setFloat("brightness", 1);
effect.setFloat("vignetteRoundness", 20.0);
};
// ----------- BLUR EFFECT ----------
var postProcess2 = new BABYLON.BlurPostProcess("Horizontal blur", new BABYLON.Vector2(0.7, 0), 4.0, 0.5, camera);
var postProcess3 = new BABYLON.BlurPostProcess("Vertical blur", new BABYLON.Vector2(0, 0.7), 4.0, 0.5, camera);
BABYLON.Effect.ShadersStore["curveFragmentShader"] = `
#ifdef GL_ES
precision highp float;
#endif
#define PI 3.1415926538
// Samplers
varying vec2 vUV;
uniform sampler2D textureSampler;
// Parameters
uniform vec2 curvature;
uniform vec2 screenResolution;
uniform vec2 scanLineOpacity;
uniform float vignetteOpacity;
uniform float brightness;
uniform float vignetteRoundness;
vec2 curveRemapUV(vec2 uv)
{
// as we near the edge of our screen apply greater distortion using a sinusoid.
uv = uv * 2.0 - 1.0;
vec2 offset = abs(uv.yx) / vec2(curvature.x, curvature.y);
uv = uv + uv * offset * offset;
uv = uv * 0.5 + 0.5;
return uv;
}
vec4 scanLineIntensity(float uv, float resolution, float opacity)
{
float intensity = sin(uv * resolution * PI * 2.0);
intensity = ((0.5 * intensity) + 0.5) * 0.9 + 0.1;
return vec4(vec3(pow(intensity, opacity)), 1.0);
}
vec4 vignetteIntensity(vec2 uv, vec2 resolution, float opacity, float roundness)
{
float intensity = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y);
return vec4(vec3(clamp(pow((resolution.x / roundness) * intensity, opacity), 0.0, 1.0)), 1.0);
}
void main(void)
{
vec2 remappedUV = curveRemapUV(vec2(vUV.x, vUV.y));
vec4 baseColor = texture2D(textureSampler, remappedUV);
baseColor *= vignetteIntensity(remappedUV, screenResolution, vignetteOpacity, vignetteRoundness);
baseColor *= scanLineIntensity(remappedUV.x, screenResolution.y, scanLineOpacity.x);
baseColor *= scanLineIntensity(remappedUV.y, screenResolution.x, scanLineOpacity.y);
baseColor *= vec4(vec3(brightness), 1.0);
if (remappedUV.x < 0.0 || remappedUV.y < 0.0 || remappedUV.x > 1.0 || remappedUV.y > 1.0){
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
} else {
gl_FragColor = baseColor;
}
}
`;
var postProcess4 = new BABYLON.PostProcess("CurveShaderPostProcess", "curve", ["curvature", "screenResolution", "scanLineOpacity", "vignetteOpacity", "brightness", "vignetteRoundness"], null, 0.25, camera);
postProcess4.onApply = function (effect) {
// having a curvature is nice, but this should happen AFTER the pixelation and blur effect
effect.setFloat2("curvature", 255.0, 255.0);
effect.setFloat2("screenResolution", config.crt.screenResolution.width, config.crt.screenResolution.height);
effect.setFloat2("scanLineOpacity", 0.2, 0.2);
effect.setFloat("vignetteOpacity", 0.3); // was 0.3
effect.setFloat("brightness", 8);
effect.setFloat("vignetteRoundness", 20.0);
};
var postProcess5 = new BABYLON.BlurPostProcess("Horizontal blur", new BABYLON.Vector2(1.0, 0), 2.0, 0.86, camera);
var postProcess6 = new BABYLON.BlurPostProcess("Vertical blur", new BABYLON.Vector2(0, 1.0), 2.0, 0.86, camera);
// var postProcess6 = new BABYLON.BlurPostProcess("Horizontal blur", new BABYLON.Vector2(1.0, 0), 2.0, 0.85, camera);
// var postProcess7 = new BABYLON.BlurPostProcess("Vertical blur", new BABYLON.Vector2(0, 1.0), 2.0, 0.85, camera);
return scene;
};
window.initFunction = async function () {
var asyncEngineCreation = async function () {
try {
return createDefaultEngine();
} catch (e) {
console.log("the available createEngine function failed. Creating the default engine instead");
return createDefaultEngine();
}
};
window.engine = await asyncEngineCreation();
if (!engine) throw "engine should not be null.";
startRenderLoop(engine, canvas);
window.scene = createScene();
};
initFunction().then(() => {
sceneToRender = scene;
});
// Resize
window.addEventListener("resize", function () {
engine.resize();
});
</script>
</body>
</html>