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

Auto shader output definitions for MRT #27808

Draft
wants to merge 9 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file modified examples/screenshots/webgl2_multiple_rendertargets.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 19 additions & 66 deletions examples/webgl2_multiple_rendertargets.html
Expand Up @@ -7,54 +7,12 @@
<link type="text/css" rel="stylesheet" href="main.css">

<!-- 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() {
<script id="gbuffer-output-normal-frag" type="x-shader/x-fragment">
#ifdef out_Normal

vUv = uv;

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

vec3 transformedNormal = normalMatrix * normal;
vNormal = normalize( transformedNormal );
out_Normal = vec4(normal, 1.0);

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 );

}
#endif
</script>

<!-- Read G-Buffer and render to screen -->
Expand Down Expand Up @@ -82,7 +40,7 @@
return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );
}

layout(location = 0) out vec4 pc_FragColor;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw: does anyone know what "pc" stands for? 🤔

layout(location = 0) out vec4 out_FragColor;

in vec2 vUv;

Expand All @@ -94,10 +52,8 @@
vec4 diffuse = texture( tDiffuse, vUv );
vec4 normal = texture( tNormal, vUv );

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

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

}
</script>
Expand Down Expand Up @@ -138,6 +94,10 @@
gui.add( parameters, 'wireframe' );
gui.onChange( render );

// Extend three's ShaderChunk library
THREE.ShaderChunk.normal_fragment_maps += '\n' +
document.querySelector( '#gbuffer-output-normal-frag' ).textContent.trim();

init();

function init() {
Expand All @@ -155,19 +115,21 @@
{
count: 2,
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter
magFilter: THREE.NearestFilter,
type: THREE.HalfFloatType
}
);

// Name our G-Buffer attachments for debugging
// The G-Buffer texture names will be used to define shader outputs as `out_${name}`

renderTarget.textures[ 0 ].name = 'diffuse';
renderTarget.textures[ 1 ].name = 'normal';
renderTarget.textures[ 0 ].name = 'Color';
renderTarget.textures[ 1 ].name = 'Normal';

// Scene setup

scene = new THREE.Scene();
scene.background = new THREE.Color( 0x222222 );
scene.background = new THREE.Color( 0x000000 );
scene.add( new THREE.AmbientLight() );

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 50 );
camera.position.z = 4;
Expand All @@ -181,16 +143,7 @@

scene.add( new THREE.Mesh(
new THREE.TorusKnotGeometry( 1, 0.3, 128, 32 ),
new THREE.RawShaderMaterial( {
name: 'G-Buffer Shader',
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
} )
new THREE.MeshStandardMaterial( { map: diffuse } )
) );

// PostProcessing setup
Expand Down
2 changes: 1 addition & 1 deletion examples/webgl2_rendertarget_texture2darray.html
Expand Up @@ -38,7 +38,7 @@
void main()
{
float voxel = texture(uTexture, vec3( vUv, uDepth )).r;
gl_FragColor.r = voxel * uIntensity;
gl_FragColor = voxel * uIntensity;
}

</script>
Expand Down
124 changes: 121 additions & 3 deletions src/renderers/webgl/WebGLProgram.js
@@ -1,9 +1,44 @@
import { WebGLUniforms } from './WebGLUniforms.js';
import { WebGLShader } from './WebGLShader.js';
import { ShaderChunk } from '../shaders/ShaderChunk.js';
import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, CubeRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, VSMShadowMap, AgXToneMapping, ACESFilmicToneMapping, NeutralToneMapping, CineonToneMapping, CustomToneMapping, ReinhardToneMapping, LinearToneMapping, GLSL3, LinearSRGBColorSpace, SRGBColorSpace, LinearDisplayP3ColorSpace, DisplayP3ColorSpace, P3Primaries, Rec709Primaries } from '../../constants.js';
import { ColorManagement } from '../../math/ColorManagement.js';

import {
NoToneMapping,
AddOperation,
MixOperation,
MultiplyOperation,
CubeRefractionMapping,
CubeUVReflectionMapping,
CubeReflectionMapping,
PCFSoftShadowMap,
PCFShadowMap,
VSMShadowMap,
AgXToneMapping,
ACESFilmicToneMapping,
NeutralToneMapping,
CineonToneMapping,
CustomToneMapping,
ReinhardToneMapping,
LinearToneMapping,
LinearSRGBColorSpace,
SRGBColorSpace,
LinearDisplayP3ColorSpace,
DisplayP3ColorSpace,
P3Primaries,
Rec709Primaries,
FloatType,
HalfFloatType,
RedFormat,
RGFormat,
IntType,
UnsignedIntType,
UnsignedShortType,
ShortType,
RedIntegerFormat,
RGIntegerFormat
} from '../../constants.js';

// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
const COMPLETION_STATUS_KHR = 0x91B1;

Expand Down Expand Up @@ -454,6 +489,88 @@ function generateCubeUVSize( parameters ) {

}

function getOutputPrecision( texture ) {

switch ( texture.type ) {

case IntType:
case UnsignedIntType:
case FloatType:
return 'highp';

case ShortType:
case UnsignedShortType:
case HalfFloatType:
return 'mediump';

default:
return 'lowp';

}

}

function getOutputType( texture ) {

const isIntType = texture.type === IntType || texture.type === ShortType;
const isUintType = texture.type === UnsignedIntType || texture.type === UnsignedShortType;

switch ( texture.format ) {

case RedFormat:
case RedIntegerFormat:
return isUintType ? 'uint' : isIntType ? 'int' : 'float';

case RGFormat:
case RGIntegerFormat:
return isUintType ? 'uvec2' : isIntType ? 'ivec2' : 'vec2';

default:
return isUintType ? 'uvec4' : isIntType ? 'ivec4' : 'vec4';

}

}

function generateOutputDefinitions( renderTarget ) {

const definitions = [];

if ( renderTarget === null ) {

// Create an output declaration for the back buffer.
definitions.push( 'layout(location = 0) out lowp vec4 out_FragData;' );
definitions.push( '#define gl_FragColor out_FragData' );

return definitions.join( '\n' );

}

for ( let i = 0, l = renderTarget.textures.length; i < l; ++ i ) {

const texture = renderTarget.textures[ i ];
const name = texture.name.replace( /\W*/g, '' );
const precision = getOutputPrecision( texture );
const type = getOutputType( texture );

definitions.push( `layout(location = ${i}) out ${precision} ${type} out_FragData${i};` );

if ( l > 1 && name !== '' ) {

// Define output variable macros for convenience if there are multiple textures.
definitions.push( `#define out_${name} out_FragData${i}` );

}

}

// Declare the first texture as the default color output.
definitions.push( '#define gl_FragColor out_FragData0' );

return definitions.join( '\n' );

}

function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {

// TODO Send this event to Three.js DevTools
Expand Down Expand Up @@ -862,6 +979,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
vertexShader = unrollLoops( vertexShader );
fragmentShader = unrollLoops( fragmentShader );

const hasOutputDefinitions = /^(?:.*\)){0,1}\s*out\b/m.test( fragmentShader );

if ( parameters.isRawShaderMaterial !== true ) {

// GLSL 3.0 conversion for built-in materials and ShaderMaterial
Expand All @@ -877,8 +996,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {

prefixFragment = [
'#define varying in',
( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
hasOutputDefinitions ? '' : generateOutputDefinitions( renderer.getRenderTarget() ),
'#define gl_FragDepthEXT gl_FragDepth',
'#define texture2D texture',
'#define textureCube texture',
Expand Down