Skip to content

Commit

Permalink
MRT Support (mrdoob#16390)
Browse files Browse the repository at this point in the history
* MRT Support

* Add MRT example

* Rename AttachnemtsNum to NumAttachments

* Reflect the review comments to webgl2_mrt.html

* Define texture parameter via WebGLMultiRenderTarget constructor in MRT example

* Minor clean up

* Fix setupFrameBufferTextre(). Use texture.format/type instead of renderTarget.texture's

* Use module in MRT example

* Replace var with let or const

* Replace ShaderMaterial with RawShaderMaterial for MRT example

* Fix formatting

* Fix for lint

* Add MRT example screenshot

* Reflect the review comments for WebGLMultiRenderTarget

* Rename .textures to .texture in WebGLMultiRenderTarget

* WebGLMultiRenderTarget: Remove setCount()

* WebGLMultiRenderTarget: Method chain

* WebGLMultiRenderTarget: More proper setTexture() and copy()

* WebGLCapabilities: Use extensions.has() instead of .get()

* WebGLMultiRenderTarget: Remove setTexture()

* Rename WebGLMultiRenderTarget to WebGLMultipleRenderTargets
  • Loading branch information
takahirox authored May 6, 2021
1 parent d9e8971 commit 2510609
Show file tree
Hide file tree
Showing 9 changed files with 523 additions and 22 deletions.
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@
"webgl2_materials_texture2darray",
"webgl2_materials_texture3d",
"webgl2_materials_texture3d_partialupdate",
"webgl2_mrt",
"webgl2_multisampled_renderbuffers",
"webgl2_rendertarget_texture2darray",
"webgl2_volume_cloud",
Expand Down
Binary file added examples/screenshots/webgl2_mrt.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
277 changes: 277 additions & 0 deletions examples/webgl2_mrt.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - Multiple Render Targets</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #000;
color: #fff;
margin: 0px;
overflow: hidden;
}
#info {
color: #fff;
position: absolute;
top: 10px;
width: 100%;
text-align: center;
display:block;
}
#info a, .button { color: #f00; font-weight: bold; text-decoration: underline; cursor: pointer }
</style>

<!-- Write to G-Buffer -->
<script id="gbuffer-vert" type="x-shader/x-vertex">
in vec3 position;
in vec3 normal;
in vec2 uv;

out vec3 vNormal;
out vec2 vUv;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat3 normalMatrix;

void main() {

vUv = uv;

// get smooth normals
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );

vec3 transformedNormal = normalMatrix * normal;
vNormal = normalize( transformedNormal );

gl_Position = projectionMatrix * mvPosition;

}
</script>
<script id="gbuffer-frag" type="x-shader/x-fragment">
precision highp float;
precision highp int;

layout(location = 0) out vec4 gColor;
layout(location = 1) out vec4 gNormal;

uniform sampler2D tDiffuse;
uniform vec2 repeat;

in vec3 vNormal;
in vec2 vUv;

void main() {

// write color to G-Buffer
gColor = texture( tDiffuse, vUv * repeat );

// write normals to G-Buffer
gNormal = vec4( normalize( vNormal ), 0.0 );

}
</script>

<!-- Read G-Buffer and render to screen -->
<script id="render-vert" type="x-shader/x-vertex">
in vec3 position;
in vec2 uv;

out vec2 vUv;

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;

void main() {

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

}
</script>
<script id="render-frag" type="x-shader/x-fragment">
precision highp float;
precision highp int;

layout(location = 0) out vec4 pc_FragColor;

in vec2 vUv;

uniform sampler2D tDiffuse;
uniform sampler2D tNormal;

void main() {

vec3 diffuse = texture( tDiffuse, vUv ).rgb;
vec3 normal = texture( tNormal, vUv ).rgb;

pc_FragColor.rgb = mix( diffuse, normal, step( 0.5, vUv.x ) );
pc_FragColor.a = 1.0;

}
</script>

</head>
<body>
<div id="info">
<a href="http://threejs.org" target="_blank">threejs</a> - WebGL - Multiple Render Targets<br/>
Renders geometry into a G-Buffer.<br/>
Visualized here is the color and normal data from the G-Buffer.<br/>
Created by <a href="http://twitter.com/mattdesl" target="_blank">@mattdesl</a>.
</div>

<script type="module">

import * as THREE from '../build/three.module.js';

import { WEBGL } from './jsm/WebGL.js';
import { OrbitControls } from './jsm/controls/OrbitControls.js';

let container;
let camera, scene, renderer, controls;
let renderTarget;
let postScene, postCamera;

init();

function init() {

if ( WEBGL.isWebGL2Available() === false ) {

document.body.appendChild( WEBGL.getWebGL2ErrorMessage() );
return;

}

container = document.createElement( 'div' );
document.body.appendChild( container );

const canvas = document.createElement( 'canvas' );
const context = canvas.getContext( 'webgl2' );

renderer = new THREE.WebGLRenderer( {
canvas: canvas,
context: context
} );

renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );

