mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-09 07:26:28 +02:00
feature: add serial + flashy-terrain
This commit is contained in:
File diff suppressed because one or more lines are too long
79
src/entities/FlashyTerrain.ts
Normal file
79
src/entities/FlashyTerrain.ts
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import { Entity } from '../heck/Entity';
|
||||||
|
import { Geometry } from '../heck/Geometry';
|
||||||
|
import { Material } from '../heck/Material';
|
||||||
|
import { Mesh } from '../heck/components/Mesh';
|
||||||
|
import { Quaternion, Vector3 } from '@fms-cat/experimental';
|
||||||
|
import { dummyRenderTarget, dummyRenderTargetFourDrawBuffers } from '../globals/dummyRenderTarget';
|
||||||
|
import { genPlane } from '../geometries/genPlane';
|
||||||
|
import { quadGeometry } from '../globals/quadGeometry';
|
||||||
|
import depthFrag from '../shaders/depth.frag';
|
||||||
|
import flashyTerrainFrag from '../shaders/flashy-terrain.frag';
|
||||||
|
import flashyTerrainVert from '../shaders/flashy-terrain.vert';
|
||||||
|
|
||||||
|
export class FlashyTerrain extends Entity {
|
||||||
|
public mesh: Mesh;
|
||||||
|
|
||||||
|
public constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.transform.position = new Vector3( [ 0.0, -4.0, 0.0 ] );
|
||||||
|
this.transform.rotation = Quaternion.fromAxisAngle(
|
||||||
|
new Vector3( [ 1.0, 0.0, 0.0 ] ),
|
||||||
|
-0.5 * Math.PI,
|
||||||
|
);
|
||||||
|
this.transform.scale = this.transform.scale.scale( 8.0 );
|
||||||
|
|
||||||
|
// -- geometry ---------------------------------------------------------------------------------
|
||||||
|
const plane = genPlane();
|
||||||
|
|
||||||
|
const geometry = new Geometry();
|
||||||
|
|
||||||
|
geometry.vao.bindVertexbuffer( plane.position, 0, 3 );
|
||||||
|
geometry.vao.bindIndexbuffer( plane.index );
|
||||||
|
|
||||||
|
geometry.count = plane.count;
|
||||||
|
geometry.mode = plane.mode;
|
||||||
|
geometry.indexType = plane.indexType;
|
||||||
|
|
||||||
|
// -- materials --------------------------------------------------------------------------------
|
||||||
|
const deferred = new Material(
|
||||||
|
flashyTerrainVert,
|
||||||
|
flashyTerrainFrag,
|
||||||
|
{
|
||||||
|
defines: [ 'DEFERRED 1' ],
|
||||||
|
initOptions: { geometry: quadGeometry, target: dummyRenderTargetFourDrawBuffers },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const depth = new Material(
|
||||||
|
flashyTerrainVert,
|
||||||
|
depthFrag,
|
||||||
|
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
|
||||||
|
);
|
||||||
|
|
||||||
|
const materials = { deferred, depth };
|
||||||
|
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
if ( module.hot ) {
|
||||||
|
module.hot.accept(
|
||||||
|
[
|
||||||
|
'../shaders/flashy-terrain.vert',
|
||||||
|
'../shaders/flashy-terrain.frag',
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
deferred.replaceShader( flashyTerrainVert, flashyTerrainFrag );
|
||||||
|
depth.replaceShader( flashyTerrainVert, depthFrag );
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- mesh -------------------------------------------------------------------------------------
|
||||||
|
this.mesh = new Mesh( {
|
||||||
|
geometry,
|
||||||
|
materials,
|
||||||
|
name: process.env.DEV && 'FlashyTerrain/mesh',
|
||||||
|
} );
|
||||||
|
this.components.push( this.mesh );
|
||||||
|
}
|
||||||
|
}
|
113
src/entities/Serial.ts
Normal file
113
src/entities/Serial.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import { Blit } from '../heck/components/Blit';
|
||||||
|
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||||
|
import { Entity } from '../heck/Entity';
|
||||||
|
import { Material } from '../heck/Material';
|
||||||
|
import { Quad } from '../heck/components/Quad';
|
||||||
|
import { RenderTarget } from '../heck/RenderTarget';
|
||||||
|
import { auto } from '../globals/automaton';
|
||||||
|
import { dummyRenderTarget } from '../globals/dummyRenderTarget';
|
||||||
|
import { gl } from '../globals/canvas';
|
||||||
|
import { quadGeometry } from '../globals/quadGeometry';
|
||||||
|
import { randomTexture } from '../globals/randomTexture';
|
||||||
|
import quadVert from '../shaders/quad.vert';
|
||||||
|
import serialDecodeFrag from '../shaders/serial-decode.frag';
|
||||||
|
import serialEncodeFrag from '../shaders/serial-encode.frag';
|
||||||
|
|
||||||
|
export interface SerialOptions {
|
||||||
|
input: BufferRenderTarget;
|
||||||
|
target: RenderTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Serial extends Entity {
|
||||||
|
public constructor( options: SerialOptions ) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
const entityBypass = new Entity();
|
||||||
|
entityBypass.visible = false;
|
||||||
|
this.children.push( entityBypass );
|
||||||
|
|
||||||
|
const entityMain = new Entity();
|
||||||
|
entityMain.active = false;
|
||||||
|
entityMain.visible = false;
|
||||||
|
this.children.push( entityMain );
|
||||||
|
|
||||||
|
// -- bypass -----------------------------------------------------------------------------------
|
||||||
|
entityBypass.components.push( new Blit( {
|
||||||
|
src: options.input,
|
||||||
|
dst: options.target,
|
||||||
|
name: 'Serial/blitBypass',
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
// -- encode -----------------------------------------------------------------------------------
|
||||||
|
const bufferEncode = new BufferRenderTarget( {
|
||||||
|
width: 4096,
|
||||||
|
height: 240,
|
||||||
|
name: process.env.DEV && 'Serial/bufferEncode',
|
||||||
|
} );
|
||||||
|
|
||||||
|
const materialEncode = new Material(
|
||||||
|
quadVert,
|
||||||
|
serialEncodeFrag,
|
||||||
|
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
|
||||||
|
);
|
||||||
|
materialEncode.addUniformTexture( 'sampler0', options.input.texture );
|
||||||
|
materialEncode.addUniformTexture( 'samplerRandom', randomTexture.texture );
|
||||||
|
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
if ( module.hot ) {
|
||||||
|
module.hot.accept( '../shaders/serial-encode.frag', () => {
|
||||||
|
materialEncode.replaceShader( quadVert, serialEncodeFrag );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entityMain.components.push( new Quad( {
|
||||||
|
target: bufferEncode,
|
||||||
|
material: materialEncode,
|
||||||
|
name: process.env.DEV && 'Serial/quadEncode',
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
// -- decode -----------------------------------------------------------------------------------
|
||||||
|
const bufferDecode = new BufferRenderTarget( {
|
||||||
|
width: 320,
|
||||||
|
height: 240,
|
||||||
|
name: process.env.DEV && 'Serial/bufferDecode',
|
||||||
|
} );
|
||||||
|
|
||||||
|
const materialDecode = new Material(
|
||||||
|
quadVert,
|
||||||
|
serialDecodeFrag,
|
||||||
|
{ initOptions: { geometry: quadGeometry, target: dummyRenderTarget } },
|
||||||
|
);
|
||||||
|
materialDecode.addUniformTexture( 'sampler0', bufferEncode.texture );
|
||||||
|
materialDecode.addUniformTexture( 'samplerRandom', randomTexture.texture );
|
||||||
|
|
||||||
|
if ( process.env.DEV ) {
|
||||||
|
if ( module.hot ) {
|
||||||
|
module.hot.accept( '../shaders/serial-decode.frag', () => {
|
||||||
|
materialDecode.replaceShader( quadVert, serialDecodeFrag );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entityMain.components.push( new Quad( {
|
||||||
|
target: bufferDecode,
|
||||||
|
material: materialDecode,
|
||||||
|
name: process.env.DEV && 'Serial/quadDecode',
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
// -- blit to target -----------------------------------------------------------------------------
|
||||||
|
entityMain.components.push( new Blit( {
|
||||||
|
src: bufferDecode,
|
||||||
|
dst: options.target,
|
||||||
|
name: 'Serial/blitTarget',
|
||||||
|
filter: gl.LINEAR,
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
// -- auto -------------------------------------------------------------------------------------
|
||||||
|
auto( 'Serial/enable', ( { uninit } ) => {
|
||||||
|
entityMain.active = !uninit;
|
||||||
|
entityBypass.active = !entityMain.active;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
56
src/geometries/genPlane.ts
Normal file
56
src/geometries/genPlane.ts
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { GLCatBuffer } from '@fms-cat/glcat-ts';
|
||||||
|
import { gl, glCat } from '../globals/canvas';
|
||||||
|
|
||||||
|
interface ResultGenPlane {
|
||||||
|
position: GLCatBuffer;
|
||||||
|
index: GLCatBuffer;
|
||||||
|
count: number;
|
||||||
|
mode: GLenum;
|
||||||
|
indexType: GLenum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function genPlane( options?: {
|
||||||
|
segment?: number;
|
||||||
|
} ): ResultGenPlane {
|
||||||
|
const segment = options?.segment ?? 33;
|
||||||
|
const segmentMinusOne = segment - 1;
|
||||||
|
|
||||||
|
const pos: number[] = [];
|
||||||
|
const ind: number[] = [];
|
||||||
|
|
||||||
|
for ( let iY = 0; iY < segmentMinusOne; iY ++ ) {
|
||||||
|
const y = iY / segmentMinusOne * 2.0 - 1.0;
|
||||||
|
|
||||||
|
for ( let iX = 0; iX < segmentMinusOne; iX ++ ) {
|
||||||
|
const x = iX / segmentMinusOne * 2.0 - 1.0;
|
||||||
|
const i = iX + iY * segment;
|
||||||
|
|
||||||
|
pos.push( x, y, 0 );
|
||||||
|
ind.push(
|
||||||
|
i, i + 1, i + segment + 1,
|
||||||
|
i, i + segment + 1, i + segment,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pos.push( 1, y, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( let iX = 0; iX < segment; iX ++ ) {
|
||||||
|
const x = iX / segmentMinusOne * 2.0 - 1.0;
|
||||||
|
|
||||||
|
pos.push( x, 1, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = glCat.createBuffer();
|
||||||
|
position.setVertexbuffer( new Float32Array( pos ) );
|
||||||
|
|
||||||
|
const index = glCat.createBuffer();
|
||||||
|
index.setIndexbuffer( new Uint32Array( ind ) );
|
||||||
|
|
||||||
|
return {
|
||||||
|
position,
|
||||||
|
index,
|
||||||
|
count: ind.length,
|
||||||
|
mode: gl.TRIANGLES,
|
||||||
|
indexType: gl.UNSIGNED_INT,
|
||||||
|
};
|
||||||
|
}
|
44
src/scene.ts
44
src/scene.ts
@@ -10,6 +10,7 @@ import { CubemapCameraEntity } from './entities/CubemapCameraEntity';
|
|||||||
import { Dog } from './heck/Dog';
|
import { Dog } from './heck/Dog';
|
||||||
import { Entity } from './heck/Entity';
|
import { Entity } from './heck/Entity';
|
||||||
import { EnvironmentMap } from './entities/EnvironmentMap';
|
import { EnvironmentMap } from './entities/EnvironmentMap';
|
||||||
|
import { FlashyTerrain } from './entities/FlashyTerrain';
|
||||||
import { FlickyParticles } from './entities/FlickyParticles';
|
import { FlickyParticles } from './entities/FlickyParticles';
|
||||||
import { Glitch } from './entities/Glitch';
|
import { Glitch } from './entities/Glitch';
|
||||||
import { IBLLUT } from './entities/IBLLUT';
|
import { IBLLUT } from './entities/IBLLUT';
|
||||||
@@ -20,6 +21,7 @@ import { Post } from './entities/Post';
|
|||||||
import { RTInspector } from './entities/RTInspector';
|
import { RTInspector } from './entities/RTInspector';
|
||||||
import { Raymarcher } from './entities/Raymarcher';
|
import { Raymarcher } from './entities/Raymarcher';
|
||||||
import { Rings } from './entities/Rings';
|
import { Rings } from './entities/Rings';
|
||||||
|
import { Serial } from './entities/Serial';
|
||||||
import { SphereParticles } from './entities/SphereParticles';
|
import { SphereParticles } from './entities/SphereParticles';
|
||||||
import { SufferTexts } from './entities/SufferTexts';
|
import { SufferTexts } from './entities/SufferTexts';
|
||||||
import { Swap, Vector3 } from '@fms-cat/experimental';
|
import { Swap, Vector3 } from '@fms-cat/experimental';
|
||||||
@@ -98,10 +100,17 @@ if ( process.env.DEV && module.hot ) {
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
const replacerSVGTest = new EntityReplacer( () => new Condition(), 'Condition' );
|
const replacerCondition = new EntityReplacer( () => new Condition(), 'Condition' );
|
||||||
if ( process.env.DEV && module.hot ) {
|
if ( process.env.DEV && module.hot ) {
|
||||||
module.hot.accept( './entities/Condition', () => {
|
module.hot.accept( './entities/Condition', () => {
|
||||||
replacerSVGTest.replace();
|
replacerCondition.replace();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
const replacerFlashyTerrain = new EntityReplacer( () => new FlashyTerrain(), 'FlashyTerrain' );
|
||||||
|
if ( process.env.DEV && module.hot ) {
|
||||||
|
module.hot.accept( './entities/FlashyTerrain', () => {
|
||||||
|
replacerFlashyTerrain.replace();
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,9 +254,13 @@ const camera = new CameraEntity( {
|
|||||||
camera.camera.clear = [ 0.0, 0.0, 0.0, 0.0 ];
|
camera.camera.clear = [ 0.0, 0.0, 0.0, 0.0 ];
|
||||||
camera.components.unshift( new Lambda( {
|
camera.components.unshift( new Lambda( {
|
||||||
onUpdate: ( { time } ) => {
|
onUpdate: ( { time } ) => {
|
||||||
const r = auto( 'Camera/r' );
|
const r = auto( 'Camera/rot/r' );
|
||||||
const t = auto( 'Camera/t' );
|
const t = auto( 'Camera/rot/t' );
|
||||||
const p = auto( 'Camera/p' );
|
const p = auto( 'Camera/rot/p' );
|
||||||
|
const x = auto( 'Camera/pos/x' );
|
||||||
|
const y = auto( 'Camera/pos/y' );
|
||||||
|
const z = auto( 'Camera/pos/z' );
|
||||||
|
const roll = auto( 'Camera/roll' );
|
||||||
|
|
||||||
const st = Math.sin( t );
|
const st = Math.sin( t );
|
||||||
const ct = Math.cos( t );
|
const ct = Math.cos( t );
|
||||||
@@ -261,17 +274,17 @@ camera.components.unshift( new Lambda( {
|
|||||||
|
|
||||||
camera.transform.lookAt(
|
camera.transform.lookAt(
|
||||||
new Vector3( [
|
new Vector3( [
|
||||||
r * ct * sp + wubPosAmp * Math.sin( wubPosTheta ),
|
r * ct * sp + wubPosAmp * Math.sin( wubPosTheta ) + x,
|
||||||
r * st + wubPosAmp * Math.sin( 2.0 + wubPosTheta ),
|
r * st + wubPosAmp * Math.sin( 2.0 + wubPosTheta ) + y,
|
||||||
r * ct * cp + wubPosAmp * Math.sin( 4.0 + wubPosTheta ),
|
r * ct * cp + wubPosAmp * Math.sin( 4.0 + wubPosTheta ) + z,
|
||||||
] ),
|
] ),
|
||||||
new Vector3( [
|
new Vector3( [
|
||||||
wubTarAmp * Math.sin( wubTarTheta ),
|
wubTarAmp * Math.sin( wubTarTheta ) + x,
|
||||||
wubTarAmp * Math.sin( 2.0 + wubTarTheta ),
|
wubTarAmp * Math.sin( 2.0 + wubTarTheta ) + y,
|
||||||
wubTarAmp * Math.sin( 4.0 + wubTarTheta ),
|
wubTarAmp * Math.sin( 4.0 + wubTarTheta ) + z,
|
||||||
] ),
|
] ),
|
||||||
undefined,
|
undefined,
|
||||||
0.02 * Math.sin( 2.74 * time ),
|
0.02 * Math.sin( 2.74 * time ) + roll,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
name: process.env.DEV && 'main/updateCamera',
|
name: process.env.DEV && 'main/updateCamera',
|
||||||
@@ -306,6 +319,13 @@ const pixelSorter = new PixelSorter( {
|
|||||||
} );
|
} );
|
||||||
dog.root.children.push( pixelSorter );
|
dog.root.children.push( pixelSorter );
|
||||||
|
|
||||||
|
swap.swap();
|
||||||
|
const serial = new Serial( {
|
||||||
|
input: swap.i,
|
||||||
|
target: swap.o,
|
||||||
|
} );
|
||||||
|
dog.root.children.push( serial );
|
||||||
|
|
||||||
swap.swap();
|
swap.swap();
|
||||||
const post = new Post( {
|
const post = new Post( {
|
||||||
input: swap.i,
|
input: swap.i,
|
||||||
|
40
src/shaders/flashy-terrain.frag
Normal file
40
src/shaders/flashy-terrain.frag
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
const float TAU = 6.283185307;
|
||||||
|
|
||||||
|
in float vInstanceId;
|
||||||
|
in vec3 vNormal;
|
||||||
|
in vec4 vPosition;
|
||||||
|
in vec4 vPositionWithoutModel;
|
||||||
|
|
||||||
|
#ifdef DEFERRED
|
||||||
|
layout (location = 0) out vec4 fragPosition;
|
||||||
|
layout (location = 1) out vec4 fragNormal;
|
||||||
|
layout (location = 2) out vec4 fragColor;
|
||||||
|
layout (location = 3) out vec4 fragWTF;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
|
||||||
|
#pragma glslify: cyclicNoise = require( ./modules/cyclicNoise );
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float grid = max(
|
||||||
|
step( 0.996, cos( 16.0 * TAU * vPositionWithoutModel.x ) ),
|
||||||
|
step( 0.996, cos( 16.0 * TAU * vPositionWithoutModel.y ) )
|
||||||
|
);
|
||||||
|
vec2 cell = floor( 16.0 * vPositionWithoutModel.xy );
|
||||||
|
grid = max(
|
||||||
|
grid,
|
||||||
|
smoothstep( 0.2, 0.3, cyclicNoise( vec3( cell.xy, 4.0 * time ) ).x )
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef DEFERRED
|
||||||
|
fragPosition = vPosition;
|
||||||
|
fragNormal = vec4( 0.0, 0.0, 1.0, 1.0 );
|
||||||
|
fragColor = vec4( grid * vec3( 2.0 ), 1.0 );
|
||||||
|
fragWTF = vec4( 0.0, 0.0, 0.0, 1 );
|
||||||
|
#endif
|
||||||
|
}
|
30
src/shaders/flashy-terrain.vert
Normal file
30
src/shaders/flashy-terrain.vert
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 position;
|
||||||
|
|
||||||
|
out vec4 vPositionWithoutModel;
|
||||||
|
out vec4 vPosition;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform mat4 viewMatrix;
|
||||||
|
uniform mat4 modelMatrix;
|
||||||
|
uniform mat4 normalMatrix;
|
||||||
|
|
||||||
|
#pragma glslify: cyclicNoise = require( ./modules/cyclicNoise );
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vPositionWithoutModel = vec4( position, 1.0 );
|
||||||
|
|
||||||
|
float n = 0.5 + 0.5 * cyclicNoise( 2.0 * vPositionWithoutModel.xyz - vec3( 0.0, time, 0.0 ) ).x;
|
||||||
|
vPositionWithoutModel.z += 1.0 * n * exp( -2.0 * length( vPositionWithoutModel.xy ) );
|
||||||
|
|
||||||
|
vPosition = modelMatrix * vPositionWithoutModel;
|
||||||
|
|
||||||
|
vec4 outPos = projectionMatrix * viewMatrix * vPosition;
|
||||||
|
outPos.x *= resolution.y / resolution.x;
|
||||||
|
gl_Position = outPos;
|
||||||
|
|
||||||
|
vPosition.w = outPos.z / outPos.w;
|
||||||
|
}
|
5
src/shaders/modules/fractSin.glsl
Normal file
5
src/shaders/modules/fractSin.glsl
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
float fractSin( float s ) {
|
||||||
|
return fract( sin( s * 114.514 ) * 1919.810 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma glslify: export(fractSin)
|
49
src/shaders/serial-decode.frag
Normal file
49
src/shaders/serial-decode.frag
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
const int DECODE_ITER = 10;
|
||||||
|
const float INV_DECODE_ITER = 1.0 / float( DECODE_ITER );
|
||||||
|
const float DECODE_PERIOD = 2.0;
|
||||||
|
const float CHROMA_AMP = 0.4;
|
||||||
|
const float PI = 3.14159265;
|
||||||
|
const float TAU = PI * 2.0;
|
||||||
|
const vec2 CHROMA_FREQ = vec2( 227.5, 120.0 );
|
||||||
|
const mat3 YCBCR_TO_RGB = mat3( 1.0, 1.0, 1.0, 0.0, -0.344136, 1.772, 1.402, -0.714136, 0.0 );
|
||||||
|
|
||||||
|
#define saturate(i) clamp(i,0.,1.)
|
||||||
|
#define linearstep(a,b,x) saturate(((x)-(a))/((b)-(a)))
|
||||||
|
#define lofi(i,m) (floor((i)/(m))*(m))
|
||||||
|
|
||||||
|
in vec2 vUv;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform sampler2D sampler0;
|
||||||
|
|
||||||
|
// https://www.shadertoy.com/view/3sKSzW
|
||||||
|
void main() {
|
||||||
|
// YCbCr
|
||||||
|
float y = 0.0;
|
||||||
|
vec2 cbcr = vec2( 0.0 );
|
||||||
|
|
||||||
|
// sample
|
||||||
|
vec2 sampleOffset = vec2( 1.0, 0.0 ) / CHROMA_FREQ.x * DECODE_PERIOD * INV_DECODE_ITER;
|
||||||
|
for ( int i = -DECODE_ITER / 2; i < DECODE_ITER / 2; i ++ ) {
|
||||||
|
vec2 uvt = vUv - float( i ) * sampleOffset;
|
||||||
|
float tex = texture( sampler0, uvt ).x * INV_DECODE_ITER;
|
||||||
|
y += tex;
|
||||||
|
float phase = TAU * dot( CHROMA_FREQ, uvt );
|
||||||
|
cbcr += tex * vec2( cos( phase ), sin( phase ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// back to rgb
|
||||||
|
vec3 col = YCBCR_TO_RGB * vec3(
|
||||||
|
saturate( 1.2 * ( linearstep( CHROMA_AMP, 1.0 - CHROMA_AMP, y ) - 0.5 ) + 0.5 ),
|
||||||
|
PI * cbcr / CHROMA_AMP
|
||||||
|
);
|
||||||
|
|
||||||
|
fragColor = vec4( col, 1.0 );
|
||||||
|
}
|
81
src/shaders/serial-encode.frag
Normal file
81
src/shaders/serial-encode.frag
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
const int LPF_ITER = 10;
|
||||||
|
const float INV_LPF_ITER = 1.0 / float( LPF_ITER );
|
||||||
|
const float LPF_WIDTH = 0.04;
|
||||||
|
const float CHROMA_AMP = 0.4;
|
||||||
|
const float DECODE_PERIOD = 2.0;
|
||||||
|
const float PI = 3.14159265;
|
||||||
|
const float TAU = PI * 2.0;
|
||||||
|
const float NOISE_CLUTCH = 0.1;
|
||||||
|
const vec2 CHROMA_FREQ = vec2( 227.5, 120.0 );
|
||||||
|
const mat3 RGB_TO_YCBCR = mat3( 0.299, -0.168736, 0.5, 0.587, -0.331264, -0.418688, 0.114, 0.5, -0.081312 );
|
||||||
|
|
||||||
|
#define saturate(i) clamp(i,0.,1.)
|
||||||
|
#define linearstep(a,b,x) saturate(((x)-(a))/((b)-(a)))
|
||||||
|
#define lofi(i,m) (floor((i)/(m))*(m))
|
||||||
|
|
||||||
|
in vec2 vUv;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
uniform float time;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform sampler2D sampler0;
|
||||||
|
|
||||||
|
#pragma glslify: fractSin = require( ./modules/fractSin );
|
||||||
|
#pragma glslify: cyclicNoise = require( ./modules/cyclicNoise );
|
||||||
|
|
||||||
|
// https://www.shadertoy.com/view/3sKSzW
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vUv;
|
||||||
|
|
||||||
|
// prepare random noises
|
||||||
|
vec3 noise = cyclicNoise( vec3( uv, time ) );
|
||||||
|
vec3 hnoise = cyclicNoise( vec3( vec2( 1.0, 320.0 ) * uv, 100.0 * fract( time ) ) );
|
||||||
|
|
||||||
|
// offsync noise
|
||||||
|
vec3 offsyncPos = vec3( vec2( 0.02, 1.0 ) * uv, 0.0 );
|
||||||
|
offsyncPos -= vec3( 0.03, 0.2, 1.0 ) * time;
|
||||||
|
vec3 offsyncNoise = cyclicNoise( offsyncPos );
|
||||||
|
float offsyncAmp = offsyncNoise.y * linearstep( 0.5, 1.0, offsyncNoise.x );
|
||||||
|
offsyncAmp *= 1.0 - uv.y;
|
||||||
|
float offsyncChromaSup = 1.0 - linearstep( 0.0, 0.1, abs( offsyncAmp ) );
|
||||||
|
|
||||||
|
float phase = TAU * dot( CHROMA_FREQ, uv );
|
||||||
|
|
||||||
|
uv.x += 0.2 * offsyncAmp;
|
||||||
|
phase += CHROMA_FREQ.x * 0.05 * offsyncAmp;
|
||||||
|
|
||||||
|
vec4 tex = saturate( texture( sampler0, uv ) );
|
||||||
|
vec3 ycbcr = RGB_TO_YCBCR * tex.xyz;
|
||||||
|
|
||||||
|
// chroma signal will be filtered using LPF, this time we're gonna use cheap LPF
|
||||||
|
ycbcr.yz *= 0.0;
|
||||||
|
for ( int i = 1; i < LPF_ITER; i ++ ) {
|
||||||
|
vec2 uvt = uv - vec2( INV_LPF_ITER * LPF_WIDTH * float( i ), 0.0 );
|
||||||
|
vec4 tex = saturate( texture( sampler0, uvt ) );
|
||||||
|
ycbcr.yz += INV_LPF_ITER * ( RGB_TO_YCBCR * tex.xyz ).yz;
|
||||||
|
}
|
||||||
|
|
||||||
|
float signal = ycbcr.x; // y as base level
|
||||||
|
signal = mix( CHROMA_AMP, 1.0 - CHROMA_AMP, signal );
|
||||||
|
signal += CHROMA_AMP * offsyncChromaSup * (
|
||||||
|
ycbcr.y * cos( phase ) +
|
||||||
|
ycbcr.z * sin( phase )
|
||||||
|
); // cb as cosine of subcarrier
|
||||||
|
|
||||||
|
// static noise
|
||||||
|
signal += 0.01 * ( fractSin( noise.x ) - 0.5 );
|
||||||
|
|
||||||
|
// high peak noise
|
||||||
|
float bump = exp( -2.0 * fract( 10.0 * hnoise.z * ( 1.0 * hnoise.x + uv.x ) ) );
|
||||||
|
signal += 4.0 * pow(
|
||||||
|
( 0.5 + 0.5 * hnoise.y ) * bump,
|
||||||
|
mix( 20.0, 8.0, linearstep( 0.0, 0.01, abs( offsyncAmp ) ) )
|
||||||
|
);
|
||||||
|
|
||||||
|
fragColor = vec4( signal, 0.0, 0.0, 1.0 );
|
||||||
|
}
|
@@ -122,7 +122,7 @@ void main() {
|
|||||||
) {
|
) {
|
||||||
dt = time - timing;
|
dt = time - timing;
|
||||||
|
|
||||||
pos = 15.0 * randomSphere( seed );
|
pos = 10.0 * randomSphere( seed );
|
||||||
|
|
||||||
vel = 1.0 * randomSphere( seed );
|
vel = 1.0 * randomSphere( seed );
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user