1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "bsdf.glsllib"
#ifdef QQ3D_SHADER_META
/*{
"uniforms": [
{ "type": "sampler2D", "name": "qt_screenTexture", "multiview_dependent": true },
{ "type": "mat4", "name": "qt_modelMatrix" },
{ "type": "mat4", "name": "qt_viewProjectionMatrix", "multiview_dependent": true }
]
}*/
#endif // QQ3D_SHADER_META
// Compute attenuated light as it travels through a volume.
vec3 qt_applyVolumeAttenuation(in vec3 radiance, in float transmissionDistance, in vec3 attenuationColor, in float attenuationDistance)
{
if (attenuationDistance == 0.0) {
return radiance;
} else {
// Compute light attenuation using Beer's law.
vec3 attenuationCoefficient = -log(attenuationColor) / attenuationDistance;
vec3 transmittance = exp(-attenuationCoefficient * transmissionDistance); // Beer's law
return transmittance * radiance;
}
}
vec3 qt_getVolumeTransmissionRay(in vec3 n, in vec3 v, in float thickness, in float ior)
{
// Direction of refracted light.
vec3 refractionVector = refract(-v, normalize(n), 1.0 / ior);
// Compute rotation-independent scaling of the model matrix.
vec3 modelScale;
modelScale.x = length(vec3(qt_modelMatrix[0].xyz));
modelScale.y = length(vec3(qt_modelMatrix[1].xyz));
modelScale.z = length(vec3(qt_modelMatrix[2].xyz));
// The thickness is specified in local space.
return normalize(refractionVector) * thickness * modelScale;
}
// Needed to correct the framebuffer texture for certain RHI backends
vec2 qt_correctFrambufferUV(in vec2 uv)
{
if (qt_rhi_properties.x < 0 && qt_rhi_properties.y == 1)
uv.y = 1 - uv.y;
return uv;
}
vec3 qt_getTransmissionSample(in vec2 fragCoord, in float roughness, in float ior)
{
const vec2 fbCoord = qt_correctFrambufferUV(fragCoord);
#if QSHADER_VIEW_COUNT >= 2
const float framebufferLod = log2(float(textureSize(qt_screenTextureArray, 0).x)) * qt_applyIorToRoughness(roughness, ior);
vec3 transmittedLight = textureLod(qt_screenTextureArray, vec3(fbCoord, qt_viewIndex), framebufferLod).rgb;
#else
const float framebufferLod = log2(float(textureSize(qt_screenTexture, 0).x)) * qt_applyIorToRoughness(roughness, ior);
vec3 transmittedLight = textureLod(qt_screenTexture, fbCoord, framebufferLod).rgb;
#endif
return transmittedLight;
}
vec3 qt_getIBLVolumeRefraction(in vec3 n, in vec3 v, in float perceptualRoughness, in vec3 baseColor, in vec3 F,
in vec3 position, in float ior, in float thickness, in vec3 attenuationColor, in float attenuationDistance)
{
vec3 transmissionRay = qt_getVolumeTransmissionRay(n, v, thickness, ior);
vec3 refractedRayExit = position + transmissionRay;
// Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
#if QSHADER_VIEW_COUNT >= 2
vec4 ndcPos = qt_viewProjectionMatrix[qt_viewIndex] * vec4(refractedRayExit, 1.0);
#else
vec4 ndcPos = qt_viewProjectionMatrix * vec4(refractedRayExit, 1.0);
#endif
vec2 refractionCoords = ndcPos.xy / ndcPos.w;
refractionCoords += 1.0;
refractionCoords /= 2.0;
// Sample framebuffer to get pixel the refracted ray hits.
vec3 transmittedLight = qt_getTransmissionSample(refractionCoords, perceptualRoughness, ior);
vec3 attenuatedColor = qt_applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance);
// Sample GGX LUT to get the specular component.
float NdotV = clamp(dot(n, v), 0.0, 1.0);
vec2 brdf = qt_brdfApproximation(n, v, perceptualRoughness);
vec3 specularColor = (F * brdf.x + brdf.y);
return (1.0 - specularColor) * attenuatedColor * baseColor;
}
|