How do you render to an R8UI, RedIntegerFormat, UnsignedByteType WebGLRenderTarget?

Viewed 271

I'm trying to render to a single component 8 bit render target in three.js but I'm getting a number of errors I'm not sure how to solve and searching doesn't seem to come up with a lot of other hits. The WebGLRenderTarget is created with the following parameters:

format: THREE.RedIntegerFormat,
type: THREE.UnsignedByteType,
internalFormat: 'R8UI',
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,

When rendering to the render target and then trying to copy it to the screen I get the following WebGL errors:

GL_INVALID_OPERATION: No defined conversion between clear value and attachment format.
GL_INVALID_OPERATION: Fragment shader output type does not match the bound framebuffer attachment type.
GL_INVALID_OPERATION: Mismatch between texture format and sampler type (signed/unsigned/float/shadow).

Here's a repro case for the issue I'm seeing:

<script type="module">
import * as THREE from 'https://cdn.skypack.dev/three'
import { FullScreenQuad } from 'https://cdn.skypack.dev/three/examples/jsm/postprocessing/Pass.js'

let camera, scene, renderer;
let geometry, material, mesh;
let renderTarget, fsQuad;

class FinalMaterial extends THREE.ShaderMaterial {

  constructor() {
  
    super( {

      uniforms: {

        map: { value: null }

      },

      vertexShader: /* glsl */`

        varying vec2 vUv;

        void main() {

          vUv = uv;
          gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

        }`,

      fragmentShader: /* glsl */`

        uniform sampler2D map;

        varying vec2 vUv;

        void main() {

          vec4 texel = texture2D( map, vUv );
          gl_FragColor = texel;

        }`

    } );

  }

}

init();

function init() {

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
    camera.position.z = 1;

    scene = new THREE.Scene();

    geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
    material = new THREE.MeshNormalMaterial();

    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.setAnimationLoop( animation );
    document.body.appendChild( renderer.domElement );
    
    renderTarget = new THREE.WebGLRenderTarget(
        window.innerWidth,
      window.innerHeight,
      {
        format: THREE.RedIntegerFormat,
        type: THREE.UnsignedByteType,
        internalFormat: 'R8UI',
        minFilter: THREE.NearestFilter,
        magFilter: THREE.NearestFilter,
        }
    );
    
    renderTarget.texture.internalFormat = 'R8UI';
    
    fsQuad = new FullScreenQuad( new FinalMaterial() );
    fsQuad.material.uniforms.map.value = renderTarget.texture;

}

function animation( time ) {

    mesh.rotation.x = time / 2000;
    mesh.rotation.y = time / 1000;

    renderer.setRenderTarget( renderTarget );
    renderer.render( scene, camera );
    
    renderer.setRenderTarget( null );
    fsQuad.render( renderer );

}
</script>

0 Answers
Related