Add GTAO shader support (#8688)
* Add GTAO options into the struct * Add gtao mat and shader * Set type specific parameters in ppm * Fix inconsistent name * Fix incorrect param type * Add bent normal calculation * Fix the gui * Adjust precision * Use mix * Add some comments * Refactoring * Update comments * Add comments for aoOptions * Update * Update * Address the comments * Split .mat into bent and non-bent * Update * Update * Use sqrt on mobile * Omit default case * Commit beamsplitter generated changes * Use built-in acosFast * Remove unused function * Fix the mismatched parameter type * Some optimizations * Commit beamsplitter results * Update the comment * Update default value * Commit beamsplitter changes * Extract common parameters out
This commit is contained in:
@@ -1801,6 +1801,22 @@ public class View {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
public static class AmbientOcclusionOptions {
|
||||
public enum AmbientOcclusionType {
|
||||
/**
|
||||
* use Scalable Ambient Occlusion
|
||||
*/
|
||||
SAO,
|
||||
/**
|
||||
* use Ground Truth-Based Ambient Occlusion
|
||||
*/
|
||||
GTAO,
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of ambient occlusion algorithm.
|
||||
*/
|
||||
@NonNull
|
||||
public AmbientOcclusionOptions.AmbientOcclusionType aoType = AmbientOcclusionOptions.AmbientOcclusionType.SAO;
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
@@ -1810,7 +1826,8 @@ public class View {
|
||||
*/
|
||||
public float power = 1.0f;
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
*/
|
||||
public float bias = 0.0005f;
|
||||
/**
|
||||
@@ -1826,12 +1843,12 @@ public class View {
|
||||
*/
|
||||
public float bilateralThreshold = 0.05f;
|
||||
/**
|
||||
* affects # of samples used for AO.
|
||||
* affects # of samples used for AO and params for filtering
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel quality = QualityLevel.LOW;
|
||||
/**
|
||||
* affects AO smoothness
|
||||
* affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
*/
|
||||
@NonNull
|
||||
public QualityLevel lowPassFilter = QualityLevel.MEDIUM;
|
||||
@@ -1849,7 +1866,7 @@ public class View {
|
||||
*/
|
||||
public boolean bentNormals = false;
|
||||
/**
|
||||
* min angle in radian to consider
|
||||
* min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
*/
|
||||
public float minHorizonAngleRad = 0.0f;
|
||||
/**
|
||||
@@ -1904,6 +1921,19 @@ public class View {
|
||||
*/
|
||||
public boolean ssctEnabled = false;
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleSliceCount = 4;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public int gtaoSampleStepsPerSlice = 3;
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
public float gtaoThicknessHeuristic = 0.004f;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,6 +262,8 @@ set(MATERIAL_SRCS
|
||||
src/materials/ssao/mipmapDepth.mat
|
||||
src/materials/ssao/sao.mat
|
||||
src/materials/ssao/saoBentNormals.mat
|
||||
src/materials/ssao/gtao.mat
|
||||
src/materials/ssao/gtaoBentNormals.mat
|
||||
src/materials/vsmMipmap.mat
|
||||
)
|
||||
|
||||
@@ -461,6 +463,28 @@ add_custom_command(
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/gtao.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
DEPENDS src/materials/ssao/ssct.fs
|
||||
DEPENDS src/materials/utils/depthUtils.fs
|
||||
DEPENDS src/materials/utils/geometry.fs
|
||||
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/gtaoBentNormals.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
DEPENDS src/materials/ssao/ssct.fs
|
||||
DEPENDS src/materials/utils/depthUtils.fs
|
||||
DEPENDS src/materials/utils/geometry.fs
|
||||
DEPENDS src/materials/ssao/gtaoImpl.fs
|
||||
DEPENDS src/materials/ssao/ssctImpl.fs
|
||||
APPEND
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${MATERIAL_DIR}/bilateralBlur.filamat"
|
||||
DEPENDS src/materials/ssao/ssaoUtils.fs
|
||||
|
||||
@@ -373,18 +373,30 @@ struct RenderQuality {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
struct AmbientOcclusionOptions {
|
||||
enum class AmbientOcclusionType : uint8_t {
|
||||
SAO, //!< use Scalable Ambient Occlusion
|
||||
GTAO, //!< use Ground Truth-Based Ambient Occlusion
|
||||
};
|
||||
|
||||
AmbientOcclusionType aoType = AmbientOcclusionType::SAO;//!< Type of ambient occlusion algorithm.
|
||||
float radius = 0.3f; //!< Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
float power = 1.0f; //!< Controls ambient occlusion's contrast. Must be positive.
|
||||
float bias = 0.0005f; //!< Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
*/
|
||||
float bias = 0.0005f;
|
||||
|
||||
float resolution = 0.5f;//!< How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0.
|
||||
float intensity = 1.0f; //!< Strength of the Ambient Occlusion effect.
|
||||
float bilateralThreshold = 0.05f; //!< depth distance that constitute an edge for filtering
|
||||
QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO.
|
||||
QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness
|
||||
QualityLevel quality = QualityLevel::LOW; //!< affects # of samples used for AO and params for filtering
|
||||
QualityLevel lowPassFilter = QualityLevel::MEDIUM; //!< affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
QualityLevel upsampling = QualityLevel::LOW; //!< affects AO buffer upsampling quality
|
||||
bool enabled = false; //!< enables or disables screen-space ambient occlusion
|
||||
bool bentNormals = false; //!< enables bent normals computation from AO, and specular AO
|
||||
float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider
|
||||
float minHorizonAngleRad = 0.0f; //!< min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
/**
|
||||
* Screen Space Cone Tracing (SSCT) options
|
||||
* Ambient shadows from dominant light
|
||||
@@ -402,6 +414,16 @@ struct AmbientOcclusionOptions {
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
};
|
||||
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
struct Gtao {
|
||||
uint8_t sampleSliceCount = 4; //!< # of slices. Higher value makes less noise.
|
||||
uint8_t sampleStepsPerSlice = 3; //!< # of steps the radius is divided into for integration. Higher value makes less bias.
|
||||
float thicknessHeuristic = 0.004f; //!< thickness heuristic, should be closed to 0
|
||||
};
|
||||
Gtao gtao; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -100,7 +100,9 @@ using namespace backend;
|
||||
static constexpr uint8_t kMaxBloomLevels = 12u;
|
||||
static_assert(kMaxBloomLevels >= 3, "We require at least 3 bloom levels");
|
||||
|
||||
constexpr static float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
namespace {
|
||||
|
||||
constexpr float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
// skipping a bunch of entries makes the average of the sequence closer to 0.5
|
||||
i += 409;
|
||||
float f = 1.0f;
|
||||
@@ -113,6 +115,19 @@ constexpr static float halton(unsigned int i, unsigned int const b) noexcept {
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void setConstantParameter(FMaterial* const material, std::string_view const name,
|
||||
ValueType value, bool& dirty) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
PostProcessManager::PostProcessMaterial::PostProcessMaterial(StaticMaterialInfo const& info) noexcept
|
||||
@@ -289,6 +304,8 @@ static const PostProcessManager::StaticMaterialInfo sMaterialList[] = {
|
||||
{ "mipmapDepth", MATERIAL(MIPMAPDEPTH) },
|
||||
{ "sao", MATERIAL(SAO) },
|
||||
{ "saoBentNormals", MATERIAL(SAOBENTNORMALS) },
|
||||
{ "gtao", MATERIAL(GTAO) },
|
||||
{ "gtaoBentNormals", MATERIAL(GTAOBENTNORMALS) },
|
||||
{ "separableGaussianBlur1", MATERIAL(SEPARABLEGAUSSIANBLUR),
|
||||
{ {"arraySampler", false}, {"componentCount", 1} } },
|
||||
{ "separableGaussianBlur1L", MATERIAL(SEPARABLEGAUSSIANBLUR),
|
||||
@@ -846,12 +863,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
0.5f * cameraInfo.projection[0].x * desc.width,
|
||||
0.5f * cameraInfo.projection[1].y * desc.height);
|
||||
|
||||
// Where the falloff function peaks
|
||||
const float peak = 0.1f * options.radius;
|
||||
const float intensity = (f::TAU * peak) * options.intensity;
|
||||
// always square AO result, as it looks much better
|
||||
const float power = options.power * 2.0f;
|
||||
|
||||
const auto invProjection = inverse(cameraInfo.projection);
|
||||
const float inc = (1.0f / (sampleCount - 0.5f)) * spiralTurns * f::TAU;
|
||||
|
||||
@@ -862,40 +873,75 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
}};
|
||||
|
||||
auto& material = computeBentNormals ?
|
||||
getPostProcessMaterial("saoBentNormals") :
|
||||
getPostProcessMaterial("sao");
|
||||
FMaterial const* const ma = material.getMaterial(mEngine);
|
||||
std::string_view materialName;
|
||||
if (options.aoType ==
|
||||
AmbientOcclusionOptions::AmbientOcclusionType::GTAO) {
|
||||
materialName = computeBentNormals ? "gtaoBentNormals" : "gtao";
|
||||
} else {
|
||||
materialName = computeBentNormals ? "saoBentNormals" : "sao";
|
||||
}
|
||||
|
||||
auto& material = getPostProcessMaterial(materialName);
|
||||
|
||||
FMaterial const * const ma = material.getMaterial(mEngine);
|
||||
FMaterialInstance* const mi = PostProcessMaterial::getMaterialInstance(ma);
|
||||
mi->setParameter("depth", depth, {
|
||||
.filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
|
||||
// Set AO type specific material parameters
|
||||
switch (options.aoType) {
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::SAO: {
|
||||
// Where the falloff function peaks
|
||||
const float peak = 0.1f * options.radius;
|
||||
const float intensity = (f::TAU * peak) * options.intensity;
|
||||
|
||||
// always square AO result, as it looks much better
|
||||
const float power = options.power * 2.0f;
|
||||
|
||||
mi->setParameter("minHorizonAngleSineSquared",
|
||||
std::pow(std::sin(options.minHorizonAngleRad), 2.0f));
|
||||
mi->setParameter("intensity", intensity / sampleCount);
|
||||
mi->setParameter("power", power);
|
||||
mi->setParameter("peak2", peak * peak);
|
||||
mi->setParameter("bias", options.bias);
|
||||
mi->setParameter("sampleCount",
|
||||
float2{ sampleCount, 1.0f / (sampleCount - 0.5f) });
|
||||
mi->setParameter("spiralTurns", spiralTurns);
|
||||
mi->setParameter("angleIncCosSin", float2{ std::cos(inc), std::sin(inc) });
|
||||
break;
|
||||
}
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::GTAO: {
|
||||
const auto sliceCount = static_cast<float>(options.gtao.sampleSliceCount);
|
||||
mi->setParameter("stepsPerSlice",
|
||||
static_cast<float>(options.gtao.sampleStepsPerSlice));
|
||||
mi->setParameter("sliceCount",
|
||||
float2{ sliceCount, 1.0f / sliceCount });
|
||||
mi->setParameter("power", options.power);
|
||||
mi->setParameter("radius", options.radius);
|
||||
mi->setParameter("intensity", options.intensity);
|
||||
mi->setParameter("thicknessHeuristic", options.gtao.thicknessHeuristic);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set common material parameters
|
||||
mi->setParameter("invRadiusSquared", 1.0f / (options.radius * options.radius));
|
||||
mi->setParameter("depth", depth,
|
||||
{ .filterMin = SamplerMinFilter::NEAREST_MIPMAP_NEAREST });
|
||||
mi->setParameter("screenFromViewMatrix",
|
||||
mat4f(screenFromClipMatrix * cameraInfo.projection));
|
||||
mi->setParameter("resolution",
|
||||
float4{ desc.width, desc.height, 1.0f / desc.width, 1.0f / desc.height });
|
||||
mi->setParameter("invRadiusSquared",
|
||||
1.0f / (options.radius * options.radius));
|
||||
mi->setParameter("minHorizonAngleSineSquared",
|
||||
std::pow(std::sin(options.minHorizonAngleRad), 2.0f));
|
||||
mi->setParameter("projectionScale",
|
||||
projectionScale);
|
||||
mi->setParameter("projectionScaleRadius",
|
||||
projectionScale * options.radius);
|
||||
mi->setParameter("positionParams", float2{
|
||||
invProjection[0][0], invProjection[1][1] } * 2.0f);
|
||||
mi->setParameter("peak2", peak * peak);
|
||||
mi->setParameter("bias", options.bias);
|
||||
mi->setParameter("power", power);
|
||||
mi->setParameter("intensity", intensity / sampleCount);
|
||||
mi->setParameter("projectionScale", projectionScale);
|
||||
mi->setParameter("projectionScaleRadius", projectionScale * options.radius);
|
||||
mi->setParameter("positionParams",
|
||||
float2{ invProjection[0][0], invProjection[1][1] } * 2.0f);
|
||||
mi->setParameter("maxLevel", uint32_t(levelCount - 1));
|
||||
mi->setParameter("sampleCount", float2{ sampleCount, 1.0f / (sampleCount - 0.5f) });
|
||||
mi->setParameter("spiralTurns", spiralTurns);
|
||||
mi->setParameter("angleIncCosSin", float2{ std::cos(inc), std::sin(inc) });
|
||||
mi->setParameter("invFarPlane", 1.0f / -cameraInfo.zf);
|
||||
|
||||
mi->setParameter("ssctShadowDistance", options.ssct.shadowDistance);
|
||||
mi->setParameter("ssctConeAngleTangeant", std::tan(options.ssct.lightConeRad * 0.5f));
|
||||
mi->setParameter("ssctContactDistanceMaxInv", 1.0f / options.ssct.contactDistanceMax);
|
||||
mi->setParameter("ssctConeAngleTangeant",
|
||||
std::tan(options.ssct.lightConeRad * 0.5f));
|
||||
mi->setParameter("ssctContactDistanceMaxInv",
|
||||
1.0f / options.ssct.contactDistanceMax);
|
||||
// light direction in view space
|
||||
const mat4f view{ cameraInfo.getUserViewMatrix() };
|
||||
const float3 l = normalize(
|
||||
@@ -2632,25 +2678,15 @@ void PostProcessManager::configureTemporalAntiAliasingMaterial(
|
||||
FMaterial* const ma = getPostProcessMaterial("taa").getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
auto setConstantParameter =
|
||||
[&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling);
|
||||
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection);
|
||||
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory);
|
||||
setConstantParameter(ma, "filterInput", taaOptions.filterInput);
|
||||
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg);
|
||||
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering);
|
||||
setConstantParameter(ma, "boxType", int32_t(taaOptions.boxType));
|
||||
setConstantParameter(ma, "boxClipping", int32_t(taaOptions.boxClipping));
|
||||
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma);
|
||||
setConstantParameter(ma, "upscaling", taaOptions.upscaling, dirty);
|
||||
setConstantParameter(ma, "historyReprojection", taaOptions.historyReprojection, dirty);
|
||||
setConstantParameter(ma, "filterHistory", taaOptions.filterHistory, dirty);
|
||||
setConstantParameter(ma, "filterInput", taaOptions.filterInput, dirty);
|
||||
setConstantParameter(ma, "useYCoCg", taaOptions.useYCoCg, dirty);
|
||||
setConstantParameter(ma, "preventFlickering", taaOptions.preventFlickering, dirty);
|
||||
setConstantParameter(ma, "boxType", int32_t(taaOptions.boxType), dirty);
|
||||
setConstantParameter(ma, "boxClipping", int32_t(taaOptions.boxClipping), dirty);
|
||||
setConstantParameter(ma, "varianceGamma", taaOptions.varianceGamma, dirty);
|
||||
if (dirty) {
|
||||
ma->invalidate();
|
||||
// TODO: call Material::compile(), we can't do that now because it works only
|
||||
@@ -2665,18 +2701,8 @@ FMaterialInstance* PostProcessManager::configureColorGradingMaterial(
|
||||
FMaterial* const ma = material.getMaterial(mEngine);
|
||||
bool dirty = false;
|
||||
|
||||
auto setConstantParameter =
|
||||
[&dirty](FMaterial* const material, std::string_view const name, auto value) noexcept {
|
||||
auto id = material->getSpecializationConstantId(name);
|
||||
if (id.has_value()) {
|
||||
if (material->setConstant(id.value(), value)) {
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional());
|
||||
setConstantParameter(ma, "isLDR", colorGrading->isLDR());
|
||||
setConstantParameter(ma, "isOneDimensional", colorGrading->isOneDimensional(), dirty);
|
||||
setConstantParameter(ma, "isLDR", colorGrading->isLDR(), dirty);
|
||||
|
||||
if (dirty) {
|
||||
ma->invalidate();
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
material {
|
||||
name : gtao,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : depth,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : mat4,
|
||||
name : screenFromViewMatrix
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : resolution,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : positionParams,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : invFarPlane
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : maxLevel
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : projectionScale
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : intensity
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : sliceCount
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : stepsPerSlice
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : radius
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : invRadiusSquared
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : projectionScaleRadius
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : power
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : thicknessHeuristic
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctShadowDistance
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctConeAngleTangeant
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctContactDistanceMaxInv
|
||||
},
|
||||
{
|
||||
type : float3,
|
||||
name : ssctVsLightDirection
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctIntensity
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : ssctDepthBias
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : ssctRayCount
|
||||
},
|
||||
{
|
||||
type : uint,
|
||||
name : ssctSampleCount
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
vertex
|
||||
],
|
||||
domain : postprocess,
|
||||
depthWrite : false,
|
||||
depthCulling : true
|
||||
}
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
// we don't use use uvToRenderTargetUV() here to compensate for metal/vulkan texture
|
||||
// coordinates differences because this is done in sampleDepth()
|
||||
postProcess.vertex.xy = postProcess.normalizedUV;
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
|
||||
#define COMPUTE_BENT_NORMAL 0
|
||||
|
||||
#include "gtaoImpl.fs"
|
||||
#include "ssctImpl.fs"
|
||||
#include "../utils/geometry.fs"
|
||||
#include "ssaoUtils.fs"
|
||||
|
||||
void dummy(){}
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
highp vec2 uv = variable_vertex.xy; // interpolated to pixel center
|
||||
|
||||
highp float depth = sampleDepth(materialParams_depth, uv, 0.0);
|
||||
highp float z = linearizeDepth(depth);
|
||||
highp vec3 origin = computeViewSpacePositionFromDepth(uv, z, materialParams.positionParams);
|
||||
|
||||
vec3 normal = computeViewSpaceNormal(materialParams_depth, uv, depth, origin,
|
||||
materialParams.resolution.zw,
|
||||
materialParams.positionParams);
|
||||
|
||||
float occlusion = 0.0;
|
||||
vec3 bentNormal; // will be discarded
|
||||
|
||||
if (materialParams.intensity > 0.0) {
|
||||
groundTruthAmbientOcclusion(occlusion, bentNormal, uv, origin, normal);
|
||||
}
|
||||
|
||||
if (materialParams.ssctIntensity > 0.0) {
|
||||
occlusion = max(occlusion, dominantLightShadowing(uv, origin, normal));
|
||||
}
|
||||
|
||||
// occlusion to visibility
|
||||
float aoVisibility = pow(saturate(1.0 - occlusion), materialParams.power);
|
||||
aoVisibility = mix(1.0, aoVisibility, materialParams.intensity);
|
||||
|
||||
#if defined(TARGET_MOBILE)
|
||||
// this line is needed to workaround what seems to be a bug on qualcomm hardware
|
||||
aoVisibility += gl_FragCoord.x * MEDIUMP_FLT_MIN;
|
||||
#endif
|
||||
|
||||
postProcess.color.rgb = vec3(aoVisibility, pack(origin.z * materialParams.invFarPlane));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
material {
|
||||
name : gtao,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : depth,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : mat4,
|
||||
name : screenFromViewMatrix
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : resolution,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : positionParams,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : invFarPlane
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : maxLevel
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : projectionScale
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : intensity
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : sliceCount
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : stepsPerSlice
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : radius
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : invRadiusSquared
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : projectionScaleRadius
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : power
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : thicknessHeuristic
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctShadowDistance
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctConeAngleTangeant
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctContactDistanceMaxInv
|
||||
},
|
||||
{
|
||||
type : float3,
|
||||
name : ssctVsLightDirection
|
||||
},
|
||||
{
|
||||
type : float,
|
||||
name : ssctIntensity
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : ssctDepthBias
|
||||
},
|
||||
{
|
||||
type : float2,
|
||||
name : ssctRayCount
|
||||
},
|
||||
{
|
||||
type : uint,
|
||||
name : ssctSampleCount
|
||||
}
|
||||
],
|
||||
outputs : [
|
||||
{
|
||||
name : aoData,
|
||||
target : color,
|
||||
type : float3
|
||||
},
|
||||
{
|
||||
name : bnData,
|
||||
target : color,
|
||||
type : float3
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
vertex
|
||||
],
|
||||
domain : postprocess,
|
||||
depthWrite : false,
|
||||
depthCulling : true
|
||||
}
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
// we don't use use uvToRenderTargetUV() here to compensate for metal/vulkan texture
|
||||
// coordinates differences because this is done in sampleDepth()
|
||||
postProcess.vertex.xy = postProcess.normalizedUV;
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
|
||||
#define COMPUTE_BENT_NORMAL 1
|
||||
|
||||
#include "gtaoImpl.fs"
|
||||
#include "ssctImpl.fs"
|
||||
#include "../utils/geometry.fs"
|
||||
#include "ssaoUtils.fs"
|
||||
|
||||
void dummy(){}
|
||||
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
highp vec2 uv = variable_vertex.xy; // interpolated to pixel center
|
||||
|
||||
highp float depth = sampleDepth(materialParams_depth, uv, 0.0);
|
||||
highp float z = linearizeDepth(depth);
|
||||
highp vec3 origin = computeViewSpacePositionFromDepth(uv, z, materialParams.positionParams);
|
||||
|
||||
vec3 normal = computeViewSpaceNormal(materialParams_depth, uv, depth, origin,
|
||||
materialParams.resolution.zw,
|
||||
materialParams.positionParams);
|
||||
|
||||
float occlusion = 0.0;
|
||||
vec3 bentNormal = normal;
|
||||
|
||||
if (materialParams.intensity > 0.0) {
|
||||
groundTruthAmbientOcclusion(occlusion, bentNormal, uv, origin, normal);
|
||||
}
|
||||
|
||||
if (materialParams.ssctIntensity > 0.0) {
|
||||
occlusion = max(occlusion, dominantLightShadowing(uv, origin, normal));
|
||||
}
|
||||
|
||||
// occlusion to visibility
|
||||
float aoVisibility = pow(saturate(1.0 - occlusion), materialParams.power);
|
||||
aoVisibility = mix(1.0, aoVisibility, materialParams.intensity);
|
||||
|
||||
#if defined(TARGET_MOBILE)
|
||||
// this line is needed to workaround what seems to be a bug on qualcomm hardware
|
||||
aoVisibility += gl_FragCoord.x * MEDIUMP_FLT_MIN;
|
||||
#endif
|
||||
|
||||
// transform to world space (we're guaranteed the view matrix is a rigid body transform)
|
||||
vec3 bn = mat3(getWorldFromViewMatrix()) * bentNormal;
|
||||
|
||||
postProcess.bnData = packBentNormal(bn);
|
||||
postProcess.aoData = vec3(aoVisibility, pack(origin.z * materialParams.invFarPlane));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is our implementation of GTAO -- it's not standalone because it uses materialParams
|
||||
* directly. Therefore it must be included in *.mat file that has all these parameters.
|
||||
* The main reason for using a separate file is to be able to have several version of the
|
||||
* code with only minor changes.
|
||||
*/
|
||||
|
||||
#include "../utils/geometry.fs"
|
||||
|
||||
#define rsqrt inversesqrt
|
||||
|
||||
#ifndef COMPUTE_BENT_NORMAL
|
||||
#error COMPUTE_BENT_NORMAL must be set
|
||||
#endif
|
||||
|
||||
const float kLog2LodRate = 3.0;
|
||||
|
||||
// Ambient Occlusion, largely inspired from:
|
||||
// "Practical Real-Time Strategies for Accurate Indirect Occlusion" by Jimenez et al.
|
||||
// https://github.com/GameTechDev/XeGTAO
|
||||
// https://github.com/MaxwellGengYF/Unity-Ground-Truth-Ambient-Occlusion
|
||||
|
||||
highp vec3 getViewSpacePosition(vec2 uv, float level) {
|
||||
highp float depth = sampleDepthLinear(materialParams_depth, uv, level);
|
||||
return computeViewSpacePositionFromDepth(uv, depth, materialParams.positionParams);
|
||||
}
|
||||
|
||||
float integrateArcCosWeight(float h, float n) {
|
||||
float arc = -cos(2.0 * h - n) + cos(n) + 2.0 * h * sin(n);
|
||||
return 0.25 * arc;
|
||||
}
|
||||
|
||||
// https://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf slide 93
|
||||
float spatialDirectionNoise(float2 uv) {
|
||||
int2 position = int2(uv * materialParams.resolution.xy);
|
||||
return (1.0/16.0) * (float(((position.x + position.y) & 3) << 2) + float(position.x & 3));
|
||||
}
|
||||
|
||||
// https://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf slide 93
|
||||
float spatialOffsetsNoise(float2 uv) {
|
||||
int2 position = int2(uv * materialParams.resolution.xy);
|
||||
return 0.25 * float((position.y - position.x) & 3);
|
||||
}
|
||||
|
||||
void groundTruthAmbientOcclusion(out float obscurance, out vec3 bentNormal,
|
||||
highp vec2 uv, highp vec3 origin, vec3 normal) {
|
||||
vec2 uvSamplePos = uv;
|
||||
highp vec3 viewDir = normalize(-origin);
|
||||
highp float ssRadius = -(materialParams.projectionScaleRadius / origin.z);
|
||||
|
||||
float noiseOffset = spatialOffsetsNoise(uv);
|
||||
float noiseDirection = spatialDirectionNoise(uv);
|
||||
|
||||
float initialRayStep = fract(noiseOffset);
|
||||
|
||||
// The distance we want to move forward for each step
|
||||
float stepRadius = ssRadius / (materialParams.stepsPerSlice + 1.0);
|
||||
|
||||
float visibility = 0.0;
|
||||
for (float i = 0.0; i < materialParams.sliceCount.x; i += 1.0) {
|
||||
float slice = (i + noiseDirection) * materialParams.sliceCount.y;
|
||||
float phi = slice * PI;
|
||||
float cosPhi = cos(phi);
|
||||
float sinPhi = sin(phi);
|
||||
vec2 omega = vec2(cosPhi, sinPhi);
|
||||
|
||||
// Calculate the direction of the current slice
|
||||
vec3 direction = vec3(cosPhi, sinPhi, 0.0);
|
||||
// Project direction onto the plane orthogonal to viewDir.
|
||||
vec3 orthoDirection = normalize(direction - (dot(direction, viewDir)*viewDir));
|
||||
// axis is orthogonal to direction and viewDir (basically the normal of the slice plane)
|
||||
// Used to define projectedNormal
|
||||
vec3 axis = cross(orthoDirection, viewDir);
|
||||
// Project the normal onto the slice plane
|
||||
vec3 projNormal = normal - axis * dot(normal, axis);
|
||||
|
||||
float signNorm = sign(dot(orthoDirection, projNormal));
|
||||
float projNormalLength = length(projNormal);
|
||||
float cosNorm = saturate(dot(projNormal, viewDir) / projNormalLength);
|
||||
|
||||
float n = signNorm * acosFast(cosNorm);
|
||||
|
||||
float horizonCos0 = -1.0;
|
||||
float horizonCos1 = -1.0;
|
||||
for (float j = 0.0; j < materialParams.stepsPerSlice; j += 1.0) {
|
||||
// At least move 1 pixel forward in the screen-space
|
||||
vec2 sampleOffset = max((j + initialRayStep)*stepRadius, 1.0 + j) * omega;
|
||||
float sampleOffsetLength = length(sampleOffset);
|
||||
|
||||
float level = clamp(floor(log2(sampleOffsetLength)) - kLog2LodRate, 0.0, float(materialParams.maxLevel));
|
||||
|
||||
vec2 uvSampleOffset = sampleOffset * materialParams.resolution.zw;
|
||||
|
||||
vec2 sampleScreenPos0 = uv + uvSampleOffset;
|
||||
vec2 sampleScreenPos1 = uv - uvSampleOffset;
|
||||
|
||||
// Sample the depth and use it to reconstruct the view space position
|
||||
highp vec3 samplePos0 = getViewSpacePosition(sampleScreenPos0, level);
|
||||
highp vec3 samplePos1 = getViewSpacePosition(sampleScreenPos1, level);
|
||||
|
||||
highp vec3 sampleDelta0 = (samplePos0 - origin);
|
||||
highp vec3 sampleDelta1 = (samplePos1 - origin);
|
||||
vec2 sqSampleDist = vec2(dot(sampleDelta0, sampleDelta0), dot(sampleDelta1, sampleDelta1));
|
||||
vec2 invSampleDist = rsqrt(sqSampleDist);
|
||||
|
||||
// Use the view space radius to calculate the fallOff
|
||||
vec2 fallOff = saturate(sqSampleDist.xy * materialParams.invRadiusSquared * 2.0);
|
||||
|
||||
// sample horizon cos
|
||||
float shc0 = dot(sampleDelta0, viewDir) * invSampleDist.x;
|
||||
float shc1 = dot(sampleDelta1, viewDir) * invSampleDist.y;
|
||||
|
||||
// If the new sample value is greater then the current one, update the value with some fallOff.
|
||||
// Otherwise, apply thicknessHeuristic.
|
||||
horizonCos0 = shc0 > horizonCos0 ? mix(shc0, horizonCos0, fallOff.x) : mix(horizonCos0, shc0, materialParams.thicknessHeuristic);
|
||||
horizonCos1 = shc1 > horizonCos1 ? mix(shc1, horizonCos1, fallOff.y) : mix(horizonCos1, shc1, materialParams.thicknessHeuristic);
|
||||
}
|
||||
|
||||
float h0 = -acosFast(horizonCos1);
|
||||
float h1 = acosFast(horizonCos0);
|
||||
h0 = n + clamp(h0 - n, -HALF_PI, HALF_PI);
|
||||
h1 = n + clamp(h1 - n, -HALF_PI, HALF_PI);
|
||||
|
||||
#if COMPUTE_BENT_NORMAL
|
||||
float angle = 0.5 * (h0 + h1);
|
||||
bentNormal += viewDir * cos(angle) - orthoDirection * sin(angle);
|
||||
#endif
|
||||
|
||||
visibility += projNormalLength * (integrateArcCosWeight(h0, n) + integrateArcCosWeight(h1, n));
|
||||
}
|
||||
|
||||
obscurance = 1.0 - saturate(visibility * materialParams.sliceCount.y);
|
||||
|
||||
#if COMPUTE_BENT_NORMAL
|
||||
bentNormal = normalize(bentNormal);
|
||||
#endif
|
||||
}
|
||||
@@ -504,6 +504,23 @@ std::ostream& operator<<(std::ostream& out, const RenderQuality& in) {
|
||||
<< "}";
|
||||
}
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::AmbientOcclusionType* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "SAO")) { *out = AmbientOcclusionOptions::AmbientOcclusionType::SAO; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "GTAO")) { *out = AmbientOcclusionOptions::AmbientOcclusionType::GTAO; }
|
||||
else {
|
||||
slog.w << "Invalid AmbientOcclusionOptions::AmbientOcclusionType: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, AmbientOcclusionOptions::AmbientOcclusionType in) {
|
||||
switch (in) {
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::SAO: return out << "\"SAO\"";
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::GTAO: return out << "\"GTAO\"";
|
||||
}
|
||||
return out << "\"INVALID\"";
|
||||
}
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::Ssct* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
@@ -557,13 +574,47 @@ std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions::Ssct&
|
||||
<< "}";
|
||||
}
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::Gtao* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "sampleSliceCount") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->sampleSliceCount);
|
||||
} else if (compare(tok, jsonChunk, "sampleStepsPerSlice") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->sampleStepsPerSlice);
|
||||
} else if (compare(tok, jsonChunk, "thicknessHeuristic") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->thicknessHeuristic);
|
||||
} else {
|
||||
slog.w << "Invalid Gtao key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid Gtao value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions::Gtao& in) {
|
||||
return out << "{\n"
|
||||
<< "\"sampleSliceCount\": " << int(in.sampleSliceCount) << ",\n"
|
||||
<< "\"sampleStepsPerSlice\": " << int(in.sampleStepsPerSlice) << ",\n"
|
||||
<< "\"thicknessHeuristic\": " << (in.thicknessHeuristic) << "\n"
|
||||
<< "}";
|
||||
}
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "radius") == 0) {
|
||||
if (compare(tok, jsonChunk, "aoType") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->aoType);
|
||||
} else if (compare(tok, jsonChunk, "radius") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->radius);
|
||||
} else if (compare(tok, jsonChunk, "power") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->power);
|
||||
@@ -589,6 +640,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusio
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->minHorizonAngleRad);
|
||||
} else if (compare(tok, jsonChunk, "ssct") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->ssct);
|
||||
} else if (compare(tok, jsonChunk, "gtao") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->gtao);
|
||||
} else {
|
||||
slog.w << "Invalid AmbientOcclusionOptions key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
@@ -603,6 +656,7 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusio
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions& in) {
|
||||
return out << "{\n"
|
||||
<< "\"aoType\": " << (in.aoType) << ",\n"
|
||||
<< "\"radius\": " << (in.radius) << ",\n"
|
||||
<< "\"power\": " << (in.power) << ",\n"
|
||||
<< "\"bias\": " << (in.bias) << ",\n"
|
||||
@@ -615,7 +669,8 @@ std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions& in) {
|
||||
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
|
||||
<< "\"bentNormals\": " << to_string(in.bentNormals) << ",\n"
|
||||
<< "\"minHorizonAngleRad\": " << (in.minHorizonAngleRad) << ",\n"
|
||||
<< "\"ssct\": " << (in.ssct) << "\n"
|
||||
<< "\"ssct\": " << (in.ssct) << ",\n"
|
||||
<< "\"gtao\": " << (in.gtao) << "\n"
|
||||
<< "}";
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,15 @@ std::ostream& operator<<(std::ostream& out, const VignetteOptions& in);
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, RenderQuality* out);
|
||||
std::ostream& operator<<(std::ostream& out, const RenderQuality& in);
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::AmbientOcclusionType* out);
|
||||
std::ostream& operator<<(std::ostream& out, AmbientOcclusionOptions::AmbientOcclusionType in);
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::Ssct* out);
|
||||
std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions::Ssct& in);
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions::Gtao* out);
|
||||
std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions::Gtao& in);
|
||||
|
||||
int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AmbientOcclusionOptions* out);
|
||||
std::ostream& operator<<(std::ostream& out, const AmbientOcclusionOptions& in);
|
||||
|
||||
|
||||
@@ -824,6 +824,12 @@ void ViewerGui::updateUserInterface() {
|
||||
if (ImGui::CollapsingHeader("SSAO Options")) {
|
||||
auto& ssao = mSettings.view.ssao;
|
||||
|
||||
ImGui::Checkbox("Enabled", &ssao.enabled);
|
||||
|
||||
int ambienOcclusionType = (int)ssao.aoType;
|
||||
ImGui::Combo("AO Type", &ambienOcclusionType, "SAO\0GTAO\0\0");
|
||||
ssao.aoType = (decltype(ssao.aoType))ambienOcclusionType;
|
||||
|
||||
int quality = (int) ssao.quality;
|
||||
int lowpass = (int) ssao.lowPassFilter;
|
||||
bool upsampling = ssao.upsampling != View::QualityLevel::LOW;
|
||||
@@ -833,7 +839,28 @@ void ViewerGui::updateUserInterface() {
|
||||
ImGui::SliderInt("Low Pass", &lowpass, 0, 2);
|
||||
ImGui::Checkbox("Bent Normals", &ssao.bentNormals);
|
||||
ImGui::Checkbox("High quality upsampling", &upsampling);
|
||||
ImGui::SliderFloat("Min Horizon angle", &ssao.minHorizonAngleRad, 0.0f, (float)M_PI_4);
|
||||
ImGui::SliderFloat("Radius", &ssao.radius, 0.1f, 10.0f);
|
||||
ImGui::SliderFloat("Power", &ssao.power, 1.0f, 8.0f);
|
||||
|
||||
switch (ssao.aoType) {
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::SAO: {
|
||||
ImGui::SliderFloat("Min Horizon angle", &ssao.minHorizonAngleRad, 0.0f,
|
||||
(float) M_PI_4);
|
||||
break;
|
||||
}
|
||||
case AmbientOcclusionOptions::AmbientOcclusionType::GTAO: {
|
||||
int sliceCount = ssao.gtao.sampleSliceCount;
|
||||
int stepsPerSlice = ssao.gtao.sampleStepsPerSlice;
|
||||
|
||||
ImGui::SliderInt("Slice Count", &sliceCount, 1, 10);
|
||||
ImGui::SliderInt("Steps Per Slice", &stepsPerSlice, 1, 4);
|
||||
|
||||
ssao.gtao.sampleSliceCount = static_cast<uint8_t>(sliceCount);
|
||||
ssao.gtao.sampleStepsPerSlice = static_cast<uint8_t>(stepsPerSlice);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SliderFloat("Bilateral Threshold", &ssao.bilateralThreshold, 0.0f, 0.1f);
|
||||
ImGui::Checkbox("Half resolution", &halfRes);
|
||||
ssao.resolution = halfRes ? 0.5f : 1.0f;
|
||||
|
||||
@@ -108,8 +108,18 @@ Filament.loadGeneratedExtensions = function() {
|
||||
return Object.assign(options, overrides);
|
||||
};
|
||||
|
||||
Filament.View.prototype.setGtaoDefaults = function(overrides) {
|
||||
const options = {
|
||||
sampleSliceCount: 4,
|
||||
sampleStepsPerSlice: 3,
|
||||
thicknessHeuristic: 0.004,
|
||||
};
|
||||
return Object.assign(options, overrides);
|
||||
};
|
||||
|
||||
Filament.View.prototype.setAmbientOcclusionOptionsDefaults = function(overrides) {
|
||||
const options = {
|
||||
aoType: Filament.View$AmbientOcclusionOptions$AmbientOcclusionType.SAO,
|
||||
radius: 0.3,
|
||||
power: 1.0,
|
||||
bias: 0.0005,
|
||||
@@ -123,6 +133,7 @@ Filament.loadGeneratedExtensions = function() {
|
||||
bentNormals: false,
|
||||
minHorizonAngleRad: 0.0,
|
||||
// JavaScript binding for ssct is not yet supported, must use default value.
|
||||
// JavaScript binding for gtao is not yet supported, must use default value.
|
||||
};
|
||||
return Object.assign(options, overrides);
|
||||
};
|
||||
|
||||
Vendored
+33
-4
@@ -1516,6 +1516,11 @@ export interface View$RenderQuality {
|
||||
hdrColorBuffer?: View$QualityLevel;
|
||||
}
|
||||
|
||||
export enum View$AmbientOcclusionOptions$AmbientOcclusionType {
|
||||
SAO, // use Scalable Ambient Occlusion
|
||||
GTAO, // use Ground Truth-Based Ambient Occlusion
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen Space Cone Tracing (SSCT) options
|
||||
* Ambient shadows from dominant light
|
||||
@@ -1563,11 +1568,33 @@ export interface View$AmbientOcclusionOptions$Ssct {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ground Truth-base Ambient Occlusion (GTAO) options
|
||||
*/
|
||||
export interface View$AmbientOcclusionOptions$Gtao {
|
||||
/**
|
||||
* # of slices. Higher value makes less noise.
|
||||
*/
|
||||
sampleSliceCount?: number;
|
||||
/**
|
||||
* # of steps the radius is divided into for integration. Higher value makes less bias.
|
||||
*/
|
||||
sampleStepsPerSlice?: number;
|
||||
/**
|
||||
* thickness heuristic, should be closed to 0
|
||||
*/
|
||||
thicknessHeuristic?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for screen space Ambient Occlusion (SSAO) and Screen Space Cone Tracing (SSCT)
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
export interface View$AmbientOcclusionOptions {
|
||||
/**
|
||||
* Type of ambient occlusion algorithm.
|
||||
*/
|
||||
aoType?: View$AmbientOcclusionOptions$AmbientOcclusionType;
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
@@ -1577,7 +1604,8 @@ export interface View$AmbientOcclusionOptions {
|
||||
*/
|
||||
power?: number;
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion.
|
||||
* Between 0 and a few mm. No effect when aoType set to GTAO
|
||||
*/
|
||||
bias?: number;
|
||||
/**
|
||||
@@ -1593,11 +1621,11 @@ export interface View$AmbientOcclusionOptions {
|
||||
*/
|
||||
bilateralThreshold?: number;
|
||||
/**
|
||||
* affects # of samples used for AO.
|
||||
* affects # of samples used for AO and params for filtering
|
||||
*/
|
||||
quality?: View$QualityLevel;
|
||||
/**
|
||||
* affects AO smoothness
|
||||
* affects AO smoothness. Recommend setting to HIGH when aoType set to GTAO.
|
||||
*/
|
||||
lowPassFilter?: View$QualityLevel;
|
||||
/**
|
||||
@@ -1613,10 +1641,11 @@ export interface View$AmbientOcclusionOptions {
|
||||
*/
|
||||
bentNormals?: boolean;
|
||||
/**
|
||||
* min angle in radian to consider
|
||||
* min angle in radian to consider. No effect when aoType set to GTAO.
|
||||
*/
|
||||
minHorizonAngleRad?: number;
|
||||
// JavaScript binding for ssct is not yet supported, must use default value.
|
||||
// JavaScript binding for gtao is not yet supported, must use default value.
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,7 +95,14 @@ value_object<View::AmbientOcclusionOptions::Ssct>("View$AmbientOcclusionOptions$
|
||||
.field("enabled", &View::AmbientOcclusionOptions::Ssct::enabled)
|
||||
;
|
||||
|
||||
value_object<View::AmbientOcclusionOptions::Gtao>("View$AmbientOcclusionOptions$Gtao")
|
||||
.field("sampleSliceCount", &View::AmbientOcclusionOptions::Gtao::sampleSliceCount)
|
||||
.field("sampleStepsPerSlice", &View::AmbientOcclusionOptions::Gtao::sampleStepsPerSlice)
|
||||
.field("thicknessHeuristic", &View::AmbientOcclusionOptions::Gtao::thicknessHeuristic)
|
||||
;
|
||||
|
||||
value_object<View::AmbientOcclusionOptions>("View$AmbientOcclusionOptions")
|
||||
.field("aoType", &View::AmbientOcclusionOptions::aoType)
|
||||
.field("radius", &View::AmbientOcclusionOptions::radius)
|
||||
.field("power", &View::AmbientOcclusionOptions::power)
|
||||
.field("bias", &View::AmbientOcclusionOptions::bias)
|
||||
@@ -109,6 +116,7 @@ value_object<View::AmbientOcclusionOptions>("View$AmbientOcclusionOptions")
|
||||
.field("bentNormals", &View::AmbientOcclusionOptions::bentNormals)
|
||||
.field("minHorizonAngleRad", &View::AmbientOcclusionOptions::minHorizonAngleRad)
|
||||
// JavaScript binding for ssct is not yet supported, must use default value.
|
||||
// JavaScript binding for gtao is not yet supported, must use default value.
|
||||
;
|
||||
|
||||
value_object<View::MultiSampleAntiAliasingOptions>("View$MultiSampleAntiAliasingOptions")
|
||||
|
||||
@@ -33,6 +33,11 @@ enum_<View::DepthOfFieldOptions::Filter>("View$DepthOfFieldOptions$Filter")
|
||||
.value("MEDIAN", View::DepthOfFieldOptions::Filter::MEDIAN)
|
||||
;
|
||||
|
||||
enum_<View::AmbientOcclusionOptions::AmbientOcclusionType>("View$AmbientOcclusionOptions$AmbientOcclusionType")
|
||||
.value("SAO", View::AmbientOcclusionOptions::AmbientOcclusionType::SAO)
|
||||
.value("GTAO", View::AmbientOcclusionOptions::AmbientOcclusionType::GTAO)
|
||||
;
|
||||
|
||||
enum_<View::TemporalAntiAliasingOptions::BoxType>("View$TemporalAntiAliasingOptions$BoxType")
|
||||
.value("AABB", View::TemporalAntiAliasingOptions::BoxType::AABB)
|
||||
.value("VARIANCE", View::TemporalAntiAliasingOptions::BoxType::VARIANCE)
|
||||
|
||||
Reference in New Issue
Block a user