I’ve gotten it successfully working with this code:
import * as ecs from '@8thwall/ecs'
ecs.registerComponent({
name: 'Camera Shaders',
schema: {
},
schemaDefaults: {
},
data: {
},
stateMachine: ({world, eid}) => {
ecs.defineState('default')
.initial()
.onEnter(() => {
window.addEventListener('xrloaded', (e) => {
const {XR8} = window as any
const fragmentShaders = [ // Define some simple shaders to apply to the camera feed.
` precision mediump float; // Just the camera feed.
varying vec2 texUv;
uniform sampler2D sampler;
void main() { gl_FragColor = texture2D(sampler, texUv); }`,
` precision mediump float; // Color boost.
varying vec2 texUv;
uniform sampler2D sampler;
void main() {
vec4 c = texture2D(sampler, texUv);
float y = dot(c.rgb, vec3(0.299, 0.587, 0.114));
float u = dot(c.rgb, vec3(-.159, -.331, .5)) * 6.0;
float v = dot(c.rgb, vec3(.5, -.419, -.081)) * 3.0;
gl_FragColor = vec4(y + 1.4 * v, y - .343 * u - .711 * v, y + 1.765 * u, c.a);
}`,
` precision mediump float; // Vignette.
varying vec2 texUv;
uniform sampler2D sampler;
void main() {
float x = texUv.x - .5;
float y = texUv.y - .5;
float v = 1.5 - sqrt(x * x + y * y) * 2.5;
vec4 c = texture2D(sampler, texUv);
gl_FragColor = vec4(c.rgb * (v > 1.0 ? 1.0 : v), c.a);
}`,
` precision mediump float; // Black and white.
varying vec2 texUv;
uniform sampler2D sampler;
void main() {
vec4 c = texture2D(sampler, texUv);
gl_FragColor = vec4(vec3(dot(c.rgb, vec3(0.299, 0.587, 0.114))), c.a);
}`,
` precision mediump float; // Sepia.
varying vec2 texUv;
uniform sampler2D sampler;
void main() {
vec4 c = texture2D(sampler, texUv);
gl_FragColor.r = dot(c.rgb, vec3(.393, .769, .189));
gl_FragColor.g = dot(c.rgb, vec3(.349, .686, .168));
gl_FragColor.b = dot(c.rgb, vec3(.272, .534, .131));
gl_FragColor.a = c.a;
}`,
` precision mediump float; // Purple.
varying vec2 texUv;
uniform sampler2D sampler;
void main() {
vec4 c = texture2D(sampler, texUv);
float y = dot(c.rgb, vec3(0.299, 0.587, 0.114));
vec3 p = vec3(.463, .067, .712);
vec3 rgb = y < .25 ? (y * 4.0) * p : ((y - .25) * 1.333) * (vec3(1.0, 1.0, 1.0) - p) + p;
gl_FragColor = vec4(rgb, c.a);
}`,
` precision mediump float; // Shader with time variable
uniform float time;
varying vec2 texUv;
uniform sampler2D sampler;
void main( void ) {
vec2 position = texUv;
float color = 0.0;
color += sin( position.x * cos( time / 15.0 ) * 80.0 ) + cos( position.y * cos( time / 15.0 ) * 10.0 );
color += sin( position.y * sin( time / 10.0 ) * 40.0 ) + cos( position.x * sin( time / 25.0 ) * 40.0 );
color += sin( position.x * sin( time / 5.0 ) * 10.0 ) + sin( position.y * sin( time / 35.0 ) * 80.0 );
color *= sin( time / 10.0 ) * 0.5;
gl_FragColor = texture2D(sampler, texUv) + vec4( vec3( color, color * 0.5, sin( color + time / 3.0 ) * 0.75 ), 1.0 );
}`,
]
const vertexShaders = [ // Vertex shaders for swapping whether or not drawing is mirrored.
` attribute vec3 position; // Normal drawing
attribute vec2 uv;
varying vec2 texUv;
void main() {
gl_Position = vec4(position, 1.0);
texUv = uv;
}`,
` attribute vec3 position; // Mirrored drawing
attribute vec2 uv;
varying vec2 texUv;
void main() {
gl_Position = vec4(position, 1.0);
texUv = vec2(1.0 - uv.x, uv.y);
}`,
]
let uniforms = 1.0
XR8.addCameraPipelineModule({
name: 'Custom Shaders',
onStart: ({canvasWidth, canvasHeight}) => {
console.log('started')
XR8.GlTextureRenderer.configure({fragmentSource: fragmentShaders[1]})
},
onUpdate: ({frameStartResult, processGpuResult}) => {
if (processGpuResult.gltexturerenderer) {
const {shader} = processGpuResult.gltexturerenderer
const {GLctx} = frameStartResult
const timeLoc = GLctx.getUniformLocation(shader, 'time')
if (timeLoc) {
const p = XR8.GlTextureRenderer.getGLctxParameters(GLctx)
GLctx.useProgram(shader)
GLctx.uniform1f(timeLoc, uniforms)
XR8.GlTextureRenderer.setGLctxParameters(GLctx, p)
uniforms += 0.1
}
}
},
})
})
})
},
add: (world, component) => {
},
tick: (world, component) => {
},
remove: (world, component) => {
},
})
This is a component that I’ve attached to the camera in my scene. As you can see from the screenshot it using the second shader in the list, as the first shader is just the normal camera feed.