cleanup and refactoring

This commit is contained in:
CDaut 2024-05-25 11:53:25 +02:00
parent 2302158928
commit 76f6bf62a4
Signed by: clara
GPG key ID: 223391B52FAD4463
1285 changed files with 757994 additions and 8 deletions

View file

@ -0,0 +1,63 @@
## Table of Contents
- [bsdf_functions.h](#bsdf_functionsh)
- [bsdf_structs.h](#bsdf_structsh)
- [dh_comp.h](#dh_comph)
- [dh_inspector.h](#dh_inspectorh)
- [dh_sky.h](#dh_skyh)
- [dh_tonemap.h](#dh_tonemaph)
## bsdf_functions.h
### Function absorptionCoefficient
> Compute the absorption coefficient of the material
### Function bsdfEvaluate
> Evaluate the BSDF for the given material
### Function bsdfSample
> Sample the BSDF for the given material
## bsdf_structs.h
### struct BsdfEvaluateData
> Data structure for evaluating a BSDF
### struct BsdfSampleData
> Data structure for sampling a BSDF
## dh_comp.h
### Function getGroupCounts
> Returns the number of workgroups needed to cover the size
This function is used to calculate the number of workgroups needed to cover a given size. It is used in the compute shader to calculate the number of workgroups needed to cover the size of the image.
## dh_inspector.h
### Function inspect32BitValue
> Inspect a 32-bit value at a given index
### Function inspectCustom32BitValue
> Inspect a 32-bit value at a given index
## dh_sky.h
### Function initSkyShaderParameters
> Initializes the sky shader parameters with default values
### Function proceduralSky
> Return the color of the procedural sky shader
## dh_tonemap.h
### Function tonemapFilmic
> Filmic tonemapping operator
http://filmicworlds.com/blog/filmic-tonemapping-operators/
### Function gammaCorrection
> Gamma correction
see https://www.teamten.com/lawrence/graphics/gamma/
### Function tonemapUncharted
> Uncharted tone map
see: http://filmicworlds.com/blog/filmic-tonemapping-operators/

View file

@ -0,0 +1,283 @@
/*
* Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2019-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#include "func.glsl" // cosineSampleHemisphere
#include "ggx.glsl" // brdfLambertian, ..
#include "bsdf_structs.h" // Bsdf*,
#include "pbr_mat_struct.h" // PbrMaterial
/** @DOC_START
# Function absorptionCoefficient
> Compute the absorption coefficient of the material
@DOC_END */
vec3 absorptionCoefficient(in PbrMaterial mat)
{
float tmp1 = mat.attenuationDistance;
return tmp1 <= 0.0F ? vec3(0.0F, 0.0F, 0.0F) :
-vec3(log(mat.attenuationColor.x), log(mat.attenuationColor.y), log(mat.attenuationColor.z)) / tmp1;
}
struct EvalData
{
float pdf;
vec3 bsdf;
};
void evalDiffuse(in BsdfEvaluateData data, in PbrMaterial mat, out EvalData eval)
{
// Diffuse reflection
float NdotL = clampedDot(mat.normal, data.k2);
eval.bsdf = brdfLambertian(mat.albedo.rgb, mat.metallic) * NdotL;
eval.pdf = M_1_OVER_PI;
}
void evalSpecular(in BsdfEvaluateData data, in PbrMaterial mat, out EvalData eval)
{
// Specular reflection
vec3 H = normalize(data.k1 + data.k2);
float alphaRoughness = mat.roughness * mat.roughness;
float NdotV = clampedDot(mat.normal, data.k1);
float NdotL = clampedDot(mat.normal, data.k2);
float VdotH = clampedDot(data.k1, H);
float NdotH = clampedDot(mat.normal, H);
float LdotH = clampedDot(data.k2, H);
vec3 f_specular = brdfSpecularGGX(mat.f0, mat.f90, alphaRoughness, VdotH, NdotL, NdotV, NdotH);
eval.bsdf = f_specular * NdotL;
eval.pdf = distributionGGX(NdotH, alphaRoughness) * NdotH / (4.0F * LdotH);
}
void evalTransmission(in BsdfEvaluateData data, in PbrMaterial mat, out EvalData eval)
{
eval.pdf = 0;
eval.bsdf = vec3(0.0F, 0.0F, 0.0F);
if(mat.transmissionFactor <= 0.0F)
return;
vec3 refractedDir;
bool totalInternalRefraction = refract(data.k2, mat.normal, mat.eta, refractedDir);
if(!totalInternalRefraction)
{
//eval.bsdf = mat.albedo.rgb * mat.transmissionFactor;
eval.pdf = abs(dot(refractedDir, mat.normal));
}
}
/** @DOC_START
# Function bsdfEvaluate
> Evaluate the BSDF for the given material.
@DOC_END */
void bsdfEvaluate(inout BsdfEvaluateData data, in PbrMaterial mat)
{
// Initialization
float diffuseRatio = 0.5F * (1.0F - mat.metallic);
float specularRatio = 1.0F - diffuseRatio;
float transmissionRatio = (1.0F - mat.metallic) * mat.transmissionFactor;
// Contribution
EvalData f_diffuse;
EvalData f_specular;
EvalData f_transmission;
evalDiffuse(data, mat, f_diffuse);
evalSpecular(data, mat, f_specular);
evalTransmission(data, mat, f_transmission);
// Combine the results
float brdfPdf = 0;
brdfPdf += f_diffuse.pdf * diffuseRatio;
brdfPdf += f_specular.pdf * specularRatio;
brdfPdf = mix(brdfPdf, f_transmission.pdf, transmissionRatio);
vec3 bsdfDiffuse = mix(f_diffuse.bsdf, f_transmission.bsdf, transmissionRatio);
vec3 bsdfGlossy = mix(f_specular.bsdf, f_transmission.bsdf, transmissionRatio);
// Return results
data.bsdf_diffuse = bsdfDiffuse;
data.bsdf_glossy = bsdfGlossy;
data.pdf = brdfPdf;
}
//-------------------------------------------------------------------------------------------------
vec3 sampleDiffuse(inout BsdfSampleData data, in PbrMaterial mat)
{
vec3 surfaceNormal = mat.normal;
vec3 tangent, bitangent;
orthonormalBasis(surfaceNormal, tangent, bitangent);
float r1 = data.xi.x;
float r2 = data.xi.y;
vec3 sampleDirection = cosineSampleHemisphere(r1, r2); // Diffuse
sampleDirection = tangent * sampleDirection.x + bitangent * sampleDirection.y + surfaceNormal * sampleDirection.z;
data.event_type = BSDF_EVENT_DIFFUSE;
return sampleDirection;
}
vec3 sampleSpecular(inout BsdfSampleData data, in PbrMaterial mat)
{
vec3 surfaceNormal = mat.normal;
vec3 tangent, bitangent;
orthonormalBasis(surfaceNormal, tangent, bitangent);
float alphaRoughness = mat.roughness * mat.roughness;
float r1 = data.xi.x;
float r2 = data.xi.y;
vec3 halfVector = ggxSampling(alphaRoughness, r1, r2); // Glossy
halfVector = tangent * halfVector.x + bitangent * halfVector.y + surfaceNormal * halfVector.z;
vec3 sampleDirection = reflect(-data.k1, halfVector);
data.event_type = BSDF_EVENT_SPECULAR;
return sampleDirection;
}
vec3 sampleThinTransmission(in BsdfSampleData data, in PbrMaterial mat)
{
vec3 incomingDir = data.k1;
float r1 = data.xi.x;
float r2 = data.xi.y;
float alphaRoughness = mat.roughness * mat.roughness;
vec3 halfVector = ggxSampling(alphaRoughness, r1, r2);
vec3 tangent, bitangent;
orthonormalBasis(incomingDir, tangent, bitangent);
vec3 transformedHalfVector = tangent * halfVector.x + bitangent * halfVector.y + incomingDir * halfVector.z;
vec3 refractedDir = -transformedHalfVector;
return refractedDir;
}
vec3 sampleSolidTransmission(inout BsdfSampleData data, in PbrMaterial mat, out bool refracted)
{
vec3 surfaceNormal = mat.normal;
if(mat.roughness > 0.0F)
{
vec3 tangent, bitangent;
orthonormalBasis(surfaceNormal, tangent, bitangent);
float alphaRoughness = mat.roughness * mat.roughness;
float r1 = data.xi.x;
float r2 = data.xi.y;
vec3 halfVector = ggxSampling(alphaRoughness, r1, r2); // Glossy
halfVector = tangent * halfVector.x + bitangent * halfVector.y + surfaceNormal * halfVector.z;
surfaceNormal = halfVector;
}
vec3 refractedDir;
refracted = refract(-data.k1, surfaceNormal, mat.eta, refractedDir);
return refractedDir;
}
void sampleTransmission(inout BsdfSampleData data, in PbrMaterial mat)
{
// Calculate transmission direction using Snell's law
vec3 refractedDir;
vec3 sampleDirection;
bool refracted = true;
float r4 = data.xi.w;
// Thin film approximation
if(mat.thicknessFactor == 0.0F && mat.roughness > 0.0F)
{
refractedDir = sampleThinTransmission(data, mat);
}
else
{
refractedDir = sampleSolidTransmission(data, mat, refracted);
}
// Fresnel term
float VdotH = dot(data.k1, mat.normal);
vec3 reflectance = fresnelSchlick(mat.f0, mat.f90, VdotH);
vec3 surfaceNormal = mat.normal;
if(!refracted || r4 < luminance(reflectance))
{
// Total internal reflection or reflection based on Fresnel term
sampleDirection = reflect(-data.k1, surfaceNormal); // Reflective direction
data.event_type = BSDF_EVENT_SPECULAR;
}
else
{
// Transmission
sampleDirection = refractedDir;
data.event_type = BSDF_EVENT_TRANSMISSION;
}
// Attenuate albedo for transmission
vec3 bsdf = mat.albedo.rgb; // * mat.transmissionFactor;
// Result
data.bsdf_over_pdf = bsdf;
data.pdf = abs(dot(surfaceNormal, sampleDirection)); //transmissionRatio;
data.k2 = sampleDirection;
}
/** @DOC_START
# Function bsdfSample
> Sample the BSDF for the given material
@DOC_END */
void bsdfSample(inout BsdfSampleData data, in PbrMaterial mat)
{
// Random numbers for importance sampling
float r3 = data.xi.z;
// Initialization
float diffuseRatio = 0.5F * (1.0F - mat.metallic);
float specularRatio = 1.0F - diffuseRatio;
float transmissionRatio = (1.0F - mat.metallic) * mat.transmissionFactor;
// Calculate if the ray goes through
if(r3 < transmissionRatio)
{
sampleTransmission(data, mat);
return;
}
// Choose between diffuse and glossy reflection
vec3 sampleDirection = vec3(0.0F, 0.0F, 0.0F);
if(r3 < diffuseRatio)
{
sampleDirection = sampleDiffuse(data, mat);
}
else
{
// Specular roughness
sampleDirection = sampleSpecular(data, mat);
}
// Evaluate the reflection coefficient with the new ray direction
BsdfEvaluateData evalData;
evalData.k1 = data.k1;
evalData.k2 = sampleDirection;
bsdfEvaluate(evalData, mat);
// Return values
data.pdf = evalData.pdf;
data.bsdf_over_pdf = (evalData.bsdf_diffuse + evalData.bsdf_glossy) / data.pdf;
data.k2 = sampleDirection;
// Avoid internal reflection
if(data.pdf <= 0.00001F || any(isnan(data.bsdf_over_pdf)))
data.event_type = BSDF_EVENT_ABSORB;
return;
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2023, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef BSDF_STRUCTS_H
#define BSDF_STRUCTS_H 1
#define BSDF_EVENT_ABSORB 0 // 0
#define BSDF_EVENT_DIFFUSE 1 // 1
#define BSDF_EVENT_GLOSSY (1 << 1) // 2
#define BSDF_EVENT_SPECULAR (1 << 2) // 4
#define BSDF_EVENT_REFLECTION (1 << 3) // 8
#define BSDF_EVENT_TRANSMISSION (1 << 4) // 16
#define BSDF_EVENT_DIFFUSE_REFLECTION (BSDF_EVENT_DIFFUSE | BSDF_EVENT_REFLECTION) // 9
#define BSDF_EVENT_DIFFUSE_TRANSMISSION (BSDF_EVENT_DIFFUSE | BSDF_EVENT_TRANSMISSION) // 17
#define BSDF_EVENT_GLOSSY_REFLECTION (BSDF_EVENT_GLOSSY | BSDF_EVENT_REFLECTION) // 10
#define BSDF_EVENT_GLOSSY_TRANSMISSION (BSDF_EVENT_GLOSSY | BSDF_EVENT_TRANSMISSION) // 18
#define BSDF_EVENT_SPECULAR_REFLECTION (BSDF_EVENT_SPECULAR | BSDF_EVENT_REFLECTION) // 12
#define BSDF_EVENT_SPECULAR_TRANSMISSION (BSDF_EVENT_SPECULAR | BSDF_EVENT_TRANSMISSION) // 20
#define BSDF_USE_MATERIAL_IOR (-1.0)
/** @DOC_START
# struct BsdfEvaluateData
> Data structure for evaluating a BSDF
@DOC_END */
struct BsdfEvaluateData
{
vec3 k1; // [in] Toward the incoming ray
vec3 k2; // [in] Toward the sampled light
vec3 bsdf_diffuse; // [out] Diffuse contribution
vec3 bsdf_glossy; // [out] Specular contribution
float pdf; // [out] PDF
};
/** @DOC_START
# struct BsdfSampleData
> Data structure for sampling a BSDF
@DOC_END */
struct BsdfSampleData
{
vec3 k1; // [in] Toward the incoming ray
vec3 k2; // [in] Toward the sampled light
vec4 xi; // [in] 4 random [0..1]
float pdf; // [out] PDF
vec3 bsdf_over_pdf; // [out] contribution / PDF
int event_type; // [out] one of the event above
};
#endif

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef CONSTANTS_GLSL
#define CONSTANTS_GLSL
precision highp float;
const float M_PI = 3.1415926535897F; // PI
const float M_TWO_PI = 6.2831853071795F; // 2*PI
const float M_PI_2 = 1.5707963267948F; // PI/2
const float M_PI_4 = 0.7853981633974F; // PI/4
const float M_1_OVER_PI = 0.3183098861837F; // 1/PI
const float M_2_OVER_PI = 0.6366197723675F; // 2/PI
const float INFINITE = 1e32F;
#endif // CONSTANTS_GLSL

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DH_COMP_H
#define DH_COMP_H 1
#define WORKGROUP_SIZE 16 // Grid size used by compute shaders
#ifdef __cplusplus
/** @DOC_START
# Function getGroupCounts
> Returns the number of workgroups needed to cover the size
This function is used to calculate the number of workgroups needed to cover a given size. It is used in the compute shader to calculate the number of workgroups needed to cover the size of the image.
@DOC_END */
inline VkExtent2D getGroupCounts(const VkExtent2D& size, int workgroupSize = WORKGROUP_SIZE)
{
return VkExtent2D{(size.width + (workgroupSize - 1)) / workgroupSize, (size.height + (workgroupSize - 1)) / workgroupSize};
}
#endif // __cplusplus
#endif // DH_COMP_H

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP
#ifndef DH_HDR_H
#define DH_HDR_H 1
#ifndef WORKGROUP_SIZE
#define WORKGROUP_SIZE 16 // Grid size used by compute shaders
#endif
#ifdef __cplusplus
#include <glm/glm.hpp>
#include <cstdint>
namespace nvvkhl_shaders {
using uint = uint32_t;
using mat4 = glm::mat4;
using vec4 = glm::vec4;
using vec2 = glm::vec2;
#endif
// Environment acceleration structure - computed in hdr_env
struct EnvAccel
{
uint alias;
float q;
};
struct HdrPushBlock
{
mat4 mvp;
vec2 size;
float roughness;
uint numSamples;
};
struct HdrDomePushConstant
{
mat4 mvp;
vec4 multColor;
float rotation;
};
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#define INLINE inline
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#define INLINE
#endif
START_BINDING(EnvBindings)
eHdr = 0,
eImpSamples = 1
END_BINDING();
START_BINDING(EnvDomeBindings)
eHdrBrdf = 0,
eHdrDiffuse = 1,
eHdrSpecular = 2
END_BINDING();
START_BINDING(EnvDomeDraw)
eHdrImage = 0
END_BINDING();
// clang-format on
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif // DH_HDR_H

View file

@ -0,0 +1,240 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
// Shader header for inspection shader variables
// Prior to including this header the following macros need to be defined
// Either INSPECTOR_MODE_COMPUTE or INSPECTOR_MODE_FRAGMENT
// If INSPECTOR_MODE_COMPUTE is defined the shader must expose invocation information (e.g. gl_LocalInvocationID).
// This typically applies to compute, task and mesh shaders
// If INSPECTOR_MODE_FRAGMENT is defined the shader must expose fragment information (e.g. gl_FragCoord).
// This applies to fragment shaders
//
// INSPECTOR_DESCRIPTOR_SET: the index of the descriptor set containing the Inspector buffers
// INSPECTOR_INSPECTION_DATA_BINDING: the binding index of the buffer containing the inspection information, as provided by ElementInspector::getComputeInspectionBuffer()
// INSPECTOR_METADATA_BINDING: the binding index of the buffer containing the inspection metadata, as provided by ElementInspector::getComputeMetadataBuffer()
#ifndef DH_INSPECTOR_H
#define DH_INSPECTOR_H
#ifdef __cplusplus
#include <cstdint>
namespace nvvkhl_shaders {
using uvec3 = glm::uvec3;
using uvec2 = glm::uvec2;
#else
#extension GL_EXT_shader_explicit_arithmetic_types : require
#extension GL_EXT_shader_atomic_int64 : require
#extension GL_KHR_shader_subgroup_basic : require
#endif
#define WARP_SIZE 32
#define WARP_2D_SIZE_X 8
#define WARP_2D_SIZE_Y 4
#define WARP_2D_SIZE_Z 1
struct InspectorComputeMetadata
{
uvec3 minBlock;
uint32_t u32PerThread;
uvec3 maxBlock;
uint32_t minWarpInBlock;
uint32_t maxWarpInBlock;
};
struct InspectorFragmentMetadata
{
uvec2 minFragment;
uvec2 maxFragment;
uvec2 renderSize;
uint32_t u32PerThread;
};
struct InspectorCustomMetadata
{
uvec3 minCoord;
uint32_t pad0;
uvec3 maxCoord;
uint32_t pad1;
uvec3 extent;
uint32_t u32PerThread;
};
#ifndef __cplusplus
#if !(defined INSPECTOR_MODE_COMPUTE) && !(defined INSPECTOR_MODE_FRAGMENT) && !(defined INSPECTOR_MODE_CUSTOM)
#error At least one inspector mode (INSPECTOR_MODE_COMPUTE, INSPECTOR_MODE_FRAGMENT, INSPECTOR_MODE_CUSTOM) must be defined before including this file
#endif
#if(defined INSPECTOR_MODE_COMPUTE) && (defined INSPECTOR_MODE_FRAGMENT)
#error Only one of inspector modes INSPECTOR_MODE_COMPUTE, INSPECTOR_MODE_FRAGMENT can be chosen
#endif
#ifndef INSPECTOR_DESCRIPTOR_SET
#error The descriptor set containing thread inspection data must be provided before including this file
#endif
#ifdef INSPECTOR_MODE_CUSTOM
#ifndef INSPECTOR_CUSTOM_INSPECTION_DATA_BINDING
#error The descriptor binding containing custom thread inspection data must be provided before including this file
#endif
#ifndef INSPECTOR_CUSTOM_METADATA_BINDING
#error The descriptor binding containing custom thread inspection metadata must be provided before including this file
#endif
#endif
#if(defined INSPECTOR_MODE_COMPUTE) || (defined INSPECTOR_MODE_FRAGMENT)
#ifndef INSPECTOR_INSPECTION_DATA_BINDING
#error The descriptor binding containing thread inspection data must be provided before including this file
#endif
#ifndef INSPECTOR_METADATA_BINDING
#error The descriptor binding containing thread inspection metadata must be provided before including this file
#endif
#endif
#ifdef INSPECTOR_MODE_COMPUTE
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_INSPECTION_DATA_BINDING) buffer InspectorInspectionData
{
uint32_t inspectorInspectionData[];
};
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_METADATA_BINDING) readonly buffer InspectorComputeInspectionMetadata
{
InspectorComputeMetadata inspectorMetadata;
};
/** @DOC_START
# Function inspect32BitValue
> Inspect a 32-bit value at a given index
@DOC_END */
void inspect32BitValue(uint32_t index, uint32_t v)
{
if(clamp(gl_WorkGroupID, inspectorMetadata.minBlock, inspectorMetadata.maxBlock) != gl_WorkGroupID)
{
return;
}
uint32_t warpIndex = gl_SubgroupID;
if(warpIndex < inspectorMetadata.minWarpInBlock || warpIndex > inspectorMetadata.maxWarpInBlock)
return;
uint32_t inspectedThreadsPerBlock = (inspectorMetadata.maxWarpInBlock - inspectorMetadata.minWarpInBlock + 1) * gl_SubgroupSize;
;
uint32_t blockIndex = gl_WorkGroupID.x + gl_NumWorkGroups.x * (gl_WorkGroupID.y + gl_NumWorkGroups.y * gl_WorkGroupID.z);
uint32_t minBlockIndex =
inspectorMetadata.minBlock.x
+ gl_NumWorkGroups.x * (inspectorMetadata.minBlock.y + gl_NumWorkGroups.y * inspectorMetadata.minBlock.z);
uint32_t blockStart = inspectedThreadsPerBlock * (blockIndex - minBlockIndex) * inspectorMetadata.u32PerThread;
uint32_t warpStart = (warpIndex - inspectorMetadata.minWarpInBlock) * inspectorMetadata.u32PerThread * gl_SubgroupSize;
uint32_t threadInWarpStart = gl_SubgroupInvocationID * inspectorMetadata.u32PerThread;
inspectorInspectionData[blockStart + warpStart + threadInWarpStart + index] = v;
}
#endif
#ifdef INSPECTOR_MODE_FRAGMENT
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_INSPECTION_DATA_BINDING) buffer InspectorInspectionData
{
uint64_t inspectorInspectionData[];
};
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_METADATA_BINDING) readonly buffer InspectorFragmentInspectionMetadata
{
InspectorFragmentMetadata inspectorMetadata;
};
void inspect32BitValue(uint32_t index, uint32_t v)
{
uvec2 fragment = uvec2(floor(gl_FragCoord.xy));
if(clamp(fragment, inspectorMetadata.minFragment, inspectorMetadata.maxFragment) != fragment)
{
return;
}
uvec2 localFragment = fragment - inspectorMetadata.minFragment;
uint32_t inspectionWidth = inspectorMetadata.maxFragment.x - inspectorMetadata.minFragment.x + 1;
uint32_t fragmentIndex = localFragment.x + inspectionWidth * localFragment.y;
// Atomically store the fragment depth along with the value so we always keep the fragment value
// with the lowest depth
float z = 1.f - clamp(gl_FragCoord.z, 0.f, 1.f);
uint64_t zUint = floatBitsToUint(z);
uint64_t value = (zUint << 32) | uint64_t(v);
atomicMax(inspectorInspectionData[fragmentIndex * inspectorMetadata.u32PerThread / 2 + index], value);
}
#endif
#ifdef INSPECTOR_MODE_CUSTOM
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_CUSTOM_INSPECTION_DATA_BINDING) buffer InspectorCustomInspections
{
uint32_t inspectorCustomInspection[];
};
layout(set = INSPECTOR_DESCRIPTOR_SET, binding = INSPECTOR_CUSTOM_METADATA_BINDING) readonly buffer InspectorCustomInspectionMetadata
{
InspectorCustomMetadata inspectorCustomMetadata;
};
/** @DOC_START
# Function inspectCustom32BitValue
> Inspect a 32-bit value at a given index
@DOC_END */
void inspectCustom32BitValue(uint32_t index, uvec3 location, uint32_t v)
{
if(clamp(location, inspectorCustomMetadata.minCoord, inspectorCustomMetadata.maxCoord) != location)
{
return;
}
uvec3 localCoord = location - inspectorCustomMetadata.minCoord;
uint32_t inspectionWidth = inspectorCustomMetadata.maxCoord.x - inspectorCustomMetadata.minCoord.x + 1;
uint32_t inspectionHeight = inspectorCustomMetadata.maxCoord.y - inspectorCustomMetadata.minCoord.y + 1;
uint32_t coordIndex = localCoord.x + inspectionWidth * (localCoord.y + inspectionHeight * localCoord.z);
inspectorCustomInspection[coordIndex * inspectorCustomMetadata.u32PerThread + index] = v;
}
#endif
#endif
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif // DH_INSPECTOR_H

View file

@ -0,0 +1,91 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP
#ifndef DH_LIGHTING_H
#define DH_LIGHTING_H 1
#ifdef __cplusplus
namespace nvvkhl_shaders {
using vec3 = glm::vec3;
#endif // __cplusplus
const int eLightTypeNone = 0;
const int eLightTypeDirectional = 1;
const int eLightTypeSpot = 2;
const int eLightTypePoint = 3;
//-----------------------------------------------------------------------
// Use for light/env contribution
struct VisibilityContribution
{
vec3 radiance; // Radiance at the point if light is visible
vec3 lightDir; // Direction to the light, to shoot shadow ray
float lightDist; // Distance to the light (1e32 for infinite or sky)
bool visible; // true if in front of the face and should shoot shadow ray
};
struct LightContrib
{
vec3 incidentVector;
float halfAngularSize;
vec3 intensity;
};
struct Light
{
vec3 direction;
int type;
vec3 position;
float radius;
vec3 color;
float intensity; // illuminance (lm/m2) for directional lights, luminous intensity (lm/sr) for positional lights
float angularSizeOrInvRange; // angular size for directional lights, 1/range for spot and point lights
float innerAngle;
float outerAngle;
float outOfBoundsShadow;
};
#ifdef __cplusplus
inline Light defaultLight()
{
Light l;
l.position = vec3{5.0F, 5.F, 5.F};
l.direction = glm::normalize(vec3{0.0F, -.7F, -.7F});
l.type = eLightTypeDirectional;
l.angularSizeOrInvRange = glm::radians(0.53F);
l.color = {1.0F, 1.0F, 1.0F};
l.intensity = 0.F; // Dark
l.innerAngle = glm::radians(10.F);
l.outerAngle = glm::radians(30.F);
l.radius = 1.0F;
return l;
}
#endif //__cplusplus
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif // DH_LIGHTING_H

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP
#ifndef DH_SCN_DESC_H
#define DH_SCN_DESC_H 1
#ifdef __cplusplus
namespace nvvkhl_shaders {
using mat4 = glm::mat4;
using mat3 = glm::mat3;
using vec4 = glm::vec4;
using vec3 = glm::vec3;
#endif // __cplusplus
struct InstanceInfo
{
mat4 objectToWorld;
mat4 worldToObject;
int materialID;
};
struct Vertex
{
vec4 position; // POS.xyz + UV.x
vec4 normal; // NRM.xyz + UV.y
vec4 tangent; // TNG.xyz + sign: 1, -1
};
struct PrimMeshInfo
{
uint64_t vertexAddress;
uint64_t indexAddress;
int materialIndex;
};
struct SceneDescription
{
uint64_t materialAddress;
uint64_t instInfoAddress;
uint64_t primInfoAddress;
};
// alphaMode
#define ALPHA_OPAQUE 0
#define ALPHA_MASK 1
#define ALPHA_BLEND 2
struct GltfShadeMaterial
{
// Core
vec4 pbrBaseColorFactor;
vec3 emissiveFactor;
int pbrBaseColorTexture;
int normalTexture;
float normalTextureScale;
int _pad0;
float pbrRoughnessFactor;
float pbrMetallicFactor;
int pbrMetallicRoughnessTexture;
int emissiveTexture;
int alphaMode;
float alphaCutoff;
// KHR_materials_transmission
float transmissionFactor;
int transmissionTexture;
// KHR_materials_ior
float ior;
// KHR_materials_volume
vec3 attenuationColor;
float thicknessFactor;
int thicknessTexture;
bool thinWalled;
float attenuationDistance;
// KHR_materials_clearcoat
float clearcoatFactor;
float clearcoatRoughness;
int clearcoatTexture;
int clearcoatRoughnessTexture;
int clearcoatNormalTexture;
// KHR_materials_specular
float specularFactor;
int specularTexture;
vec3 specularColorFactor;
int specularColorTexture;
// KHR_texture_transform
mat3 uvTransform;
};
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DH_SKY_H
#define DH_SKY_H 1
#ifdef __cplusplus
#define inout // Not used
namespace nvvkhl_shaders {
using mat4 = glm::mat4;
using vec2 = glm::vec2;
using vec3 = glm::vec3;
#else
#define static
#define inline
#endif // __cplusplus
#ifndef WORKGROUP_SIZE
#define WORKGROUP_SIZE 16 // Grid size used by compute shaders
#endif
// clang-format off
#ifdef __cplusplus // Descriptor binding helper for C++ and GLSL
#define START_BINDING(a) enum a {
#define END_BINDING() }
#else
#define START_BINDING(a) const uint
#define END_BINDING()
#endif
START_BINDING(SkyBindings)
eSkyOutImage = 0,
eSkyParam = 1
END_BINDING();
// clang-format on
struct ProceduralSkyShaderParameters
{
vec3 directionToLight;
float angularSizeOfLight;
vec3 lightColor;
float glowSize;
vec3 skyColor;
float glowIntensity;
vec3 horizonColor;
float horizonSize;
vec3 groundColor;
float glowSharpness;
vec3 directionUp;
float pad1;
};
struct SkyPushConstant
{
mat4 mvp;
};
/** @DOC_START
# Function initSkyShaderParameters
> Initializes the sky shader parameters with default values
@DOC_END */
inline ProceduralSkyShaderParameters initSkyShaderParameters()
{
ProceduralSkyShaderParameters p;
p.directionToLight = vec3(0.0F, 0.707F, 0.707F);
p.angularSizeOfLight = 0.059F;
p.lightColor = vec3(1.0F, 1.0F, 1.0F);
p.skyColor = vec3(0.17F, 0.37F, 0.65F);
p.horizonColor = vec3(0.50F, 0.70F, 0.92F);
p.groundColor = vec3(0.62F, 0.59F, 0.55F);
p.directionUp = vec3(0.F, 1.F, 0.F);
p.horizonSize = 0.5F; // +/- degrees
p.glowSize = 0.091F; // degrees, starting from the edge of the light disk
p.glowIntensity = 0.9F; // [0-1] relative to light intensity
p.glowSharpness = 4.F; // [1-10] is the glow power exponent
return p;
}
#ifndef __cplusplus
/** @DOC_START
# Function proceduralSky
> Return the color of the procedural sky shader
@DOC_END */
inline vec3 proceduralSky(ProceduralSkyShaderParameters params, vec3 direction, float angularSizeOfPixel)
{
float elevation = asin(clamp(dot(direction, params.directionUp), -1.0F, 1.0F));
float top = smoothstep(0.F, params.horizonSize, elevation);
float bottom = smoothstep(0.F, params.horizonSize, -elevation);
vec3 environment = mix(mix(params.horizonColor, params.groundColor, bottom), params.skyColor, top);
float angle_to_light = acos(clamp(dot(direction, params.directionToLight), 0.0F, 1.0F));
float half_angular_size = params.angularSizeOfLight * 0.5F;
float light_intensity =
clamp(1.0F - smoothstep(half_angular_size - angularSizeOfPixel * 2.0F, half_angular_size + angularSizeOfPixel * 2.0F, angle_to_light),
0.0F, 1.0F);
light_intensity = pow(light_intensity, 4.0F);
float glow_input =
clamp(2.0F * (1.0F - smoothstep(half_angular_size - params.glowSize, half_angular_size + params.glowSize, angle_to_light)),
0.0F, 1.0F);
float glow_intensity = params.glowIntensity * pow(glow_input, params.glowSharpness);
vec3 light = max(light_intensity, glow_intensity) * params.lightColor;
return environment + light;
}
#endif
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif // DH_SKY_H

View file

@ -0,0 +1,169 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef DH_TONEMAMP_H
#define DH_TONEMAMP_H 1
#ifdef __cplusplus
namespace nvvkhl_shaders {
using vec3 = glm::vec3;
using vec2 = glm::vec2;
using uint = uint32_t;
#define INLINE inline
#else
#define INLINE
#endif
const int eTonemapFilmic = 0;
const int eTonemapUncharted = 1;
const int eTonemapGamma = 2;
// Tonemapper settings
struct Tonemapper
{
int method;
int isActive;
float exposure;
float brightness;
float contrast;
float saturation;
float vignette;
float gamma;
};
INLINE Tonemapper defaultTonemapper()
{
Tonemapper t;
t.method = 0;
t.isActive = 1;
t.exposure = 1.0F;
t.brightness = 1.0F;
t.contrast = 1.0F;
t.saturation = 1.0F;
t.vignette = 0.0F;
t.gamma = 2.2F;
return t;
}
// Bindings
const int eTonemapperInput = 0;
const int eTonemapperOutput = 1;
/** @DOC_START
# Function tonemapFilmic
> Filmic tonemapping operator
http://filmicworlds.com/blog/filmic-tonemapping-operators/
@DOC_END */
INLINE vec3 tonemapFilmic(vec3 color)
{
vec3 temp = max(vec3(0.0F), color - vec3(0.004F));
vec3 result = (temp * (vec3(6.2F) * temp + vec3(0.5F))) / (temp * (vec3(6.2F) * temp + vec3(1.7F)) + vec3(0.06F));
return result;
}
/** @DOC_START
# Function gammaCorrection
> Gamma correction
see https://www.teamten.com/lawrence/graphics/gamma/
@DOC_END */
INLINE vec3 gammaCorrection(vec3 color, float gamma)
{
return pow(color, vec3(1.0F / gamma));
}
/** @DOC_START
# Function tonemapUncharted
> Uncharted tone map
see: http://filmicworlds.com/blog/filmic-tonemapping-operators/
@DOC_END */
INLINE vec3 tonemapUncharted2Impl(vec3 color)
{
const float a = 0.15F;
const float b = 0.50F;
const float c = 0.10F;
const float d = 0.20F;
const float e = 0.02F;
const float f = 0.30F;
return ((color * (a * color + c * b) + d * e) / (color * (a * color + b) + d * f)) - e / f;
}
INLINE vec3 tonemapUncharted(vec3 color, float gamma)
{
const float W = 11.2F;
const float exposure_bias = 2.0F;
color = tonemapUncharted2Impl(color * exposure_bias);
vec3 white_scale = vec3(1.0F) / tonemapUncharted2Impl(vec3(W));
return gammaCorrection(color * white_scale, gamma);
}
INLINE vec3 applyTonemap(Tonemapper tm, vec3 color, vec2 uv)
{
// Exposure
color *= tm.exposure;
vec3 c;
// Tonemap
switch(tm.method)
{
case eTonemapFilmic:
c = tonemapFilmic(color);
break;
case eTonemapUncharted:
c = tonemapUncharted(color, tm.gamma);
break;
default:
c = gammaCorrection(color, tm.gamma);
break;
}
//contrast
c = clamp(mix(vec3(0.5F), c, vec3(tm.contrast)), vec3(0.F), vec3(1.F));
// brighness
c = pow(c, vec3(1.0F / tm.brightness));
// saturation
vec3 i = vec3(dot(c, vec3(0.299F, 0.587F, 0.114F)));
c = mix(i, c, tm.saturation);
// vignette
vec2 center_uv = ((uv)-vec2(0.5F)) * vec2(2.0F);
c *= 1.0F - dot(center_uv, center_uv) * tm.vignette;
return c;
}
// http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
INLINE vec3 toSrgb(vec3 rgb)
{
vec3 s1 = sqrt(rgb);
vec3 s2 = sqrt(s1);
vec3 s3 = sqrt(s2);
return vec3(0.662002687F) * s1 + vec3(0.684122060F) * s2 - vec3(0.323583601F) * s3 - vec3(0.0225411470F) * rgb;
}
INLINE vec3 toLinear(vec3 srgb)
{
return srgb * (srgb * (srgb * vec3(0.305306011F) + vec3(0.682171111F)) + vec3(0.012522878F));
}
#ifdef __cplusplus
} // namespace nvvkhl_shaders
#endif
#endif // DH_TONEMAMP_H

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef FUNC_GLSL
#define FUNC_GLSL 1
#include "constants.glsl"
precision highp float;
float square(float x)
{
return x * x;
}
float saturate(float x)
{
return clamp(x, 0.0F, 1.0F);
}
vec3 saturate(vec3 x)
{
return clamp(x, vec3(0.0F), vec3(1.0F));
}
// Return the luminance of a color
float luminance(in vec3 color)
{
return color.x * 0.2126F + color.y * 0.7152F + color.z * 0.0722F;
}
vec3 slerp(vec3 a, vec3 b, float angle, float t)
{
t = saturate(t);
float sin1 = sin(angle * t);
float sin2 = sin(angle * (1.0F - t));
float ta = sin1 / (sin1 + sin2);
vec3 result = mix(a, b, ta);
return normalize(result);
}
float clampedDot(vec3 x, vec3 y)
{
return clamp(dot(x, y), 0.0F, 1.0F);
}
// Return the tangent and binormal from the incoming normal
void createCoordinateSystem(in vec3 normal, out vec3 tangent, out vec3 bitangent)
{
if(abs(normal.x) > abs(normal.y))
tangent = vec3(normal.z, 0.0F, -normal.x) / sqrt(normal.x * normal.x + normal.z * normal.z);
else
tangent = vec3(0.0F, -normal.z, normal.y) / sqrt(normal.y * normal.y + normal.z * normal.z);
bitangent = cross(normal, tangent);
}
//-----------------------------------------------------------------------
// Building an Orthonormal Basis, Revisited
// by Tom Duff, James Burgess, Per Christensen, Christophe Hery, Andrew Kensler, Max Liani, Ryusuke Villemin
// https://graphics.pixar.com/library/OrthonormalB/
//-----------------------------------------------------------------------
void orthonormalBasis(in vec3 normal, out vec3 tangent, out vec3 bitangent)
{
float sgn = normal.z > 0.0F ? 1.0F : -1.0F;
float a = -1.0F / (sgn + normal.z);
float b = normal.x * normal.y * a;
tangent = vec3(1.0f + sgn * normal.x * normal.x * a, sgn * b, -sgn * normal.x);
bitangent = vec3(b, sgn + normal.y * normal.y * a, -normal.y);
}
vec3 rotate(vec3 v, vec3 k, float theta)
{
float cos_theta = cos(theta);
float sin_theta = sin(theta);
return (v * cos_theta) + (cross(k, v) * sin_theta) + (k * dot(k, v)) * (1.0F - cos_theta);
}
//-----------------------------------------------------------------------
// Return the UV in a lat-long HDR map
//-----------------------------------------------------------------------
vec2 getSphericalUv(vec3 v)
{
float gamma = asin(-v.y);
float theta = atan(v.z, v.x);
vec2 uv = vec2(theta * M_1_OVER_PI * 0.5F, gamma * M_1_OVER_PI) + 0.5F;
return uv;
}
//-----------------------------------------------------------------------
// Return the interpolated value between 3 values and the barycentrics
//-----------------------------------------------------------------------
vec2 mixBary(vec2 a, vec2 b, vec2 c, vec3 bary)
{
return a * bary.x + b * bary.y + c * bary.z;
}
vec3 mixBary(vec3 a, vec3 b, vec3 c, vec3 bary)
{
return a * bary.x + b * bary.y + c * bary.z;
}
vec4 mixBary(vec4 a, vec4 b, vec4 c, vec3 bary)
{
return a * bary.x + b * bary.y + c * bary.z;
}
//-----------------------------------------------------------------------
// https://www.realtimerendering.com/raytracinggems/unofficial_RayTracingGems_v1.4.pdf
// 16.6.1 COSINE-WEIGHTED HEMISPHERE ORIENTED TO THE Z-AXIS
//-----------------------------------------------------------------------
vec3 cosineSampleHemisphere(float r1, float r2)
{
float r = sqrt(r1);
float phi = M_TWO_PI * r2;
vec3 dir;
dir.x = r * cos(phi);
dir.y = r * sin(phi);
dir.z = sqrt(max(0.0, 1.0 - dir.x * dir.x - dir.y * dir.y));
return dir;
}
#endif // FUNC_GLSL

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef GGX_GLSL
#define GGX_GLSL 1
#include "constants.glsl"
//-----------------------------------------------------------------------
// The following equation models the Fresnel reflectance term of the spec equation (aka F())
// Implementation of fresnel from [4], Equation 15
//-----------------------------------------------------------------------
vec3 fresnelSchlick(vec3 f0, vec3 f90, float VdotH)
{
return f0 + (f90 - f0) * pow(clamp(vec3(1.0F) - VdotH, vec3(0.0F), vec3(1.0F)), vec3(5.0F));
}
float fresnelSchlick(float f0, float f90, float VdotH)
{
return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0F, 1.0F), 5.0F);
}
//-----------------------------------------------------------------------
// Smith Joint GGX
// Note: Vis = G / (4 * NdotL * NdotV)
// see Eric Heitz. 2014. Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. Journal of Computer Graphics Techniques, 3
// see Real-Time Rendering. Page 331 to 336.
// see https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)
//-----------------------------------------------------------------------
float smithJointGGX(float NdotL, float NdotV, float alphaRoughness)
{
float alphaRoughnessSq = max(alphaRoughness * alphaRoughness, 1e-07);
float ggxV = NdotL * sqrt(NdotV * NdotV * (1.0F - alphaRoughnessSq) + alphaRoughnessSq);
float ggxL = NdotV * sqrt(NdotL * NdotL * (1.0F - alphaRoughnessSq) + alphaRoughnessSq);
float ggx = ggxV + ggxL;
if(ggx > 0.0F)
{
return 0.5F / ggx;
}
return 0.0F;
}
//-----------------------------------------------------------------------
// The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D())
// Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz
// Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3.
//-----------------------------------------------------------------------
float distributionGGX(float NdotH, float alphaRoughness) // alphaRoughness = roughness * roughness;
{
float alphaSqr = max(alphaRoughness * alphaRoughness, 1e-07);
float NdotHSqr = NdotH * NdotH;
float denom = NdotHSqr * (alphaSqr - 1.0) + 1.0;
return alphaSqr / (M_PI * denom * denom);
}
//-----------------------------------------------------------------------
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
//-----------------------------------------------------------------------
vec3 brdfLambertian(vec3 diffuseColor, float metallic)
{
return (1.0F - metallic) * (diffuseColor / M_PI);
}
//-----------------------------------------------------------------------
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
//-----------------------------------------------------------------------
vec3 brdfSpecularGGX(vec3 f0, vec3 f90, float alphaRoughness, float VdotH, float NdotL, float NdotV, float NdotH)
{
vec3 f = fresnelSchlick(f0, f90, VdotH);
float vis = smithJointGGX(NdotL, NdotV, alphaRoughness); // Vis = G / (4 * NdotL * NdotV)
float d = distributionGGX(NdotH, alphaRoughness);
return f * vis * d;
}
//-----------------------------------------------------------------------
// Sample the GGX distribution
// - Return the half vector
//-----------------------------------------------------------------------
vec3 ggxSampling(float alphaRoughness, float r1, float r2)
{
float alphaSqr = max(alphaRoughness * alphaRoughness, 1e-07);
float phi = 2.0 * M_PI * r1;
float cosTheta = sqrt((1.0 - r2) / (1.0 + (alphaSqr - 1.0) * r2));
float sinTheta = sqrt(1.0 - cosTheta * cosTheta);
return vec3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta);
}
// Return false if it produce a total internal reflection
bool refract(vec3 incident, vec3 normal, float eta, out vec3 transmitted)
{
float cosTheta = dot(incident, normal);
float k = 1.0F - eta * eta * (1.0F - cosTheta * cosTheta);
if(k < 0.0F)
{
// Total internal reflection
return false;
}
else
{
transmitted = eta * incident - (eta * cosTheta + sqrt(k)) * normal;
return true;
}
}
#endif // GGX_H

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "dh_hdr.h"
#include "constants.glsl"
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
layout(set = 0, binding = eHdrBrdf) writeonly uniform image2D gOutHdr;
layout(set = 1, binding = eHdr) uniform sampler2D gInHdr;
layout(push_constant) uniform SkyDomePushConstant_
{
HdrDomePushConstant pc;
};
vec2 getSphericalUv(vec3 v)
{
float gamma = asin(-v.y);
float theta = atan(v.z, v.x);
return vec2(theta * M_1_OVER_PI * 0.5, gamma * M_1_OVER_PI) + 0.5F;
}
vec3 rotate(vec3 v, vec3 k, float theta)
{
float cos_theta = cos(theta);
float sin_theta = sin(theta);
return (v * cos_theta) + (cross(k, v) * sin_theta) + (k * dot(k, v)) * (1.0F - cos_theta);
}
void main()
{
const vec2 pixel_center = vec2(gl_GlobalInvocationID.xy) + vec2(0.5);
const vec2 in_uv = pixel_center / vec2(imageSize(gOutHdr));
const vec2 d = in_uv * 2.0F - 1.0F;
vec3 direction = vec3(pc.mvp * vec4(d.x, d.y, 1.0F, 1.0F));
direction = rotate(direction, vec3(0.0F, 1.0F, 0.0F), -pc.rotation);
const vec2 uv = getSphericalUv(normalize(direction.xyz));
const vec3 color = texture(gInHdr, uv).rgb * pc.multColor.rgb;
imageStore(gOutHdr, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.0));
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
//-------------------------------------------------------------------------------------------------
// This file has the functions to sample the environment
#ifndef HDR_ENV_SAMPLING_GLSL
#define HDR_ENV_SAMPLING_GLSL 1
precision highp float;
#include "dh_hdr.h"
//-------------------------------------------------------------------------------------------------
// Environment Sampling (HDR)
// See: https://arxiv.org/pdf/1901.05423.pdf
//-------------------------------------------------------------------------------------------------
vec4 environmentSample(in sampler2D hdrTexture, in vec3 randVal, out vec3 toLight)
{
// Uniformly pick a texel index idx in the environment map
vec3 xi = randVal;
uvec2 tsize = uvec2(textureSize(hdrTexture, 0));
uint width = tsize.x;
uint height = tsize.y;
uint size = width * height;
uint idx = min(uint(xi.x * float(size)), size - 1U);
// Fetch the sampling data for that texel, containing the ratio q between its
// emitted radiance and the average of the environment map, the texel alias,
// the probability distribution function (PDF) values for that texel and its
// alias
EnvAccel sample_data = envSamplingData[idx];
uint env_idx;
if(xi.y < sample_data.q)
{
// If the random variable is lower than the intensity ratio q, we directly pick
// this texel, and renormalize the random variable for later use. The PDF is the
// one of the texel itself
env_idx = idx;
xi.y /= sample_data.q;
}
else
{
// Otherwise we pick the alias of the texel, renormalize the random variable and use
// the PDF of the alias
env_idx = sample_data.alias;
xi.y = (xi.y - sample_data.q) / (1.0f - sample_data.q);
}
// Compute the 2D integer coordinates of the texel
const uint px = env_idx % width;
uint py = env_idx / width;
// Uniformly sample the solid angle subtended by the pixel.
// Generate both the UV for texture lookup and a direction in spherical coordinates
const float u = float(px + xi.y) / float(width);
const float phi = u * (2.0f * M_PI) - M_PI;
float sin_phi = sin(phi);
float cos_phi = cos(phi);
const float step_theta = M_PI / float(height);
const float theta0 = float(py) * step_theta;
const float cos_theta = cos(theta0) * (1.0f - xi.z) + cos(theta0 + step_theta) * xi.z;
const float theta = acos(cos_theta);
const float sin_theta = sin(theta);
const float v = theta * M_1_OVER_PI;
// Convert to a light direction vector in Cartesian coordinates
toLight = vec3(cos_phi * sin_theta, cos_theta, sin_phi * sin_theta);
// Lookup the environment value using bilinear filtering
return texture(hdrTexture, vec2(u, v));
}
float powerHeuristic(float a, float b)
{
const float t = a * a;
return t / (b * b + t);
}
#endif // ENV_SAMPLING_GLSL

View file

@ -0,0 +1,138 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
// This shader computes a glossy BRDF map to be used with the Unreal 4 PBR shading model as
// described in
//
// "Real Shading in Unreal Engine 4" by Brian Karis
// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
//
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "dh_hdr.h"
layout(set = 0, binding = eHdrImage) writeonly uniform image2D gOutColor;
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
const float M_PI = 3.14159265359F;
// See http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
float radinv(uint bits)
{
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 hammersley2D(uint i, uint N)
{
return vec2(float(i) / float(N), radinv(i));
}
vec3 ggxSample(vec2 xi, vec3 normal, float alpha)
{
// compute half-vector in spherical coordinates
float phi = 2.0F * M_PI * xi.x;
float cos_theta = sqrt((1.0F - xi.y) / (1.0F + (alpha * alpha - 1.0F) * xi.y));
float sin_theta = sqrt(1.0F - cos_theta * cos_theta);
return vec3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta);
}
float geometrySchlickGgx(float ndotv, float roughness)
{
// note that we use a different k for IBL
float a = roughness;
float k = (a * a) / 2.0F;
float nom = ndotv;
float denom = ndotv * (1.0F - k) + k;
return nom / denom;
}
float geometrySmith(vec3 normal, vec3 view, vec3 light, float roughness)
{
float ndotv = max(dot(normal, view), 0.0F);
float ndotl = max(dot(normal, light), 0.0F);
float g1 = geometrySchlickGgx(ndotv, roughness);
float g2 = geometrySchlickGgx(ndotl, roughness);
return g1 * g2;
}
vec2 integrateBrdf(float ndotv, float roughness)
{
vec3 view;
view.x = sqrt(1.0F - ndotv * ndotv); // sin
view.y = 0.0;
view.z = ndotv;
float A = 0.0F;
float B = 0.0F;
const vec3 normal = vec3(0.0F, 0.0F, 1.0F);
const uint nsamples = 1024u;
float alpha = roughness * roughness;
for(uint i = 0u; i < nsamples; ++i)
{
vec2 xi = hammersley2D(i, nsamples);
vec3 h0 = ggxSample(xi, normal, alpha);
vec3 h = vec3(h0.y, -h0.x, h0.z);
vec3 light = normalize(2.0F * dot(view, h) * h - view);
float ndotl = max(light.z, 0.0F);
float ndoth = max(h.z, 0.0F);
float vdoth = max(dot(view, h), 0.0F);
if(ndotl > 0.0)
{
float G = geometrySmith(normal, view, light, roughness);
float G_Vis = (G * vdoth) / (ndoth * ndotv);
float Fc = pow(1.0 - vdoth, 5.0F);
A += (1.0 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(nsamples);
B /= float(nsamples);
return vec2(A, B);
}
void main()
{
const vec2 pixel_center = vec2(gl_GlobalInvocationID.xy) + vec2(0.5F);
const vec2 in_uv = pixel_center / vec2(imageSize(gOutColor));
vec2 brdf = integrateBrdf(in_uv.s, 1.0F - in_uv.t);
imageStore(gOutColor, ivec2(gl_GlobalInvocationID.xy), vec4(brdf, 0.0F, 0.0F));
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
// This shader computes a diffuse irradiance IBL map using multiple importance sampling weighted
// hemisphere sampling and environment map importance sampling.
// varying inputs
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_scalar_block_layout : enable
#include "dh_hdr.h"
#include "constants.glsl"
#include "func.glsl"
#include "random.glsl"
// clang-format off
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
layout(set = 0, binding = eHdrImage) writeonly uniform image2D gOutColor;
layout(set = 1, binding = eImpSamples, scalar) buffer _EnvAccel { EnvAccel envSamplingData[]; };
layout(set = 1, binding = eHdr) uniform sampler2D hdrTexture;
layout(push_constant) uniform HdrPushBlock_ { HdrPushBlock pc; };
// clang-format on
#include "hdr_env_sampling.glsl"
void main()
{
// Finding the world direction
const vec2 pixelCenter = vec2(gl_GlobalInvocationID.xy) + vec2(0.5F);
const vec2 inUV = pixelCenter / pc.size;
const vec2 d = inUV * 2.0F - 1.0F;
vec3 direction = vec3(pc.mvp * vec4(d.x, d.y, 1.0F, 1.0F));
// Getting axis
vec3 tangent, bitangent;
vec3 normal = normalize(vec3(direction.x, -direction.y, direction.z)); // Flipping Y
orthonormalBasis(normal, tangent, bitangent);
// Random seed
uint seed = xxhash32(uvec3(gl_GlobalInvocationID.xyz));
vec3 result = vec3(0.0f);
uint nsamples = 512u;
float inv_samples = 1.0f / float(nsamples);
for(uint i = 0u; i < nsamples; ++i)
{
// Importance sample diffuse BRDF.
{
float xi0 = (float(i) + 0.5f) * inv_samples;
float xi1 = rand(seed);
float phi = 2.0f * M_PI * xi0;
float sin_phi = sin(phi);
float cos_phi = cos(phi);
float sin_theta = sqrt(1.0f - xi1);
float cos_theta = sqrt(xi1);
vec3 d = vec3(sin_theta * cos_phi, sin_theta * sin_phi, cos_theta);
vec3 direction = d.x * tangent + d.y * bitangent + d.z * normal;
vec2 uv = getSphericalUv(direction);
float p_brdf_sqr = cos_theta * cos_theta * (M_1_OVER_PI * M_1_OVER_PI);
vec4 rad_pdf = texture(hdrTexture, uv);
float p_env = rad_pdf.a;
float w = p_brdf_sqr / (p_brdf_sqr + p_env * p_env);
result += rad_pdf.rgb * w * M_PI;
}
// Importance sample environment.
{
vec3 dir;
vec3 rand_val = vec3(rand(seed), rand(seed), rand(seed));
vec4 rad_pdf = environmentSample(hdrTexture, rand_val, dir);
float pdf = rad_pdf.a;
vec3 value = rad_pdf.rgb / pdf;
float cosine = dot(dir, normal);
float p_brdf_sqr = cosine * cosine * (M_1_OVER_PI * M_1_OVER_PI);
float p_env_sqr = pdf * pdf;
if(cosine > 0.0f)
{
float w = p_env_sqr / (p_env_sqr + p_brdf_sqr);
result += w * value * cosine;
}
}
}
vec4 frag_color = vec4(result * (1.0f / float(nsamples)) / M_PI, 1.0f);
imageStore(gOutColor, ivec2(gl_GlobalInvocationID.xy), frag_color);
}

View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
// This shader computes a glossy IBL map to be used with the Unreal 4 PBR shading model as
// described in
//
// "Real Shading in Unreal Engine 4" by Brian Karis
// http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
//
// As an extension to the original it uses multiple importance sampling weighted BRDF importance
// sampling and environment map importance sampling to yield good results for high dynamic range
// lighting.
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#extension GL_EXT_scalar_block_layout : enable
#include "dh_hdr.h"
// clang-format off
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
layout(set = 0, binding = eHdrImage) writeonly uniform image2D g_outColor;
layout(set = 1, binding = eImpSamples, scalar) buffer _EnvAccel { EnvAccel envSamplingData[]; };
layout(set = 1, binding = eHdr) uniform sampler2D hdrTexture;
layout(push_constant) uniform HdrPushBlock_ { HdrPushBlock pc; };
// clang-format on
#include "constants.glsl"
#include "func.glsl"
#include "random.glsl"
#include "hdr_env_sampling.glsl"
// Importance sample a GGX microfacet distribution.
vec3 ggxSample(vec2 xi, float alpha)
{
float phi = 2.0F * M_PI * xi.x;
float cos_theta = sqrt((1.0F - xi.y) / (1.0F + (alpha * alpha - 1.0F) * xi.y));
float sin_theta = sqrt(1.0F - cos_theta * cos_theta);
return vec3(cos(phi) * sin_theta, sin(phi) * sin_theta, cos_theta);
}
// Evaluate a GGX microfacet distribution.
float ggxEval(float alpha, float nh)
{
float a2 = alpha * alpha;
float nh2 = nh * nh;
float tan2 = (1.0f - nh2) / nh2;
float f = a2 + tan2;
return a2 / (f * f * M_PI * nh2 * nh);
}
struct EnvmapSampleValue
{
vec3 dir;
vec3 value;
float pdf;
};
void main()
{
const vec2 pixel_center = vec2(gl_GlobalInvocationID.xy) + vec2(0.5F);
const vec2 in_uv = pixel_center / vec2(pc.size);
const vec2 d = in_uv * 2.0F - 1.0F;
vec3 direction = vec3(pc.mvp * vec4(d.x, d.y, 1.0F, 1.0F));
vec3 tangent, bitangent;
vec3 normal = normalize(vec3(direction.x, -direction.y, direction.z)); // Flipping Y
orthonormalBasis(normal, tangent, bitangent);
float alpha = pc.roughness;
uint nsamples = alpha > 0.0F ? 512u : 1u;
uint state = xxhash32(uvec3(gl_GlobalInvocationID.xy, pc.roughness * 10.0F));
// The integrals are additionally weighted by the cosine and normalized using the average cosine of
// the importance sampled BRDF directions (as in the Unreal publication).
float weight_sum = 0.0f;
vec3 result = vec3(0.0F);
float inv_nsamples = 1.0F / float(nsamples);
for(uint i = 0u; i < nsamples; ++i)
{
// Importance sample BRDF.
{
float xi0 = (float(i) + 0.5F) * inv_nsamples;
float xi1 = rand(state);
vec3 h0 = alpha > 0.0f ? ggxSample(vec2(xi0, xi1), alpha) : vec3(0.0F, 0.0F, 1.0F);
vec3 h = tangent * h0.x + bitangent * h0.y + normal * h0.z;
vec3 direction = normalize(2.0 * dot(normal, h) * h - normal);
float cos_theta = dot(normal, direction);
if(cos_theta > 0.0F)
{
vec2 uv = getSphericalUv(direction);
float w = 1.0F;
if(alpha > 0.0F)
{
float pdf_brdf_sqr = ggxEval(alpha, h0.z) * 0.25F / dot(direction, h);
pdf_brdf_sqr *= pdf_brdf_sqr;
float pdf_env = texture(hdrTexture, uv).a;
w = pdf_brdf_sqr / (pdf_brdf_sqr + pdf_env * pdf_env);
}
result += w * texture(hdrTexture, uv).rgb * cos_theta;
weight_sum += cos_theta;
}
}
// Importance sample environment.
if(alpha > 0.0f)
{
vec3 randVal = vec3(rand(state), rand(state), rand(state));
EnvmapSampleValue val;
vec4 radPdf = environmentSample(hdrTexture, randVal, val.dir);
val.pdf = radPdf.a;
val.value = radPdf.rgb / val.pdf;
vec3 h = normalize(normal + val.dir);
float nh = dot(h, normal);
float kh = dot(val.dir, h);
float nk = dot(val.dir, normal);
if(kh > 0.0F && nh > 0.0F && nk > 0.0F)
{
float pdf_env_sqr = val.pdf * val.pdf;
float pdf_brdf = ggxEval(alpha, nh) * 0.25F / kh;
float w = pdf_env_sqr / (pdf_env_sqr + pdf_brdf * pdf_brdf);
result += w * val.value * pdf_brdf * nk * nk;
}
}
}
vec4 result_color = vec4(result / float(weight_sum), 1.0F);
imageStore(g_outColor, ivec2(gl_GlobalInvocationID.xy), result_color);
}

View file

@ -0,0 +1,118 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef LIGHT_CONTRIB_H
#define LIGHT_CONTRIB_H 1
#include "func.glsl"
#include "dh_lighting.h"
LightContrib singleLightContribution(in Light light, in vec3 surfacePos, in vec3 surfaceNormal, in vec3 viewIncident, in vec2 randVal)
{
LightContrib contrib;
contrib.incidentVector = vec3(0.0F);
contrib.halfAngularSize = 0.0F;
contrib.intensity = vec3(0.0F);
float irradiance = 0.0F;
if(light.type == eLightTypeDirectional)
{
contrib.incidentVector = light.direction;
contrib.halfAngularSize = light.angularSizeOrInvRange * 0.5F;
irradiance = light.intensity;
}
else if(light.type == eLightTypeSpot || light.type == eLightTypePoint)
{
vec3 light_to_surface = surfacePos - light.position;
float distance = sqrt(dot(light_to_surface, light_to_surface));
float r_distance = 1.0F / distance;
contrib.incidentVector = light_to_surface * r_distance;
float attenuation = 1.F;
if(light.angularSizeOrInvRange > 0.0F)
{
attenuation = square(saturate(1.0F - square(square(distance * light.angularSizeOrInvRange))));
if(attenuation == 0.0F)
return contrib;
}
float spotlight = 1.0F;
if(light.type == eLightTypeSpot)
{
float lDotD = dot(contrib.incidentVector, light.direction);
float direction_angle = acos(lDotD);
spotlight = 1.0F - smoothstep(light.innerAngle, light.outerAngle, direction_angle);
if(spotlight == 0.0F)
return contrib;
}
if(light.radius > 0.0F)
{
contrib.halfAngularSize = atan(min(light.radius * r_distance, 1.0F));
// A good enough approximation for 2 * (1 - cos(halfAngularSize)), numerically more accurate for small angular sizes
float solidAngleOverPi = square(contrib.halfAngularSize);
float radianceTimesPi = light.intensity / square(light.radius);
irradiance = radianceTimesPi * solidAngleOverPi;
}
else
{
irradiance = light.intensity * square(r_distance);
}
irradiance *= spotlight * attenuation;
}
contrib.intensity = irradiance * light.color;
if(contrib.halfAngularSize > 0.0F)
{ // <----- Sampling area lights
float angular_size = contrib.halfAngularSize;
// section 34 https://people.cs.kuleuven.be/~philip.dutre/GI/TotalCompendium.pdf
vec3 dir;
float tmp = (1.0F - randVal.y * (1.0F - cos(angular_size)));
float tmp2 = tmp * tmp;
float tetha = sqrt(1.0F - tmp2);
dir.x = cos(M_TWO_PI * randVal.x) * tetha;
dir.y = sin(M_TWO_PI * randVal.x) * tetha;
dir.z = tmp;
vec3 light_dir = -contrib.incidentVector;
vec3 tangent, binormal;
orthonormalBasis(light_dir, tangent, binormal);
mat3 tbn = mat3(tangent, binormal, light_dir);
light_dir = normalize(tbn * dir);
contrib.incidentVector = -light_dir;
}
return contrib;
}
// Version without random values
LightContrib singleLightContribution(in Light light, in vec3 surfacePos, in vec3 surfaceNormal, in vec3 viewIncident)
{
return singleLightContribution(light, surfacePos, surfaceNormal, viewIncident, vec2(0.0F));
}
#endif

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
layout(location = 0) out vec2 outUv;
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
gl_Position = vec4(outUv * 2.0f - 1.0f, 1.0f, 1.0f);
}

View file

@ -0,0 +1,195 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
//-------------------------------------------------------------------------------------------------
// This file takes the incoming GltfShadeMaterial (material uploaded in a buffer) and
// evaluates it, basically sample the textures and return the struct PbrMaterial
// which is used by the Bsdf functions to evaluate and sample the material
//
#ifndef MAT_EVAL_H
#define MAT_EVAL_H 1
#include "pbr_mat_struct.h"
// This is the list of all textures
#ifndef MAT_EVAL_TEXTURE_ARRAY
#define MAT_EVAL_TEXTURE_ARRAY texturesMap
#endif
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// MATERIAL FOR EVALUATION
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
const float g_min_reflectance = 0.04F;
//-----------------------------------------------------------------------
// sRGB to linear approximation, see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
vec4 srgbToLinear(in vec4 sRgb)
{
//return vec4(pow(sRgb.xyz, vec3(2.2f)), sRgb.w);
vec3 rgb = sRgb.xyz * (sRgb.xyz * (sRgb.xyz * 0.305306011F + 0.682171111F) + 0.012522878F);
return vec4(rgb, sRgb.a);
}
//-----------------------------------------------------------------------
// From the incoming material return the material for evaluating PBR
//-----------------------------------------------------------------------
PbrMaterial evaluateMaterial(in GltfShadeMaterial material, in vec3 normal, in vec3 tangent, in vec3 bitangent, in vec2 texCoord, in bool isInside)
{
float perceptual_roughness = 0.0F;
float metallic = 0.0F;
vec3 f0 = vec3(0.0F);
vec3 f90 = vec3(1.0F);
vec4 baseColor = vec4(0.0F, 0.0F, 0.0F, 1.0F);
// KHR_texture_transform
texCoord = vec2(vec3(texCoord, 1) * material.uvTransform);
// Normal Map
if(material.normalTexture > -1)
{
mat3 tbn = mat3(tangent, bitangent, normal);
vec3 normal_vector = texture(MAT_EVAL_TEXTURE_ARRAY[nonuniformEXT(material.normalTexture)], texCoord).xyz;
normal_vector = normal_vector * 2.0F - 1.0F;
normal_vector *= vec3(material.normalTextureScale, material.normalTextureScale, 1.0F);
normal = normalize(tbn * normal_vector);
}
// Metallic-Roughness
{
perceptual_roughness = material.pbrRoughnessFactor;
metallic = material.pbrMetallicFactor;
if(material.pbrMetallicRoughnessTexture > -1.0F)
{
// Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel.
vec4 mr_sample = texture(MAT_EVAL_TEXTURE_ARRAY[nonuniformEXT(material.pbrMetallicRoughnessTexture)], texCoord);
perceptual_roughness *= mr_sample.g;
metallic *= mr_sample.b;
}
// The albedo may be defined from a base texture or a flat color
baseColor = material.pbrBaseColorFactor;
if(material.pbrBaseColorTexture > -1.0F)
{
baseColor *= texture(MAT_EVAL_TEXTURE_ARRAY[nonuniformEXT(material.pbrBaseColorTexture)], texCoord);
}
vec3 specular_color = mix(vec3(g_min_reflectance), vec3(baseColor), float(metallic));
f0 = specular_color;
}
// Protection
metallic = clamp(metallic, 0.0F, 1.0F);
// Emissive term
vec3 emissive = material.emissiveFactor;
if(material.emissiveTexture > -1.0F)
{
emissive *= vec3(texture(MAT_EVAL_TEXTURE_ARRAY[material.emissiveTexture], texCoord));
}
// KHR_materials_specular
// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular
vec4 specularColorTexture = vec4(1.0F);
if(material.specularColorTexture > -1)
{
specularColorTexture = textureLod(texturesMap[nonuniformEXT(material.specularColorTexture)], texCoord, 0);
}
float specularTexture = 1.0F;
if(material.specularTexture > -1)
{
specularTexture = textureLod(texturesMap[nonuniformEXT(material.specularTexture)], texCoord, 0).a;
}
// Dielectric Specular
float ior1 = 1.0F;
float ior2 = material.ior;
if(isInside)
{
ior1 = material.ior;
ior2 = 1.0F;
}
float iorRatio = ((ior1 - ior2) / (ior1 + ior2));
float iorRatioSqr = iorRatio * iorRatio;
vec3 dielectricSpecularF0 = material.specularColorFactor * specularColorTexture.rgb;
float dielectricSpecularF90 = material.specularFactor * specularTexture;
f0 = mix(min(iorRatioSqr * dielectricSpecularF0, vec3(1.0F)) * dielectricSpecularF0, baseColor.rgb, metallic);
f90 = vec3(mix(dielectricSpecularF90, 1.0F, metallic));
// Material Evaluated
PbrMaterial pbrMat;
pbrMat.albedo = baseColor;
pbrMat.f0 = f0;
pbrMat.f90 = f90;
pbrMat.roughness = perceptual_roughness;
pbrMat.metallic = metallic;
pbrMat.emissive = max(vec3(0.0F), emissive);
pbrMat.normal = normal;
pbrMat.eta = (material.thicknessFactor == 0.0F) ? 1.0F : ior1 / ior2;
// KHR_materials_transmission
pbrMat.transmissionFactor = material.transmissionFactor;
if(material.transmissionTexture > -1)
{
pbrMat.transmissionFactor *= textureLod(texturesMap[nonuniformEXT(material.transmissionTexture)], texCoord, 0).r;
}
// KHR_materials_ior
pbrMat.ior = material.ior;
// KHR_materials_volume
pbrMat.attenuationColor = material.attenuationColor;
pbrMat.attenuationDistance = material.attenuationDistance;
pbrMat.thicknessFactor = material.thicknessFactor;
// KHR_materials_clearcoat
pbrMat.clearcoatFactor = material.clearcoatFactor;
pbrMat.clearcoatRoughness = material.clearcoatRoughness;
if(material.clearcoatTexture > -1)
{
pbrMat.clearcoatFactor *= textureLod(texturesMap[nonuniformEXT(material.clearcoatTexture)], texCoord, 0).r;
}
if(material.clearcoatRoughnessTexture > -1)
{
pbrMat.clearcoatRoughness *= textureLod(texturesMap[nonuniformEXT(material.clearcoatRoughnessTexture)], texCoord, 0).g;
}
pbrMat.clearcoatRoughness = max(pbrMat.clearcoatRoughness, 0.001F);
return pbrMat;
}
PbrMaterial evaluateMaterial(in GltfShadeMaterial material, in vec3 normal, in vec3 tangent, in vec3 bitangent, in vec2 texCoord)
{
return evaluateMaterial(material, normal, tangent, bitangent, texCoord, false);
}
#endif // MAT_EVAL_H

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
/// @DOC_SKIP
#ifndef PBR_MAT_STRUCT_H
#define PBR_MAT_STRUCT_H 1
struct PbrMaterial
{
vec4 albedo; // base color
float roughness; // 0 = smooth, 1 = rough
float metallic; // 0 = dielectric, 1 = metallic
vec3 normal; // shading normal
vec3 emissive; // emissive color
vec3 f0; // full reflectance color (n incidence angle)
vec3 f90; // reflectance color at grazing angle
float eta; // index of refraction
float specularWeight; // product of specularFactor and specularTexture.a
float transmissionFactor; // KHR_materials_transmission
float ior; // KHR_materials_ior
vec3 attenuationColor; // KHR_materials_volume
float attenuationDistance; // KHR_materials_volume
float thicknessFactor; // KHR_materials_volume
float clearcoatFactor; // KHR_materials_clearcoat
float clearcoatRoughness; // KHR_materials_clearcoat
vec3 clearcoatNormal; // KHR_materials_clearcoat
};
#endif

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef RANDOM_GLSL
#define RANDOM_GLSL 1
precision highp float;
// Generate a seed for the random generator.
// Input - pixel.x, pixel.y, frame_nb
// From https://github.com/Cyan4973/xxHash, https://www.shadertoy.com/view/XlGcRh
uint xxhash32(uvec3 p)
{
const uvec4 primes = uvec4(2246822519U, 3266489917U, 668265263U, 374761393U);
uint h32;
h32 = p.z + primes.w + p.x * primes.y;
h32 = primes.z * ((h32 << 17) | (h32 >> (32 - 17)));
h32 += p.y * primes.y;
h32 = primes.z * ((h32 << 17) | (h32 >> (32 - 17)));
h32 = primes.x * (h32 ^ (h32 >> 15));
h32 = primes.y * (h32 ^ (h32 >> 13));
return h32 ^ (h32 >> 16);
}
//-----------------------------------------------------------------------
// https://www.pcg-random.org/
//-----------------------------------------------------------------------
uint pcg(inout uint state)
{
uint prev = state * 747796405u + 2891336453u;
uint word = ((prev >> ((prev >> 28u) + 4u)) ^ prev) * 277803737u;
state = prev;
return (word >> 22u) ^ word;
}
//-----------------------------------------------------------------------
// Generate a random float in [0, 1) given the previous RNG state
//-----------------------------------------------------------------------
float rand(inout uint seed)
{
uint r = pcg(seed);
return float(r) * (1.F / float(0xffffffffu));
}
#endif // RANDOM_GLSL

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef RAY_UTIL_H
#define RAY_UTIL_H 1
precision highp float;
//-------------------------------------------------------------------------------------------------
// Avoiding self intersections
//-----------------------------------------------------------------------
vec3 offsetRay(in vec3 p, in vec3 n)
{
// Smallest epsilon that can be added without losing precision is 1.19209e-07, but we play safe
const float epsilon = 1.0f / 65536.0f; // Safe epsilon
float magnitude = length(p);
float offset = epsilon * magnitude;
// multiply the direction vector by the smallest offset
vec3 offsetVector = n * offset;
// add the offset vector to the starting point
vec3 offsetPoint = p + offsetVector;
return offsetPoint;
}
// Hacking the shadow terminator
// https://jo.dreggn.org/home/2021_terminator.pdf
// p : point of intersection
// p[a..c]: position of the triangle
// n[a..c]: normal of the triangle
// bary: barycentric coordinate of the hit position
// return the offset position
vec3 pointOffset(vec3 p, vec3 pa, vec3 pb, vec3 pc, vec3 na, vec3 nb, vec3 nc, vec3 bary)
{
vec3 tmpu = p - pa;
vec3 tmpv = p - pb;
vec3 tmpw = p - pc;
float dotu = min(0.0F, dot(tmpu, na));
float dotv = min(0.0F, dot(tmpv, nb));
float dotw = min(0.0F, dot(tmpw, nc));
tmpu -= dotu * na;
tmpv -= dotv * nb;
tmpw -= dotw * nc;
vec3 pP = p + tmpu * bary.x + tmpv * bary.y + tmpw * bary.z;
return pP;
}
#endif

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2022 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
#extension GL_GOOGLE_include_directive : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int8 : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int16 : enable
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require
#include "dh_sky.h"
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
layout(set = 0, binding = eSkyOutImage) writeonly uniform image2D g_out_hdr;
layout(set = 0, binding = eSkyParam) uniform SkyInfo_
{
ProceduralSkyShaderParameters skyInfo;
};
layout(push_constant) uniform SkyDomePushConstant_
{
SkyPushConstant pc;
};
void main()
{
const vec2 pixel_center = vec2(gl_GlobalInvocationID.xy) + vec2(0.5F);
const vec2 in_uv = pixel_center / vec2(imageSize(g_out_hdr));
const vec2 d = in_uv * 2.0 - 1.0;
vec3 direction = normalize(vec3(pc.mvp * vec4(d.x, d.y, 1.0F, 1.0F)));
vec3 color = proceduralSky(skyInfo, direction, 0.0F);
imageStore(g_out_hdr, ivec2(gl_GlobalInvocationID.xy), vec4(color, 1.0F));
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "dh_tonemap.h"
#include "dh_comp.h"
layout(set = 0, binding = eTonemapperInput) uniform sampler2D g_image;
layout(set = 0, binding = eTonemapperOutput) writeonly uniform image2D g_out_image;
layout(push_constant) uniform shaderInformation
{
Tonemapper tm;
};
layout(local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1) in;
void main()
{
if(gl_GlobalInvocationID.xy != clamp(gl_GlobalInvocationID.xy, vec2(0.0F), imageSize(g_out_image)))
return;
const vec2 pixel_center = vec2(gl_GlobalInvocationID.xy) + vec2(0.5F);
const vec2 i_uv = pixel_center / vec2(imageSize(g_out_image));
vec4 R = texture(g_image, i_uv);
if(tm.isActive == 1)
R.xyz = applyTonemap(tm, R.xyz, i_uv);
R.a = 1.0F; // No alpha, or it will blend with ImGui black viewport
imageStore(g_out_image, ivec2(gl_GlobalInvocationID.xy), R);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION
* SPDX-License-Identifier: Apache-2.0
*/
#version 450
#extension GL_GOOGLE_include_directive : enable
#include "dh_tonemap.h"
layout(location = 0) in vec2 i_uv;
layout(location = 0) out vec4 o_color;
layout(set = 0, binding = eTonemapperInput) uniform sampler2D g_image;
layout(push_constant) uniform shaderInformation
{
Tonemapper tm;
};
void main()
{
vec4 R = texture(g_image, i_uv);
if(tm.isActive == 1)
R.xyz = applyTonemap(tm, R.xyz, i_uv);
o_color = R;
}