#ifdef DESC [program] type: graphics vertex: main fragment: main [binding] name: mesh rate: vertex [attribute] name: position type: vec3 [attribute] name: normal type: vec3 [attribute] name: tangent type: vec3 [attribute] name: uv type: vec2 [interpolator] name: uv type: vec2 [interpolator] name: position type: vec4 [interpolator] name: tbn type: mat3 [struct] name: Model [variable] name: model type: mat4 [struct] name: VP [variable] name: view_projection type: mat4 [struct] name: Material [variable] name: albedo type: vec3 [variable] name: metalness type: float [variable] name: roughness type: float [variable] name: ao type: float [variable] name: light_count type: int [variable] name: camera_pos type: vec3 [struct] name: Light [variable] name: dir type: vec3 [variable] name: brightness type: float [variable] name: colour type: vec3 [variable] name: caster_id type: int [struct] name: Caster [variable] name: projection type: mat4 [cbuffer] name: c_vp type: VP stage: vertex [cbuffer] name: c_model type: Model stage: vertex [cbuffer] name: material type: Material stage: fragment [sbuffer] name: lights type: Light stage: fragment [sbuffer] name: casters type: Caster stage: fragment [texture] name: albedo stage: fragment dimension: 2 [texture] name: ao stage: fragment dimension: 2 [texture] name: metal stage: fragment dimension: 2 [texture] name: rough stage: fragment dimension: 2 [texture] name: normal stage: fragment dimension: 2 [texture] name: env_cube stage: fragment dimension: cube [texture] name: shadowmaps stage: fragment dimension: shadowArray [target] name: colour type: vec4 #endif #ifdef VERTEX_SHADER void main() { vec4 pos = c_model.model * vec4(position, 1.0); vec3 t = normalize((c_model.model * vec4(tangent, 0.0)).xyz); vec3 n = normalize((c_model.model * vec4(normal, 0.0)).xyz); vec3 b = cross(t, n); interpolator.tbn = mat3(t, b, n); interpolator.uv = uv; interpolator.position = pos; interpolator.tbn = mat3(t, b, n); gl_Position = c_vp.view_projection * pos; } #endif #ifdef FRAGMENT_SHADER #define pi 3.14159265358979323846 vec3 diffuse_brdf(vec2 uv) { vec3 a = material.albedo * texture(albedo, uv).rgb; return a / pi; } float specular_G1(float a, vec3 v, vec3 n) { float ndv = max(dot(n, v), 0.0); float a1 = a + 1.0; float k = (a1 * a1) / 8.0; return ndv / (ndv * (1.0 - k) + k); } float specular_brdf(vec2 uv, vec3 ref, vec3 l, vec3 v, vec3 n) { float ndl = max(dot(n, l), 0.0); float ndv = max(dot(n, v), 0.0); float a = texture(rough, uv).r * material.roughness; float a2 = a * a; float ndr = max(dot(n, ref), 0.0); float b = ((ndr * ndr) * (a2 - 1) + 1); float D = a2 / (pi * b * b); float G = specular_G1(a, l, n) * specular_G1(a, v, n); float F0 = 0.04; float F = F0 + (1.0 - F0) * pow(2, ((-5.55473 * ndr - 6.98316), ndr)); return (D * F * G) / (4.0 * ndl * ndv + 0.001); } vec2 poissonDisk[16] = vec2[]( vec2(-0.94201624, -0.39906216), vec2(0.94558609, -0.76890725), vec2(-0.094184101, -0.92938870), vec2(0.34495938, 0.29387760), vec2(-0.91588581, 0.45771432), vec2(-0.81544232, -0.87912464), vec2(-0.38277543, 0.27676845), vec2(0.97484398, 0.75648379), vec2(0.44323325, -0.97511554), vec2(0.53742981, -0.47373420), vec2(-0.26496911, -0.41893023), vec2(0.79197514, 0.19090188), vec2(-0.24188840, 0.99706507), vec2(-0.81409955, 0.91437590), vec2(0.19984126, 0.78641367), vec2(0.14383161, -0.14100790) ); float random(vec3 seed, int i){ vec4 seed4 = vec4(seed,i); float dot_product = dot(seed4, vec4(12.9898,78.233,45.164,94.673)); return fract(sin(dot_product) * 43758.5453); } float get_shadow(Light l, vec3 wpos) { const int taps = 4; const float w = 1.0 / float(taps); const float m = 1.0 / 1000.0; int i; float d = 0.0f; Caster caster = casters[l.caster_id]; vec4 surf = caster.projection * vec4(wpos, 1.0); surf /= surf.w; surf.xy = surf.xy * 0.5 + 0.5; surf.z -= 0.005; for (i = 0; i < taps; i++) { int index = int(16.0 * random(floor(wpos.xyz * 1000.0), i)) % 16; vec2 coord = surf.xy + poissonDisk[index] * m; vec4 vec = vec4(coord, float(l.caster_id), surf.z); d += texture(shadowmaps, vec).r * w; } return d; } void main() { int i; vec2 uv = interpolator.uv; vec3 p = interpolator.position.xyz; vec3 nrmsample = texture(normal, uv).rgb; vec2 nrmxy = nrmsample.xy * 2.0 - 1.0; vec3 nrm = normalize(vec3(nrmxy, 1.0)); if (nrmsample.b == 1.0) /* default texture */ nrm = normalize(interpolator.tbn[2]); else nrm = normalize(interpolator.tbn * nrm); vec3 col = texture(albedo, uv).rgb * material.albedo; vec3 view_dir = normalize(material.camera_pos - p); float met = texture(metal, uv).r * material.metalness; vec3 ref = reflect(-view_dir, nrm); vec3 ref_col = texture(env_cube, ref, material.roughness * 8.0).rgb; vec3 spec_col = mix(ref_col, ref_col * col, met); vec3 amb_col = min(textureLod(env_cube, nrm, 8.0).rgb, 0.05); vec3 ambient = amb_col * texture(ao, uv).r * material.ao; vec3 base_diffuse = diffuse_brdf(uv) * (1.0 - met); vec3 light = 0.0.xxx; for (i = 0; i < material.light_count; i++) { Light l = lights[i]; vec3 light_dir = l.dir; float cos_theta_i = max(dot(nrm, light_dir), 0.0); vec3 diffuse = base_diffuse * cos_theta_i; vec3 spec = spec_col * specular_brdf(uv, ref, light_dir, view_dir, nrm) * cos_theta_i; float shadow = 1.0f; if (l.caster_id >= 0) shadow = get_shadow(l, p); light += (diffuse + spec) * l.brightness * l.colour * shadow; } colour = vec4(ambient + light, 1.0); } #endif