mirror of
https://github.com/FMS-Cat/condition.git
synced 2025-08-30 08:39:56 +02:00
feature: IBL??
This commit is contained in:
@@ -17,6 +17,8 @@ export interface CameraEntityOptions {
|
||||
root: Entity;
|
||||
target: RenderTarget;
|
||||
lights: LightEntity[];
|
||||
textureIBLLUT: GLCatTexture<WebGL2RenderingContext>;
|
||||
textureEnv: GLCatTexture<WebGL2RenderingContext>;
|
||||
textureRandom: GLCatTexture<WebGL2RenderingContext>;
|
||||
}
|
||||
|
||||
@@ -185,6 +187,8 @@ export class CameraEntity {
|
||||
shadingMaterial.blend = [ gl.ONE, gl.ONE ];
|
||||
shadingMaterial.addUniformTexture( 'samplerAo', aoTarget.texture );
|
||||
shadingMaterial.addUniformTexture( 'samplerShadow', light.shadowMap.texture );
|
||||
shadingMaterial.addUniformTexture( 'samplerIBLLUT', options.textureIBLLUT );
|
||||
shadingMaterial.addUniformTexture( 'samplerEnv', options.textureEnv );
|
||||
shadingMaterial.addUniformTexture( 'samplerRandom', options.textureRandom );
|
||||
|
||||
const shadingQuad = new Quad( {
|
||||
|
81
src/entities/EnvironmentMap.ts
Normal file
81
src/entities/EnvironmentMap.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Entity } from '../heck/Entity';
|
||||
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 quadVert from '../shaders/quad.vert';
|
||||
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||
import { Swap, Xorshift } from '@fms-cat/experimental';
|
||||
import { Lambda } from '../heck/components/Lambda';
|
||||
|
||||
const WIDTH = 1024;
|
||||
const HEIGHT = 512;
|
||||
|
||||
export class EnvironmentMap {
|
||||
public entity: Entity;
|
||||
|
||||
public swap: Swap<BufferRenderTarget>;
|
||||
|
||||
public get texture(): GLCatTexture<WebGL2RenderingContext> {
|
||||
return this.swap.o.texture;
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
this.entity = new Entity();
|
||||
this.entity.visible = false;
|
||||
|
||||
const rng = new Xorshift( 114514 );
|
||||
|
||||
// -- swap -------------------------------------------------------------------------------------
|
||||
this.swap = new Swap(
|
||||
new BufferRenderTarget( {
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
name: process.env.DEV && 'EnvironmentMap/swap0',
|
||||
} ),
|
||||
new BufferRenderTarget( {
|
||||
width: WIDTH,
|
||||
height: HEIGHT,
|
||||
name: process.env.DEV && 'EnvironmentMap/swap1',
|
||||
} ),
|
||||
);
|
||||
|
||||
// -- post -------------------------------------------------------------------------------------
|
||||
const material = new Material(
|
||||
quadVert,
|
||||
environmentMapFrag,
|
||||
);
|
||||
material.addUniform( 'uniformSeed', '4f', rng.gen(), rng.gen(), rng.gen(), rng.gen() );
|
||||
material.addUniformTexture( 'sampler0', this.swap.i.texture );
|
||||
|
||||
if ( process.env.DEV ) {
|
||||
if ( module.hot ) {
|
||||
module.hot.accept( '../shaders/environment-map.frag', () => {
|
||||
material.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( quad );
|
||||
}
|
||||
}
|
80
src/entities/IBLLUT.ts
Normal file
80
src/entities/IBLLUT.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import { Entity } from '../heck/Entity';
|
||||
import { GLCatTexture } from '@fms-cat/glcat-ts';
|
||||
import { Material } from '../heck/Material';
|
||||
import { Quad } from '../heck/components/Quad';
|
||||
import iblLutFrag from '../shaders/ibl-lut.frag';
|
||||
import quadVert from '../shaders/quad.vert';
|
||||
import { BufferRenderTarget } from '../heck/BufferRenderTarget';
|
||||
import { Swap } from '@fms-cat/experimental';
|
||||
import { Lambda } from '../heck/components/Lambda';
|
||||
import { vdc } from '../utils/vdc';
|
||||
|
||||
const IBL_SIZE = 256;
|
||||
|
||||
export class IBLLUT {
|
||||
public entity: Entity;
|
||||
|
||||
public swap: Swap<BufferRenderTarget>;
|
||||
|
||||
public get texture(): GLCatTexture<WebGL2RenderingContext> {
|
||||
return this.swap.o.texture;
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
this.entity = new Entity();
|
||||
this.entity.visible = false;
|
||||
|
||||
// -- swap -------------------------------------------------------------------------------------
|
||||
this.swap = new Swap(
|
||||
new BufferRenderTarget( {
|
||||
width: IBL_SIZE,
|
||||
height: IBL_SIZE,
|
||||
name: process.env.DEV && 'IBLLUT/swap0',
|
||||
} ),
|
||||
new BufferRenderTarget( {
|
||||
width: IBL_SIZE,
|
||||
height: IBL_SIZE,
|
||||
name: process.env.DEV && 'IBLLUT/swap1',
|
||||
} ),
|
||||
);
|
||||
|
||||
// -- post -------------------------------------------------------------------------------------
|
||||
let samples = 0.0;
|
||||
|
||||
const material = new Material(
|
||||
quadVert,
|
||||
iblLutFrag,
|
||||
);
|
||||
material.addUniform( 'samples', '1f', samples );
|
||||
material.addUniform( 'vdc', '1f', vdc( samples, 2.0 ) );
|
||||
material.addUniformTexture( 'sampler0', this.swap.i.texture );
|
||||
|
||||
const quad = new Quad( {
|
||||
target: this.swap.o,
|
||||
material,
|
||||
name: process.env.DEV && 'IBLLUT/quad',
|
||||
} );
|
||||
|
||||
// -- swapper ----------------------------------------------------------------------------------
|
||||
this.entity.components.push( new Lambda( {
|
||||
onUpdate: () => {
|
||||
samples ++;
|
||||
this.swap.swap();
|
||||
|
||||
if ( samples > 1024 ) {
|
||||
this.entity.active = false;
|
||||
} else {
|
||||
material.addUniform( 'samples', '1f', samples );
|
||||
material.addUniform( 'vdc', '1f', vdc( samples, 2.0 ) );
|
||||
material.addUniformTexture( 'sampler0', this.swap.i.texture );
|
||||
|
||||
quad.target = this.swap.o;
|
||||
}
|
||||
},
|
||||
visible: false,
|
||||
name: process.env.DEV && 'IBLLUT/swapper',
|
||||
} ) );
|
||||
|
||||
this.entity.components.push( quad );
|
||||
}
|
||||
}
|
37
src/main.ts
37
src/main.ts
@@ -24,6 +24,8 @@ import { RTInspector } from './entities/RTInspector';
|
||||
import { Component } from './heck/components/Component';
|
||||
import { FlickyParticles } from './entities/FlickyParticles';
|
||||
import { PixelSorter } from './entities/PixelSorter';
|
||||
import { IBLLUT } from './entities/IBLLUT';
|
||||
import { EnvironmentMap } from './entities/EnvironmentMap';
|
||||
|
||||
// == music ========================================================================================
|
||||
const audio = new AudioContext();
|
||||
@@ -193,6 +195,13 @@ dog.root.components.push( new Lambda( {
|
||||
name: process.env.DEV && 'main/update',
|
||||
} ) );
|
||||
|
||||
// -- bake -----------------------------------------------------------------------------------------
|
||||
const ibllut = new IBLLUT();
|
||||
dog.root.children.push( ibllut.entity );
|
||||
|
||||
const environmentMap = new EnvironmentMap();
|
||||
dog.root.children.push( environmentMap.entity );
|
||||
|
||||
// -- "objects" ------------------------------------------------------------------------------------
|
||||
const sphereParticles = new SphereParticles( {
|
||||
particlesSqrt: 256,
|
||||
@@ -201,13 +210,13 @@ const sphereParticles = new SphereParticles( {
|
||||
} );
|
||||
dog.root.children.push( sphereParticles.entity );
|
||||
|
||||
const trails = new Trails( {
|
||||
trails: 4096,
|
||||
trailLength: 64,
|
||||
textureRandom: randomTexture.texture,
|
||||
textureRandomStatic: randomTextureStatic.texture
|
||||
} );
|
||||
dog.root.children.push( trails.entity );
|
||||
// const trails = new Trails( {
|
||||
// trails: 4096,
|
||||
// trailLength: 64,
|
||||
// textureRandom: randomTexture.texture,
|
||||
// textureRandomStatic: randomTextureStatic.texture
|
||||
// } );
|
||||
// dog.root.children.push( trails.entity );
|
||||
|
||||
const rings = new Rings();
|
||||
dog.root.children.push( rings.entity );
|
||||
@@ -219,11 +228,11 @@ const flickyParticles = new FlickyParticles( {
|
||||
} );
|
||||
dog.root.children.push( flickyParticles.entity );
|
||||
|
||||
const raymarcher = new Raymarcher( {
|
||||
textureRandom: randomTexture.texture,
|
||||
textureRandomStatic: randomTextureStatic.texture
|
||||
} );
|
||||
dog.root.children.push( raymarcher.entity );
|
||||
// const raymarcher = new Raymarcher( {
|
||||
// textureRandom: randomTexture.texture,
|
||||
// textureRandomStatic: randomTextureStatic.texture
|
||||
// } );
|
||||
// dog.root.children.push( raymarcher.entity );
|
||||
|
||||
// -- things that is not an "object" ---------------------------------------------------------------
|
||||
const swapOptions = {
|
||||
@@ -249,7 +258,7 @@ const light = new LightEntity( {
|
||||
shadowMapFar: 20.0,
|
||||
namePrefix: process.env.DEV && 'light1',
|
||||
} );
|
||||
light.color = [ 60.0, 60.0, 60.0 ];
|
||||
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 );
|
||||
|
||||
@@ -271,6 +280,8 @@ const camera = new CameraEntity( {
|
||||
light,
|
||||
// light2
|
||||
],
|
||||
textureIBLLUT: ibllut.texture,
|
||||
textureEnv: environmentMap.texture,
|
||||
textureRandom: randomTexture.texture
|
||||
} );
|
||||
camera.camera.clear = [ 0.0, 0.0, 0.0, 0.0 ];
|
||||
|
@@ -9,12 +9,16 @@ out vec4 fragColor;
|
||||
uniform sampler2D samplerDry;
|
||||
uniform sampler2D samplerWet;
|
||||
|
||||
vec4 sampleLOD( vec2 uv, float lv ) {
|
||||
float p = pow( 0.5, float( lv ) );
|
||||
vec2 uvt = mix( vec2( 1.0 - p ), vec2( 1.0 - 0.5 * p ), uv );
|
||||
return texture( samplerWet, uvt );
|
||||
}
|
||||
|
||||
void main() {
|
||||
fragColor = texture( samplerDry, vUv );
|
||||
for ( int i = 0; i < 5; i ++ ) {
|
||||
float fuck = pow( 0.5, float( i ) );
|
||||
vec2 suv = mix( vec2( 1.0 - fuck ), vec2( 1.0 - 0.5 * fuck ), vUv );
|
||||
fragColor += texture( samplerWet, suv );
|
||||
fragColor += sampleLOD( vUv, float( i ) );
|
||||
}
|
||||
fragColor.xyz = max( vec3( 0.0 ), fragColor.xyz );
|
||||
}
|
||||
|
119
src/shaders/environment-map.frag
Normal file
119
src/shaders/environment-map.frag
Normal file
@@ -0,0 +1,119 @@
|
||||
#version 300 es
|
||||
|
||||
// https://learnopengl.com/PBR/IBL/Specular-IBL
|
||||
|
||||
precision highp float;
|
||||
|
||||
#define saturate(x) clamp(x,0.,1.)
|
||||
#define linearstep(a,b,x) saturate(((x)-(a))/((b)-(a)))
|
||||
|
||||
#pragma glslify: prng = require( ./-prng );
|
||||
|
||||
const int SAMPLES = 16;
|
||||
const float UV_MARGIN = 0.9;
|
||||
const float PI = 3.14159265;
|
||||
const float TAU = 6.283185307;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform float head;
|
||||
uniform vec2 resolution;
|
||||
uniform vec4 uniformSeed;
|
||||
uniform sampler2D sampler0;
|
||||
|
||||
vec4 seed;
|
||||
|
||||
float vdc( float i, float base ) {
|
||||
float r = 0.0;
|
||||
float denom = 1.0;
|
||||
|
||||
for ( int j = 0; j < 32; j ++ ) {
|
||||
denom *= base;
|
||||
r += mod( i, base ) / denom;
|
||||
i = floor( i / base );
|
||||
|
||||
if ( i <= 0.0 ) { break; }
|
||||
}
|
||||
|
||||
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 ) {
|
||||
bool circ = dot( L, normalize( vec3( 1.0, 3.0, 3.0 ) ) ) > 0.9;
|
||||
vec3 c = circ ? 0.01 * vec3( 0.1, 0.1, 1.0 ) : vec3( 0.0 );
|
||||
|
||||
bool ring = abs( dot( L, vec3( 0.0, 1.0, 0.0 ) ) ) < 0.1;
|
||||
c += ring ? 10.0 * vec3( 0.1, 1.0, 0.3 ) : vec3( 0.0 );
|
||||
|
||||
return c;
|
||||
// return 0.5 + 0.5 * L;
|
||||
}
|
||||
|
||||
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 );
|
||||
vec2 uv00 = floor( vUv / p ) * p;
|
||||
vec2 uv11 = uv00 + p;
|
||||
vec2 uv = clamp( vUv, uv00 + halfTexel, uv11 - halfTexel );
|
||||
uv = linearstep( uv00, uv11, uv );
|
||||
uv = ( uv - 0.5 ) / UV_MARGIN + 0.5;
|
||||
|
||||
vec3 tex = texture( sampler0, vUv ).xyz;
|
||||
float roughness = lv * 0.2;
|
||||
|
||||
float a = TAU * uv.x;
|
||||
float b = PI * ( uv.y - 0.5 );
|
||||
vec3 N = vec3( sin( a ) * cos( b ), -sin( b ), -cos( a ) * cos( b ) );
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
|
||||
seed = uniformSeed + N.xyzx;
|
||||
|
||||
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 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.xyz = col.w <= 0.001 ? vec3( 0.0 ) : ( col.xyz / col.w );
|
||||
|
||||
tex.xyz = mix( tex.xyz, col.xyz, 1.0 / 16.0 );
|
||||
|
||||
fragColor = vec4( tex, 1.0 );
|
||||
}
|
90
src/shaders/ibl-lut.frag
Normal file
90
src/shaders/ibl-lut.frag
Normal file
@@ -0,0 +1,90 @@
|
||||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
const float TAU = 6.283185307;
|
||||
|
||||
in vec2 vUv;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform float samples;
|
||||
uniform float vdc;
|
||||
uniform sampler2D sampler0;
|
||||
|
||||
vec3 ImportanceSampleGGX( vec2 Xi, float roughness, vec3 N ) {
|
||||
float a = roughness * roughness;
|
||||
|
||||
float phi = TAU * Xi.x;
|
||||
float cosTheta = 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 );
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX( float NdotV, float roughness ) {
|
||||
float a = roughness;
|
||||
float k = ( a * a ) / 2.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * ( 1.0 - k ) + k;
|
||||
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
float GeometrySmith( float roughness, float NoV, float NoL ) {
|
||||
float ggx2 = GeometrySchlickGGX( NoV, roughness );
|
||||
float ggx1 = GeometrySchlickGGX( NoL, roughness );
|
||||
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
// https://github.com/HectorMF/BRDFGenerator/blob/master/BRDFGenerator/BRDFGenerator.cpp
|
||||
vec2 IntegrateBRDF( float NdotV, float roughness ) {
|
||||
vec3 V = vec3( sqrt( 1.0 - NdotV * NdotV ), 0.0, NdotV );
|
||||
vec3 N = vec3( 0.0, 0.0, 1.0 );
|
||||
|
||||
vec2 Xi = vec2( samples / 1024.0, vdc );
|
||||
vec3 H = ImportanceSampleGGX( Xi, roughness, N );
|
||||
vec3 L = normalize( 2.0 * dot( V, H ) * H - V );
|
||||
|
||||
float NoL = max( L.z, 0.0 );
|
||||
float NoH = max( H.z, 0.0 );
|
||||
float VoH = max( dot( V, H ), 0.0 );
|
||||
float NoV = max( dot( N, V ), 0.0 );
|
||||
|
||||
if ( NoL > 0.0 ) {
|
||||
float G = GeometrySmith( roughness, NoV, NoL );
|
||||
|
||||
float G_Vis = ( G * VoH ) / ( NoH * NoV );
|
||||
float Fc = pow( 1.0 - VoH, 5.0 );
|
||||
|
||||
return vec2( ( 1.0 - Fc ) * G_Vis, Fc * G_Vis );
|
||||
}
|
||||
|
||||
return vec2( 0.0 );
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 tex = texture( sampler0, vUv ).xy;
|
||||
|
||||
float NdotV = vUv.y;
|
||||
float roughness = vUv.x;
|
||||
|
||||
tex = mix( tex, IntegrateBRDF( NdotV, roughness ), 1.0 / samples );
|
||||
|
||||
fragColor = vec4( tex, 0.0, 1.0 );
|
||||
}
|
@@ -70,7 +70,7 @@ void main() {
|
||||
}
|
||||
|
||||
vec3 normal = normalFunc( rayPos, 1E-4 );
|
||||
vec4 color = vec4( 0.1, 0.2, 0.4, 1.0 );
|
||||
vec4 color = vec4( 0.4, 0.7, 0.9, 1.0 );
|
||||
|
||||
vec4 projPos = projectionMatrix * viewMatrix * vec4( rayPos, 1.0 ); // terrible
|
||||
float depth = projPos.z / projPos.w;
|
||||
@@ -79,5 +79,5 @@ void main() {
|
||||
fragPosition = vec4( rayPos, depth );
|
||||
fragNormal = vec4( normal, 1.0 );
|
||||
fragColor = color;
|
||||
fragWTF = vec4( vec3( 2.0, 0.9, 0.9 ), MTL_IRIDESCENT );
|
||||
fragWTF = vec4( vec3( 0.8, 0.8, 0.0 ), MTL_PBR );
|
||||
}
|
||||
|
@@ -8,6 +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 AO_BIAS = 0.0;
|
||||
const float AO_RADIUS = 0.5;
|
||||
const float PI = 3.14159265359;
|
||||
@@ -36,7 +37,7 @@ uniform sampler2D sampler1; // normal.xyz (yes, this is not good)
|
||||
uniform sampler2D sampler2; // color.rgba (what is a though????)
|
||||
uniform sampler2D sampler3; // materialParams.xyz, materialId
|
||||
uniform sampler2D samplerShadow;
|
||||
uniform sampler2D samplerBRDFLUT;
|
||||
uniform sampler2D samplerIBLLUT;
|
||||
uniform sampler2D samplerEnv;
|
||||
uniform sampler2D samplerAo;
|
||||
uniform sampler2D samplerRandom;
|
||||
@@ -86,6 +87,21 @@ vec3 blurpleGradient( float t ) {
|
||||
);
|
||||
}
|
||||
|
||||
vec4 sampleEnvNearest( vec2 uv, float lv ) {
|
||||
float p = pow( 0.5, float( lv ) );
|
||||
vec2 uvt = ENV_UV_MARGIN * ( uv - 0.5 ) + 0.5;
|
||||
uvt = mix( vec2( 1.0 - p ), vec2( 1.0 - 0.5 * p ), uvt );
|
||||
return texture( samplerEnv, uvt );
|
||||
}
|
||||
|
||||
vec4 sampleEnvLinear( vec2 uv, float lv ) {
|
||||
return mix(
|
||||
sampleEnvNearest( uv, floor( lv ) ),
|
||||
sampleEnvNearest( uv, floor( lv + 1.0 ) ),
|
||||
fract( lv )
|
||||
);
|
||||
}
|
||||
|
||||
// == structs ======================================================================================
|
||||
struct Isect {
|
||||
vec2 screenUv;
|
||||
@@ -188,16 +204,18 @@ vec3 shadePBR( Isect isect, AngularInfo aI ) {
|
||||
vec3 color = shade;
|
||||
|
||||
#ifdef IS_FIRST_LIGHT
|
||||
// vec3 refl = reflect( aI.V, isect.normal );
|
||||
// vec2 envCoord = vec2(
|
||||
// 0.5 + atan( refl.z, refl.x ) / TAU,
|
||||
// 0.5 + atan( refl.y, length( refl.zx ) ) / PI
|
||||
// );
|
||||
// vec2 brdf = texture( samplerBRDFLUT, vec2( aI.dotNV, 1.0 - roughness ) ).xy;
|
||||
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
|
||||
);
|
||||
|
||||
// vec3 texEnv = 0.2 * pow( texture( samplerEnv, envCoord ).rgb, vec3( 2.2 ) );
|
||||
// color += PI * texEnv * ( brdf.x * F0 + brdf.y );
|
||||
// reflective ibl
|
||||
vec2 brdf = texture( samplerIBLLUT, vec2( aI.dotNV, 1.0 - roughness ) ).xy;
|
||||
vec3 texEnv = 0.2 * sampleEnvLinear( envUv, 5.0 * roughness ).rgb;
|
||||
color += PI * ao * texEnv * ( brdf.x * F0 + brdf.y );
|
||||
|
||||
// emissive
|
||||
color += emissive * aI.dotNV * isect.albedo;
|
||||
#endif // IS_FIRST_LIGHT
|
||||
|
||||
|
@@ -38,5 +38,5 @@ void main() {
|
||||
fragPosition = vPosition;
|
||||
fragNormal = vec4( vNormal, 1.0 );
|
||||
fragColor = vec4( vColor.xyz, 1.0 );
|
||||
fragWTF = vec4( vec3( 0.8, 0.8, 0.0 ), MTL_PBR );
|
||||
fragWTF = vec4( vec3( 0.4, 0.4, 0.0 ), MTL_PBR );
|
||||
}
|
||||
|
@@ -83,15 +83,15 @@ void main() {
|
||||
size *= sin( PI * saturate( vLife ) );
|
||||
|
||||
vec3 shape = position * size;
|
||||
shape.yz = rotate2D( 7.0 * vPosition.x ) * shape.yz;
|
||||
shape.zx = rotate2D( 7.0 * vPosition.y ) * shape.zx;
|
||||
shape.yz = rotate2D( 7.0 * ( vPosition.x + vDice.z ) ) * shape.yz;
|
||||
shape.zx = rotate2D( 7.0 * ( vPosition.y + vDice.w ) ) * shape.zx;
|
||||
|
||||
vPosition.xyz += shape;
|
||||
|
||||
// == compute normals ============================================================================
|
||||
vNormal = ( normalMatrix * vec4( normal, 1.0 ) ).xyz;
|
||||
vNormal.yz = rotate2D( 7.0 * vPosition.x ) * vNormal.yz;
|
||||
vNormal.zx = rotate2D( 7.0 * vPosition.y ) * vNormal.zx;
|
||||
vNormal.yz = rotate2D( 7.0 * ( vPosition.x + vDice.z ) ) * vNormal.yz;
|
||||
vNormal.zx = rotate2D( 7.0 * ( vPosition.y + vDice.w ) ) * vNormal.zx;
|
||||
|
||||
// == send the vertex position ===================================================================
|
||||
vPosition = modelMatrix * vPosition;
|
||||
|
18
src/utils/vdc.ts
Normal file
18
src/utils/vdc.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Generate a number using Van der Corput sequence.
|
||||
* e.g. vdc(i, 2) = 1/2, 1/4, 3/4, 1/8, 5/8, 3/8, 7/8, 1/16, ...
|
||||
* @param i Index of the sequence
|
||||
* @param base Base of the sequence
|
||||
*/
|
||||
export function vdc( i: number, base: number ) {
|
||||
let r = 0;
|
||||
let denom = 1;
|
||||
|
||||
while ( 0 < i ) {
|
||||
denom *= base;
|
||||
r += ( i % base ) / denom;
|
||||
i = Math.floor( i / base );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
Reference in New Issue
Block a user