Skip to content

Commit

Permalink
Add a way to set the shadow sampling quality
Browse files Browse the repository at this point in the history
BUGS=[379754325]
  • Loading branch information
pixelflinger committed Dec 13, 2024
1 parent d2e8529 commit 3d15e9d
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 16 deletions.
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

0 comments on commit 3d15e9d

Please sign in to comment.