Created
August 26, 2022 03:05
-
-
Save erichlof/a806e8b6b0b6ba3daf2c157f101e2a81 to your computer and use it in GitHub Desktop.
A simple example of adding UBOs to a demo's fragment shader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
#include <pathtracing_uniforms_and_defines> | |
uniform mat4 uTorusInvMatrix; | |
uniform InvMatrices_UniformGroup { | |
mat4 u_InvMatrices[64]; | |
}; | |
uniform TopLevelBVH_UniformGroup { | |
vec4 u_AABBData[256]; | |
}; | |
#define N_LIGHTS 3.0 | |
#define N_SPHERES 6 | |
#define N_PLANES 1 | |
#define N_DISKS 1 | |
#define N_TRIANGLES 1 | |
#define N_QUADS 1 | |
#define N_BOXES 2 | |
#define N_ELLIPSOIDS 1 | |
#define N_PARABOLOIDS 1 | |
#define N_OPENCYLINDERS 1 | |
#define N_CAPPEDCYLINDERS 1 | |
#define N_CONES 1 | |
#define N_CAPSULES 1 | |
#define N_TORII 1 | |
//----------------------------------------------------------------------- | |
vec3 rayOrigin, rayDirection; | |
// recorded intersection data: | |
vec3 hitNormal, hitEmission, hitColor; | |
vec2 hitUV; | |
float hitObjectID; | |
int hitType = -100; | |
struct Sphere { float radius; vec3 position; vec3 emission; vec3 color; int type; }; | |
struct Ellipsoid { vec3 radii; vec3 position; vec3 emission; vec3 color; int type; }; | |
struct Paraboloid { float rad; float height; vec3 pos; vec3 emission; vec3 color; int type; }; | |
struct OpenCylinder { float radius; float height; vec3 position; vec3 emission; vec3 color; int type; }; | |
struct CappedCylinder { float radius; vec3 cap1pos; vec3 cap2pos; vec3 emission; vec3 color; int type; }; | |
struct Cone { vec3 pos0; float radius0; vec3 pos1; float radius1; vec3 emission; vec3 color; int type; }; | |
struct Capsule { vec3 pos0; float radius0; vec3 pos1; float radius1; vec3 emission; vec3 color; int type; }; | |
struct UnitTorus { float parameterK; vec3 emission; vec3 color; int type; }; | |
struct Box { vec3 minCorner; vec3 maxCorner; vec3 emission; vec3 color; int type; }; | |
Sphere spheres[N_SPHERES]; | |
Ellipsoid ellipsoids[N_ELLIPSOIDS]; | |
Paraboloid paraboloids[N_PARABOLOIDS]; | |
OpenCylinder openCylinders[N_OPENCYLINDERS]; | |
CappedCylinder cappedCylinders[N_CAPPEDCYLINDERS]; | |
Cone cones[N_CONES]; | |
Capsule capsules[N_CAPSULES]; | |
UnitTorus torii[N_TORII]; | |
Box boxes[N_BOXES]; | |
#include <pathtracing_random_functions> | |
#include <pathtracing_calc_fresnel_reflectance> | |
#include <pathtracing_sphere_intersect> | |
#include <pathtracing_unit_bounding_sphere_intersect> | |
#include <pathtracing_ellipsoid_intersect> | |
#include <pathtracing_opencylinder_intersect> | |
#include <pathtracing_cappedcylinder_intersect> | |
#include <pathtracing_cone_intersect> | |
#include <pathtracing_capsule_intersect> | |
#include <pathtracing_paraboloid_intersect> | |
#include <pathtracing_unit_torus_intersect> | |
#include <pathtracing_box_intersect> | |
#include <pathtracing_sample_sphere_light> | |
//------------------------------------------------------------------------------------------------------------------- | |
float SceneIntersect( out bool finalIsRayExiting ) | |
//------------------------------------------------------------------------------------------------------------------- | |
{ | |
vec3 rObjOrigin, rObjDirection; | |
vec3 n; | |
float d, dt; | |
float t = INFINITY; | |
bool isRayExiting = false; | |
bool insideSphere = false; | |
int objectCount = 0; | |
hitObjectID = -INFINITY; | |
for (int i = 0; i < N_SPHERES; i++) | |
{ | |
d = SphereIntersect( spheres[i].radius, spheres[i].position, rayOrigin, rayDirection ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = (rayOrigin + rayDirection * t) - spheres[i].position; | |
hitEmission = spheres[i].emission; | |
hitColor = spheres[i].color; | |
hitType = spheres[i].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
} | |
for (int i = 0; i < N_BOXES; i++) | |
{ | |
d = BoxIntersect( boxes[i].minCorner, boxes[i].maxCorner, rayOrigin, rayDirection, n, isRayExiting ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = boxes[i].emission; | |
hitColor = boxes[i].color; | |
hitType = boxes[i].type; | |
finalIsRayExiting = isRayExiting; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
} | |
d = EllipsoidIntersect( ellipsoids[0].radii, ellipsoids[0].position, rayOrigin, rayDirection ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = ((rayOrigin + rayDirection * t) - | |
ellipsoids[0].position) / (ellipsoids[0].radii * ellipsoids[0].radii); | |
hitEmission = ellipsoids[0].emission; | |
hitColor = ellipsoids[0].color; | |
hitType = ellipsoids[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
d = ParaboloidIntersect( paraboloids[0].rad, paraboloids[0].height, paraboloids[0].pos, rayOrigin, rayDirection, n ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = paraboloids[0].emission; | |
hitColor = paraboloids[0].color; | |
hitType = paraboloids[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
d = OpenCylinderIntersect( openCylinders[0].position, openCylinders[0].position + vec3(0,30,30), openCylinders[0].radius, rayOrigin, rayDirection, n ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = openCylinders[0].emission; | |
hitColor = openCylinders[0].color; | |
hitType = openCylinders[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
d = CappedCylinderIntersect( cappedCylinders[0].cap1pos, cappedCylinders[0].cap2pos, cappedCylinders[0].radius, rayOrigin, rayDirection, n); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = cappedCylinders[0].emission; | |
hitColor = cappedCylinders[0].color; | |
hitType = cappedCylinders[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
d = ConeIntersect( cones[0].pos0, cones[0].radius0, cones[0].pos1, cones[0].radius1, rayOrigin, rayDirection, n ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = cones[0].emission; | |
hitColor = cones[0].color; | |
hitType = cones[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
d = CapsuleIntersect( capsules[0].pos0, capsules[0].radius0, capsules[0].pos1, capsules[0].radius1, rayOrigin, rayDirection, n ); | |
if (d < t) | |
{ | |
t = d; | |
hitNormal = n; | |
hitEmission = capsules[0].emission; | |
hitColor = capsules[0].color; | |
hitType = capsules[0].type; | |
hitObjectID = float(objectCount); | |
} | |
objectCount++; | |
// transform ray into Torus's object space | |
rObjOrigin = vec3( uTorusInvMatrix * vec4(rayOrigin, 1.0) ); | |
rObjDirection = vec3( uTorusInvMatrix * vec4(rayDirection, 0.0) ); | |
// first check that the ray hits the bounding sphere around the torus | |
d = UnitBoundingSphereIntersect( rObjOrigin, rObjDirection, insideSphere ); | |
if (d < INFINITY) | |
{ // if outside the sphere, move the ray up close to the Torus, for numerical stability | |
d = insideSphere ? 0.0 : d; | |
rObjOrigin += rObjDirection * d; | |
dt = d + UnitTorusIntersect( rObjOrigin, rObjDirection, torii[0].parameterK, n ); | |
if (dt < t) | |
{ | |
t = dt; | |
hitNormal = transpose(mat3(uTorusInvMatrix)) * n; | |
hitEmission = torii[0].emission; | |
hitColor = torii[0].color; | |
hitType = torii[0].type; | |
hitObjectID = float(objectCount); | |
} | |
} | |
return t; | |
} // end float SceneIntersect( out bool finalIsRayExiting ) | |
//----------------------------------------------------------------------------------------------------------------------------- | |
vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float objectID, out float pixelSharpness ) | |
//----------------------------------------------------------------------------------------------------------------------------- | |
{ | |
Sphere lightChoice; | |
vec3 accumCol = vec3(0); | |
vec3 mask = vec3(1); | |
vec3 checkCol0 = vec3(1); | |
vec3 checkCol1 = vec3(0.5); | |
vec3 dirToLight; | |
vec3 tdir; | |
vec3 x, n, nl; | |
float t; | |
float nc, nt, ratioIoR, Re, Tr; | |
float P, RP, TP; | |
float weight; | |
float thickness = 0.1; | |
int diffuseCount = 0; | |
int previousIntersecType = -100; | |
hitType = -100; | |
bool coatTypeIntersected = false; | |
bool bounceIsSpecular = true; | |
bool sampleLight = false; | |
bool isRayExiting; | |
lightChoice = spheres[int(rand() * N_LIGHTS)]; | |
for (int bounces = 0; bounces < 6; bounces++) | |
{ | |
previousIntersecType = hitType; | |
t = SceneIntersect(isRayExiting); | |
/* | |
//not used in this scene because we are inside a huge sphere - no rays can escape | |
if (t == INFINITY) | |
{ | |
break; | |
} | |
*/ | |
// useful data | |
n = normalize(hitNormal); | |
nl = dot(n, rayDirection) < 0.0 ? n : -n; | |
x = rayOrigin + rayDirection * t; | |
if (bounces == 0) | |
{ | |
objectNormal = nl; | |
objectColor = hitColor; | |
objectID = hitObjectID; | |
} | |
if (hitType == LIGHT) | |
{ | |
if (diffuseCount == 0) | |
pixelSharpness = 1.01; | |
if (bounceIsSpecular || sampleLight) | |
accumCol = mask * hitEmission; | |
// reached a light, so we can exit | |
break; | |
} // end if (hitType == LIGHT) | |
if (sampleLight) | |
break; | |
if (hitType == DIFF || hitType == CHECK) // Ideal DIFFUSE reflection | |
{ | |
if( hitType == CHECK ) | |
{ | |
float q = clamp( mod( dot( floor(x.xz * 0.04), vec2(1.0) ), 2.0 ) , 0.0, 1.0 ); | |
//hitColor = checkCol0 * q + checkCol1 * (1.0 - q); | |
//float q = step(sin(x.x * 0.12) * sin(x.z * 0.12), 0.0); | |
hitColor = mix(checkCol1, checkCol0, q);// (checkCol0 * q) + (checkCol1 * (1.0 - q)); | |
} | |
if (bounces == 0 || (diffuseCount == 0 && !coatTypeIntersected && previousIntersecType == SPEC)) | |
objectColor = hitColor; | |
diffuseCount++; | |
mask *= hitColor; | |
bounceIsSpecular = false; | |
if (diffuseCount == 1 && rand() < 0.5) | |
{ | |
mask *= 2.0; | |
// choose random Diffuse sample vector | |
rayDirection = randomCosWeightedDirectionInHemisphere(nl); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
dirToLight = sampleSphereLight(x, nl, lightChoice, weight); | |
mask *= diffuseCount == 1 ? 2.0 : 1.0; | |
mask *= weight * N_LIGHTS; | |
rayDirection = dirToLight; | |
rayOrigin = x + nl * uEPS_intersect; | |
sampleLight = true; | |
continue; | |
} // end if (hitType == DIFF) | |
if (hitType == SPEC) // Ideal SPECULAR reflection | |
{ | |
mask *= hitColor; | |
rayDirection = reflect(rayDirection, nl); | |
rayOrigin = x + nl * uEPS_intersect; | |
//if (diffuseCount == 1) | |
// bounceIsSpecular = true; // turn on reflective mirror caustics | |
continue; | |
} | |
if (hitType == REFR) // Ideal dielectric REFRACTION | |
{ | |
pixelSharpness = diffuseCount == 0 ? -1.0 : pixelSharpness; | |
nc = 1.0; // IOR of Air | |
nt = 1.5; // IOR of common Glass | |
Re = calcFresnelReflectance(rayDirection, n, nc, nt, ratioIoR); | |
Tr = 1.0 - Re; | |
P = 0.25 + (0.5 * Re); | |
RP = Re / P; | |
TP = Tr / (1.0 - P); | |
if (diffuseCount == 0 && rand() < P) | |
{ | |
mask *= RP; | |
rayDirection = reflect(rayDirection, nl); // reflect ray from surface | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
// transmit ray through surface | |
// is ray leaving a solid object from the inside? | |
// If so, attenuate ray color with object color by how far ray has travelled through the medium | |
if (isRayExiting) | |
{ | |
isRayExiting = false; | |
mask *= exp(log(hitColor) * thickness * t); | |
} | |
else | |
mask *= hitColor; | |
mask *= TP; | |
tdir = refract(rayDirection, nl, ratioIoR); | |
rayDirection = tdir; | |
rayOrigin = x - nl * uEPS_intersect; | |
if (diffuseCount == 1) | |
bounceIsSpecular = true; // turn on refracting caustics | |
continue; | |
} // end if (hitType == REFR) | |
if (hitType == COAT) // Diffuse object underneath with ClearCoat on top | |
{ | |
coatTypeIntersected = true; | |
nc = 1.0; // IOR of Air | |
nt = 1.4; // IOR of Clear Coat | |
Re = calcFresnelReflectance(rayDirection, nl, nc, nt, ratioIoR); | |
Tr = 1.0 - Re; | |
P = 0.25 + (0.5 * Re); | |
RP = Re / P; | |
TP = Tr / (1.0 - P); | |
if (diffuseCount == 0 && rand() < P) | |
{ | |
mask *= RP; | |
rayDirection = reflect(rayDirection, nl); // reflect ray from surface | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
diffuseCount++; | |
mask *= TP; | |
mask *= hitColor; | |
bounceIsSpecular = false; | |
if (diffuseCount == 1 && rand() < 0.5) | |
{ | |
mask *= 2.0; | |
// choose random Diffuse sample vector | |
rayDirection = randomCosWeightedDirectionInHemisphere(nl); | |
rayOrigin = x + nl * uEPS_intersect; | |
continue; | |
} | |
if (hitColor.r > 0.5 && rand() < 0.8) // this makes white capsule more 'white' | |
dirToLight = sampleSphereLight(x, nl, spheres[0], weight); | |
else | |
dirToLight = sampleSphereLight(x, nl, lightChoice, weight); | |
mask *= diffuseCount == 1 ? 2.0 : 1.0; | |
mask *= weight * N_LIGHTS; | |
rayDirection = dirToLight; | |
rayOrigin = x + nl * uEPS_intersect; | |
sampleLight = true; | |
continue; | |
} //end if (hitType == COAT) | |
} // end for (int bounces = 0; bounces < 6; bounces++) | |
return max(vec3(0), accumCol); | |
} // end vec3 CalculateRadiance( out vec3 objectNormal, out vec3 objectColor, out float objectID, out float pixelSharpness ) | |
//----------------------------------------------------------------------- | |
void SetupScene(void) | |
//----------------------------------------------------------------------- | |
{ | |
vec3 z = vec3(0); | |
vec3 L1 = vec3(1.0, 1.0, 1.0) * 5.0;// White light | |
vec3 L2 = vec3(1.0, 0.8, 0.2) * 4.0;// Yellow light | |
vec3 L3 = vec3(0.1, 0.7, 1.0) * 2.0;// Blue light | |
spheres[0] = Sphere(150.0, vec3(-400, 900, 200), L1, z, LIGHT);//spherical white Light1 | |
spheres[1] = Sphere(100.0, vec3( 300, 400,-300), L2, z, LIGHT);//spherical yellow Light2 | |
spheres[2] = Sphere( 50.0, vec3( 500, 250,-100), L3, z, LIGHT);//spherical blue Light3 | |
float density = 0.75; | |
spheres[3] = Sphere(1000.0, vec3( 0.0, 1000.0, 0.0), z, vec3(1.0, 1.0, 1.0), CHECK);//Checkered Floor | |
spheres[4] = Sphere( mix(0.001, 16.5, step(1.0-density, rng())), vec3(-26.0, 17.2, 5.0), z, vec3(0.95, 0.0, 0.0), SPEC);//Mirror sphere | |
spheres[5] = Sphere( 15.0, vec3( 32.0, 16.1, 30.0), z, vec3(u_AABBData[255].x, u_AABBData[255].y, u_AABBData[255].z), REFR);//Glass sphere | |
ellipsoids[0] = Ellipsoid( vec3(30,40,16), vec3(90,5,-30), z, vec3(1.0, 0.765557, 0.336057), SPEC);//metallic gold ellipsoid | |
paraboloids[0] = Paraboloid( 16.5, 50.0, vec3(20.0, 1.5,-50), z, vec3(1.0, 0.2, 0.7), REFR);//paraboloid | |
openCylinders[0] = OpenCylinder( 15.0, 30.0, vec3(-70,7,-80), z, vec3(0.9,0.01,0.01), REFR);//red glass open Cylinder | |
cappedCylinders[0] = CappedCylinder( 14.0, vec3(-60,0,20), vec3(-60,14,20), z, vec3(0.04,0.04,0.04), COAT);//dark gray capped Cylinder | |
cones[0] = Cone( vec3(1,20,-12), 15.0, vec3(1,0,-12), 0.0, z, vec3(0.01,0.1,0.5), REFR);//blue Cone | |
capsules[0] = Capsule( vec3(80,13,15), 10.0, vec3(110,15.8,15), 10.0, z, vec3(u_InvMatrices[63][0][0], u_InvMatrices[63][1][0], u_InvMatrices[63][2][0]), COAT);//white Capsule | |
torii[0] = UnitTorus( 0.75, z, vec3(0.955008, 0.637427, 0.538163), SPEC);//copper Torus | |
boxes[0] = Box( vec3(50.0,21.0,-60.0), vec3(100.0,28.0,-130.0), z, vec3(0.2,0.9,0.7), REFR);//Glass Box | |
boxes[1] = Box( vec3(56.0,23.0,-66.0), vec3(94.0,26.0,-124.0), z, vec3(0.0,0.0,0.0), DIFF);//Diffuse Box | |
} | |
#include <pathtracing_main> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment