| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | #version 430 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  | #include sphere.glsl | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  | layout(local_size_x = 1, local_size_y = 1) in;                  // size of local work group - 1 pixel | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  | // TODO: do i actually need explicit location descriptors? | 
					
						
							|  |  |  | layout (location = 1)   uniform vec4 _t; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  | layout (location = 2)   uniform vec3 _w;                        // view space axes | 
					
						
							|  |  |  | layout (location = 3)   uniform vec3 _u; | 
					
						
							|  |  |  | layout (location = 4)   uniform vec3 _v; | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  | layout (location = 5)   uniform mat4 _cameraInverseProjection; | 
					
						
							|  |  |  | layout (location = 6)   uniform vec3 _camh; | 
					
						
							|  |  |  | layout (location = 7)   uniform vec3 _camv; | 
					
						
							|  |  |  | layout (location = 8)   uniform vec3 _camll; | 
					
						
							|  |  |  | layout (location = 9)   uniform vec3 _cpos; | 
					
						
							|  |  |  | layout (location = 10)  uniform vec3 _tpos;                     // target | 
					
						
							| 
									
										
										
										
											2021-07-30 02:06:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  | // 253 is the maximum?? TODO: use uniform buffer objects | 
					
						
							|  |  |  | const int SPHERES = 250;  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  | layout (location = 12)  uniform int _activeSpheres; | 
					
						
							|  |  |  | layout (location = 13)  uniform Sphere _spheres[SPHERES]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | uniform vec4 _seed; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  | layout(rgba32f, binding = 0) uniform image2D img_output;        // rgba32f defines internal format, image2d for random write to output texture | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  | layout(binding=1) uniform sampler2D _noise;                     // noise texture | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | const float INF = 1000.0; | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  | const float PI = 3.14159; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct Ray  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vec3 origin; | 
					
						
							|  |  |  |     vec3 direction; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     vec3 energy; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | Ray createRay(vec3 origin, vec3 direction) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Ray ray; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ray.origin = origin; | 
					
						
							|  |  |  |     ray.direction = direction; | 
					
						
							|  |  |  |     ray.energy = vec3(1.0,1.0,1.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ray; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct RayHit | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vec3 position; | 
					
						
							|  |  |  |     float distance; | 
					
						
							|  |  |  |     vec3 normal; | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  |     vec3 albedo; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | RayHit createRayHit() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RayHit hit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     hit.position = vec3(0.0,0.0,0.0); | 
					
						
							|  |  |  |     hit.distance = INF; | 
					
						
							|  |  |  |     hit.normal = vec3(0.0,0.0,0.0); | 
					
						
							|  |  |  |     hit.albedo = vec3(0.0,0.0,0.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return hit; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | void intersectSphere(Ray ray, inout RayHit bestHit, Sphere sphere) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  |     vec3 c = sphere.cr.xyz; | 
					
						
							|  |  |  |     float r = sphere.cr.w; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vec3 d = ray.origin-c; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  |     float p1 = -dot(ray.direction,d); | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  |     float p2sqr = p1*p1-dot(d,d)+r*r; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (p2sqr < 0) return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float p2 = sqrt(p2sqr); | 
					
						
							|  |  |  |     float t = p1-p2 > 0 ? p1-p2 : p1+p2; | 
					
						
							|  |  |  |     if (t > 0 && t < bestHit.distance) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bestHit.distance = t; | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  |         bestHit.position = ray.origin + t * ray.direction; | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  |         bestHit.normal = normalize(bestHit.position-c); | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  |         bestHit.albedo = sphere.albedo; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | void intersectPlane(Ray ray, inout RayHit bestHit, vec3 p, vec3 normal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     //normal = vec3(0.0,0.0,1.0); | 
					
						
							|  |  |  |     float denom = dot(normal, ray.direction); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (abs(denom) > 0.0001) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         float t = dot(p-ray.origin, normal) / denom; | 
					
						
							|  |  |  |         if (t >= 0 && t < bestHit.distance) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             bestHit.distance = t; | 
					
						
							|  |  |  |             bestHit.position = ray.origin + t*ray.direction; | 
					
						
							|  |  |  |             bestHit.normal = normal; | 
					
						
							|  |  |  |             bestHit.albedo = vec3(1.0,1.0,1.0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | Ray createCameraRay(vec2 uv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // transform -1..1 -> 0..1 | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  |     uv = uv*0.5+0.5; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  |     //uv.x=1-uv.x; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  |     vec3 target = vec3(0,0,0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  |     vec3 dir; | 
					
						
							|  |  |  |     dir = uv.x*_camh + uv.y*_camv; | 
					
						
							|  |  |  |     dir = _camll + uv.x*_camh + uv.y*_camv; | 
					
						
							|  |  |  |     dir = normalize(dir); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     Ray ray = createRay(_cpos, dir); | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return ray; | 
					
						
							| 
									
										
										
										
											2021-08-02 23:32:47 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | RayHit trace(Ray ray) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     RayHit hit = createRayHit(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO: intersect something other than spheres | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  |     Sphere s; | 
					
						
							|  |  |  |     s.cr = vec4(0.0,0.0,0.0,2.0); | 
					
						
							|  |  |  |     s.albedo = vec3(1.0,0.0,0.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     intersectPlane(ray, hit, vec3(0.0,-1.5,0.0),vec3(0.0,1.0,0.0)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     for (int i = 0; i < _activeSpheres; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         intersectSphere(ray, hit, _spheres[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  |     //intersectSphere(ray, hit, s); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     return hit; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  | vec2 pixelUv()  | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ivec2 dims = imageSize(img_output); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vec2 uv; | 
					
						
							|  |  |  |     uv.x = (float(pixelCoords.x * 2 - dims.x) / dims.x) * dims.x/dims.y;       // account for aspect ratio | 
					
						
							|  |  |  |     uv.y = (float(pixelCoords.y * 2 - dims.y) / dims.y); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return uv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vec4 sampleNoise() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-09 18:15:43 +01:00
										 |  |  |     vec2 uv = pixelUv(); | 
					
						
							|  |  |  |     uv += _seed.xy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return texture(_noise, uv); | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | float random(vec2 st) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     //st += gl_GlobalInvocationID.xy; | 
					
						
							|  |  |  |     //st += _seed.xy; | 
					
						
							|  |  |  |     //st += _seed.zw; | 
					
						
							|  |  |  |     //normalize(st); | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     vec2 nuv = texture(_noise, st.xy).xy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return fract(sin(dot(nuv,vec2(12.9898,78.233)))*43758.5453123); | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float sdot(vec3 x, vec3 y, float f = 1.0) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return clamp(dot(x,y)*f,0.0,1.0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mat3 getTangentSpace(vec3 normal) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vec3 helper = abs(normal.x) > 0.99  | 
					
						
							|  |  |  |         ? vec3(1.0,0.0,0.0)  | 
					
						
							|  |  |  |         : vec3(0.0,0.0,1.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vec3 tangent = normalize(cross(normal, helper)); | 
					
						
							|  |  |  |     vec3 binormal = normalize(cross(normal, tangent)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return mat3(tangent, binormal, normal); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vec3 sampleHemisphere(vec3 normal) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     vec4 noise = sampleNoise(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     float cosTheta = random(normalize(normal.xy+noise.xy)); | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     float sinTheta = sqrt(max(0.0,1.0-cosTheta*cosTheta)); | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     float phi = 2.0*PI*random(normalize(normal.yz+noise.xw)); | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     vec3 tangentSpaceDir = vec3(cos(phi)*sinTheta, sin(phi)*sinTheta, cosTheta); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  |     // convert direction from tangent space to world space | 
					
						
							| 
									
										
										
										
											2021-08-07 18:30:43 +01:00
										 |  |  |     mat3 ts = getTangentSpace(normal); | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     return ts * tangentSpaceDir; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vec3 scatterLambert(inout Ray ray, RayHit hit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     ray.origin = hit.position + hit.normal*0.001; | 
					
						
							|  |  |  |     ray.direction = sampleHemisphere(hit.normal); | 
					
						
							|  |  |  |     ray.energy *= 2.0 * hit.albedo * sdot(hit.normal, ray.direction); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return vec3(0.0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | vec3 shade(inout Ray ray, RayHit hit) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (hit.distance < INF) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return scatterLambert(ray, hit); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     //ray.energy = vec3(0.0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // sky color | 
					
						
							|  |  |  |     return vec3(0.68,0.85,0.9); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | void main() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // base pixel colour for the image | 
					
						
							|  |  |  |     vec4 pixel = vec4(0.0, 0.0, 0.0, 1.0); | 
					
						
							|  |  |  |     // get index in global work group ie xy position | 
					
						
							|  |  |  |     ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     vec2 uv = pixelUv(); | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 18:15:43 +01:00
										 |  |  |     int samples = 1; | 
					
						
							|  |  |  |     int bounces = 4; | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     for (int i = 0; i < samples; i++)  | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |         // create a ray from the uv | 
					
						
							|  |  |  |         Ray ray = createCameraRay(uv); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // trace the rays path around the scene | 
					
						
							|  |  |  |         for (int j = 0; j < bounces; j++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             RayHit hit = trace(ray); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             pixel.xyz += ray.energy * shade(ray, hit); | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (length(ray.energy) < 0.001) break; | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-08-06 19:25:52 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-08 16:47:25 +01:00
										 |  |  |     pixel.xyz /= samples; | 
					
						
							| 
									
										
										
										
											2021-08-07 18:30:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-02 09:35:39 +01:00
										 |  |  |     // TODO: write depth to texture | 
					
						
							| 
									
										
										
										
											2021-08-07 17:50:24 +01:00
										 |  |  |     //float depth = hit.distance/INF; | 
					
						
							|  |  |  |     //pixel = vec4(hit.albedo,1.0); | 
					
						
							|  |  |  |     //pixel *= (1.0-depth); | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-09 15:49:05 +01:00
										 |  |  |     //pixel = texture(_noise, uv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 01:31:35 +01:00
										 |  |  |     // output to a specific pixel in the image | 
					
						
							|  |  |  |     imageStore(img_output, pixel_coords, pixel); | 
					
						
							|  |  |  | } |