Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebXR hybrid renderer #216

Open
munrocket opened this issue Apr 17, 2024 · 2 comments
Open

WebXR hybrid renderer #216

munrocket opened this issue Apr 17, 2024 · 2 comments

Comments

@munrocket
Copy link

Any chances that WebXR will be implemented? Can be a cool 3js alternative for simple UI.

@CodyJasonBennett
Copy link
Contributor

Here's a WebXR example based on https://twitter.com/Cody_J_Bennett/status/1558040614352158722.

image

Show code:
import { Renderer, Camera, Geometry, Program, Mesh } from 'ogl'

const renderer = new Renderer()
const gl = renderer.gl
document.body.appendChild(gl.canvas)

const camera = new Camera(gl, { fov: 50 })
camera.position.z = 5

const geometry = new Geometry(gl, {
  position: {
    size: 3,
    data: new Float32Array([
      0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5,
      -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
      -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5,
      0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
    ]),
  },
  normal: {
    size: 3,
    data: new Float32Array([
      1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
      -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    ]),
  },
  uv: {
    size: 2,
    data: new Float32Array([
      0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0,
      1, 0, 0, 1, 1, 1, 0, 0, 1, 0,
    ]),
  },
  index: {
    size: 1,
    data: new Uint16Array([
      0, 2, 1, 2, 3, 1, 4, 6, 5, 6, 7, 5, 8, 10, 9, 10, 11, 9, 12, 14, 13, 14, 15, 13, 16, 18, 17, 18, 19, 17, 20, 22,
      21, 22, 23, 21,
    ]),
  },
})
const program = new Program(gl, {
  uniforms: {
    color: { value: [1, 0.4, 0.7] },
  },
  vertex: /* glsl */ `#version 300 es
    uniform mat3 normalMatrix;
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;

    in vec3 position;
    in vec3 normal;
    out vec3 vNormal;

    void main() {
      vNormal = normalMatrix * normal;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1);
    }
  `,
  fragment: /* glsl */ `#version 300 es
    precision lowp float;

    uniform vec3 color;
    in vec3 vNormal;
    out vec4 fColor;

    void main() {
      float lighting = dot(vNormal, normalize(vec3(10)));
      fColor = vec4(color + lighting * 0.1, 1);
    }
  `,
})
const cube = new Mesh(gl, { geometry, program })

function onResize() {
  renderer.setSize(window.innerWidth, window.innerHeight)
  camera.perspective({ fov: 50, aspect: window.innerWidth / window.innerHeight })
}
onResize()
window.addEventListener('resize', onResize)

renderer.autoClear = false

const button = document.createElement('button')
button.textContent = 'Enter VR'
document.body.appendChild(button)

let session = null
let referenceSpace = null
let baseLayer = null

function render(time, frame) {
  session ? session.requestAnimationFrame(render) : window.requestAnimationFrame(render)

  if (frame) {
    gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer)
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)

    const pose = frame.getViewerPose(referenceSpace)
    for (const view of pose.views) {
      const viewport = baseLayer.getViewport(view)
      renderer.setViewport(viewport.width, viewport.height, viewport.x, viewport.y)

      camera.matrix.set(...view.transform.matrix)
      camera.worldMatrixNeedsUpdate = true
      camera.projectionMatrix.set(...view.projectionMatrix)
      camera.updateMatrixWorld()

      renderer.render({ scene: cube, camera })
    }
  } else {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
    renderer.render({ scene: cube, camera })
  }
}
requestAnimationFrame(render)

await gl.makeXRCompatible()

button.onclick = async () => {
  await navigator.xr.isSessionSupported('immersive-vr')
  session = await navigator.xr.requestSession('immersive-vr', {
    optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking'],
  })

  baseLayer = new XRWebGLLayer(session, gl)
  session.updateRenderState({ baseLayer })

  referenceSpace = await session.requestReferenceSpace('local-floor')

  camera.matrixAutoUpdate = false
}

@munrocket
Copy link
Author

@CodyJasonBennett nice. Waiting in four examples!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants