#version 430 core #define $Material$ #if defined(MT_NORMAL) | defined(MT_COLORNORMAL) | defined(MT_COLORNORMALREFLECTIVITY) const bool SHADE_DIFFUSE = false; #else const bool SHADE_DIFFUSE = true; #endif in vec2 UV; out vec4 color; uniform sampler2D depthTexture; uniform sampler2D renderTexture; uniform sampler2D voxelPositionsTexture; layout(location = $width$) uniform int width; layout(location = $height$) uniform int height; layout(location = $MVP$) uniform mat4x4 MVP; layout(location = $lightDirection$) uniform vec3 lightDirection; layout(location = $lightType$) uniform int lightType; const uint range = 1 << ($max_level$ + 1); const float extent = $extent$; const float rangeF = float(range); const float scale = rangeF / (extent * 2.); const float offset = extent + 0.5 / scale; const int SAMPLE_DISTANCE = 3; const float MAX_DISTANCE = 0.02 * rangeF; const float ssaoRadius = 2.0; const float ssaoPower = 2.0; #define SSAO_KERNEL_SIZE 10 const vec3[SSAO_KERNEL_SIZE] SSAO_KERNEL = { vec3(-0.013627260795642221, -0.08986502062675834, 0.04169623281496606), vec3(0.1530762079182679, -0.07153954612140453, 0.08688940044738859), vec3(0.07090584436998379, 0.1490828023178984, 0.22615631604538947), vec3(-0.15616336851550036, -0.26564930875054044, 0.20480099388003975), vec3(0.26677241220752623, 0.28676826613128037, 0.2412393865541797), vec3(-0.3475187558492847, -0.15578006191669713, 0.39681643948076967), vec3(0.3887426730563284, 0.02398677725666013, 0.5078422675022826), vec3(0.49626198926704007, -0.21014511667561903, 0.49240538984266874), vec3(-0.5032145340980271, 0.5942213554886051, 0.2570527443031691), vec3(0.5983551080400994, 0.25120169632241235, 0.6379411198904361) }; #define PI 3.14159265 //vec3 screenToWorld(vec3 screen) { // vec4 homogeniousWorld = invMVP * vec4(screen * 2.0 - 1.0, 1); // homogeniousWorld /= homogeniousWorld.z; // return homogeniousWorld.xyz; //} vec3 NormalFromTriangleVertices(vec3 triangleVertices[3]) { // now is same as RedBook (OpenGL Programming Guide) vec3 u = triangleVertices[0] - triangleVertices[1]; vec3 v = triangleVertices[1] - triangleVertices[2]; return normalize(cross(u, v)); } float getDiffuseLight(vec3 normal, vec3 position) { if (lightType == 0) return 1.0; else if (lightType == 1) return max(dot(-lightDirection, normal), 0); else if (lightType == 2) { vec3 toLight = lightDirection / scale - position; vec3 lightDir = normalize(toLight); return max(dot(lightDir, normal), 0); } } float rand(vec2 n) { return 0.5 + 0.5 * fract(sin(dot(n.xy, vec2(12.9898, 78.233)))* 43758.5453); } vec3 getTangent(vec3 normal) { vec3 tangent; vec3 c1 = cross(normal, vec3(0.0, 0.0, 1.0)); vec3 c2 = cross(normal, vec3(0.0, 1.0, 0.0)); if (length(c1)>length(c2)) tangent = c1; else tangent = c2; return normalize(tangent); } vec3 voxelGridToWorld(vec3 voxelGridCoord) { return (voxelGridCoord / scale) - offset; } vec4 worldToScreen(vec3 sam) { vec4 samUV = vec4(sam , 1.0); samUV = MVP * samUV; samUV.xy /= samUV.w; samUV.xy = samUV.xy * 0.5 + 0.5; return samUV; } // Calculates the SSAO occlusion float SSAO(vec3 pos, vec3 normal) { // Rotate our kernel vec3 rvec = vec3(rand(UV), rand(normal.xy), rand(pos.xy)); vec3 tangent = normalize(rvec - normal * dot(rvec, normal)); vec3 bitangent = cross(normal, tangent); mat3 tbn = mat3(tangent, bitangent, normal); float occlusion = 0.0; for (int i = 0; i < SSAO_KERNEL_SIZE; i++) { // get sample position: vec3 sam = tbn * SSAO_KERNEL[i]; sam = sam * ssaoRadius + pos; vec3 towardsSam = sam - pos; float samDot = dot(normal, towardsSam); // project sample position: vec4 samUV = worldToScreen(sam); // get sample depth: vec3 sampledPos = voxelGridToWorld(texture(voxelPositionsTexture, samUV.xy).xyz); vec3 towardsSampledPos = sampledPos - pos; float sampledDot = dot(normal, towardsSampledPos); //color = vec4(towardsSampledPos, 1); //return abs(sampledDot * 1.0) / rangeF; // range check & accumulate: float rangeCheck = abs(sampledDot) < ssaoRadius ? 1.0 : 0.0; occlusion += (sampledDot >= samDot ? 1.0 : 0.0) * rangeCheck; } return pow(1.0 - (occlusion / float(SSAO_KERNEL_SIZE)), ssaoPower); } void main(void) { color = texture(renderTexture, UV); // Get the voxel positions in the center, left, right, top bottom: ivec2 screenCoord = ivec2(UV * vec2(width, height)); vec3 c = texelFetch(voxelPositionsTexture, screenCoord, 0).xyz; vec3 pos = voxelGridToWorld(c); if (c == vec3(0)) return; // If no vertex position is known, don't do further processing vec3 l = texelFetch(voxelPositionsTexture, screenCoord + ivec2(-SAMPLE_DISTANCE, 0), 0).xyz; vec3 r = texelFetch(voxelPositionsTexture, screenCoord + ivec2(+SAMPLE_DISTANCE, 0), 0).xyz; vec3 t = texelFetch(voxelPositionsTexture, screenCoord + ivec2(0, +SAMPLE_DISTANCE), 0).xyz; vec3 b = texelFetch(voxelPositionsTexture, screenCoord + ivec2(0, -SAMPLE_DISTANCE), 0).xyz; // Check if we need to dispose any location as they are too far away (in world space); bool ignoreL = length(l - c) > MAX_DISTANCE; bool ignoreR = length(r - c) > MAX_DISTANCE; bool ignoreT = length(t - c) > MAX_DISTANCE; bool ignoreB = length(t - b) > MAX_DISTANCE; vec3 normal = vec3(0); // Make some triangles and calculate the normal based on those triangles if (!ignoreT && !ignoreR) { vec3 triangle1[3] = { t, c, r }; normal += NormalFromTriangleVertices(triangle1); } if (!ignoreR && !ignoreB) { vec3 triangle2[3] = { r, c, b }; normal += NormalFromTriangleVertices(triangle2); } if (!ignoreB && !ignoreL) { vec3 triangle3[3] = { b, c, l }; normal += NormalFromTriangleVertices(triangle3); } if (!ignoreL && !ignoreT) { vec3 triangle4[3] = { l, c, t }; normal += NormalFromTriangleVertices(triangle4); } normal = normalize(normal); //color = vec4(normal == vec3(0) ? 1.0 : 0.0); return; //color = vec4(normal, 1); return; if (SHADE_DIFFUSE) color *= (0.4 + 0.6 * getDiffuseLight(normal, pos)); float occlusion = SSAO(pos, normal); color *= occlusion; }