├── .github └── FUNDING.yml ├── README.md └── shaders ├── compatibility ├── bs │ ├── default.frag │ ├── default.vert │ ├── nolighting.frag │ └── nolighting.vert ├── debug.frag ├── debug.vert ├── depthclipped.frag ├── depthclipped.vert ├── fog.glsl ├── fullscreen_tri.frag ├── fullscreen_tri.vert ├── groundcover.frag ├── groundcover.vert ├── gui.frag ├── gui.vert ├── luminance │ ├── luminance.frag │ └── resolve.frag ├── multiview_resolve.frag ├── multiview_resolve.vert ├── objects.frag ├── objects.vert ├── s360.frag ├── s360.vert ├── shadowcasting.frag ├── shadowcasting.vert ├── shadows_fragment.glsl ├── shadows_vertex.glsl ├── sky.frag ├── sky.vert ├── terrain.frag ├── terrain.vert ├── vertexcolors.glsl ├── water.frag └── water.vert ├── core ├── gui.frag ├── gui.vert ├── ripples_blobber.comp └── ripples_simulate.comp └── lib ├── core ├── fragment.glsl ├── fragment.h.glsl ├── fragment_multiview.glsl ├── vertex.glsl ├── vertex.h.glsl └── vertex_multiview.glsl ├── light ├── lighting.glsl └── lighting_util.glsl ├── luminance └── constants.glsl ├── material ├── alpha.glsl └── parallax.glsl ├── particle ├── occlusion.glsl └── soft.glsl ├── sky └── passes.glsl ├── util ├── coordinates.glsl └── quickstep.glsl ├── view └── depth.glsl ├── water ├── fresnel.glsl ├── rain_ripples.glsl └── ripples.glsl └── zesterer ├── config.glsl ├── pbr.glsl ├── rand.glsl ├── sway.glsl ├── warp.glsl ├── water_nm.png └── wave.glsl /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [zesterer] 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zesterer's OpenMW Shader Pack 2 | 3 | Play Morrowind with beautiful shaders like it's 2022, not 2002. 4 | 5 | ## Screenshots 6 | 7 | ![Early morning in Balmora](https://i.imgur.com/1Fa85UT.png) 8 | 9 | *Note that these screenshots were taken with additional mods installed, such as [Morrowind Rebirth](https://www.nexusmods.com/morrowind/mods/37795/).* 10 | 11 |
12 | More screenshots 13 | An early morning view of Vivec 14 | The beaches and tidal pools outside Vivec 15 | Lanterns in the night outside Vivec 16 | Inside a building in Balmora 17 | A tavern in Pelagiad 18 | The grasslands outside Vivec on a misty afternoon 19 |
20 | 21 | ## Status 22 | 23 | Sadly, core shaders for OpenMW are a hack, with no compatibility guarantees. That means that almost every OpenMW release results in the shaders breaking 24 | in some manner. I don't find myself with enough time in my life to keep the shaders up to date with these changes. Occasionally some kind soul sends me a 25 | patch that updates them, but no guarantees are provided about these shaders work with the current version of OpenMW. 26 | 27 | I've noticed that several people have confused this mod with my [Volumetric Clouds & Mist Mod](https://github.com/zesterer/openmw-volumetric-clouds). 28 | The latter is a properly supported mod, and should continue to work with OpenMW for the forseeable future. 29 | 30 | ## Features 31 | 32 | - **Efficient**: in my (very unscientific) tests, only a ~12% framerate hit compared to vanilla OpenMW shaders 33 | - **PBR (Physically-Based Rendering) lighting model**: surfaces reflect light consistently and realistically 34 | - **Support for PBR textures (via specular maps)**: PBR texture mods correctly inform surface lighting 35 | - **Improved sun light colours**: dawn and dusk are red, midday is yellow, night is blue 36 | - **Better ambient illumination**: ambient light is omnidirectional scattered light from the sky, not direct sunlight 37 | - **Brighter point lights**: lights in the scene emit more light, illuminating the world in a more immersive manner 38 | - **Underwater light attenuation**: objects under the water shift towards blue with depth, adding realism 39 | - **Underwater caustics**: underwater scenes experience wavy lighting caused by surface refraction 40 | - **Leaves sway in the wind**: unfortunately, Morrowind has no realiable way to mark leaves so detection is imperfect 41 | - **Sub-surface scattering**: thin objects like grass and leaves allow bright direct light to scatter through them 42 | - **Procedural detail for distant land**: terrain in the distance maintains sharp details 43 | - **Wave shader**: Dynamic waves, froth, and backwash on beaches 44 | - **Easy to configure**: if you prefer realism over bright colours, you can [tweak the shaders](#configuration) accordingly! 45 | 46 | ## Installation Guide 47 | 48 | 1. [Download the shader pack](#download). 49 | 50 | 2. Locate your [`resources/`](https://modding-openmw.com/tips/custom-shaders/#installing) directory. 51 | 52 | 3. Copy the extracted shader pack into `resources/` (make sure to back up anything that was in there 53 | before doing this, should something go wrong). This should result in the following directory structure: 54 | 55 | ``` 56 | resources/ 57 | |-- shaders/ 58 | | |-- compatibility/ 59 | | |-- core/ 60 | | |-- lib/ 61 | '-- README.md 62 | ``` 63 | 64 | 4. Enable required settings 65 | 66 | - Enable [per-pixel lighting](https://openmw.readthedocs.io/en/stable/reference/modding/settings/shaders.html#force-per-pixel-lighting) 67 | - Disable [light clamping](https://openmw.readthedocs.io/en/stable/reference/modding/settings/shaders.html#clamp-lighting) 68 | - Set [lighting method](https://openmw.readthedocs.io/en/latest/reference/modding/settings/shaders.html#lighting-method) to 'shaders' 69 | 70 | 5. Start OpenMW and have fun! 71 | 72 | See the [OpenMW Modding Guide](https://modding-openmw.com/tips/custom-shaders/#installing) for more detailed information 73 | about installing custom shader packs. 74 | 75 | ## Download 76 | 77 | This shader pack currently supports both [development builds]((https://openmw.org/downloads/)) of OpenMW and OpenMW 78 | 0.48 (still in pre-release). I recommend using a development build of OpenMW if you can to get access to all of the 79 | latest funky features of both OpenMW and this shader pack. 80 | 81 | - [For OpenMW Development](https://github.com/zesterer/openmw-shaders/archive/refs/heads/main.zip) 82 | 83 | - [For OpenMW 0.48](https://github.com/zesterer/openmw-shaders/archive/refs/heads/openmw-0.48.zip) 84 | 85 | ## Configuration 86 | 87 | There are various presets and parameters that can be changed via 88 | [`shaders/lib/zesterer/config.glsl`](https://github.com/zesterer/openmw-shaders/blob/main/shaders/lib/zesterer/config.glsl). 89 | 90 | ## Recommendations 91 | 92 | This mod works best with: 93 | 94 | - My [Volumetric Clouds & Mist Mod](https://github.com/zesterer/openmw-volumetric-clouds). 95 | - High-resolution textures, normal maps, etc. where possible 96 | - Wazabear's [post-processing shader effects](https://gitlab.com/glassmancody.info/omwfx-shaders/-/tree/main/) 97 | - Enabled [per-pixel lighting](https://openmw.readthedocs.io/en/stable/reference/modding/settings/shaders.html#force-per-pixel-lighting) 98 | - Disabled [light clamping](https://openmw.readthedocs.io/en/stable/reference/modding/settings/shaders.html#clamp-lighting) 99 | - Enabled [sky blending](https://openmw.readthedocs.io/en/latest/reference/modding/settings/fog.html#sky-blending) 100 | 101 | ## Known Issues 102 | 103 | - Morrowind's assets don't differentiate between 'leaves' and 'not leaves'. As a result, the shaders use a primitive 104 | heuristic to determine what is and is not a leaf for the wind sway effect. This can sometimes cause some objects that 105 | are not leaves (candle flames, banners, baskets, etc.) to exhibit strange swaying behaviour too. If this is too 106 | distracting for you, you can disable wind sway by setting `WIND_AMPLITUDE` to `0.0` in 107 | [`shaders/config.glsl`](https://github.com/zesterer/openmw-shaders/blob/main/shaders/config.glsl). 108 | 109 | - On the version of the mod for OpenMW 0.48, objects reflected in water can have incorrect tinting applied to them. This 110 | is fixed in the version of the mod for OpenMW development builds. 111 | 112 | ## Getting Help & Feedback 113 | 114 | Got a question or a suggestion? Feel free to [open a discussion topic](https://github.com/zesterer/openmw-shaders/discussions/new). 115 | 116 | Please note that I'm not responsible for whatever happens if you use this mod. Pretty much all settings in `config.glsl` 117 | are safe to play around with, but if you somehow manage to make your graphics card explode by plugging in stupid 118 | numbers, that's on you. 119 | 120 | ## License 121 | 122 | The code in this repository is derived from the OpenMW vanilla shaders. Accordingly, the code in this repository is similarly licensed under GPL v3. 123 | -------------------------------------------------------------------------------- /shaders/compatibility/bs/default.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | #pragma import_defines(FORCE_OPAQUE) 3 | 4 | #if @useUBO 5 | #extension GL_ARB_uniform_buffer_object : require 6 | #endif 7 | 8 | #if @useGPUShader4 9 | #extension GL_EXT_gpu_shader4: require 10 | #endif 11 | 12 | #if @diffuseMap 13 | uniform sampler2D diffuseMap; 14 | varying vec2 diffuseMapUV; 15 | #endif 16 | 17 | #if @emissiveMap 18 | uniform sampler2D emissiveMap; 19 | varying vec2 emissiveMapUV; 20 | #endif 21 | 22 | #if @normalMap 23 | uniform sampler2D normalMap; 24 | varying vec2 normalMapUV; 25 | varying vec4 passTangent; 26 | #endif 27 | 28 | varying float euclideanDepth; 29 | varying float linearDepth; 30 | 31 | #define PER_PIXEL_LIGHTING 1 32 | 33 | varying vec3 passViewPos; 34 | varying vec3 passNormal; 35 | 36 | uniform vec2 screenRes; 37 | uniform float far; 38 | uniform float alphaRef; 39 | 40 | uniform mat4 osg_ViewMatrixInverse; 41 | 42 | #include "vertexcolors.glsl" 43 | #include "shadows_fragment.glsl" 44 | #include "lib/light/lighting.glsl" 45 | #include "lib/material/alpha.glsl" 46 | #include "fog.glsl" 47 | 48 | uniform float emissiveMult; 49 | uniform float specStrength; 50 | 51 | void main() 52 | { 53 | vec3 worldNormal = normalize(passNormal); 54 | 55 | #if @diffuseMap 56 | gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV); 57 | gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV); 58 | #else 59 | gl_FragData[0] = vec4(1.0); 60 | #endif 61 | 62 | vec4 diffuseColor = getDiffuseColor(); 63 | gl_FragData[0].a *= diffuseColor.a; 64 | gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); 65 | 66 | #if @normalMap 67 | vec4 normalTex = texture2D(normalMap, normalMapUV); 68 | 69 | vec3 normalizedNormal = worldNormal; 70 | vec3 normalizedTangent = normalize(passTangent.xyz); 71 | vec3 binormal = cross(normalizedTangent, normalizedNormal) * passTangent.w; 72 | mat3 tbnTranspose = mat3(normalizedTangent, binormal, normalizedNormal); 73 | 74 | worldNormal = normalize(tbnTranspose * (normalTex.xyz * 2.0 - 1.0)); 75 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 76 | #else 77 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 78 | #endif 79 | 80 | float shadowing = unshadowedLightRatio(linearDepth); 81 | /* 82 | vec3 diffuseLight, ambientLight; 83 | doLighting(passViewPos, normalize(viewNormal), shadowing, diffuseLight, ambientLight, 0, false); 84 | vec3 emission = getEmissionColor().xyz * emissiveMult; 85 | vec3 lighting = diffuseColor.xyz * diffuseLight + getAmbientColor().xyz * ambientLight + emission; 86 | clampLightingResult(lighting); 87 | gl_FragData[0].xyz *= lighting; 88 | */ 89 | 90 | vec3 emission = getEmissionColor().xyz * emissiveMult; 91 | #if @emissiveMap 92 | emission += texture2D(emissiveMap, emissiveMapUV).xyz; 93 | #endif 94 | 95 | vec3 color = gl_FragData[0].rgb; 96 | 97 | vec3 albedo; float ao; 98 | colorToPbr(color, albedo, ao); 99 | 100 | gl_FragData[0].xyz = getPbr( 101 | osg_ViewMatrixInverse, 102 | passViewPos, 103 | normalize(viewNormal), 104 | albedo, 105 | 0.65, // roughness 106 | 1.0, // base reflectance 107 | 0.0, // metalness 108 | shadowing, 109 | #if SHADOWS 110 | shadowFadeStart, 111 | #else 112 | 3500.0, 113 | #endif 114 | ao, 115 | emission * color, 116 | 0.0, 117 | 0.0, 118 | MAT_DEFAULT 119 | ); 120 | 121 | float shininess = gl_FrontMaterial.shininess; 122 | vec3 matSpec = getSpecularColor().xyz * specStrength; 123 | #if @normalMap 124 | matSpec *= normalTex.a; 125 | #endif 126 | 127 | if (matSpec != vec3(0.0)) 128 | gl_FragData[0].xyz += getSpecular(normalize(viewNormal), normalize(passViewPos.xyz), shininess, matSpec) * shadowing; 129 | 130 | gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); 131 | 132 | #if defined(FORCE_OPAQUE) && FORCE_OPAQUE 133 | // having testing & blending isn't enough - we need to write an opaque pixel to be opaque 134 | gl_FragData[0].a = 1.0; 135 | #endif 136 | 137 | #if !@disableNormals 138 | gl_FragData[1].xyz = worldNormal * 0.5 + 0.5; 139 | #endif 140 | 141 | tonemap(gl_FragData[0].rgb); 142 | 143 | applyShadowDebugOverlay(); 144 | } 145 | -------------------------------------------------------------------------------- /shaders/compatibility/bs/default.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | uniform mat4 projectionMatrix; 12 | 13 | #if @diffuseMap 14 | varying vec2 diffuseMapUV; 15 | #endif 16 | 17 | #if @emissiveMap 18 | varying vec2 emissiveMapUV; 19 | #endif 20 | 21 | #if @normalMap 22 | varying vec2 normalMapUV; 23 | varying vec4 passTangent; 24 | #endif 25 | 26 | varying float euclideanDepth; 27 | varying float linearDepth; 28 | 29 | varying vec3 passViewPos; 30 | varying vec3 passNormal; 31 | 32 | #define PER_PIXEL_LIGHTING 1 33 | 34 | #include "vertexcolors.glsl" 35 | #include "shadows_vertex.glsl" 36 | #include "lib/light/lighting.glsl" 37 | #include "lib/view/depth.glsl" 38 | 39 | void main(void) 40 | { 41 | gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); 42 | 43 | vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); 44 | gl_ClipVertex = viewPos; 45 | euclideanDepth = length(viewPos.xyz); 46 | linearDepth = getLinearDepth(gl_Position.z, viewPos.z); 47 | 48 | #if @diffuseMap 49 | diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; 50 | #endif 51 | 52 | #if @emissiveMap 53 | emissiveMapUV = (gl_TextureMatrix[@emissiveMapUV] * gl_MultiTexCoord@emissiveMapUV).xy; 54 | #endif 55 | 56 | #if @normalMap 57 | normalMapUV = (gl_TextureMatrix[@normalMapUV] * gl_MultiTexCoord@normalMapUV).xy; 58 | passTangent = gl_MultiTexCoord7.xyzw; 59 | #endif 60 | 61 | passColor = gl_Color; 62 | passViewPos = viewPos.xyz; 63 | passNormal = gl_Normal.xyz; 64 | 65 | #if @shadows_enabled 66 | vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); 67 | setupShadowCoords(viewPos, viewNormal); 68 | #endif 69 | } 70 | -------------------------------------------------------------------------------- /shaders/compatibility/bs/nolighting.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | #pragma import_defines(FORCE_OPAQUE) 3 | 4 | #if @useGPUShader4 5 | #extension GL_EXT_gpu_shader4: require 6 | #endif 7 | 8 | #if @diffuseMap 9 | uniform sampler2D diffuseMap; 10 | varying vec2 diffuseMapUV; 11 | #endif 12 | 13 | varying vec3 passNormal; 14 | varying float euclideanDepth; 15 | varying float linearDepth; 16 | varying float passFalloff; 17 | 18 | uniform bool useFalloff; 19 | uniform vec2 screenRes; 20 | uniform float far; 21 | uniform float alphaRef; 22 | 23 | #include "vertexcolors.glsl" 24 | #include "lib/material/alpha.glsl" 25 | #include "fog.glsl 26 | 27 | void main() 28 | { 29 | #if @diffuseMap 30 | gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV); 31 | gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, diffuseMapUV); 32 | #else 33 | gl_FragData[0] = vec4(1.0); 34 | #endif 35 | 36 | gl_FragData[0] *= getDiffuseColor(); 37 | 38 | if (useFalloff) 39 | gl_FragData[0].a *= passFalloff; 40 | 41 | gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); 42 | 43 | gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); 44 | 45 | #if defined(FORCE_OPAQUE) && FORCE_OPAQUE 46 | gl_FragData[0].a = 1.0; 47 | #endif 48 | 49 | #if !defined(FORCE_OPAQUE) && !@disableNormals 50 | vec3 viewNormal = normalize(gl_NormalMatrix * passNormal); 51 | gl_FragData[1].xyz = viewNormal * 0.5 + 0.5; 52 | #endif 53 | 54 | applyShadowDebugOverlay(); 55 | } 56 | -------------------------------------------------------------------------------- /shaders/compatibility/bs/nolighting.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | uniform mat4 projectionMatrix; 12 | 13 | #if @diffuseMap 14 | varying vec2 diffuseMapUV; 15 | #endif 16 | 17 | varying vec3 passNormal; 18 | varying float euclideanDepth; 19 | varying float linearDepth; 20 | varying float passFalloff; 21 | 22 | uniform bool useFalloff; 23 | uniform vec4 falloffParams; 24 | 25 | varying vec3 passViewPos; 26 | varying float passFalloff; 27 | 28 | uniform mat4 osg_ViewMatrixInverse; 29 | uniform mat4 osg_ModelViewMatrix; 30 | uniform sampler2D diffuseMap; 31 | 32 | #include "vertexcolors.glsl" 33 | #include "lib/view/depth.glsl" 34 | #include "lib/zesterer/sway.glsl" 35 | 36 | void main(void) 37 | { 38 | #if @diffuseMap 39 | diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; 40 | #endif 41 | 42 | vec4 modelPos = gl_Vertex; 43 | #if @diffuseMap 44 | doSway(diffuseMap, diffuseMapUV, modelPos.xyz, leafiness); 45 | #endif 46 | gl_Position = projectionMatrix * (gl_ModelViewMatrix * modelPos); 47 | 48 | vec4 viewPos = (gl_ModelViewMatrix * modelPos); 49 | gl_ClipVertex = viewPos; 50 | euclideanDepth = length(viewPos.xyz); 51 | linearDepth = getLinearDepth(gl_Position.z, viewPos.z); 52 | 53 | passColor = gl_Color; 54 | passNormal = gl_Normal.xyz; 55 | if (useFalloff) 56 | { 57 | vec3 viewNormal = gl_NormalMatrix * normalize(gl_Normal.xyz); 58 | vec3 viewDir = normalize(viewPos.xyz); 59 | float viewAngle = abs(dot(viewNormal, viewDir)); 60 | passFalloff = smoothstep(falloffParams.y, falloffParams.x, viewAngle); 61 | } 62 | else 63 | { 64 | passFalloff = 1.0; 65 | } 66 | 67 | #if @shadows_enabled 68 | vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); 69 | setupShadowCoords(viewPos, viewNormal); 70 | #endif 71 | } 72 | -------------------------------------------------------------------------------- /shaders/compatibility/debug.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "vertexcolors.glsl" 4 | 5 | varying vec3 vertexNormal; 6 | 7 | uniform bool useAdvancedShader = false; 8 | 9 | void main() 10 | { 11 | vec3 lightDir = normalize(vec3(-1., -0.5, -2.)); 12 | 13 | float lightAttenuation = dot(-lightDir, vertexNormal) * 0.5 + 0.5; 14 | 15 | if(!useAdvancedShader) 16 | { 17 | gl_FragData[0] = getDiffuseColor(); 18 | } 19 | else 20 | { 21 | gl_FragData[0] = vec4(passColor.xyz * lightAttenuation, 1.); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /shaders/compatibility/debug.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/core/vertex.h.glsl" 4 | 5 | uniform vec3 color; 6 | uniform vec3 trans; 7 | uniform vec3 scale; 8 | uniform bool useNormalAsColor; 9 | uniform bool useAdvancedShader = false; 10 | 11 | centroid varying vec4 passColor; 12 | varying vec3 vertexNormal; 13 | 14 | void main() 15 | { 16 | if(!useAdvancedShader) 17 | { 18 | gl_Position = modelToClip( vec4(gl_Vertex)); 19 | vertexNormal = vec3(1., 1., 1.); 20 | passColor = gl_Color; 21 | } 22 | else 23 | { 24 | gl_Position = modelToClip( vec4(gl_Vertex.xyz * scale + trans,1)); 25 | 26 | vertexNormal = useNormalAsColor ? vec3(1., 1., 1.) : gl_Normal.xyz; 27 | vec3 colorOut = useNormalAsColor? gl_Normal.xyz : color; 28 | passColor = vec4(colorOut, 1.); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /shaders/compatibility/depthclipped.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform sampler2D diffuseMap; 4 | 5 | varying vec2 diffuseMapUV; 6 | varying float alphaPassthrough; 7 | 8 | void main() 9 | { 10 | float alpha = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; 11 | 12 | const float alphaRef = 0.499; 13 | 14 | if (alpha < alphaRef) 15 | discard; 16 | 17 | // DO NOT write to color! 18 | // This is in charge of only updating depth buffer. 19 | } 20 | -------------------------------------------------------------------------------- /shaders/compatibility/depthclipped.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | varying vec2 diffuseMapUV; 12 | varying float alphaPassthrough; 13 | 14 | uniform mat4 osg_ViewMatrixInverse; 15 | uniform sampler2D diffuseMap; 16 | 17 | #include "lib/core/vertex.h.glsl" 18 | #include "vertexcolors.glsl" 19 | #include "lib/zesterer/sway.glsl" 20 | 21 | void main() 22 | { 23 | vec4 modelPos = gl_Vertex; 24 | float leafiness; 25 | doSway(diffuseMap, diffuseMapUV, modelPos.xyz, leafiness); 26 | 27 | gl_Position = modelToClip(modelPos); 28 | 29 | vec4 viewPos = modelToView(modelPos); 30 | gl_ClipVertex = viewPos; 31 | 32 | if (colorMode == 2) 33 | alphaPassthrough = gl_Color.a; 34 | else 35 | alphaPassthrough = gl_FrontMaterial.diffuse.a; 36 | 37 | diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 38 | } 39 | -------------------------------------------------------------------------------- /shaders/compatibility/fog.glsl: -------------------------------------------------------------------------------- 1 | #if @skyBlending 2 | #include "lib/core/fragment.h.glsl" 3 | 4 | uniform float skyBlendingStart; 5 | #endif 6 | 7 | vec4 applyFogAtDist(vec4 color, float euclideanDist, float linearDist, float far) 8 | { 9 | #if @radialFog 10 | float dist = euclideanDist; 11 | #else 12 | float dist = abs(linearDist); 13 | #endif 14 | #if @exponentialFog 15 | float fogValue = 1.0 - exp(-2.0 * max(0.0, dist - gl_Fog.start/2.0) / (gl_Fog.end - gl_Fog.start/2.0)); 16 | #else 17 | float fogValue = clamp((dist - gl_Fog.start) * gl_Fog.scale, 0.0, 1.0); 18 | #endif 19 | #ifdef ADDITIVE_BLENDING 20 | color.xyz *= 1.0 - fogValue; 21 | #else 22 | color.xyz = mix(color.xyz, gl_Fog.color.xyz, fogValue); 23 | #endif 24 | 25 | #if @skyBlending && !@useOVR_multiview 26 | float fadeValue = clamp((far - dist) / (far - skyBlendingStart), 0.0, 1.0); 27 | fadeValue *= fadeValue; 28 | #ifdef ADDITIVE_BLENDING 29 | color.xyz *= fadeValue; 30 | #else 31 | color.xyz = mix(sampleSkyColor(gl_FragCoord.xy / screenRes), color.xyz, fadeValue); 32 | #endif 33 | #endif 34 | 35 | return color; 36 | } 37 | 38 | #if (BUILTIN_FOG == 1) 39 | vec4 applyFogAtPos(vec4 color, vec3 pos, float far) 40 | { 41 | return applyFogAtDist(color, length(pos), pos.z, far); 42 | } 43 | #else 44 | vec4 applyFogAtPos(in vec4 color, in vec3 pos, float far) { return color; } 45 | #endif 46 | -------------------------------------------------------------------------------- /shaders/compatibility/fullscreen_tri.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 uv; 4 | 5 | #include "lib/core/fragment.h.glsl" 6 | 7 | void main() 8 | { 9 | gl_FragColor = samplerLastShader(uv); 10 | } 11 | -------------------------------------------------------------------------------- /shaders/compatibility/fullscreen_tri.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 uv; 4 | 5 | #include "lib/core/vertex.h.glsl" 6 | 7 | void main() 8 | { 9 | gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); 10 | uv = gl_Position.xy * 0.5 + 0.5; 11 | } 12 | -------------------------------------------------------------------------------- /shaders/compatibility/groundcover.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | #define GROUNDCOVER 12 | 13 | #if @diffuseMap 14 | uniform sampler2D diffuseMap; 15 | varying vec2 diffuseMapUV; 16 | #endif 17 | 18 | #if @normalMap 19 | #define NORMAL_MAP 20 | uniform sampler2D normalMap; 21 | varying vec2 normalMapUV; 22 | varying vec4 passTangent; 23 | #endif 24 | 25 | // Other shaders respect forcePPL, but legacy groundcover mods were designed to work with vertex lighting. 26 | // They may do not look as intended with per-pixel lighting, so ignore this setting for now. 27 | #define PER_PIXEL_LIGHTING 1//@normalMap 28 | 29 | varying float euclideanDepth; 30 | varying float linearDepth; 31 | uniform vec2 screenRes; 32 | uniform float far; 33 | uniform float alphaRef; 34 | 35 | #if PER_PIXEL_LIGHTING 36 | varying vec3 passViewPos; 37 | #else 38 | centroid varying vec3 passLighting; 39 | centroid varying vec3 shadowDiffuseLighting; 40 | #endif 41 | 42 | varying vec3 passNormal; 43 | 44 | uniform mat4 osg_ViewMatrixInverse; 45 | uniform mat4 osg_ModelViewMatrix; 46 | uniform mat4 osg_ViewMatrix; 47 | 48 | #include "shadows_fragment.glsl" 49 | #include "lib/light/lighting.glsl" 50 | #include "lib/material/alpha.glsl" 51 | #include "fog.glsl" 52 | 53 | void main() 54 | { 55 | vec3 worldNormal = normalize(passNormal); 56 | #if @normalMap 57 | vec4 normalTex = texture2D(normalMap, normalMapUV); 58 | 59 | vec3 normalizedNormal = worldNormal; 60 | vec3 normalizedTangent = normalize(passTangent.xyz); 61 | vec3 binormal = cross(normalizedTangent, normalizedNormal) * passTangent.w; 62 | mat3 tbnTranspose = mat3(normalizedTangent, binormal, normalizedNormal); 63 | 64 | worldNormal = normalize(tbnTranspose * (normalTex.xyz * 2.0 - 1.0)); 65 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 66 | #else 67 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 68 | #endif 69 | 70 | #if @diffuseMap 71 | gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV); 72 | #else 73 | gl_FragData[0] = vec4(1.0); 74 | #endif 75 | 76 | vec3 wPos = (osg_ViewMatrixInverse * osg_ModelViewMatrix * vec4(passViewPos, 1)).xyz; 77 | float waterDepth = max(-wPos.z, 0); 78 | 79 | if (euclideanDepth > @groundcoverFadeStart) 80 | gl_FragData[0].a *= 1.0-smoothstep(@groundcoverFadeStart, @groundcoverFadeEnd, euclideanDepth); 81 | 82 | gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); 83 | 84 | float shadowing = unshadowedLightRatio(linearDepth); 85 | 86 | vec3 lighting; 87 | #if !PER_PIXEL_LIGHTING 88 | lighting = passLighting + gl_LightModel.ambient.xyz + shadowDiffuseLighting * shadowing; 89 | gl_FragData[0].xyz *= lighting; 90 | #else 91 | /* 92 | vec3 diffuseLight, ambientLight; 93 | doLighting(passViewPos, normalize(viewNormal), shadowing, diffuseLight, ambientLight, 1, false); 94 | lighting = diffuseLight + ambientLight; 95 | clampLightingResult(lighting); 96 | */ 97 | 98 | vec3 color = gl_FragData[0].rgb; 99 | 100 | vec3 albedo; float ao; 101 | colorToPbr(color, albedo, ao); 102 | 103 | gl_FragData[0].xyz = getPbr( 104 | osg_ViewMatrixInverse, 105 | passViewPos, 106 | viewNormal, 107 | albedo, 108 | 0.75, // roughness 109 | 0.5, // base reflectance 110 | 0.0, // metalness 111 | shadowing, 112 | #if SHADOWS 113 | shadowFadeStart, 114 | #else 115 | 3500.0, 116 | #endif 117 | ao, 118 | vec3(0.0), 119 | 0.5, 120 | waterDepth, 121 | MAT_DEFAULT 122 | ); 123 | #endif 124 | 125 | clampLightingResult(gl_FragData[0].xyz); 126 | 127 | gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); 128 | 129 | #if !@disableNormals 130 | gl_FragData[1].xyz = worldNormal * 0.5 + 0.5; 131 | #endif 132 | 133 | tonemap(gl_FragData[0].rgb); 134 | debug_materials(gl_FragData[0].rgb); 135 | 136 | applyShadowDebugOverlay(); 137 | } 138 | -------------------------------------------------------------------------------- /shaders/compatibility/groundcover.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | #define GROUNDCOVER 12 | 13 | #include "lib/core/vertex.h.glsl" 14 | 15 | attribute vec4 aOffset; 16 | attribute vec3 aRotation; 17 | 18 | #if @diffuseMap 19 | varying vec2 diffuseMapUV; 20 | #endif 21 | 22 | #if @normalMap 23 | varying vec2 normalMapUV; 24 | varying vec4 passTangent; 25 | #endif 26 | 27 | // Other shaders respect forcePPL, but legacy groundcover mods were designed to work with vertex lighting. 28 | // They may do not look as intended with per-pixel lighting, so ignore this setting for now. 29 | #define PER_PIXEL_LIGHTING 1//@normalMap 30 | 31 | varying float euclideanDepth; 32 | varying float linearDepth; 33 | 34 | #if PER_PIXEL_LIGHTING 35 | varying vec3 passViewPos; 36 | #else 37 | centroid varying vec3 passLighting; 38 | centroid varying vec3 shadowDiffuseLighting; 39 | #endif 40 | 41 | varying vec3 passNormal; 42 | 43 | #include "shadows_vertex.glsl" 44 | #include "lib/zesterer/warp.glsl" 45 | #include "lib/light/lighting.glsl" 46 | #include "lib/view/depth.glsl" 47 | 48 | uniform float osg_SimulationTime; 49 | uniform float windSpeed; 50 | uniform vec3 playerPos; 51 | 52 | #if @groundcoverStompMode == 0 53 | #else 54 | #define STOMP 1 55 | #if @groundcoverStompMode == 2 56 | #define STOMP_HEIGHT_SENSITIVE 1 57 | #endif 58 | #define STOMP_INTENSITY_LEVEL @groundcoverStompIntensity 59 | #endif 60 | 61 | vec2 groundcoverDisplacement(in vec3 worldpos, float h) 62 | { 63 | vec2 windDirection = vec2(1.0); 64 | vec3 footPos = playerPos; 65 | vec3 windVec = vec3(windSpeed * windDirection, 1.0); 66 | 67 | float v = length(windVec); 68 | vec2 displace = vec2(2.0 * windVec + 1.5); 69 | vec2 harmonics = vec2(0.0); 70 | 71 | harmonics += vec2((1.0 - 0.10*v) * sin(1.0*osg_SimulationTime + worldpos.xy / 1100.0)); 72 | harmonics += vec2((1.0 - 0.04*v) * cos(2.0*osg_SimulationTime + worldpos.xy / 750.0)); 73 | harmonics += vec2((1.0 + 0.14*v) * sin(3.0*osg_SimulationTime + worldpos.xy / 500.0)); 74 | harmonics += vec2((1.0 + 0.28*v) * sin(5.0*osg_SimulationTime + worldpos.xy / 200.0)); 75 | 76 | vec2 stomp = vec2(0.0); 77 | #if STOMP 78 | float d = length(worldpos.xy - footPos.xy); 79 | #if STOMP_INTENSITY_LEVEL == 0 80 | // Gentle intensity 81 | const float STOMP_RANGE = 50.0; // maximum distance from player that grass is affected by stomping 82 | const float STOMP_DISTANCE = 20.0; // maximum distance stomping can move grass 83 | #elif STOMP_INTENSITY_LEVEL == 1 84 | // Reduced intensity 85 | const float STOMP_RANGE = 80.0; 86 | const float STOMP_DISTANCE = 40.0; 87 | #elif STOMP_INTENSITY_LEVEL == 2 88 | // MGE XE intensity 89 | const float STOMP_RANGE = 150.0; 90 | const float STOMP_DISTANCE = 60.0; 91 | #endif 92 | if (d < STOMP_RANGE && d > 0.0) 93 | stomp = (STOMP_DISTANCE / d - STOMP_DISTANCE / STOMP_RANGE) * (worldpos.xy - footPos.xy); 94 | 95 | #ifdef STOMP_HEIGHT_SENSITIVE 96 | stomp *= clamp((worldpos.z - footPos.z) / h, 0.0, 1.0); 97 | #endif 98 | #endif 99 | 100 | return clamp(0.02 * h, 0.0, 1.0) * (harmonics * displace + stomp); 101 | } 102 | 103 | mat4 rotation(in vec3 angle) 104 | { 105 | float sin_x = sin(angle.x); 106 | float cos_x = cos(angle.x); 107 | float sin_y = sin(angle.y); 108 | float cos_y = cos(angle.y); 109 | float sin_z = sin(angle.z); 110 | float cos_z = cos(angle.z); 111 | 112 | return mat4( 113 | cos_z*cos_y+sin_x*sin_y*sin_z, -sin_z*cos_x, cos_z*sin_y+sin_z*sin_x*cos_y, 0.0, 114 | sin_z*cos_y+cos_z*sin_x*sin_y, cos_z*cos_x, sin_z*sin_y-cos_z*sin_x*cos_y, 0.0, 115 | -sin_y*cos_x, sin_x, cos_x*cos_y, 0.0, 116 | 0.0, 0.0, 0.0, 1.0); 117 | } 118 | 119 | mat3 rotation3(in mat4 rot4) 120 | { 121 | return mat3( 122 | rot4[0].xyz, 123 | rot4[1].xyz, 124 | rot4[2].xyz); 125 | } 126 | 127 | void main(void) 128 | { 129 | vec3 position = aOffset.xyz; 130 | float scale = aOffset.w; 131 | 132 | mat4 rotation = rotation(aRotation); 133 | vec4 displacedVertex = rotation * scale * gl_Vertex; 134 | 135 | displacedVertex = vec4(displacedVertex.xyz + position, 1.0); 136 | 137 | vec4 worldPos = osg_ViewMatrixInverse * gl_ModelViewMatrix * displacedVertex; 138 | worldPos.xy += groundcoverDisplacement(worldPos.xyz, gl_Vertex.z); 139 | vec4 viewPos = osg_ViewMatrix * worldPos; 140 | 141 | gl_ClipVertex = viewPos; 142 | euclideanDepth = length(viewPos.xyz); 143 | 144 | if (length(gl_ModelViewMatrix * vec4(position, 1.0)) > @groundcoverFadeEnd) 145 | gl_Position = vec4(0.0, 0.0, 0.0, 1.0); 146 | else 147 | gl_Position = warp_position(viewPos.xyz); 148 | 149 | linearDepth = getLinearDepth(gl_Position.z, viewPos.z); 150 | 151 | #if (!PER_PIXEL_LIGHTING || @shadows_enabled) 152 | vec3 viewNormal = normalize((gl_NormalMatrix * rotation3(rotation) * gl_Normal).xyz); 153 | #endif 154 | 155 | #if @diffuseMap 156 | diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; 157 | #endif 158 | 159 | #if @normalMap 160 | normalMapUV = (gl_TextureMatrix[@normalMapUV] * gl_MultiTexCoord@normalMapUV).xy; 161 | passTangent = gl_MultiTexCoord7.xyzw * rotation; 162 | #endif 163 | 164 | passNormal = rotation3(rotation) * gl_Normal.xyz; 165 | #if PER_PIXEL_LIGHTING 166 | passViewPos = viewPos.xyz; 167 | #else 168 | vec3 diffuseLight, ambientLight; 169 | doLighting(viewPos.xyz, viewNormal, diffuseLight, ambientLight, shadowDiffuseLighting); 170 | passLighting = diffuseLight + ambientLight; 171 | clampLightingResult(passLighting); 172 | #endif 173 | 174 | #if (@shadows_enabled) 175 | setupShadowCoords(viewPos, viewNormal); 176 | #endif 177 | } 178 | -------------------------------------------------------------------------------- /shaders/compatibility/gui.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | uniform sampler2D diffuseMap; 4 | 5 | varying vec2 diffuseMapUV; 6 | varying vec4 passColor; 7 | 8 | void main() 9 | { 10 | gl_FragData[0] = texture2D(diffuseMap, diffuseMapUV) * passColor; 11 | } 12 | -------------------------------------------------------------------------------- /shaders/compatibility/gui.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 diffuseMapUV; 4 | varying vec4 passColor; 5 | 6 | void main() 7 | { 8 | gl_Position = vec4(gl_Vertex.xyz, 1.0); 9 | diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 10 | passColor = gl_Color; 11 | } 12 | -------------------------------------------------------------------------------- /shaders/compatibility/luminance/luminance.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/luminance/constants.glsl" 4 | 5 | varying vec2 uv; 6 | uniform sampler2D sceneTex; 7 | 8 | void main() 9 | { 10 | float lum = dot(texture2D(sceneTex, uv).rgb, vec3(0.2126, 0.7152, 0.0722)); 11 | lum = max(lum, epsilon); 12 | 13 | gl_FragColor.r = clamp((log2(lum) - minLog) * invLogLumRange, 0.0, 1.0); 14 | } 15 | -------------------------------------------------------------------------------- /shaders/compatibility/luminance/resolve.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/luminance/constants.glsl" 4 | 5 | varying vec2 uv; 6 | uniform sampler2D luminanceSceneTex; 7 | uniform sampler2D prevLuminanceSceneTex; 8 | 9 | uniform float osg_DeltaFrameTime; 10 | 11 | void main() 12 | { 13 | float prevLum = texture2D(prevLuminanceSceneTex, vec2(0.5, 0.5)).r; 14 | float currLum = texture2D(luminanceSceneTex, vec2(0.5, 0.5)).r; 15 | 16 | float avgLum = exp2((currLum * logLumRange) + minLog); 17 | gl_FragColor.r = prevLum + (avgLum - prevLum) * (1.0 - exp(-osg_DeltaFrameTime * hdrExposureTime)); 18 | } 19 | -------------------------------------------------------------------------------- /shaders/compatibility/multiview_resolve.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | #extension GL_EXT_texture_array : require 3 | 4 | varying vec2 uv; 5 | uniform sampler2DArray lastShader; 6 | 7 | void main() 8 | { 9 | int view = 0; 10 | vec3 uvz = vec3(uv.x * 2., uv.y, 0); 11 | if(uvz.x > 1.) 12 | { 13 | uvz.x -= 1.; 14 | uvz.z = 1; 15 | } 16 | 17 | gl_FragColor = texture2DArray(lastShader, uvz); 18 | } 19 | -------------------------------------------------------------------------------- /shaders/compatibility/multiview_resolve.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 uv; 4 | 5 | void main() 6 | { 7 | gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); 8 | uv = gl_Position.xy * 0.5 + 0.5; 9 | } 10 | -------------------------------------------------------------------------------- /shaders/compatibility/objects.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | #pragma import_defines(FORCE_OPAQUE) 3 | 4 | #if @useUBO 5 | #extension GL_ARB_uniform_buffer_object : require 6 | #endif 7 | 8 | #if @useGPUShader4 9 | #extension GL_EXT_gpu_shader4: require 10 | #endif 11 | 12 | #if @diffuseMap 13 | uniform sampler2D diffuseMap; 14 | varying vec2 diffuseMapUV; 15 | #endif 16 | 17 | #if @darkMap 18 | #define DARK_MAP 19 | uniform sampler2D darkMap; 20 | varying vec2 darkMapUV; 21 | #endif 22 | 23 | #if @detailMap 24 | uniform sampler2D detailMap; 25 | varying vec2 detailMapUV; 26 | #endif 27 | 28 | #if @decalMap 29 | uniform sampler2D decalMap; 30 | varying vec2 decalMapUV; 31 | #endif 32 | 33 | #if @emissiveMap 34 | #define EMISSIVE_MAP 35 | uniform sampler2D emissiveMap; 36 | varying vec2 emissiveMapUV; 37 | #endif 38 | 39 | #if @normalMap 40 | #define NORMAL_MAP 41 | uniform sampler2D normalMap; 42 | varying vec2 normalMapUV; 43 | varying vec4 passTangent; 44 | #endif 45 | 46 | #if @envMap 47 | uniform sampler2D envMap; 48 | varying vec2 envMapUV; 49 | uniform vec4 envMapColor; 50 | #endif 51 | 52 | #if @specularMap 53 | #define SPECULAR_MAP 54 | uniform sampler2D specularMap; 55 | varying vec2 specularMapUV; 56 | #endif 57 | 58 | #if @bumpMap 59 | #define BUMP_MAP 60 | uniform sampler2D bumpMap; 61 | varying vec2 bumpMapUV; 62 | uniform vec2 envMapLumaBias; 63 | uniform mat2 bumpMapMatrix; 64 | #endif 65 | 66 | #if @glossMap 67 | #define GLOSS_MAP 68 | uniform sampler2D glossMap; 69 | varying vec2 glossMapUV; 70 | #endif 71 | 72 | uniform vec2 screenRes; 73 | uniform float near; 74 | uniform float far; 75 | uniform float alphaRef; 76 | varying float leafiness; 77 | varying vec4 modelPos; 78 | 79 | #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) 80 | 81 | #if !PER_PIXEL_LIGHTING 82 | centroid varying vec3 passLighting; 83 | centroid varying vec3 shadowDiffuseLighting; 84 | #else 85 | uniform float emissiveMult; 86 | #endif 87 | uniform float specStrength; 88 | varying vec3 passViewPos; 89 | varying vec3 passNormal; 90 | 91 | uniform mat4 osg_ViewMatrixInverse; 92 | uniform mat4 osg_ViewMatrix; 93 | uniform mat4 osg_ModelViewMatrix; 94 | 95 | uniform mat4 projectionMatrix; 96 | 97 | uniform bool isReflection; 98 | 99 | #if @additiveBlending 100 | #define ADDITIVE_BLENDING 101 | #endif 102 | 103 | #include "vertexcolors.glsl" 104 | #include "shadows_fragment.glsl" 105 | #include "lib/light/lighting.glsl" 106 | #include "lib/material/parallax.glsl" 107 | #include "lib/material/alpha.glsl" 108 | #include "fog.glsl" 109 | 110 | #if @softParticles 111 | #include "lib/particle/soft.glsl" 112 | 113 | uniform sampler2D opaqueDepthTex; 114 | uniform float particleSize; 115 | uniform bool particleFade; 116 | #endif 117 | 118 | #if @particleOcclusion 119 | #include "lib/particle/occlusion.glsl" 120 | uniform sampler2D orthoDepthMap; 121 | 122 | varying vec3 orthoDepthMapCoord; 123 | #endif 124 | 125 | void main() 126 | { 127 | #if @particleOcclusion 128 | applyOcclusionDiscard(orthoDepthMapCoord, texture2D(orthoDepthMap, orthoDepthMapCoord.xy * 0.5 + 0.5).r); 129 | #endif 130 | 131 | vec3 worldNormal = normalize(passNormal); 132 | vec3 viewVec = normalize(passViewPos.xyz); 133 | 134 | #if @diffuseMap 135 | vec2 adjustedDiffuseUV = diffuseMapUV; 136 | #endif 137 | 138 | #if @normalMap 139 | vec4 normalTex = texture2D(normalMap, normalMapUV); 140 | 141 | vec3 normalizedNormal = worldNormal; 142 | vec3 normalizedTangent = normalize(passTangent.xyz); 143 | vec3 binormal = cross(normalizedTangent, normalizedNormal) * passTangent.w; 144 | mat3 tbnTranspose = mat3(normalizedTangent, binormal, normalizedNormal); 145 | 146 | worldNormal = normalize(tbnTranspose * (normalTex.xyz * 2.0 - 1.0)); 147 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 148 | #endif 149 | 150 | #if (!@normalMap && (@parallax || @forcePPL || @softParticles)) 151 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 152 | #endif 153 | 154 | #if @parallax 155 | #define PARALLAX 156 | 157 | vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; 158 | vec3 objectPos = (gl_ModelViewMatrixInverse * vec4(passViewPos, 1)).xyz; 159 | vec3 eyeDir = normalize(cameraPos - objectPos); 160 | vec2 offset = getParallaxOffset(eyeDir, tbnTranspose, normalTex.a, (passTangent.w > 0.0) ? -1.f : 1.f); 161 | adjustedDiffuseUV += offset; // only offset diffuse for now, other textures are more likely to be using a completely different UV set 162 | 163 | // TODO: check not working as the same UV buffer is being bound to different targets 164 | // if diffuseMapUV == normalMapUV 165 | #if 1 166 | // fetch a new normal using updated coordinates 167 | normalTex = texture2D(normalMap, adjustedDiffuseUV); 168 | 169 | worldNormal = normalize(tbnTranspose * (normalTex.xyz * 2.0 - 1.0)); 170 | viewNormal = gl_NormalMatrix * worldNormal; 171 | #endif 172 | 173 | #endif 174 | 175 | #if @diffuseMap 176 | gl_FragData[0] = texture2D(diffuseMap, adjustedDiffuseUV); 177 | gl_FragData[0].a *= coveragePreservingAlphaScale(diffuseMap, adjustedDiffuseUV); 178 | #else 179 | gl_FragData[0] = vec4(1.0); 180 | #endif 181 | 182 | vec4 diffuseColor = getDiffuseColor(); 183 | gl_FragData[0].a *= diffuseColor.a; 184 | 185 | vec3 wPos = (osg_ViewMatrixInverse * vec4(passViewPos, 1)).xyz * vec3(1.0, 1.0, isReflection ? -1.0 : 1.0); 186 | bool inMinimap = projectionMatrix[0][3] == 0.0 && projectionMatrix[1][3] == 0.0 && projectionMatrix[2][3] == 0.0; 187 | float waterDepth = inMinimap ? 0.0 : max(-wPos.z, 0); 188 | 189 | #if @darkMap 190 | gl_FragData[0] *= texture2D(darkMap, darkMapUV); 191 | gl_FragData[0].a *= coveragePreservingAlphaScale(darkMap, darkMapUV); 192 | #endif 193 | 194 | gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); 195 | 196 | #if @detailMap 197 | gl_FragData[0].xyz *= texture2D(detailMap, detailMapUV).xyz * 2.0; 198 | #endif 199 | 200 | #if @decalMap 201 | vec4 decalTex = texture2D(decalMap, decalMapUV); 202 | gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a * diffuseColor.a); 203 | #endif 204 | 205 | #if @envMap 206 | 207 | vec2 envTexCoordGen = envMapUV; 208 | float envLuma = 1.0; 209 | 210 | #if @normalMap 211 | // if using normal map + env map, take advantage of per-pixel normals for envTexCoordGen 212 | vec3 r = reflect( viewVec, viewNormal ); 213 | float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); 214 | envTexCoordGen = vec2(r.x/m + 0.5, r.y/m + 0.5); 215 | #endif 216 | 217 | #if @bumpMap 218 | vec4 bumpTex = texture2D(bumpMap, bumpMapUV); 219 | envTexCoordGen += bumpTex.rg * bumpMapMatrix; 220 | envLuma = clamp(bumpTex.b * envMapLumaBias.x + envMapLumaBias.y, 0.0, 1.0); 221 | #endif 222 | 223 | vec3 envEffect = texture2D(envMap, envTexCoordGen).xyz * envMapColor.xyz * envLuma; 224 | 225 | #if @glossMap 226 | envEffect *= texture2D(glossMap, glossMapUV).xyz; 227 | #endif 228 | 229 | #if @preLightEnv 230 | gl_FragData[0].xyz += envEffect; 231 | #endif 232 | #else 233 | vec3 envEffect = vec3(0); 234 | #endif 235 | 236 | float roughness = 0.6; 237 | float reflectance = 1.0; 238 | float metalness = 0.1; 239 | 240 | float shininess = gl_FrontMaterial.shininess; 241 | 242 | #if @specularMap 243 | vec4 matSpec = texture2D(specularMap, specularMapUV); 244 | #else 245 | vec4 matSpec = getSpecularColor(); 246 | #endif 247 | matSpecToPbr(matSpec, leafiness, roughness, metalness, reflectance, shininess); 248 | 249 | float shadowing = unshadowedLightRatio(-passViewPos.z); 250 | vec3 lighting; 251 | #if !PER_PIXEL_LIGHTING 252 | lighting = passLighting + shadowDiffuseLighting * shadowing; 253 | #if @darkMap 254 | lighting *= texture2D(darkMap, darkMapUV).rgb; 255 | #endif 256 | gl_FragData[0].xyz *= lighting; 257 | #else 258 | vec3 emission = getEmissionColor().rgb * emissiveMult; 259 | #if @emissiveMap 260 | emission += texture2D(emissiveMap, emissiveMapUV).rgb; 261 | #endif 262 | 263 | #if @darkMap 264 | emission *= texture2D(darkMap, darkMapUV).rgb; 265 | #endif 266 | 267 | vec3 color = gl_FragData[0].rgb * diffuseColor.rgb; 268 | 269 | vec3 albedo; float ao; 270 | colorToPbr(color, albedo, ao); 271 | 272 | gl_FragData[0].xyz = getPbr( 273 | osg_ViewMatrixInverse, 274 | passViewPos, 275 | normalize(viewNormal), 276 | albedo, 277 | roughness, 278 | reflectance, 279 | metalness, 280 | shadowing, 281 | #if SHADOWS 282 | shadowFadeStart, 283 | #else 284 | 3500.0, 285 | #endif 286 | ao, 287 | emission * color, 288 | leafiness, 289 | waterDepth, 290 | leafiness 291 | ); 292 | //#if @specularMap 293 | // gl_FragData[0].xyz = matSpec.rgb; 294 | //#endif 295 | //gl_FragData[0].xyz = vec3(reflectance); 296 | #endif 297 | 298 | #if @envMap && !@preLightEnv 299 | gl_FragData[0].xyz += envEffect; 300 | #endif 301 | 302 | clampLightingResult(gl_FragData[0].xyz); 303 | 304 | gl_FragData[0] = applyFogAtPos(gl_FragData[0], passViewPos, far); 305 | 306 | vec2 screenCoords = gl_FragCoord.xy / screenRes; 307 | #if !defined(FORCE_OPAQUE) && @softParticles 308 | gl_FragData[0].a *= calcSoftParticleFade( 309 | viewVec, 310 | passViewPos, 311 | viewNormal, 312 | near, 313 | far, 314 | texture2D(opaqueDepthTex, screenCoords).x, 315 | particleSize, 316 | particleFade 317 | ); 318 | #endif 319 | 320 | #if defined(FORCE_OPAQUE) && FORCE_OPAQUE 321 | // having testing & blending isn't enough - we need to write an opaque pixel to be opaque 322 | gl_FragData[0].a = 1.0; 323 | #endif 324 | 325 | #if !defined(FORCE_OPAQUE) && !@disableNormals 326 | gl_FragData[1].xyz = worldNormal * 0.5 + 0.5; 327 | #endif 328 | 329 | tonemap(gl_FragData[0].rgb); 330 | debug_materials(gl_FragData[0].rgb); 331 | 332 | applyShadowDebugOverlay(); 333 | } 334 | -------------------------------------------------------------------------------- /shaders/compatibility/objects.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | #include "lib/core/vertex.h.glsl" 12 | #if @diffuseMap 13 | varying vec2 diffuseMapUV; 14 | #endif 15 | 16 | #if @darkMap 17 | varying vec2 darkMapUV; 18 | #endif 19 | 20 | #if @detailMap 21 | varying vec2 detailMapUV; 22 | #endif 23 | 24 | #if @decalMap 25 | varying vec2 decalMapUV; 26 | #endif 27 | 28 | #if @emissiveMap 29 | varying vec2 emissiveMapUV; 30 | #endif 31 | 32 | #if @normalMap 33 | varying vec2 normalMapUV; 34 | varying vec4 passTangent; 35 | #endif 36 | 37 | #if @envMap 38 | varying vec2 envMapUV; 39 | #endif 40 | 41 | #if @bumpMap 42 | varying vec2 bumpMapUV; 43 | #endif 44 | 45 | #if @specularMap 46 | varying vec2 specularMapUV; 47 | #endif 48 | 49 | #if @glossMap 50 | varying vec2 glossMapUV; 51 | #endif 52 | 53 | varying vec4 modelPos; 54 | 55 | #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) 56 | 57 | #if !PER_PIXEL_LIGHTING 58 | centroid varying vec3 passLighting; 59 | centroid varying vec3 shadowDiffuseLighting; 60 | uniform float emissiveMult; 61 | #endif 62 | varying vec3 passViewPos; 63 | varying vec3 passNormal; 64 | varying float normZ; 65 | varying float normZ2; 66 | 67 | uniform mat4 osg_ModelViewMatrix; 68 | uniform sampler2D diffuseMap; 69 | 70 | varying float leafiness; 71 | 72 | #include "vertexcolors.glsl" 73 | #include "lib/zesterer/warp.glsl" 74 | #include "shadows_vertex.glsl" 75 | 76 | #include "lib/light/lighting.glsl" 77 | #include "lib/view/depth.glsl" 78 | #include "lib/zesterer/sway.glsl" 79 | 80 | #if @particleOcclusion 81 | varying vec3 orthoDepthMapCoord; 82 | 83 | uniform mat4 depthSpaceMatrix; 84 | //uniform mat4 osg_ViewMatrixInverse; 85 | #endif 86 | 87 | void main(void) 88 | { 89 | #if @particleOcclusion 90 | mat4 model = osg_ViewMatrixInverse * gl_ModelViewMatrix; 91 | orthoDepthMapCoord = ((depthSpaceMatrix * model) * vec4(gl_Vertex.xyz, 1.0)).xyz; 92 | #endif 93 | 94 | #if @diffuseMap 95 | diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; 96 | #endif 97 | 98 | // Waving in the wind 99 | modelPos = gl_Vertex; 100 | leafiness = 0.0; 101 | #if @diffuseMap 102 | doSway(diffuseMap, diffuseMapUV, modelPos.xyz, leafiness); 103 | #endif 104 | gl_Position = modelToClip(modelPos); 105 | 106 | vec4 viewPos = modelToView(modelPos); 107 | gl_ClipVertex = viewPos; 108 | 109 | gl_Position = warp_position(viewPos.xyz); 110 | 111 | #if (@envMap || !PER_PIXEL_LIGHTING || @shadows_enabled) 112 | vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); 113 | #endif 114 | 115 | #if @envMap 116 | vec3 viewVec = normalize(viewPos.xyz); 117 | vec3 r = reflect( viewVec, viewNormal ); 118 | float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); 119 | envMapUV = vec2(r.x/m + 0.5, r.y/m + 0.5); 120 | #endif 121 | 122 | #if @diffuseMap 123 | diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy; 124 | #endif 125 | 126 | #if @darkMap 127 | darkMapUV = (gl_TextureMatrix[@darkMapUV] * gl_MultiTexCoord@darkMapUV).xy; 128 | #endif 129 | 130 | #if @detailMap 131 | detailMapUV = (gl_TextureMatrix[@detailMapUV] * gl_MultiTexCoord@detailMapUV).xy; 132 | #endif 133 | 134 | #if @decalMap 135 | decalMapUV = (gl_TextureMatrix[@decalMapUV] * gl_MultiTexCoord@decalMapUV).xy; 136 | #endif 137 | 138 | #if @emissiveMap 139 | emissiveMapUV = (gl_TextureMatrix[@emissiveMapUV] * gl_MultiTexCoord@emissiveMapUV).xy; 140 | #endif 141 | 142 | #if @normalMap 143 | normalMapUV = (gl_TextureMatrix[@normalMapUV] * gl_MultiTexCoord@normalMapUV).xy; 144 | passTangent = gl_MultiTexCoord7.xyzw; 145 | #endif 146 | 147 | #if @bumpMap 148 | bumpMapUV = (gl_TextureMatrix[@bumpMapUV] * gl_MultiTexCoord@bumpMapUV).xy; 149 | #endif 150 | 151 | #if @specularMap 152 | specularMapUV = (gl_TextureMatrix[@specularMapUV] * gl_MultiTexCoord@specularMapUV).xy; 153 | #endif 154 | 155 | #if @glossMap 156 | glossMapUV = (gl_TextureMatrix[@glossMapUV] * gl_MultiTexCoord@glossMapUV).xy; 157 | #endif 158 | 159 | passColor = gl_Color; 160 | passViewPos = viewPos.xyz; 161 | passNormal = gl_Normal.xyz; 162 | 163 | #if !PER_PIXEL_LIGHTING 164 | vec3 diffuseLight, ambientLight; 165 | doLighting(viewPos.xyz, viewNormal, diffuseLight, ambientLight, shadowDiffuseLighting); 166 | vec3 emission = getEmissionColor().xyz * emissiveMult; 167 | passLighting = getDiffuseColor().xyz * diffuseLight + getAmbientColor().xyz * ambientLight + emission; 168 | clampLightingResult(passLighting); 169 | shadowDiffuseLighting *= getDiffuseColor().xyz; 170 | #endif 171 | 172 | #if (@shadows_enabled) 173 | // This is an extremely silly hack. A lot of tree models 'lie' about their normal, and this result in very bizarre 174 | // shadows because shadow-mapping relies on the normal actually pertaining to the real position of the polygon. To 175 | // resolve this, and because we really don't care about the exact normal of leaves, we force the shadows to believe 176 | // that the normal is pointing towards the sun, thereby ensuring correct shadow casting. We *only* do this if the 177 | // vertex is part of a leaf. 178 | setupShadowCoords(viewPos, (leafiness > 0.0) ? -lcalcPosition(0) : viewNormal); 179 | #endif 180 | } 181 | -------------------------------------------------------------------------------- /shaders/compatibility/s360.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 uv; 4 | uniform samplerCube cubeMap; 5 | uniform int mapping; 6 | 7 | #include "lib/util/coordinates.glsl" 8 | 9 | void main(void) 10 | { 11 | vec3 c; 12 | 13 | if (mapping == 0) 14 | c = sphericalCoords(uv); 15 | else if (mapping == 1) 16 | c = cylindricalCoords(uv); 17 | else 18 | c = planetCoords(uv); 19 | 20 | gl_FragData[0] = textureCube(cubeMap,c); 21 | } 22 | -------------------------------------------------------------------------------- /shaders/compatibility/s360.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 uv; 4 | 5 | void main(void) 6 | { 7 | gl_Position = gl_Vertex; 8 | uv = (gl_Vertex.xy * vec2(1.0,-1.0) + vec2(1.0)) / 2; 9 | } 10 | -------------------------------------------------------------------------------- /shaders/compatibility/shadowcasting.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useGPUShader4 4 | #extension GL_EXT_gpu_shader4: require 5 | #endif 6 | 7 | uniform sampler2D diffuseMap; 8 | varying vec2 diffuseMapUV; 9 | 10 | varying float alphaPassthrough; 11 | 12 | uniform bool useDiffuseMapForShadowAlpha; 13 | uniform bool alphaTestShadows; 14 | uniform float alphaRef; 15 | 16 | #include "lib/material/alpha.glsl" 17 | 18 | void main() 19 | { 20 | gl_FragData[0].rgb = vec3(1.0); 21 | if (useDiffuseMapForShadowAlpha) 22 | gl_FragData[0].a = texture2D(diffuseMap, diffuseMapUV).a * alphaPassthrough; 23 | else 24 | gl_FragData[0].a = alphaPassthrough; 25 | 26 | gl_FragData[0].a = alphaTest(gl_FragData[0].a, alphaRef); 27 | 28 | // Prevent translucent things casting shadow (including the player using an invisibility effect). 29 | // This replaces alpha blending, which obviously doesn't work with depth buffers 30 | if (alphaTestShadows && gl_FragData[0].a <= 0.5) 31 | discard; 32 | } 33 | -------------------------------------------------------------------------------- /shaders/compatibility/shadowcasting.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 diffuseMapUV; 4 | 5 | varying float alphaPassthrough; 6 | 7 | uniform int colorMode; 8 | uniform bool useDiffuseMapForShadowAlpha = true; 9 | uniform bool alphaTestShadows = true; 10 | 11 | uniform mat4 osg_ViewMatrixInverse; 12 | uniform mat4 osg_ModelViewMatrix; 13 | uniform sampler2D diffuseMap; 14 | 15 | void main(void) 16 | { 17 | vec4 modelPos = gl_Vertex; 18 | float leafiness; 19 | diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 20 | //doSway(diffuseMap, diffuseMapUV, modelPos.xyz, leafiness); 21 | gl_Position = gl_ModelViewProjectionMatrix * modelPos; 22 | 23 | vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex); 24 | gl_ClipVertex = viewPos; 25 | 26 | if (useDiffuseMapForShadowAlpha) 27 | diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 28 | else 29 | diffuseMapUV = vec2(0.0); // Avoid undefined behaviour if running on hardware predating the concept of dynamically uniform expressions 30 | if (colorMode == 2) 31 | alphaPassthrough = gl_Color.a; 32 | else 33 | // This is uniform, so if it's too low, we might be able to put the position/clip vertex outside the view frustum and skip the fragment shader and rasteriser 34 | alphaPassthrough = gl_FrontMaterial.diffuse.a; 35 | } 36 | -------------------------------------------------------------------------------- /shaders/compatibility/shadows_fragment.glsl: -------------------------------------------------------------------------------- 1 | #define SHADOWS @shadows_enabled 2 | 3 | #if SHADOWS 4 | uniform float maximumShadowMapDistance; 5 | uniform float shadowFadeStart; 6 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 7 | uniform sampler2D shadowTexture@shadow_texture_unit_index; 8 | varying vec4 shadowSpaceCoords@shadow_texture_unit_index; 9 | 10 | #if @perspectiveShadowMaps 11 | varying vec4 shadowRegionCoords@shadow_texture_unit_index; 12 | #endif 13 | @endforeach 14 | #endif // SHADOWS 15 | 16 | #if SHADOWS 17 | const float lightSizeFactor = 0.05; 18 | const float nearPlane = 0.4; 19 | const float maxSearchDistance = 0.01; 20 | const float maxFilterRadius = 0.01; 21 | const int shadowSampleCount = 16; 22 | 23 | float interleavedGradientNoise(vec2 position) 24 | { 25 | const vec2 magicVector = vec2(0.06711056, 0.00583715); 26 | const float magicScalar = 52.9829189; 27 | return fract(magicScalar * fract(dot(position, magicVector))); 28 | } 29 | 30 | vec2 vogelDisk(int index, float phi) 31 | { 32 | const float goldenAngle = 2.39996322972865332; 33 | float r = sqrt(index + 0.5) / sqrt(shadowSampleCount); 34 | float theta = index * goldenAngle + phi; 35 | return vec2(r * cos(theta), r * sin(theta)); 36 | } 37 | 38 | vec2 findShadowOccluders(sampler2D shadowMap, vec3 coords, float receiver, float phi) 39 | { 40 | float searchDistance = min(maxSearchDistance, lightSizeFactor / receiver * (receiver - nearPlane)); 41 | float scaledDistance = searchDistance * coords.z; 42 | float depthSum = 0; 43 | int occluderCount = 0; 44 | for (int i = 0; i < shadowSampleCount; ++i) 45 | { 46 | vec3 offset = vec3(vogelDisk(i, phi) * scaledDistance, 0); 47 | float depth = texture2DProj(shadowMap, coords + offset).r; 48 | if (depth < receiver) 49 | { 50 | ++occluderCount; 51 | depthSum += depth; 52 | } 53 | } 54 | return vec2(depthSum / occluderCount, occluderCount); 55 | } 56 | 57 | float percentageCloserFilter(sampler2D shadowMap, vec3 coords, float receiver, float filterRadius, float phi) 58 | { 59 | float scaledRadius = filterRadius * coords.z; 60 | float sum = 0.0; 61 | for (int i = 0; i < shadowSampleCount; ++i) 62 | { 63 | vec3 offset = vec3(vogelDisk(i, phi) * scaledRadius, 0); 64 | sum += float(receiver <= texture2DProj(shadowMap, coords + offset).r); 65 | } 66 | return sum / shadowSampleCount; 67 | } 68 | 69 | float sampleShadow(sampler2D shadowMap, vec4 coords) 70 | { 71 | float phi = interleavedGradientNoise(gl_FragCoord.xy); 72 | float receiverDepth = min(coords.z / coords.w, 1); 73 | vec3 coordsProj = coords.xyw; 74 | vec2 occluders = findShadowOccluders(shadowMap, coordsProj, receiverDepth, phi); 75 | if (occluders.y == 0) 76 | { 77 | return 1.0; 78 | } 79 | 80 | float meanDepth = occluders.x; 81 | float penumbra = (receiverDepth - meanDepth) / meanDepth; 82 | float filterRadius = penumbra * lightSizeFactor * nearPlane / receiverDepth; 83 | filterRadius = min(filterRadius, maxFilterRadius); 84 | return percentageCloserFilter(shadowMap, coordsProj, receiverDepth, filterRadius, phi); 85 | } 86 | #endif 87 | 88 | float unshadowedLightRatio(float distance) 89 | { 90 | float shadowing = 1.0; 91 | #if SHADOWS 92 | #if @limitShadowMapDistance 93 | float fade = clamp((distance - shadowFadeStart) / (maximumShadowMapDistance - shadowFadeStart), 0.0, 1.0); 94 | if (fade == 1.0) 95 | return shadowing; 96 | #endif 97 | #if @shadowMapsOverlap 98 | bool doneShadows = false; 99 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 100 | if (!doneShadows) 101 | { 102 | vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; 103 | #if @perspectiveShadowMaps 104 | vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; 105 | #endif 106 | if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) 107 | { 108 | shadowing = min(sampleShadow(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index), shadowing); 109 | 110 | 111 | doneShadows = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); 112 | #if @perspectiveShadowMaps 113 | doneShadows = doneShadows && all(lessThan(shadowRegionXYZ, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); 114 | #endif 115 | } 116 | } 117 | @endforeach 118 | #else 119 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 120 | shadowing = min(sampleShadow(shadowTexture@shadow_texture_unit_index, shadowSpaceCoords@shadow_texture_unit_index), shadowing); 121 | @endforeach 122 | #endif 123 | #if @limitShadowMapDistance 124 | shadowing = mix(shadowing, 1.0, fade); 125 | #endif 126 | #endif // SHADOWS 127 | return shadowing; 128 | } 129 | 130 | void applyShadowDebugOverlay() 131 | { 132 | #if SHADOWS && @useShadowDebugOverlay 133 | bool doneOverlay = false; 134 | float colourIndex = 0.0; 135 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 136 | if (!doneOverlay) 137 | { 138 | vec3 shadowXYZ = shadowSpaceCoords@shadow_texture_unit_index.xyz / shadowSpaceCoords@shadow_texture_unit_index.w; 139 | #if @perspectiveShadowMaps 140 | vec3 shadowRegionXYZ = shadowRegionCoords@shadow_texture_unit_index.xyz / shadowRegionCoords@shadow_texture_unit_index.w; 141 | #endif 142 | if (all(lessThan(shadowXYZ.xy, vec2(1.0, 1.0))) && all(greaterThan(shadowXYZ.xy, vec2(0.0, 0.0)))) 143 | { 144 | colourIndex = mod(@shadow_texture_unit_index.0, 3.0); 145 | if (colourIndex < 1.0) 146 | gl_FragData[0].x += 0.1; 147 | else if (colourIndex < 2.0) 148 | gl_FragData[0].y += 0.1; 149 | else 150 | gl_FragData[0].z += 0.1; 151 | 152 | doneOverlay = all(lessThan(shadowXYZ, vec3(0.95, 0.95, 1.0))) && all(greaterThan(shadowXYZ, vec3(0.05, 0.05, 0.0))); 153 | #if @perspectiveShadowMaps 154 | doneOverlay = doneOverlay && all(lessThan(shadowRegionXYZ.xyz, vec3(1.0, 1.0, 1.0))) && all(greaterThan(shadowRegionXYZ.xy, vec2(-1.0, -1.0))); 155 | #endif 156 | } 157 | } 158 | @endforeach 159 | #endif // SHADOWS 160 | } 161 | -------------------------------------------------------------------------------- /shaders/compatibility/shadows_vertex.glsl: -------------------------------------------------------------------------------- 1 | #define SHADOWS @shadows_enabled 2 | 3 | #if SHADOWS 4 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 5 | uniform mat4 shadowSpaceMatrix@shadow_texture_unit_index; 6 | uniform int shadowTextureUnit@shadow_texture_unit_index; 7 | varying vec4 shadowSpaceCoords@shadow_texture_unit_index; 8 | 9 | #if @perspectiveShadowMaps 10 | uniform mat4 validRegionMatrix@shadow_texture_unit_index; 11 | varying vec4 shadowRegionCoords@shadow_texture_unit_index; 12 | #endif 13 | @endforeach 14 | 15 | // Enabling this may reduce peter panning. Probably unnecessary. 16 | const bool onlyNormalOffsetUV = false; 17 | #endif // SHADOWS 18 | 19 | void setupShadowCoords(vec4 viewPos, vec3 viewNormal) 20 | { 21 | #if SHADOWS 22 | // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. 23 | vec4 shadowOffset; 24 | @foreach shadow_texture_unit_index @shadow_texture_unit_list 25 | #if @perspectiveShadowMaps 26 | shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; 27 | #endif 28 | 29 | #if @disableNormalOffsetShadows 30 | shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * viewPos; 31 | #else 32 | shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0); 33 | 34 | if (onlyNormalOffsetUV) 35 | { 36 | vec4 lightSpaceXY = viewPos + shadowOffset; 37 | lightSpaceXY = shadowSpaceMatrix@shadow_texture_unit_index * lightSpaceXY; 38 | 39 | shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy; 40 | } 41 | else 42 | { 43 | vec4 offsetViewPosition = viewPos + shadowOffset; 44 | shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * offsetViewPosition; 45 | } 46 | #endif 47 | @endforeach 48 | #endif // SHADOWS 49 | } 50 | -------------------------------------------------------------------------------- /shaders/compatibility/sky.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/sky/passes.glsl" 4 | 5 | uniform int pass; 6 | uniform sampler2D diffuseMap; 7 | uniform sampler2D maskMap; // PASS_MOON 8 | uniform float opacity; // PASS_CLOUDS, PASS_ATMOSPHERE_NIGHT 9 | uniform vec4 moonBlend; // PASS_MOON 10 | uniform vec4 atmosphereFade; // PASS_MOON 11 | 12 | varying vec2 diffuseMapUV; 13 | varying vec4 passColor; 14 | 15 | void paintAtmosphere(inout vec4 color) 16 | { 17 | color = gl_FrontMaterial.emission; 18 | color.a *= passColor.a; 19 | } 20 | 21 | void paintAtmosphereNight(inout vec4 color) 22 | { 23 | color = texture2D(diffuseMap, diffuseMapUV); 24 | color.a *= passColor.a * opacity; 25 | } 26 | 27 | void paintClouds(inout vec4 color) 28 | { 29 | color = texture2D(diffuseMap, diffuseMapUV); 30 | color.a *= passColor.a * opacity; 31 | color.xyz = clamp(color.xyz * gl_FrontMaterial.emission.xyz, 0.0, 1.0); 32 | 33 | // ease transition between clear color and atmosphere/clouds 34 | color = mix(vec4(gl_Fog.color.xyz, color.a), color, passColor.a); 35 | } 36 | 37 | void paintMoon(inout vec4 color) 38 | { 39 | vec4 phase = texture2D(diffuseMap, diffuseMapUV); 40 | vec4 mask = texture2D(maskMap, diffuseMapUV); 41 | 42 | vec4 blendedLayer = phase * moonBlend; 43 | color = vec4(blendedLayer.xyz + atmosphereFade.xyz, atmosphereFade.a * mask.a); 44 | } 45 | 46 | void paintSun(inout vec4 color) 47 | { 48 | color = texture2D(diffuseMap, diffuseMapUV); 49 | color.a *= gl_FrontMaterial.diffuse.a; 50 | } 51 | 52 | void paintSunglare(inout vec4 color) 53 | { 54 | color = gl_FrontMaterial.emission; 55 | color.a = gl_FrontMaterial.diffuse.a; 56 | } 57 | 58 | void processSunflashQuery() 59 | { 60 | const float threshold = 0.8; 61 | 62 | if (texture2D(diffuseMap, diffuseMapUV).a <= threshold) 63 | discard; 64 | } 65 | 66 | void main() 67 | { 68 | vec4 color = vec4(0.0); 69 | 70 | if (pass == PASS_ATMOSPHERE) 71 | paintAtmosphere(color); 72 | else if (pass == PASS_ATMOSPHERE_NIGHT) 73 | paintAtmosphereNight(color); 74 | else if (pass == PASS_CLOUDS) 75 | paintClouds(color); 76 | else if (pass == PASS_MOON) 77 | paintMoon(color); 78 | else if (pass == PASS_SUN) 79 | paintSun(color); 80 | else if (pass == PASS_SUNGLARE) 81 | paintSunglare(color); 82 | else if (pass == PASS_SUNFLASH_QUERY) { 83 | processSunflashQuery(); 84 | return; 85 | } 86 | 87 | gl_FragData[0] = color; 88 | } 89 | -------------------------------------------------------------------------------- /shaders/compatibility/sky.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/sky/passes.glsl" 4 | 5 | uniform mat4 projectionMatrix; 6 | uniform int pass; 7 | 8 | varying vec4 passColor; 9 | varying vec2 diffuseMapUV; 10 | 11 | void main() 12 | { 13 | gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex); 14 | passColor = gl_Color; 15 | 16 | if (pass == PASS_CLOUDS) 17 | diffuseMapUV = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 18 | else 19 | diffuseMapUV = gl_MultiTexCoord0.xy; 20 | } 21 | -------------------------------------------------------------------------------- /shaders/compatibility/terrain.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | varying vec2 uv; 12 | 13 | uniform sampler2D diffuseMap; 14 | 15 | #if @normalMap 16 | #define NORMAL_MAP 17 | uniform sampler2D normalMap; 18 | #endif 19 | 20 | #if @blendMap 21 | #define BLEND_MAP 22 | uniform sampler2D blendMap; 23 | #endif 24 | 25 | varying float euclideanDepth; 26 | varying float linearDepth; 27 | 28 | uniform mat4 osg_ViewMatrixInverse; 29 | 30 | #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) 31 | 32 | #if !PER_PIXEL_LIGHTING 33 | centroid varying vec3 passLighting; 34 | centroid varying vec3 shadowDiffuseLighting; 35 | #endif 36 | varying vec3 passViewPos; 37 | varying vec3 passNormal; 38 | 39 | uniform vec2 screenRes; 40 | uniform float far; 41 | 42 | uniform bool isReflection; 43 | 44 | #include "vertexcolors.glsl" 45 | #include "shadows_fragment.glsl" 46 | #include "lib/light/lighting.glsl" 47 | #include "lib/material/parallax.glsl" 48 | #include "lib/zesterer/rand.glsl" 49 | #include "lib/zesterer/wave.glsl" 50 | #include "fog.glsl" 51 | 52 | void main() 53 | { 54 | vec2 adjustedUV = (gl_TextureMatrix[0] * vec4(uv, 0.0, 1.0)).xy; 55 | 56 | vec3 worldNormal = normalize(passNormal); 57 | 58 | #if @normalMap 59 | vec4 normalTex = texture2D(normalMap, adjustedUV); 60 | 61 | vec3 normalizedNormal = worldNormal; 62 | vec3 tangent = vec3(1.0, 0.0, 0.0); 63 | vec3 binormal = normalize(cross(tangent, normalizedNormal)); 64 | tangent = normalize(cross(normalizedNormal, binormal)); // note, now we need to re-cross to derive tangent again because it wasn't orthonormal 65 | mat3 tbnTranspose = mat3(tangent, binormal, normalizedNormal); 66 | 67 | worldNormal = tbnTranspose * (normalTex.xyz * 2.0 - 1.0); 68 | vec3 viewNormal = normalize(gl_NormalMatrix * worldNormal); 69 | normalize(worldNormal); 70 | #endif 71 | 72 | #if (!@normalMap && (@parallax || @forcePPL)) 73 | vec3 viewNormal = gl_NormalMatrix * worldNormal; 74 | #endif 75 | 76 | #if @parallax 77 | vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; 78 | vec3 objectPos = (gl_ModelViewMatrixInverse * vec4(passViewPos, 1)).xyz; 79 | vec3 eyeDir = normalize(cameraPos - objectPos); 80 | adjustedUV += getParallaxOffset(eyeDir, tbnTranspose, normalTex.a, 1.f); 81 | 82 | // update normal using new coordinates 83 | normalTex = texture2D(normalMap, adjustedUV); 84 | 85 | worldNormal = tbnTranspose * (normalTex.xyz * 2.0 - 1.0); 86 | viewNormal = normalize(gl_NormalMatrix * worldNormal); 87 | normalize(worldNormal); 88 | #endif 89 | 90 | vec3 wPos = (osg_ViewMatrixInverse * vec4(passViewPos, 1)).xyz * vec3(1.0, 1.0, isReflection ? -1.0 : 1.0); 91 | float waterDepth = max(-wPos.z + doWave(wPos.xy), 0); 92 | 93 | if (PROCEDURAL_DETAIL_LEVEL > 0.0) { 94 | //proceduralUV(wPos, length(passViewPos), adjustedUV); 95 | } 96 | 97 | vec4 diffuseTex = texture2D(diffuseMap, adjustedUV);//textureBicubic(diffuseMap, adjustedUV); 98 | gl_FragData[0] = vec4(diffuseTex.xyz, 1.0); 99 | 100 | #if @blendMap 101 | vec2 blendMapUV = (gl_TextureMatrix[1] * vec4(uv, 0.0, 1.0)).xy; 102 | gl_FragData[0].a *= texture2D(blendMap, blendMapUV).a; 103 | #endif 104 | 105 | vec4 diffuseColor = getDiffuseColor(); 106 | gl_FragData[0].a *= diffuseColor.a; 107 | 108 | float roughness = 1.0; 109 | float reflectance = 1.0; 110 | float metalness = 0.0; 111 | 112 | float shininess = gl_FrontMaterial.shininess; 113 | 114 | #if @specularMap 115 | vec4 matSpec = vec4(diffuseTex.a); 116 | #else 117 | vec4 matSpec = getSpecularColor(); 118 | #endif 119 | matSpecToPbr(matSpec, 0.0, roughness, metalness, reflectance, shininess); 120 | 121 | float shadowing = unshadowedLightRatio(linearDepth); 122 | vec3 lighting; 123 | #if !PER_PIXEL_LIGHTING 124 | lighting = passLighting + shadowDiffuseLighting * shadowing; 125 | gl_FragData[0].xyz *= lighting; 126 | #else 127 | vec3 color = gl_FragData[0].rgb 128 | // Apply terrain shadowing, but less closer to the camera 129 | * mix(diffuseColor.rgb, vec3(1.0), 1.0 / (1.0 + length(passViewPos) / 10000.0)); 130 | 131 | color = color * 1.1 - 0.05; // TODO: Why?! Bad vanilla textures? 132 | vec3 albedo; float ao; 133 | colorToPbr(color, albedo, ao); 134 | 135 | if (PROCEDURAL_DETAIL_LEVEL > 0.0) { 136 | // Apply procedural detail to distant terrain 137 | proceduralNormal(wPos, length(passViewPos), viewNormal); 138 | } 139 | 140 | float waterH = 0.0; 141 | #if (WAVES == 1) 142 | waterH = doWave(wPos.xy, 0.0, 0.2, 0.0); 143 | float prevWaterH = doWave(wPos.xy, -1.5, 0.1, 0.5); 144 | float wave_depth = 5.0; 145 | if (wPos.z < waterH) { 146 | albedo *= mix(vec3(1.0), vec3(0.7, 0.8, 1.0), clamp(5.0 - (0.0 - wPos.z) * 1.5, 0.0, 1.0)); 147 | } 148 | if (wPos.z < waterH && wPos.z > waterH - wave_depth) { 149 | albedo += clamp(1.0 - (waterH - wPos.z) / wave_depth, 0.0, 1.0) * 1.0; 150 | } 151 | if (wPos.z > waterH && wPos.z < prevWaterH) { 152 | roughness *= 0.5; 153 | } 154 | #endif 155 | 156 | #if (CAUSTICS == 1) 157 | // TODO: Don't apply to ao, very hacky 158 | ao *= mix(1.0, 0.5 + caustics(wPos.xy * 0.01, osg_SimulationTime * 0.5) * 1.5, clamp((waterH - wPos.z) * 0.01, 0.0, 1.0) / (1.0 + waterDepth / 1000.0)); 159 | #endif 160 | 161 | gl_FragData[0].xyz = getPbr( 162 | osg_ViewMatrixInverse, 163 | passViewPos, 164 | viewNormal, 165 | albedo, 166 | roughness, 167 | reflectance, 168 | metalness, 169 | shadowing, 170 | #if SHADOWS 171 | shadowFadeStart, 172 | #else 173 | 3500.0, 174 | #endif 175 | ao, 176 | getEmissionColor().rgb, 177 | 0.0, 178 | waterDepth, 179 | MAT_DEFAULT 180 | ); 181 | //gl_FragData[0].xyz = matSpec.rgb; 182 | #endif 183 | 184 | clampLightingResult(gl_FragData[0].xyz); 185 | 186 | gl_FragData[0] = applyFogAtDist(gl_FragData[0], euclideanDepth, linearDepth, far); 187 | 188 | #if !@disableNormals && @writeNormals 189 | gl_FragData[1].xyz = worldNormal.xyz * 0.5 + 0.5; 190 | #endif 191 | 192 | tonemap(gl_FragData[0].rgb); 193 | debug_materials(gl_FragData[0].rgb); 194 | 195 | applyShadowDebugOverlay(); 196 | } 197 | -------------------------------------------------------------------------------- /shaders/compatibility/terrain.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | #include "lib/core/vertex.h.glsl" 12 | varying vec2 uv; 13 | varying float euclideanDepth; 14 | varying float linearDepth; 15 | 16 | #define PER_PIXEL_LIGHTING (@normalMap || @forcePPL) 17 | 18 | #if !PER_PIXEL_LIGHTING 19 | centroid varying vec3 passLighting; 20 | centroid varying vec3 shadowDiffuseLighting; 21 | #endif 22 | varying vec3 passViewPos; 23 | varying vec3 passNormal; 24 | 25 | #include "vertexcolors.glsl" 26 | #include "lib/zesterer/warp.glsl" 27 | #include "shadows_vertex.glsl" 28 | 29 | #include "lib/light/lighting.glsl" 30 | #include "lib/view/depth.glsl" 31 | 32 | void main(void) 33 | { 34 | gl_Position = modelToClip(gl_Vertex); 35 | 36 | vec4 viewPos = modelToView(gl_Vertex); 37 | gl_ClipVertex = viewPos; 38 | euclideanDepth = length(viewPos.xyz); 39 | 40 | gl_Position = warp_position(viewPos.xyz); 41 | 42 | linearDepth = getLinearDepth(gl_Position.z, viewPos.z); 43 | 44 | #if (!PER_PIXEL_LIGHTING || @shadows_enabled) 45 | vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz); 46 | #endif 47 | 48 | passColor = gl_Color; 49 | passNormal = gl_Normal.xyz; 50 | passViewPos = viewPos.xyz; 51 | 52 | #if !PER_PIXEL_LIGHTING 53 | vec3 diffuseLight, ambientLight; 54 | doLighting(viewPos.xyz, viewNormal, diffuseLight, ambientLight, shadowDiffuseLighting); 55 | passLighting = getDiffuseColor().xyz * diffuseLight + getAmbientColor().xyz * ambientLight + getEmissionColor().xyz; 56 | clampLightingResult(passLighting); 57 | shadowDiffuseLighting *= getDiffuseColor().xyz; 58 | #endif 59 | 60 | uv = gl_MultiTexCoord0.xy; 61 | 62 | #if (@shadows_enabled) 63 | setupShadowCoords(viewPos, viewNormal); 64 | #endif 65 | } 66 | -------------------------------------------------------------------------------- /shaders/compatibility/vertexcolors.glsl: -------------------------------------------------------------------------------- 1 | centroid varying vec4 passColor; 2 | 3 | uniform int colorMode; 4 | 5 | const int ColorMode_None = 0; 6 | const int ColorMode_Emission = 1; 7 | const int ColorMode_AmbientAndDiffuse = 2; 8 | const int ColorMode_Ambient = 3; 9 | const int ColorMode_Diffuse = 4; 10 | const int ColorMode_Specular = 5; 11 | 12 | vec4 getEmissionColor() 13 | { 14 | if (colorMode == ColorMode_Emission) 15 | return passColor; 16 | return gl_FrontMaterial.emission; 17 | } 18 | 19 | vec4 getAmbientColor() 20 | { 21 | if (colorMode == ColorMode_AmbientAndDiffuse || colorMode == ColorMode_Ambient) 22 | return passColor; 23 | return gl_FrontMaterial.ambient; 24 | } 25 | 26 | vec4 getDiffuseColor() 27 | { 28 | if (colorMode == ColorMode_AmbientAndDiffuse || colorMode == ColorMode_Diffuse) 29 | return passColor; 30 | return gl_FrontMaterial.diffuse; 31 | } 32 | 33 | vec4 getSpecularColor() 34 | { 35 | if (colorMode == ColorMode_Specular) 36 | return passColor; 37 | return gl_FrontMaterial.specular; 38 | } 39 | -------------------------------------------------------------------------------- /shaders/compatibility/water.frag: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #if @useUBO 4 | #extension GL_ARB_uniform_buffer_object : require 5 | #endif 6 | 7 | #if @useGPUShader4 8 | #extension GL_EXT_gpu_shader4: require 9 | #endif 10 | 11 | #include "lib/core/fragment.h.glsl" 12 | 13 | #define REFRACTION @refraction_enabled 14 | #define RAIN_RIPPLE_DETAIL @rain_ripple_detail 15 | 16 | // Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) 17 | 18 | // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 19 | 20 | const float VISIBILITY = 2500.0; 21 | 22 | const float BIG_WAVES_X = 0.1; // strength of big waves 23 | const float BIG_WAVES_Y = 0.1; 24 | 25 | const float MID_WAVES_X = 0.1; // strength of middle sized waves 26 | const float MID_WAVES_Y = 0.1; 27 | const float MID_WAVES_RAIN_X = 0.2; 28 | const float MID_WAVES_RAIN_Y = 0.2; 29 | 30 | const float SMALL_WAVES_X = 0.1; // strength of small waves 31 | const float SMALL_WAVES_Y = 0.1; 32 | const float SMALL_WAVES_RAIN_X = 0.3; 33 | const float SMALL_WAVES_RAIN_Y = 0.3; 34 | 35 | const float WAVE_CHOPPYNESS = 0.05; // wave choppyness 36 | const float WAVE_SCALE = 75.0; // overall wave scale 37 | 38 | const float BUMP = 0.5; // overall water surface bumpiness 39 | const float BUMP_RAIN = 2.5; 40 | const float REFL_BUMP = 0.10; // reflection distortion amount 41 | const float REFR_BUMP = 0.07; // refraction distortion amount 42 | 43 | const float SCATTER_AMOUNT = 0.3; // amount of sunlight scattering 44 | const vec3 SCATTER_COLOUR = vec3(0.0,1.0,0.95); // colour of sunlight scattering 45 | 46 | const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction 47 | 48 | const float SPEC_HARDNESS = 256.0; // specular highlights hardness 49 | 50 | const float BUMP_SUPPRESS_DEPTH = 300.0; // at what water depth bumpmap will be suppressed for reflections and refractions (prevents artifacts at shores) 51 | 52 | const vec2 WIND_DIR = vec2(0.5f, -0.8f); 53 | const float WIND_SPEED = 0.2f; 54 | 55 | const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); 56 | 57 | const float WOBBLY_SHORE_FADE_DISTANCE = 6200.0; // fade out wobbly shores to mask precision errors, the effect is almost impossible to see at a distance 58 | 59 | // ---------------- rain ripples related stuff --------------------- 60 | 61 | const float RAIN_RIPPLE_GAPS = 10.0; 62 | const float RAIN_RIPPLE_RADIUS = 0.2; 63 | 64 | float scramble(float x, float z) 65 | { 66 | return fract(pow(fract(x)*3.0+1.0, z)); 67 | } 68 | 69 | vec2 randOffset(vec2 c, float time) 70 | { 71 | time = fract(time/1000.0); 72 | c = vec2(c.x * c.y / 8.0 + c.y * 0.3 + c.x * 0.2, 73 | c.x * c.y / 14.0 + c.y * 0.5 + c.x * 0.7); 74 | c.x *= scramble(scramble(time + c.x/1000.0, 4.0), 3.0) + 1.0; 75 | c.y *= scramble(scramble(time + c.y/1000.0, 3.5), 3.0) + 1.0; 76 | return fract(c); 77 | } 78 | 79 | float randPhase(vec2 c) 80 | { 81 | return fract((c.x * c.y) / (c.x + c.y + 0.1)); 82 | } 83 | 84 | float blip(float x) 85 | { 86 | x = max(0.0, 1.0-x*x); 87 | return x*x*x; 88 | } 89 | 90 | float blipDerivative(float x) 91 | { 92 | x = clamp(x, -1.0, 1.0); 93 | float n = x*x-1.0; 94 | return -6.0*x*n*n; 95 | } 96 | 97 | const float RAIN_RING_TIME_OFFSET = 1.0/6.0; 98 | 99 | vec4 circle(vec2 coords, vec2 corner, float adjusted_time) 100 | { 101 | vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(corner, floor(adjusted_time)) - 1.0); 102 | float phase = fract(adjusted_time); 103 | vec2 toCenter = coords - center; 104 | 105 | float r = RAIN_RIPPLE_RADIUS; 106 | float d = length(toCenter); 107 | float ringfollower = (phase-d/r)/RAIN_RING_TIME_OFFSET-1.0; // -1.0 ~ +1.0 cover the breadth of the ripple's ring 108 | 109 | #if RAIN_RIPPLE_DETAIL > 0 110 | // normal mapped ripples 111 | if(ringfollower < -1.0 || ringfollower > 1.0) 112 | return vec4(0.0); 113 | 114 | if(d > 1.0) // normalize center direction vector, but not for near-center ripples 115 | toCenter /= d; 116 | 117 | float height = blip(ringfollower*2.0+0.5); // brighten up outer edge of ring; for fake specularity 118 | float range_limit = blip(min(0.0, ringfollower)); 119 | float energy = 1.0-phase; 120 | 121 | vec2 normal2d = -toCenter*blipDerivative(ringfollower)*5.0; 122 | vec3 normal = vec3(normal2d, 0.5); 123 | vec4 ret = vec4(normal, height); 124 | ret.xyw *= energy*energy; 125 | // do energy adjustment here rather than later, so that we can use the w component for fake specularity 126 | ret.xyz = normalize(ret.xyz) * energy*range_limit; 127 | ret.z *= range_limit; 128 | return ret; 129 | #else 130 | // ring-only ripples 131 | if(ringfollower < -1.0 || ringfollower > 0.5) 132 | return vec4(0.0); 133 | 134 | float energy = 1.0-phase; 135 | float height = blip(ringfollower*2.0+0.5)*energy*energy; // fake specularity 136 | 137 | return vec4(0.0, 0.0, 0.0, height); 138 | #endif 139 | } 140 | vec4 rain(vec2 uv, float time) 141 | { 142 | uv *= RAIN_RIPPLE_GAPS; 143 | vec2 f_part = fract(uv); 144 | vec2 i_part = floor(uv); 145 | float adjusted_time = time * 1.2 + randPhase(i_part); 146 | #if RAIN_RIPPLE_DETAIL > 0 147 | vec4 a = circle(f_part, i_part, adjusted_time); 148 | vec4 b = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET); 149 | vec4 c = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET*2.0); 150 | vec4 d = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET*3.0); 151 | vec4 ret; 152 | ret.xy = a.xy - b.xy/2.0 + c.xy/4.0 - d.xy/8.0; 153 | // z should always point up 154 | ret.z = a.z + b.z /2.0 + c.z /4.0 + d.z /8.0; 155 | //ret.xyz *= 1.5; 156 | // fake specularity looks weird if we use every single ring, also if the inner rings are too bright 157 | ret.w = (a.w + c.w /8.0)*1.5; 158 | return ret; 159 | #else 160 | return circle(f_part, i_part, adjusted_time) * 1.5; 161 | #endif 162 | } 163 | 164 | vec2 complex_mult(vec2 a, vec2 b) 165 | { 166 | return vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); 167 | } 168 | vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and fake specularity in w 169 | { 170 | return 171 | rain(uv, time) 172 | + rain(complex_mult(uv, vec2(0.4, 0.7)) + vec2(1.2, 3.0),time) 173 | #if RAIN_RIPPLE_DETAIL == 2 174 | + rain(uv * 0.75 + vec2( 3.7,18.9),time) 175 | + rain(uv * 0.9 + vec2( 5.7,30.1),time) 176 | + rain(uv * 1.0 + vec2(10.5 ,5.7),time) 177 | #endif 178 | ; 179 | } 180 | 181 | 182 | // -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - 183 | 184 | float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) 185 | { 186 | float c = abs(dot(Incoming, Normal)); 187 | float g = eta * eta - 1.0 + c * c; 188 | float result; 189 | 190 | if(g > 0.0) { 191 | g = sqrt(g); 192 | float A =(g - c)/(g + c); 193 | float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); 194 | result = 0.5 * A * A *(1.0 + B * B); 195 | } 196 | else 197 | result = 1.0; /* TIR (no refracted component) */ 198 | 199 | return result; 200 | } 201 | 202 | vec2 normalCoords(vec2 uv, float scale, float speed, float time, float timer1, float timer2, vec3 previousNormal) 203 | { 204 | return uv * (WAVE_SCALE * scale) + WIND_DIR * time * (WIND_SPEED * speed) -(previousNormal.xy/previousNormal.zz) * WAVE_CHOPPYNESS + vec2(time * timer1,time * timer2); 205 | } 206 | 207 | varying vec4 position; 208 | varying float linearDepth; 209 | 210 | uniform sampler2D normalMap; 211 | 212 | uniform float osg_SimulationTime; 213 | 214 | uniform float near; 215 | uniform float far; 216 | uniform vec3 nodePosition; 217 | 218 | uniform float rainIntensity; 219 | 220 | uniform vec2 screenRes; 221 | 222 | uniform mat4 osg_ViewMatrixInverse; 223 | 224 | #define PER_PIXEL_LIGHTING 0 225 | 226 | #include "shadows_fragment.glsl" 227 | #include "lib/light/lighting.glsl" 228 | #include "lib/view/depth.glsl" 229 | #include "fog.glsl" 230 | 231 | float frustumDepth; 232 | 233 | void main(void) 234 | { 235 | frustumDepth = abs(far - near); 236 | vec3 worldPos = position.xyz + nodePosition.xyz; 237 | vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; 238 | UV.y *= -1.0; 239 | 240 | float shadow = unshadowedLightRatio(linearDepth); 241 | 242 | vec2 screenCoords = gl_FragCoord.xy / screenRes; 243 | 244 | #define waterTimer osg_SimulationTime 245 | 246 | vec3 normal0 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.05, 0.04, waterTimer, -0.015, -0.005, vec3(0.0,0.0,0.0))).rgb - 1.0; 247 | vec3 normal1 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.1, 0.08, waterTimer, 0.02, 0.015, normal0)).rgb - 1.0; 248 | vec3 normal2 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.25, 0.07, waterTimer, -0.04, -0.03, normal1)).rgb - 1.0; 249 | vec3 normal3 = 2.0 * texture2D(normalMap,normalCoords(UV, 0.5, 0.09, waterTimer, 0.03, 0.04, normal2)).rgb - 1.0; 250 | vec3 normal4 = 2.0 * texture2D(normalMap,normalCoords(UV, 1.0, 0.4, waterTimer, -0.02, 0.1, normal3)).rgb - 1.0; 251 | vec3 normal5 = 2.0 * texture2D(normalMap,normalCoords(UV, 2.0, 0.7, waterTimer, 0.1, -0.06, normal4)).rgb - 1.0; 252 | 253 | vec4 rainRipple; 254 | 255 | if (rainIntensity > 0.01) 256 | rainRipple = rainCombined(position.xy/1000.0, waterTimer) * clamp(rainIntensity, 0.0, 1.0); 257 | else 258 | rainRipple = vec4(0.0); 259 | 260 | vec3 rippleAdd = rainRipple.xyz * 10.0; 261 | 262 | vec2 bigWaves = vec2(BIG_WAVES_X,BIG_WAVES_Y); 263 | vec2 midWaves = mix(vec2(MID_WAVES_X,MID_WAVES_Y),vec2(MID_WAVES_RAIN_X,MID_WAVES_RAIN_Y),rainIntensity); 264 | vec2 smallWaves = mix(vec2(SMALL_WAVES_X,SMALL_WAVES_Y),vec2(SMALL_WAVES_RAIN_X,SMALL_WAVES_RAIN_Y),rainIntensity); 265 | float bump = mix(BUMP,BUMP_RAIN,rainIntensity); 266 | 267 | vec3 normal = (normal0 * bigWaves.x + normal1 * bigWaves.y + normal2 * midWaves.x + 268 | normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd); 269 | normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z)); 270 | 271 | vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(lcalcPosition(0).xyz, 0.0)).xyz); 272 | vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; 273 | vec3 vVec = normalize(position.xyz - cameraPos.xyz); 274 | 275 | float sunFade = length(gl_LightModel.ambient.xyz); 276 | 277 | // fresnel 278 | float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air 279 | float fresnel = clamp(fresnel_dielectric(vVec, normal, ior), 0.0, 1.0); 280 | 281 | float radialise = 1.0; 282 | 283 | #if @radialFog 284 | float radialDepth = distance(position.xyz, cameraPos); 285 | // TODO: Figure out how to properly radialise refraction depth and thus underwater fog 286 | // while avoiding oddities when the water plane is close to the clipping plane 287 | // radialise = radialDepth / linearDepth; 288 | #else 289 | float radialDepth = 0.0; 290 | #endif 291 | 292 | vec2 screenCoordsOffset = normal.xy * REFL_BUMP; 293 | #if REFRACTION 294 | float depthSample = linearizeDepth(sampleRefractionDepthMap(screenCoords), near, far) * radialise; 295 | float depthSampleDistorted = linearizeDepth(sampleRefractionDepthMap(screenCoords-screenCoordsOffset), near, far) * radialise; 296 | float surfaceDepth = linearizeDepth(gl_FragCoord.z, near, far) * radialise; 297 | float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum 298 | screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); 299 | #endif 300 | // reflection 301 | vec3 reflection = sampleReflectionMap(screenCoords + screenCoordsOffset).rgb; 302 | 303 | // specular 304 | float specular = pow(max(dot(reflect(vVec, normal), lVec), 0.0),SPEC_HARDNESS) * shadow; 305 | 306 | vec3 waterColor = WATER_COLOR * sunFade; 307 | 308 | //vec4 sunSpec = lcalcSpecular(0); 309 | vec4 sunSpec = vec4(getPbr( 310 | osg_ViewMatrixInverse, 311 | (gl_ModelViewMatrix * position).xyz, 312 | (gl_ModelViewMatrix * vec4(normal, 0.0)).xyz, 313 | waterColor, 314 | 0.02, 315 | 1.0, 316 | 1.0, 317 | shadow, 318 | #if SHADOWS 319 | shadowFadeStart, 320 | #else 321 | 3500.0, 322 | #endif 323 | 1.0, 324 | vec3(0.0), 325 | 0.0, 326 | 0.0, 327 | MAT_DEFAULT 328 | ), 1.0); 329 | 330 | // artificial specularity to make rain ripples more noticeable 331 | vec3 skyColorEstimate = vec3(max(0.0, mix(-0.3, 1.0, sunFade))); 332 | vec3 rainSpecular = abs(rainRipple.w)*mix(skyColorEstimate, vec3(1.0), 0.05)*0.5; 333 | 334 | #if REFRACTION 335 | // no alpha here, so make sure raindrop ripple specularity gets properly subdued 336 | rainSpecular *= clamp(fresnel*6.0 + specular * sunSpec.w, 0.0, 1.0); 337 | 338 | // refraction 339 | vec3 refraction = sampleRefractionMap(screenCoords - screenCoordsOffset).rgb; 340 | vec3 rawRefraction = refraction; 341 | 342 | // brighten up the refraction underwater 343 | if (cameraPos.z < 0.0) 344 | refraction = clamp(refraction * 1.5, 0.0, 1.0); 345 | else 346 | refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0)); 347 | 348 | // sunlight scattering 349 | // normal for sunlight scattering 350 | vec3 lNormal = (normal0 * bigWaves.x * 0.5 + normal1 * bigWaves.y * 0.5 + normal2 * midWaves.x * 0.2 + 351 | normal3 * midWaves.y * 0.2 + normal4 * smallWaves.x * 0.1 + normal5 * smallWaves.y * 0.1 + rippleAdd); 352 | lNormal = normalize(vec3(-lNormal.x * bump, -lNormal.y * bump, lNormal.z)); 353 | float sunHeight = lVec.z; 354 | vec3 scatterColour = mix(SCATTER_COLOUR*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); 355 | vec3 lR = reflect(lVec, lNormal); 356 | float lightScatter = clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0) * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); 357 | gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpec.xyz + rainSpecular; 358 | gl_FragData[0].w = 1.0; 359 | 360 | // wobbly water: hard-fade into refraction texture at extremely low depth, with a wobble based on normal mapping 361 | vec3 normalShoreRippleRain = texture2D(normalMap,normalCoords(UV, 2.0, 2.7, -1.0*waterTimer, 0.05, 0.1, normal3)).rgb - 0.5 362 | + texture2D(normalMap,normalCoords(UV, 2.0, 2.7, waterTimer, 0.04, -0.13, normal4)).rgb - 0.5; 363 | float verticalWaterDepth = realWaterDepth * mix(abs(vVec.z), 1.0, 0.2); // an estimate 364 | float shoreOffset = verticalWaterDepth - (normal2.r + mix(0.0, normalShoreRippleRain.r, rainIntensity) + 0.15)*8.0; 365 | float fuzzFactor = min(1.0, 1000.0/surfaceDepth) * mix(abs(vVec.z), 1.0, 0.2); 366 | shoreOffset *= fuzzFactor; 367 | shoreOffset = clamp(mix(shoreOffset, 1.0, clamp(linearDepth / WOBBLY_SHORE_FADE_DISTANCE, 0.0, 1.0)), 0.0, 1.0); 368 | gl_FragData[0].xyz = mix(rawRefraction, gl_FragData[0].xyz, shoreOffset); 369 | #else 370 | gl_FragData[0].xyz = mix(waterColor, reflection, fresnel) + specular * sunSpec.xyz + rainSpecular; 371 | gl_FragData[0].w = clamp(fresnel*6.0 + specular * sunSpec.w, 0.0, 1.0); //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); 372 | #endif 373 | 374 | gl_FragData[0] = applyFogAtDist(gl_FragData[0], radialDepth, linearDepth, far); 375 | 376 | #if !@disableNormals 377 | gl_FragData[1].rgb = normal * 0.5 + 0.5; 378 | #endif 379 | 380 | tonemap(gl_FragData[0].rgb); 381 | 382 | applyShadowDebugOverlay(); 383 | } 384 | -------------------------------------------------------------------------------- /shaders/compatibility/water.vert: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/core/vertex.h.glsl" 4 | 5 | varying vec4 position; 6 | varying float linearDepth; 7 | 8 | #include "shadows_vertex.glsl" 9 | #include "lib/zesterer/warp.glsl" 10 | #include "lib/view/depth.glsl" 11 | #include "lib/zesterer/wave.glsl" 12 | 13 | void main(void) 14 | { 15 | vec4 modelPos = gl_Vertex; 16 | //mpos.z += doWave(); 17 | 18 | gl_Position = modelToClip(modelPos); 19 | 20 | position = modelPos; 21 | 22 | vec4 viewPos = modelToView(modelPos); 23 | 24 | gl_Position = warp_position(viewPos.xyz); 25 | 26 | linearDepth = getLinearDepth(gl_Position.z, viewPos.z); 27 | 28 | setupShadowCoords(viewPos, normalize((gl_NormalMatrix * gl_Normal).xyz)); 29 | } 30 | -------------------------------------------------------------------------------- /shaders/core/gui.frag: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | 3 | layout (location = 0) in vec4 Position; 4 | layout (location = 3) in vec4 Color; 5 | layout (location = 8) in vec3 TexCoord0; 6 | 7 | out vec4 passColor; 8 | out vec2 uv; 9 | 10 | void main() 11 | { 12 | gl_Position = vec4(Position.xyz, 1.0); 13 | uv = TexCoord0.xy; 14 | passColor = Color; 15 | } 16 | -------------------------------------------------------------------------------- /shaders/core/gui.vert: -------------------------------------------------------------------------------- 1 | #version 430 core 2 | 3 | layout(location = 0) out vec4 Color; 4 | 5 | layout(location = 0) uniform sampler2D diffuseMap; 6 | 7 | in vec4 passColor; 8 | in vec2 uv; 9 | 10 | void main() 11 | { 12 | Color = texture(diffuseMap, uv) * passColor; 13 | } 14 | -------------------------------------------------------------------------------- /shaders/core/ripples_blobber.comp: -------------------------------------------------------------------------------- 1 | #version 440 core 2 | 3 | layout (binding = 0, rgba16f) restrict writeonly uniform image2D imageOut; 4 | layout (binding = 1, rgba16f) restrict readonly uniform image2D imageIn; 5 | 6 | layout (local_size_x=16, local_size_y=16) in; 7 | 8 | #define MAX_POSITIONS 100 9 | uniform vec3 positions[MAX_POSITIONS]; 10 | uniform int positionCount; 11 | 12 | uniform float osg_SimulationTime; 13 | uniform vec2 offset; 14 | 15 | #include "lib/water/ripples.glsl" 16 | 17 | void main() 18 | { 19 | ivec2 texel = ivec2(gl_GlobalInvocationID.xy + offset); 20 | 21 | vec4 color = imageLoad(imageIn, texel); 22 | float wavesizeMultiplier = getTemporalWaveSizeMultiplier(osg_SimulationTime); 23 | for (int i = 0; i < positionCount; ++i) 24 | { 25 | float wavesize = wavesizeMultiplier * positions[i].z; 26 | float displace = clamp(2.0 * abs(length((positions[i].xy + offset) - vec2(gl_GlobalInvocationID.xy)) / wavesize - 1.0), 0.0, 1.0); 27 | color.rg = mix(vec2(-1.0), color.rg, displace); 28 | } 29 | 30 | imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), color); 31 | } 32 | -------------------------------------------------------------------------------- /shaders/core/ripples_simulate.comp: -------------------------------------------------------------------------------- 1 | #version 440 core 2 | 3 | layout (binding = 0, rgba16f) restrict writeonly uniform image2D imageOut; 4 | layout (binding = 1, rgba16f) restrict readonly uniform image2D imageIn; 5 | 6 | layout (local_size_x=16, local_size_y=16) in; 7 | 8 | #include "lib/water/ripples.glsl" 9 | 10 | void main() 11 | { 12 | ivec2 texel = ivec2(gl_GlobalInvocationID.xy); 13 | 14 | vec4 n = vec4( 15 | imageLoad(imageIn, texel + ivec2(1, 0)).r, 16 | imageLoad(imageIn, texel + ivec2(-1, 0)).r, 17 | imageLoad(imageIn, texel + ivec2(0, 1)).r, 18 | imageLoad(imageIn, texel + ivec2(0, -1)).r 19 | ); 20 | 21 | vec4 n2 = vec4( 22 | imageLoad(imageIn, texel + ivec2(2, 0)).r, 23 | imageLoad(imageIn, texel + ivec2(-2, 0)).r, 24 | imageLoad(imageIn, texel + ivec2(0, 2)).r, 25 | imageLoad(imageIn, texel + ivec2(0, -2)).r 26 | ); 27 | 28 | vec4 color = imageLoad(imageIn, texel); 29 | 30 | imageStore(imageOut, texel, applySprings(color, n, n2)); 31 | } 32 | -------------------------------------------------------------------------------- /shaders/lib/core/fragment.glsl: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/core/fragment.h.glsl" 4 | 5 | uniform sampler2D reflectionMap; 6 | 7 | vec4 sampleReflectionMap(vec2 uv) 8 | { 9 | return texture2D(reflectionMap, uv); 10 | } 11 | 12 | #if @refraction_enabled 13 | uniform sampler2D refractionMap; 14 | uniform sampler2D refractionDepthMap; 15 | 16 | vec4 sampleRefractionMap(vec2 uv) 17 | { 18 | return texture2D(refractionMap, uv); 19 | } 20 | 21 | float sampleRefractionDepthMap(vec2 uv) 22 | { 23 | return texture2D(refractionDepthMap, uv).x; 24 | } 25 | 26 | #endif 27 | 28 | uniform sampler2D lastShader; 29 | 30 | vec4 samplerLastShader(vec2 uv) 31 | { 32 | return texture2D(lastShader, uv); 33 | } 34 | 35 | #if @skyBlending 36 | uniform sampler2D sky; 37 | 38 | vec3 sampleSkyColor(vec2 uv) 39 | { 40 | return texture2D(sky, uv).xyz; 41 | } 42 | #endif 43 | -------------------------------------------------------------------------------- /shaders/lib/core/fragment.h.glsl: -------------------------------------------------------------------------------- 1 | #ifndef OPENMW_FRAGMENT_H_GLSL 2 | #define OPENMW_FRAGMENT_H_GLSL 3 | 4 | @link "lib/core/fragment.glsl" if !@useOVR_multiview 5 | @link "lib/core/fragment_multiview.glsl" if @useOVR_multiview 6 | 7 | vec4 sampleReflectionMap(vec2 uv); 8 | 9 | #if @refraction_enabled 10 | vec4 sampleRefractionMap(vec2 uv); 11 | float sampleRefractionDepthMap(vec2 uv); 12 | #endif 13 | 14 | vec4 samplerLastShader(vec2 uv); 15 | 16 | #if @skyBlending 17 | vec3 sampleSkyColor(vec2 uv); 18 | #endif 19 | 20 | #endif // OPENMW_FRAGMENT_H_GLSL 21 | -------------------------------------------------------------------------------- /shaders/lib/core/fragment_multiview.glsl: -------------------------------------------------------------------------------- 1 | #version 330 2 | 3 | #extension GL_OVR_multiview : require 4 | #extension GL_OVR_multiview2 : require 5 | #extension GL_EXT_texture_array : require 6 | 7 | #include "lib/core/fragment.h.glsl" 8 | 9 | uniform sampler2DArray reflectionMap; 10 | 11 | vec4 sampleReflectionMap(vec2 uv) 12 | { 13 | return texture2DArray(reflectionMap, vec3((uv), gl_ViewID_OVR)); 14 | } 15 | 16 | #if @refraction_enabled 17 | 18 | uniform sampler2DArray refractionMap; 19 | uniform sampler2DArray refractionDepthMap; 20 | 21 | vec4 sampleRefractionMap(vec2 uv) 22 | { 23 | return texture2DArray(refractionMap, vec3((uv), gl_ViewID_OVR)); 24 | } 25 | 26 | float sampleRefractionDepthMap(vec2 uv) 27 | { 28 | return texture2DArray(refractionDepthMap, vec3((uv), gl_ViewID_OVR)).x; 29 | } 30 | 31 | #endif 32 | 33 | uniform sampler2DArray omw_SamplerLastShader; 34 | 35 | vec4 samplerLastShader(vec2 uv) 36 | { 37 | return texture2DArray(omw_SamplerLastShader, vec3((uv), gl_ViewID_OVR)); 38 | } 39 | 40 | #if @skyBlending 41 | uniform sampler2DArray sky; 42 | 43 | vec3 sampleSkyColor(vec2 uv) 44 | { 45 | return texture2DArray(sky, vec3((uv), gl_ViewID_OVR)).xyz; 46 | } 47 | #endif 48 | -------------------------------------------------------------------------------- /shaders/lib/core/vertex.glsl: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "lib/core/vertex.h.glsl" 4 | 5 | uniform mat4 projectionMatrix; 6 | 7 | vec4 modelToClip(vec4 pos) 8 | { 9 | return projectionMatrix * modelToView(pos); 10 | } 11 | 12 | vec4 modelToView(vec4 pos) 13 | { 14 | return gl_ModelViewMatrix * pos; 15 | } 16 | 17 | vec4 viewToClip(vec4 pos) 18 | { 19 | return projectionMatrix * pos; 20 | } 21 | -------------------------------------------------------------------------------- /shaders/lib/core/vertex.h.glsl: -------------------------------------------------------------------------------- 1 | @link "lib/core/vertex.glsl" 2 | 3 | vec4 modelToClip(vec4 pos); 4 | vec4 modelToView(vec4 pos); 5 | vec4 viewToClip(vec4 pos); 6 | -------------------------------------------------------------------------------- /shaders/lib/core/vertex_multiview.glsl: -------------------------------------------------------------------------------- 1 | #version 330 compatibility 2 | // Note: compatibility profile required to access gl_ModelViewMatrix 3 | 4 | #extension GL_OVR_multiview : require 5 | #extension GL_OVR_multiview2 : require 6 | 7 | layout(num_views = @numViews) in; 8 | 9 | #include "lib/core/vertex.h.glsl" 10 | 11 | uniform mat4 projectionMatrixMultiView[@numViews]; 12 | 13 | vec4 modelToClip(vec4 pos) 14 | { 15 | return viewToClip(modelToView(pos)); 16 | } 17 | 18 | vec4 modelToView(vec4 pos) 19 | { 20 | return gl_ModelViewMatrix * pos; 21 | } 22 | 23 | vec4 viewToClip(vec4 pos) 24 | { 25 | return projectionMatrixMultiView[gl_ViewID_OVR] * pos; 26 | } 27 | -------------------------------------------------------------------------------- /shaders/lib/light/lighting.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_LIGHT_LIGHTING 2 | #define LIB_LIGHT_LIGHTING 3 | 4 | #include "lib/zesterer/pbr.glsl" 5 | 6 | float getFresnelSpecular(vec3 viewDir, vec3 viewNormal, vec3 lightDir) { 7 | const float lift = 0.0; 8 | return (0.0 9 | + max((dot(viewDir, reflect(lightDir, viewNormal)) + lift) / (1.0 + lift), .0) 10 | ) * 1.75; 11 | } 12 | 13 | float getFresnelDiffuse(vec3 viewDir, vec3 viewNormal, vec3 lightDir) { 14 | const float lift = 0.0; 15 | return (0.0 16 | + max((dot(-viewDir, viewNormal) + lift) / (1.0 + lift), 0.0) 17 | ) * 1.75; 18 | } 19 | 20 | void perLightSun(out vec3 diffuseOut, out vec3 ambientOut, vec3 viewPos, vec3 viewNormal, float roughness, float shadowing, bool isBack) 21 | { 22 | vec3 lightDir = normalize(lcalcPosition(0)); 23 | vec3 viewDir = normalize(viewPos); 24 | viewNormal = normalize(viewNormal); 25 | 26 | float lambert; 27 | #ifdef GROUNDCOVER 28 | lambert = dot(viewNormal, lightDir) * shadowing; 29 | #else 30 | // Leaves 31 | if (roughness > 0.5) { 32 | //viewNormal = viewDir; 33 | lambert = max(0.0, dot(viewDir, -lightDir) * 0.5 + 0.5) * shadowing; 34 | #ifdef GROUNDCOVER 35 | // Hacky 36 | lambert = (lambert + pow(max(0.0, (dot(viewDir, lightDir) * 0.5 + 0.5)), 3.0) * shadowing * 0.75) * 0.5; 37 | #endif 38 | // Sub-surface scattering 39 | //if (dot(viewNormal, lightDir) < 0 /*isBack*/) { // TODO: Make this work for front faces too! 40 | // lambert += pow(max(dot(viewDir, lightDir), 0), 4) * shadowing; 41 | //} 42 | } else { 43 | lambert = dot(viewNormal, lightDir); 44 | } 45 | #endif 46 | 47 | float fresnelSpecular = 1.0; 48 | float fresnelDiffuse = 1.0; 49 | 50 | #ifndef GROUNDCOVER 51 | lambert = max(lambert, 0.0); 52 | fresnelSpecular = getFresnelSpecular(viewDir, viewNormal, lightDir); 53 | fresnelDiffuse = getFresnelDiffuse(viewDir, viewNormal, lightDir); 54 | #else 55 | float eyeCosine = dot(viewDir, viewNormal.xyz); 56 | if (lambert < 0.0) 57 | { 58 | lambert = -lambert; 59 | eyeCosine = -eyeCosine; 60 | } 61 | lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); 62 | #endif 63 | 64 | const float intensity = 1.0; 65 | vec3 direct_light = lcalcDiffuse(0).xyz * vec3(2.2, 2.0, 1.6) * intensity; 66 | vec3 indirect_light = gl_LightModel.ambient.xyz * vec3(0.7, 0.85, 1.1) / intensity; 67 | 68 | diffuseOut = mix( 69 | mix(fresnelSpecular, 1.0, max(0.35, roughness)) * pow(lambert, 0.5), 70 | lambert, 71 | 0.5) * direct_light; 72 | //#ifndef GROUNDCOVER // TODO: Make groundcover behave correctly with ambiance 73 | ambientOut = indirect_light * mix(fresnelDiffuse, 1.0, max(0.0, roughness)); 74 | //#endif 75 | } 76 | 77 | void perLightPoint(out vec3 diffuseOut, out vec3 ambientOut, int lightIndex, vec3 viewPos, vec3 viewNormal, float roughness) 78 | { 79 | vec3 lightPos = lcalcPosition(lightIndex) - viewPos; 80 | float lightDistance = length(lightPos); 81 | vec3 viewDir = normalize(viewPos); 82 | 83 | // cull non-FFP point lighting by radius, light is guaranteed to not fall outside this bound with our cutoff 84 | #if !@lightingMethodFFP 85 | float radius = lcalcRadius(lightIndex); 86 | 87 | if (lightDistance > radius * 2.0) 88 | { 89 | ambientOut = vec3(0.0); 90 | diffuseOut = vec3(0.0); 91 | return; 92 | } 93 | #endif 94 | 95 | lightPos = normalize(lightPos); 96 | 97 | float illumination = lcalcIllumination(lightIndex, lightDistance); 98 | ambientOut = lcalcAmbient(lightIndex) * illumination; 99 | float lambert = dot(viewNormal.xyz, lightPos); 100 | float fresnelSpecular = 1.0; 101 | float fresnelDiffuse = 1.0; 102 | 103 | #ifndef GROUNDCOVER 104 | lambert = max(lambert, 0.0); 105 | fresnelSpecular = getFresnelSpecular(viewDir, viewNormal, lightPos); 106 | fresnelDiffuse = getFresnelDiffuse(viewDir, viewNormal, lightPos); 107 | #else 108 | float eyeCosine = dot(normalize(viewPos), viewNormal.xyz); 109 | if (lambert < 0.0) 110 | { 111 | lambert = -lambert; 112 | eyeCosine = -eyeCosine; 113 | } 114 | lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); 115 | #endif 116 | 117 | vec3 directLight = illumination * lcalcDiffuse(lightIndex) * 4.5 / (vec3(1.0) + lcalcDiffuse(0).r * 2.5); 118 | vec3 indirectLight = directLight * 0.5; 119 | 120 | diffuseOut = mix( 121 | mix(fresnelSpecular, 1.0, max(0.5, roughness)) * pow(lambert, 0.5), 122 | lambert, 123 | 0.5) * directLight; 124 | //#ifndef GROUNDCOVER // TODO: Make groundcover behave correctly with ambiance 125 | ambientOut = indirectLight * gl_LightModel.ambient.xyz * mix(fresnelDiffuse, 1.0, max(0.0, roughness)); 126 | //#endif 127 | } 128 | 129 | #if PER_PIXEL_LIGHTING 130 | void doLighting(vec3 viewPos, vec3 viewNormal, float shadowing, out vec3 diffuseLight, out vec3 ambientLight, float roughness, bool isBack) 131 | #else 132 | void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 ambientLight, out vec3 shadowDiffuse) 133 | #endif 134 | { 135 | vec3 ambientOut, diffuseOut; 136 | 137 | #if !PER_PIXEL_LIGHTING 138 | float roughness = 0.0; 139 | float shadowing = 1.0; 140 | bool isBack = false; 141 | #endif 142 | 143 | #if SHADOWS 144 | perLightSun(diffuseOut, ambientOut, viewPos, viewNormal, roughness, shadowing, isBack); 145 | #endif 146 | 147 | #if PER_PIXEL_LIGHTING 148 | diffuseLight = diffuseOut * mix(shadowing, 1.0, roughness); 149 | ambientLight = ambientOut; 150 | #else 151 | shadowDiffuse = diffuseOut * shadowing; 152 | ambientLight = ambientOut; 153 | diffuseLight = vec3(0.0); 154 | #endif 155 | 156 | for (int i = @startLight; i < @endLight; ++i) 157 | { 158 | #if @lightingMethodUBO 159 | perLightPoint(diffuseOut, ambientOut, PointLightIndex[i], viewPos, viewNormal, roughness); 160 | #else 161 | perLightPoint(diffuseOut, ambientOut, i, viewPos, viewNormal, roughness); 162 | #endif 163 | ambientLight += ambientOut; 164 | diffuseLight += diffuseOut; 165 | } 166 | } 167 | 168 | vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec) 169 | { 170 | return vec3(0.0); // TODO: Use specularity 171 | vec3 lightDir = normalize(lcalcPosition(0)); 172 | float NdotL = dot(viewNormal, lightDir); 173 | if (NdotL <= 0.0) 174 | return vec3(0.0); 175 | vec3 halfVec = normalize(lightDir - viewDirection); 176 | float NdotH = dot(viewNormal, halfVec); 177 | return pow(max(NdotH, 0.0), max(1e-4, shininess)) * lcalcSpecular(0).xyz * matSpec; 178 | } 179 | 180 | #endif 181 | -------------------------------------------------------------------------------- /shaders/lib/light/lighting_util.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIGHTING_UTIL_GLSL 2 | #define LIGHTING_UTIL_GLSL 3 | 4 | #include "lib/util/quickstep.glsl" 5 | 6 | #if @lightingMethodUBO 7 | 8 | const int mask = int(0xff); 9 | const ivec4 shift = ivec4(int(0), int(8), int(16), int(24)); 10 | 11 | vec3 unpackRGB(int data) 12 | { 13 | return vec3( (float(((data >> shift.x) & mask)) / 255.0) 14 | ,(float(((data >> shift.y) & mask)) / 255.0) 15 | ,(float(((data >> shift.z) & mask)) / 255.0)); 16 | } 17 | 18 | vec4 unpackRGBA(int data) 19 | { 20 | return vec4( (float(((data >> shift.x) & mask)) / 255.0) 21 | ,(float(((data >> shift.y) & mask)) / 255.0) 22 | ,(float(((data >> shift.z) & mask)) / 255.0) 23 | ,(float(((data >> shift.w) & mask)) / 255.0)); 24 | } 25 | 26 | /* Layout: 27 | packedColors: 8-bit unsigned RGB packed as (diffuse, ambient, specular). 28 | sign bit is stored in unused alpha component 29 | attenuation: constant, linear, quadratic, light radius (as defined in content) 30 | */ 31 | struct LightData 32 | { 33 | ivec4 packedColors; 34 | vec4 position; 35 | vec4 attenuation; 36 | }; 37 | 38 | uniform int PointLightIndex[@maxLights]; 39 | uniform int PointLightCount; 40 | 41 | // Defaults to shared layout. If we ever move to GLSL 140, std140 layout should be considered 42 | uniform LightBufferBinding 43 | { 44 | LightData LightBuffer[@maxLightsInScene]; 45 | }; 46 | 47 | #elif @lightingMethodPerObjectUniform 48 | 49 | /* Layout: 50 | --------------------------------------- ----------- 51 | | pos_x | ambi_r | diff_r | spec_r | 52 | | pos_y | ambi_g | diff_g | spec_g | 53 | | pos_z | ambi_b | diff_b | spec_b | 54 | | att_c | att_l | att_q | radius/spec_a | 55 | -------------------------------------------------- 56 | */ 57 | uniform mat4 LightBuffer[@maxLights]; 58 | uniform int PointLightCount; 59 | 60 | #endif 61 | 62 | #if !@lightingMethodFFP 63 | float lcalcRadius(int lightIndex) 64 | { 65 | #if @lightingMethodPerObjectUniform 66 | return @getLight[lightIndex][3].w; 67 | #else 68 | return @getLight[lightIndex].attenuation.w; 69 | #endif 70 | } 71 | #endif 72 | 73 | float lcalcIllumination(int lightIndex, float lightDistance) 74 | { 75 | #if @lightingMethodPerObjectUniform 76 | float illumination = clamp(1.0 / (@getLight[lightIndex][0].w + @getLight[lightIndex][1].w * lightDistance + @getLight[lightIndex][2].w * lightDistance * lightDistance), 0.0, 1.0); 77 | return (illumination * (1.0 - quickstep((lightDistance / lcalcRadius(lightIndex)) - 1.0))); 78 | #elif @lightingMethodUBO 79 | float illumination = clamp(1.0 / (@getLight[lightIndex].attenuation.x + @getLight[lightIndex].attenuation.y * lightDistance + @getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0); 80 | return (illumination * (1.0 - quickstep((lightDistance / lcalcRadius(lightIndex)) - 1.0))); 81 | #else 82 | return clamp(1.0 / (@getLight[lightIndex].constantAttenuation + @getLight[lightIndex].linearAttenuation * lightDistance + @getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); 83 | #endif 84 | } 85 | 86 | vec3 lcalcPosition(int lightIndex) 87 | { 88 | #if @lightingMethodPerObjectUniform 89 | return @getLight[lightIndex][0].xyz; 90 | #else 91 | return @getLight[lightIndex].position.xyz; 92 | #endif 93 | } 94 | 95 | vec3 lcalcDiffuse(int lightIndex) 96 | { 97 | #if @lightingMethodPerObjectUniform 98 | return @getLight[lightIndex][2].xyz; 99 | #elif @lightingMethodUBO 100 | return unpackRGB(@getLight[lightIndex].packedColors.x) * float(@getLight[lightIndex].packedColors.w); 101 | #else 102 | return @getLight[lightIndex].diffuse.xyz; 103 | #endif 104 | } 105 | 106 | vec3 lcalcAmbient(int lightIndex) 107 | { 108 | #if @lightingMethodPerObjectUniform 109 | return @getLight[lightIndex][1].xyz; 110 | #elif @lightingMethodUBO 111 | return unpackRGB(@getLight[lightIndex].packedColors.y); 112 | #else 113 | return @getLight[lightIndex].ambient.xyz; 114 | #endif 115 | } 116 | 117 | vec4 lcalcSpecular(int lightIndex) 118 | { 119 | #if @lightingMethodPerObjectUniform 120 | return @getLight[lightIndex][3]; 121 | #elif @lightingMethodUBO 122 | return unpackRGBA(@getLight[lightIndex].packedColors.z); 123 | #else 124 | return @getLight[lightIndex].specular; 125 | #endif 126 | } 127 | 128 | void clampLightingResult(inout vec3 lighting) 129 | { 130 | #if @clamp 131 | lighting = clamp(lighting, vec3(0.0), vec3(1.0)); 132 | #else 133 | lighting = max(lighting, 0.0); 134 | #endif 135 | } 136 | 137 | #endif 138 | -------------------------------------------------------------------------------- /shaders/lib/luminance/constants.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LUMINANCE_CONSTANTS 2 | #define LUMINANCE_CONSTANTS 3 | 4 | const float minLog = -9.0; 5 | const float maxLog = 4.0; 6 | const float logLumRange = (maxLog - minLog); 7 | const float invLogLumRange = 1.0 / logLumRange; 8 | const float epsilon = 0.004; 9 | const float hdrExposureTime = @hdrExposureTime; 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /shaders/lib/material/alpha.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_MATERIAL_ALPHA 2 | #define LIB_MATERIAL_ALPHA 3 | 4 | #define FUNC_NEVER 512 // 0x0200 5 | #define FUNC_LESS 513 // 0x0201 6 | #define FUNC_EQUAL 514 // 0x0202 7 | #define FUNC_LEQUAL 515 // 0x0203 8 | #define FUNC_GREATER 516 // 0x0204 9 | #define FUNC_NOTEQUAL 517 // 0x0205 10 | #define FUNC_GEQUAL 518 // 0x0206 11 | #define FUNC_ALWAYS 519 // 0x0207 12 | 13 | float mipmapLevel(vec2 scaleduv) 14 | { 15 | vec2 dUVdx = dFdx(scaleduv); 16 | vec2 dUVdy = dFdy(scaleduv); 17 | float maxDUVSquared = max(dot(dUVdx, dUVdx), dot(dUVdy, dUVdy)); 18 | return max(0.0, 0.5 * log2(maxDUVSquared)); 19 | } 20 | 21 | float coveragePreservingAlphaScale(sampler2D diffuseMap, vec2 uv) 22 | { 23 | #if @adjustCoverage 24 | vec2 textureSize; 25 | #if @useGPUShader4 26 | textureSize = textureSize2D(diffuseMap, 0); 27 | #else 28 | textureSize = vec2(256.0); 29 | #endif 30 | return 1.0 + mipmapLevel(uv * textureSize) * 0.25; 31 | #else 32 | return 1.0; 33 | #endif 34 | } 35 | 36 | float alphaTest(float alpha, float ref) 37 | { 38 | #if @alphaToCoverage 39 | float coverageAlpha = (alpha - clamp(ref, 0.0001, 0.9999)) / max(fwidth(alpha), 0.0001) + 0.5; 40 | 41 | // Some functions don't make sense with A2C or are a pain to think about and no meshes use them anyway 42 | // Use regular alpha testing in such cases until someone complains. 43 | #if @alphaFunc == FUNC_NEVER 44 | discard; 45 | #elif @alphaFunc == FUNC_LESS 46 | return 1.0 - coverageAlpha; 47 | #elif @alphaFunc == FUNC_EQUAL 48 | if (alpha != ref) 49 | discard; 50 | #elif @alphaFunc == FUNC_LEQUAL 51 | return 1.0 - coverageAlpha; 52 | #elif @alphaFunc == FUNC_GREATER 53 | return coverageAlpha; 54 | #elif @alphaFunc == FUNC_NOTEQUAL 55 | if (alpha == ref) 56 | discard; 57 | #elif @alphaFunc == FUNC_GEQUAL 58 | return coverageAlpha; 59 | #endif 60 | #else 61 | #if @alphaFunc == FUNC_NEVER 62 | discard; 63 | #elif @alphaFunc == FUNC_LESS 64 | if (alpha >= ref) 65 | discard; 66 | #elif @alphaFunc == FUNC_EQUAL 67 | if (alpha != ref) 68 | discard; 69 | #elif @alphaFunc == FUNC_LEQUAL 70 | if (alpha > ref) 71 | discard; 72 | #elif @alphaFunc == FUNC_GREATER 73 | if (alpha <= ref) 74 | discard; 75 | #elif @alphaFunc == FUNC_NOTEQUAL 76 | if (alpha == ref) 77 | discard; 78 | #elif @alphaFunc == FUNC_GEQUAL 79 | if (alpha < ref) 80 | discard; 81 | #endif 82 | #endif 83 | 84 | return alpha; 85 | } 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /shaders/lib/material/parallax.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_MATERIAL_PARALLAX 2 | #define LIB_MATERIAL_PARALLAX 3 | 4 | #define PARALLAX_SCALE 0.04 5 | #define PARALLAX_BIAS -0.02 6 | 7 | vec2 getParallaxOffset(vec3 eyeDir, mat3 tbnTranspose, float height, float flipY) 8 | { 9 | vec3 TSeyeDir = normalize(eyeDir * tbnTranspose); 10 | return vec2(TSeyeDir.x, TSeyeDir.y * flipY) * ( height * PARALLAX_SCALE + PARALLAX_BIAS ); 11 | } 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /shaders/lib/particle/occlusion.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_PARTICLE_OCCLUSION 2 | #define LIB_PARTICLE_OCCLUSION 3 | 4 | void applyOcclusionDiscard(in vec3 coord, float sceneDepth) 5 | { 6 | #if @reverseZ 7 | if (coord.z < sceneDepth) 8 | discard; 9 | #else 10 | if (coord.z * 0.5 + 0.5 > sceneDepth) 11 | discard; 12 | #endif 13 | } 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /shaders/lib/particle/soft.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_PARTICLE_SOFT 2 | #define LIB_PARTICLE_SOFT 3 | 4 | #include "lib/util/quickstep.glsl" 5 | 6 | float viewDepth(float depth, float near, float far) 7 | { 8 | #if @reverseZ 9 | depth = 1.0 - depth; 10 | #endif 11 | return (near * far) / ((far - near) * depth - far); 12 | } 13 | 14 | float calcSoftParticleFade( 15 | in vec3 viewDir, 16 | in vec3 viewPos, 17 | in vec3 viewNormal, 18 | float near, 19 | float far, 20 | float depth, 21 | float size, 22 | bool fade 23 | ) 24 | { 25 | float euclidianDepth = length(viewPos); 26 | 27 | const float falloffMultiplier = 0.33; 28 | const float contrast = 1.30; 29 | 30 | float sceneDepth = viewDepth(depth, near, far); 31 | float particleDepth = viewPos.z; 32 | float falloff = size * falloffMultiplier; 33 | float delta = particleDepth - sceneDepth; 34 | 35 | const float nearMult = 300.0; 36 | float viewBias = 1.0; 37 | 38 | if (fade) 39 | { 40 | float VdotN = dot(viewDir, viewNormal); 41 | viewBias = abs(VdotN) * quickstep(euclidianDepth / nearMult) * (1.0 - pow(1.0 + VdotN, 1.3)); 42 | } 43 | 44 | const float shift = 0.845; 45 | return shift * pow(clamp(delta/falloff, 0.0, 1.0), contrast) * viewBias; 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /shaders/lib/sky/passes.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_SKY_PASSES 2 | #define LIB_SKY_PASSES 3 | 4 | #define PASS_ATMOSPHERE 0 5 | #define PASS_ATMOSPHERE_NIGHT 1 6 | #define PASS_CLOUDS 2 7 | #define PASS_MOON 3 8 | #define PASS_SUN 4 9 | #define PASS_SUNFLASH_QUERY 5 10 | #define PASS_SUNGLARE 6 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /shaders/lib/util/coordinates.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_UTIL_COORDINATES 2 | #define LIB_UTIL_COORDINATES 3 | 4 | #define PI 3.1415926535 5 | 6 | vec3 sphericalCoords(vec2 coords) 7 | { 8 | coords.x = -1 * coords.x * 2 * PI; 9 | coords.y = (coords.y - 0.5) * PI; 10 | 11 | vec3 result = vec3(0.0,cos(coords.y),sin(coords.y)); 12 | result = vec3(cos(coords.x) * result.y,sin(coords.x) * result.y,result.z); 13 | 14 | return result; 15 | } 16 | 17 | vec3 cylindricalCoords(vec2 coords) 18 | { 19 | return normalize(vec3(cos(-1 * coords.x * 2 * PI),sin(-1 * coords.x * 2 * PI),coords.y * 2.0 - 1.0)); 20 | } 21 | 22 | vec3 planetCoords(vec2 coords) 23 | { 24 | vec2 fromCenter = coords - vec2(0.5,0.5); 25 | 26 | float magnitude = length(fromCenter); 27 | 28 | fromCenter = normalize(fromCenter); 29 | 30 | float dotProduct = dot(fromCenter,vec2(0.0,1.0)); 31 | 32 | coords.x = coords.x > 0.5 ? 0.5 - (dotProduct + 1.0) / 4.0 : 0.5 + (dotProduct + 1.0) / 4.0; 33 | coords.y = max(0.0,1.0 - pow(magnitude / 0.5,0.5)); 34 | return sphericalCoords(coords); 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /shaders/lib/util/quickstep.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_UTIL_QUICKSTEP 2 | #define LIB_UTIL_QUICKSTEP 3 | 4 | float quickstep(float x) 5 | { 6 | x = clamp(x, 0.0, 1.0); 7 | x = 1.0 - x*x; 8 | x = 1.0 - x*x; 9 | return x; 10 | } 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /shaders/lib/view/depth.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_VIEW_DEPTH 2 | #define LIB_VIEW_DEPTH 3 | 4 | float linearizeDepth(float depth, float near, float far) 5 | { 6 | #if @reverseZ 7 | depth = 1.0 - depth; 8 | #endif 9 | float z_n = 2.0 * depth - 1.0; 10 | depth = 2.0 * near * far / (far + near - z_n * (far - near)); 11 | return depth; 12 | } 13 | 14 | float getLinearDepth(in float z, in float viewZ) 15 | { 16 | #if @reverseZ 17 | // FIXME: Fixme, figure out how to calculate correct linear depth for reverse z 18 | return -viewZ; 19 | #else 20 | return z; 21 | #endif 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /shaders/lib/water/fresnel.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_WATER_FRESNEL 2 | #define LIB_WATER_FRESNEL 3 | 4 | float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) 5 | { 6 | float c = abs(dot(Incoming, Normal)); 7 | float g = eta * eta - 1.0 + c * c; 8 | float result; 9 | 10 | if (g > 0.0) { 11 | g = sqrt(g); 12 | float A =(g - c)/(g + c); 13 | float B =(c *(g + c)- 1.0)/(c *(g - c)+ 1.0); 14 | result = 0.5 * A * A *(1.0 + B * B); 15 | } 16 | else { 17 | result = 1.0; /* TIR (no refracted component) */ 18 | } 19 | 20 | return result; 21 | } 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /shaders/lib/water/rain_ripples.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_WATER_RIPPLES 2 | #define LIB_WATER_RIPPLES 3 | 4 | #define RAIN_RIPPLE_DETAIL @rain_ripple_detail 5 | 6 | const float RAIN_RIPPLE_GAPS = 10.0; 7 | const float RAIN_RIPPLE_RADIUS = 0.2; 8 | 9 | float scramble(float x, float z) 10 | { 11 | return fract(pow(fract(x)*3.0+1.0, z)); 12 | } 13 | 14 | vec2 randOffset(vec2 c, float time) 15 | { 16 | time = fract(time/1000.0); 17 | c = vec2(c.x * c.y / 8.0 + c.y * 0.3 + c.x * 0.2, 18 | c.x * c.y / 14.0 + c.y * 0.5 + c.x * 0.7); 19 | c.x *= scramble(scramble(time + c.x/1000.0, 4.0), 3.0) + 1.0; 20 | c.y *= scramble(scramble(time + c.y/1000.0, 3.5), 3.0) + 1.0; 21 | return fract(c); 22 | } 23 | 24 | float randPhase(vec2 c) 25 | { 26 | return fract((c.x * c.y) / (c.x + c.y + 0.1)); 27 | } 28 | 29 | float blip(float x) 30 | { 31 | x = max(0.0, 1.0-x*x); 32 | return x*x*x; 33 | } 34 | 35 | float blipDerivative(float x) 36 | { 37 | x = clamp(x, -1.0, 1.0); 38 | float n = x*x-1.0; 39 | return -6.0*x*n*n; 40 | } 41 | 42 | const float RAIN_RING_TIME_OFFSET = 1.0/6.0; 43 | 44 | vec4 circle(vec2 coords, vec2 corner, float adjusted_time) 45 | { 46 | vec2 center = vec2(0.5,0.5) + (0.5 - RAIN_RIPPLE_RADIUS) * (2.0 * randOffset(corner, floor(adjusted_time)) - 1.0); 47 | float phase = fract(adjusted_time); 48 | vec2 toCenter = coords - center; 49 | 50 | float r = RAIN_RIPPLE_RADIUS; 51 | float d = length(toCenter); 52 | float ringfollower = (phase-d/r)/RAIN_RING_TIME_OFFSET-1.0; // -1.0 ~ +1.0 cover the breadth of the ripple's ring 53 | 54 | #if RAIN_RIPPLE_DETAIL > 0 55 | // normal mapped ripples 56 | if(ringfollower < -1.0 || ringfollower > 1.0) 57 | return vec4(0.0); 58 | 59 | if(d > 1.0) // normalize center direction vector, but not for near-center ripples 60 | toCenter /= d; 61 | 62 | float height = blip(ringfollower*2.0+0.5); // brighten up outer edge of ring; for fake specularity 63 | float range_limit = blip(min(0.0, ringfollower)); 64 | float energy = 1.0-phase; 65 | 66 | vec2 normal2d = -toCenter*blipDerivative(ringfollower)*5.0; 67 | vec3 normal = vec3(normal2d, 0.5); 68 | vec4 ret = vec4(normal, height); 69 | ret.xyw *= energy*energy; 70 | // do energy adjustment here rather than later, so that we can use the w component for fake specularity 71 | ret.xyz = normalize(ret.xyz) * energy*range_limit; 72 | ret.z *= range_limit; 73 | return ret; 74 | #else 75 | // ring-only ripples 76 | if(ringfollower < -1.0 || ringfollower > 0.5) 77 | return vec4(0.0); 78 | 79 | float energy = 1.0-phase; 80 | float height = blip(ringfollower*2.0+0.5)*energy*energy; // fake specularity 81 | 82 | return vec4(0.0, 0.0, 0.0, height); 83 | #endif 84 | } 85 | vec4 rain(vec2 uv, float time) 86 | { 87 | uv *= RAIN_RIPPLE_GAPS; 88 | vec2 f_part = fract(uv); 89 | vec2 i_part = floor(uv); 90 | float adjusted_time = time * 1.2 + randPhase(i_part); 91 | #if RAIN_RIPPLE_DETAIL > 0 92 | vec4 a = circle(f_part, i_part, adjusted_time); 93 | vec4 b = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET); 94 | vec4 c = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET*2.0); 95 | vec4 d = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET*3.0); 96 | vec4 ret; 97 | ret.xy = a.xy - b.xy/2.0 + c.xy/4.0 - d.xy/8.0; 98 | // z should always point up 99 | ret.z = a.z + b.z /2.0 + c.z /4.0 + d.z /8.0; 100 | //ret.xyz *= 1.5; 101 | // fake specularity looks weird if we use every single ring, also if the inner rings are too bright 102 | ret.w = (a.w + c.w /8.0)*1.5; 103 | return ret; 104 | #else 105 | return circle(f_part, i_part, adjusted_time) * 1.5; 106 | #endif 107 | } 108 | 109 | vec2 complex_mult(vec2 a, vec2 b) 110 | { 111 | return vec2(a.x*b.x - a.y*b.y, a.x*b.y + a.y*b.x); 112 | } 113 | vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and fake specularity in w 114 | { 115 | return 116 | rain(uv, time) 117 | + rain(complex_mult(uv, vec2(0.4, 0.7)) + vec2(1.2, 3.0),time) 118 | #if RAIN_RIPPLE_DETAIL == 2 119 | + rain(uv * 0.75 + vec2( 3.7,18.9),time) 120 | + rain(uv * 0.9 + vec2( 5.7,30.1),time) 121 | + rain(uv * 1.0 + vec2(10.5 ,5.7),time) 122 | #endif 123 | ; 124 | } 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /shaders/lib/water/ripples.glsl: -------------------------------------------------------------------------------- 1 | #ifndef LIB_WATER_RIPPLES 2 | #define LIB_WATER_RIPPLES 3 | 4 | float getTemporalWaveSizeMultiplier(in float time) 5 | { 6 | return 1.0 + 0.055 * sin(16.0 * time) + 0.065 * sin(12.87645 * time); 7 | } 8 | 9 | vec4 applySprings(in vec4 samplerData, in vec4 n, in vec4 n2) 10 | { 11 | vec4 storage = vec4(0.0, samplerData.r, 0.0, 0.0); 12 | 13 | // Tweak to look most like water, not a physically accurate simulation 14 | const float a = 0.14; 15 | const float udamp = 0.02; 16 | const float vdamp = 0.02; 17 | 18 | // Apply 2d wave equation with dampening 19 | // Continous impulse needed to maintain simulation, otherwise ripples will fade 20 | float nsum = n.x + n.y + n.z + n.w; 21 | storage.r = a * nsum + ((2.0 - udamp - vdamp) - 4.0 * a) * samplerData.r - (1.0 - vdamp) * samplerData.g; 22 | 23 | // Calculate normal and store in blue-alpha channel 24 | storage.ba = 2.0 * (n.xy - n.zw) + 0.5 * (n2.xy - n2.zw); 25 | 26 | return storage; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/config.glsl: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_GLSL 2 | #define CONFIG_GLSL 3 | 4 | // This file contains various configuration parameters for the mod's shaders. 5 | // Ensure that you restart OpenMW after making a change to this file: it will not reload automatically! 6 | 7 | // Here is a list of lighting 'presets' you can try to avoid spending ages tweaking values: 8 | #define CUSTOM 0 // You can use this present to customise things as you like 9 | #define VANILLA 1 // Designed to emulate the feel of vanilla Morrowind 10 | #define ZESTERER 2 // Colorful and intense fantasy lighting 11 | #define MGE_XE 3 // An attempt at emulating the soft lighting of MGE XE 12 | 13 | // IMPORTANT: Change this variable to quickly switch presets 14 | // ,--------. 15 | #define PRESET ZESTERER 16 | // '------- ' 17 | 18 | #if (PRESET == CUSTOM) 19 | // IMPORTANT: For these settings to have an effect, the 'PRESET' variable above must be set to 'CUSTOM' 20 | // 21 | // Change these values to edit your custom preset 22 | // Each value comes with an explanation, and recommended values. 23 | 24 | // Change this to alter the saturation of albedo (i.e: base color). 25 | // Recommended values: 26 | // 0.8 => Very desaturated (looks like Vvardenfell is in the UK) 27 | // 1.0 => Desaturated (close to the original vanilla colors of Morrowind) 28 | // 1.2 => Mildly desaturated (most realistic) 29 | // 1.4 => Bright, fun colours (I prefer this) 30 | // 1.75 => Oversaturated (more Alice in Wonderland than Morrowind) 31 | #define SATURATION_FACTOR 1.2 32 | 33 | // Normal map mods for Morrowind can often be very extreme and may need toning down. 34 | // Note that AI-generated normal maps can often look extremely garish at an intensity of 1.0; consider lowering it 35 | // if you're using such AI-generated normal maps. 36 | // Recommended values: 37 | // 0.0 => Normal maps have no effect 38 | // 0.5 => Less intense (smoother surfaces) 39 | // 1.0 => Default 40 | // 2.0 => Very intense (rougher surfaces) 41 | #define NORMAL_MAP_INTENSITY 1.0 42 | 43 | // The intensity of direct sunlight 44 | // Recommended values: 45 | // 0.4 => Weak, closer to the original game 46 | // 0.7 => Bright, but not overpowering 47 | // 1.0 => Solar flare, take cover! 48 | #define SUNLIGHT_STRENGTH 0.6 49 | 50 | // The intensity of ambient light 51 | // Recommended values: 52 | // 0.3 => Low, like being in space 53 | // 0.5 => Medium, more realistic 54 | // 0.7 => Strong, well-lit shadows 55 | // 1.0 => Shadows? What shadows? 56 | #define AMBIANCE_STRENGTH 0.5 57 | 58 | // The intensity of interior light (applies for buildings and underground spaces) 59 | // Recommended values: 60 | // 0.4 => Low, very dark interiors 61 | // 0.6 => Medium, dingy interiors 62 | // 0.8 => Normal, well-lit interiors 63 | // 1.1 => Bright, very well-lit interiors 64 | #define INTERIOR_STRENGTH 0.8 65 | 66 | // The extent of procedural detailing on distant terrain (increasing this doesn't impact performance) 67 | // Recommended values: 68 | // 0.0 => Disabled entirely (slightly better for performance) 69 | // 0.25 => Very low, almost too subtle to notice 70 | // 0.5 => Medium, nice with vanilla textures 71 | // 0.75 => Moderate, looks better if you have a normal map mod for near terrain too 72 | // 1.0 => Strong, harsh craggs and details 73 | #define PROCEDURAL_DETAIL_LEVEL 0.75 74 | 75 | // The amplitude of wind swaying applied to leaves 76 | // Recommended values: 77 | // 0.0 => Disabled entirely (slightly better for performance) 78 | // 0.2 => Very subtle 79 | // 0.6 => Regular 80 | // 1.0 => Strong 81 | // 2.0 => Hurricane 82 | #define WIND_AMPLITUDE 0.5 83 | 84 | // Whether a wave effect is enabled for terrain near water 85 | // Recommended values: 86 | // 0 => Disabled 87 | // 1 => Enabled 88 | #define WAVES 1 89 | 90 | // The amplitude of waves in world units 91 | // Recommended values: 92 | // 3.0 => Makes ponds look nice and calm 93 | // 6.0 => Makes moderate-to-large bodies of water look good 94 | // 10.0 => Makes oceans look good 95 | #define WAVE_HEIGHT 6.0 96 | 97 | // Whether caustics (refractive light from waves on the water surface) are applied to underwater scenes 98 | // Recommended values: 99 | // 0 => Disabled 100 | // 1 => Enabled 101 | #define CAUSTICS 1 102 | 103 | // Whether tonemapping at the end of the forward pass is eanbled. This will make colour grading look slightly 104 | // better, with the disadvantage that post-processing shaders no longer operate upon linear light values. 105 | // Recommended values: 106 | // 0 => Disabled 107 | // 1 => Enabled 108 | #define FORWARD_TONEMAPPING 1 109 | 110 | // The gamma value used by the forward pass tonemapper, if enabled. 111 | // Recommended values: 112 | // 1.0 => Low contrast 113 | // 1.3 => Medium contrast 114 | // 1.5 => High contrast 115 | #define FORWARD_TONEMAPPING_GAMMA 1.3 116 | 117 | // The exposure value used by the forward pass tonemapper, if enabled. 118 | // Recommended values: 119 | // 1.0 => Dark, dingy lighting 120 | // 1.2 => Well-lit lighting 121 | // 1.4 => Bright, over-exposed lighting 122 | #define FORWARD_TONEMAPPING_EXPOSURE 1.25 123 | 124 | // Whether support for Physically-Based Rendering (PBR) textures is enabled. Even if you don't use PBR texture 125 | // mods, there should be no need to disable this: the shaders will generate reasonable PBR parameters for anything 126 | // that lacks PBR textures. 127 | // Recommended values: 128 | // 0 => Disabled 129 | // 1 => Enabled 130 | #define PBR_TEXTURES 1 131 | 132 | // As-yet undocumented settings. Play with them if you wish! 133 | #define TINT 0.5 134 | #define HUE_SHIFT 0.0 135 | #define BUILTIN_FOG 1 136 | #define POINT_LIGHT_MODERATION 1 137 | #define MAJESTIC_WARP 0 138 | #elif (PRESET == VANILLA) 139 | #define SATURATION_FACTOR 1.0 140 | #define NORMAL_MAP_INTENSITY 0.75 141 | #define SUNLIGHT_STRENGTH 0.4 142 | #define AMBIANCE_STRENGTH 0.55 143 | #define INTERIOR_STRENGTH 0.75 144 | #define PROCEDURAL_DETAIL_LEVEL 0.5 145 | #define WIND_AMPLITUDE 0.2 146 | #define WAVES 1 147 | #define WAVE_HEIGHT 6.0 148 | #define FORWARD_TONEMAPPING 1 149 | #define FORWARD_TONEMAPPING_GAMMA 1.3 150 | #define FORWARD_TONEMAPPING_EXPOSURE 1.25 151 | #define PBR_TEXTURES 1 152 | #define TINT 0.0 153 | #define HUE_SHIFT -0.01 154 | #define CAUSTICS 1 155 | #define BUILTIN_FOG 1 156 | #define POINT_LIGHT_MODERATION 1 157 | #define MAJESTIC_WARP 0 158 | #elif (PRESET == ZESTERER) 159 | #define SATURATION_FACTOR 1.4 160 | #define NORMAL_MAP_INTENSITY 1.25 161 | #define SUNLIGHT_STRENGTH 0.8 162 | #define AMBIANCE_STRENGTH 0.6 163 | #define INTERIOR_STRENGTH 0.5 164 | #define PROCEDURAL_DETAIL_LEVEL 1.0 165 | #define WIND_AMPLITUDE 0.75 166 | #define WAVES 1 167 | #define WAVE_HEIGHT 8.0 168 | #define FORWARD_TONEMAPPING 1 169 | #define FORWARD_TONEMAPPING_GAMMA 1.3 170 | #define FORWARD_TONEMAPPING_EXPOSURE 1.25 171 | #define PBR_TEXTURES 1 172 | #define TINT 1.25 173 | #define HUE_SHIFT -0.02 174 | #define CAUSTICS 1 175 | #define BUILTIN_FOG 1 176 | #define POINT_LIGHT_MODERATION 0 177 | #define MAJESTIC_WARP 0 178 | #elif (PRESET == MGE_XE) 179 | #define SATURATION_FACTOR 1.4 180 | #define NORMAL_MAP_INTENSITY 0.65 181 | #define SUNLIGHT_STRENGTH 0.3 182 | #define AMBIANCE_STRENGTH 0.4 183 | #define INTERIOR_STRENGTH 0.7 184 | #define PROCEDURAL_DETAIL_LEVEL 0.4 185 | #define WIND_AMPLITUDE 0.4 186 | #define WAVES 1 187 | #define WAVE_HEIGHT 8.0 188 | #define FORWARD_TONEMAPPING 1 189 | #define FORWARD_TONEMAPPING_GAMMA 1.3 190 | #define FORWARD_TONEMAPPING_EXPOSURE 1.25 191 | #define PBR_TEXTURES 1 192 | #define TINT 0.5 193 | #define HUE_SHIFT -0.015 194 | #define CAUSTICS 1 195 | #define BUILTIN_FOG 1 196 | #define POINT_LIGHT_MODERATION 1 197 | #define MAJESTIC_WARP 0 198 | #else 199 | #error Selected shader preset does not exist! 200 | #endif 201 | 202 | // Enable this to check that your texture mods are loaded correctly. 203 | // Bands of colour correspond to material properties: 204 | // Red = Normal maps are present 205 | // Yellow = Parallax maps are present 206 | // Purple = Dark maps are present 207 | // Dark green = Bump maps are present 208 | // Orange = Gloss maps are present 209 | // Blue = Specular maps / PBR parameters are present 210 | // Pink = Emissive maps are present 211 | // Lime = Blend maps are present 212 | #define DEBUG_MATERIALS 0 213 | 214 | const float saturation_factor = SATURATION_FACTOR; 215 | const float normal_map_intensity = NORMAL_MAP_INTENSITY; 216 | const float sunlight_strength = SUNLIGHT_STRENGTH; 217 | const float ambiance_strength = AMBIANCE_STRENGTH; 218 | const float interior_strength = INTERIOR_STRENGTH; 219 | const float procedural_detail_level = PROCEDURAL_DETAIL_LEVEL; 220 | 221 | #endif 222 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/pbr.glsl: -------------------------------------------------------------------------------- 1 | #include "lib/light/lighting_util.glsl" 2 | #include "lib/zesterer/config.glsl" 3 | 4 | const vec3 normal_map_scale = vec3(1.0, 1.0, 1.0 / max(normal_map_intensity, 0.01)); 5 | 6 | const float PI = 3.1416; 7 | const float INV_PI = 0.31830; 8 | 9 | float normGgx(float nDotH, float k) { 10 | float denom = mix(1.0, k, nDotH * nDotH); 11 | return k / (PI * denom * denom); 12 | } 13 | 14 | float geomSchlick(float nDotV, float k) { 15 | return nDotV / mix(k, 1.0, nDotV); 16 | } 17 | 18 | float fresnelSchlick(float hDotV, float baseRefl) { 19 | // Faster form of pow(1.0 - hDotV, 4) 20 | float revHDotV = 1.0 - hDotV; 21 | revHDotV *= revHDotV; 22 | return mix(baseRefl, 1.0, revHDotV * revHDotV); 23 | } 24 | 25 | const float MAT_DEFAULT = 0.0; 26 | const float MAT_LEAF = 1.0; 27 | 28 | vec3 getLightPbr( 29 | vec3 surfPos, 30 | vec3 surfNorm, 31 | vec3 camDir, 32 | // Normalized 33 | vec3 lightDir, 34 | // ~ 1 / distance^2 35 | vec3 lightColor, 36 | vec3 albedo, 37 | float roughness, 38 | float baseRefl, 39 | float metalness, 40 | // 1 if in light, 0 if not in light 41 | float isShadow, 42 | float shadowFadeStart, 43 | float subsurface, 44 | float ao, 45 | float mat 46 | ) { 47 | vec3 viewDir = -camDir; 48 | 49 | vec3 halfVec = normalize(lightDir + viewDir); 50 | 51 | if (mat > 0.0) { 52 | surfNorm = viewDir; 53 | } 54 | 55 | float nDotV = max(dot(surfNorm, viewDir), 0.0); 56 | float nDotL = max(dot(surfNorm, lightDir), 0.0); 57 | 58 | float nDotH = max(dot(surfNorm, halfVec), 0.0); 59 | float hDotV = max(dot(halfVec, viewDir), 0.0); 60 | float glare = dot(-lightDir, viewDir); 61 | 62 | float k = roughness * roughness; 63 | vec3 radiance = lightColor; 64 | // How well-aligned the surface is with the incoming light 65 | float lambert = nDotL; 66 | 67 | // Normal Distribution Function (proportion of microfacets aligned with the half vector) 68 | float ndf = normGgx(nDotH, k); 69 | // Geometry Function (proportion of microfacets not self-shadowed by the surface) 70 | float gf = geomSchlick(nDotV, k) * geomSchlick(nDotL, k); 71 | // Fresnel term (how close we are to a 'grazing' light ray, which approaches perfect reflection) 72 | float f = fresnelSchlick(hDotV, baseRefl); 73 | // Cook-Torrance BRDF, combination of above factors 74 | float specular = ndf * gf / (4.0 * nDotL * nDotV + 0.0001); 75 | 76 | // Rough surfaces are more diffuse 77 | float kDiff = roughness; 78 | // Any light not reflected not diffused by the surface gets reflected specularly 79 | float kSpec = 1.0 - kDiff; 80 | // Metals don't emit light diffusely 81 | kDiff *= 1.0 - metalness; 82 | 83 | // Color of specular reflections is determined by metalness and surface alignment and angle of incidence 84 | const vec3 specular_albedo = vec3(1.0);//mix(vec3(1.0), albedo, metalness); 85 | 86 | // The final diffuse and specular reflectance of the surface 87 | vec3 brdf = kDiff * albedo * INV_PI + kSpec * specular * specular_albedo; 88 | 89 | // Some surfaces scatter light internally. This models that effect, but non-physically 90 | float max_scatter_dist_inv = 1.0 / shadowFadeStart; 91 | float scatter_factor = max(1.0 - length(surfPos) * max_scatter_dist_inv, 0.0); 92 | vec3 subsurfaceScatter = ((subsurface == 0.0) ? 0.0 : (ao * isShadow * subsurface * pow(max(glare, 0.0), 4.0) * 0.1 * scatter_factor)) * albedo; 93 | 94 | // How occluded is the light by other shadow casters (isShadow), the object itself (ao), or the surface angle? 95 | float occlusion = isShadow * ao; 96 | 97 | vec3 solidLight = brdf * occlusion; 98 | vec3 leafLight = mix(solidLight * 0.3, 0.2 * ao * isShadow * albedo, scatter_factor); // Non-physical 99 | 100 | // Combine reflected light and sub-surface scattering together with the incoming radiance to find the final light 101 | // reflected/emitted 102 | return radiance * (mix(solidLight * lambert, leafLight, mat) + subsurfaceScatter); 103 | } 104 | 105 | vec3 getSunColor(float sunLightLevel, in float isntDusk, in float isInterior) { 106 | const vec3 interiorSunColor = vec3(1.7, 1.6, 1.5); 107 | return (isInterior > 0.5) ? (interiorSunColor * interior_strength) : (mix( 108 | mix( 109 | vec3(0.25, 0.65, 1.0) * 1.65, 110 | // TODO: Actually detect time of day and make dawn/dusk more red 111 | vec3(6.0, 5.0, 0.5), 112 | clamp(sunLightLevel * 10.0 - 3.0, 0.0, 1.0) 113 | ), 114 | vec3(7.0 + TINT, 7.0, 7.0 - TINT), 115 | isntDusk 116 | ) * lcalcDiffuse(0) * sunlight_strength); 117 | } 118 | 119 | vec3 getAmbientColor(in float isntDusk, in float isInterior) { 120 | const vec3 interiorAmbientColor = vec3(0.4, 0.35, 0.2); 121 | return (isInterior > 0.5) ? (interiorAmbientColor * interior_strength) : (mix( 122 | vec3(0.15, 0.2, 0.4), 123 | vec3(1.5 - TINT * 0.3, 1.5, 1.5 + TINT * 0.3), 124 | isntDusk 125 | ) * mix(lcalcDiffuse(0), vec3(1.0), 0.5) * ambiance_strength); 126 | } 127 | 128 | vec3 getPbr( 129 | mat4 osg_ViewMatrixInverse, 130 | vec3 surfPos, 131 | vec3 surfNorm, 132 | // Base reflectance of the material 133 | vec3 albedo, 134 | // Rate of perfect vs diffuse reflection 135 | float roughness, 136 | // Proportion of light that is reflected from the surface 137 | float baseRefl, 138 | float metalness, 139 | // From shadow map, for sun 140 | float sunShadow, 141 | float shadowFadeStart, 142 | // Reduction in reflected light due to occlusion 143 | float ao, 144 | // Diffuse emission 145 | vec3 emission, 146 | // Sub-surface scattering factor 147 | float subsurface, 148 | // Distance from water surface 149 | float waterDepth, 150 | // Leafiness?! 151 | float mat 152 | ) { 153 | vec3 camDir = normalize(surfPos); 154 | 155 | vec3 light = vec3(0.0); 156 | 157 | // Emissive light, eminating from the object itself (non-physical) 158 | light += emission * 3.0 * max(dot(surfNorm, -camDir), 0.5); 159 | 160 | vec3 sunPos = lcalcPosition(0); 161 | vec3 sunDir = normalize(sunPos); 162 | float sunLightLevel = lcalcDiffuse(0).r; 163 | // If this seems silly, that's because it is. We use this to approximate how close we are to dusk 164 | // pow(sunLightLevel, 4) 165 | vec3 sunWDir = (osg_ViewMatrixInverse * vec4(sunDir, 0.0)).xyz; 166 | float isntDusk = clamp(lcalcDiffuse(0).r * 2.0 - 0.25, 0.0, 1.0); 167 | 168 | // Extremely silly hack to determine whether we're indoors or not 169 | float isInterior = step(0.0, sunWDir.y);//step(0.9, dot(sunWDir, vec3(0.0, 0.0, 1.0))) * step(lcalcDiffuse(0).b, 0.2); 170 | 171 | // Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths. 172 | // See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water 173 | const vec3 MU_WATER = vec3(0.6, 0.04, 0.01); 174 | const float unitsToMetres = 0.014; 175 | // Light attenuation in water 176 | vec3 attenuation = (waterDepth == 0.0 || isInterior > 0.5) ? vec3(1.0) : exp(-MU_WATER * waterDepth * unitsToMetres); 177 | 178 | // Direct sunlight 179 | vec3 sunColor = getSunColor(sunLightLevel, isntDusk, isInterior) * attenuation; 180 | light += getLightPbr(surfPos, surfNorm, camDir, sunDir, sunColor, albedo, roughness, baseRefl, metalness, sunShadow, shadowFadeStart, subsurface, ao, mat); 181 | 182 | // Sky (ambient) 183 | // TODO: Better ambiance 184 | float ambientFresnel = mix(max(dot(surfNorm, -camDir), 0.0) * 0.5 + 0.5, 1.0, subsurface); 185 | vec3 skyColor = getAmbientColor(isntDusk, isInterior) /* * lcalcAmbient(0)*/ * attenuation; 186 | // Even ambient light has some directionality, favouring surfaces facing toward the sky. Account for that. 187 | float ambientDirectionalBias = (max(dot((osg_ViewMatrixInverse * vec4(surfNorm, 0.0)).xyz, vec3(0.0, 0.0, 1.0)), 0.0) * 0.5 + 0.5) * 1.5; 188 | light += albedo * ao * baseRefl * skyColor * ambientFresnel * ambientDirectionalBias; 189 | 190 | vec3 point_light = vec3(0.0); 191 | for (int i = @startLight; i < @endLight; ++i) { 192 | int lightIdx = 193 | #if @lightingMethodUBO 194 | PointLightIndex[i] 195 | #else 196 | i 197 | #endif 198 | ; 199 | 200 | vec3 lightDelta = lcalcPosition(lightIdx) - surfPos; 201 | float lightMaxRadius = lcalcRadius(lightIdx) * 3.0; 202 | float lightDist = length(lightDelta) * 0.75; 203 | 204 | // Skip this light if it's too far away 205 | if (lightDist > lightMaxRadius) { continue; } 206 | 207 | vec3 lightDir = lightDelta / lightDist; 208 | 209 | vec3 lightColor = lcalcDiffuse(lightIdx) 210 | // The strength of a light reduces with distance 211 | * lcalcIllumination(lightIdx, lightDist) * 9.0 212 | // Make lights less powerful during the day (otherwise, they're a bit overpowering) 213 | * max(1.0 - sunLightLevel, 0.5) 214 | // Final cap to make sure that lights don't abruptly cut off beyond the maximum light distance 215 | * min((1.0 - lightDist / lightMaxRadius) * 3.0, 1.0); 216 | 217 | point_light += getLightPbr(surfPos, surfNorm, camDir, lightDir, lightColor, albedo, roughness, baseRefl, metalness, 1.0, 1.0, subsurface, ao, mat); 218 | 219 | // Ambiance from the point light 220 | point_light += albedo * ao * baseRefl * lightColor * 0.05; 221 | } 222 | #if (POINT_LIGHT_MODERATION == 1) 223 | light += point_light / (1.0 + length(point_light) * 0.35); 224 | #else 225 | light += point_light; 226 | #endif 227 | 228 | // Experimental water silt 229 | //vec3 wDir = (osg_ViewMatrixInverse * vec4(camDir, 0.0)).xyz; 230 | //light = mix(vec3(0.3, 0.2, 0.05), light, 1.0 / exp(waterDepth * 0.02 / abs(wDir.z))); 231 | 232 | return light; 233 | } 234 | 235 | vec3 rgb2hsv(vec3 c) 236 | { 237 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 238 | vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); 239 | vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); 240 | 241 | float d = q.x - min(q.w, q.y); 242 | float e = 1.0e-10; 243 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); 244 | } 245 | 246 | vec3 hsv2rgb(vec3 c) 247 | { 248 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 249 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); 250 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); 251 | } 252 | 253 | void untonemap(inout vec3 color) { 254 | const float k = 1.5; 255 | color = -log2(1.0 - color); 256 | color = vec3(1.0) - exp2(color * -k); 257 | } 258 | 259 | vec3 srgb_to_linear(vec3 srgb) { 260 | vec3 cutoff = step(vec3(0.04045), -srgb); 261 | vec3 higher = pow((srgb + vec3(0.055))/vec3(1.055), vec3(2.4)); 262 | vec3 lower = srgb/vec3(12.92); 263 | 264 | return mix(higher, lower, cutoff); 265 | } 266 | 267 | // We need to derive PBR inputs from Morrowind's extremely ad-hoc, non-PBR textures. 268 | // As a result, this entire thing is an enormous hack that lets us do that! 269 | void colorToPbr(vec3 color, out vec3 albedo, out float ao) { 270 | untonemap(color); 271 | //color = srgb_to_linear(color); 272 | 273 | vec3 hsv = rgb2hsv(color); 274 | 275 | ao = hsv.z * 1.2; 276 | albedo = hsv2rgb(vec3(hsv.x + HUE_SHIFT, hsv.y * saturation_factor, 1.0)); 277 | 278 | /* 279 | ao = min(length(color) * 0.58, 1.0); 280 | float saturation = mix(1.0, saturation_factor, ao); 281 | albedo = clamp(pow(normalize(color), vec3(saturation)) * mix(saturation, 1.5, 0.5) - 0.25, vec3(0.0), vec3(1.0)); 282 | */ 283 | } 284 | 285 | // Derive PBR parameters from coloured specular, if possible. If not, old values will be used. 286 | void matSpecToPbr( 287 | in vec4 specMat, 288 | in float leafiness, 289 | inout float roughness, 290 | inout float metalness, 291 | inout float reflectance, 292 | inout float shininess 293 | ) { 294 | #if (PBR_TEXTURES == 1) 295 | metalness = specMat.x; 296 | roughness = mix(0.9, 0.025, specMat.y); 297 | shininess = mix(min(0.5 + sqrt(specMat.z), 1.0), 1.0, leafiness); 298 | //ao = specMat.a; 299 | #else 300 | // The only thing we can do is to look at the magnitude of the specular element and use that as 1 - roughness 301 | metalness = mix(0.0, 0.75, clamp(length(specMat.rgb) * 5.0, 0.0, 1.0)); 302 | roughness = 0.9 / (1.0 + sqrt(shininess) * 0.25 + metalness * 0.5); 303 | #endif 304 | } 305 | 306 | void tonemap(inout vec3 color) { 307 | #if (FORWARD_TONEMAPPING == 1) 308 | const float gamma = FORWARD_TONEMAPPING_GAMMA; 309 | const float exposure = FORWARD_TONEMAPPING_EXPOSURE; 310 | color = pow(vec3(1.0) - exp(-color * exposure), vec3(gamma)); 311 | #endif 312 | } 313 | 314 | void debug_materials(inout vec3 color) { 315 | #if (DEBUG_MATERIALS == 1) 316 | #ifdef NORMAL_MAP 317 | if (abs(fract(passViewPos.x * 0.02) - 0.0 - 0.05) < 0.05) color = mix(color, vec3(1.0, 0.0, 0.0), vec3(0.5)); 318 | #endif 319 | #ifdef PARALLAX 320 | if (abs(fract(passViewPos.x * 0.02) - 0.1 - 0.05) < 0.05) color = mix(color, vec3(1.0, 1.0, 0.0), vec3(0.5)); 321 | #endif 322 | #ifdef DARK_MAP 323 | if (abs(fract(passViewPos.x * 0.02) - 0.2 - 0.05) < 0.05) color = mix(color, vec3(0.7, 0.0, 1.0), vec3(0.5)); 324 | #endif 325 | #ifdef BUMP_MAP 326 | if (abs(fract(passViewPos.x * 0.02) - 0.3 - 0.05) < 0.05) color = mix(color, vec3(0.0, 0.7, 0.2), vec3(0.5)); 327 | #endif 328 | #ifdef GLOSS_MAP 329 | if (abs(fract(passViewPos.x * 0.02) - 0.4 - 0.05) < 0.05) color = mix(color, vec3(1.0, 0.6, 0.0), vec3(0.5)); 330 | #endif 331 | #ifdef SPECULAR_MAP 332 | if (abs(fract(passViewPos.x * 0.02) - 0.5 - 0.05) < 0.05) color = mix(color, vec3(0.0, 0.4, 1.0), vec3(0.5)); 333 | #endif 334 | #ifdef EMISSIVE_MAP 335 | if (abs(fract(passViewPos.x * 0.02) - 0.6 - 0.05) < 0.05) color = mix(color, vec3(1.0, 0.0, 0.3), vec3(0.5)); 336 | #endif 337 | #ifdef BLEND_MAP 338 | if (abs(fract(passViewPos.x * 0.02) - 0.7 - 0.05) < 0.05) color = mix(color, vec3(0.5, 1.0, 0.0), vec3(0.5)); 339 | #endif 340 | #endif 341 | } 342 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/rand.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RAND_GLSL 2 | #define RAND_GLSL 3 | 4 | #include "lib/zesterer/config.glsl" 5 | 6 | float rand(float n){return fract(sin(n) * 43758.5453123);} 7 | 8 | float rand(vec2 n) { 9 | return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); 10 | } 11 | 12 | 13 | float noise(float p){ 14 | float fl = floor(p); 15 | float fc = fract(p); 16 | return mix(rand(fl), rand(fl + 1.0), fc); 17 | } 18 | 19 | float noise(vec2 n) { 20 | const vec2 d = vec2(0.0, 1.0); 21 | vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n)); 22 | return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y); 23 | } 24 | 25 | 26 | 27 | float hash(vec2 p) {return fract(sin(p.x * 1e2 + p.y) * 1e5 + sin(p.y * 1e3) * 1e3 + sin(p.x * 735. + p.y * 11.1) * 1.5e2); } 28 | 29 | // GLSL smootherstep [smthrstp] from http://graphicscodex.com for reference 30 | float smootherstep(float start, float end, float t) { 31 | t = max(0.0, min(1.0, (t - start) / (end - start))); 32 | return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); 33 | } 34 | 35 | 36 | // Returns three values on [-1, +1]: 37 | // vec3(d noise(x,y) / dx, d noise(x, y) / dy, noise(x,y)); 38 | // 39 | // This noise function can be combined in octaves to produce derivatives at multiple 40 | // scales as well. 41 | vec3 noised(vec2 x) { 42 | vec2 p = floor(x); 43 | vec2 f = fract(x); 44 | 45 | // Four corners in 2D of a tile 46 | float a = hash(p); 47 | float b = hash(p + vec2(1.0, 0.0)); 48 | float c = hash(p + vec2(0.0, 1.0)); 49 | float d = hash(p + vec2(1.0, 1.0)); 50 | 51 | // Simple 2D lerp using smoothstep envelope between the values. This is the underlying 52 | // "noise" function that is being differentiated. 53 | // 54 | // return vec3(mix( 55 | // mix(a, b, smootherstep(0.0, 1.0, f.x)), 56 | // mix(c, d, smootherstep(0.0, 1.0, f.x)), 57 | // smootherstep(0.0, 1.0, f.y))); 58 | 59 | // Inigo's version with the derivatives, expanded and refactored. This stores the bilinear 60 | // [smoothstep weighted] interpolated value noise in z and the derivatives in x and y. 61 | 62 | // Definition of smootherstep on a unit interval, applied in two dimensions simultaneously. 63 | vec2 v = f * f * f * (f * (f * 6.0 - 15.0) + 10.0); 64 | 65 | float noiseValue = 66 | // Inigo's smoothstep approximation of smootherstep, which is slightly blurrier and 67 | // less expensive, but doesn't match the function being differentiated below: 68 | // mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y; 69 | 70 | // Full smootherstep version: 71 | mix(mix(a, b, v.x), mix(c, d, v.x), v.y); 72 | 73 | // Definition of smoothstep, which appears as a common subexpression below in the derivative terms. 74 | vec2 u = f * f * (3.0 - 2.0 * f); 75 | return vec3((30.0 * f * f * (f * (f - 2.0) + 1.0)) * 76 | (vec2(b, c) + (a - b - c + d) * u.yx - a), 77 | noiseValue); 78 | } 79 | 80 | vec3 proceduralNoise(vec3 wPos, float dist) { 81 | const float avg_scale = 0.001; 82 | const float fade = 1.0 / 5000.0; 83 | 84 | vec2 level_scales = max(vec2(floor(dist * avg_scale), ceil(dist * avg_scale)) / vec2(avg_scale), vec2(0.00001)); 85 | float merge = fract(dist * avg_scale); 86 | return mix( 87 | noised(wPos.xy * 600.0 / level_scales.x), 88 | noised(wPos.xy * 600.0 / level_scales.y), 89 | vec3(merge) 90 | ); 91 | } 92 | 93 | void proceduralNormal(vec3 wPos, float dist, inout vec3 normal) { 94 | const float fade = 1.0 / 5000.0; 95 | const float min_dist = 5000.0; 96 | 97 | vec3 nz = proceduralNoise(wPos, dist) * clamp((dist - min_dist) * fade, 0.0, 1.0); 98 | 99 | float level = dot(normal, vec3(0.0, 0.0, 1.0)); 100 | normal = normalize(normal + nz * procedural_detail_level * level * level * level); 101 | } 102 | 103 | void proceduralUV(vec3 wPos, float dist, inout vec2 uv) { 104 | const float fade = 1.0 / 20000.0; 105 | const float min_dist = 5000.0; 106 | 107 | /* 108 | vec3 nz = proceduralNoise(wPos, dist * 10.0) * clamp((dist - min_dist) * fade, 0.0, 1.0); 109 | 110 | uv += nz.xy * sqrt(dist) * 0.0001; 111 | */ 112 | 113 | uv += vec2( 114 | noise(wPos.xy * 0.004), 115 | noise(wPos.xy * 0.004 + 0.5) 116 | ) 117 | * 0.03 118 | * min((1.0 - abs(uv - 0.5) * 2.0) * 25.0, vec2(1.0)) 119 | * clamp((dist - min_dist) * fade, 0.0, 1.0); 120 | } 121 | 122 | /* 123 | // from http://www.java-gaming.org/index.php?topic=35123.0 124 | vec4 cubic(float v){ 125 | vec4 n = vec4(1.0, 2.0, 3.0, 4.0) - v; 126 | vec4 s = n * n * n; 127 | float x = s.x; 128 | float y = s.y - 4.0 * s.x; 129 | float z = s.z - 4.0 * s.y + 6.0 * s.x; 130 | float w = 6.0 - x - y - z; 131 | return vec4(x, y, z, w) * (1.0/6.0); 132 | } 133 | 134 | vec4 textureBicubic(sampler2D sampler, vec2 texCoords){ 135 | 136 | vec2 texSize = textureSize(sampler, 0) / 16.0; 137 | vec2 invTexSize = 1.0 / texSize; 138 | 139 | texCoords = texCoords * texSize - 0.5; 140 | 141 | 142 | vec2 fxy = fract(texCoords); 143 | texCoords -= fxy; 144 | 145 | vec4 xcubic = cubic(fxy.x); 146 | vec4 ycubic = cubic(fxy.y); 147 | 148 | vec4 c = texCoords.xxyy + vec2 (-0.5, +1.5).xyxy; 149 | 150 | vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw); 151 | vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s; 152 | 153 | offset *= invTexSize.xxyy; 154 | 155 | vec4 sample0 = texture(sampler, offset.xz); 156 | vec4 sample1 = texture(sampler, offset.yz); 157 | vec4 sample2 = texture(sampler, offset.xw); 158 | vec4 sample3 = texture(sampler, offset.yw); 159 | 160 | float sx = s.x / (s.x + s.y); 161 | float sy = s.z / (s.z + s.w); 162 | 163 | return mix( 164 | mix(sample3, sample2, sx), mix(sample1, sample0, sx) 165 | , sy); 166 | } 167 | */ 168 | 169 | float n12(vec2 p) 170 | { 171 | vec2 i = floor(p); 172 | vec2 f = fract(p); 173 | f *= f * (3.-2.*f); 174 | return mix( 175 | mix(hash(i+vec2(0.,0.)),hash(i+vec2(1.,0.)),f.x), 176 | mix(hash(i+vec2(0.,1.)),hash(i+vec2(1.,1.)),f.x), 177 | f.y 178 | ); 179 | } 180 | 181 | float caustics(vec2 p, float t) 182 | { 183 | vec3 k = vec3(p,t); 184 | float l; 185 | mat3 m = mat3(-2.,-1.,2.,3.,-2.,1.,1.,2.,2.); 186 | float n = n12(p); 187 | k = k*m*.5; 188 | l = length(.5 - fract(k+n)); 189 | k = k*m*.4; 190 | l = min(l, length(.5-fract(k+n))); 191 | k = k*m*.3; 192 | l = min(l, length(.5-fract(k+n))); 193 | return pow(l,4.)*5.5; 194 | } 195 | 196 | #endif 197 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/sway.glsl: -------------------------------------------------------------------------------- 1 | #include "lib/zesterer/config.glsl" 2 | 3 | uniform float osg_SimulationTime; 4 | 5 | #include "lib/light/lighting_util.glsl" 6 | 7 | void doSway(sampler2D diffuseMap, vec2 diffuseMapUV, inout vec3 modelPos, inout float leafiness) { 8 | if (texture2D(diffuseMap, diffuseMapUV).a < 0.2 9 | && dot(gl_FrontMaterial.emission.rgb, vec3(1.0)) == 0.0 10 | //&& abs(abs(gl_Normal.z) - 0.5) < 0.4 11 | // Only enable swaying in exteriors, for now 12 | && step(0.0, (osg_ViewMatrixInverse * vec4(lcalcPosition(0), 0.0)).y) == 0.0 13 | ) { 14 | if (WIND_AMPLITUDE > 0.0) { 15 | modelPos.xyz += sin(osg_SimulationTime * (WIND_AMPLITUDE + 1.0) * 1.5 + modelPos.yzx * 0.01) 16 | * 0.01 17 | * WIND_AMPLITUDE 18 | * modelPos.z 19 | ; 20 | } 21 | leafiness = 1.0; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/warp.glsl: -------------------------------------------------------------------------------- 1 | #include "lib/zesterer/config.glsl" 2 | 3 | uniform mat4 osg_ViewMatrix; 4 | uniform mat4 osg_ViewMatrixInverse; 5 | 6 | vec4 warp_position(vec3 viewPos) { 7 | #if (MAJESTIC_WARP == 1) 8 | vec3 cam_wPos = (osg_ViewMatrixInverse * vec4(vec3(0), 1)).xyz; 9 | vec3 wPos = (osg_ViewMatrixInverse * vec4(viewPos.xyz, 1)).xyz; 10 | 11 | //vec3 new_wPos = wPos + vec3(0, 0, wPos.z - cam_wPos.z + 500.0) * min(distance(cam_wPos.xy, wPos.xy), 100000.0) * 0.00002; 12 | //vec3 new_wPos = wPos + vec3(0, 0, pow(max(abs(wPos.z - cam_wPos.z) - 0.0, 0.0), 1.5) * 0.01 * sign(wPos.z - cam_wPos.z)); 13 | float water_z = abs(cam_wPos.z) * -sign(cam_wPos.z); 14 | float new_z = water_z * 0 + wPos.z * (1.0 + min(distance(cam_wPos.xy, wPos.xy), 100000.0) * 0.00002); 15 | vec3 new_wPos = vec3(wPos.xy, new_z); 16 | return viewToClip(osg_ViewMatrix * vec4(new_wPos, 1)); 17 | #else 18 | return viewToClip(vec4(viewPos, 1)); 19 | #endif 20 | } 21 | -------------------------------------------------------------------------------- /shaders/lib/zesterer/water_nm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zesterer/openmw-shaders/93cb05448e3acc0f67710ab4af5cb3688acc86ac/shaders/lib/zesterer/water_nm.png -------------------------------------------------------------------------------- /shaders/lib/zesterer/wave.glsl: -------------------------------------------------------------------------------- 1 | #include "lib/zesterer/config.glsl" 2 | #include "lib/zesterer/rand.glsl" 3 | 4 | uniform float osg_SimulationTime; 5 | 6 | float doWave(vec2 pos, float time_off, float fizzle, float part) { 7 | #if (WAVES == 1) 8 | float nz = noise(pos.xy * 0.3) * 2.0 - 1.0; 9 | return mix(sin((osg_SimulationTime + time_off - nz * fizzle) * 1.0 + dot(sin(pos * 0.01 + osg_SimulationTime * 0.3), vec2(1.0)) * 1.0), 1.0, part) * WAVE_HEIGHT + nz * 1.0; 10 | #else 11 | return 0.0; 12 | #endif 13 | } 14 | 15 | float doWave(vec2 pos) { 16 | return doWave(pos, 0.0, 1.0, 0.0); 17 | } 18 | --------------------------------------------------------------------------------