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

WebGL Multiple Render Targets (DrawBuffers) #9358

Closed
wants to merge 16 commits into from
1,014 changes: 571 additions & 443 deletions build/three.js

Large diffs are not rendered by default.

873 changes: 14 additions & 859 deletions build/three.min.js

Large diffs are not rendered by default.

1,015 changes: 571 additions & 444 deletions build/three.module.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion examples/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ var files = {
"webgl_custom_attributes_points",
"webgl_custom_attributes_points2",
"webgl_custom_attributes_points3",
"webgl_raymarching_reflect"
"webgl_raymarching_reflect",
"webgl_mrt"
],
"webgl deferred": [
"webgldeferred_animation"
Expand Down
275 changes: 275 additions & 0 deletions examples/webgl_mrt.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
<!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 {
color: #fff;
font-family:Monospace;
font-size:13px;
text-align:center;
background-color: #000;
margin: 0px;
overflow: hidden;
}
a {
color: #B2E9FF;
font-weight: bold;
pointer-events: auto;
}

canvas {
position: absolute;
top: 0;
left: 0;
}

#info {
pointer-events: none;
position: absolute;
left: 0;
top: 0px; width: 100%;
padding: 5px;
display: inline-block;
}

#error {
margin: auto;
margin-top: 40px;
display: block;
max-width: 400px;
padding: 20px;
background: #CE0808;
}
</style>

<!-- Write to G-Buffer -->
<script id="gbuffer-vert" type="x-shader/x-vertex">
#extension GL_EXT_draw_buffers : require
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
attribute vec4 position;
attribute vec3 normal;
attribute vec2 uv;
varying vec3 vNormal;
varying vec2 vUv;

void main() {
vUv = uv;

// get smooth normals
vec4 mvPosition = modelViewMatrix * position;

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

gl_Position = projectionMatrix * mvPosition;
}
</script>
<script id="gbuffer-frag" type="x-shader/x-fragment">
#extension GL_EXT_draw_buffers : require
precision mediump float;

uniform sampler2D map;
uniform vec2 repeat;

varying vec3 vNormal;
varying vec2 vUv;

void main() {
// write color to G-Buffer
// gl_FragData[0] = texture2D(map, vUv * repeat);
gl_FragData[0] = texture2D(map, vUv * repeat);

// write normals to G-Buffer
gl_FragData[1] = vec4(normalize( vNormal ), 0.0);
}
</script>

<!-- Read G-Buffer and render to screen -->
<script id="render-vert" type="x-shader/x-vertex">
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

attribute vec4 position;
attribute vec2 uv;
varying vec2 vUv;

void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * position;
}
</script>
<script id="render-frag" type="x-shader/x-fragment">
precision mediump float;

varying vec2 vUv;
uniform sampler2D tDiffuse;
uniform sampler2D tNormal;
uniform int showAttachment;

void main() {
vec3 diffuse = texture2D(tDiffuse, vUv).rgb;
vec3 normal = texture2D(tNormal, vUv).rgb;

gl_FragColor.rgb = mix(diffuse, normal, step(0.5, vUv.x));
gl_FragColor.a = 1.0;
}
</script>

</head>
<body>
<canvas></canvas>
<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 id="error" style="display: none;">
Your browser does not support <strong>WEBGL_draw_buffers</strong>.<br/><br/>
This demo will not work.
</div>
</div>

<script src="../build/three.js"></script>
<script src="js/controls/OrbitControls.js"></script>

<script>

var camera, scene, renderer, controls;
var target;
var postScene, postCamera;
var supportsMRT = true;

init();
animate();

function init() {

renderer = new THREE.WebGLRenderer( {
canvas: document.querySelector('canvas')
} );

if ( !renderer.extensions.get('WEBGL_draw_buffers') ) {
supportsMRT = false;
document.querySelector('#error').style.display = 'block';
return;
}

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

//

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.001, 1000 );
camera.position.z = -4;

controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableDamping = true;
controls.dampingFactor = 0.25;
controls.rotateSpeed = 0.35;

// Create a multi render target with Float buffers
target = new THREE.WebGLMultiRenderTarget( window.innerWidth, window.innerHeight );
target.texture.format = THREE.RGBFormat;
target.texture.minFilter = THREE.NearestFilter;
target.texture.magFilter = THREE.NearestFilter;
target.texture.type = THREE.FloatType;
target.texture.generateMipmaps = false;
target.stencilBuffer = false;
target.depthBuffer = true;

// Add an attachment for normals
target.attachments.push( target.texture.clone() );

// Name our G-Buffer attachments for debugging
target.attachments[0].name = 'diffuse';
target.attachments[1].name = 'normal';

