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__INPLANE_LIGHTING_COMMON_H
17 #define SHADERS__COMMON__INPLANE_LIGHTING_COMMON_H
18
19 #include "3d/shaders/common/3d_dm_brdf_common.h"
20 #include "3d/shaders/common/3d_dm_shadowing_common.h"
21 #include "3d/shaders/common/3d_dm_lighting_common.h"
22 // NOTE: inplace
23 #include "3d/shaders/common/3d_dm_inplace_sampling_common.h"
24
25 /*
26 * Needs to be included after the descriptor sets are bound.
27 */
28
CalculateLightInplace(uint currLightIdx,vec3 materialDiffuseBRDF,vec3 L,float NoL,ShadingDataInplace sd,ClearcoatShadingVariables ccsv,SheenShadingVariables ssv)29 vec3 CalculateLightInplace(uint currLightIdx, vec3 materialDiffuseBRDF, vec3 L, float NoL, ShadingDataInplace sd,
30 ClearcoatShadingVariables ccsv, SheenShadingVariables ssv)
31 {
32 const vec3 H = normalize(L + sd.V);
33 const float VoH = clamp(dot(sd.V, H), 0.0, 1.0);
34 const float NoH = clamp(dot(sd.N, H), 0.0, 1.0);
35
36 float extAttenuation = 1.0;
37 vec3 calculatedColor = vec3(0.0);
38 if ((CORE_MATERIAL_FLAGS & CORE_MATERIAL_SHEEN_BIT) == CORE_MATERIAL_SHEEN_BIT) {
39 const float sheenD = dCharlie(ssv.sheenRoughness, NoH);
40 const float sheenV = vAshikhmin(sd.NoV, NoL);
41 const vec3 sheenSpec = ssv.sheenColor * (sheenD * sheenV); // F = 1.0
42
43 extAttenuation *= (1.0 - (ssv.sheenColorMax * ssv.sheenBRDFApprox));
44 calculatedColor += (sheenSpec * NoL);
45 }
46 if ((CORE_MATERIAL_FLAGS & CORE_MATERIAL_CLEARCOAT_BIT) == CORE_MATERIAL_CLEARCOAT_BIT) {
47 const float ccNoL = clamp(dot(ccsv.ccNormal, L), CORE3D_PBR_LIGHTING_EPSILON, 1.0);
48 const float ccNoH = clamp(dot(ccsv.ccNormal, H), CORE3D_PBR_LIGHTING_EPSILON, 1.0);
49 const float ccLoH = clamp(dot(L, H), CORE3D_PBR_LIGHTING_EPSILON, 1.0);
50 const float ccNoV = clamp(dot(ccsv.ccNormal, sd.V), CORE3D_PBR_LIGHTING_EPSILON, 1.0);
51 const float ccf0 = 0.04;
52
53 const float ccD = dGGX(ccsv.ccAlpha2, ccNoH);
54 const float ccG = vKelemen(ccLoH);
55 const float ccF = fSchlickSingle(ccf0, ccNoV) * ccsv.cc; // NOTE: cc in ccF
56 const float ccSpec = ccF * ccD * ccG;
57
58 extAttenuation *= (1.0 - ccF);
59 calculatedColor += vec3(ccSpec * ccNoL);
60 }
61 const float D = dGGX(sd.alpha2, NoH);
62 const float G = vGGXWithCombinedDenominator(sd.alpha2, sd.NoV, NoL);
63 const vec3 F = fSchlick(sd.f0, VoH);
64 const vec3 specContrib = F * (D * G);
65
66 // KHR_materials_specular: "In the diffuse component we have to account for the fact that F is now an RGB value.",
67 // but it already was? const vec3 diffuseContrib = (1.0 - max(F.x, (max(F.y, F.z)))) * materialDiffuseBRDF;
68 const vec3 diffuseContrib = (1.0 - F.xyz) * materialDiffuseBRDF;
69 calculatedColor += (diffuseContrib + specContrib * extAttenuation) * extAttenuation * NoL;
70 calculatedColor *= uLightData.lights[currLightIdx].color.xyz;
71 return calculatedColor;
72 }
73
CheckLightLayerMask(uint currLightIdx,uvec2 layers)74 bool CheckLightLayerMask(uint currLightIdx, uvec2 layers) {
75 // Check that the light is enabled for this specific object.
76 // TODO: It seems like the mask bits are in .wz order when it should be .zw?
77 const uvec2 lightLayerMask = uLightData.lights[currLightIdx].indices.wz;
78 // If any of the layer bits match the light layer mask -> return true (i.e. use this light).
79 return (layers & lightLayerMask) != uvec2(0, 0);
80 }
81
CalculateLightingInplace(ShadingDataInplace sd,ClearcoatShadingVariables ccsv,SheenShadingVariables ssv)82 vec3 CalculateLightingInplace(ShadingDataInplace sd, ClearcoatShadingVariables ccsv, SheenShadingVariables ssv)
83 {
84 const vec3 materialDiffuseBRDF = sd.diffuseColor * diffuseCoeff();
85 vec3 color = vec3(0.0);
86 const uint directionalLightCount = uLightData.directionalLightCount;
87 const uint directionalLightBeginIndex = uLightData.directionalLightBeginIndex;
88 const vec4 atlasSizeInvSize = uLightData.atlasSizeInvSize;
89 for (uint lightIdx = 0; lightIdx < directionalLightCount; ++lightIdx) {
90 const uint currLightIdx = directionalLightBeginIndex + lightIdx;
91
92 if (!CheckLightLayerMask(currLightIdx, sd.layers)) {
93 continue;
94 }
95
96 const vec3 L = -uLightData.lights[currLightIdx].dir.xyz; // normalization already done in c-code
97 const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
98 // NOTE: could check for NoL > 0.0 and NoV > 0.0
99 CORE_RELAXEDP float shadowCoeff = 1.0;
100 if ((CORE_MATERIAL_FLAGS & CORE_MATERIAL_SHADOW_RECEIVER_BIT) == CORE_MATERIAL_SHADOW_RECEIVER_BIT) {
101 const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
102 if ((lightFlags.x & CORE_LIGHT_USAGE_SHADOW_LIGHT_BIT) == CORE_LIGHT_USAGE_SHADOW_LIGHT_BIT) {
103 const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
104 const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
105 if ((CORE_LIGHTING_FLAGS & CORE_LIGHTING_SHADOW_TYPE_VSM_BIT) == CORE_LIGHTING_SHADOW_TYPE_VSM_BIT) {
106 shadowCoeff = CalcVsmShadow(
107 uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
108 } else {
109 shadowCoeff = CalcPcfShadow(
110 uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
111 }
112 }
113 }
114 color += CalculateLightInplace(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv) * shadowCoeff;
115 }
116
117 if ((CORE_LIGHTING_FLAGS & CORE_LIGHTING_SPOT_ENABLED_BIT) == CORE_LIGHTING_SPOT_ENABLED_BIT) {
118 const uint spotLightCount = uLightData.spotLightCount;
119 const uint spotLightLightBeginIndex = uLightData.spotLightBeginIndex;
120 for (uint spotIdx = 0; spotIdx < spotLightCount; ++spotIdx) {
121 const uint currLightIdx = spotLightLightBeginIndex + spotIdx;
122
123 if (!CheckLightLayerMask(currLightIdx, sd.layers)) {
124 continue;
125 }
126
127 const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
128 const float dist = length(pointToLight);
129 const vec3 L = pointToLight / dist;
130 const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
131 // NOTE: could check for NoL > 0.0 and NoV > 0.0
132 CORE_RELAXEDP float shadowCoeff = 1.0;
133 if ((CORE_MATERIAL_FLAGS & CORE_MATERIAL_SHADOW_RECEIVER_BIT) == CORE_MATERIAL_SHADOW_RECEIVER_BIT) {
134 const uvec4 lightFlags = uLightData.lights[currLightIdx].flags;
135 if ((lightFlags.x & CORE_LIGHT_USAGE_SHADOW_LIGHT_BIT) == CORE_LIGHT_USAGE_SHADOW_LIGHT_BIT) {
136 const vec4 shadowCoord = GetShadowMatrix(lightFlags.y) * vec4(sd.pos.xyz, 1.0);
137 const vec4 shadowFactors = uLightData.lights[currLightIdx].shadowFactors;
138 if ((CORE_LIGHTING_FLAGS & CORE_LIGHTING_SHADOW_TYPE_VSM_BIT) ==
139 CORE_LIGHTING_SHADOW_TYPE_VSM_BIT) {
140 shadowCoeff = CalcVsmShadow(
141 uSampColorShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
142 } else {
143 shadowCoeff = CalcPcfShadow(
144 uSampDepthShadow, shadowCoord, NoL, shadowFactors, atlasSizeInvSize, lightFlags.zw);
145 }
146 }
147 }
148
149 const float lightAngleScale = uLightData.lights[currLightIdx].spotLightParams.x;
150 const float lightAngleOffset = uLightData.lights[currLightIdx].spotLightParams.y;
151 // See: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
152 const float cd = dot(uLightData.lights[currLightIdx].dir.xyz, -L);
153 const float angularAttenuation = clamp(cd * lightAngleScale + lightAngleOffset, 0.0, 1.0);
154
155 const float range = uLightData.lights[currLightIdx].dir.w;
156 const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
157 color += CalculateLightInplace(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv) *
158 (angularAttenuation * angularAttenuation * attenuation) * shadowCoeff;
159 }
160 }
161 if ((CORE_LIGHTING_FLAGS & CORE_LIGHTING_POINT_ENABLED_BIT) == CORE_LIGHTING_POINT_ENABLED_BIT) {
162 const uint pointLightCount = uLightData.pointLightCount;
163 const uint pointLightBeginIndex = uLightData.pointLightBeginIndex;
164 for (uint pointIdx = 0; pointIdx < pointLightCount; ++pointIdx) {
165 const uint currLightIdx = pointLightBeginIndex + pointIdx;
166
167 if (!CheckLightLayerMask(currLightIdx, sd.layers)) {
168 continue;
169 }
170
171 const vec3 pointToLight = uLightData.lights[currLightIdx].pos.xyz - sd.pos.xyz;
172 const float dist = length(pointToLight);
173 if (dist == 0) {
174 return color;
175 }
176 const vec3 L = pointToLight / dist;
177 const float NoL = clamp(dot(sd.N, L), 0.0, 1.0);
178 const float range = uLightData.lights[currLightIdx].dir.w;
179 const float attenuation = max(min(1.0 - pow(dist / range, 4.0), 1.0), 0.0) / (dist * dist);
180 // NOTE: could check for NoL > 0.0 and NoV > 0.0
181 color += CalculateLightInplace(currLightIdx, materialDiffuseBRDF, L, NoL, sd, ccsv, ssv) * attenuation;
182 }
183 }
184
185 return color;
186 }
187
188 #endif // SHADERS__COMMON__INPLANE_LIGHTING_COMMON_H
189