Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slicer effect #119

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Slicer effect based on a shader I wrote for this http://mikedotalmond…
….co.uk/projects/horizon

Includes camera and static image examples.
Todo: tidy up and add slice position animation
mikedotalmond committed Apr 14, 2016
commit cd66ae780e695fd9a7a726cac4c6d84635a7787d
172 changes: 172 additions & 0 deletions effects/seriously.slicer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* global define, require */
(function (root, factory) {
'use strict';

if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['seriously'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
factory(require('seriously'));
} else {
if (!root.Seriously) {
root.Seriously = { plugin: function (name, opt) { this[name] = opt; } };
}
factory(root.Seriously);
}
}(window, function (Seriously) {
'use strict';

Seriously.plugin('slicer', function (options) {

if(typeof options !== 'object') options = {};

var u,
slicePositions,
updateSlices = function(){
u.slicesA = slicePositions.slice(0,4);
u.slicesB = slicePositions.slice(4);
},
reset = function(){
slicePositions=[];
for(var i=0; i<8; i++){ slicePositions[i] = i/7; }
updateSlices();
},
randomise = function(){
slicePositions=[];
for(var i=0; i<8; i++){ slicePositions[i] = i/7 + Math.random()*1/8; }
updateSlices();
};

return {
initialize: function (initialize, gl) {
initialize();
u = this.uniforms;

options.reset = reset;
options.randomise = randomise;

slicePositions=[];
for(var i=0; i<8; i++){ slicePositions.push(.0); }
},
resize: function () {
this.uniforms.invHeight = 1.0 / this.height;
},
commonShader: true,
shader: function (inputs, shaderSource) {

shaderSource.fragment = [

'precision mediump float;',

'const float noiseAmt = .04;', // just add a low level of noise. make configurable if you want...

'varying vec2 vTexCoord;',

'uniform sampler2D source;',

'uniform vec4 slicesA;',
'uniform vec4 slicesB;',

'uniform float seed;',
'uniform float invHeight;',
'uniform float ySpread;',

'float rnd(vec2 x) {',
'return fract(sin(dot(x.xy, vec2(12.9898, 78.233))) * 43758.5453);',
'}',

'void main() {',

'float vx = vTexCoord.x;',
'float r = rnd(seed * vTexCoord);',

// get y position, and add offsets to scale and position some Y noise
'float y = vTexCoord.y + (r-.5) * ySpread * invHeight;',

'vec2 sliceACoord = vec2(0, y);',
'vec2 sliceBCoord = vec2(0, y);',

'if(vx < slicesA[1]) {',
'sliceACoord.x = slicesA[0];',
'sliceBCoord.x = slicesA[1];',
'}',
'else if(vx < slicesA[2]) {',
'sliceACoord.x = slicesA[1];',
'sliceBCoord.x = slicesA[2];',
'}',
'else if(vx < slicesA[3]) {',
'sliceACoord.x = slicesA[2];',
'sliceBCoord.x = slicesA[3];',
'}',
'else if(vx < slicesB[0]) {',
'sliceACoord.x = slicesA[3];',
'sliceBCoord.x = slicesB[0];',
'}',
'else if(vx < slicesB[1]) {',
'sliceACoord.x = slicesB[0];',
'sliceBCoord.x = slicesB[1];',
'}',
'else if(vx < slicesB[2]) {',
'sliceACoord.x = slicesB[1];',
'sliceBCoord.x = slicesB[2];',
'}',
'else {',
'sliceACoord.x = slicesB[2];',
'sliceBCoord.x = slicesB[3];',
'}',

'float f2 = (vx - sliceACoord.x) / (sliceBCoord.x - sliceACoord.x);',

// lerp between the two sampling positions
'vec4 c = mix(texture2D(source, sliceACoord), texture2D(source, sliceBCoord), f2);',

// add noise (monochromatic)
'c += (r - 0.5) * noiseAmt;',

// output
'gl_FragColor = c;',
'}'
].join('\n');
return shaderSource;
}
};
},
{ // meta
inPlace: true,
inputs: {
source: {
type: 'image',
uniform: 'source'
},
ySpread:{
type:'number',
uniform: 'ySpread',
min: 0,
max: 1024,
defaultValue:1.5
},
slicesA: {
type: 'vector',
dimensions: 4,
uniform: 'slicesA',
defaultValue: [.0, 1/7, 2/7, 3/7]
},
slicesB: {
type: 'vector',
dimensions: 4,
uniform: 'slicesB',
defaultValue: [4/7, 5/7, 6/7, 1.0]
},
seed: {
type: 'number',
uniform: 'seed',
min: 1,
max: 1024,
defaultValue: 1 + Math.random() * 1023
}
},
title: 'Slicer',
description: 'Slicer Effect'
});
}));
1 change: 1 addition & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@
<li><a href="demo/threejs-source.html">Three.js Source</a></li>
<li><a href="demo/threejs-target.html">Three.js Target</a></li>
<li><a href="mirror/">Mirror</a> (<a href="mirror/camera.html">Camera</a>)</li>
<li><a href="slicer/">Slicer</a> (<a href="slicer/camera.html">Camera</a>)</li>
<li>Transforms
<ul>
<li><a href="transform/reformat.html">Reformat</a></li>
107 changes: 107 additions & 0 deletions examples/slicer/camera.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>Seriously.js Camera Demo with slicer effect</title>
<style type="text/css">
body {
margin: 0;
}
img {
display: none;
}
#canvas {
position: relative;
top: 0;
left: 0;
width: 1024px;
display:block;
}
button {
padding:4px;
margin-bottom:8px;
}
.controls{
margin:16px;
}
</style>
</head>
<body>
<canvas id="target" width="640" height="480"></canvas>

