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