// Our scene
scene = new THREE.Scene();

// Add geometries
setupScene();
// Setup post-processing step
setupPost();

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

}

function setupPost () {

// Setup post processing stage
postCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
var postMaterial = new THREE.RawShaderMaterial({
vertexShader: document.querySelector('#render-vert').textContent.trim(),
fragmentShader: document.querySelector('#render-frag').textContent.trim(),
uniforms: {
tDiffuse: { type: 't', value: target.attachments[0] },
tNormal: { type: 't', value: target.attachments[1] },
showAttachment: { type: 'i', value: 0 }
}
});
var postPlane = new THREE.PlaneGeometry(2, 2);
var postQuad = new THREE.Mesh(postPlane, postMaterial);
postScene = new THREE.Scene();
postScene.add(postQuad);

}

function setupScene () {
var diffuse = new THREE.TextureLoader().load('textures/brick_diffuse.jpg');
diffuse.wrapS = diffuse.wrapT = THREE.RepeatWrapping;

// Setup some geometries
var geometry = new THREE.TorusKnotGeometry(1, 0.3, 128, 64);
var material = new THREE.RawShaderMaterial({
vertexShader: document.querySelector('#gbuffer-vert').textContent.trim(),
fragmentShader: document.querySelector('#gbuffer-frag').textContent.trim(),
uniforms: {
map: { type: 't', value: diffuse },
repeat: { type: 'v2', value: new THREE.Vector2(5, 0.5) }
}
});

var torus = new THREE.Mesh(geometry, material);
scene.add(torus);
}

function onWindowResize() {

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

var dpr = renderer.getPixelRatio();
target.setSize( window.innerWidth * dpr, window.innerHeight * dpr );
renderer.setSize( window.innerWidth, window.innerHeight );

}

function animate() {

if ( !supportsMRT ) return;
controls.update();

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

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

requestAnimationFrame( animate );

}

</script>

</body>
</html>
Empty file modified examples/webvr_vive.html
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions src/Three.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import './polyfills.js';

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

/**
* @author Matt DesLauriers / @mattdesl
*/

function WebGLMultiRenderTarget( width, height, options ) {

WebGLRenderTarget.call( this, width, height, options );

this.attachments = [ this.texture ];
};

WebGLMultiRenderTarget.prototype = Object.create( WebGLRenderTarget.prototype );
WebGLMultiRenderTarget.prototype.constructor = WebGLMultiRenderTarget;

WebGLMultiRenderTarget.prototype.isWebGLMultiRenderTarget = true;

WebGLMultiRenderTarget.copy = function ( source ) {

WebGLRenderTarget.prototype.copy.call( this, source );

this.attachments = source.attachments.map(function ( attachment ) {
return attachment.clone();
});

return this;

};

export { WebGLMultiRenderTarget };
26 changes: 24 additions & 2 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ function WebGLRenderer( parameters ) {
extensions.get( 'OES_standard_derivatives' );
extensions.get( 'ANGLE_instanced_arrays' );

var DrawBuffersEXT = extensions.get( 'WEBGL_draw_buffers' );

if ( extensions.get( 'OES_element_index_uint' ) ) {

BufferGeometry.MaxIndex = 4294967296;
Expand All @@ -294,6 +296,8 @@ function WebGLRenderer( parameters ) {

var bufferRenderer = new WebGLBufferRenderer( _gl, extensions, _infoRender );
var indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, _infoRender );
var defaultAttachments = [ _gl.COLOR_ATTACHMENT0 ];
var defaultBackAttachment = [ _gl.BACK ];

//

Expand Down Expand Up @@ -2630,11 +2634,11 @@ function WebGLRenderer( parameters ) {
}

var isCube = ( renderTarget && renderTarget.isWebGLRenderTargetCube );
var framebuffer;
var framebuffer, renderTargetProperties;

if ( renderTarget ) {

var renderTargetProperties = properties.get( renderTarget );
renderTargetProperties = properties.get( renderTarget );

if ( isCube ) {

Expand Down Expand Up @@ -2667,6 +2671,24 @@ function WebGLRenderer( parameters ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_currentFramebuffer = framebuffer;

if ( DrawBuffersEXT ) {

if ( renderTargetProperties && renderTargetProperties.__webglAttachments ) {

DrawBuffersEXT.drawBuffersWEBGL( renderTargetProperties.__webglAttachments );

} else if ( renderTarget ) {

DrawBuffersEXT.drawBuffersWEBGL( defaultAttachments );

} else {

DrawBuffersEXT.drawBuffersWEBGL( defaultBackAttachment );

}

}

}

state.scissor( _currentScissor );
Expand Down
Loading