@remotion/effects 4.0.541 → 4.0.543
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_LICENSES.md +10 -0
- package/dist/esm/lightning.mjs +603 -0
- package/dist/esm/magnify.mjs +403 -0
- package/dist/esm/preview/barrel-distortion.mjs +303 -0
- package/dist/esm/preview/bevel-alpha.mjs +525 -0
- package/dist/esm/preview/blur.mjs +435 -0
- package/dist/esm/preview/brightness.mjs +95 -0
- package/dist/esm/preview/burlap.mjs +481 -0
- package/dist/esm/preview/checkerboard.mjs +8 -0
- package/dist/esm/preview/chromatic-aberration.mjs +308 -0
- package/dist/esm/preview/color-correction.mjs +522 -0
- package/dist/esm/preview/color-key.mjs +440 -0
- package/dist/esm/preview/contour-lines.mjs +608 -0
- package/dist/esm/preview/contrast.mjs +95 -0
- package/dist/esm/preview/corner-pin.mjs +6 -0
- package/dist/esm/preview/curves.mjs +357 -0
- package/dist/esm/preview/cylinder.mjs +273 -0
- package/dist/esm/preview/dot-grid.mjs +333 -0
- package/dist/esm/preview/drop-shadow.mjs +607 -0
- package/dist/esm/preview/duotone.mjs +344 -0
- package/dist/esm/preview/emboss.mjs +479 -0
- package/dist/esm/preview/evolve.mjs +485 -0
- package/dist/esm/preview/exposure.mjs +264 -0
- package/dist/esm/preview/film-burn.mjs +298 -0
- package/dist/esm/preview/fisheye.mjs +422 -0
- package/dist/esm/preview/flannel.mjs +401 -0
- package/dist/esm/preview/fractal-noise.mjs +642 -0
- package/dist/esm/preview/glow.mjs +598 -0
- package/dist/esm/preview/grayscale.mjs +86 -0
- package/dist/esm/preview/gridlines.mjs +8 -0
- package/dist/esm/preview/halftone-linear-gradient.mjs +523 -0
- package/dist/esm/preview/halftone.mjs +552 -0
- package/dist/esm/preview/hue.mjs +83 -0
- package/dist/esm/preview/index-00v3hr66.mjs +299 -0
- package/dist/esm/preview/index-0w4eqht8.mjs +351 -0
- package/dist/esm/preview/index-18y0zcy2.mjs +440 -0
- package/dist/esm/preview/index-1m1b1ad7.mjs +520 -0
- package/dist/esm/preview/index-34fxm3ax.mjs +518 -0
- package/dist/esm/preview/index-4fvp93ps.mjs +32 -0
- package/dist/esm/preview/index-4scpn12x.mjs +224 -0
- package/dist/esm/preview/index-4z6pt3ka.mjs +104 -0
- package/dist/esm/preview/index-618ky75w.mjs +51 -0
- package/dist/esm/preview/index-6agxdrvr.mjs +411 -0
- package/dist/esm/preview/index-6jkps947.mjs +120 -0
- package/dist/esm/preview/index-8agtsbw4.mjs +617 -0
- package/dist/esm/preview/index-8jx11jyn.mjs +29 -0
- package/dist/esm/preview/index-8p04sssx.mjs +123 -0
- package/dist/esm/preview/index-afdtmrh2.mjs +596 -0
- package/dist/esm/preview/index-b86qstcs.mjs +18 -0
- package/dist/esm/preview/index-cb77qg3g.mjs +587 -0
- package/dist/esm/preview/index-cdp7tr8x.mjs +122 -0
- package/dist/esm/preview/index-evy8hyah.mjs +55 -0
- package/dist/esm/preview/index-gnsce796.mjs +6 -0
- package/dist/esm/preview/index-kkvzt8b7.mjs +199 -0
- package/dist/esm/preview/index-r0v18b2n.mjs +425 -0
- package/dist/esm/preview/index-rswpzmm5.mjs +926 -0
- package/dist/esm/preview/index-s9mrx750.mjs +97 -0
- package/dist/esm/preview/index-tvfexb7s.mjs +164 -0
- package/dist/esm/preview/index-vp56k1gj.mjs +215 -0
- package/dist/esm/preview/index-wxhvgv2s.mjs +79 -0
- package/dist/esm/preview/index-wy95a41r.mjs +407 -0
- package/dist/esm/preview/index-ysnwfc4t.mjs +306 -0
- package/dist/esm/preview/index.mjs +51 -0
- package/dist/esm/preview/invert.mjs +84 -0
- package/dist/esm/preview/iris-wipe.mjs +315 -0
- package/dist/esm/preview/lens-blur.mjs +563 -0
- package/dist/esm/preview/levels.mjs +400 -0
- package/dist/esm/preview/light-leak.mjs +8 -0
- package/dist/esm/preview/light-trail.mjs +516 -0
- package/dist/esm/preview/lightning.mjs +603 -0
- package/dist/esm/preview/linear-gradient-tint.mjs +6 -0
- package/dist/esm/preview/linear-gradient.mjs +6 -0
- package/dist/esm/preview/linear-progressive-blur.mjs +516 -0
- package/dist/esm/preview/linear-progressive-pixelate.mjs +176 -0
- package/dist/esm/preview/lines.mjs +536 -0
- package/dist/esm/preview/liquid-contours.mjs +512 -0
- package/dist/esm/preview/long-shadows.mjs +437 -0
- package/dist/esm/preview/lut.mjs +601 -0
- package/dist/esm/preview/magnify.mjs +403 -0
- package/dist/esm/preview/mirror.mjs +341 -0
- package/dist/esm/preview/noise-displacement.mjs +584 -0
- package/dist/esm/preview/noise.mjs +318 -0
- package/dist/esm/preview/outline.mjs +725 -0
- package/dist/esm/preview/page-turn.mjs +302 -0
- package/dist/esm/preview/paper.mjs +1249 -0
- package/dist/esm/preview/pattern.mjs +6 -0
- package/dist/esm/preview/pixel-dissolve.mjs +360 -0
- package/dist/esm/preview/pixelate.mjs +249 -0
- package/dist/esm/preview/radial-progressive-blur.mjs +582 -0
- package/dist/esm/preview/radial-progressive-pixelate.mjs +220 -0
- package/dist/esm/preview/radial-wipe.mjs +224 -0
- package/dist/esm/preview/rain-fall.mjs +114 -0
- package/dist/esm/preview/region-blur.mjs +500 -0
- package/dist/esm/preview/rings.mjs +8 -0
- package/dist/esm/preview/roughen-edges.mjs +590 -0
- package/dist/esm/preview/saturation.mjs +86 -0
- package/dist/esm/preview/scale.mjs +109 -0
- package/dist/esm/preview/scanlines.mjs +362 -0
- package/dist/esm/preview/shadows-highlights.mjs +284 -0
- package/dist/esm/preview/shatter.mjs +868 -0
- package/dist/esm/preview/shine.mjs +368 -0
- package/dist/esm/preview/shrinkwrap.mjs +769 -0
- package/dist/esm/preview/skew.mjs +300 -0
- package/dist/esm/preview/snow-fall.mjs +170 -0
- package/dist/esm/preview/speckle.mjs +356 -0
- package/dist/esm/preview/sphere.mjs +252 -0
- package/dist/esm/preview/starburst.mjs +8 -0
- package/dist/esm/preview/tear.mjs +375 -0
- package/dist/esm/preview/thermal-vision.mjs +387 -0
- package/dist/esm/preview/tile.mjs +7 -0
- package/dist/esm/preview/tint.mjs +125 -0
- package/dist/esm/preview/translate.mjs +151 -0
- package/dist/esm/preview/turbulent-displace.mjs +613 -0
- package/dist/esm/preview/tv-signal-off.mjs +308 -0
- package/dist/esm/preview/venetian-blinds.mjs +341 -0
- package/dist/esm/preview/vibrance.mjs +254 -0
- package/dist/esm/preview/vignette.mjs +458 -0
- package/dist/esm/preview/wave.mjs +384 -0
- package/dist/esm/preview/waves.mjs +599 -0
- package/dist/esm/preview/white-balance.mjs +280 -0
- package/dist/esm/preview/white-noise.mjs +244 -0
- package/dist/esm/preview/zigzag.mjs +8 -0
- package/dist/esm/preview/zoom-blur.mjs +389 -0
- package/dist/lightning/geometry.d.ts +10 -0
- package/dist/lightning/index.d.ts +4 -0
- package/dist/lightning/mask.d.ts +2 -0
- package/dist/lightning/params.d.ts +259 -0
- package/dist/lightning/shaders.d.ts +2 -0
- package/dist/lightning.d.ts +2 -0
- package/dist/magnify/shader.d.ts +1 -0
- package/dist/magnify/webgpu-shader.d.ts +1 -0
- package/dist/magnify.d.ts +28 -0
- package/package.json +30 -6
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import {
|
|
2
|
+
colorAmountSchema,
|
|
3
|
+
assertOptionalFiniteNumber,
|
|
4
|
+
validateUnitInterval
|
|
5
|
+
} from "./index-wxhvgv2s.mjs";
|
|
6
|
+
import {
|
|
7
|
+
WEBGPU_SINGLE_PASS_VERTEX,
|
|
8
|
+
setupWebGpuSinglePass,
|
|
9
|
+
cleanupWebGpuSinglePass,
|
|
10
|
+
applyWebGpuSinglePass
|
|
11
|
+
} from "./index-tvfexb7s.mjs";
|
|
12
|
+
import {
|
|
13
|
+
assertEffectParamsObject,
|
|
14
|
+
assertRequiredFiniteNumber
|
|
15
|
+
} from "./index-4fvp93ps.mjs";
|
|
16
|
+
|
|
17
|
+
// src/curves.ts
|
|
18
|
+
import { Internals } from "remotion";
|
|
19
|
+
var { createEffect, createCurveSampler, createWebGL2ContextError } = Internals;
|
|
20
|
+
var DEFAULT_POINTS = [
|
|
21
|
+
[0, 0],
|
|
22
|
+
[1, 1]
|
|
23
|
+
];
|
|
24
|
+
var DEFAULT_CHANNEL = "rgb";
|
|
25
|
+
var DEFAULT_INTERPOLATION = "smooth";
|
|
26
|
+
var DEFAULT_AMOUNT = 1;
|
|
27
|
+
var MAX_POINTS = 32;
|
|
28
|
+
var LUT_SIZE = 1024;
|
|
29
|
+
var CURVES_CHANNELS = ["rgb", "red", "green", "blue"];
|
|
30
|
+
var CURVES_INTERPOLATIONS = ["smooth", "linear"];
|
|
31
|
+
var curvesSchema = {
|
|
32
|
+
channel: {
|
|
33
|
+
type: "enum",
|
|
34
|
+
variants: { rgb: {}, red: {}, green: {}, blue: {} },
|
|
35
|
+
default: DEFAULT_CHANNEL,
|
|
36
|
+
description: "Channel"
|
|
37
|
+
},
|
|
38
|
+
points: {
|
|
39
|
+
type: "array",
|
|
40
|
+
item: { type: "uv-coordinate", min: 0, max: 1, step: 0.001 },
|
|
41
|
+
default: DEFAULT_POINTS,
|
|
42
|
+
minLength: 2,
|
|
43
|
+
maxLength: MAX_POINTS,
|
|
44
|
+
newItemDefault: [0.5, 0.5],
|
|
45
|
+
description: "Points",
|
|
46
|
+
keyframable: false
|
|
47
|
+
},
|
|
48
|
+
interpolation: {
|
|
49
|
+
type: "enum",
|
|
50
|
+
variants: { smooth: {}, linear: {} },
|
|
51
|
+
default: DEFAULT_INTERPOLATION,
|
|
52
|
+
description: "Interpolation"
|
|
53
|
+
},
|
|
54
|
+
amount: colorAmountSchema
|
|
55
|
+
};
|
|
56
|
+
var resolve = (params) => ({
|
|
57
|
+
points: params.points ?? DEFAULT_POINTS,
|
|
58
|
+
channel: params.channel ?? DEFAULT_CHANNEL,
|
|
59
|
+
interpolation: params.interpolation ?? DEFAULT_INTERPOLATION,
|
|
60
|
+
amount: params.amount ?? DEFAULT_AMOUNT
|
|
61
|
+
});
|
|
62
|
+
var validateCurvesParams = (params) => {
|
|
63
|
+
assertEffectParamsObject(params, "Curves");
|
|
64
|
+
assertOptionalFiniteNumber(params.amount, "amount");
|
|
65
|
+
validateUnitInterval(params.amount ?? DEFAULT_AMOUNT, "amount");
|
|
66
|
+
if (params.channel !== undefined && !CURVES_CHANNELS.includes(params.channel)) {
|
|
67
|
+
throw new TypeError(`"channel" must be "rgb", "red", "green" or "blue", but got ${JSON.stringify(params.channel)}`);
|
|
68
|
+
}
|
|
69
|
+
if (params.interpolation !== undefined && !CURVES_INTERPOLATIONS.includes(params.interpolation)) {
|
|
70
|
+
throw new TypeError(`"interpolation" must be "smooth" or "linear", but got ${JSON.stringify(params.interpolation)}`);
|
|
71
|
+
}
|
|
72
|
+
if (params.points === undefined)
|
|
73
|
+
return;
|
|
74
|
+
if (!Array.isArray(params.points) || params.points.length < 2 || params.points.length > MAX_POINTS) {
|
|
75
|
+
throw new TypeError(`"points" must be an array of 2 to ${MAX_POINTS} input/output pairs`);
|
|
76
|
+
}
|
|
77
|
+
for (let index = 0;index < params.points.length; index++) {
|
|
78
|
+
const point = params.points[index];
|
|
79
|
+
if (!Array.isArray(point) || point.length !== 2) {
|
|
80
|
+
throw new TypeError(`"points[${index}]" must be an [input, output] pair`);
|
|
81
|
+
}
|
|
82
|
+
assertRequiredFiniteNumber(point[0], `points[${index}][0]`);
|
|
83
|
+
assertRequiredFiniteNumber(point[1], `points[${index}][1]`);
|
|
84
|
+
validateUnitInterval(point[0], `points[${index}][0]`);
|
|
85
|
+
validateUnitInterval(point[1], `points[${index}][1]`);
|
|
86
|
+
if (index > 0 && point[0] <= params.points[index - 1][0]) {
|
|
87
|
+
throw new TypeError('"points" must have strictly increasing input values');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var VERTEX_SHADER = `#version 300 es
|
|
92
|
+
in vec2 aPos;
|
|
93
|
+
in vec2 aUv;
|
|
94
|
+
out vec2 vUv;
|
|
95
|
+
|
|
96
|
+
void main() {
|
|
97
|
+
vUv = aUv;
|
|
98
|
+
gl_Position = vec4(aPos, 0.0, 1.0);
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
var FRAGMENT_SHADER = `#version 300 es
|
|
102
|
+
precision highp float;
|
|
103
|
+
|
|
104
|
+
in vec2 vUv;
|
|
105
|
+
out vec4 fragColor;
|
|
106
|
+
|
|
107
|
+
uniform sampler2D uSource;
|
|
108
|
+
uniform highp sampler2D uCurve;
|
|
109
|
+
uniform int uChannel;
|
|
110
|
+
uniform float uAmount;
|
|
111
|
+
|
|
112
|
+
float sampleCurve(float inputValue) {
|
|
113
|
+
float position = clamp(inputValue, 0.0, 1.0) * float(${LUT_SIZE - 1});
|
|
114
|
+
int lower = int(floor(position));
|
|
115
|
+
int upper = min(lower + 1, ${LUT_SIZE - 1});
|
|
116
|
+
return mix(
|
|
117
|
+
texelFetch(uCurve, ivec2(lower, 0), 0).r,
|
|
118
|
+
texelFetch(uCurve, ivec2(upper, 0), 0).r,
|
|
119
|
+
fract(position)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void main() {
|
|
124
|
+
vec4 sourceColor = texture(uSource, vUv);
|
|
125
|
+
float alpha = sourceColor.a;
|
|
126
|
+
if (alpha <= 0.0) {
|
|
127
|
+
fragColor = vec4(0.0);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
vec3 color = sourceColor.rgb / alpha;
|
|
132
|
+
vec3 corrected = color;
|
|
133
|
+
if (uChannel == 0 || uChannel == 1) corrected.r = sampleCurve(color.r);
|
|
134
|
+
if (uChannel == 0 || uChannel == 2) corrected.g = sampleCurve(color.g);
|
|
135
|
+
if (uChannel == 0 || uChannel == 3) corrected.b = sampleCurve(color.b);
|
|
136
|
+
fragColor = vec4(mix(color, corrected, uAmount) * alpha, alpha);
|
|
137
|
+
}
|
|
138
|
+
`;
|
|
139
|
+
var compileShader = (gl, type, source) => {
|
|
140
|
+
const shader = gl.createShader(type);
|
|
141
|
+
if (!shader)
|
|
142
|
+
throw new Error("Failed to create curves shader");
|
|
143
|
+
gl.shaderSource(shader, source);
|
|
144
|
+
gl.compileShader(shader);
|
|
145
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
146
|
+
const log = gl.getShaderInfoLog(shader);
|
|
147
|
+
gl.deleteShader(shader);
|
|
148
|
+
throw new Error(`Curves shader compile failed: ${log ?? "(no log)"}`);
|
|
149
|
+
}
|
|
150
|
+
return shader;
|
|
151
|
+
};
|
|
152
|
+
var createTexture = (gl, filter) => {
|
|
153
|
+
const texture = gl.createTexture();
|
|
154
|
+
if (!texture)
|
|
155
|
+
throw new Error("Failed to create curves texture");
|
|
156
|
+
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
157
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
|
|
158
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
|
|
159
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
160
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
161
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
162
|
+
return texture;
|
|
163
|
+
};
|
|
164
|
+
var CURVES_WEBGPU_SHADER = `
|
|
165
|
+
${WEBGPU_SINGLE_PASS_VERTEX}
|
|
166
|
+
struct Params {settings: vec4f, curve: array<vec4f, 256>,}
|
|
167
|
+
@group(0) @binding(0) var source: texture_2d<f32>;
|
|
168
|
+
@group(0) @binding(1) var sourceSampler: sampler;
|
|
169
|
+
@group(0) @binding(2) var<uniform> params: Params;
|
|
170
|
+
fn sampleCurve(value: f32) -> f32 {
|
|
171
|
+
let position = clamp(value, 0.0, 1.0) * 1023.0;
|
|
172
|
+
let lower = u32(floor(position));
|
|
173
|
+
let upper = min(lower + 1u, 1023u);
|
|
174
|
+
return mix(params.curve[lower / 4u][lower % 4u], params.curve[upper / 4u][upper % 4u], fract(position));
|
|
175
|
+
}
|
|
176
|
+
@fragment fn fragment(input: VertexOutput) -> @location(0) vec4f {
|
|
177
|
+
let sampled = textureSampleLevel(source, sourceSampler, input.uv, 0);
|
|
178
|
+
if (sampled.a == 0.0) {return vec4f(0);}
|
|
179
|
+
let color = sampled.rgb / sampled.a;
|
|
180
|
+
var corrected = color;
|
|
181
|
+
let channel = params.settings.x;
|
|
182
|
+
if (channel == 0.0 || channel == 1.0) {corrected.r = sampleCurve(color.r);}
|
|
183
|
+
if (channel == 0.0 || channel == 2.0) {corrected.g = sampleCurve(color.g);}
|
|
184
|
+
if (channel == 0.0 || channel == 3.0) {corrected.b = sampleCurve(color.b);}
|
|
185
|
+
return vec4f(mix(color, corrected, params.settings.y) * sampled.a, sampled.a);
|
|
186
|
+
}
|
|
187
|
+
`;
|
|
188
|
+
var curves = createEffect({
|
|
189
|
+
type: "remotion/curves",
|
|
190
|
+
label: "curves()",
|
|
191
|
+
documentationLink: "https://www.remotion.dev/docs/effects/curves",
|
|
192
|
+
calculateKey: (params) => {
|
|
193
|
+
const { points, channel, interpolation, amount } = resolve(params);
|
|
194
|
+
return `curves-${JSON.stringify(points)}-${channel}-${interpolation}-${amount}`;
|
|
195
|
+
},
|
|
196
|
+
implementations: {
|
|
197
|
+
webgpu: Internals.createEffectImplementation({
|
|
198
|
+
setup: (target) => ({
|
|
199
|
+
...setupWebGpuSinglePass(target, "curves"),
|
|
200
|
+
cachedCurveKey: null,
|
|
201
|
+
uniformData: new Float32Array(4 + LUT_SIZE)
|
|
202
|
+
}),
|
|
203
|
+
apply: ({ source, width, height, params, state, gpuDevice }) => {
|
|
204
|
+
if (!gpuDevice)
|
|
205
|
+
throw new Error("A WebGPU device is required for the curves effect");
|
|
206
|
+
const { points, channel, interpolation, amount } = resolve(params);
|
|
207
|
+
const key = `${interpolation}-${JSON.stringify(points)}`;
|
|
208
|
+
if (state.cachedCurveKey !== key) {
|
|
209
|
+
const sample = createCurveSampler(points, interpolation);
|
|
210
|
+
for (let index = 0;index < LUT_SIZE; index++)
|
|
211
|
+
state.uniformData[4 + index] = sample(index / (LUT_SIZE - 1));
|
|
212
|
+
state.cachedCurveKey = key;
|
|
213
|
+
}
|
|
214
|
+
state.uniformData[0] = CURVES_CHANNELS.indexOf(channel);
|
|
215
|
+
state.uniformData[1] = amount;
|
|
216
|
+
applyWebGpuSinglePass({
|
|
217
|
+
state,
|
|
218
|
+
source,
|
|
219
|
+
width,
|
|
220
|
+
height,
|
|
221
|
+
device: gpuDevice,
|
|
222
|
+
shader: CURVES_WEBGPU_SHADER,
|
|
223
|
+
uniformData: state.uniformData
|
|
224
|
+
});
|
|
225
|
+
},
|
|
226
|
+
cleanup: cleanupWebGpuSinglePass
|
|
227
|
+
}),
|
|
228
|
+
webgl2: Internals.createEffectImplementation({
|
|
229
|
+
setup: (target) => {
|
|
230
|
+
const gl = target.getContext("webgl2", {
|
|
231
|
+
premultipliedAlpha: true,
|
|
232
|
+
alpha: true,
|
|
233
|
+
preserveDrawingBuffer: true
|
|
234
|
+
});
|
|
235
|
+
if (!gl)
|
|
236
|
+
throw createWebGL2ContextError("curves effect");
|
|
237
|
+
const vertexShader = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
|
|
238
|
+
const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
|
|
239
|
+
const program = gl.createProgram();
|
|
240
|
+
if (!program)
|
|
241
|
+
throw new Error("Failed to create curves shader program");
|
|
242
|
+
gl.attachShader(program, vertexShader);
|
|
243
|
+
gl.attachShader(program, fragmentShader);
|
|
244
|
+
gl.linkProgram(program);
|
|
245
|
+
gl.deleteShader(vertexShader);
|
|
246
|
+
gl.deleteShader(fragmentShader);
|
|
247
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
248
|
+
const log = gl.getProgramInfoLog(program);
|
|
249
|
+
gl.deleteProgram(program);
|
|
250
|
+
throw new Error(`Curves shader link failed: ${log ?? "(no log)"}`);
|
|
251
|
+
}
|
|
252
|
+
const vao = gl.createVertexArray();
|
|
253
|
+
if (!vao)
|
|
254
|
+
throw new Error("Failed to create curves vertex array");
|
|
255
|
+
const vbo = gl.createBuffer();
|
|
256
|
+
if (!vbo)
|
|
257
|
+
throw new Error("Failed to create curves vertex buffer");
|
|
258
|
+
gl.bindVertexArray(vao);
|
|
259
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
260
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
261
|
+
-1,
|
|
262
|
+
-1,
|
|
263
|
+
0,
|
|
264
|
+
0,
|
|
265
|
+
1,
|
|
266
|
+
-1,
|
|
267
|
+
1,
|
|
268
|
+
0,
|
|
269
|
+
-1,
|
|
270
|
+
1,
|
|
271
|
+
0,
|
|
272
|
+
1,
|
|
273
|
+
1,
|
|
274
|
+
1,
|
|
275
|
+
1,
|
|
276
|
+
1
|
|
277
|
+
]), gl.STATIC_DRAW);
|
|
278
|
+
const aPos = gl.getAttribLocation(program, "aPos");
|
|
279
|
+
const aUv = gl.getAttribLocation(program, "aUv");
|
|
280
|
+
gl.enableVertexAttribArray(aPos);
|
|
281
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
282
|
+
gl.enableVertexAttribArray(aUv);
|
|
283
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
284
|
+
gl.bindVertexArray(null);
|
|
285
|
+
return {
|
|
286
|
+
gl,
|
|
287
|
+
program,
|
|
288
|
+
vao,
|
|
289
|
+
vbo,
|
|
290
|
+
sourceTexture: createTexture(gl, gl.LINEAR),
|
|
291
|
+
curveTexture: createTexture(gl, gl.NEAREST),
|
|
292
|
+
uniforms: {
|
|
293
|
+
uSource: gl.getUniformLocation(program, "uSource"),
|
|
294
|
+
uCurve: gl.getUniformLocation(program, "uCurve"),
|
|
295
|
+
uChannel: gl.getUniformLocation(program, "uChannel"),
|
|
296
|
+
uAmount: gl.getUniformLocation(program, "uAmount")
|
|
297
|
+
},
|
|
298
|
+
cachedCurveKey: null
|
|
299
|
+
};
|
|
300
|
+
},
|
|
301
|
+
apply: ({ source, width, height, params, state, flipSourceY }) => {
|
|
302
|
+
const { points, channel, interpolation, amount } = resolve(params);
|
|
303
|
+
const { gl, program, sourceTexture, curveTexture, uniforms, vao } = state;
|
|
304
|
+
const curveKey = `${interpolation}-${JSON.stringify(points)}`;
|
|
305
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
306
|
+
gl.bindTexture(gl.TEXTURE_2D, curveTexture);
|
|
307
|
+
if (state.cachedCurveKey !== curveKey) {
|
|
308
|
+
const sample = createCurveSampler(points, interpolation);
|
|
309
|
+
const data = new Float32Array(LUT_SIZE);
|
|
310
|
+
for (let index = 0;index < LUT_SIZE; index++) {
|
|
311
|
+
data[index] = sample(index / (LUT_SIZE - 1));
|
|
312
|
+
}
|
|
313
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
|
314
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
315
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, LUT_SIZE, 1, 0, gl.RED, gl.FLOAT, data);
|
|
316
|
+
state.cachedCurveKey = curveKey;
|
|
317
|
+
}
|
|
318
|
+
gl.viewport(0, 0, width, height);
|
|
319
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
320
|
+
gl.clearColor(0, 0, 0, 0);
|
|
321
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
322
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
323
|
+
gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
|
|
324
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
325
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, flipSourceY);
|
|
326
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
327
|
+
gl.useProgram(program);
|
|
328
|
+
if (uniforms.uSource)
|
|
329
|
+
gl.uniform1i(uniforms.uSource, 0);
|
|
330
|
+
if (uniforms.uCurve)
|
|
331
|
+
gl.uniform1i(uniforms.uCurve, 1);
|
|
332
|
+
if (uniforms.uChannel)
|
|
333
|
+
gl.uniform1i(uniforms.uChannel, CURVES_CHANNELS.indexOf(channel));
|
|
334
|
+
if (uniforms.uAmount)
|
|
335
|
+
gl.uniform1f(uniforms.uAmount, amount);
|
|
336
|
+
gl.bindVertexArray(vao);
|
|
337
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
338
|
+
gl.bindVertexArray(null);
|
|
339
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
340
|
+
gl.useProgram(null);
|
|
341
|
+
},
|
|
342
|
+
cleanup: ({ gl, program, vao, vbo, sourceTexture, curveTexture }) => {
|
|
343
|
+
gl.deleteTexture(sourceTexture);
|
|
344
|
+
gl.deleteTexture(curveTexture);
|
|
345
|
+
gl.deleteBuffer(vbo);
|
|
346
|
+
gl.deleteProgram(program);
|
|
347
|
+
gl.deleteVertexArray(vao);
|
|
348
|
+
}
|
|
349
|
+
})
|
|
350
|
+
},
|
|
351
|
+
schema: curvesSchema,
|
|
352
|
+
validateParams: validateCurvesParams
|
|
353
|
+
});
|
|
354
|
+
export {
|
|
355
|
+
curves,
|
|
356
|
+
curvesSchema
|
|
357
|
+
};
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setupWebGlProjection,
|
|
3
|
+
applyWebGlProjection,
|
|
4
|
+
cleanupWebGlProjection,
|
|
5
|
+
cleanupWebGpuProjection,
|
|
6
|
+
setupWebGpuProjection,
|
|
7
|
+
applyWebGpuProjection
|
|
8
|
+
} from "./index-vp56k1gj.mjs";
|
|
9
|
+
import {
|
|
10
|
+
assertOptionalFiniteNumber,
|
|
11
|
+
validateUnitInterval
|
|
12
|
+
} from "./index-wxhvgv2s.mjs";
|
|
13
|
+
import {
|
|
14
|
+
assertEffectParamsObject
|
|
15
|
+
} from "./index-4fvp93ps.mjs";
|
|
16
|
+
|
|
17
|
+
// src/cylinder/index.ts
|
|
18
|
+
import { Internals } from "remotion";
|
|
19
|
+
|
|
20
|
+
// src/cylinder/shader.ts
|
|
21
|
+
var CYLINDER_SHADER = `
|
|
22
|
+
struct Params {
|
|
23
|
+
resolution: vec2f,
|
|
24
|
+
center: vec2f,
|
|
25
|
+
radius: f32,
|
|
26
|
+
spin: f32,
|
|
27
|
+
shading: f32,
|
|
28
|
+
faces: f32,
|
|
29
|
+
rotation: vec4f,
|
|
30
|
+
}
|
|
31
|
+
@group(0) @binding(0) var source: texture_2d<f32>;
|
|
32
|
+
@group(0) @binding(1) var sourceSampler: sampler;
|
|
33
|
+
@group(0) @binding(2) var<uniform> params: Params;
|
|
34
|
+
|
|
35
|
+
@vertex fn vertex(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
|
|
36
|
+
let positions = array<vec2f, 3>(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3));
|
|
37
|
+
return vec4f(positions[index], 0, 1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn sampleFace(point: vec3f, inverse: mat3x3f, rotation: mat3x3f) -> vec4f {
|
|
41
|
+
let local = inverse * point;
|
|
42
|
+
let uv = vec2f(fract((atan2(local.x, local.z) + params.spin) / 6.28318530718 + 0.5), local.y / params.resolution.y + 0.5);
|
|
43
|
+
let color = textureSampleLevel(source, sourceSampler, uv, 0);
|
|
44
|
+
if (uv.y < 0 || uv.y > 1) { return vec4f(0); }
|
|
45
|
+
let normal = rotation * vec3f(local.x / params.radius, 0, local.z / params.radius);
|
|
46
|
+
let shade = mix(1.0, abs(normal.z), params.shading);
|
|
47
|
+
return vec4f(color.rgb * shade, color.a);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@fragment fn fragment(@builtin(position) position: vec4f) -> @location(0) vec4f {
|
|
51
|
+
let s = sin(params.rotation.xyz);
|
|
52
|
+
let c = cos(params.rotation.xyz);
|
|
53
|
+
let rx = mat3x3f(vec3f(1, 0, 0), vec3f(0, c.x, s.x), vec3f(0, -s.x, c.x));
|
|
54
|
+
let ry = mat3x3f(vec3f(c.y, 0, -s.y), vec3f(0, 1, 0), vec3f(s.y, 0, c.y));
|
|
55
|
+
let rz = mat3x3f(vec3f(c.z, s.z, 0), vec3f(-s.z, c.z, 0), vec3f(0, 0, 1));
|
|
56
|
+
let rotation = rz * ry * rx;
|
|
57
|
+
let axis = rotation[1];
|
|
58
|
+
let p = position.xy - params.center;
|
|
59
|
+
// Orthographic viewing ray intersecting the rotated, open cylinder wall.
|
|
60
|
+
let a = 1.0 - axis.z * axis.z;
|
|
61
|
+
let da = dot(p, axis.xy);
|
|
62
|
+
let b = -da * axis.z;
|
|
63
|
+
let discriminant = b * b - a * (dot(p, p) - da * da - params.radius * params.radius);
|
|
64
|
+
if (a < 0.000001 || discriminant <= 0) { return vec4f(0); }
|
|
65
|
+
let root = sqrt(discriminant);
|
|
66
|
+
let inverse = transpose(rotation);
|
|
67
|
+
let front = sampleFace(vec3f(p, (-b + root) / a), inverse, rotation);
|
|
68
|
+
let back = sampleFace(vec3f(p, (-b - root) / a), inverse, rotation);
|
|
69
|
+
if (params.faces == 1) { return front; }
|
|
70
|
+
if (params.faces == 2) { return back; }
|
|
71
|
+
// Both the texture and output use premultiplied alpha.
|
|
72
|
+
return front + back * (1.0 - front.a);
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
// src/cylinder/webgl-shader.ts
|
|
77
|
+
var CYLINDER_WEBGL_SHADER = `#version 300 es
|
|
78
|
+
precision highp float;
|
|
79
|
+
uniform sampler2D uSource;
|
|
80
|
+
uniform vec4 uParams[3];
|
|
81
|
+
out vec4 fragColor;
|
|
82
|
+
vec4 sampleFace(vec3 point, mat3 inverseRotation, mat3 rotation) {
|
|
83
|
+
vec3 local = inverseRotation * point;
|
|
84
|
+
vec2 uv = vec2(fract((atan(local.x, local.z) + uParams[1].y) / 6.28318530718 + 0.5), local.y / uParams[0].xy.y + 0.5);
|
|
85
|
+
vec4 color = textureLod(uSource, vec2(uv.x, 1.0 - uv.y), 0.0);
|
|
86
|
+
if (uv.y < 0.0 || uv.y > 1.0) { return vec4(0); }
|
|
87
|
+
vec3 normal = rotation * vec3(local.x / uParams[1].x, 0, local.z / uParams[1].x);
|
|
88
|
+
float shade = mix(1.0, abs(normal.z), uParams[1].z);
|
|
89
|
+
return vec4(color.rgb * shade, color.a);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
vec4 project(vec2 position) {
|
|
93
|
+
vec3 s = sin(uParams[2].xyz);
|
|
94
|
+
vec3 c = cos(uParams[2].xyz);
|
|
95
|
+
mat3 rx = mat3(vec3(1, 0, 0), vec3(0, c.x, s.x), vec3(0, -s.x, c.x));
|
|
96
|
+
mat3 ry = mat3(vec3(c.y, 0, -s.y), vec3(0, 1, 0), vec3(s.y, 0, c.y));
|
|
97
|
+
mat3 rz = mat3(vec3(c.z, s.z, 0), vec3(-s.z, c.z, 0), vec3(0, 0, 1));
|
|
98
|
+
mat3 rotation = rz * ry * rx;
|
|
99
|
+
vec3 axis = rotation[1];
|
|
100
|
+
vec2 p = position - uParams[0].zw;
|
|
101
|
+
// Orthographic viewing ray intersecting the rotated, open cylinder wall.
|
|
102
|
+
float a = 1.0 - axis.z * axis.z;
|
|
103
|
+
float da = dot(p, axis.xy);
|
|
104
|
+
float b = -da * axis.z;
|
|
105
|
+
float discriminant = b * b - a * (dot(p, p) - da * da - uParams[1].x * uParams[1].x);
|
|
106
|
+
if (a < 0.000001 || discriminant <= 0.0) { return vec4(0); }
|
|
107
|
+
float root = sqrt(discriminant);
|
|
108
|
+
mat3 inverseRotation = transpose(rotation);
|
|
109
|
+
vec4 front = sampleFace(vec3(p, (-b + root) / a), inverseRotation, rotation);
|
|
110
|
+
vec4 back = sampleFace(vec3(p, (-b - root) / a), inverseRotation, rotation);
|
|
111
|
+
if (uParams[1].w == 1.0) { return front; }
|
|
112
|
+
if (uParams[1].w == 2.0) { return back; }
|
|
113
|
+
// Both the texture and output use premultiplied alpha.
|
|
114
|
+
return front + back * (1.0 - front.a);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void main() { fragColor = project(vec2(gl_FragCoord.x, uParams[0].y - gl_FragCoord.y)); }
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
// src/cylinder/index.ts
|
|
121
|
+
var DEFAULT_RADIUS = 250;
|
|
122
|
+
var DEFAULT_ROTATION = 0;
|
|
123
|
+
var DEFAULT_POSITION = [0.5, 0.5];
|
|
124
|
+
var DEFAULT_RENDER = "both";
|
|
125
|
+
var DEFAULT_SHADING = 0.35;
|
|
126
|
+
var cylinderSchema = {
|
|
127
|
+
radius: {
|
|
128
|
+
type: "number",
|
|
129
|
+
min: 1,
|
|
130
|
+
max: 1000,
|
|
131
|
+
step: 1,
|
|
132
|
+
default: DEFAULT_RADIUS,
|
|
133
|
+
description: "Radius",
|
|
134
|
+
hiddenFromList: false
|
|
135
|
+
},
|
|
136
|
+
rotation: {
|
|
137
|
+
type: "rotation-degrees",
|
|
138
|
+
default: DEFAULT_ROTATION,
|
|
139
|
+
description: "Texture rotation"
|
|
140
|
+
},
|
|
141
|
+
rotationX: {
|
|
142
|
+
type: "rotation-degrees",
|
|
143
|
+
default: DEFAULT_ROTATION,
|
|
144
|
+
description: "X rotation"
|
|
145
|
+
},
|
|
146
|
+
rotationY: {
|
|
147
|
+
type: "rotation-degrees",
|
|
148
|
+
default: DEFAULT_ROTATION,
|
|
149
|
+
description: "Y rotation"
|
|
150
|
+
},
|
|
151
|
+
rotationZ: {
|
|
152
|
+
type: "rotation-degrees",
|
|
153
|
+
default: DEFAULT_ROTATION,
|
|
154
|
+
description: "Z rotation"
|
|
155
|
+
},
|
|
156
|
+
position: {
|
|
157
|
+
type: "uv-coordinate",
|
|
158
|
+
default: DEFAULT_POSITION,
|
|
159
|
+
description: "Position"
|
|
160
|
+
},
|
|
161
|
+
render: {
|
|
162
|
+
type: "enum",
|
|
163
|
+
variants: { both: {}, front: {}, back: {} },
|
|
164
|
+
default: DEFAULT_RENDER,
|
|
165
|
+
description: "Faces"
|
|
166
|
+
},
|
|
167
|
+
shading: {
|
|
168
|
+
type: "number",
|
|
169
|
+
min: 0,
|
|
170
|
+
max: 1,
|
|
171
|
+
step: 0.01,
|
|
172
|
+
default: DEFAULT_SHADING,
|
|
173
|
+
description: "Shading",
|
|
174
|
+
hiddenFromList: false
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
var resolve = (params) => ({
|
|
178
|
+
radius: params.radius ?? DEFAULT_RADIUS,
|
|
179
|
+
rotation: params.rotation ?? DEFAULT_ROTATION,
|
|
180
|
+
rotationX: params.rotationX ?? DEFAULT_ROTATION,
|
|
181
|
+
rotationY: params.rotationY ?? DEFAULT_ROTATION,
|
|
182
|
+
rotationZ: params.rotationZ ?? DEFAULT_ROTATION,
|
|
183
|
+
position: params.position ?? DEFAULT_POSITION,
|
|
184
|
+
render: params.render ?? DEFAULT_RENDER,
|
|
185
|
+
shading: params.shading ?? DEFAULT_SHADING
|
|
186
|
+
});
|
|
187
|
+
var getUniformData = (params, width, height) => {
|
|
188
|
+
const r = resolve(params);
|
|
189
|
+
const radians = Math.PI / 180;
|
|
190
|
+
return new Float32Array([
|
|
191
|
+
width,
|
|
192
|
+
height,
|
|
193
|
+
r.position[0] * width,
|
|
194
|
+
r.position[1] * height,
|
|
195
|
+
r.radius,
|
|
196
|
+
r.rotation % 360 * radians,
|
|
197
|
+
r.shading,
|
|
198
|
+
r.render === "front" ? 1 : r.render === "back" ? 2 : 0,
|
|
199
|
+
r.rotationX % 360 * radians,
|
|
200
|
+
r.rotationY % 360 * radians,
|
|
201
|
+
r.rotationZ % 360 * radians,
|
|
202
|
+
0
|
|
203
|
+
]);
|
|
204
|
+
};
|
|
205
|
+
var cylinder = Internals.createEffect({
|
|
206
|
+
type: "remotion/cylinder",
|
|
207
|
+
label: "cylinder()",
|
|
208
|
+
documentationLink: "https://www.remotion.dev/docs/effects/cylinder",
|
|
209
|
+
schema: cylinderSchema,
|
|
210
|
+
validateParams: (params) => {
|
|
211
|
+
assertEffectParamsObject(params, "Cylinder");
|
|
212
|
+
for (const key of [
|
|
213
|
+
"radius",
|
|
214
|
+
"rotation",
|
|
215
|
+
"rotationX",
|
|
216
|
+
"rotationY",
|
|
217
|
+
"rotationZ",
|
|
218
|
+
"shading"
|
|
219
|
+
]) {
|
|
220
|
+
assertOptionalFiniteNumber(params[key], key);
|
|
221
|
+
}
|
|
222
|
+
const r = resolve(params);
|
|
223
|
+
if (r.radius <= 0) {
|
|
224
|
+
throw new TypeError('"radius" must be greater than 0');
|
|
225
|
+
}
|
|
226
|
+
validateUnitInterval(r.shading, "shading");
|
|
227
|
+
if (params.position !== undefined && (!Array.isArray(params.position) || params.position.length !== 2 || !Number.isFinite(params.position[0]) || !Number.isFinite(params.position[1]))) {
|
|
228
|
+
throw new TypeError('"position" must contain two finite numbers');
|
|
229
|
+
}
|
|
230
|
+
if (params.render !== undefined && params.render !== "both" && params.render !== "front" && params.render !== "back") {
|
|
231
|
+
throw new TypeError('"render" must be "both", "front", or "back"');
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
calculateKey: (params) => {
|
|
235
|
+
const r = resolve(params);
|
|
236
|
+
return `cylinder-${r.radius}-${r.rotation}-${r.rotationX}-${r.rotationY}-${r.rotationZ}-${r.position.join(",")}-${r.render}-${r.shading}`;
|
|
237
|
+
},
|
|
238
|
+
implementations: {
|
|
239
|
+
webgpu: Internals.createEffectImplementation({
|
|
240
|
+
setup: (target) => setupWebGpuProjection(target, "cylinder"),
|
|
241
|
+
apply: ({ source, width, height, params, state, gpuDevice }) => {
|
|
242
|
+
if (!gpuDevice) {
|
|
243
|
+
throw new Error("A WebGPU device is required for the cylinder effect");
|
|
244
|
+
}
|
|
245
|
+
applyWebGpuProjection({
|
|
246
|
+
source,
|
|
247
|
+
width,
|
|
248
|
+
height,
|
|
249
|
+
state,
|
|
250
|
+
device: gpuDevice,
|
|
251
|
+
shader: CYLINDER_SHADER,
|
|
252
|
+
uniformData: getUniformData(params, width, height)
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
cleanup: cleanupWebGpuProjection
|
|
256
|
+
}),
|
|
257
|
+
webgl2: Internals.createEffectImplementation({
|
|
258
|
+
setup: (target) => setupWebGlProjection(target, CYLINDER_WEBGL_SHADER),
|
|
259
|
+
apply: ({ source, width, height, params, state, flipSourceY }) => applyWebGlProjection({
|
|
260
|
+
source,
|
|
261
|
+
width,
|
|
262
|
+
height,
|
|
263
|
+
state,
|
|
264
|
+
flipSourceY,
|
|
265
|
+
uniformData: getUniformData(params, width, height)
|
|
266
|
+
}),
|
|
267
|
+
cleanup: cleanupWebGlProjection
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
export {
|
|
272
|
+
cylinder
|
|
273
|
+
};
|