google / filament

Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WebGL2
https://google.github.io/filament/
Apache License 2.0
17.59k stars 1.86k forks source link

Material with BlendingMode::FADE is always influenced by the camera's depth of field effects. #7663

Closed beeble-wonjunyoon closed 5 months ago

beeble-wonjunyoon commented 5 months ago

⚠️ Issues not using this template will be systematically closed.

Describe the bug

I'm working on compositing an RGBA image from a green screen onto an HDRI image using IBL. For this, I've created a rectangular geometry and applied various material maps derived from the image. To achieve a blurry skybox, I've enabled camera depth of field options view->setDepthOfFieldOptions({ .cocScale = 3.0f, .enabled = true });. However, when I use blending(MaterialBuilder::BlendingMode::FADE) for the foreground material, it results in both the foreground and background being blurred. This doesn't happen with blending(MaterialBuilder::BlendingMode::MASKED), but I need to use the FADE mode to retain the original alpha mask instead of a binary one. How can I keep the background blurred while preventing the foreground from getting blurred when using the FADE blending mode?

To Reproduce Steps to reproduce the behavior:

  1. setDepthOfFieldOptions to true

    view->setDepthOfFieldOptions({ .cocScale = 3.0f, .enabled = true });

  2. load IBL and skybox

    ibl->loadFromEquirect(globalData.environmentPath);
    ibl->getIndirectLight()->setIntensity(25000);
    scene->setIndirectLight(ibl->getIndirectLight());
    scene->setSkybox(ibl->getSkybox());
  1. Set foreground material
shaderCode = R"SHADER(
        // sRGB to Linear conversion function
        float sRGB_to_linear(float color) {
            return color <= 0.04045 ? color / 12.92 : pow((color + 0.055) / 1.055, 2.4);
        }

        void material(inout MaterialInputs material) {
            vec2 uv0 = getUV0();

            material.normal = texture(materialParams_normalMap, uv0).xyz * 2.0 - 1.0;
            material.normal.y *= -1.0;

            prepareMaterial(material);

            float4 baseColor = texture(materialParams_baseColorMap, uv0);
            float4 keyColor = texture(materialParams_keyMap, uv0);

            // Perform the weighted sum of color and keyColor, ignoring the alpha channel
            float3 color = baseColor.rgb * materialParams.blendFactor + keyColor.rgb * (1.0 - materialParams.blendFactor);

            // Use the original alpha from color, assuming you want to retain it
            float alpha = baseColor.a;

            // Convert sRGB to linear for each color component if the texture is sRGB
            if (materialParams.useSRGB == 1.0) {
                color.r = clamp(sRGB_to_linear(color.r), 0.0, 1.0);
                color.g = clamp(sRGB_to_linear(color.g), 0.0, 1.0);
                color.b = clamp(sRGB_to_linear(color.b), 0.0, 1.0);
            }

            color.rgb *= alpha;
            material.baseColor = float4(color.rgb, alpha);
        )SHADER";

    // Close the material function
    shaderCode += "}\n";

    // Configure the material builder with the selected shader code
    builder
        .name(name.c_str())
        .targetApi(MaterialBuilder::TargetApi::ALL)
        .material(shaderCode.c_str())
        .blending(MaterialBuilder::BlendingMode::FADE)
        .shading(MaterialBuilder::Shading::LIT)
        .require(VertexAttribute::UV0);
  1. Change the background (skybox) blurriness
void GuiCallbacks::setBackgroundBlurriness(float value) {
    // Calculate the aperture based on blurriness
    float newAperture = 16.0f - (15.0f * value);
    // Ensure the aperture ranges from 1 to 16
    newAperture = std::max(1.0f, std::min(newAperture, 16.0f));

    if (mCamera) {
        float baseAperture = 16.0f; // Base aperture
        float baseShutterSpeed = 1.0f / 250; // Keep the base shutter speed constant
        float baseIso = 200.0f; // Base ISO

        // Calculate the new ISO to maintain exposure
        float newShutterSpeed = baseShutterSpeed * (newAperture) / (baseAperture);
        float newIso = baseIso * (newAperture) / (baseAperture);

        // Set the mCamera exposure using the new aperture and new ISO while keeping the shutter speed constant
        mCamera->setExposure(newAperture, newShutterSpeed, newIso);
    }
}

I adjust the blurriness of the background(skybox) by changing the aperture. To maintain consistent brightness despite these changes, I correspondingly alter the shutter speed and ISO values. However, using blendingMode::FADE for the material results in the foreground also appearing blurred, irrespective of the camera's focus distance. In contrast, when I use blendingMode::MASKED, only the background becomes blurred.

Expected behavior

I'm looking to ensure that my foreground material remains clear and only the skybox is blurred, despite using blendingMode::FADE, so that the alpha mask can be effectively used.

Screenshots

  1. blendingMode::MASKED with blurred background. You can see that compositing is not clear because of binary mask. masked_blurred_bg

  2. blendingMode::FADE with clean background. You can observe a smoother compositing due to the alpha mask. fade_not_blurred

  3. blendingMode::FADE with blurred background. You can see that the foreground is also blurred. fade_blurred_bg

Logs If applicable, copy full logs from your console here. Please do not use screenshots of logs, copy them as text, use gist or attach an uncompressed file.

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Add any other context about the problem here.

romainguy commented 5 months ago

Enable depth write for your transparent objects otherwise they are not part of the depth buffer, and therefore are not handled by depth of field. Note that this means you won't see depth of field through transparent objects (lifting that limitation woild be very expensive and other engines have the same limitation).

beeble-wonjunyoon commented 5 months ago

Thank you for your quick response. @romainguy

Just to clarify, after I apply .depthWrite(true), the entire rectangular plane does not become blurred. So you mean that there is no way to make only those areas with alpha 0 be blurred, without affecting the rest of the rectangle? fade_blur_depthwriteTrue

romainguy commented 5 months ago

Right, for this you could discard the fragments where alpha=0.