Compare commits

...

14 Commits

Author SHA1 Message Date
Eliza Velasquez
ea9fdbeb5c wip: shader compilation benchmark 2024-01-16 17:03:41 -08:00
Ben Doherty
5fd7a4e153 Don't render in background (#7486) 2024-01-12 10:17:00 -08:00
Sungun Park
20ff230b92 Fix a json parsing bug (#7490)
When parsing a lexeme, we use one less byte than it's intended to be for
comparing the current string.

This results in a success in cases like:
- true and truX
- false and falsX
- null and nulX
where X means an arbitrary character.

Fix this by the full intended length.
2024-01-11 12:47:11 -08:00
Ben Doherty
44ff79ad34 Metal: disable fast math (#7485) 2024-01-10 15:31:23 -08:00
Mathias Agopian
102d2db008 Bokeh aspect ratio (#7482)
* Bokeh aspect ratio

new DoF option to set the bokeh aspect ratio, this can be used to
simulate anamorphic lenses

* Update android/filament-android/src/main/java/com/google/android/filament/View.java

Co-authored-by: Powei Feng <powei@google.com>

* Update web/filament-js/filament.d.ts

Co-authored-by: Powei Feng <powei@google.com>

---------

Co-authored-by: Powei Feng <powei@google.com>
2024-01-10 15:25:28 -08:00
Powei Feng
5c9039e650 Release Filament 1.49.3 2024-01-10 13:55:33 -08:00
Eliza Velasquez
1203c24f06 Generate dummy stereo variants for FL0 mats
See #7415 for a more detailed description of why this change is necessary.

The remaining variants which are filtered from FL0 materials are all related to
lighting, so further hacks like this won't be necessary.

Future work involves properly supporting differing sets of variants based on
shader language.
2024-01-10 13:50:53 -08:00
Mathias Agopian
9704d27aeb TAA upscaling
This feature is still work in progress. TAA can now optionally
upscale by 4x (this disables dynamic resolution scaling).
2024-01-09 14:07:18 -08:00
Mathias Agopian
c6f2c3fc1c bloom: disable fireflies reduction when using TAA
TAA already does a fireflies reduction pass, so it's not needed when
applying bloom.
2024-01-09 14:04:01 -08:00
Mathias Agopian
2faf868341 fix missing includes (new CLion warnings) 2024-01-09 14:04:01 -08:00
Powei Feng
81f6260843 Fix typo oin MaterialCompiler (#7477) 2024-01-08 15:03:07 -08:00
Ben Doherty
1a9063d53a Metal: Always report material name in use-after-free detector (#7473) 2024-01-04 11:55:28 -08:00
Ben Doherty
6062b3c8c6 Fix ostream linking error when compiling Linux DSO (#7470) 2024-01-03 12:06:44 -08:00
Ben Doherty
d9186c44ba matdbg: Load codicon font (#7469) 2024-01-03 10:41:18 -08:00
38 changed files with 428 additions and 80 deletions

View File

@@ -7,3 +7,5 @@ for next branch cut* header.
appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- Metal: fix some shader artifacts by disabling fast math optimizations.

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.49.2'
implementation 'com.google.android.filament:filament-android:1.49.3'
}
```
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
iOS projects can use CocoaPods to install the latest release:
```shell
pod 'Filament', '~> 1.49.2'
pod 'Filament', '~> 1.49.3'
```
### Snapshots

View File

@@ -7,8 +7,12 @@ A new header is inserted each time a *tag* is created.
Instead, if you are authoring a PR for the main branch, add your release note to
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
## v1.50.0
- engine: TAA now supports 4x upscaling [BETA] [⚠️ **New Material Version**]
## v1.49.3
- matc: Generate stereo variants for FL0 materials [⚠️ **Recompile materials**]
## v1.49.2

View File

@@ -1637,6 +1637,10 @@ public class View {
* circle of confusion scale factor (amount of blur)
*/
public float cocScale = 1.0f;
/**
* width/height aspect ratio of the circle of confusion (simulate anamorphic lenses)
*/
public float cocAspectRatio = 1.0f;
/**
* maximum aperture diameter in meters (zero to disable rotation)
*/
@@ -1878,7 +1882,7 @@ public class View {
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
@@ -1931,10 +1935,18 @@ public class View {
* history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
*/
public float feedback = 0.12f;
/**
* texturing lod bias (typically -1 or -2)
*/
public float lodBias = -1.0f;
/**
* enables or disables temporal anti-aliasing
*/
public boolean enabled = false;
/**
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
*/
public boolean upscaling = false;
/**
* whether to filter the history buffer
*/

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.49.2
VERSION_NAME=1.49.3
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -103,10 +103,19 @@ void MetalShaderCompiler::terminate() noexcept {
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
length:source.size() - 1
encoding:NSUTF8StringEncoding];
// By default, Metal uses the most recent language version.
MTLCompileOptions* options = [MTLCompileOptions new];
// Disable Fast Math optimizations.
// This ensures that operations adhere to IEEE standards for floating-point arithmetic,
// which is crucial for half precision floats in scenarios where fast math optimizations
// lead to inaccuracies, such as in handling special values like NaN or Infinity.
options.fastMathEnabled = NO;
NSError* error = nil;
// When options is nil, Metal uses the most recent language version available.
id<MTLLibrary> library = [device newLibraryWithSource:objcSource
options:nil
options:options
error:&error];
if (library == nil) {
if (error) {

View File

@@ -293,6 +293,7 @@ struct DepthOfFieldOptions {
MEDIAN
};
float cocScale = 1.0f; //!< circle of confusion scale factor (amount of blur)
float cocAspectRatio = 1.0f; //!< width/height aspect ratio of the circle of confusion (simulate anamorphic lenses)
float maxApertureDiameter = 0.01f; //!< maximum aperture diameter in meters (zero to disable rotation)
bool enabled = false; //!< enable or disable depth of field effect
Filter filter = Filter::MEDIAN; //!< filter to use for filling gaps in the kernel
@@ -426,7 +427,7 @@ struct MultiSampleAntiAliasingOptions {
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed an any time.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
@@ -436,7 +437,9 @@ struct MultiSampleAntiAliasingOptions {
struct TemporalAntiAliasingOptions {
float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2)
bool enabled = false; //!< enables or disables temporal anti-aliasing
bool upscaling = false; //!< 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
enum class BoxType : uint8_t {
AABB, //!< use an AABB neighborhood

View File

@@ -71,8 +71,7 @@ void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
s.clipControl = engine.getDriverApi().getClipSpaceParams();
}
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
float bias) noexcept {
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction, float bias) noexcept {
auto& s = edit(transaction);
s.lodBias = bias;
}

View File

@@ -96,9 +96,10 @@ void PerViewUniforms::prepareCamera(FEngine& engine, const CameraInfo& camera) n
s.clipControl = engine.getDriverApi().getClipSpaceParams();
}
void PerViewUniforms::prepareLodBias(float bias) noexcept {
void PerViewUniforms::prepareLodBias(float bias, float2 derivativesScale) noexcept {
auto& s = mUniforms.edit();
s.lodBias = bias;
s.derivativesScale = derivativesScale;
}
void PerViewUniforms::prepareExposure(float ev100) noexcept {

View File

@@ -69,7 +69,7 @@ public:
void terminate(backend::DriverApi& driver);
void prepareCamera(FEngine& engine, const CameraInfo& camera) noexcept;
void prepareLodBias(float bias) noexcept;
void prepareLodBias(float bias, math::float2 derivativesScale) noexcept;
/*
* @param viewport viewport (should be same as RenderPassParams::viewport)

View File

@@ -27,9 +27,12 @@
#include "details/Engine.h"
#include "fg/FrameGraph.h"
#include "fg/FrameGraphId.h"
#include "fg/FrameGraphResources.h"
#include "fg/FrameGraphTexture.h"
#include "fsr.h"
#include "FrameHistory.h"
#include "PerViewUniforms.h"
#include "RenderPass.h"
@@ -41,15 +44,44 @@
#include "generated/resources/materials.h"
#include <filament/Material.h>
#include <filament/MaterialEnums.h>
#include <filament/Options.h>
#include <filament/Viewport.h>
#include <private/filament/EngineEnums.h>
#include <backend/DriverEnums.h>
#include <backend/DriverApiForward.h>
#include <backend/Handle.h>
#include <backend/PipelineState.h>
#include <backend/PixelBufferDescriptor.h>
#include <private/backend/BackendUtils.h>
#include <math/half.h>
#include <math/mat2.h>
#include <math/mat3.h>
#include <math/mat4.h>
#include <math/scalar.h>
#include <math/vec3.h>
#include <math/vec4.h>
#include <utils/algorithm.h>
#include <utils/BitmaskEnum.h>
#include <utils/debug.h>
#include <utils/compiler.h>
#include <utils/FixedCapacityVector.h>
#include <algorithm>
#include <cmath>
#include <limits>
#include <string_view>
#include <variant>
#include <utility>
#include <stddef.h>
#include <stdint.h>
namespace filament {
@@ -772,7 +804,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::screenSpaceAmbientOcclusion(
auto ssao = resources.getRenderPassInfo();
auto const& desc = resources.getDescriptor(data.depth);
// estimate of the size in pixel of a 1m tall/wide object viewed from 1m away (i.e. at z=-1)
// Estimate of the size in pixel units of a 1m tall/wide object viewed from 1m away (i.e. at z=-1)
const float projectionScale = std::min(
0.5f * cameraInfo.projection[0].x * desc.width,
0.5f * cameraInfo.projection[1].y * desc.height);
@@ -929,7 +961,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::bilateralBlurPass(FrameGraph
auto const& desc = resources.getDescriptor(data.blurred);
// unnormalized gaussian half-kernel of a given standard deviation
// returns number of samples stored in array (max 16)
// returns number of samples stored in the array (max 16)
constexpr size_t kernelArraySize = 16; // limited by bilateralBlur.mat
auto gaussianKernel =
[kernelArraySize](float* outKernel, size_t gaussianWidth, float stdDev) -> uint32_t {
@@ -973,7 +1005,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::generateGaussianMipmap(Frame
auto const subResourceDesc = fg.getSubResourceDescriptor(input);
// create one subresource per level to be generated from the input. These will be our
// Create one subresource per level to be generated from the input. These will be our
// destinations.
struct MipmapPassData {
FixedCapacityVector<FrameGraphId<FrameGraphTexture>> out;
@@ -1134,7 +1166,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
size_t const m = computeGaussianCoefficients(kernel,
std::min(sizeof(kernel) / sizeof(*kernel), kernelStorageSize));
std::string_view sourceParameterName = is2dArray ? "sourceArray"sv : "source"sv;
std::string_view const sourceParameterName = is2dArray ? "sourceArray"sv : "source"sv;
// horizontal pass
mi->setParameter(sourceParameterName, hwIn, {
.filterMag = SamplerMagFilter::LINEAR,
@@ -1180,7 +1212,7 @@ PostProcessManager::ScreenSpaceRefConfig PostProcessManager::prepareMipmapSSR(Fr
// The kernel-size was determined empirically so that we don't get too many artifacts
// due to the down-sampling with a box filter (which happens implicitly).
// requires only 6 stored coefficients and 11 tap/pass
// Requires only 6 stored coefficients and 11 tap/pass
// e.g.: size of 13 (4 stored coefficients)
// +-------+-------+-------*===*-------+-------+-------+
// ... | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | ...
@@ -1344,10 +1376,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::generateMipmapSSR(
FrameGraphId<FrameGraphTexture> output,
bool needInputDuplication, ScreenSpaceRefConfig const& config) noexcept {
// descriptor of our actual input image (e.g. reflection buffer or refraction framebuffer)
// Descriptor of our actual input image (e.g. reflection buffer or refraction framebuffer)
auto const& desc = fg.getDescriptor(input);
// descriptor of the destination. output is a subresource (i.e. a layer of a 2D array)
// Descriptor of the destination. `output` is a subresource (i.e. a layer of a 2D array)
auto const& outDesc = fg.getDescriptor(output);
/*
@@ -1396,7 +1428,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> depth,
const CameraInfo& cameraInfo,
bool translucent,
float bokehAspectRatio,
float2 bokehScale,
const DepthOfFieldOptions& dofOptions) noexcept {
assert_invariant(depth);
@@ -1407,7 +1439,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
const TextureFormat format = translucent ? TextureFormat::RGBA16F
: TextureFormat::R11F_G11F_B10F;
// rotate the bokeh based on the aperture diameter (i.e. angle of the blades)
// Rotate the bokeh based on the aperture diameter (i.e. angle of the blades)
float bokehAngle = f::PI / 6.0f;
if (dofOptions.maxApertureDiameter > 0.0f) {
bokehAngle += f::PI_2 * saturate(cameraInfo.A / dofOptions.maxApertureDiameter);
@@ -1786,8 +1818,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
mi->setParameter("tiles", tilesCocMinMax,
{ .filterMin = SamplerMinFilter::NEAREST });
mi->setParameter("cocToTexelScale", float2{
bokehAspectRatio / (inputDesc.width * dofResolution),
1.0 / (inputDesc.height * dofResolution)
bokehScale.x / (inputDesc.width * dofResolution),
bokehScale.y / (inputDesc.height * dofResolution)
});
mi->setParameter("cocToPixelScale", (1.0f / float(dofResolution)));
mi->setParameter("ringCounts", float4{
@@ -1893,14 +1925,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::dof(FrameGraph& fg,
return ppDoFCombine->output;
}
PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
BloomOptions& inoutBloomOptions,
backend::TextureFormat outFormat,
math::float2 scale) noexcept {
return bloomPass(fg, input, outFormat, inoutBloomOptions, scale);
}
FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,
@@ -1932,9 +1956,11 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::downscalePass(FrameGraph& fg
return downsamplePass->output;
}
PostProcessManager::BloomPassOutput PostProcessManager::bloomPass(FrameGraph& fg,
PostProcessManager::BloomPassOutput PostProcessManager::bloom(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, TextureFormat outFormat,
BloomOptions& inoutBloomOptions, float2 scale) noexcept {
BloomOptions& inoutBloomOptions,
TemporalAntiAliasingOptions const& taaOptions,
float2 scale) noexcept {
// Figure out a good size for the bloom buffer. We must use a fixed bloom buffer size so
// that the size/strength of the bloom doesn't vary much with the resolution, otherwise
@@ -1976,6 +2002,9 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloomPass(FrameGraph& fg
bool threshold = inoutBloomOptions.threshold;
// we don't need to do the fireflies reduction if we have TAA (it already does it)
bool fireflies = threshold && !taaOptions.enabled;
while (2 * bloomWidth < float(desc.width) || 2 * bloomHeight < float(desc.height)) {
if (inoutBloomOptions.quality == QualityLevel::LOW ||
inoutBloomOptions.quality == QualityLevel::MEDIUM) {
@@ -1984,8 +2013,9 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloomPass(FrameGraph& fg
.height = (desc.height = std::max(1u, desc.height / 2)),
.format = outFormat
},
threshold, inoutBloomOptions.highlight, threshold);
threshold, inoutBloomOptions.highlight, fireflies);
threshold = false; // we do the thresholding only once during down sampling
fireflies = false; // we do the fireflies reduction only once during down sampling
} else if (inoutBloomOptions.quality == QualityLevel::HIGH ||
inoutBloomOptions.quality == QualityLevel::ULTRA) {
// In high quality mode, we increase the size of the bloom buffer such that the
@@ -2006,7 +2036,7 @@ PostProcessManager::BloomPassOutput PostProcessManager::bloomPass(FrameGraph& fg
input = downscalePass(fg, input,
{ .width = width, .height = height, .format = outFormat },
threshold, inoutBloomOptions.highlight, threshold);
threshold, inoutBloomOptions.highlight, fireflies);
struct BloomPassData {
FrameGraphId<FrameGraphTexture> out;
@@ -2635,6 +2665,10 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
auto& taaPass = fg.addPass<TAAData>("TAA",
[&](FrameGraph::Builder& builder, auto& data) {
auto desc = fg.getDescriptor(input);
if (taaOptions.upscaling) {
desc.width *= 2;
desc.height *= 2;
}
data.color = builder.sample(input);
data.depth = builder.sample(depth);
data.history = builder.sample(colorHistory);
@@ -2669,18 +2703,26 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
{ -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f },
};
float sum = 0.0;
constexpr float2 subSampleOffsets[4] = {
{ -0.25f, 0.25f }, { 0.25f, 0.25f }, { 0.25f, -0.25f }, { -0.25f, -0.25f }
};
float4 sum = 0.0;
float4 weights[9];
// this doesn't get vectorized (probably because of exp()), so don't bother
// unrolling it.
#pragma nounroll
for (size_t i = 0; i < 9; i++) {
float2 const d = (sampleOffsets[i] - current.jitter) / taaOptions.filterWidth;
// This is a gaussian fit of a 3.3-wide Blackman-Harris window
// see: "High Quality Temporal Supersampling" by Brian Karis
weights[i][0] = std::exp(-2.29f * (d.x * d.x + d.y * d.y));
sum += weights[i][0];
float2 const o = sampleOffsets[i];
for (size_t j = 0; j < 4; j++) {
float2 const s = taaOptions.upscaling ? subSampleOffsets[j] : float2{ 0 };
float2 const d = (o - current.jitter - s) / taaOptions.filterWidth;
// This is a gaussian fit of a 3.3-wide Blackman-Harris window
// see: "High Quality Temporal Supersampling" by Brian Karis
weights[i][j] = std::exp(-2.29f * (d.x * d.x + d.y * d.y));
}
sum += weights[i];
}
for (auto& w : weights) {
w /= sum;
@@ -3149,7 +3191,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
auto& material = getPostProcessMaterial("vsmMipmap");
// When generating shadow map mip levels, we want to preserve the 1 texel border.
// (note clearing never respects the scissor in filament)
// (note clearing never respects the scissor in Filament)
PipelineState pipeline(material.getPipelineState(mEngine));
pipeline.scissor = { 1u, 1u, dim - 2u, dim - 2u };

View File

@@ -162,7 +162,7 @@ public:
FrameGraphId<FrameGraphTexture> depth,
const CameraInfo& cameraInfo,
bool translucent,
float bokehAspectRatio,
math::float2 bokehScale,
const DepthOfFieldOptions& dofOptions) noexcept;
// Bloom
@@ -171,7 +171,9 @@ public:
FrameGraphId<FrameGraphTexture> flare;
};
BloomPassOutput bloom(FrameGraph& fg, FrameGraphId<FrameGraphTexture> input,
BloomOptions& inoutBloomOptions, backend::TextureFormat outFormat,
backend::TextureFormat outFormat,
BloomOptions& inoutBloomOptions,
TemporalAntiAliasingOptions const& taaOptions,
math::float2 scale) noexcept;
FrameGraphId<FrameGraphTexture> flarePass(FrameGraph& fg,
@@ -342,10 +344,6 @@ private:
math::int2 axis, float zf, backend::TextureFormat format,
BilateralPassConfig const& config) noexcept;
BloomPassOutput bloomPass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input, backend::TextureFormat outFormat,
BloomOptions& inoutBloomOptions, math::float2 scale) noexcept;
FrameGraphId<FrameGraphTexture> downscalePass(FrameGraph& fg,
FrameGraphId<FrameGraphTexture> input,
FrameGraphTexture::Descriptor const& outDesc,

View File

@@ -117,7 +117,7 @@ void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* ma
if (!material->getSamplerInterfaceBlock().isEmpty()) {
mSamplers = SamplerGroup(material->getSamplerInterfaceBlock().getSize());
mSbHandle = driver.createSamplerGroup(
mSamplers.getSize(), utils::FixedSizeString<32>("Default material"));
mSamplers.getSize(), utils::FixedSizeString<32>(mMaterial->getName().c_str_safe()));
}
const RasterState& rasterState = material->getRasterState();

View File

@@ -495,6 +495,14 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// This configures post-process materials by setting constant parameters
if (taaOptions.enabled) {
ppm.configureTemporalAntiAliasingMaterial(taaOptions);
if (taaOptions.upscaling) {
// for now TAA upscaling is incompatible with regular dsr
dsrOptions.enabled = false;
// also, upscaling doesn't work well with quater-resolution SSAO
aoOptions.resolution = 1.0;
// Currently we only support a fixed TAA upscaling ratio
scale = 0.5f;
}
}
}
@@ -525,7 +533,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
};
// whether we're scaled at all
const bool scaled = any(notEqual(scale, float2(1.0f)));
bool scaled = any(notEqual(scale, float2(1.0f)));
// vp is the user defined viewport within the View
filament::Viewport const& vp = view.getViewport();
@@ -614,7 +622,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
view.prepare(engine, driver, arena, svp, cameraInfo, getShaderUserTime(), needsAlphaChannel);
view.prepareUpscaler(scale, dsrOptions);
view.prepareUpscaler(scale, taaOptions, dsrOptions);
/*
* Allocate command buffer
@@ -1011,6 +1019,15 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
if (taaOptions.enabled) {
input = ppm.taa(fg, input, depth, view.getFrameHistory(), &FrameHistoryEntry::taa,
taaOptions, colorGradingConfig);
if (taaOptions.upscaling) {
scale = 1.0f;
scaled = false;
UTILS_UNUSED_IN_RELEASE auto const& inputDesc = fg.getDescriptor(input);
svp.width = inputDesc.width;
svp.height = inputDesc.height;
xvp.width *= 2;
xvp.height *= 2;
}
}
// --------------------------------------------------------------------------------------------
@@ -1026,16 +1043,21 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
// The bokeh height is always correct regardless of the dynamic resolution scaling.
// (because the CoC is calculated w.r.t. the height), so we only need to adjust
// the width.
float const bokehAspectRatio = scale.x / scale.y;
float const aspect = (scale.x / scale.y) * dofOptions.cocAspectRatio;
float2 const bokehScale{
aspect < 1.0f ? aspect : 1.0f,
aspect > 1.0f ? 1.0f / aspect : 1.0f
};
input = ppm.dof(fg, input, depth, cameraInfo, needsAlphaChannel,
bokehAspectRatio, dofOptions);
bokehScale, dofOptions);
}
FrameGraphId<FrameGraphTexture> bloom, flare;
if (bloomOptions.enabled) {
// Generate the bloom buffer, which is stored in the blackboard as "bloom". This is
// consumed by the colorGrading pass and will be culled if colorGrading is disabled.
auto [bloom_, flare_] = ppm.bloom(fg, input, bloomOptions, TextureFormat::R11F_G11F_B10F, scale);
auto [bloom_, flare_] = ppm.bloom(fg, input, TextureFormat::R11F_G11F_B10F,
bloomOptions, taaOptions, scale);
bloom = bloom_;
flare = flare_;
}

View File

@@ -725,11 +725,22 @@ UTILS_NOINLINE
});
}
void FView::prepareUpscaler(float2 scale, DynamicResolutionOptions const& options) const noexcept {
void FView::prepareUpscaler(float2 scale,
TemporalAntiAliasingOptions const& taaOptions,
DynamicResolutionOptions const& dsrOptions) const noexcept {
SYSTRACE_CALL();
const float bias = (options.quality >= QualityLevel::HIGH) ?
std::log2(std::min(scale.x, scale.y)) : 0.0f;
mPerViewUniforms.prepareLodBias(bias);
float bias = 0.0f;
float2 derivativesScale{ 1.0f };
if (dsrOptions.enabled && dsrOptions.quality >= QualityLevel::HIGH) {
bias = std::log2(std::min(scale.x, scale.y));
}
if (taaOptions.enabled) {
bias += taaOptions.lodBias;
if (taaOptions.upscaling) {
derivativesScale = 0.5f;
}
}
mPerViewUniforms.prepareLodBias(bias, derivativesScale);
}
void FView::prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) const noexcept {

View File

@@ -133,7 +133,9 @@ public:
return mName.c_str_safe();
}
void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) const noexcept;
void prepareUpscaler(math::float2 scale,
TemporalAntiAliasingOptions const& taaOptions,
DynamicResolutionOptions const& dsrOptions) const noexcept;
void prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) const noexcept;
void prepareViewport(

View File

@@ -240,7 +240,8 @@ void postProcess(inout PostProcessInputs postProcess) {
history.rgb = RGB_YCoCg(history.rgb);
}
highp vec2 p = uv.xy;
highp vec2 size = vec2(textureSize(materialParams_color, 0));
highp vec2 p = (floor(uv.xy * size) + 0.5) / size;
vec4 color = textureLod(materialParams_color, p, 0.0);
vec3 s[9];
@@ -265,15 +266,25 @@ void postProcess(inout PostProcessInputs postProcess) {
}
}
vec4 filtered;
vec2 subPixelOffset = p - uv.xy; // +/- [0.25, 0.25]
float confidence = 0.0;
vec4 filtered = color;
if (materialConstants_filterInput) {
// unjitter/filter input
// figure out which set of coeficients to use
int jxp = subPixelOffset.y > 0.0 ? 3 : 0;
int jxn = subPixelOffset.y > 0.0 ? 2 : 1;
int j = subPixelOffset.x > 0.0 ? jxp : jxn;
filtered = vec4(0, 0, 0, color.a);
for (int i = 0; i < 9; i++) {
filtered.rgb += s[i] * materialParams.filterWeights[i][0];
float w = materialParams.filterWeights[i][j];
filtered.rgb += s[i] * w;
confidence = max(confidence, w);
}
} else {
filtered = color;
confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 &&
materialParams.jitter.y * subPixelOffset.y > 0.0);
}
// build the history clamping box
@@ -321,7 +332,7 @@ void postProcess(inout PostProcessInputs postProcess) {
float lumaColor = luma(filtered.rgb);
float lumaHistory = luma(history.rgb);
float alpha = materialParams.alpha;
float alpha = materialParams.alpha * confidence;
if (materialConstants_preventFlickering) {
// [Lottes] prevents flickering by modulating the blend weight by the difference in luma
float diff = 1.0 - abs(lumaColor - lumaHistory) / (0.001 + max(lumaColor, lumaHistory));

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.49.2"
spec.version = "1.49.3"
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
spec.homepage = "https://google.github.io/filament"
spec.authors = "Google LLC."
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
spec.platform = :ios, "11.0"
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.49.2/filament-v1.49.2-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.49.3/filament-v1.49.3-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -47,6 +47,9 @@ const float kToastDelayDuration = 2.0f;
- (void)createRenderables;
- (void)createLights;
- (void)appWillResignActive:(NSNotification*)notification;
- (void)appDidBecomeActive:(NSNotification*)notification;
@end
@implementation FILViewController {
@@ -73,6 +76,16 @@ const float kToastDelayDuration = 2.0f;
self.title = @"https://google.github.io/filament/remote";
// Observe lifecycle notifications to prevent us from rendering in the background.
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(appWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector(appDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
// Arguments:
// --model <path>
// path to glb or gltf file to load from documents directory
@@ -125,6 +138,14 @@ const float kToastDelayDuration = 2.0f;
[self.view addSubview:_toastLabel];
}
- (void)appWillResignActive:(NSNotification*)notification {
[self stopDisplayLink];
}
- (void)appDidBecomeActive:(NSNotification*)notification {
[self startDisplayLink];
}
- (void)viewWillAppear:(BOOL)animated {
[self startDisplayLink];
}
@@ -330,6 +351,7 @@ const float kToastDelayDuration = 2.0f;
}
- (void)dealloc {
[NSNotificationCenter.defaultCenter removeObserver:self];
delete _server;
delete _automation;
self.modelView.engine->destroy(_indirectLight);

View File

@@ -99,6 +99,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float lodBias; // load bias to apply to user materials
float refractionLodOffset;
math::float2 derivativesScale;
// camera position in view space (when camera_at_origin is enabled), i.e. it's (0,0,0).
float oneOverFarMinusNear; // 1 / (f-n), always positive
@@ -111,8 +112,6 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
// AO
float aoSamplingQualityAndEdgeDistance; // <0: no AO, 0: bilinear, !0: bilateral edge distance
float aoBentNormals; // 0: no AO bent normal, >0.0 AO bent normals
float aoReserved0;
float aoReserved1;
// --------------------------------------------------------------------------------------------
// Dynamic Lighting [variant: DYN]

View File

@@ -1168,7 +1168,6 @@ error:
mVariantFilter |= uint32_t(UserVariantFilterBit::SHADOW_RECEIVER);
mVariantFilter |= uint32_t(UserVariantFilterBit::VSM);
mVariantFilter |= uint32_t(UserVariantFilterBit::SSR);
mVariantFilter |= uint32_t(UserVariantFilterBit::STE);
}
// Create chunk tree.

View File

@@ -52,7 +52,7 @@ void ShaderGenerator::generateSurfaceMaterialVariantDefines(utils::io::sstream&
CodeGenerator::generateDefine(out, "VARIANT_HAS_VSM",
filament::Variant::isVSMVariant(variant));
CodeGenerator::generateDefine(out, "VARIANT_HAS_INSTANCED_STEREO",
filament::Variant::isStereoVariant(variant));
hasInstancedStereo(variant, featureLevel));
switch (stage) {
case ShaderStage::VERTEX:
@@ -758,4 +758,12 @@ bool ShaderGenerator::hasSkinningOrMorphing(
&& featureLevel > MaterialBuilder::FeatureLevel::FEATURE_LEVEL_0;
}
bool ShaderGenerator::hasInstancedStereo(
filament::Variant variant, MaterialBuilder::FeatureLevel featureLevel) noexcept {
return variant.hasInstancedStereo()
// HACK(exv): Ignore stereo variant when targeting ESSL 1.0. We should properly build a
// system in matc which allows the set of included variants to differ per-feature level.
&& featureLevel > MaterialBuilder::FeatureLevel::FEATURE_LEVEL_0;
}
} // namespace filament

View File

@@ -115,6 +115,10 @@ private:
filament::Variant variant,
MaterialBuilder::FeatureLevel featureLevel) noexcept;
static bool hasInstancedStereo(
filament::Variant variant,
MaterialBuilder::FeatureLevel featureLevel) noexcept;
MaterialBuilder::PropertyList mProperties;
MaterialBuilder::VariableList mVariables;
MaterialBuilder::OutputList mOutputs;

View File

@@ -60,6 +60,7 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
{ "lodBias", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 },
{ "refractionLodOffset", 0, Type::FLOAT, Precision::DEFAULT, FeatureLevel::FEATURE_LEVEL_0 },
{ "derivativesScale", 0, Type::FLOAT2 },
{ "oneOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
{ "nearOverFarMinusNear", 0, Type::FLOAT, Precision::HIGH, FeatureLevel::FEATURE_LEVEL_0 },
@@ -71,8 +72,6 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
// AO
{ "aoSamplingQualityAndEdgeDistance", 0, Type::FLOAT },
{ "aoBentNormals", 0, Type::FLOAT },
{ "aoReserved0", 0, Type::FLOAT },
{ "aoReserved1", 0, Type::FLOAT },
// ------------------------------------------------------------------------------------
// Dynamic Lighting [variant: DYN]

View File

@@ -12,6 +12,11 @@
margin: 0;
font-family: "Open Sans";
}
@font-face {
font-family: codicon;
src: url(https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/vs/base/browser/ui/codicons/codicon/codicon.ttf);
}
</style>
<script src="api.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/vs/loader.js"></script>

View File

@@ -111,7 +111,7 @@ private:
friend ostream& hex(ostream& s) noexcept;
friend ostream& dec(ostream& s) noexcept;
friend ostream& endl(ostream& s) noexcept;
friend ostream& flush(ostream& s) noexcept;
UTILS_PUBLIC friend ostream& flush(ostream& s) noexcept;
enum type {
SHORT, USHORT, CHAR, UCHAR, INT, UINT, LONG, ULONG, LONG_LONG, ULONG_LONG, FLOAT, DOUBLE,

View File

@@ -391,6 +391,8 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt
CHECK_KEY(tok);
if (compare(tok, jsonChunk, "cocScale") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cocScale);
} else if (compare(tok, jsonChunk, "cocAspectRatio") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->cocAspectRatio);
} else if (compare(tok, jsonChunk, "maxApertureDiameter") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->maxApertureDiameter);
} else if (compare(tok, jsonChunk, "enabled") == 0) {
@@ -424,6 +426,7 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOpt
std::ostream& operator<<(std::ostream& out, const DepthOfFieldOptions& in) {
return out << "{\n"
<< "\"cocScale\": " << (in.cocScale) << ",\n"
<< "\"cocAspectRatio\": " << (in.cocAspectRatio) << ",\n"
<< "\"maxApertureDiameter\": " << (in.maxApertureDiameter) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"filter\": " << (in.filter) << ",\n"
@@ -716,8 +719,12 @@ int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, TemporalAntiAli
i = parse(tokens, i + 1, jsonChunk, &out->filterWidth);
} else if (compare(tok, jsonChunk, "feedback") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->feedback);
} else if (compare(tok, jsonChunk, "lodBias") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->lodBias);
} else if (compare(tok, jsonChunk, "enabled") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
} else if (compare(tok, jsonChunk, "upscaling") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->upscaling);
} else if (compare(tok, jsonChunk, "filterHistory") == 0) {
i = parse(tokens, i + 1, jsonChunk, &out->filterHistory);
} else if (compare(tok, jsonChunk, "filterInput") == 0) {
@@ -752,7 +759,9 @@ std::ostream& operator<<(std::ostream& out, const TemporalAntiAliasingOptions& i
return out << "{\n"
<< "\"filterWidth\": " << (in.filterWidth) << ",\n"
<< "\"feedback\": " << (in.feedback) << ",\n"
<< "\"lodBias\": " << (in.lodBias) << ",\n"
<< "\"enabled\": " << to_string(in.enabled) << ",\n"
<< "\"upscaling\": " << to_string(in.upscaling) << ",\n"
<< "\"filterHistory\": " << to_string(in.filterHistory) << ",\n"
<< "\"filterInput\": " << to_string(in.filterInput) << ",\n"
<< "\"useYCoCg\": " << to_string(in.useYCoCg) << ",\n"

View File

@@ -793,11 +793,13 @@ void ViewerGui::updateUserInterface() {
}
if (ImGui::CollapsingHeader("TAA Options")) {
ImGui::Checkbox("Upscaling", &mSettings.view.taa.upscaling);
ImGui::Checkbox("History Reprojection", &mSettings.view.taa.historyReprojection);
ImGui::SliderFloat("Feedback", &mSettings.view.taa.feedback, 0.0f, 1.0f);
ImGui::Checkbox("Filter History", &mSettings.view.taa.filterHistory);
ImGui::Checkbox("Filter Input", &mSettings.view.taa.filterInput);
ImGui::SliderFloat("FilterWidth", &mSettings.view.taa.filterWidth, 0.2f, 2.0f);
ImGui::SliderFloat("LOD bias", &mSettings.view.taa.lodBias, -8.0f, 0.0f);
ImGui::Checkbox("Use YCoCg", &mSettings.view.taa.useYCoCg);
ImGui::Checkbox("Prevent Flickering", &mSettings.view.taa.preventFlickering);
int jitterSequence = (int)mSettings.view.taa.jitterPattern;
@@ -1034,6 +1036,7 @@ void ViewerGui::updateUserInterface() {
ImGui::Checkbox("Enabled##dofEnabled", &mSettings.view.dof.enabled);
ImGui::SliderFloat("Focus distance", &mSettings.viewer.cameraFocusDistance, 0.0f, 30.0f);
ImGui::SliderFloat("Blur scale", &mSettings.view.dof.cocScale, 0.1f, 10.0f);
ImGui::SliderFloat("CoC aspect-ratio", &mSettings.view.dof.cocAspectRatio, 0.25f, 4.0f);
ImGui::SliderInt("Ring count", &dofRingCount, 1, 17);
ImGui::SliderInt("Max CoC", &dofMaxCoC, 1, 32);
ImGui::Checkbox("Native Resolution", &mSettings.view.dof.nativeResolution);

View File

@@ -37,8 +37,11 @@ float normalFiltering(float perceptualRoughness, const vec3 worldNormal) {
vec3 du = dFdx(worldNormal);
vec3 dv = dFdy(worldNormal);
float variance = materialParams._specularAntiAliasingVariance * (dot(du, du) + dot(dv, dv));
// specular AA factor to correct for resolution scaling (DSR and TAAx4)
du *= frameUniforms.derivativesScale.x;
dv *= frameUniforms.derivativesScale.y;
float variance = materialParams._specularAntiAliasingVariance * (dot(du, du) + dot(dv, dv));
float roughness = perceptualRoughnessToRoughness(perceptualRoughness);
float kernelRoughness = min(2.0 * variance, materialParams._specularAntiAliasingThreshold);
float squareRoughness = saturate(roughness * roughness + kernelRoughness);

View File

@@ -27,9 +27,7 @@ JsonType JsonishLexer::readIdentifier() noexcept {
consume();
}
const char* lexemeEnd = mCursor - 1;
size_t lexemeSize = lexemeEnd - lexemeStart;
size_t lexemeSize = mCursor - lexemeStart;
// Check what kind of keyword we got here.
if (strncmp("true", lexemeStart, lexemeSize) == 0) {

View File

@@ -229,7 +229,7 @@ static bool reflectParameters(const MaterialBuilder& builder) {
std::cout << R"( "format": ")" <<
Enums::toString(parameter.format) << "\"," << std::endl;
std::cout << R"( "precision": ")" <<
Enums::toString(parameter.precision) << "\"" << std::endl;
Enums::toString(parameter.precision) << "\"," << std::endl;
std::cout << R"( "multisample": ")" <<
(parameter.multisample ? "true" : "false")<< "\"" << std::endl;
} else if (parameter.isUniform()) {

View File

@@ -60,6 +60,7 @@ Filament.loadGeneratedExtensions = function() {
Filament.View.prototype.setDepthOfFieldOptionsDefaults = function(overrides) {
const options = {
cocScale: 1.0,
cocAspectRatio: 1.0,
maxApertureDiameter: 0.01,
enabled: false,
filter: Filament.View$DepthOfFieldOptions$Filter.MEDIAN,
@@ -139,7 +140,9 @@ Filament.loadGeneratedExtensions = function() {
const options = {
filterWidth: 1.0,
feedback: 0.12,
lodBias: -1.0,
enabled: false,
upscaling: false,
filterHistory: true,
filterInput: true,
useYCoCg: false,

View File

@@ -1409,6 +1409,10 @@ export interface View$DepthOfFieldOptions {
* circle of confusion scale factor (amount of blur)
*/
cocScale?: number;
/**
* width/height aspect ratio of the circle of confusion (simulate anamorphic lenses)
*/
cocAspectRatio?: number;
/**
* maximum aperture diameter in meters (zero to disable rotation)
*/
@@ -1659,7 +1663,7 @@ export enum View$TemporalAntiAliasingOptions$JitterPattern {
* Options for Temporal Anti-aliasing (TAA)
* Most TAA parameters are extremely costly to change, as they will trigger the TAA post-process
* shaders to be recompiled. These options should be changed or set during initialization.
* `filterWidth`, `feedback` and `jitterPattern`, however, can be changed at any time.
* `filterWidth`, `feedback` and `jitterPattern`, however, could be changed at any time.
*
* `feedback` of 0.1 effectively accumulates a maximum of 19 samples in steady state.
* see "A Survey of Temporal Antialiasing Techniques" by Lei Yang and all for more information.
@@ -1675,10 +1679,18 @@ export interface View$TemporalAntiAliasingOptions {
* history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
*/
feedback?: number;
/**
* texturing lod bias (typically -1 or -2)
*/
lodBias?: number;
/**
* enables or disables temporal anti-aliasing
*/
enabled?: boolean;
/**
* 4x TAA upscaling. Disables Dynamic Resolution. [BETA]
*/
upscaling?: boolean;
/**
* whether to filter the history buffer
*/

View File

@@ -58,6 +58,7 @@ value_object<View::FogOptions>("View$FogOptions")
value_object<View::DepthOfFieldOptions>("View$DepthOfFieldOptions")
.field("cocScale", &View::DepthOfFieldOptions::cocScale)
.field("cocAspectRatio", &View::DepthOfFieldOptions::cocAspectRatio)
.field("maxApertureDiameter", &View::DepthOfFieldOptions::maxApertureDiameter)
.field("enabled", &View::DepthOfFieldOptions::enabled)
.field("filter", &View::DepthOfFieldOptions::filter)
@@ -119,7 +120,9 @@ value_object<View::MultiSampleAntiAliasingOptions>("View$MultiSampleAntiAliasing
value_object<View::TemporalAntiAliasingOptions>("View$TemporalAntiAliasingOptions")
.field("filterWidth", &View::TemporalAntiAliasingOptions::filterWidth)
.field("feedback", &View::TemporalAntiAliasingOptions::feedback)
.field("lodBias", &View::TemporalAntiAliasingOptions::lodBias)
.field("enabled", &View::TemporalAntiAliasingOptions::enabled)
.field("upscaling", &View::TemporalAntiAliasingOptions::upscaling)
.field("filterHistory", &View::TemporalAntiAliasingOptions::filterHistory)
.field("filterInput", &View::TemporalAntiAliasingOptions::filterInput)
.field("useYCoCg", &View::TemporalAntiAliasingOptions::useYCoCg)

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.49.2",
"version": "1.49.3",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",

View File

@@ -203,7 +203,9 @@ set(HTML_FILES
skinning.html
suzanne.html
test-filament-viewer.html
triangle.html)
triangle.html
benchmark-shader-compilation.html
benchmark-shader-compilation.js)
set(ASSET_FILES
assets/favicon.png)

View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Shader Compilation Benchmark</title>
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1">
<style>
body { margin: 0; overflow: hidden; }
canvas { touch-action: none; width: 100%; height: 100%; }
.frame-time { position: absolute; color: #ffffff; }
</style>
</head>
<body>
<div class="frame-time">
Average Frame Time: <span id="frame-time-counter">Calculating...</span>
</div>
<canvas></canvas>
<script src="filament.js"></script>
<script src="gl-matrix-min.js"></script>
<script src="benchmark-shader-compilation.js"></script>
</body>
</html>

View File

@@ -0,0 +1,141 @@
Filament.init(['nonlit.filamat'], () => {
window.VertexAttribute = Filament.VertexAttribute;
window.AttributeType = Filament.VertexBuffer$AttributeType;
window.Projection = Filament.Camera$Projection;
window.app = new App(
document.getElementsByTagName('canvas')[0],
document.getElementById('frame-time-counter'));
});
const NUMBER_OF_TRIANGLES = 100;
// probably 60 fps; record 1 seconds ish worth of frames.
const NUMBER_OF_FRAMES_TO_RECORD_FPS = 1 * 60;
class App {
constructor(canvas, frameTimeCounter) {
this.canvas = canvas;
this.frameTimeCounter = frameTimeCounter;
this.lastFrameTime = null;
this.frameDeltas = [];
for (let i = 0; i < NUMBER_OF_FRAMES_TO_RECORD_FPS; ++i) {
this.frameDeltas.push(0);
}
this.frameDeltasIndex = 0;
this.frameDeltasSum = 0;
this.frameTimeIsValid = false;
const engine = this.engine = Filament.Engine.create(this.canvas);
this.scene = engine.createScene();
this.triangles = [];
for (let i = 0; i < NUMBER_OF_TRIANGLES; ++i) {
const entity = Filament.EntityManager.get().create();
this.triangles.push({entity: entity});
this.scene.addEntity(entity);
}
const TRIANGLE_POSITIONS = new Float32Array([
1,
0,
Math.cos(Math.PI * 2 / 3),
Math.sin(Math.PI * 2 / 3),
Math.cos(Math.PI * 4 / 3),
Math.sin(Math.PI * 4 / 3),
]);
const TRIANGLE_COLORS =
new Uint32Array([0xffff0000, 0xff00ff00, 0xff0000ff]);
this.vb =
Filament.VertexBuffer.Builder()
.vertexCount(3)
.bufferCount(2)
.attribute(VertexAttribute.POSITION, 0, AttributeType.FLOAT2, 0, 8)
.attribute(VertexAttribute.COLOR, 1, AttributeType.UBYTE4, 0, 4)
.normalized(VertexAttribute.COLOR)
.build(engine);
this.vb.setBufferAt(engine, 0, TRIANGLE_POSITIONS);
this.vb.setBufferAt(engine, 1, TRIANGLE_COLORS);
this.ib = Filament.IndexBuffer.Builder()
.indexCount(3)
.bufferType(Filament.IndexBuffer$IndexType.USHORT)
.build(engine);
this.ib.setBuffer(engine, new Uint16Array([0, 1, 2]));
this.swapChain = engine.createSwapChain();
this.renderer = engine.createRenderer();
this.camera = engine.createCamera(Filament.EntityManager.get().create());
this.view = engine.createView();
this.view.setSampleCount(4);
this.view.setCamera(this.camera);
this.view.setScene(this.scene);
this.renderer.setClearOptions(
{clearColor: [0.0, 0.1, 0.2, 1.0], clear: true});
this.resize();
this.render = this.render.bind(this);
this.resize = this.resize.bind(this);
window.addEventListener('resize', this.resize);
window.requestAnimationFrame(this.render);
}
render() {
const frameTime = Date.now();
if (this.lastFrameTime) {
const delta = frameTime - this.lastFrameTime;
this.frameDeltasSum =
this.frameDeltasSum - this.frameDeltas[this.frameDeltasIndex] + delta;
this.frameDeltas[this.frameDeltasIndex] = delta;
this.frameDeltasIndex =
(this.frameDeltasIndex + 1) % NUMBER_OF_FRAMES_TO_RECORD_FPS;
if (this.frameDeltasIndex == 0) {
this.frameTimeIsValid = true;
}
}
this.lastFrameTime = frameTime;
if (this.frameTimeIsValid) {
const averageFrameDelta =
this.frameDeltasSum * 1.0 / NUMBER_OF_FRAMES_TO_RECORD_FPS;
this.frameTimeCounter.innerHTML = averageFrameDelta.toFixed(2) + ' ms';
}
this.triangles.forEach(triangle => {
if (triangle.mat) {
this.engine.destroyMaterial(triangle.mat);
}
triangle.mat = this.engine.createMaterial('nonlit.filamat');
const matinst = triangle.mat.getDefaultInstance();
Filament.RenderableManager.Builder(1)
.boundingBox({center: [-1, -1, -1], halfExtent: [1, 1, 1]})
.material(0, matinst)
.geometry(
0, Filament.RenderableManager$PrimitiveType.TRIANGLES, this.vb,
this.ib)
.build(this.engine, triangle.entity);
});
const radians = Date.now() / 1000;
const transform = mat4.fromRotation(mat4.create(), radians, [0, 0, 1]);
const tcm = this.engine.getTransformManager();
const inst = tcm.getInstance(this.triangles[0].entity);
tcm.setTransform(inst, transform);
inst.delete();
this.renderer.render(this.swapChain, this.view);
window.requestAnimationFrame(this.render);
}
resize() {
const dpr = window.devicePixelRatio;
const width = this.canvas.width = window.innerWidth * dpr;
const height = this.canvas.height = window.innerHeight * dpr;
this.view.setViewport([0, 0, width, height]);
const aspect = width / height;
this.camera.setProjection(Projection.ORTHO, -aspect, aspect, -1, 1, 0, 1);
}
}