/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2018 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #ifndef TEXTURETILEMAPPING_HGLSL #define TEXTURETILEMAPPING_HGLSL #include <${MODULE_GLOBEBROWSING}/shaders/tile.hglsl> #include <${MODULE_GLOBEBROWSING}/shaders/blending.hglsl> // First layer type from LayerShaderManager is height map #define NUMLAYERS_HEIGHTMAP #{lastLayerIndexHeightLayers} + 1 #define USE_HEIGHTMAP #{useHeightLayers} #define HEIGHTMAP_BLENDING_ENABLED #{blendHeightLayers} // Second layer type from LayerShaderManager is color texture #define NUMLAYERS_COLORTEXTURE #{lastLayerIndexColorLayers} + 1 #define USE_COLORTEXTURE #{useColorLayers} #define COLORTEXTURE_BLENDING_ENABLED #{blendColorLayers} // Third layer type from LayerShaderManager is water mask #define NUMLAYERS_WATERMASK #{lastLayerIndexWaterMasks} + 1 #define USE_WATERMASK #{useWaterMasks} #define WATERMASK_BLENDING_ENABLED #{blendWaterMasks} // Fourth layer type from LayerShaderManager is night texture #define NUMLAYERS_NIGHTTEXTURE #{lastLayerIndexNightLayers} + 1 #define USE_NIGHTTEXTURE #{useNightLayers} #define NIGHTTEXTURE_BLENDING_ENABLED #{blendNightLayers} // Fifth layer type from LayerShaderManager is overlay #define NUMLAYERS_OVERLAY #{lastLayerIndexOverlays} + 1 #define USE_OVERLAY #{useOverlays} #define OVERLAY_BLENDING_ENABLED #{blendOverlays} // Global constants #define CHUNK_DEFAULT_HEIGHT #{defaultHeight} // Other key value pairs used for settings #define USE_ACCURATE_NORMALS #{useAccurateNormals} #define PERFORM_SHADING #{performShading} #define USE_ECLIPSE_SHADOWS #{useEclipseShadows} #define USE_ECLIPSE_HARD_SHADOWS #{useEclipseHardShadows} #define SHOW_CHUNK_EDGES #{showChunkEdges} #define SHOW_HEIGHT_RESOLUTION #{showHeightResolution} #define SHOW_HEIGHT_INTENSITIES #{showHeightIntensities} const vec3 DefaultLevelWeights = vec3(1.0, 0.0, 0.0); float orenNayarDiffuse(vec3 lightDirection, vec3 viewDirection, vec3 surfaceNormal, float roughness) { // calculate intermediary values float NdotL = dot(surfaceNormal, lightDirection); float NdotV = dot(surfaceNormal, viewDirection); float angleVN = acos(NdotV); float angleLN = acos(NdotL); float alpha = max(angleVN, angleLN); float beta = min(angleVN, angleLN); float gamma = dot( viewDirection - surfaceNormal * dot(viewDirection, surfaceNormal), lightDirection - surfaceNormal * dot(lightDirection, surfaceNormal) ); float roughnessSquared = roughness * roughness; // calculate A and B float A = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.57)); float B = 0.45 * (roughnessSquared / (roughnessSquared + 0.09)); float C = sin(alpha) * tan(beta); // put it all together return max(0.0, NdotL) * (A + B * max(0.0, gamma) * C); } float performLayerSettings(float currentValue, LayerSettings settings) { float v = sign(currentValue) * pow(abs(currentValue), settings.gamma) * settings.multiplier + settings.offset; return v * settings.opacity; } vec4 performLayerSettings(vec4 currentValue, LayerSettings settings) { vec3 newValue = sign(currentValue.rgb) * pow(abs(currentValue.rgb), vec3(settings.gamma)) * settings.multiplier + settings.offset; return vec4(newValue, currentValue.a * settings.opacity); } vec2 tileUVToTextureSamplePosition(ChunkTile chunkTile, vec2 tileUV, PixelPadding padding) { vec2 uv = chunkTile.uvTransform.uvOffset + chunkTile.uvTransform.uvScale * tileUV; // compensateSourceTextureSampling ivec2 resolution = textureSize(chunkTile.textureSampler, 0); vec2 sourceSize = vec2(resolution) + padding.sizeDifference; vec2 currentSize = vec2(resolution); vec2 sourceToCurrentSize = currentSize / sourceSize; return sourceToCurrentSize * (uv - padding.startOffset / sourceSize); } vec4 getTexVal(ChunkTilePile chunkTilePile, vec3 w, vec2 uv, PixelPadding padding) { vec4 v1 = texture( chunkTilePile.chunkTile0.textureSampler, tileUVToTextureSamplePosition(chunkTilePile.chunkTile0, uv, padding) ); vec4 v2 = texture( chunkTilePile.chunkTile1.textureSampler, tileUVToTextureSamplePosition(chunkTilePile.chunkTile1, uv, padding) ); vec4 v3 = texture( chunkTilePile.chunkTile2.textureSampler, tileUVToTextureSamplePosition(chunkTilePile.chunkTile2, uv, padding) ); return w.x * v1 + w.y * v2 + w.z * v3; } #for id, layerGroup in layerGroups #for i in 0..#{lastLayerIndex#{layerGroup}} vec4 getSample#{layerGroup}#{i}(vec2 uv, vec3 levelWeights, Layer #{layerGroup}[#{lastLayerIndex#{layerGroup}} + 1]) { vec4 color = vec4(0.0, 0.0, 0.0, 1.0); // All tile layers are the same. Sample from texture #if (#{#{layerGroup}#{i}LayerType} == 0) // DefaultTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 1) // SingleImageTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 2) // SizeReferenceTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 3) // TemporalTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 4) // TileIndexTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 5) // ByIndexTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 6) // ByLevelTileLayer color = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 7) // SolidColor color.rgb = #{layerGroup}[#{i}].color; #endif return color; } #endfor #endfor #for id, layerGroup in layerGroups #for i in 0..#{lastLayerIndex#{layerGroup}} vec4 blend#{layerGroup}#{i}(vec4 currentColor, vec4 newColor, float blendFactor) { #if (#{#{layerGroup}#{i}BlendMode} == 0) // Default, Normal return blendNormal(currentColor, vec4(newColor.rgb, newColor.a * blendFactor)); #elif (#{#{layerGroup}#{i}BlendMode} == 1) // Multiply return blendMultiply(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 2) // Add return blendAdd(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 3) // Subtract return blendSubtract(currentColor, newColor * blendFactor); #elif (#{#{layerGroup}#{i}BlendMode} == 4) // Color // Convert color to grayscale float gray = (newColor.r + newColor.g + newColor.b) / 3.0; vec3 hsvCurrent = rgb2hsv(currentColor.rgb); // Use gray from new color as value in hsv vec3 hsvNew = vec3(hsvCurrent.x, hsvCurrent.y, gray); vec3 rgbNew = hsv2rgb(hsvNew); vec4 color = blendNormal(currentColor, vec4(rgbNew, newColor.a * blendFactor)); return color; #endif } #endfor #endfor #for id, layerGroup in layerGroups #for i in 0..#{lastLayerIndex#{layerGroup}} vec4 performAdjustment#{layerGroup}#{i}(vec4 currentColor, LayerAdjustment adjustment) { #if (#{#{layerGroup}#{i}LayerAdjustmentType} == 0) // Default, None return currentColor; #elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 1) // ChromaKey if (distance( currentColor.rgb, adjustment.chromaKeyColor ) <= adjustment.chromaKeyTolerance) { return vec4(0.0); } else { return currentColor; } #elif (#{#{layerGroup}#{i}LayerAdjustmentType} == 2) // TransferFunction return currentColor; #else return currentColor; #endif } #endfor #endfor float calculateUntransformedHeight(vec2 uv, vec3 levelWeights, Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { float height = 0; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // HEIGHTMAP_BLENDING_ENABLED #for i in 0..#{lastLayerIndexHeightLayers} { vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); height = colorSample.r; height = performLayerSettings(height, HeightLayers[#{i}].settings); } #endfor return height; } float calculateHeight(vec2 uv, vec3 levelWeights, Layer HeightLayers[NUMLAYERS_HEIGHTMAP]) { float height = 0; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !HEIGHTMAP_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // HEIGHTMAP_BLENDING_ENABLED #for i in 0..#{lastLayerIndexHeightLayers} { vec4 colorSample = getSampleHeightLayers#{i}(uv, levelWeights, HeightLayers); colorSample = performAdjustmentHeightLayers#{i}(colorSample, HeightLayers[#{i}].adjustment); float untransformedHeight = colorSample.r; TileDepthTransform transform = HeightLayers[#{i}].depthTransform; float heightSample = transform.depthScale * untransformedHeight + transform.depthOffset; if (heightSample > -100000) { heightSample = performLayerSettings(heightSample, HeightLayers[#{i}].settings); height = heightSample; } } #endfor return height; } vec4 calculateColor(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer ColorLayers[NUMLAYERS_COLORTEXTURE]) { vec4 color = currentColor; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !COLORTEXTURE_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // COLORTEXTURE_BLENDING_ENABLED #for i in 0..#{lastLayerIndexColorLayers} { vec4 colorSample = getSampleColorLayers#{i}(uv, levelWeights, ColorLayers); colorSample = performAdjustmentColorLayers#{i}(colorSample, ColorLayers[#{i}].adjustment); colorSample = performLayerSettings(colorSample, ColorLayers[#{i}].settings); color = blendColorLayers#{i}(color, colorSample, 1.0); } #endfor return color; } float gridDots(vec2 uv, vec2 gridResolution) { vec2 uvVertexSpace = fract((gridResolution) * uv) + 0.5; vec2 uvDotSpace = abs(2.0 * (uvVertexSpace - 0.5)); return 1.0 - length(1.0 - uvDotSpace); } vec4 calculateDebugColor(vec2 uv, vec4 fragPos, vec2 vertexResolution) { vec2 uvVertexSpace = fract(vertexResolution * uv); vec3 colorUv = vec3(0.3 * uv.x, 0.3 * uv.y, 0); vec3 colorDistance = vec3(0.0, 0.0, min(0.4 * log(fragPos.w) - 3.9, 1)); vec3 colorVertex = (1.0 - length(uvVertexSpace)) * vec3(0.5); vec3 colorSum = colorUv + colorDistance + colorVertex; return vec4(0.5 * colorSum, 1); } float tileResolution(vec2 tileUV, ChunkTile chunkTile) { PixelPadding padding; padding.startOffset = ivec2(0); padding.sizeDifference = ivec2(0); vec2 heightResolution = textureSize(chunkTile.textureSampler, 0); vec2 uv = tileUVToTextureSamplePosition(chunkTile, tileUV, padding); return gridDots(uv, heightResolution); } vec4 calculateNight(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer NightLayers[NUMLAYERS_NIGHTTEXTURE], vec3 ellipsoidNormalCameraSpace, vec3 lightDirectionCameraSpace) { vec4 nightColor = vec4(0.0); vec4 color = currentColor; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !NIGHTTEXTURE_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // NIGHTTEXTURE_BLENDING_ENABLED vec3 n = normalize(ellipsoidNormalCameraSpace); vec3 l = lightDirectionCameraSpace; float cosineFactor = clamp(dot(l, normalize(n + 0.20 * l)) * 3 , 0, 1); #for i in 0..#{lastLayerIndexNightLayers} { vec4 colorSample = getSampleNightLayers#{i}(uv, levelWeights, NightLayers); colorSample = performAdjustmentNightLayers#{i}(colorSample, NightLayers[#{i}].adjustment); colorSample = performLayerSettings(colorSample, NightLayers[#{i}].settings); float adjustedAlpha = cosineFactor * colorSample.a; // Filter to night side vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha); color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha); } #endfor return color; } vec4 calculateShadedColor(vec4 currentColor, vec3 ellipsoidNormalCameraSpace, vec3 lightDirectionCameraSpace, vec3 viewDirectionCameraSpace, float roughness) { vec3 shadedColor = currentColor.rgb * 0.05; vec3 n = normalize(ellipsoidNormalCameraSpace); vec3 l = lightDirectionCameraSpace; float power = orenNayarDiffuse( -lightDirectionCameraSpace, viewDirectionCameraSpace, ellipsoidNormalCameraSpace, roughness); power = max(smoothstep(0.0f, 0.1f, max(dot(-l, n), 0.0f)) * power, 0.0f); vec4 color = vec4(shadedColor + currentColor.rgb * power, currentColor.a); return color; } vec4 calculateOverlay(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer Overlays[NUMLAYERS_OVERLAY]) { vec4 color = currentColor; // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !OVERLAY_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // OVERLAY_BLENDING_ENABLED #for i in 0..#{lastLayerIndexOverlays} { vec4 colorSample = getSampleOverlays#{i}(uv, levelWeights, Overlays); colorSample = performAdjustmentOverlays#{i}(colorSample, Overlays[#{i}].adjustment); colorSample = performLayerSettings(colorSample, Overlays[#{i}].settings); color = blendNormal(color, colorSample); color = blendOverlays#{i}(color, colorSample, 1.0); } #endfor return color; } vec4 calculateWater(vec4 currentColor, vec2 uv, vec3 levelWeights, Layer WaterMasks[NUMLAYERS_WATERMASK], vec3 ellipsoidNormalCameraSpace, vec3 lightDirectionCameraSpace, vec3 positionCameraSpace, out float reflectance) { vec4 waterColor = vec4(0.0); // The shader compiler will remove unused code when variables are multiplied by // a constant 0 #if !WATERMASK_BLENDING_ENABLED levelWeights = DefaultLevelWeights; #endif // WATERMASK_BLENDING_ENABLED #for i in 0..#{lastLayerIndexWaterMasks} { vec4 colorSample = getSampleWaterMasks#{i}(uv, levelWeights, WaterMasks); colorSample = performAdjustmentWaterMasks#{i}(colorSample, WaterMasks[#{i}].adjustment); colorSample.a = performLayerSettings(colorSample.a, WaterMasks[#{i}].settings); waterColor = blendWaterMasks#{i}(waterColor, colorSample, 1.0); } #endfor vec3 directionToFragmentCameraSpace = normalize(positionCameraSpace - vec3(0, 0, 0)); vec3 reflectionDirectionCameraSpace = reflect(lightDirectionCameraSpace, ellipsoidNormalCameraSpace); float cosineFactor = clamp(dot(-reflectionDirectionCameraSpace, directionToFragmentCameraSpace), 0, 1); cosineFactor = pow(cosineFactor, 100); const vec3 specularColor = vec3(1.0); const float specularIntensity = 0.4; vec3 specularTotal = specularColor * cosineFactor * specularIntensity * waterColor.a; reflectance = waterColor.a; //return blendNormal(currentColor, waterColor); //return currentColor + vec4(specularTotal, 1); return currentColor; } #endif // TEXTURETILEMAPPING_HGLSL