Created
October 22, 2022 03:58
-
-
Save hzqst/a0b0a6e5de86e41a596cba4d47a435dc to your computer and use it in GitHub Desktop.
This file contains 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
#version 430 | |
#define DIFFUSE_ENABLED | |
#define LIGHTMAP_ENABLED | |
#define GBUFFER_ENABLED | |
#define BINDLESS_ENABLED | |
#define SHADOW_TEXTURE_OFFSET (1.0 / 4096.0) | |
#define IS_FRAGMENT_SHADER | |
#extension GL_EXT_texture_array : require | |
#extension GL_EXT_gpu_shader4 : require | |
#ifdef BINDLESS_ENABLED | |
#extension GL_ARB_shader_draw_parameters : require | |
#endif | |
#ifdef BINDLESS_ENABLED | |
#ifdef UINT64_ENABLED | |
#extension GL_NV_bindless_texture : require | |
#extension GL_NV_gpu_shader5 : require | |
#else | |
#extension GL_ARB_bindless_texture : require | |
#endif | |
#endif | |
#if defined(OIT_ALPHA_BLEND_ENABLED) || defined(OIT_ADDITIVE_BLEND_ENABLED) | |
#ifdef IS_FRAGMENT_SHADER | |
// See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_shader_image_load_store.txt | |
#extension GL_ARB_shader_image_load_store : require | |
// See https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_fragment_shader_interlock.txt | |
#extension GL_ARB_fragment_shader_interlock : require | |
// Use early z-test to cull transparent fragments occluded by opaque fragments. | |
// Additionaly, use fragment interlock. | |
layout(early_fragment_tests) in; | |
// gl_FragCoord will be used for pixel centers at integer coordinates. | |
// See https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/gl_FragCoord.xhtml | |
layout(pixel_center_integer) in vec4 gl_FragCoord; | |
#define MAX_NUM_NODES 16 | |
#endif | |
#endif | |
#if defined(UINT64_ENABLED) | |
#define texture_handle_t uint64_t | |
#else | |
#define texture_handle_t uvec2 | |
#endif | |
#define TEXTURE_SSBO_DIFFUSE 0 | |
#define TEXTURE_SSBO_REPLACE 1 | |
#define TEXTURE_SSBO_DETAIL 2 | |
#define TEXTURE_SSBO_NORMAL 3 | |
#define TEXTURE_SSBO_PARALLAX 4 | |
#define TEXTURE_SSBO_SPECULAR 5 | |
#define TEXTURE_SSBO_MAX 6 | |
#define TEXTURE_SSBO_WATER_BASE 0 | |
#define TEXTURE_SSBO_WATER_NORMAL 1 | |
#define TEXTURE_SSBO_WATER_REFLECT 2 | |
#define TEXTURE_SSBO_WATER_REFRACT 3 | |
#define TEXTURE_SSBO_WATER_DEPTH 4 | |
#define BINDING_POINT_SCENE_UBO 0 | |
#define BINDING_POINT_SKYBOX_SSBO 1 | |
#define BINDING_POINT_DECAL_SSBO 1 | |
#define BINDING_POINT_TEXTURE_SSBO 1 | |
#define BINDING_POINT_ENTITY_UBO 2 | |
#define BINDING_POINT_STUDIO_UBO 2 | |
#define BINDING_POINT_OIT_FRAGMENT_SSBO 3 | |
#define BINDING_POINT_OIT_NUMFRAGMENT_SSBO 4 | |
#define BINDING_POINT_OIT_COUNTER_SSBO 5 | |
#define WSURF_DIFFUSE_TEXTURE 0 | |
#define WSURF_REPLACE_TEXTURE 1 | |
#define WSURF_DETAIL_TEXTURE 2 | |
#define WSURF_NORMAL_TEXTURE 3 | |
#define WSURF_PARALLAX_TEXTURE 4 | |
#define WSURF_SPECULAR_TEXTURE 5 | |
#define WSURF_MAX_TEXTURE 6 | |
#define SPR_VP_PARALLEL_UPRIGHT 0 | |
#define SPR_FACING_UPRIGHT 1 | |
#define SPR_VP_PARALLEL 2 | |
#define SPR_ORIENTED 3 | |
#define SPR_VP_PARALLEL_ORIENTED 4 | |
struct scene_ubo_t{ | |
mat4 viewMatrix; | |
mat4 projMatrix; | |
mat4 invViewMatrix; | |
mat4 invProjMatrix; | |
mat4 shadowMatrix[3]; | |
uvec4 viewport; | |
vec4 frustumpos[4]; | |
vec4 viewpos; | |
vec4 vpn; | |
vec4 vright; | |
vec4 vup; | |
vec4 shadowDirection; | |
vec4 shadowColor; | |
vec4 shadowFade; | |
vec4 clipPlane; | |
vec4 fogColor; | |
float fogStart; | |
float fogEnd; | |
float fogDensity; | |
float time; | |
float r_g; | |
float r_g3; | |
float v_brightness; | |
float v_lightgamma; | |
float v_lambert; | |
float v_gamma; | |
float v_texgamma; | |
float z_near; | |
float z_far; | |
float r_alpha_shift; | |
float r_additive_shift; | |
float padding; | |
}; | |
struct entity_ubo_t{ | |
mat4 entityMatrix; | |
vec4 color; | |
float scrollSpeed; | |
}; | |
struct studio_ubo_t{ | |
float r_ambientlight; | |
float r_shadelight; | |
float r_blend; | |
float r_scale; | |
vec4 r_plightvec; | |
vec4 r_colormix; | |
vec4 r_origin; | |
vec4 entity_origin; | |
mat3x4 bonematrix[128]; | |
}; | |
//Scene level | |
layout (std140, binding = BINDING_POINT_SCENE_UBO) uniform SceneBlock | |
{ | |
scene_ubo_t SceneUBO; | |
}; | |
#if defined(BINDLESS_ENABLED) | |
layout (std430, binding = BINDING_POINT_DECAL_SSBO) coherent buffer DecalBlock | |
{ | |
texture_handle_t DecalSSBO[]; | |
}; | |
layout (std430, binding = BINDING_POINT_SKYBOX_SSBO) coherent buffer SkyboxBlock | |
{ | |
texture_handle_t SkyboxSSBO[]; | |
}; | |
#endif | |
//Entity level | |
layout (std140, binding = BINDING_POINT_ENTITY_UBO) uniform EntityBlock | |
{ | |
entity_ubo_t EntityUBO; | |
}; | |
#if defined(BINDLESS_ENABLED) | |
layout (std430, binding = BINDING_POINT_TEXTURE_SSBO) coherent buffer TextureBlock | |
{ | |
texture_handle_t TextureSSBO[]; | |
}; | |
#endif | |
layout (std140, binding = BINDING_POINT_STUDIO_UBO) uniform StudioBlock | |
{ | |
studio_ubo_t StudioUBO; | |
}; | |
#if defined(OIT_ALPHA_BLEND_ENABLED) || defined(OIT_ADDITIVE_BLEND_ENABLED) | |
// A fragment node stores rendering information about one specific fragment | |
struct FragmentNode | |
{ | |
// RGBA color of the node | |
uint color; | |
// Depth value of the fragment (in view space) | |
float depth; | |
// The index of the next node in "nodes" array | |
uint next; | |
}; | |
// Fragment-and-link buffer (linked list). Stores "nodesPerPixel" number of fragments. | |
layout (std430, binding = BINDING_POINT_OIT_FRAGMENT_SSBO) coherent buffer FragmentNodes | |
{ | |
FragmentNode nodes[]; | |
}; | |
// Start-offset buffer (mapping pixels to first pixel in the buffer) of size viewportW*viewportH. | |
layout (std430, binding = BINDING_POINT_OIT_NUMFRAGMENT_SSBO) coherent buffer NumFragmentsBuffer | |
{ | |
uint numFragments[]; | |
}; | |
layout(binding = BINDING_POINT_OIT_COUNTER_SSBO, offset = 0) uniform atomic_uint fragCounter; | |
#ifdef IS_FRAGMENT_SHADER | |
void GatherFragment(inout vec4 color) | |
{ | |
uint x = uint(gl_FragCoord.x); | |
uint y = uint(gl_FragCoord.y); | |
uint viewportW = SceneUBO.viewport.x; | |
uint linkedListSize = SceneUBO.viewport.z; | |
uint pixelIndex = viewportW*y + x; | |
FragmentNode frag; | |
frag.color = packUnorm4x8(color); | |
#ifdef OIT_ADDITIVE_BLEND_ENABLED | |
frag.depth = -gl_FragCoord.z; | |
#else | |
frag.depth = gl_FragCoord.z; | |
#endif | |
frag.next = -1; | |
uint insertIndex = atomicCounterIncrement(fragCounter); | |
if (insertIndex < linkedListSize) { | |
// Insert the fragment into the linked list | |
frag.next = atomicExchange(numFragments[pixelIndex], insertIndex); | |
nodes[insertIndex] = frag; | |
} | |
discard; | |
} | |
#endif | |
#endif | |
vec2 UnitVectorToHemiOctahedron(vec3 dir) { | |
dir.y = max(dir.y, 0.0001); | |
dir.xz /= dot(abs(dir), vec3(1.0)); | |
return clamp(0.5 * vec2(dir.x + dir.z, dir.x - dir.z) + 0.5, 0.0, 1.0); | |
} | |
vec3 HemiOctahedronToUnitVector(vec2 coord) { | |
coord = 2.0 * coord - 1.0; | |
coord = 0.5 * vec2(coord.x + coord.y, coord.x - coord.y); | |
float y = 1.0 - dot(vec2(1.0), abs(coord)); | |
return normalize(vec3(coord.x, y + 0.0001, coord.y)); | |
} | |
vec2 UnitVectorToOctahedron(vec3 dir) { | |
dir.xz /= dot(abs(dir), vec3(1.0)); | |
// Lower hemisphere | |
if (dir.y < 0.0) { | |
vec2 orig = dir.xz; | |
dir.x = (orig.x >= 0.0 ? 1.0 : -1.0) * (1.0 - abs(orig.y)); | |
dir.z = (orig.y >= 0.0 ? 1.0 : -1.0) * (1.0 - abs(orig.x)); | |
} | |
return clamp(0.5 * vec2(dir.x, dir.z) + 0.5, 0.0, 1.0); | |
} | |
vec3 OctahedronToUnitVector(vec2 coord) { | |
coord = 2.0 * coord - 1.0; | |
float y = 1.0 - dot(abs(coord), vec2(1.0)); | |
// Lower hemisphere | |
if (y < 0.0) { | |
vec2 orig = coord; | |
coord.x = (orig.x >= 0.0 ? 1.0 : -1.0) * (1.0 - abs(orig.y)); | |
coord.y = (orig.y >= 0.0 ? 1.0 : -1.0) * (1.0 - abs(orig.x)); | |
} | |
return normalize(vec3(coord.x, y + 0.0001, coord.y)); | |
} | |
#if defined(LINEAR_FOG_ENABLED) && defined(IS_FRAGMENT_SHADER) | |
vec4 CalcFogWithDistance(vec4 color, float z) | |
{ | |
float fogFactor = ( SceneUBO.fogEnd - z ) / ( SceneUBO.fogEnd - SceneUBO.fogStart ); | |
fogFactor = clamp(fogFactor, 0.0, 1.0); | |
color.xyz = mix(SceneUBO.fogColor.xyz, color.xyz, fogFactor ); | |
return color; | |
} | |
vec4 CalcFog(vec4 color) | |
{ | |
return CalcFogWithDistance(color, gl_FragCoord.z / gl_FragCoord.w); | |
} | |
#elif defined(EXP_FOG_ENABLED) && defined(IS_FRAGMENT_SHADER) | |
vec4 CalcFogWithDistance(vec4 color, float z) | |
{ | |
float f = SceneUBO.fogDensity * z; | |
float fogFactor = exp( -f ); | |
fogFactor = clamp(fogFactor, 0.0, 1.0); | |
color.xyz = mix(SceneUBO.fogColor.xyz, color.xyz, fogFactor ); | |
return color; | |
} | |
vec4 CalcFog(vec4 color) | |
{ | |
return CalcFogWithDistance(color, gl_FragCoord.z / gl_FragCoord.w); | |
} | |
#elif defined(EXP2_FOG_ENABLED) && defined(IS_FRAGMENT_SHADER) | |
vec4 CalcFogWithDistance(vec4 color, float z) | |
{ | |
//const float LOG2 = 1.442695; | |
//float fogFactor = exp2( -SceneUBO.fogDensity * SceneUBO.fogDensity * z * z * LOG2 ); | |
float f = SceneUBO.fogDensity * z / 1.8; | |
float fogFactor = exp(-f*f); | |
fogFactor = clamp(fogFactor, 0.0, 1.0); | |
color.xyz = mix(SceneUBO.fogColor.xyz, color.xyz, fogFactor ); | |
return color; | |
} | |
vec4 CalcFog(vec4 color) | |
{ | |
return CalcFogWithDistance(color, gl_FragCoord.z / gl_FragCoord.w); | |
} | |
#else | |
vec4 CalcFog(vec4 color) | |
{ | |
return color; | |
} | |
vec4 CalcFogWithDistance(vec4 color, float z) | |
{ | |
return color; | |
} | |
#endif | |
vec4 GammaToLinear(vec4 color) | |
{ | |
color.rgb = pow(color.rgb, vec3(SceneUBO.v_gamma)); | |
return color; | |
} | |
vec4 TexGammaToLinear(vec4 color) | |
{ | |
color.rgb = pow(color.rgb, vec3(SceneUBO.v_texgamma)); | |
return color; | |
} | |
//This was being applied for GL_Upload16 | |
vec4 TexGammaToGamma(vec4 color) | |
{ | |
color.rgb = pow(color.rgb, vec3(SceneUBO.v_texgamma * SceneUBO.r_g));//r_g = 1.0 / v_gamma | |
return color; | |
} | |
vec4 LinearToGamma(vec4 color) | |
{ | |
color.rgb = pow(color.rgb, vec3(SceneUBO.r_g));//r_g = 1.0 / v_gamma | |
return color; | |
} | |
vec3 LinearToGamma3(vec3 color) | |
{ | |
color.rgb = pow(color.rgb, vec3(SceneUBO.r_g));//r_g = 1.0 / v_gamma | |
return color; | |
} | |
//This was being applied for R_BuildLightMap and R_StudioLighting | |
float LightGammaToGammaInternal(float color) | |
{ | |
float fv = pow(color, SceneUBO.v_lightgamma); | |
fv = fv * max(SceneUBO.v_brightness, 1.0); | |
//if (fv > SceneUBO.r_g3) | |
float fv1 = 0.125 + ((fv - SceneUBO.r_g3) / (1.0 - SceneUBO.r_g3)) * 0.875; | |
//else | |
float fv2 = (fv / SceneUBO.r_g3) * 0.125; | |
fv = clamp(fv1, fv2, step(fv, SceneUBO.r_g3)); | |
return clamp(pow( fv, SceneUBO.r_g ), 0.0, 1.0); | |
} | |
vec4 LightGammaToGamma(vec4 color) | |
{ | |
return vec4(LightGammaToGammaInternal(color.r), LightGammaToGammaInternal(color.g), LightGammaToGammaInternal(color.b), color.a); | |
} | |
float LightGammaToLinearInternal(float color) | |
{ | |
float fv = pow(color, SceneUBO.v_lightgamma); | |
fv = fv * max(SceneUBO.v_brightness, 1.0); | |
fv = mix( | |
0.125 + ((fv - SceneUBO.r_g3) / (1.0 - SceneUBO.r_g3)) * 0.875, | |
(fv / SceneUBO.r_g3) * 0.125, | |
step(fv, SceneUBO.r_g3)); | |
/*if (fv > SceneUBO.r_g3) | |
fv = 0.125 + ((fv - SceneUBO.r_g3) / (1.0 - SceneUBO.r_g3)) * 0.875; | |
else | |
fv = (fv / SceneUBO.r_g3) * 0.125;*/ | |
return clamp(fv, 0.0, 1.0); | |
} | |
vec4 LightGammaToLinear(vec4 color) | |
{ | |
return vec4(LightGammaToLinearInternal(color.r), LightGammaToLinearInternal(color.g), LightGammaToLinearInternal(color.b), color.a); | |
} | |
#if defined(IS_FRAGMENT_SHADER) | |
void ClipPlaneTest(vec3 worldpos, vec3 normal) | |
{ | |
#if defined(CLIP_WATER_ENABLED) | |
vec4 clipVec = vec4(worldpos.xyz, 1.0); | |
vec4 clipPlane = SceneUBO.clipPlane; | |
if(dot(clipVec, clipPlane) < 0) | |
discard; | |
clipPlane.w += 32.0; | |
if(dot(clipVec, clipPlane) < 0 && dot(normalize(normal.xyz), -clipPlane.xyz) > 0.866) | |
discard; | |
#elif defined(CLIP_ENABLED) | |
vec4 clipVec = vec4(worldpos.xyz - SceneUBO.clipPlane.xyz * 4.0, -1.0); | |
vec4 clipPlane = SceneUBO.clipPlane; | |
if(dot(clipVec, clipPlane) > 0) | |
discard; | |
#endif | |
} | |
#else | |
void ClipPlaneTest(vec3 worldpos, vec3 normal) | |
{ | |
} | |
#endif | |
uniform float u_parallaxScale; | |
#ifndef BINDLESS_ENABLED | |
layout(binding = 0) uniform sampler2D diffuseTex; | |
layout(binding = 1) uniform sampler2DArray lightmapTexArray; | |
layout(binding = 2) uniform sampler2D detailTex; | |
layout(binding = 3) uniform sampler2D normalTex; | |
layout(binding = 4) uniform sampler2D parallaxTex; | |
layout(binding = 5) uniform sampler2D specularTex; | |
layout(binding = 6) uniform sampler2DArray shadowmapTexArray; | |
#else | |
layout(binding = 1) uniform sampler2DArray lightmapTexArray; | |
layout(binding = 6) uniform sampler2DArray shadowmapTexArray; | |
#endif | |
in vec3 v_worldpos; | |
in vec3 v_normal; | |
in vec3 v_tangent; | |
in vec3 v_bitangent; | |
in vec2 v_diffusetexcoord; | |
in vec3 v_lightmaptexcoord; | |
in vec2 v_replacetexcoord; | |
in vec2 v_detailtexcoord; | |
in vec2 v_normaltexcoord; | |
in vec2 v_parallaxtexcoord; | |
in vec2 v_speculartexcoord; | |
in vec4 v_shadowcoord[3]; | |
#ifdef BINDLESS_ENABLED | |
#if defined(SKYBOX_ENABLED) | |
flat in int v_drawid; | |
#elif defined(DECAL_ENABLED) | |
flat in int v_decalindex; | |
#else | |
flat in int v_texindex; | |
#endif | |
#endif | |
#ifdef GBUFFER_ENABLED | |
#if defined(DECAL_ENABLED) | |
//Decal only affects diffuse and worldnorm channel | |
layout(location = 0) out vec4 out_Diffuse; | |
layout(location = 1) out vec4 out_WorldNorm; | |
#else | |
layout(location = 0) out vec4 out_Diffuse; | |
layout(location = 1) out vec4 out_Lightmap; | |
layout(location = 2) out vec4 out_WorldNorm; | |
layout(location = 3) out vec4 out_Specular; | |
layout(location = 4) out vec4 out_Additive; | |
#endif | |
#else | |
layout(location = 0) out vec4 out_Diffuse; | |
#endif | |
#ifdef BINDLESS_ENABLED | |
texture_handle_t GetCurrentTextureHandle(int type) | |
{ | |
#if defined(SKYBOX_ENABLED) | |
return SkyboxSSBO[v_drawid]; | |
#elif defined(DECAL_ENABLED) | |
return DecalSSBO[v_decalindex * TEXTURE_SSBO_MAX + type]; | |
#else | |
return TextureSSBO[v_texindex * TEXTURE_SSBO_MAX + type]; | |
#endif | |
} | |
#endif | |
#ifdef NORMALTEXTURE_ENABLED | |
vec3 NormalMapping(vec3 T, vec3 B, vec3 N, vec2 baseTexcoord) | |
{ | |
#ifdef BINDLESS_ENABLED | |
sampler2D normalTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_NORMAL)); | |
#endif | |
// Create TBN matrix. from tangent to world space | |
mat3 TBN = mat3(normalize(T), normalize(B), normalize(N)); | |
vec2 vNormTexcoord = vec2(baseTexcoord.x * v_normaltexcoord.x, baseTexcoord.y * v_normaltexcoord.y); | |
// Sample tangent space normal vector from normal map and remap it from [0, 1] to [-1, 1] range. | |
vec3 n = texture2D(normalTex, vNormTexcoord).xyz; | |
n = normalize(n * 2.0 - 1.0); | |
// Multiple normal by the TBN matrix to transform the normal from tangent space to world space. | |
n = normalize(TBN * n); | |
return n; | |
} | |
#endif | |
#ifdef PARALLAXTEXTURE_ENABLED | |
vec2 ParallaxMapping(vec3 T, vec3 B, vec3 N, vec3 viewDirWorld, vec2 baseTexcoord) | |
{ | |
#ifdef BINDLESS_ENABLED | |
sampler2D parallaxTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_PARALLAX)); | |
#endif | |
// Create TBN matrix. | |
mat3 TBN = mat3(normalize(T), normalize(B), normalize(N)); | |
//Multiple viewDir by the TBN matrix to transform the normal from tangent space to world space. | |
vec3 viewDir = normalize(transpose(TBN) * viewDirWorld); | |
const float minLayers = 20; | |
const float maxLayers = 40; | |
float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0.0f, 0.0f, 1.0f), viewDir))); | |
float layerDepth = 1.0 / numLayers; | |
float currentLayerDepth = 0.0; | |
vec2 p = viewDir.xy / viewDir.z * u_parallaxScale; | |
vec2 deltaTexCoords = p / numLayers; | |
vec2 mainTexCoods = baseTexcoord; | |
vec2 currentTexCoords = mainTexCoods; | |
vec2 ddx = dFdx(mainTexCoods); | |
vec2 ddy = dFdy(mainTexCoods); | |
float currentDepthMapValue = 1.0 - textureGrad(parallaxTex, vec2(currentTexCoords.x * v_parallaxtexcoord.x, currentTexCoords.y * v_parallaxtexcoord.y), ddx, ddy ).r; | |
while(currentLayerDepth < currentDepthMapValue) | |
{ | |
currentTexCoords -= deltaTexCoords; | |
currentDepthMapValue = 1.0 - textureGrad(parallaxTex, vec2(currentTexCoords.x * v_parallaxtexcoord.x, currentTexCoords.y * v_parallaxtexcoord.y), ddx, ddy ).r; | |
currentLayerDepth += layerDepth; | |
} | |
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; | |
// get depth after and before collision for linear interpolation | |
float afterDepth = currentDepthMapValue - currentLayerDepth; | |
float beforeDepth = 1.0 - textureGrad(parallaxTex, vec2(prevTexCoords.x * v_parallaxtexcoord.x, prevTexCoords.y * v_parallaxtexcoord.y), ddx, ddy ).r - currentLayerDepth + layerDepth; | |
// interpolation of texture coordinates | |
float weight = afterDepth / (afterDepth - beforeDepth); | |
vec2 finalTexCoords = mix(currentTexCoords, prevTexCoords, weight); | |
return finalTexCoords; | |
} | |
#endif | |
float ShadowCompareDepth(vec4 coord, vec2 off, float layer) | |
{ | |
vec4 newcoord = coord + vec4(off.x * SHADOW_TEXTURE_OFFSET, off.y * SHADOW_TEXTURE_OFFSET, 0.0, 0.0); | |
float depth0 = texture2DArray(shadowmapTexArray, vec3(newcoord.xy / newcoord.w, layer) ).a; | |
float depth1 = newcoord.z / newcoord.w; | |
return depth0 < depth1 ? 0.0 : 1.0; | |
} | |
vec3 ShadowGetWorldPosition(vec4 coord, float layer) | |
{ | |
return texture2DArray(shadowmapTexArray, vec3(coord.xy / coord.w, layer) ).xyz; | |
} | |
float CalcShadowIntensityInternal(vec3 worldpos, int ilayer, float layer, float shadow_high, float shadow_medium, float shadow_low) | |
{ | |
float shadow_intensity = 1.0; | |
vec3 scene = worldpos.xyz; | |
vec3 caster = ShadowGetWorldPosition(v_shadowcoord[ilayer], layer); | |
float dist = abs(caster.z - scene.z); | |
float distlerp = (dist - SceneUBO.shadowFade.x) / SceneUBO.shadowFade.y; | |
shadow_intensity *= 1.0 - clamp(distlerp, 0.0, 1.0); | |
shadow_high = 1.0 - shadow_high; | |
shadow_medium = 1.0 - shadow_medium; | |
shadow_low = 1.0 - shadow_low; | |
float shadow_final = shadow_high + shadow_medium + shadow_low; | |
shadow_final = clamp(shadow_final, 0.0, 1.0) * shadow_intensity; | |
return shadow_final;//0 = shadow, 1 = no shadow | |
} | |
float CalcShadowIntensity(vec3 worldpos, vec3 norm, vec3 lightdir) | |
{ | |
float shadow_final = 0.0; | |
if(dot(norm.xyz, lightdir.xyz) < 0.0) | |
{ | |
float shadow_high = 1.0; | |
#ifdef SHADOWMAP_HIGH_ENABLED | |
shadow_high = 0.0; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2(0.0,0.0), 0.0) * 0.25; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( -1.0, -1.0), 0.0) * 0.0625; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( -1.0, 0.0), 0.0) * 0.125; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( -1.0, 1.0), 0.0) * 0.0625; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( 0.0, -1.0), 0.0) * 0.125; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( 0.0, 1.0), 0.0) * 0.125; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( 1.0, -1.0), 0.0) * 0.0625; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( 1.0, 0.0), 0.0) * 0.125; | |
shadow_high += ShadowCompareDepth(v_shadowcoord[0], vec2( 1.0, 1.0), 0.0) * 0.0625; | |
#endif | |
float shadow_medium = 1.0; | |
#ifdef SHADOWMAP_MEDIUM_ENABLED | |
shadow_medium = 0.0; | |
shadow_medium += ShadowCompareDepth(v_shadowcoord[1], vec2(0.0,0.0), 1.0); | |
shadow_medium += ShadowCompareDepth(v_shadowcoord[1], vec2(0.035,0.0), 1.0); | |
shadow_medium += ShadowCompareDepth(v_shadowcoord[1], vec2(-0.035,0.0), 1.0); | |
shadow_medium += ShadowCompareDepth(v_shadowcoord[1], vec2(0.0,0.035), 1.0); | |
shadow_medium += ShadowCompareDepth(v_shadowcoord[1], vec2(0.0,-0.035), 1.0); | |
shadow_medium *= 0.2; | |
#endif | |
float shadow_low = 1.0; | |
#ifdef SHADOWMAP_LOW_ENABLED | |
shadow_low = 0.0; | |
shadow_low += ShadowCompareDepth(v_shadowcoord[2], vec2(0.0,0.0), 2.0); | |
shadow_low += ShadowCompareDepth(v_shadowcoord[2], vec2(0.035,0.0), 2.0); | |
shadow_low += ShadowCompareDepth(v_shadowcoord[2], vec2(-0.035,0.0), 2.0); | |
shadow_low += ShadowCompareDepth(v_shadowcoord[2], vec2(0.0,0.035), 2.0); | |
shadow_low += ShadowCompareDepth(v_shadowcoord[2], vec2(0.0,-0.035), 2.0); | |
shadow_low *= 0.2; | |
#endif | |
if(false) | |
{ | |
//nothing here | |
} | |
#ifdef SHADOWMAP_HIGH_ENABLED | |
else if(shadow_high < 0.95) | |
{ | |
shadow_final = CalcShadowIntensityInternal(worldpos, 0, 0.0, shadow_high, shadow_medium, shadow_low); | |
} | |
#endif | |
#ifdef SHADOWMAP_MEDIUM_ENABLED | |
else if(shadow_medium < 0.95) | |
{ | |
shadow_final = CalcShadowIntensityInternal(worldpos, 1, 1.0, shadow_high, shadow_medium, shadow_low); | |
} | |
#endif | |
#ifdef SHADOWMAP_LOW_ENABLED | |
else if(shadow_low < 0.95) | |
{ | |
shadow_final = CalcShadowIntensityInternal(worldpos, 2, 2.0, shadow_high, shadow_medium, shadow_low); | |
} | |
#endif | |
} | |
return shadow_final; | |
} | |
float CalcShadowIntensityLumFadeout(vec4 lightmapColor, float intensity) | |
{ | |
float lightmapLum = 0.299 * lightmapColor.x + 0.587 * lightmapColor.y + 0.114 * lightmapColor.z; | |
float shadowLerp = (lightmapLum - SceneUBO.shadowFade.w) / (SceneUBO.shadowFade.z - SceneUBO.shadowFade.w); | |
float shadowIntensity = intensity * clamp(shadowLerp, 0.0, 1.0); | |
shadowIntensity *= SceneUBO.shadowColor.a; | |
return shadowIntensity; | |
} | |
void main() | |
{ | |
#ifndef SKYBOX_ENABLED | |
ClipPlaneTest(v_worldpos.xyz, v_normal.xyz); | |
#endif | |
vec2 baseTexcoord = vec2(0.0, 0.0); | |
#ifdef DIFFUSE_ENABLED | |
#ifdef REPLACETEXTURE_ENABLED | |
#ifdef BINDLESS_ENABLED | |
sampler2D diffuseTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_REPLACE)); | |
#endif | |
baseTexcoord = vec2(v_diffusetexcoord.x * v_replacetexcoord.x, v_diffusetexcoord.y * v_replacetexcoord.y); | |
#else | |
#ifdef BINDLESS_ENABLED | |
sampler2D diffuseTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_DIFFUSE)); | |
#endif | |
baseTexcoord = v_diffusetexcoord.xy; | |
#endif | |
#ifdef PARALLAXTEXTURE_ENABLED | |
vec3 viewDir = normalize(v_worldpos.xyz - SceneUBO.viewpos.xyz); | |
vec4 diffuseColor = texture(diffuseTex, ParallaxMapping(v_tangent, v_bitangent, v_normal, viewDir, baseTexcoord)); | |
#else | |
vec4 diffuseColor = texture(diffuseTex, baseTexcoord); | |
#endif | |
//dynamic gamma correction will corrupt the alpha-blend routine that decal rendering was using when there was pre-applied texgamma correction. | |
#if !defined(DECAL_ENABLED) | |
diffuseColor = TexGammaToLinear(diffuseColor); | |
#else | |
diffuseColor = TexGammaToLinear(diffuseColor); | |
//so we have to shift the alpha a little bit up... | |
#ifndef TRANSPARENT_ENABLED | |
diffuseColor.a = pow(diffuseColor.a, SceneUBO.r_alpha_shift); | |
#else | |
//Don't do alpha adjustment for decals on transparent surfaces. | |
#endif | |
#endif | |
#else | |
vec4 diffuseColor = vec4(1.0, 1.0, 1.0, 1.0); | |
#endif | |
#ifdef LIGHTMAP_ENABLED | |
vec4 lightmapColor = texture2DArray(lightmapTexArray, v_lightmaptexcoord.xyz); | |
lightmapColor = LightGammaToLinear(lightmapColor); | |
//lightmapColor.x = max(lightmapColor.x, 0.03); | |
//lightmapColor.y = max(lightmapColor.y, 0.03); | |
//lightmapColor.z = max(lightmapColor.z, 0.03); | |
#else | |
vec4 lightmapColor = vec4(1.0, 1.0, 1.0, 1.0); | |
#endif | |
#ifdef NORMALTEXTURE_ENABLED | |
vec3 vNormal = NormalMapping(v_tangent, v_bitangent, v_normal, baseTexcoord); | |
#else | |
vec3 vNormal = normalize(v_normal.xyz); | |
#endif | |
#ifdef DETAILTEXTURE_ENABLED | |
#ifdef BINDLESS_ENABLED | |
sampler2D detailTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_DETAIL)); | |
#endif | |
vec2 detailTexCoord = vec2(baseTexcoord.x * v_detailtexcoord.x, baseTexcoord.y * v_detailtexcoord.y); | |
vec4 detailColor = texture(detailTex, detailTexCoord); | |
detailColor.xyz *= 2.0; | |
detailColor.a = 1.0; | |
detailColor = TexGammaToLinear(detailColor); | |
#else | |
vec4 detailColor = vec4(1.0, 1.0, 1.0, 1.0); | |
#endif | |
#ifdef SHADOW_CASTER_ENABLED | |
out_Diffuse.xyz = v_worldpos.xyz; | |
out_Diffuse.w = gl_FragCoord.z; | |
#else | |
#ifdef SHADOWMAP_ENABLED | |
float shadowIntensity = CalcShadowIntensity(v_worldpos, vNormal, SceneUBO.shadowDirection.xyz); | |
#endif | |
#ifdef GBUFFER_ENABLED | |
vec4 specularColor = vec4(0.0); | |
vec2 vOctNormal = UnitVectorToOctahedron(vNormal); | |
float flDistanceToFragment = distance(v_worldpos.xyz, SceneUBO.viewpos.xyz); | |
#ifdef SPECULARTEXTURE_ENABLED | |
#ifdef BINDLESS_ENABLED | |
sampler2D specularTex = sampler2D(GetCurrentTextureHandle(TEXTURE_SSBO_SPECULAR)); | |
#endif | |
vec2 specularTexCoord = vec2(baseTexcoord.x * v_speculartexcoord.x, baseTexcoord.y * v_speculartexcoord.y); | |
specularColor.xy = texture2D(specularTex, specularTexCoord).xy; | |
#endif | |
#ifdef SHADOWMAP_ENABLED | |
specularColor.z = shadowIntensity; | |
#endif | |
#ifdef DECAL_ENABLED | |
out_Diffuse = diffuseColor * detailColor; | |
out_WorldNorm = vec4(vOctNormal.x, vOctNormal.y, flDistanceToFragment, 0.0); | |
#else | |
out_Diffuse = diffuseColor * detailColor; | |
out_Lightmap = lightmapColor; | |
out_WorldNorm = vec4(vOctNormal.x, vOctNormal.y, flDistanceToFragment, 0.0); | |
out_Specular = specularColor; | |
out_Additive = vec4(0.0); | |
#endif | |
#else | |
#ifdef SHADOWMAP_ENABLED | |
shadowIntensity = CalcShadowIntensityLumFadeout(lightmapColor, shadowIntensity); | |
lightmapColor.xyz *= (1.0 - shadowIntensity); | |
#endif | |
#ifdef TRANSPARENT_ENABLED | |
vec4 color = CalcFog(diffuseColor * lightmapColor * detailColor * EntityUBO.color); | |
#else | |
vec4 color = CalcFog(diffuseColor * lightmapColor * detailColor); | |
#endif | |
#if defined(OIT_ALPHA_BLEND_ENABLED) || defined(OIT_ADDITIVE_BLEND_ENABLED) | |
GatherFragment(color); | |
#endif | |
out_Diffuse = color; | |
#endif | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment