1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef SHADERS__COMMON__3D_DM_INPLACE_FOG_COMMON_H
17 #define SHADERS__COMMON__3D_DM_INPLACE_FOG_COMMON_H
18 
19 #include "3d/shaders/common/3d_dm_structures_common.h"
20 #include "render/shaders/common/render_compatibility_common.h"
21 
22 #ifdef VULKAN
23 
24 struct FogLayer {
25     float density;
26     float fallOff;
27     float offset;
28 };
29 
CalculateLineIntegral(in FogLayer layer,in float rayDirY,in float rayOrigY)30 float CalculateLineIntegral(in FogLayer layer, in float rayDirY, in float rayOrigY)
31 {
32     const float epsilon = 0.005;
33 
34     const float exponent = max(-127.0f, layer.fallOff * (rayOrigY - layer.offset));
35 
36     const float falloff = max(-127.0f, layer.fallOff * rayDirY);
37 
38     const float lineIntegral = (1.0f - exp2(-falloff)) / falloff;
39     const float lineIntegralTaylor = log(2.0) - (0.5 * (log(2.0) * log(2.0))) * falloff; // Taylor expansion around 0
40 
41     return layer.density * exp2(-exponent) * (abs(falloff) > epsilon ? lineIntegral : lineIntegralTaylor);
42 }
43 
InplaceFogBlock(in uint flags,in vec3 worldPos,in vec3 camWorldPos,in vec4 inCol,out vec3 outCol)44 void InplaceFogBlock(in uint flags, in vec3 worldPos, in vec3 camWorldPos, in vec4 inCol, out vec3 outCol)
45 {
46     outCol = inCol.rgb;
47     if ((flags & CORE_CAMERA_FOG_BIT) == CORE_CAMERA_FOG_BIT) {
48         const vec3 cameraToPointVector = worldPos - camWorldPos;
49 
50         float cameraToPointY = cameraToPointVector.y;
51         float cameraY = camWorldPos.y;
52 
53         const float cameraToPointLengthSqr = dot(cameraToPointVector, cameraToPointVector);
54         const float cameraToPointLengthInv = inversesqrt(cameraToPointLengthSqr);
55         float worldDistanceToCamera = cameraToPointLengthSqr * cameraToPointLengthInv;
56 
57         const float minDistance = uFogData.baseFactors.x;
58         if (minDistance > 0) {
59             // recalculate fog starting point when minDistance is valid
60             const float minIntersectionT = minDistance * cameraToPointLengthInv;
61             const float cameraToMinIntersectionY = minIntersectionT * cameraToPointY;
62             // shift the values accordingly
63             cameraToPointY = cameraToPointY - cameraToMinIntersectionY;
64             cameraY = cameraY + cameraToMinIntersectionY;
65             worldDistanceToCamera = (1.0f - minIntersectionT) * worldDistanceToCamera;
66         }
67 
68         const FogLayer L1 = FogLayer(uFogData.firstLayer.x, uFogData.firstLayer.y, uFogData.firstLayer.z);
69         const float layer1Integral = CalculateLineIntegral(L1, cameraToPointY, cameraY);
70 
71         const FogLayer L2 = FogLayer(uFogData.secondLayer.x, uFogData.secondLayer.y, uFogData.secondLayer.z);
72         const float layer2Integral = CalculateLineIntegral(L2, cameraToPointY, cameraY);
73 
74         const float exponentialHeightLineIntegral = (layer1Integral + layer2Integral) * worldDistanceToCamera;
75 
76         const float maxOpacity = uFogData.baseFactors.z;
77         float expFogFactor = min(1.0 - clamp(exp2(-exponentialHeightLineIntegral), 0.0, 1.0), maxOpacity);
78 
79         const float cutOffDistance = uFogData.baseFactors.y;
80         if (cutOffDistance > 0 && worldDistanceToCamera > cutOffDistance) {
81             expFogFactor = 0;
82         }
83 
84         const vec4 inscatteringColor = uFogData.inscatteringColor;
85         const vec4 envMapColor = uFogData.envMapFactor;
86         const vec3 fogColor = inscatteringColor.rgb * inscatteringColor.a + envMapColor.rgb * envMapColor.a;
87         const vec3 baseColor = inCol.rgb;
88 
89         outCol.rgb = mix(baseColor, fogColor, expFogFactor);
90     }
91 }
92 
93 #else
94 
95 #endif
96 
97 #endif // SHADERS__COMMON__3D_DM_INPLACE_FOG_COMMON_H
98