1. Concept of off-screen rendering:

Those of you who have used three.js are familiar with WebGLRenderer, the WebGLRender that renders your colorful 3d entities into the scene. WebGLRenderTarget is a buffer that stores render data and is usually used for post-processing before rendering to the screen.

2. Application of off-screen rendering in this paper:

In this paper, we will apply the off-screen rendering technology to output the scene rendered by WebGL in real time into a static picture, which can be downloaded locally. Project source code address: github.com/liyang00770…

3. Core code analysis:

A, first build a basic scene in initThree, load the model of F16 fighter and sky box, use perspective camera and bind track controller, at the same time add two lights on the camera, make F16 fighter highlight reflection effect. I recommend reading other basic articles…) . Drag the screen to see the model in full view. In the main requestAnimationFrame, the Renderer renders the model to the screen in real time, as shown below

function animate() {
    requestAnimationFrame( animate );
    controls.update();
    renderer.render( scene, camera );      
}
animate();
Copy the code

B, main character entrance: off-screen rendering! Our current appeal is that we can get the rendering data in webGL scene and output it as a PNG image to achieve the effect similar to screenshot. But because we are directly take the rendering data, so there is no web screenshot that will lose the definition of the problem, 100% copy rendering scene! Without further ado, let’s get right to the code.

1. Create a WebGLRenderTarget. The off-screen rendered pixel data will be stored in this buffer area

let rt = new THREE.WebGLRenderTarget(el.clientWidth * 4, el.clientHeight * 4, {  encoding: THREE.sRGBEncoding})
Copy the code

2. Do an anti-aliasing treatment before rendering.

const renderPass = new RenderPass( scene, camera ); const pixelRatio = renderer.getPixelRatio(); const pass = new SMAAPass( el.clientWidth * pixelRatio, el.clientHeight * pixelRatio ); fxaaPass.material.uniforms[ 'resolution' ].value.x = 1 / ( el.offsetWidth * pixelRatio ); fxaaPass.material.uniforms[ 'resolution' ].value.y = 1 / ( el.offsetHeight * pixelRatio ); composer1 = new EffectComposer( renderer, rt ); composer1.addPass( renderPass ); composer1.addPass( pass ); composer1.renderToScreen = falsecomposer1.render()Copy the code

3. Create a Canvas canvas dynamically and render data cached in WebGLRenderTarget onto the canvas. Then you can output base64 image data using Canvas toDataURL() or canvas.toblob (). Use the file-Saver library to download the image locally

const canvas2d = document.createElement('canvas') document.body.appendChild(canvas2d); const width = el.clientWidth * 4 const height = el.clientHeight * 4 const preview = canvas2d; preview.width = width preview.height = height const ctx = preview.getContext('2d'); const buffer = new Uint8Array(width * height * 4); const clamped = new Uint8ClampedArray(buffer.buffer); const reversed = [] composer1.renderer.readRenderTargetPixels(rt, 0, 0, width, height, buffer); Const imageData = new imageData (Clamped, width, height); PutImageData (imageData, 0, 0); For (let I = height-1; i >= 0; i--) { reversed.push(... clamped.slice(width * 4 * i, width * 4 * (i + 1))) } const imageDataFliped = new ImageData(new Uint8ClampedArray(reversed), width, height) ctx.putImageData(imageDataFliped, 0, 0); this.base64 = preview.toDataURL(); if (type === 'download') { canvas2d.toBlob((blob) => { FileSaver.saveAs(blob, 'pretty image.png') }) } document.body.removeChild(canvas2d);Copy the code

The end result is the cover image.

4. Conclusion:

This paper introduces a webGL off-screen rendering mechanism to achieve the effect of webGL screen capture output picture data and save the picture. This can be used in some scenarios where DOM and WebGL interact.

5. Advertising:

Bytedance VR team is in hot recruitment, and its current business covers VR house viewing, decoration and other scenes.

Business scenes cover VR shooting, house modeling, cross-terminal VR display and the whole process.

It is being rapidly commercialized. Welcome all talents and students who are interested in VR&webgl to join our team.

Personal email: [email protected], Wechat liyang920308