bbc / VideoContext

An experimental HTML5 & WebGL video composition and rendering API.
http://bbc.github.io/VideoContext/
Apache License 2.0
1.32k stars 156 forks source link

can i use effectNode with time variable,like transitionNode mix #161

Closed jo-hnny closed 4 years ago

jo-hnny commented 5 years ago

I want to generate a special effect that changes over time. and only one image input

PTaylour commented 5 years ago

Sorry about the slow response. I haven't forgotten! Expect an answer from me early next week.

richski commented 5 years ago

@johnny19941216 You should be able to achieve this with the TransitionNode. If you write your own shader, then you can specify a single image input and adjust the effect to any property defined in customDescription.properties, e.g. the mix property populated by the TransitionNode.

Here is an example - essentially the TransitionNode and EffectNode examples merged - where a single image is transitioned from its default colour to sepia:

Custom shader:

// This an unmodified copy of the `TransitionNode` example vertexShader
const vertexShader = `
attribute vec2 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;
void main() {
    gl_Position = vec4(vec2(2.0,2.0)*a_position-vec2(1.0, 1.0), 0.0, 1.0);
    v_texCoord = a_texCoord;
}`;

/**
 * This is the `EffectNode` and `TransitionNode` `fragmentShader` examples merged, 
 * where a single input (`u_image`) is transitioned to sepia using the `mix` 
 * property provided by the `transitionNode`.
 */
const fragmentShader = `
precision mediump float;
uniform sampler2D u_image;
uniform float mix;
uniform vec3 inputMix;
uniform vec3 outputMix;
varying vec2 v_texCoord;
varying float v_mix;
void main(){
    vec4 color_a = texture2D(u_image, v_texCoord);
    vec4 color_b = texture2D(u_image, v_texCoord);
    float mono = color_b[0]*inputMix[0] + color_b[1]*inputMix[1] + color_b[2]*inputMix[2];
    color_b[0] = mono * outputMix[0];
    color_b[1] = mono * outputMix[1];
    color_b[2] = mono * outputMix[2];
    color_a[0] *= (1.0 - mix);
    color_a[1] *= (1.0 - mix);
    color_a[2] *= (1.0 - mix);
    color_a[3] *= (1.0 - mix);
    color_b[0] *= mix;
    color_b[1] *= mix;
    color_b[2] *= mix;
    color_b[3] *= mix;
    gl_FragColor = color_a + color_b;
}`;

var customDescription = {
  title: "Time-Based-Transition",
  description: "Transition from normal to sepia.",
  vertexShader,
  fragmentShader,
  properties: {
    mix: { type: "uniform", value: 0.0 },
    inputMix: { type: "uniform", value: [0.4, 0.6, 0.2] },
    outputMix: { type: "uniform", value: [1.0, 1.0, 1.0] }
  },
  inputs: ["u_image"]
};

TransitionNode example with a single input:

// Setup the video context
var canvas = document.getElementById("canvas");
var ctx = new VideoContext(canvas);

// Create an image node that plays for 5 seconds
var imageNode = ctx.image("https://source.unsplash.com/random/1280x720");
imageNode.start(0);
imageNode.stop(5);

// Create the effect node
var customEffect = ctx.transition(customDescription);

// Give a sepia tint to the monochrome output (note how shader description properties are automatically bound to the JavaScript object).
customEffect.outputMix = [1.25, 1.18, 0.9];

/**
 * Setup the transition. This will change the "mix" property of the node from 0.0 to 1.0.
 * Transition mix value from 0.0 to 1.0 at time = 1 over a period of 3 seconds to time = 4.
 */
customEffect.transition(1.0, 4.0, 0.0, 1.0, "mix");

// Connect videoNode to the "image_u" input of the processing node
imageNode.connect(customEffect);

customEffect.connect(ctx.destination);

// Start playback
ctx.play();

CodeSandbox: https://codesandbox.io/embed/tender-meitner-edmxo