Shaders

Runtime SkSL shaders and uniforms.

Shader.tsx
1import { Canvas, Fill, Shader } from 'react-native-tgfx'
2const rings = `uniform float2 uSize;
3uniform float uRings;
4half4 main(float2 pos) {
5 float2 uv = pos / uSize;
6 float k = 0.8 + 0.2 * cos(length(uv - 0.5) * uRings);
7 return half4(half3(uv.x, uv.y * 0.5, 0.9) * k, 1.0);
8}`
9
10<Canvas style={{ width: 402, height: 600 }}>
11 <Fill>
12 <Shader source={rings} uniforms={{
13 uRings: ,
14 uSize: [402, 600],
15 }} />
16 </Fill>
17</Canvas>
9:41

Shader runs tgfx's SkSL subset (ShaderProps). main gets local coordinates and returns premultiplied half4.

import { Canvas, Fill, Shader } from 'react-native-tgfx'

const source = `
uniform float2 uSize;
half4 main(float2 pos) {
  float2 uv = pos / uSize;
  return half4(uv.x, uv.y, 0.6, 1.0);
}
`

<Canvas style={{ width: 300, height: 140 }}>
  <Fill>
    <Shader source={source} uniforms={{ uSize: [300, 140] }} />
  </Fill>
</Canvas>

Declarations must come before main().

Animated uniforms

Uniforms accept a SharedValue. useClock counts seconds.

const t = useClock()

<Fill>
  <Shader source={source} uniforms={{ uTime: t, uSize: [width, height] }} />
</Fill>

Shader inputs

One shader child per uniform shader, in order.

const source = `
uniform shader img;
uniform float uShift;

half4 main(float2 pos) {
  half4 base = img.eval(pos);
  half4 red = img.eval(pos + float2(uShift, 0.0));
  half4 blue = sample(img, pos - float2(uShift, 0.0));
  return half4(red.r, base.g, blue.b, base.a);
}
`

<Shader source={source} uniforms={{ uShift: 4 }}>
  <ImageShader image={image} fit="cover" rect={{ x: 0, y: 0, width: 300, height: 200 }} />
</Shader>

Inputs can be any shader:

<Shader source={banded}>
  <LinearGradient start={{ x: 0, y: 0 }} end={{ x: 300, y: 0 }} colors={['#2b6cff', '#ff3b6b']} />
</Shader>

A count mismatch throws:

[tgfx] shader: the source declares 1 'uniform shader' (img) but 0 shader children
were given - pass one shader child per declaration, in order

On this page