added pbr-pathtracing
This commit is contained in:
parent
a6e826f7f9
commit
c4d3854b27
|
@ -0,0 +1,208 @@
|
||||||
|
|
||||||
|
#define SAMPLES 8
|
||||||
|
#define BOUNCES 8
|
||||||
|
|
||||||
|
// sphere of size ra centered at point ce
|
||||||
|
vec2 sphIntersect(in vec3 ro, in vec3 rd, in vec3 ce, float ra)
|
||||||
|
{
|
||||||
|
vec3 oc = ro - ce;
|
||||||
|
float b = dot( oc, rd );
|
||||||
|
vec3 qc = oc - b*rd;
|
||||||
|
float h = ra*ra - dot( qc, qc );
|
||||||
|
if( h<0.0 ) return vec2(-1.0); // no intersection
|
||||||
|
h = sqrt( h );
|
||||||
|
return vec2( -b-h, -b+h );
|
||||||
|
}
|
||||||
|
|
||||||
|
// disk center c, normal n, radius r
|
||||||
|
float diskIntersect( in vec3 ro, in vec3 rd, vec3 c, vec3 n, float r )
|
||||||
|
{
|
||||||
|
vec3 o = ro - c;
|
||||||
|
float t = -dot(n,o)/dot(rd,n);
|
||||||
|
vec3 q = o + rd*t;
|
||||||
|
return (dot(q,q)<r*r) ? t : -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mat {
|
||||||
|
vec3 emission;
|
||||||
|
vec3 albedo;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Mat WHITE = Mat(vec3(0), vec3(0.89));
|
||||||
|
const Mat LIGHT = Mat(vec3(4, 2, 0) * 32.0, vec3(0));
|
||||||
|
const Mat LIGHT2 = Mat(vec3(0, 4, 2) * 32.0, vec3(0));
|
||||||
|
|
||||||
|
struct hit {
|
||||||
|
vec3 nor;
|
||||||
|
float t;
|
||||||
|
Mat mat;
|
||||||
|
} Hit;
|
||||||
|
|
||||||
|
void intersect_sp(in vec3 ro, in vec3 rd, in vec3 o, in float r, in Mat mat)
|
||||||
|
{
|
||||||
|
vec2 hit = sphIntersect(ro, rd, o, r);
|
||||||
|
float d = hit.x;
|
||||||
|
|
||||||
|
if (hit.x < 1e-3)
|
||||||
|
d = hit.y;
|
||||||
|
|
||||||
|
if (d < Hit.t && d > 1e-3)
|
||||||
|
{
|
||||||
|
Hit.t = d;
|
||||||
|
Hit.nor = normalize(ro + rd * d - o);
|
||||||
|
Hit.mat = mat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void intersect_disk(in vec3 ro, in vec3 rd, in vec3 o, in vec3 n, in float r, in Mat mat)
|
||||||
|
{
|
||||||
|
float d = diskIntersect(ro, rd, o, n, r);
|
||||||
|
|
||||||
|
if (d < Hit.t && d > 1e-3)
|
||||||
|
{
|
||||||
|
Hit.t = d;
|
||||||
|
Hit.nor = n;
|
||||||
|
Hit.mat = mat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void intersect(in vec3 ro, in vec3 rd)
|
||||||
|
{
|
||||||
|
Hit.t = 1e3;
|
||||||
|
|
||||||
|
intersect_sp(ro, rd, vec3(0,1,0), 1.0, WHITE);
|
||||||
|
intersect_sp(ro, rd, vec3(2,1,0), 1.0, WHITE);
|
||||||
|
intersect_sp(ro, rd, vec3(2,3,-0.5), 0.5, LIGHT);
|
||||||
|
intersect_sp(ro, rd, vec3(-2,4,+0.5), 0.5, LIGHT2);
|
||||||
|
intersect_sp(ro, rd, vec3(0,3,0), 1.0, WHITE);
|
||||||
|
intersect_disk(ro, rd, vec3(0,0,0), vec3(0,1,0), 4.0, WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 cosine_hemisphere(in float ra)
|
||||||
|
{
|
||||||
|
float u1 = gold_noise();
|
||||||
|
float u2 = gold_noise();
|
||||||
|
|
||||||
|
float r = sqrt(u1) * ra;
|
||||||
|
float theta = 2.0 * PI * u2;
|
||||||
|
|
||||||
|
float x = r * cos(theta);
|
||||||
|
float y = r * sin(theta);
|
||||||
|
|
||||||
|
return vec3(x, y, sqrt(1.0 - u1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// project vector b onto vector a
|
||||||
|
vec3 project(in vec3 a, in vec3 b) {
|
||||||
|
return a * (dot(a, b) / dot(a, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct a 3D coordinate system with the input up being the "upwards" facing vector
|
||||||
|
// which will be directly stored in w.
|
||||||
|
// Mathematically this function will create two non linear vectors of up and generate an orthonormal
|
||||||
|
// basis using gram-schmidt.
|
||||||
|
// This function assumes "up" being already normalized
|
||||||
|
void construct_orthonormal_basis(in vec3 up, out vec3 u, out vec3 v, out vec3 w) {
|
||||||
|
w = up;
|
||||||
|
|
||||||
|
vec3 n2 = normalize(cross(w, vec3(0, 1, 1))); // build perpendicular vector from w
|
||||||
|
vec3 n3 = cross(w, n2); // create 2nd vector perpendicular to w and n2
|
||||||
|
|
||||||
|
// gram schmidt
|
||||||
|
u = n2 - (project(w, n2));
|
||||||
|
v = n3 - project(w, n3) - project(u, n3);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gen_diffuse(in vec3 normal, in vec3 incident) {
|
||||||
|
vec3 hemisphere = cosine_hemisphere(1.0);
|
||||||
|
|
||||||
|
vec3 u, v, w;
|
||||||
|
construct_orthonormal_basis(normal, u, v, w);
|
||||||
|
|
||||||
|
return u * hemisphere.x + v * hemisphere.y + w * hemisphere.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 gen_reflection(in vec3 normal, in vec3 incident, in float roughness) {
|
||||||
|
vec3 hemisphere = cosine_hemisphere(roughness);
|
||||||
|
|
||||||
|
vec3 u, v, w;
|
||||||
|
construct_orthonormal_basis(reflect(incident, normal), u, v, w);
|
||||||
|
|
||||||
|
return u * hemisphere.x + v * hemisphere.y + w * hemisphere.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
float schlick(in float cosTheta, in float R0) {
|
||||||
|
return R0 + (1.0 - R0) * pow(1.0 - cosTheta, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float R0(in float ior) {
|
||||||
|
float a = (ior - 1.0);
|
||||||
|
float b = (ior + 1.0);
|
||||||
|
return (a * a) / (b * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 trace_path(in vec3 ro, in vec3 rd)
|
||||||
|
{
|
||||||
|
vec3 rad = vec3(1);
|
||||||
|
vec3 acc = vec3(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < BOUNCES; i++)
|
||||||
|
{
|
||||||
|
intersect(ro, rd);
|
||||||
|
if (Hit.t < 1e3)
|
||||||
|
{
|
||||||
|
float cosTheta = abs(dot(rd, Hit.nor));
|
||||||
|
float pdf = cosTheta * INV_PI;
|
||||||
|
|
||||||
|
acc += rad * Hit.mat.emission * pdf;
|
||||||
|
|
||||||
|
ro = ro + rd * Hit.t;
|
||||||
|
|
||||||
|
if (schlick(cosTheta, R0(1.450)) < gold_noise())
|
||||||
|
{
|
||||||
|
rd = gen_diffuse(Hit.nor, rd);
|
||||||
|
rad *= Hit.mat.albedo;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
rd = gen_reflection(Hit.nor, rd, 0.05);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
acc += rad * pow(texture(iChannel1, rd).rgb, vec3(2.0)) * 8.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
init_random_state(fragCoord.xy, iTime);
|
||||||
|
|
||||||
|
vec2 taa_off = vec2(gold_noise(), gold_noise()) * 1.5 - 0.5;
|
||||||
|
vec2 uv = (fragCoord + taa_off - 0.5 * iResolution.xy) / iResolution.y;
|
||||||
|
|
||||||
|
vec3 col = vec3(0);
|
||||||
|
|
||||||
|
float s = sin(iTime);
|
||||||
|
float c = cos(iTime);
|
||||||
|
mat2 r = mat2(c, -s, s, c);
|
||||||
|
|
||||||
|
vec3 rd = normalize(vec3(uv, 1.0));
|
||||||
|
vec3 ro = vec3(0,2,-8.0);
|
||||||
|
float t = 0.01;
|
||||||
|
|
||||||
|
rd.xz *= r;
|
||||||
|
ro.xz *= r;
|
||||||
|
|
||||||
|
for (int i = 0; i < SAMPLES; i++) {
|
||||||
|
col += trace_path(ro, rd);
|
||||||
|
}
|
||||||
|
col /= float(SAMPLES);
|
||||||
|
|
||||||
|
vec3 prev = texture(iChannel0, fragCoord/iResolution.xy).rgb;
|
||||||
|
|
||||||
|
fragColor = vec4(mix(prev, col, 0.3) ,1.0);
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
void aces_approx(inout vec3 col)
|
||||||
|
{
|
||||||
|
col *= 0.4f;
|
||||||
|
float a = 2.51f;
|
||||||
|
float b = 0.03f;
|
||||||
|
float c = 2.43f;
|
||||||
|
float d = 0.59f;
|
||||||
|
float e = 0.14f;
|
||||||
|
col = clamp((col * (a * col + b)) / (col * (c * col + d) + e), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
init_random_state(fragCoord.xy, iTime);
|
||||||
|
|
||||||
|
vec2 uv = fragCoord/iResolution.xy;
|
||||||
|
vec3 col = texture(iChannel0, uv).rgb;
|
||||||
|
|
||||||
|
aces_approx(col);
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
const float PHI = 1.61803398874989484820459; // Φ = Golden Ratio
|
||||||
|
const float INV_PI = 0.31830988618379067153776752674503;
|
||||||
|
const float INV_SQRT_OF_2PI = 0.39894228040143267793994605993439;
|
||||||
|
const float PI = 3.141592653589793;
|
||||||
|
|
||||||
|
float seed = 0.0;
|
||||||
|
vec2 xy = vec2(0.0);
|
||||||
|
|
||||||
|
// based on https://www.shadertoy.com/view/ltB3zD
|
||||||
|
//
|
||||||
|
// Gold Noise ©2015 dcerisano@standard3d.com
|
||||||
|
// - based on the Golden Ratio
|
||||||
|
// - uniform normalized distribution
|
||||||
|
// - fastest static noise generator function (also runs at low precision)
|
||||||
|
// - use with indicated fractional seeding method.
|
||||||
|
float gold_noise(){
|
||||||
|
seed += 0.1;
|
||||||
|
return fract(tan(distance(xy * PHI, xy) * seed)*xy.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_random_state(in vec2 st, in float s)
|
||||||
|
{
|
||||||
|
xy = st;
|
||||||
|
seed = s * 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
float luminance(in vec3 col)
|
||||||
|
{
|
||||||
|
return dot(col, vec3(0.2126, 0.7152, 0.0722));
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
|
||||||
|
#define DENOISE
|
||||||
|
#define FILM_GRAIN
|
||||||
|
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// Copyright (c) 2018-2019 Michele Morrone
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// https://michelemorrone.eu - https://BrutPitt.com
|
||||||
|
//
|
||||||
|
// me@michelemorrone.eu - brutpitt@gmail.com
|
||||||
|
// twitter: @BrutPitt - github: BrutPitt
|
||||||
|
//
|
||||||
|
// https://github.com/BrutPitt/glslSmartDeNoise/
|
||||||
|
//
|
||||||
|
// This software is distributed under the terms of the BSD 2-Clause license
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
// smartDeNoise - parameters
|
||||||
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
//
|
||||||
|
// sampler2D tex - sampler image / texture
|
||||||
|
// vec2 uv - actual fragment coord
|
||||||
|
// float sigma > 0 - sigma Standard Deviation
|
||||||
|
// float kSigma >= 0 - sigma coefficient
|
||||||
|
// kSigma * sigma --> radius of the circular kernel
|
||||||
|
// float threshold - edge sharpening threshold
|
||||||
|
vec4 smart_de_noise(in sampler2D tex, vec2 uv, float sigma, float kSigma, float threshold)
|
||||||
|
{
|
||||||
|
float radius = round(kSigma*sigma);
|
||||||
|
float radQ = radius * radius;
|
||||||
|
|
||||||
|
float invSigmaQx2 = 0.5 / (sigma * sigma); // 1.0 / (sigma^2 * 2.0)
|
||||||
|
float invSigmaQx2PI = INV_PI * invSigmaQx2; // 1/(2 * PI * sigma^2)
|
||||||
|
|
||||||
|
float invThresholdSqx2 = .5 / (threshold * threshold); // 1.0 / (sigma^2 * 2.0)
|
||||||
|
float invThresholdSqrt2PI = INV_SQRT_OF_2PI / threshold; // 1.0 / (sqrt(2*PI) * sigma^2)
|
||||||
|
|
||||||
|
vec4 centrPx = texture(tex,uv);
|
||||||
|
|
||||||
|
float zBuff = 0.0;
|
||||||
|
vec4 aBuff = vec4(0.0);
|
||||||
|
vec2 size = vec2(textureSize(tex, 0));
|
||||||
|
|
||||||
|
vec2 d;
|
||||||
|
for (d.x=-radius; d.x <= radius; d.x++) {
|
||||||
|
float pt = sqrt(radQ-d.x*d.x); // pt = yRadius: have circular trend
|
||||||
|
for (d.y=-pt; d.y <= pt; d.y++) {
|
||||||
|
float blurFactor = exp( -dot(d , d) * invSigmaQx2 ) * invSigmaQx2PI;
|
||||||
|
|
||||||
|
vec4 walkPx = texture(tex,uv+d/size);
|
||||||
|
vec4 dC = walkPx-centrPx;
|
||||||
|
float deltaFactor = exp( -dot(dC, dC) * invThresholdSqx2) * invThresholdSqrt2PI * blurFactor;
|
||||||
|
|
||||||
|
zBuff += deltaFactor;
|
||||||
|
aBuff += deltaFactor*walkPx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aBuff/zBuff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||||
|
{
|
||||||
|
init_random_state(fragCoord.xy, iTime);
|
||||||
|
|
||||||
|
#ifdef DENOISE
|
||||||
|
vec3 col = smart_de_noise(iChannel0, fragCoord/iResolution.xy, 10.0, 1.0, 0.2).rgb;
|
||||||
|
#else
|
||||||
|
vec3 col = texture(iChannel0, fragCoord/iResolution.xy).rgb;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef FILM_GRAIN
|
||||||
|
float strength = 0.4;
|
||||||
|
vec3 noise = vec3(gold_noise(), gold_noise(), gold_noise());
|
||||||
|
col = pow(col, noise * strength + 1.0) + pow(noise, vec3(strength)) * strength * 0.5;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fragColor = vec4(col, 1.0);
|
||||||
|
}
|
Loading…
Reference in New Issue