Experimenting with fragment shaders for WebXR - work in progress, but feedback always welcome.
Try it: https://matthewarcus.github.io/xrshader
Main repository: https://github.com/matthewarcus/xrshader
WebXR is an emerging W3C standard that allows use of Virtual and Augmented Reality technology from within web browsers.
This project is an experiment in using Shadertoy-style fragment shaders to generate WebXR images.
The code is modelled on the examples to be found at the Immersive Web website, so if those examples don’t work for you, it’s likely that the code here won’t work either. Also, I can’t pretend to understand everything in the standard, so the code may contain misconceptions or errors - I’m very happy to have any issues pointed out.
Clone the repo to somewhere that is visible to a webserver. I use nginx and the
top level directory is /var/www/html/xrshader
.
To work, WebXR must be served with https - otherwise you will see “WebXR not supported” messages,
so for testing with nginx, enable https and use the self signed certs
generated by the ssl-cert
package (don’t use them in a production server!).
Tested with Chrome on Samsung A5 phone (Android 8.0, Chrome 87.0), and with Firefox and Chrome with WebXR API emulator. Find the WebXR emulator for either Firefox or Chrome in the Add-on store - it’s the same for both.
If you need it, the source is at https://github.com/MozillaReality/, but the Store version is up to date (as of Jan 2021), including for example AR support.
Get developer tools up with F12 and set a suitable emulated device - note that you can either use an AR device (eg. Samsung Galaxy S8+ (AR)) or a VR device (currently all the other devices), no device supports both simultaneously.
(0,0,1,0)
, ie. infinitely far away in
the positive z direction. To get a real viewer position, apply the
inverse of the projection matrix combined with the view matrix (which
defines how the user is positioned in the reference frame).
mat4.mul(transformMatrix,projectionMatrix,viewMatrix);
mat4.invert(transformMatrix,transformMatrix);
gl.uniformMatrix4fv(gl.getUniformLocation(program, "transformMatrix"), false, transformMatrix);
vec3 drdx = dFdx(r);
vec3 drdy = dFdy(r);
float k = dot(r,rcentre);
float aa = float(k > 0.96 ? 3 : k > 0.9 ? 2 : 1);
for (float i = 0.0; i < aa; i++) {
for (float j = 0.0; j < aa; j++) {
if (scene(p,normalize(r+i/aa*drdx+j/aa*drdy),col1)) {
color += col1;
}
}
}
(0,0,-1.0)
, ie. infinitely far away in the negative z direction, to
map that to a viewer relative direction, apply the inverse of the view
matrix (so the result is still a projective point at infinity):
vec3 rcentre = (inverse(iView)*vec4(0,0,-1,0)).xyz;
To be continued…