// Create a multi render target with Float buffers

renderTarget = new THREE.WebGLMultipleRenderTargets(
window.innerWidth * window.devicePixelRatio,
window.innerHeight * window.devicePixelRatio,
2
);

for ( let i = 0, il = renderTarget.texture.length; i < il; i ++ ) {

renderTarget.texture[ i ].minFilter = THREE.NearestFilter;
renderTarget.texture[ i ].magFilter = THREE.NearestFilter;
renderTarget.texture[ i ].type = THREE.FloatType;

}

// Name our G-Buffer attachments for debugging

renderTarget.texture[ 0 ].name = 'diffuse';
renderTarget.texture[ 1 ].name = 'normal';

// Scene setup

scene = new THREE.Scene();

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

const diffuse = new THREE.TextureLoader().load(

'textures/brick_diffuse.jpg',

function () {

// ready to render
render();

}

);

diffuse.wrapS = diffuse.wrapT = THREE.RepeatWrapping;

scene.add( new THREE.Mesh(
new THREE.TorusKnotGeometry( 1, 0.3, 128, 64 ),
new THREE.RawShaderMaterial( {
vertexShader: document.querySelector( '#gbuffer-vert' ).textContent.trim(),
fragmentShader: document.querySelector( '#gbuffer-frag' ).textContent.trim(),
uniforms: {
tDiffuse: { value: diffuse },
repeat: { value: new THREE.Vector2( 5, 0.5 ) }
},
glslVersion: THREE.GLSL3
} )
) );

// PostProcessing setup

postScene = new THREE.Scene();
postCamera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );

postScene.add( new THREE.Mesh(
new THREE.PlaneGeometry( 2, 2 ),
new THREE.RawShaderMaterial( {
vertexShader: document.querySelector( '#render-vert' ).textContent.trim(),
fragmentShader: document.querySelector( '#render-frag' ).textContent.trim(),
uniforms: {
tDiffuse: { value: renderTarget.texture[ 0 ] },
tNormal: { value: renderTarget.texture[ 1 ] },
},
glslVersion: THREE.GLSL3
} )
) );

// Controls

controls = new OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render );
controls.enableZoom = false;
controls.screenSpacePanning = true;

window.addEventListener( 'resize', onWindowResize, false );

}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );

const dpr = renderer.getPixelRatio();
renderTarget.setSize( window.innerWidth * dpr, window.innerHeight * dpr );

render();

}

function render() {

// render scene into target
renderer.setRenderTarget( renderTarget );
renderer.render( scene, camera );

// render post FX
renderer.setRenderTarget( null );
renderer.render( postScene, postCamera );

}

</script>

</body>
</html>
1 change: 1 addition & 0 deletions src/Three.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { REVISION } from './constants.js';

export { WebGLMultipleRenderTargets } from './renderers/WebGLMultipleRenderTargets.js';
export { WebGLMultisampleRenderTarget } from './renderers/WebGLMultisampleRenderTarget.js';
export { WebGLCubeRenderTarget } from './renderers/WebGLCubeRenderTarget.js';
export { WebGLRenderTarget } from './renderers/WebGLRenderTarget.js';
Expand Down
79 changes: 79 additions & 0 deletions src/renderers/WebGLMultipleRenderTargets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { WebGLRenderTarget } from './WebGLRenderTarget.js';

class WebGLMultipleRenderTargets extends WebGLRenderTarget {

constructor( width, height, count ) {

super( width, height );

const texture = this.texture;

this.texture = [];

for ( let i = 0; i < count; i ++ ) {

this.texture[ i ] = texture.clone();

}

}

setSize( width, height, depth = 1 ) {

if ( this.width !== width || this.height !== height || this.depth !== depth ) {

this.width = width;
this.height = height;
this.depth = depth;

for ( let i = 0, il = this.texture.length; i < il; i ++ ) {

this.texture[ i ].image.width = width;
this.texture[ i ].image.height = height;
this.texture[ i ].image.depth = depth;

}

this.dispose();

}

this.viewport.set( 0, 0, width, height );
this.scissor.set( 0, 0, width, height );

return this;

}

copy( source ) {

this.dispose();

this.width = source.width;
this.height = source.height;
this.depth = source.depth;

this.viewport.set( 0, 0, this.width, this.height );
this.scissor.set( 0, 0, this.width, this.height );

this.depthBuffer = source.depthBuffer;
this.stencilBuffer = source.stencilBuffer;
this.depthTexture = source.depthTexture;

this.texture.length = 0;

for ( let i = 0, il = source.texture.length; i < il; i ++ ) {

this.texture[ i ] = source.texture[ i ].clone();

}

return this;

}

}

WebGLMultipleRenderTargets.prototype.isWebGLMultipleRenderTargets = true;

export { WebGLMultipleRenderTargets };
Loading

0 comments on commit 2510609

Please sign in to comment.