mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-09 15:36:34 +02:00
aesthetics: even better cubemap
This commit is contained in:
@@ -2,8 +2,8 @@ export const
|
||||
RTINSPECTOR_MULTIPLE = false,
|
||||
RTINSPECTOR_CAPTURE_NAME: string | null = null,
|
||||
// RTINSPECTOR_CAPTURE_NAME: string | null = 'light1/shadowMap',
|
||||
// RTINSPECTOR_CAPTURE_NAME: string | null = 'EnvironmentMap/swap0',
|
||||
// RTINSPECTOR_CAPTURE_NAME: string | null = 'EnvironmentMap/swap1',
|
||||
RTINSPECTOR_CAPTURE_INDEX = 0,
|
||||
COMPONENT_UPDATE_BREAKPOINT: string | null = null,
|
||||
// COMPONENT_UPDATE_BREAKPOINT: string | null = 'Bloom/quadDup3',
|
||||
// COMPONENT_UPDATE_BREAKPOINT: string | null = 'EnvironmentMap/quadIntegrate',
|
||||
COMPONENT_DRAW_BREAKPOINT: string | null = null;
|
||||
|
@@ -3,11 +3,13 @@ import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||
import { Material } from '../heck/Material';
|
||||
import { Quad } from '../heck/components/Quad';
|
||||
import environmentMapFrag from '../shaders/environment-map.frag';
|
||||
import environmentMapMergeFrag from '../shaders/environment-map-merge.frag';
|
||||
import quadVert from '../shaders/quad.vert';
|
||||
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||
import { Swap, Xorshift } from '@fms-cat/experimental';
|
||||
import { Lambda } from '../heck/components/Lambda';
|
||||
import { CubemapRenderTarget } from '../heck/CubemapRenderTarget';
|
||||
import { gl } from '../globals/canvas';
|
||||
|
||||
const WIDTH = 1024;
|
||||
const HEIGHT = 512;
|
||||
@@ -15,11 +17,7 @@ const HEIGHT = 512;
|
||||
export class EnvironmentMap {
|
||||
public entity: Entity;
|
||||
|
||||
public swap: Swap<BufferRenderTarget>;
|
||||
|
||||
public get texture(): GLCatTexture {
|
||||
return this.swap.o.texture;
|
||||
}
|
||||
public readonly texture: GLCatTexture;
|
||||
|
||||
public constructor( { cubemap }: {
|
||||
cubemap: CubemapRenderTarget;
|
||||
@@ -30,7 +28,7 @@ export class EnvironmentMap {
|
||||
const rng = new Xorshift( 114514 );
|
||||
|
||||
// -- swap -------------------------------------------------------------------------------------
|
||||
this.swap = new Swap(
|
||||
const swap = new Swap(
|
||||
new BufferRenderTarget( {
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
@@ -42,44 +40,74 @@ export class EnvironmentMap {
|
||||
name: process.env.DEV && 'EnvironmentMap/swap1',
|
||||
} ),
|
||||
);
|
||||
swap.i.texture.textureWrap( gl.REPEAT );
|
||||
swap.o.texture.textureWrap( gl.REPEAT );
|
||||
|
||||
// -- post -------------------------------------------------------------------------------------
|
||||
const material = new Material(
|
||||
// -- integrate --------------------------------------------------------------------------------
|
||||
swap.swap();
|
||||
|
||||
const materialIntegrate = new Material(
|
||||
quadVert,
|
||||
environmentMapFrag,
|
||||
);
|
||||
material.addUniform( 'uniformSeed', '4f', rng.gen(), rng.gen(), rng.gen(), rng.gen() );
|
||||
material.addUniformTexture( 'sampler0', this.swap.i.texture );
|
||||
material.addUniformCubemap( 'samplerCubemap', cubemap.texture );
|
||||
materialIntegrate.addUniform( 'uniformSeed', '4f', rng.gen(), rng.gen(), rng.gen(), rng.gen() );
|
||||
materialIntegrate.addUniformTexture( 'sampler0', swap.i.texture );
|
||||
materialIntegrate.addUniformCubemap( 'samplerCubemap', cubemap.texture );
|
||||
|
||||
if ( process.env.DEV ) {
|
||||
if ( module.hot ) {
|
||||
module.hot.accept( '../shaders/environment-map.frag', () => {
|
||||
material.replaceShader( quadVert, environmentMapFrag );
|
||||
materialIntegrate.replaceShader( quadVert, environmentMapFrag );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
const quad = new Quad( {
|
||||
target: this.swap.o,
|
||||
material,
|
||||
name: process.env.DEV && 'EnvironmentMap/quad',
|
||||
} );
|
||||
|
||||
// -- swapper ----------------------------------------------------------------------------------
|
||||
this.entity.components.push( new Lambda( {
|
||||
onUpdate: () => {
|
||||
this.swap.swap();
|
||||
|
||||
material.addUniform( 'uniformSeed', '4f', rng.gen(), rng.gen(), rng.gen(), rng.gen() );
|
||||
material.addUniformTexture( 'sampler0', this.swap.i.texture );
|
||||
|
||||
quad.target = this.swap.o;
|
||||
},
|
||||
visible: false,
|
||||
name: process.env.DEV && 'EnvironmentMap/swapper',
|
||||
this.entity.components.push( new Quad( {
|
||||
target: swap.o,
|
||||
material: materialIntegrate,
|
||||
name: process.env.DEV && 'EnvironmentMap/quadIntegrate',
|
||||
} ) );
|
||||
|
||||
this.entity.components.push( quad );
|
||||
// -- merge results ----------------------------------------------------------------------------
|
||||
swap.swap();
|
||||
|
||||
const materialMerge = new Material(
|
||||
quadVert,
|
||||
environmentMapMergeFrag,
|
||||
);
|
||||
materialMerge.addUniformTexture( 'sampler0', swap.i.texture );
|
||||
|
||||
if ( process.env.DEV ) {
|
||||
if ( module.hot ) {
|
||||
module.hot.accept( '../shaders/environment-map-merge.frag', () => {
|
||||
materialMerge.replaceShader( quadVert, environmentMapMergeFrag );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
this.entity.components.push( new Quad( {
|
||||
target: swap.o,
|
||||
material: materialMerge,
|
||||
name: process.env.DEV && 'EnvironmentMap/quadMerge',
|
||||
} ) );
|
||||
|
||||
// -- this is the output -----------------------------------------------------------------------
|
||||
this.texture = swap.o.texture;
|
||||
|
||||
// -- updater ----------------------------------------------------------------------------------
|
||||
this.entity.components.push( new Lambda( {
|
||||
onUpdate: () => {
|
||||
materialIntegrate.addUniform(
|
||||
'uniformSeed',
|
||||
'4f',
|
||||
rng.gen(),
|
||||
rng.gen(),
|
||||
rng.gen(),
|
||||
rng.gen(),
|
||||
);
|
||||
},
|
||||
visible: false,
|
||||
name: process.env.DEV && 'EnvironmentMap/updater',
|
||||
} ) );
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ export class RTInspector {
|
||||
this.blitSingle = new Blit( {
|
||||
dst: options.target,
|
||||
name: process.env.DEV && 'RTInspector/blitSingle',
|
||||
ignoreBreakpoints: true,
|
||||
} );
|
||||
this.entitySingle.components.push( this.blitSingle );
|
||||
|
||||
@@ -64,6 +65,7 @@ export class RTInspector {
|
||||
attachment: gl.COLOR_ATTACHMENT0 + iAttachment,
|
||||
dstRect,
|
||||
name: `RTInspector/blitsMultiple/${ src.name }/${ iAttachment }`,
|
||||
ignoreBreakpoints: true,
|
||||
} );
|
||||
|
||||
this.blitsMultiple.push( blit );
|
||||
|
@@ -53,7 +53,7 @@ export class SphereParticles {
|
||||
}
|
||||
|
||||
private __createGeometryRender(): Geometry {
|
||||
const octahedron = genOctahedron( { radius: 1.0, div: 3 } );
|
||||
const octahedron = genOctahedron( { radius: 1.0, div: 1 } );
|
||||
|
||||
const geometry = new InstancedGeometry();
|
||||
|
||||
|
14
src/scene.ts
14
src/scene.ts
@@ -71,12 +71,12 @@ const ibllut = new IBLLUT();
|
||||
dog.root.children.push( ibllut.entity );
|
||||
|
||||
// -- "objects" ------------------------------------------------------------------------------------
|
||||
// const replacerSphereParticles = new EntityReplacer( () => new SphereParticles() );
|
||||
// if ( process.env.DEV && module.hot ) {
|
||||
// module.hot.accept( './entities/SphereParticles', () => {
|
||||
// replacerSphereParticles.replace();
|
||||
// } );
|
||||
// }
|
||||
const replacerSphereParticles = new EntityReplacer( () => new SphereParticles() );
|
||||
if ( process.env.DEV && module.hot ) {
|
||||
module.hot.accept( './entities/SphereParticles', () => {
|
||||
replacerSphereParticles.replace();
|
||||
} );
|
||||
}
|
||||
|
||||
// const replacerTrails = new EntityReplacer( () => new Trails() );
|
||||
// if ( process.env.DEV && module.hot ) {
|
||||
@@ -137,7 +137,7 @@ const light = new LightEntity( {
|
||||
shadowMapFar: 20.0,
|
||||
namePrefix: process.env.DEV && 'light1',
|
||||
} );
|
||||
light.color = [ 0.1, 0.1, 0.1 ];
|
||||
light.color = [ 40.0, 40.0, 40.0 ];
|
||||
light.entity.transform.lookAt( new Vector3( [ -1.0, 2.0, 8.0 ] ) );
|
||||
dog.root.children.push( light.entity );
|
||||
|
||||
|
46
src/shaders/blur.frag
Normal file
46
src/shaders/blur.frag
Normal file
@@ -0,0 +1,46 @@
|
||||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
const float OFFSET1 = 1.411764705882353;
|
||||
const float OFFSET2 = 3.2941176470588234;
|
||||
const float OFFSET3 = 5.176470588235294;
|
||||
const float CONTRIBUTION0 = 0.1964825501511404;
|
||||
const float CONTRIBUTION1 = 0.2969069646728344;
|
||||
const float CONTRIBUTION2 = 0.09447039785044732;
|
||||
const float CONTRIBUTION3 = 0.010381362401148057;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform vec2 resolution;
|
||||
uniform sampler2D sampler0;
|
||||
|
||||
void main() {
|
||||
vec2 bv;
|
||||
|
||||
#ifdef IS_VERTICAL
|
||||
bv = vec2( 0.0, 1.0 ) / resolution;
|
||||
#else
|
||||
bv = vec2( 1.0, 0.0 ) / resolution;
|
||||
#endif
|
||||
|
||||
vec4 sum = vec4( 0.0 );
|
||||
|
||||
sum += CONTRIBUTION0 * texture( sampler0, vUv );
|
||||
vec2 uvt = vUv - bv * OFFSET1;
|
||||
sum += CONTRIBUTION1 * texture( sampler0, uvt );
|
||||
uvt = vUv + bv * OFFSET1;
|
||||
sum += CONTRIBUTION1 * texture( sampler0, uvt );
|
||||
uvt = vUv - bv * OFFSET2;
|
||||
sum += CONTRIBUTION2 * texture( sampler0, uvt );
|
||||
uvt = vUv + bv * OFFSET2;
|
||||
sum += CONTRIBUTION2 * texture( sampler0, uvt );
|
||||
uvt = vUv - bv * OFFSET3;
|
||||
sum += CONTRIBUTION3 * texture( sampler0, uvt );
|
||||
uvt = vUv + bv * OFFSET3;
|
||||
sum += CONTRIBUTION3 * texture( sampler0, uvt );
|
||||
|
||||
fragColor = vec4( sum.xyz, 1.0 );
|
||||
}
|
38
src/shaders/environment-map-merge.frag
Normal file
38
src/shaders/environment-map-merge.frag
Normal file
@@ -0,0 +1,38 @@
|
||||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
const float PI = 3.14159265;
|
||||
const float TAU = 6.283185307;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform float head;
|
||||
uniform vec2 resolution;
|
||||
uniform sampler2D sampler0;
|
||||
|
||||
void main() {
|
||||
float lv = floor( -log( 1.0 - max( vUv.x, vUv.y ) ) / log( 2.0 ) );
|
||||
|
||||
if ( lv >= 5.0 ) { discard; }
|
||||
|
||||
fragColor = texture( sampler0, vUv );
|
||||
|
||||
if ( lv != floor( -log( 1.0 - min( vUv.x, vUv.y ) ) / log( 2.0 ) ) ) { return; }
|
||||
if ( lv < 1.0 ) { return; }
|
||||
|
||||
float p = pow( 0.5, lv + 1.0 );
|
||||
vec2 uvt;
|
||||
|
||||
for ( int i = 1; i < 31; i ++ ) {
|
||||
uvt = vUv - p * vec2( i, 0.0 );
|
||||
if ( uvt.x < 0.0 ) { break; }
|
||||
fragColor += texture( sampler0, uvt );
|
||||
uvt = vUv - p * vec2( 0.0, i );
|
||||
fragColor += texture( sampler0, uvt );
|
||||
}
|
||||
|
||||
fragColor = fragColor / fragColor.w;
|
||||
}
|
@@ -1,7 +1,5 @@
|
||||
#version 300 es
|
||||
|
||||
// https://learnopengl.com/PBR/IBL/Specular-IBL
|
||||
|
||||
precision highp float;
|
||||
|
||||
#define saturate(x) clamp(x,0.,1.)
|
||||
@@ -10,7 +8,7 @@ precision highp float;
|
||||
#pragma glslify: prng = require( ./-prng );
|
||||
|
||||
const int SAMPLES = 16;
|
||||
const float UV_MARGIN = 0.9;
|
||||
const float UV_MARGIN = 0.9375;
|
||||
const float PI = 3.14159265;
|
||||
const float TAU = 6.283185307;
|
||||
|
||||
@@ -41,40 +39,16 @@ float vdc( float i, float base ) {
|
||||
return r;
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX( vec2 Xi, float roughness, vec3 N ) {
|
||||
float a = roughness * roughness;
|
||||
|
||||
float phi = TAU * Xi.x;
|
||||
float cosTheta = roughness < 0.0 // negative roughness to usa lambert ???
|
||||
? asin( sqrt( Xi.y ) )
|
||||
: sqrt( ( 1.0 - Xi.y ) / ( 1.0 + ( a * a - 1.0 ) * Xi.y ) );
|
||||
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
||||
|
||||
// from spherical coordinates to cartesian coordinates
|
||||
vec3 H = vec3(
|
||||
cos( phi ) * sinTheta,
|
||||
sin( phi ) * sinTheta,
|
||||
cosTheta
|
||||
);
|
||||
|
||||
// from tangent-space vector to world-space sample vector
|
||||
vec3 up = abs( N.y ) < 0.999 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 1.0, 0.0, 0.0 );
|
||||
vec3 tangent = normalize( cross( up, N ) );
|
||||
vec3 bitangent = cross( N, tangent );
|
||||
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
return normalize( sampleVec );
|
||||
}
|
||||
|
||||
vec3 haha( vec3 L ) {
|
||||
return texture( samplerCubemap, L ).xyz;
|
||||
}
|
||||
#pragma glslify: importanceSampleGGX = require( ./modules/importanceSampleGGX );
|
||||
|
||||
void main() {
|
||||
vec2 halfTexel = 1.0 / resolution; // * 0.5;
|
||||
|
||||
float lv = ceil( -log( 1.0 - min( vUv.x, vUv.y ) ) / log( 2.0 ) );
|
||||
float p = pow( 0.5, lv );
|
||||
float lv = floor( -log( 1.0 - max( vUv.x, vUv.y ) ) / log( 2.0 ) );
|
||||
|
||||
if ( lv >= 5.0 ) { discard; }
|
||||
|
||||
float p = pow( 0.5, lv + 1.0 );
|
||||
vec2 uv00 = floor( vUv / p ) * p;
|
||||
vec2 uv11 = uv00 + p;
|
||||
vec2 uv = clamp( vUv, uv00 + halfTexel, uv11 - halfTexel );
|
||||
@@ -82,7 +56,7 @@ void main() {
|
||||
uv = ( uv - 0.5 ) / UV_MARGIN + 0.5;
|
||||
|
||||
vec3 tex = texture( sampler0, vUv ).xyz;
|
||||
float roughness = lv * 0.2;
|
||||
float roughness = lv * 0.333;
|
||||
|
||||
float a = TAU * uv.x;
|
||||
float b = PI * ( uv.y - 0.5 );
|
||||
@@ -90,18 +64,18 @@ void main() {
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
|
||||
seed = uniformSeed + 500.0 * N.xyzx;
|
||||
seed = uniformSeed + 500.0 * vec4( N.xy, uv00 );
|
||||
|
||||
vec4 col = vec4( 0.0 );
|
||||
for ( int i = 0; i < SAMPLES; i ++ ) {
|
||||
vec2 Xi = vec2( prng( seed ), prng( seed ) );
|
||||
vec3 H = ImportanceSampleGGX( Xi, roughness, N );
|
||||
vec3 H = importanceSampleGGX( Xi, roughness, N );
|
||||
vec3 L = normalize( 2.0 * dot( V, H ) * H - V );
|
||||
|
||||
float NoL = dot( N, L );
|
||||
|
||||
if ( NoL > 0.0 ) {
|
||||
col += vec4( haha( L ), 1.0 ) * NoL;
|
||||
col += texture( samplerCubemap, L ) * NoL;
|
||||
}
|
||||
}
|
||||
|
||||
|
14
src/shaders/modules/brdfLambert.glsl
Normal file
14
src/shaders/modules/brdfLambert.glsl
Normal file
@@ -0,0 +1,14 @@
|
||||
// Ref: https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/38b88e365728d7b2e28a78a57d84be2675fdb70d/source/Renderer/shaders/brdf.glsl
|
||||
|
||||
const float PI = 3.14159265;
|
||||
const vec3 DIELECTRIC_SPECULAR = vec3( 0.04 );
|
||||
const vec3 ONE_SUB_DIELECTRIC_SPECULAR = 1.0 - DIELECTRIC_SPECULAR;
|
||||
|
||||
vec3 brdfLambert( vec3 f0, vec3 albedo, float VdotH ) {
|
||||
// F_Schlick
|
||||
vec3 F = f0 + ( 1.0 - f0 ) * pow( max( 0.0, 1.0 - VdotH ), 5.0 );
|
||||
|
||||
return ( 1.0 - F ) * albedo / PI;
|
||||
}
|
||||
|
||||
#pragma glslify: export(brdfLambert)
|
26
src/shaders/modules/brdfSpecularGGX.glsl
Normal file
26
src/shaders/modules/brdfSpecularGGX.glsl
Normal file
@@ -0,0 +1,26 @@
|
||||
// Ref: https://github.com/KhronosGroup/glTF-Sample-Viewer/blob/38b88e365728d7b2e28a78a57d84be2675fdb70d/source/Renderer/shaders/brdf.glsl
|
||||
|
||||
const float PI = 3.14159265;
|
||||
const vec3 DIELECTRIC_SPECULAR = vec3( 0.04 );
|
||||
|
||||
vec3 brdfSpecularGGX( vec3 f0, float roughness, float VdotH, float NdotL, float NdotV, float NdotH ) {
|
||||
// F_Schlick
|
||||
vec3 F = f0 + ( 1.0 - f0 ) * pow( max( 0.0, 1.0 - VdotH ), 5.0 );
|
||||
|
||||
// V_GGX
|
||||
float roughnessSq = roughness * roughness;
|
||||
|
||||
float GGXV = NdotL * sqrt( NdotV * NdotV * ( 1.0 - roughnessSq ) + roughnessSq );
|
||||
float GGXL = NdotV * sqrt( NdotL * NdotL * ( 1.0 - roughnessSq ) + roughnessSq );
|
||||
|
||||
float GGX = GGXV + GGXL;
|
||||
float Vis = ( 0.0 < GGX ) ? ( 0.5 / GGX ) : 0.0;
|
||||
|
||||
// D_GGX
|
||||
float f = ( NdotH * NdotH ) * ( roughnessSq - 1.0 ) + 1.0;
|
||||
float D = roughnessSq / ( PI * f * f );
|
||||
|
||||
return F * Vis * D;
|
||||
}
|
||||
|
||||
#pragma glslify: export(brdfSpecularGGX)
|
30
src/shaders/modules/importanceSampleGGX.glsl
Normal file
30
src/shaders/modules/importanceSampleGGX.glsl
Normal file
@@ -0,0 +1,30 @@
|
||||
// Ref: https://learnopengl.com/PBR/IBL/Specular-IBL
|
||||
|
||||
const float TAU = 6.28318530718;
|
||||
|
||||
vec3 importanceSampleGGX( vec2 Xi, float roughness, vec3 N ) {
|
||||
float a = roughness * roughness;
|
||||
|
||||
float phi = TAU * Xi.x;
|
||||
float cosTheta = roughness > 1.0 // use lambert ???
|
||||
? cos( asin( sqrt( Xi.y ) ) )
|
||||
: sqrt( ( 1.0 - Xi.y ) / ( 1.0 + ( a * a - 1.0 ) * Xi.y ) );
|
||||
float sinTheta = sqrt( 1.0 - cosTheta * cosTheta );
|
||||
|
||||
// from spherical coordinates to cartesian coordinates
|
||||
vec3 H = vec3(
|
||||
cos( phi ) * sinTheta,
|
||||
sin( phi ) * sinTheta,
|
||||
cosTheta
|
||||
);
|
||||
|
||||
// from tangent-space vector to world-space sample vector
|
||||
vec3 up = abs( N.y ) < 0.999 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 1.0, 0.0, 0.0 );
|
||||
vec3 tangent = normalize( cross( up, N ) );
|
||||
vec3 bitangent = cross( N, tangent );
|
||||
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
return normalize( sampleVec );
|
||||
}
|
||||
|
||||
#pragma glslify: export(importanceSampleGGX)
|
@@ -87,7 +87,7 @@ void main() {
|
||||
fragPosition = vec4( rayPos, depth );
|
||||
fragNormal = vec4( normal, 1.0 );
|
||||
fragColor = color;
|
||||
fragWTF = vec4( vec3( 0.2, 0.2, 0.0 ), MTL_PBR );
|
||||
fragWTF = vec4( vec3( 0.2, 0.9, 0.0 ), MTL_PBR );
|
||||
#endif
|
||||
|
||||
#ifdef SHADOW
|
||||
|
@@ -23,7 +23,7 @@ uniform float time;
|
||||
|
||||
void main() {
|
||||
#ifdef FORWARD
|
||||
fragColor = vec4( 28.0 * vec3( 0.2, 0.9, 0.5 ), 1.0 );
|
||||
fragColor = vec4( 6.0 * vec3( 0.2, 0.9, 0.5 ), 1.0 );
|
||||
#endif
|
||||
|
||||
#ifdef DEFERRED
|
||||
|
@@ -8,7 +8,7 @@ const int MTL_PBR = 2;
|
||||
const int MTL_GRADIENT = 3;
|
||||
const int MTL_IRIDESCENT = 4;
|
||||
const int AO_ITER = 8;
|
||||
const float ENV_UV_MARGIN = 0.9;
|
||||
const float ENV_UV_MARGIN = 0.9375;
|
||||
const float AO_BIAS = 0.0;
|
||||
const float AO_RADIUS = 0.5;
|
||||
const float PI = 3.14159265359;
|
||||
@@ -16,10 +16,13 @@ const float TAU = 6.28318530718;
|
||||
const float EPSILON = 1E-3;
|
||||
const vec3 BLACK = vec3( 0.0 );
|
||||
const vec3 DIELECTRIC_SPECULAR = vec3( 0.04 );
|
||||
const vec3 ONE_SUB_DIELECTRIC_SPECULAR = 1.0 - DIELECTRIC_SPECULAR;
|
||||
|
||||
#define saturate(x) clamp(x,0.,1.)
|
||||
#define linearstep(a,b,x) saturate(((x)-(a))/((b)-(a)))
|
||||
|
||||
vec4 seed;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 fragColor;
|
||||
@@ -44,6 +47,9 @@ uniform sampler2D samplerRandom;
|
||||
|
||||
// == commons ======================================================================================
|
||||
#pragma glslify: prng = require( ./-prng );
|
||||
#pragma glslify: brdfLambert = require( ./modules/brdfLambert.glsl );
|
||||
#pragma glslify: brdfSpecularGGX = require( ./modules/brdfSpecularGGX.glsl );
|
||||
#pragma glslify: importanceSampleGGX = require( ./modules/importanceSampleGGX.glsl );
|
||||
|
||||
vec3 catColor( float _p ) {
|
||||
return 0.5 + 0.5 * vec3(
|
||||
@@ -53,19 +59,6 @@ vec3 catColor( float _p ) {
|
||||
);
|
||||
}
|
||||
|
||||
vec3 randomSphere( inout vec4 seed ) {
|
||||
vec3 v;
|
||||
for ( int i = 0; i < 10; i ++ ) {
|
||||
v = vec3(
|
||||
prng( seed ),
|
||||
prng( seed ),
|
||||
prng( seed )
|
||||
) * 2.0 - 1.0;
|
||||
if ( length( v ) < 1.0 ) { break; }
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
vec3 blurpleGradient( float t ) {
|
||||
vec3 colorA = vec3( 0.01, 0.04, 0.2 );
|
||||
vec3 colorB = vec3( 0.02, 0.3, 0.9 );
|
||||
@@ -105,7 +98,7 @@ vec4 sampleEnvLinear( vec2 uv, float lv ) {
|
||||
// == structs ======================================================================================
|
||||
struct Isect {
|
||||
vec2 screenUv;
|
||||
vec3 albedo;
|
||||
vec3 color;
|
||||
vec3 position;
|
||||
float depth;
|
||||
vec3 normal;
|
||||
@@ -185,38 +178,41 @@ vec3 shadePBR( Isect isect, AngularInfo aI ) {
|
||||
float lenL = length( isect.position - lightPos );
|
||||
float decay = 1.0 / ( lenL * lenL );
|
||||
|
||||
vec3 F0 = mix( DIELECTRIC_SPECULAR, isect.albedo, metallic );
|
||||
vec3 F = F0 + ( 1.0 - F0 ) * pow( 1.0 - aI.dotVH, 5.0 );
|
||||
vec3 albedo = mix( isect.color * ONE_SUB_DIELECTRIC_SPECULAR, vec3( 0.0 ), metallic );
|
||||
vec3 f0 = mix( DIELECTRIC_SPECULAR, isect.color, metallic );
|
||||
|
||||
float roughnessSq = roughness * roughness;
|
||||
float GGXV = aI.dotNL * sqrt( aI.dotNV * aI.dotNV * ( 1.0 - roughnessSq ) + roughnessSq );
|
||||
float GGXL = aI.dotNV * sqrt( aI.dotNL * aI.dotNL * ( 1.0 - roughnessSq ) + roughnessSq );
|
||||
float GGX = GGXV + GGXL;
|
||||
float Vis = ( 0.0 < GGX ) ? ( 0.5 / GGX ) : 0.0;
|
||||
vec3 diffuse = brdfLambert( f0, albedo, aI.dotVH );
|
||||
vec3 spec = brdfSpecularGGX( f0, roughness, aI.dotVH, aI.dotNL, aI.dotNV, aI.dotNH );
|
||||
|
||||
float f = ( aI.dotNH * roughnessSq - aI.dotNH ) * aI.dotNH + 1.0;
|
||||
float D = roughnessSq / ( PI * f * f );
|
||||
|
||||
vec3 diffuse = max( vec3( 0.0 ), ( 1.0 - F ) * ( isect.albedo / PI ) );
|
||||
vec3 spec = max( vec3( 0.0 ), F * Vis * D );
|
||||
vec3 shade = PI * lightColor * decay * shadow * aI.dotNL * ( diffuse + spec );
|
||||
|
||||
vec3 color = shade;
|
||||
|
||||
#ifdef IS_FIRST_LIGHT
|
||||
vec3 refl = reflect( aI.V, isect.normal );
|
||||
vec2 envUv = vec2(
|
||||
0.5 + atan( refl.x, -refl.z ) / TAU,
|
||||
0.5 + atan( refl.y, length( refl.zx ) ) / PI
|
||||
|
||||
// cheat the texture seam using noise!
|
||||
vec3 nEnvDiffuse = importanceSampleGGX( vec2( prng( seed ), prng( seed ) * 0.05 ), 2.0, isect.normal );
|
||||
|
||||
// diffuse ibl
|
||||
vec2 uvEnvDiffuse = vec2(
|
||||
0.5 + atan( nEnvDiffuse.x, -nEnvDiffuse.z ) / TAU,
|
||||
0.5 + atan( nEnvDiffuse.y, length( nEnvDiffuse.zx ) ) / PI
|
||||
);
|
||||
vec3 texEnvDiffuse = sampleEnvNearest( uvEnvDiffuse, 4.0 ).rgb;
|
||||
color += ao * texEnvDiffuse * albedo;
|
||||
|
||||
// reflective ibl
|
||||
vec2 brdf = texture( samplerIBLLUT, vec2( aI.dotNV, roughness ) ).xy;
|
||||
vec3 texEnv = 0.2 * sampleEnvLinear( envUv, 5.0 * roughness ).rgb;
|
||||
color += PI * ao * texEnv * ( brdf.x * F0 + brdf.y );
|
||||
vec3 reflEnvReflective = reflect( aI.V, isect.normal );
|
||||
vec2 uvEnvReflective = vec2(
|
||||
0.5 + atan( reflEnvReflective.x, -reflEnvReflective.z ) / TAU,
|
||||
0.5 + atan( reflEnvReflective.y, length( reflEnvReflective.zx ) ) / PI
|
||||
);
|
||||
vec2 brdfEnvReflective = texture( samplerIBLLUT, vec2( aI.dotNV, roughness ) ).xy;
|
||||
vec3 texEnvReflective = sampleEnvLinear( uvEnvReflective, 3.0 * roughness ).rgb;
|
||||
color += ao * texEnvReflective * ( brdfEnvReflective.x * f0 + brdfEnvReflective.y );
|
||||
|
||||
// emissive
|
||||
color += emissive * aI.dotNV * isect.albedo;
|
||||
color += emissive * aI.dotNV * isect.color;
|
||||
#endif // IS_FIRST_LIGHT
|
||||
|
||||
return color;
|
||||
@@ -243,12 +239,15 @@ void main() {
|
||||
vec4 tex2 = texture( sampler2, vUv );
|
||||
vec4 tex3 = texture( sampler3, vUv );
|
||||
|
||||
seed = texture( samplerRandom, vUv ) * 1919.810;
|
||||
prng( seed );
|
||||
|
||||
Isect isect;
|
||||
isect.screenUv = vUv;
|
||||
isect.position = tex0.xyz;
|
||||
isect.depth = tex0.w;
|
||||
isect.normal = tex1.xyz;
|
||||
isect.albedo = tex2.rgb;
|
||||
isect.color = tex2.rgb;
|
||||
isect.materialId = int( tex3.w + 0.5 );
|
||||
isect.materialParams = tex3.xyz;
|
||||
|
||||
@@ -259,7 +258,7 @@ void main() {
|
||||
|
||||
} else if ( isect.materialId == MTL_UNLIT ) {
|
||||
#ifdef IS_FIRST_LIGHT
|
||||
color = isect.albedo;
|
||||
color = isect.color;
|
||||
#endif
|
||||
|
||||
} else if ( isect.materialId == MTL_PBR ) {
|
||||
@@ -271,7 +270,7 @@ void main() {
|
||||
|
||||
} else if ( isect.materialId == MTL_IRIDESCENT ) {
|
||||
AngularInfo aI = genAngularInfo( isect );
|
||||
isect.albedo *= mix(
|
||||
isect.color *= mix(
|
||||
vec3( 1.0 ),
|
||||
catColor( isect.materialParams.x * aI.dotNV ),
|
||||
isect.materialParams.y
|
||||
|
@@ -41,6 +41,6 @@ void main() {
|
||||
fragPosition = vPosition;
|
||||
fragNormal = vec4( vNormal, 1.0 );
|
||||
fragColor = vec4( vColor.xyz, 1.0 );
|
||||
fragWTF = vec4( vec3( 0.1, 0.2, 0.0 ), MTL_PBR );
|
||||
fragWTF = vec4( vec3( 0.9, 0.1, 0.0 ), MTL_PBR );
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user