mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-20 12:21:38 +02:00
feature: add PixelSorter
This commit is contained in:
@@ -1 +1 @@
|
|||||||
{"version":"4.1.1","resolution":100,"curves":[{"nodes":[[0,1,0,0,0.16140350877192983],[1,0,-0.47719298245614045]]}],"channels":[["Glitch/amp",{"items":[{"length":1,"curve":0}]}]],"labels":{"zero":0},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":0.1,"snapBeatActive":false,"bpm":140,"beatOffset":0,"useBeatInGUI":false,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}}
|
{"version":"4.1.1","resolution":100,"curves":[{"nodes":[[0,1,0,0,0.16140350877192983],[1,0,-0.47719298245614045]]}],"channels":[["Glitch/amp",{"items":[{"length":1,"curve":0}]}],["PixelSorter/amp",{"items":[{},{"time":1,"length":1,"curve":0}]}]],"labels":{"zero":0},"guiSettings":{"snapTimeActive":true,"snapTimeInterval":0.1,"snapValueActive":true,"snapValueInterval":0.1,"snapBeatActive":false,"bpm":140,"beatOffset":0,"useBeatInGUI":false,"minimizedPrecisionTime":3,"minimizedPrecisionValue":3}}
|
125
src/entities/PixelSorter.ts
Normal file
125
src/entities/PixelSorter.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import { Entity } from '../heck/Entity';
|
||||||
|
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||||
|
import { Material } from '../heck/Material';
|
||||||
|
import { Quad } from '../heck/components/Quad';
|
||||||
|
import { RenderTarget } from '../heck/RenderTarget';
|
||||||
|
import pixelSorterIndexFrag from '../shaders/pixel-sorter-index.frag';
|
||||||
|
import pixelSorterFrag from '../shaders/pixel-sorter.frag';
|
||||||
|
import quadVert from '../shaders/quad.vert';
|
||||||
|
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||||
|
import { Swap } from '@fms-cat/experimental';
|
||||||
|
import { DISPLAY } from '../heck/DISPLAY';
|
||||||
|
import { Automaton } from '@fms-cat/automaton';
|
||||||
|
|
||||||
|
export interface PixelSorterOptions {
|
||||||
|
input: GLCatTexture<WebGL2RenderingContext>;
|
||||||
|
target: RenderTarget;
|
||||||
|
automaton: Automaton;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PixelSorter {
|
||||||
|
public entity: Entity;
|
||||||
|
public swapBuffer: Swap<BufferRenderTarget>;
|
||||||
|
|
||||||
|
public constructor( options: PixelSorterOptions ) {
|
||||||
|
const { gl } = DISPLAY;
|
||||||
|
|
||||||
|
this.entity = new Entity();
|
||||||
|
this.entity.visible = false;
|
||||||
|
|
||||||
|
this.swapBuffer = new Swap(
|
||||||
|
new BufferRenderTarget( {
|
||||||
|
width: options.target.width,
|
||||||
|
height: options.target.height,
|
||||||
|
numBuffers: 2,
|
||||||
|
name: process.env.DEV && 'PixelSorter/swap0',
|
||||||
|
} ),
|
||||||
|
new BufferRenderTarget( {
|
||||||
|
width: options.target.width,
|
||||||
|
height: options.target.height,
|
||||||
|
numBuffers: 2,
|
||||||
|
name: process.env.DEV && 'PixelSorter/swap1',
|
||||||
|
} ),
|
||||||
|
);
|
||||||
|
|
||||||
|
// -- calc index -------------------------------------------------------------------------------
|
||||||
|
let mul = 1;
|
||||||
|
const indexMaterials: Material[] = [];
|
||||||
|
|
||||||
|
while ( mul < options.target.width ) {
|
||||||
|
const isFirst = mul === 1;
|
||||||
|
|
||||||
|
const material = new Material(
|
||||||
|
quadVert,
|
||||||
|
pixelSorterIndexFrag,
|
||||||
|
);
|
||||||
|
material.addUniform( 'mul', '1f', mul );
|
||||||
|
material.addUniformTexture(
|
||||||
|
'sampler0',
|
||||||
|
isFirst ? options.input : this.swapBuffer.o.getTexture( gl.COLOR_ATTACHMENT0 ),
|
||||||
|
);
|
||||||
|
material.addUniformTexture(
|
||||||
|
'sampler1',
|
||||||
|
this.swapBuffer.o.getTexture( gl.COLOR_ATTACHMENT1 ),
|
||||||
|
);
|
||||||
|
indexMaterials.push( material );
|
||||||
|
|
||||||
|
this.entity.components.push( new Quad( {
|
||||||
|
target: this.swapBuffer.i,
|
||||||
|
material,
|
||||||
|
name: process.env.DEV && `PixelSorter/quadIndex-${ mul }`,
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
this.swapBuffer.swap();
|
||||||
|
|
||||||
|
mul *= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- sort -------------------------------------------------------------------------------------
|
||||||
|
let dir = 1.0 / 64.0;
|
||||||
|
let comp = 1.0 / 64.0;
|
||||||
|
|
||||||
|
while ( dir < 1.0 ) {
|
||||||
|
const isLast = ( dir === 0.5 ) && ( comp === 1.0 / 64.0 );
|
||||||
|
|
||||||
|
const material = new Material(
|
||||||
|
quadVert,
|
||||||
|
pixelSorterFrag,
|
||||||
|
);
|
||||||
|
material.addUniform( 'dir', '1f', dir );
|
||||||
|
material.addUniform( 'comp', '1f', comp );
|
||||||
|
material.addUniformTexture(
|
||||||
|
'sampler0',
|
||||||
|
this.swapBuffer.o.getTexture( gl.COLOR_ATTACHMENT0 ),
|
||||||
|
);
|
||||||
|
material.addUniformTexture(
|
||||||
|
'sampler1',
|
||||||
|
this.swapBuffer.o.getTexture( gl.COLOR_ATTACHMENT1 ),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.entity.components.push( new Quad( {
|
||||||
|
target: isLast ? options.target : this.swapBuffer.i,
|
||||||
|
material,
|
||||||
|
name: process.env.DEV && `PixelSorter/quad-${ dir }-${ comp }`,
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
this.swapBuffer.swap();
|
||||||
|
|
||||||
|
if ( comp === 1.0 / 64.0 ) {
|
||||||
|
dir *= 2.0;
|
||||||
|
comp = dir;
|
||||||
|
} else {
|
||||||
|
comp /= 2.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- update uniform ---------------------------------------------------------------------------
|
||||||
|
options.automaton.auto( 'PixelSorter/amp', ( { value } ) => {
|
||||||
|
indexMaterials.map( ( material ) => {
|
||||||
|
material.addUniform( 'threshold', '1f', value );
|
||||||
|
} );
|
||||||
|
|
||||||
|
this.entity.active = 0.0 < value;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
11
src/main.ts
11
src/main.ts
@@ -23,6 +23,7 @@ import { Rings } from './entities/Rings';
|
|||||||
import { RTInspector } from './entities/RTInspector';
|
import { RTInspector } from './entities/RTInspector';
|
||||||
import { Component } from './heck/components/Component';
|
import { Component } from './heck/components/Component';
|
||||||
import { FlickyParticles } from './entities/FlickyParticles';
|
import { FlickyParticles } from './entities/FlickyParticles';
|
||||||
|
import { PixelSorter } from './entities/PixelSorter';
|
||||||
|
|
||||||
// == gl ===========================================================================================
|
// == gl ===========================================================================================
|
||||||
const { canvas, glCat } = DISPLAY;
|
const { canvas, glCat } = DISPLAY;
|
||||||
@@ -166,7 +167,7 @@ if ( process.env.DEV ) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// == random texture ===============================================================================
|
// == textures =====================================================================================
|
||||||
const randomTexture = new RandomTexture(
|
const randomTexture = new RandomTexture(
|
||||||
glCat,
|
glCat,
|
||||||
RANDOM_RESOLUTION[ 0 ],
|
RANDOM_RESOLUTION[ 0 ],
|
||||||
@@ -316,6 +317,14 @@ const glitch = new Glitch( {
|
|||||||
} );
|
} );
|
||||||
dog.root.children.push( glitch.entity );
|
dog.root.children.push( glitch.entity );
|
||||||
|
|
||||||
|
swap.swap();
|
||||||
|
const pixelSorter = new PixelSorter( {
|
||||||
|
input: swap.i.texture,
|
||||||
|
target: swap.o,
|
||||||
|
automaton,
|
||||||
|
} );
|
||||||
|
dog.root.children.push( pixelSorter.entity );
|
||||||
|
|
||||||
swap.swap();
|
swap.swap();
|
||||||
const post = new Post( {
|
const post = new Post( {
|
||||||
input: swap.i.texture,
|
input: swap.i.texture,
|
||||||
|
37
src/shaders/pixel-sorter-index.frag
Normal file
37
src/shaders/pixel-sorter-index.frag
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
const vec3 RGB = vec3( 0.299, 0.587, 0.114 );
|
||||||
|
|
||||||
|
in vec2 vUv;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 fragColor;
|
||||||
|
layout (location = 1) out vec4 fragClamp;
|
||||||
|
|
||||||
|
uniform float threshold;
|
||||||
|
uniform float mul;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform sampler2D sampler0;
|
||||||
|
uniform sampler2D sampler1;
|
||||||
|
|
||||||
|
vec2 getValue( vec2 uv ) {
|
||||||
|
return ( ( uv.x < 0.0 ) || ( 1.0 < uv.x ) )
|
||||||
|
? vec2( 0.0 )
|
||||||
|
: ( mul == 1.0 )
|
||||||
|
? vec2( 1E9 * step( dot( texture( sampler0, uv ).xyz, RGB ), threshold ) )
|
||||||
|
: texture( sampler1, uv ).xy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vUv;
|
||||||
|
|
||||||
|
fragColor = vec4( texture( sampler0, uv ).xyz, 1.0 );
|
||||||
|
fragClamp = vec4( getValue( uv ), 0.0, 1.0 );
|
||||||
|
|
||||||
|
for ( int i = 1; i < 8; i ++ ) {
|
||||||
|
vec2 uvc = uv - vec2( i, 0 ) / resolution * mul;
|
||||||
|
vec2 texc = getValue( uvc );
|
||||||
|
fragClamp.xy = min( fragClamp.xy, texc + mul * float( i ) );
|
||||||
|
}
|
||||||
|
}
|
58
src/shaders/pixel-sorter.frag
Normal file
58
src/shaders/pixel-sorter.frag
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#version 300 es
|
||||||
|
|
||||||
|
precision highp float;
|
||||||
|
|
||||||
|
#define lofi(i,m) (floor((i)/(m))*(m))
|
||||||
|
|
||||||
|
const vec3 RGB = vec3( 0.299, 0.587, 0.114 );
|
||||||
|
|
||||||
|
in vec2 vUv;
|
||||||
|
|
||||||
|
layout (location = 0) out vec4 fragColor;
|
||||||
|
layout (location = 1) out vec4 fragClamp;
|
||||||
|
|
||||||
|
uniform float dir;
|
||||||
|
uniform float comp;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform sampler2D sampler0;
|
||||||
|
uniform sampler2D sampler1;
|
||||||
|
|
||||||
|
float positiveOrHuge( float i ) {
|
||||||
|
return 0.0 < i ? i : 1E9;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 uv = vUv;
|
||||||
|
|
||||||
|
fragColor = texture( sampler0, uv );
|
||||||
|
fragClamp = texture( sampler1, uv );
|
||||||
|
|
||||||
|
if ( fragClamp.x < 0.5 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float index = fragClamp.x - 1.0;
|
||||||
|
float width = fragClamp.x + fragClamp.y - 1.0;
|
||||||
|
|
||||||
|
bool isCompRight = mod( index, 2.0 * comp * width ) < comp * width;
|
||||||
|
float offset = floor( ( isCompRight ? comp : -comp ) * width + 0.5 );
|
||||||
|
|
||||||
|
vec2 uvc = uv;
|
||||||
|
uvc.x += offset / resolution.x;
|
||||||
|
vec4 cColor = texture( sampler0, uvc );
|
||||||
|
vec4 cClamp = texture( sampler1, uvc );
|
||||||
|
|
||||||
|
if ( uvc.x < 0.0 || 1.0 < uvc.x ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float vp = dot( fragColor.xyz, RGB );
|
||||||
|
float vc = dot( cColor.xyz, RGB );
|
||||||
|
|
||||||
|
bool shouldSwap = mod( index / ( 2.0 * dir * width ), 2.0 ) < 1.0;
|
||||||
|
shouldSwap = shouldSwap ^^ isCompRight;
|
||||||
|
shouldSwap = shouldSwap ^^ ( vc < vp );
|
||||||
|
if ( shouldSwap ) {
|
||||||
|
fragColor = cColor;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user