<div class="controls">
Slice positions &#160;
<button id="reset">Reset</button>&#160;
<button id="randomise">Randomise</button>&#160;
<button disabled id="animate">Animate</button>&#160;
<span>Todo: add slice position animation</span>

<div>
<label for="ySpread">Y Spread</label>
<input type="range" id="ySpread" min="0" max="128" step="0.1" value="16" style="width:512px" />
</div>
<div>
<label for="blur-amount">Blur</label>
<input type="range" id="blur-amount" min="0" max="1" step="0.001" value=".25" style="width:512px" />
</div>
</div>

<script src="../../seriously.js"></script>
<script src="../../sources/seriously.camera.js"></script>
<script src="../../effects/seriously.slicer.js"></script>
<script src="../../effects/seriously.blur.js"></script>
<script>
(function() {
//main code goes here

// declare our variables
var srsly, // the main object that holds the entire composition
source, // wrapper object for source video
slicer, // slicer effect
slicerOptions,
blur, // optional, add some blur to the output
target; // a wrapper object for our target canvas

if (Seriously.incompatible('camera')) {
document.body.appendChild(document.createTextNode('Sorry, your browser does not support getUserMedia'));
document.querySelector('canvas').style.display = 'none';
return;
}

slicerOptions={};
// construct our seriously object
srsly = new Seriously();

source = srsly.source('camera');
target = srsly.target('#target');
slicer = srsly.effect('slicer', slicerOptions);
blur = srsly.effect('blur');

// connect the nodes
slicer.source = source;
blur.source = slicer;
target.source = blur;

//
// optional. some built-in utils - reset slices so they are evenly distributed, or randomise them.
document.getElementById('reset').addEventListener('click',function(){
slicerOptions.reset();
});
document.getElementById('randomise').addEventListener('click',function(){
slicerOptions.randomise();
});

slicer.ySpread= '#ySpread';
blur.amount = '#blur-amount';

srsly.go(
function(){
// before render
slicer.seed = 1.0 + Math.random() * 1024;
}
);
}());
</script>

</body>
</html>
100 changes: 100 additions & 0 deletions examples/slicer/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!DOCTYPE html>
<html>
<head>
<title>Seriously.js Slicer Example</title>
<meta name="viewport" content="width=device-width, user-scalable=no">
<style type="text/css">
img{
display:none;
}
body {
margin: 0;
}
#canvas {
position: relative;
top: 0;
left: 0;
width: 1024px;
display:block;
}
button {
padding:4px;
margin-bottom:8px;
}
.controls{
margin:16px;
}
</style>
</head>
<body>
<img src="../images/field.jpg" id="image"/>
<canvas id="canvas" width="1024" height="628"></canvas>

<div class="controls">
Slice positions &#160;
<button id="reset">Reset</button>&#160;
<button id="randomise">Randomise</button>&#160;
<button disabled id="animate">Animate</button>&#160;
<span>Todo: add slice position animation</span>

<div>
<label for="ySpread">Y Spread</label>
<input type="range" id="ySpread" min="0" max="128" step="0.1" value="16" style="width:512px" />
</div>
<div>
<label for="blur-amount">Blur</label>
<input type="range" id="blur-amount" min="0" max="1" step="0.001" value=".25" style="width:512px" />
</div>
</div>


<script src="../../lib/require.js"></script>
<script>
require.config({
baseUrl: '../../'
});

require([
'seriously',
'effects/seriously.slicer',
'effects/seriously.blur'
], function (Seriously) {

var seriously,
target,
slicer, slicerOptions,
blur;

seriously = new Seriously();
target = seriously.target('#canvas');

slicerOptions={};
slicer = seriously.effect('slicer', slicerOptions);


slicer.ySpread= '#ySpread';

blur = seriously.effect('blur');
blur.amount = '#blur-amount';

slicer.source = '#image';
blur.source = slicer;
target.source = blur;

// optional. some built-in utils - reset slices so they are evenly distributed, or randomise them.
document.getElementById('reset').addEventListener('click',function(){
slicerOptions.reset();
});
document.getElementById('randomise').addEventListener('click',function(){
slicerOptions.randomise();
});

seriously.go(
function(){ // before render
slicer.seed = Math.random() * 1024;
}
);
});
</script>
</body>
</html>
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@
<script type="text/javascript" src="effects/seriously.vibrance.js"></script>
<script type="text/javascript" src="effects/seriously.vignette.js"></script>
<script type="text/javascript" src="effects/seriously.split.js"></script>
<script type="text/javascript" src="effects/seriously.slicer.js"></script>
<style>

body {