Files
Destrum/destrum/assets_src/shaders/mesh.frag
T

162 lines
5.3 KiB
GLSL

#version 460
#extension GL_GOOGLE_include_directive : require
#include "bindless.glsl"
#include "scene_data.glsl"
#include "mesh_pcs.glsl"
#include "lighting.glsl"
#include "shadows.glsl"
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec4 inTangent;
layout (location = 4) flat in uint inMaterialID;
layout (location = 5) flat in uint inObjectID;
layout (location = 0) out vec4 outFragColor;
// Stable per object, the same object keeps its color between frames and runs
vec3 selectionColor(uint objectID)
{
if (objectID == 0u) {
return vec3(0.0);
}
uint hash = objectID * 2654435761u;
hash ^= hash >> 15;
hash *= 2246822519u;
hash ^= hash >> 13;
return vec3(hash & 255u, (hash >> 8) & 255u, (hash >> 16) & 255u) / 255.0;
}
vec3 calculateNormal(MaterialData material, uint samplerID)
{
vec3 n = normalize(inNormal);
// Meshes without tangents can't use a normal map
if (dot(inTangent.xyz, inTangent.xyz) < 1e-8) {
return n;
}
// Re-orthogonalize, the interpolated tangent isn't perpendicular to the normal anymore
vec3 t = normalize(inTangent.xyz - n * dot(n, inTangent.xyz));
vec3 b = cross(n, t) * inTangent.w;
vec3 tangentNormal = sampleTexture2D(material.normalTex, samplerID, inUV).rgb * 2.0 - 1.0;
tangentNormal.xy *= material.metallicRoughnessNormalOcclusion.z;
return normalize(mat3(t, b, n) * tangentNormal);
}
float calculateShadow(Light light, vec3 fragPos, vec3 geometryNormal)
{
if (light.shadowIndex == NO_SHADOW) {
return 1.0;
}
if (light.type == TYPE_DIRECTIONAL_LIGHT) {
return calculateDirectionalShadow(
fragPos, geometryNormal,
pcs.sceneData.lightViewProj,
pcs.sceneData.shadowMapId,
pcs.sceneData.shadowNormalOffset);
}
if (light.type == TYPE_SPOT_LIGHT) {
return calculateSpotShadow(
fragPos, geometryNormal, light.position,
pcs.sceneData.spotShadows[light.shadowIndex],
light.shadowIndex,
pcs.sceneData.spotShadowAtlasId,
pcs.sceneData.spotShadowTilesPerRow);
}
return 1.0;
}
void main()
{
MaterialData material = pcs.sceneData.materials.data[inMaterialID];
uint samplerID = material.textureFilteringMode;
vec4 diffuse = sampleTexture2D(material.diffuseTex, samplerID, inUV) * material.baseColor;
vec3 baseColor = diffuse.rgb;
// if (diffuse.a < 0.1) {
// discard;
// }
vec3 n = calculateNormal(material, samplerID);
float metallicF = material.metallicRoughnessNormalOcclusion.x;
float roughnessF = material.metallicRoughnessNormalOcclusion.y;
float occlusionStrength = material.metallicRoughnessNormalOcclusion.w;
float metallic = metallicF * sampleTexture2D(material.metallicTex, samplerID, inUV).b;
float roughness = roughnessF * sampleTexture2D(material.roughnessTex, samplerID, inUV).g;
roughness = max(roughness, 1e-2); // 0.0 roughness leads to NaNs
float occlusion = sampleTexture2D(material.occlusionTex, samplerID, inUV).r;
float ambientOcclusion = mix(1.0, occlusion, occlusionStrength);
vec3 dielectricSpecular = vec3(0.04);
vec3 black = vec3(0.0);
vec3 diffuseColor = mix(baseColor * (1.0 - dielectricSpecular.r), black, metallic);
vec3 f0 = mix(dielectricSpecular, baseColor, metallic);
vec3 cameraPos = pcs.sceneData.cameraPos.xyz;
vec3 fragPos = inPos.xyz;
vec3 v = normalize(cameraPos - fragPos);
// forward+: only loop over the lights the culling pass put in this pixel's tile
uvec2 tileID = uvec2(gl_FragCoord.xy) / LIGHT_TILE_SIZE;
uint tileOffset = (tileID.y * pcs.sceneData.tileCountX + tileID.x) * LIGHT_TILE_STRIDE;
uint tileLightCount = pcs.sceneData.tileLightIndices.data[tileOffset];
vec3 geometryNormal = normalize(inNormal);
vec3 fragColor = vec3(0.0);
for (uint i = 0; i < tileLightCount; i++) {
uint lightIndex = pcs.sceneData.tileLightIndices.data[tileOffset + 1 + i];
Light light = pcs.sceneData.lights.data[lightIndex];
float shadow = calculateShadow(light, fragPos, geometryNormal);
fragColor += calculateLight(light, fragPos, n, v,
diffuseColor, roughness, metallic, f0, shadow);
}
vec3 emissiveColor = material.emissiveColor.rgb * sampleTexture2D(material.emissiveTex, samplerID, inUV).rgb;
fragColor += emissiveColor;
float NoV = clamp(dot(n, v), 0.0001, 1.0);
vec3 ambientLight = pcs.sceneData.ambientColor * pcs.sceneData.ambientIntensity;
vec3 ambientSpecular = envBRDFApprox(f0, roughness, NoV);
fragColor += (diffuseColor + ambientSpecular) * ambientLight * ambientOcclusion;
float fogAmount = pcs.sceneData.fogDensity * length(cameraPos - fragPos);
fragColor = mix(pcs.sceneData.fogColor, fragColor, exp(-fogAmount * fogAmount));
if (pcs.sceneData.debugLightHeatmap != 0) {
fragColor = mix(fragColor, lightHeatmapColor(tileLightCount), 0.5);
}
if (pcs.sceneData.debugSelectionView != 0) {
fragColor = selectionColor(inObjectID & 0x7FFFFFFFu);
}
#if 0
// TANGENT DEBUG
if (inTangent == vec4(0.0)) {
fragColor = vec3(1.0f, 0.0f, 0.0f);
}
#endif
#if 0
// NORMAL DEBUG
fragColor = n;
#endif
outFragColor = vec4(fragColor, diffuse.a);
}