Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to set the shadow sampling quality #8315

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion android/filament-android/src/main/cpp/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ using namespace filament;

extern "C" JNIEXPORT jlong JNICALL
Java_com_google_android_filament_Material_nBuilderBuild(JNIEnv *env, jclass,
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount) {
jlong nativeEngine, jobject buffer_, jint size, jint shBandCount, jint shadowQuality) {
Engine* engine = (Engine*) nativeEngine;
AutoBuffer buffer(env, buffer_, size);
auto builder = Material::Builder();
if (shBandCount) {
builder.sphericalHarmonicsBandCount(shBandCount);
}
builder.shadowSamplingQuality((Material::Builder::ShadowSamplingQuality)shadowQuality);
Material* material = builder
.package(buffer.getData(), buffer.getSize())
.build(*engine);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,9 +344,18 @@ public Material(long nativeMaterial) {
}

public static class Builder {
public enum ShadowSamplingQuality {
/** 2x2 PCF */
HARD,
/** 3x3 gaussian filter */
LOW,
}

private Buffer mBuffer;
private int mSize;
private int mShBandCount = 0;
private ShadowSamplingQuality mShadowSamplingQuality = ShadowSamplingQuality.LOW;


/**
* Specifies the material data. The material data is a binary blob produced by
Expand Down Expand Up @@ -378,6 +387,18 @@ public Builder sphericalHarmonicsBandCount(@IntRange(from = 0) int shBandCount)
return this;
}

/**
* Set the quality of shadow sampling. This is only taken into account
* if this material is lit and in the surface domain.
* @param quality
* @return Reference to this Builder for chaining calls.
*/
@NonNull
public Builder shadowSamplingQuality(ShadowSamplingQuality quality) {
mShadowSamplingQuality = quality;
return this;
}

/**
* Creates and returns the Material object.
*
Expand All @@ -390,7 +411,7 @@ public Builder sphericalHarmonicsBandCount(@IntRange(from = 0) int shBandCount)
@NonNull
public Material build(@NonNull Engine engine) {
long nativeMaterial = nBuilderBuild(engine.getNativeObject(),
mBuffer, mSize, mShBandCount);
mBuffer, mSize, mShBandCount, mShadowSamplingQuality.ordinal());
if (nativeMaterial == 0) throw new IllegalStateException("Couldn't create Material");
return new Material(nativeMaterial);
}
Expand Down Expand Up @@ -1041,7 +1062,7 @@ void clearNativeObject() {
mNativeObject = 0;
}

private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount);
private static native long nBuilderBuild(long nativeEngine, @NonNull Buffer buffer, int size, int shBandCount, int shadowQuality);
private static native long nCreateInstance(long nativeMaterial);
private static native long nCreateInstanceWithName(long nativeMaterial, @NonNull String name);
private static native long nGetDefaultInstance(long nativeMaterial);
Expand Down
13 changes: 13 additions & 0 deletions filament/include/filament/Material.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ class UTILS_PUBLIC Material : public FilamentAPI {
Builder& operator=(Builder const& rhs) noexcept;
Builder& operator=(Builder&& rhs) noexcept;

enum class ShadowSamplingQuality : uint8_t {
HARD, // 2x2 PCF
LOW // 3x3 gaussian filter
};

/**
* Specifies the material data. The material data is a binary blob produced by
* libfilamat or by matc.
Expand Down Expand Up @@ -152,6 +157,14 @@ class UTILS_PUBLIC Material : public FilamentAPI {
*/
Builder& sphericalHarmonicsBandCount(size_t shBandCount) noexcept;

/**
* Set the quality of shadow sampling. This is only taken into account
* if this material is lit and in the surface domain.
* @param quality
* @return
*/
Builder& shadowSamplingQuality(ShadowSamplingQuality quality) noexcept;

/**
* Creates the Material object and returns a pointer to it.
*
Expand Down
12 changes: 11 additions & 1 deletion filament/src/details/Material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ struct Material::BuilderDetails {
size_t mSize = 0;
bool mDefaultMaterial = false;
int32_t mShBandsCount = 3;
Builder::ShadowSamplingQuality mShadowSamplingQuality = Builder::ShadowSamplingQuality::LOW;
std::unordered_map<
utils::CString,
std::variant<int32_t, float, bool>,
Expand Down Expand Up @@ -152,6 +153,11 @@ Material::Builder& Material::Builder::sphericalHarmonicsBandCount(size_t shBandC
return *this;
}

Material::Builder& Material::Builder::shadowSamplingQuality(ShadowSamplingQuality quality) noexcept {
mImpl->mShadowSamplingQuality = quality;
return *this;
}

template<typename T, typename>
Material::Builder& Material::Builder::constant(const char* name, size_t nameLength, T value) {
FILAMENT_CHECK_PRECONDITION(name != nullptr) << "name cannot be null";
Expand Down Expand Up @@ -999,7 +1005,11 @@ void FMaterial::processSpecializationConstants(FEngine& engine, Material::Builde
+ReservedSpecializationConstants::CONFIG_STEREO_EYE_COUNT,
(int)engine.getConfig().stereoscopicEyeCount });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, builder->mShBandsCount });
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT,
builder->mShBandsCount });
mSpecializationConstants.push_back({
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD,
(int32_t)builder->mShadowSamplingQuality });
if (UTILS_UNLIKELY(parser->getShaderLanguage() == ShaderLanguage::ESSL1)) {
// The actual value of this spec-constant is set in the OpenGLDriver backend.
mSpecializationConstants.push_back({
Expand Down
4 changes: 3 additions & 1 deletion libs/filabridge/include/private/filament/EngineEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ enum class ReservedSpecializationConstants : uint8_t {
CONFIG_DEBUG_DIRECTIONAL_SHADOWMAP = 6,
CONFIG_DEBUG_FROXEL_VISUALIZATION = 7,
CONFIG_STEREO_EYE_COUNT = 8, // don't change (hardcoded in ShaderCompilerService.cpp)
CONFIG_SH_BANDS_COUNT = 9
CONFIG_SH_BANDS_COUNT = 9,
CONFIG_SHADOW_SAMPLING_METHOD = 10
// check CONFIG_MAX_RESERVED_SPEC_CONSTANTS below
};

enum class PushConstantIds : uint8_t {
Expand Down
3 changes: 3 additions & 0 deletions libs/filamat/src/shaders/CodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
generateSpecializationConstant(out, "CONFIG_SH_BANDS_COUNT",
+ReservedSpecializationConstants::CONFIG_SH_BANDS_COUNT, 3);

generateSpecializationConstant(out, "CONFIG_SHADOW_SAMPLING_METHOD",
+ReservedSpecializationConstants::CONFIG_SHADOW_SAMPLING_METHOD, 1);

// CONFIG_MAX_STEREOSCOPIC_EYES is used to size arrays and on Adreno GPUs + vulkan, this has to
// be explicitly, statically defined (as in #define). Otherwise (using const int for
// example), we'd run into a GPU crash.
Expand Down
17 changes: 6 additions & 11 deletions shaders/src/shadowing.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@
#define SHADOW_SAMPLING_RUNTIME_DPCF 2u
#define SHADOW_SAMPLING_RUNTIME_PCSS 3u

// TODO: this should be user-settable, maybe at the material level
#define SHADOW_SAMPLING_PCF_HARD 0
#define SHADOW_SAMPLING_PCF_LOW 1
#define SHADOW_SAMPLING_METHOD SHADOW_SAMPLING_PCF_LOW

//------------------------------------------------------------------------------
// PCF Shadow Sampling
Expand All @@ -29,7 +27,6 @@ float sampleDepth(const mediump sampler2DArrayShadow map,
return texture(map, vec4(uv, layer, saturate(depth)));
}

#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
// use hardware assisted PCF
float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
Expand All @@ -38,9 +35,7 @@ float ShadowSample_PCF_Hard(const mediump sampler2DArrayShadow map,
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
return sampleDepth(map, scissorNormalized, layer, position.xy, position.z);
}
#endif

#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
// use hardware assisted PCF + 3x3 gaussian filter
float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
const highp vec4 scissorNormalized,
Expand Down Expand Up @@ -77,7 +72,6 @@ float ShadowSample_PCF_Low(const mediump sampler2DArrayShadow map,
sum += uw.y * vw.y * sampleDepth(map, scissorNormalized, layer, base + vec2(u.y, v.y), depth);
return sum * (1.0 / 16.0);
}
#endif

// use manual PCF
float ShadowSample_PCF(const mediump sampler2DArray map,
Expand Down Expand Up @@ -523,11 +517,12 @@ float shadow(const bool DIRECTIONAL,
const int index, highp vec4 shadowPosition, highp float zLight) {
highp vec4 scissorNormalized = shadowUniforms.shadows[index].scissorNormalized;
uint layer = shadowUniforms.shadows[index].layer;
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
#endif

if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD) {
return ShadowSample_PCF_Hard(shadowMap, scissorNormalized, layer, shadowPosition);
} else if (CONFIG_SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW) {
return ShadowSample_PCF_Low(shadowMap, scissorNormalized, layer, shadowPosition);
}
}

// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
Expand Down
Loading