Some particulars on the setup – I am utilizing React Native with Expo (SDK 51) and I am constructing an app that has a picture filter/editor sort element on one of many pages.
I ended up utilizing gl-react
and gl-react-expo
to use some filters to the photographs after which use captureRef
to avoid wasting the edited photographs. The issue is available in once I need to use LUTs – this was (or at the least appeared like) the best choice to simply switch any photograph edits I’ve made right into a filter. I opted to make use of sq. LUT png textures, began with smaller ones nevertheless it launched banding, so I went for 4096x4096
textures, and it seems fantastic.
Firstly, it takes ages to load every one of many filters (I nonetheless have not tried out the app exterior of Metro in a standalone construct), and when the filter does load, it takes up an extra 150-250MB of RAM for every filter loaded within the efficiency inspector. I am genuinely unsure why this is able to be occurring, when the LUT photos are 10-12MB at most. When clicking by way of all the filters the RAM utilization simply goes up, going from 300MB to 3-4GB! This goes again to regular when leaving the web page.
The biggest of the filter textures is not more than 11-12 MB, and I’ve all of them in a map able to map over within the listing the place the person chooses filters, like this:
export const FILTERS = {
regular: {
key: 'regular',
sort: 'lut',
title: 'Regular',
displayName: <LUTPreview color1="#FFFFFF" color2="#FFFFFF" title="Regular" />,
shader: lutShader,
uniforms: {
lut: require('../belongings/luts/impartial.png'),
t: { uri: '' },
depth: 1,
},
},
'blackwhite-fade': {
key: 'blackwhite-fade',
sort: 'lut',
title: 'B&W Fade',
displayName: (
<LUTPreview color1="#FFFFFF" color2="#222222" title="B&W Fade" />
),
shader: lutShader,
uniforms: {
lut: require('../belongings/luts/blackwhite-fade.png'),
t: { uri: '' },
depth: 1,
},
},
... remainder of the filters
Then within the ImageEditor element I load up the filter and shader, cross within the t
prop of the uniforms for the picture being edited:
{*/ Shortened for simply the half the place I present the picture /*}
<Floor
model={{
width: imageDimensions.width,
peak: imageDimensions.peak,
}}
>
{selectedFilterObj && (
<ImageFilter
key={selectedFilterObj.key}
shader={selectedFilterObj.shader}
uniforms={{
...selectedFilterObj.uniforms,
depth: filterIntensity,
}}
/>
)}
</Floor>
The ImageFilter is only a Node
from gl-react
:
const ImageFilter = ({ uniforms, shader }: ImageFilterProps<UniformsType>) => {
return (
<Node
shader={shader}
uniforms={{
...uniforms,
}}
/>
);
};
I will embrace the shader as properly, together with a pattern LUT picture:
Shader
import { GLSL } from 'gl-react';
const lutShader = {
frag: GLSL`
precision mediump float;
various vec2 uv;
uniform sampler2D t;
uniform sampler2D lut;
uniform float depth;
vec4 applyLUT(vec4 src_color) {
const vec2 tiles = vec2(16.0);
const float tileSize = 256.0;
float b = clamp(src_color.b * 255.0, 0.0, 255.0);
float b_i = ground(b);
// Calculate tile indices extra effectively
vec2 tileIndex;
tileIndex.y = ground(b_i * 0.0625); // Precalculated 1/16
tileIndex.x = mod(b_i, 16.0);
// Simplified UV calculation
vec2 pixelPos = src_color.rg * (tileSize - 1.0) + 0.5;
vec2 uv1 = (tileIndex * tileSize + pixelPos) * 0.000244140625; // Precalculated 1/4096
vec3 lutColor = texture2D(lut, uv1).rgb;
return vec4(lutColor, 1.0);
}
void essential() {
vec4 shade = texture2D(t, uv);
vec4 lutColor = applyLUT(shade);
gl_FragColor = combine(shade, lutColor, depth);
}
`,
};
export default lutShader;
Pattern LUT – Notice needed to compress into JPEG to submit right here
I attempted to vary the tactic to make use of Skia, nevertheless it wasn’t working properly and it wasn’t even a lot quicker. I consider I additionally tried preloading the belongings with expo-asset
which simply stored the app loading for a very long time, and did not assist in any respect.