Compare commits

..

24 Commits

Author SHA1 Message Date
Benjamin Doherty
bbe7dbfa92 Merge branch 'rc/1.14.1' into release 2021-11-22 10:11:06 -08:00
Benjamin Doherty
5697922a65 Update RELEASE_NOTES for 1.14.1 2021-11-17 12:04:26 -08:00
Ben Doherty
4da83df2b9 Fix material compilation error with device vertex domain (#4865)
A recent refactor was causing the following error when the vertex domain
was set to `device`:
```
ERROR: main.vs:23: 'material' : undeclared identifier
ERROR: main.vs:23: 'materialVertex' : no matching overloaded function found
```
2021-11-17 12:03:55 -08:00
Ben Doherty
8f156d6588 Android: re-enable VSM cascade fix (#4863) 2021-11-17 10:19:09 -08:00
Benjamin Doherty
cec0871c11 Bump version to 1.14.1 2021-11-15 10:09:45 -08:00
Benjamin Doherty
f690015a88 Release Filament 1.14.0 2021-11-15 10:06:45 -08:00
Ben Doherty
342deb5a64 speed up under ThreadSanitizer (#4842) 2021-11-12 09:52:58 -08:00
Mathias Agopian
fdc480ff6e Gaussian blur is now applied only on the needed channels
The gaussian blur code was always processing 3 channels no matter the
source or destination. We now have 4 versions for all possible cases.
2021-11-11 23:35:10 -08:00
Mathias Agopian
378b7cd4dd rearrange EVSM code to make it easy to test full EVSM
We're currently only using the positive layer of EVSM which works
work small blurs and anti-aliasing. This just rearranges the code to
make it easy to test the full formulation.
2021-11-11 23:35:10 -08:00
Mathias Agopian
f779fc7a0e move the shadowmap position computation inside shadow()
This is possible because, in fact, we know if we're dealing with a
spot or directional light when we invoke shadow(). So a conditional
inside it is resolved at compile time.

This will allow more flexibility in the future. Also now the shadow()
function only needs the shadow index and cascade -- which is more
future proof (e.g. if we want to handle more than one directional
shadow or spot lights with cascades).
2021-11-11 23:35:10 -08:00
Mathias Agopian
fe11f495d6 simplify how we compute the shadow position
this effectively undoes a recent change, where we had a method for
spot lights and one for the directional light. instead, we can
calculate the bias at the correct Z on the caller side -- which is
needed only for spotlights.
2021-11-11 23:35:10 -08:00
Mathias Agopian
265876c849 store the texel size in world-space in the spot shadow structure 2021-11-11 23:35:10 -08:00
Mathias Agopian
c9c52518c0 repair transparent shadows 2021-11-10 19:48:25 -08:00
Mathias Agopian
96c9ac6f8b fix point-lights which broke recently.
The faulty commit was:

commit 23dab0a013
Author: Mathias Agopian <mathias@google.com>
Date:   Fri Oct 29 12:03:14 2021 -0700

    Fix very narrow spotlight lighting and other minor issues
2021-11-10 15:22:38 -08:00
Ben Doherty
bdeb30a847 Use workflow_dispatch instead of repository_dispatch (#4834) 2021-11-10 13:38:58 -08:00
Romain Guy
d67210155b Skip task incompatible with configuration caching (#4831) 2021-11-09 15:01:02 -08:00
Mathias Agopian
ae92c50cee more robust GL compiler error parsing 2021-11-09 14:59:50 -08:00
Mathias Agopian
43429dc0ec remove depth_main.vs from source tree 2021-11-09 12:34:19 -08:00
Mathias Agopian
04cf92a27f Remove all "Shadow Receiver Plane Depth Bias" related code
Shadow Receiver Plane Depth Bias is only needed when using large PCF
filters, which we are no longer doing. Large filter kernels are now 
supported through VSM sampling.
2021-11-09 12:31:43 -08:00
Mathias Agopian
57a57f50f6 most methods can be static in CodeGenerator 2021-11-09 12:31:28 -08:00
Mathias Agopian
5e5a75e6c5 fix bug with MASKED blending mode introduced in previous PR 2021-11-09 10:27:52 -08:00
Mathias Agopian
109c86aaf7 get rid of depth_main.vs
It's functionality is now handled in main.vs which, hopefully will be
less error prone.
2021-11-09 09:54:50 -08:00
Mathias Agopian
10e7e7727a filamat cleanup
This changes how we select the "optimized depth vertex shader", but
this shouldn't change the current behavior.

We now select the "optimized depth vertex shader" if and only if the
user code is empty. In that case, we can safely assume we can remove
all the code that's not necessary for the depth, since it is all
controlled by filament.
2021-11-09 09:54:50 -08:00
Mathias Agopian
a39775050a workaround a IDE (CLion) code parsing bug
It looks like some parts of CLion don't like MaterialDomain because
it exists as an enum value
2021-11-09 09:54:50 -08:00
45 changed files with 856 additions and 614 deletions

View File

@@ -1,14 +1,25 @@
name: Release
# This Workflow can be triggered two ways:
# 1. A GitHub release is created (using the GitHub web UI). This triggers all of the platforms to build and upload assets.
# 2. A repository_dispatch API event is sent. This triggers a build for only the platform specified in the dispatch event.
# 1. A GitHub release is created (using the GitHub web UI). This triggers all of the platforms to
# build and upload assets.
# 2. A workflow_dispatch event is triggered from the GitHub web UI. This triggers a build for only
# the platform specified in the dispatch event.
env:
RELEASE_TAG: ${{ github.event.client_payload.release_tag }}
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
on:
repository_dispatch:
workflow_dispatch:
inputs:
platform:
description: 'Platform to build (desktop, web, android, ios, windows)'
required: true
default: 'desktop'
release_tag:
description: 'Release tag to build (e.g., v1.13.0)'
required: true
default: 'v1.13.0'
release:
types: [created]
@@ -16,7 +27,7 @@ jobs:
build-desktop:
name: build-desktop
runs-on: ${{ matrix.os }}
if: github.event_name == 'release' || github.event.client_payload.platform == 'desktop'
if: github.event_name == 'release' || github.event.inputs.platform == 'desktop'
strategy:
matrix:
@@ -51,7 +62,7 @@ jobs:
build-web:
name: build-web
runs-on: macos-latest
if: github.event_name == 'release' || github.event.client_payload.platform == 'web'
if: github.event_name == 'release' || github.event.inputs.platform == 'web'
steps:
- name: Decide Git ref
@@ -80,7 +91,7 @@ jobs:
build-android:
name: build-android
runs-on: macos-latest
if: github.event_name == 'release' || github.event.client_payload.platform == 'android'
if: github.event_name == 'release' || github.event.inputs.platform == 'android'
steps:
- name: Decide Git ref
@@ -129,7 +140,7 @@ jobs:
build-ios:
name: build-ios
runs-on: macos-latest
if: github.event_name == 'release' || github.event.client_payload.platform == 'ios'
if: github.event_name == 'release' || github.event.inputs.platform == 'ios'
steps:
- name: Decide Git ref
@@ -158,7 +169,7 @@ jobs:
build-windows:
name: build-windows
runs-on: windows-latest
if: github.event_name == 'release' || github.event.client_payload.platform == 'windows'
if: github.event_name == 'release' || github.event.inputs.platform == 'windows'
steps:
- name: Decide Git ref

View File

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

View File

@@ -3,7 +3,11 @@
This file contains one line summaries of commits that are worthy of mentioning in release notes.
A new header is inserted each time a *tag* is created.
## v1.14.1 (currently main branch)
## v1.14.2 (currently main branch)
## v1.14.1
- engine: Improvements to shadowing.
## v1.14.0

View File

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

View File

@@ -198,7 +198,10 @@ set(MATERIAL_SRCS
src/materials/skybox.mat
src/materials/ssao/sao.mat
src/materials/ssao/saoBentNormals.mat
src/materials/separableGaussianBlur.mat
src/materials/separableGaussianBlur1.mat
src/materials/separableGaussianBlur2.mat
src/materials/separableGaussianBlur3.mat
src/materials/separableGaussianBlur4.mat
src/materials/antiAliasing/fxaa.mat
src/materials/antiAliasing/taa.mat
src/materials/vsmMipmap.mat
@@ -393,6 +396,34 @@ add_custom_command(
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur1.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur2.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur3.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT "${MATERIAL_DIR}/separableGaussianBlur4.filamat"
DEPENDS src/materials/separableGaussianBlur.vs
DEPENDS src/materials/separableGaussianBlur.fs
APPEND
)
add_custom_command(
OUTPUT ${RESGEN_OUTPUTS}
COMMAND resgen ${RESGEN_FLAGS} ${MATERIAL_BINS}

View File

@@ -89,11 +89,10 @@ OpenGLContext::OpenGLContext() noexcept {
bugs.dont_use_timer_query = true;
// Blits to texture arrays are failing
// This bug doesn't happen anymore, but we don't know why. The standalone sample
// app that was written to show this problem still does. We have tested this on
// several V@0490.0 on several devices and the problem appears to have gone away.
// This bug continues to reproduce, though at times we've seen it appear to "go away". The
// standalone sample app that was written to show this problem still reproduces.
// The working hypthesis is that some other state affects this behavior.
bugs.disable_sidecar_blit_into_texture_array = false;
bugs.disable_sidecar_blit_into_texture_array = true;
// early exit condition is flattened in EASU code
bugs.split_easu = true;

View File

@@ -33,6 +33,13 @@ using namespace filament::math;
using namespace utils;
using namespace backend;
static void logCompilationError(utils::io::ostream& out,
backend::Program::Shader shaderType, const char* name,
GLuint shaderId, std::string_view source) noexcept;
static void logProgramLinkError(utils::io::ostream& out,
const char* name, GLuint program) noexcept;
OpenGLProgram::OpenGLProgram(OpenGLDriver* gl, const Program& programBuilder) noexcept
: HwProgram(programBuilder.getName()), mIsValid(false) {
@@ -57,7 +64,7 @@ OpenGLProgram::OpenGLProgram(OpenGLDriver* gl, const Program& programBuilder) no
if (!shadersSource[i].empty()) {
GLint status;
auto shader = shadersSource[i];
Program::ShaderBlob shader = shadersSource[i];
std::string temp;
std::string_view shaderView((const char*)shader.data(), shader.size());
@@ -123,17 +130,18 @@ highp uint packHalf2x16(vec2 v) {
shaderView = temp;
}
const char * const source = shaderView.data();
GLint length = (GLint)shaderView.length();
GLuint shaderId = glCreateShader(glShaderType);
glShaderSource(shaderId, 1, &source, &length);
glCompileShader(shaderId);
{ // scope for source/length (we don't want them to leak out)
const char* const source = shaderView.data();
const GLint length = (GLint)shaderView.length();
glShaderSource(shaderId, 1, &source, &length);
glCompileShader(shaderId);
}
glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
if (UTILS_UNLIKELY(status != GL_TRUE)) {
logCompilationError(slog.e, type,
programBuilder.getName().c_str_safe(), shaderId, source);
programBuilder.getName().c_str_safe(), shaderId, shaderView);
glDeleteShader(shaderId);
return;
}
@@ -315,8 +323,8 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
}
UTILS_NOINLINE
void OpenGLProgram::logCompilationError(io::ostream& out, Program::Shader shaderType,
const char* name, GLuint shaderId, char const* source) noexcept {
void logCompilationError(io::ostream& out, Program::Shader shaderType,
const char* name, GLuint shaderId, std::string_view shader) noexcept {
auto to_string = [](Program::Shader type) -> const char* {
switch (type) {
@@ -333,23 +341,26 @@ void OpenGLProgram::logCompilationError(io::ostream& out, Program::Shader shader
<< io::endl;
size_t lc = 1;
char* shader = strdup(source);
char* start = shader;
char* endl = strchr(start, '\n');
while (endl != nullptr) {
*endl = '\0';
out << lc++ << ": ";
out << start << io::endl;
start = endl + 1;
endl = strchr(start, '\n');
size_t start = 0;
std::string line;
while (true) {
size_t end = shader.find('\n', start);
if (end == std::string::npos) {
line = shader.substr(start);
} else {
line = shader.substr(start, end - start);
}
out << lc++ << ": "<< line.c_str() << '\n';
if (end == std::string::npos) {
break;
}
start = end + 1;
}
free(shader);
out << io::endl;
}
UTILS_NOINLINE
void OpenGLProgram::logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
char error[1024];
glGetProgramInfoLog(program, sizeof(error), nullptr, error);

View File

@@ -66,13 +66,6 @@ public:
GLuint program;
} gl; // 12 bytes
static void logCompilationError(utils::io::ostream& out,
backend::Program::Shader shaderType, const char* name,
GLuint shaderId, char const* source) noexcept;
static void logProgramLinkError(utils::io::ostream& out,
const char* name, GLuint program) noexcept;
private:
static constexpr uint8_t TEXTURE_UNIT_COUNT = OpenGLContext::MAX_TEXTURE_UNIT_COUNT;
static constexpr uint8_t VERTEX_SHADER_BIT = uint8_t(1) << size_t(backend::Program::Shader::VERTEX);

View File

@@ -572,9 +572,13 @@ void Froxelizer::froxelizeLoop(FEngine& engine,
.position = (camera.view * float4{ spheres[j].xyz, 1 }).xyz, // to view-space
.cosSqr = std::min(maxCosSquared, lcm.getCosOuterSquared(li)), // spot only
.axis = vn * directions[j], // spot only
.invSin = std::min(maxInvSin, lcm.getSinInverse(li)), // spot only
.invSin = lcm.getSinInverse(li), // spot only
.radius = spheres[j].w,
};
// infinity means "pointlight"
if (light.invSin != std::numeric_limits<float>::infinity()) {
light.invSin = std::min(maxInvSin, light.invSin);
}
const size_t group = i % GROUP_COUNT;
const size_t bit = i / GROUP_COUNT;

View File

@@ -224,7 +224,10 @@ static const MaterialInfo sMaterialList[] = {
{ "mipmapDepth", MATERIAL(MIPMAPDEPTH) },
{ "sao", MATERIAL(SAO) },
{ "saoBentNormals", MATERIAL(SAOBENTNORMALS) },
{ "separableGaussianBlur", MATERIAL(SEPARABLEGAUSSIANBLUR) },
{ "separableGaussianBlur1", MATERIAL(SEPARABLEGAUSSIANBLUR1) },
{ "separableGaussianBlur2", MATERIAL(SEPARABLEGAUSSIANBLUR2) },
{ "separableGaussianBlur3", MATERIAL(SEPARABLEGAUSSIANBLUR3) },
{ "separableGaussianBlur4", MATERIAL(SEPARABLEGAUSSIANBLUR4) },
{ "taa", MATERIAL(TAA) },
{ "vsmMipmap", MATERIAL(VSMMIPMAP) },
{ "fsr_easu", MATERIAL(FSR_EASU) },
@@ -844,7 +847,23 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
[=](FrameGraphResources const& resources,
auto const& data, DriverApi& driver) {
auto const& separableGaussianBlur = getPostProcessMaterial("separableGaussianBlur");
auto hwTempRT = resources.getRenderPassInfo(0);
auto hwOutRT = resources.getRenderPassInfo(1);
auto hwTemp = resources.getTexture(data.temp);
auto hwIn = resources.getTexture(data.in);
auto const& inDesc = resources.getDescriptor(data.in);
auto const& outDesc = resources.getDescriptor(data.out);
auto const& tempDesc = resources.getDescriptor(data.temp);
utils::StaticString materialName;
switch (backend::getFormatSize(outDesc.format)) {
case 1: materialName = "separableGaussianBlur1"; break;
case 2: materialName = "separableGaussianBlur2"; break;
case 3: materialName = "separableGaussianBlur3"; break;
default: materialName = "separableGaussianBlur4"; break;
}
auto const& separableGaussianBlur = getPostProcessMaterial(materialName);
FMaterialInstance* const mi = separableGaussianBlur.getMaterialInstance();
const size_t kernelStorageSize = mi->getMaterial()->reflect("kernel")->size;
@@ -853,13 +872,6 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
std::min(sizeof(kernel) / sizeof(*kernel), kernelStorageSize));
// horizontal pass
auto hwTempRT = resources.getRenderPassInfo(0);
auto hwOutRT = resources.getRenderPassInfo(1);
auto hwTemp = resources.getTexture(data.temp);
auto hwIn = resources.getTexture(data.in);
auto const& inDesc = resources.getDescriptor(data.in);
auto const& outDesc = resources.getDescriptor(data.out);
auto const& tempDesc = resources.getDescriptor(data.temp);
mi->setParameter("source", hwIn, {
.filterMag = SamplerMagFilter::LINEAR,

View File

@@ -346,10 +346,10 @@ void ShadowMap::updateDirectional(const FScene::LightSoa& lightData, size_t inde
// note: in texelSizeWorldSpace() below, we could use Mb * Mt * F * W because
// L * Mp * Mv is a rigid transform (for directional lights)
if (USE_LISPSM) {
mTexelSizeWs = texelSizeWorldSpace(Wp, mat4f(MbMt * F));
mTexelSizeAtOneMeterWs = texelSizeWorldSpace(Wp, mat4f(MbMt * F));
} else {
// We know we're using an ortho projection
mTexelSizeWs = texelSizeWorldSpace(St.upperLeft());
mTexelSizeAtOneMeterWs = texelSizeWorldSpace(St.upperLeft());
}
if (!mShadowMapInfo.vsm) {
mLightSpace = St;
@@ -429,9 +429,8 @@ void ShadowMap::updateSpot(const FScene::LightSoa& lightData, size_t index,
// For spotlights, we store the texel size at 1 world unit
// The size of a texel in world unit is given by: (near/dimension) / lightspace.z,
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
// Note: this would not work with LISPSM, which warps the texture space.
mTexelSizeWs = 0.5f * nearPlane / float(mShadowMapInfo.shadowDimension);
mTexelSizeAtOneMeterWs = nearPlane / float(mShadowMapInfo.shadowDimension);
if (!mShadowMapInfo.vsm) {
mLightSpace = St;

View File

@@ -116,7 +116,7 @@ public:
math::mat4f const& getLightSpaceMatrix() const noexcept { return mLightSpace; }
// return the size of a texel in world space (pre-warping)
float getTexelSizeWorldSpace() const noexcept { return mTexelSizeWs; }
float getTexelSizAtOneMeterWs() const noexcept { return mTexelSizeAtOneMeterWs; }
// Returns the light's projection. Valid after calling update().
FCamera const& getCamera() const noexcept { return *mCamera; }
@@ -233,7 +233,7 @@ private:
FCamera* mCamera = nullptr; // 8
FCamera* mDebugCamera = nullptr; // 8
math::mat4f mLightSpace; // 64
float mTexelSizeWs = 0.0f; // 4
float mTexelSizeAtOneMeterWs = 0.0f; // 4
// set-up in update()
ShadowMapInfo mShadowMapInfo; // 20

View File

@@ -368,11 +368,14 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
FView::cullRenderables(engine.getJobSystem(), renderableData, frustum,
VISIBLE_DIR_SHADOW_RENDERABLE_BIT);
// note: normalBias is set to zero for VSM
const float normalBias = shadowMapInfo.vsm ? 0.0f : lcm.getShadowNormalBias(0);
// Set shadowBias, using the first directional cascade.
const float texelSizeWorldSpace = shadowMap.getTexelSizeWorldSpace();
mShadowMappingUniforms.shadowBias = float3{ 0, normalBias * texelSizeWorldSpace, 0 };
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
// note: normalBias is set to zero for VSM
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
// Texel size is constant for directional light (although that's not true when LISPSM
// is used, but in that case we're pretending it is).
const float wsTexelSize = shadowMap.getTexelSizAtOneMeterWs();
mShadowMappingUniforms.shadowBias = float3{ 0, normalBias * wsTexelSize, 0 };
}
// Adjust the near and far planes to tightly bound the scene.
@@ -529,13 +532,15 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
shadowInfo[lightIndex].index = i;
shadowInfo[lightIndex].layer = entry.getLayer();
const float wsTexelSizeAtOneMeter = shadowMap.getTexelSizAtOneMeterWs();
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
// note: normalBias is set to zero for VSM
const float texelSizeWorldSpace = shadowMap.getTexelSizeWorldSpace();
const float normalBias = shadowMapInfo.vsm ? 0.0f : options->normalBias;
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * options->normalBias;
auto& s = shadowUb.edit();
s.shadows[i].direction = direction;
s.shadows[i].normalBias = normalBias * texelSizeWorldSpace;
s.shadows[i].normalBias = normalBias * wsTexelSizeAtOneMeter;
s.shadows[i].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
s.shadows[i].lightFromWorldMatrix = shadowMap.getLightSpaceMatrix();
shadowTechnique |= ShadowTechnique::SHADOW_MAP;

View File

@@ -0,0 +1,49 @@
// BLUR_TYPE and BLUR_SWIZZLE must be defined
// BLUR_TYPE vec2, vec3, vec4
// BLUR_SWIZZLE r, rg, rgb, rgba
float vmax(const float v) {
return v;
}
void tap(inout highp BLUR_TYPE sum, const float weight, const highp vec2 position) {
vec4 s = textureLod(materialParams_source, position, materialParams.level);
sum.BLUR_SWIZZLE += s.BLUR_SWIZZLE * weight;
}
void tapReinhard(inout highp BLUR_TYPE sum, inout float totalWeight, const float weight, const highp vec2 position) {
vec4 s = textureLod(materialParams_source, position, materialParams.level);
float w = weight / (1.0 + vmax(s.BLUR_SWIZZLE));
totalWeight += w;
sum.BLUR_SWIZZLE += s.BLUR_SWIZZLE * w;
}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
// we handle the center pixel separately
highp BLUR_TYPE sum = BLUR_TYPE(0.0);
if (materialParams.reinhard != 0) {
float totalWeight = 0.0;
tapReinhard(sum, totalWeight, materialParams.kernel[0].x, uv);
vec2 offset = materialParams.axis;
for (int i = 1; i < materialParams.count; i++, offset += materialParams.axis * 2.0) {
float k = materialParams.kernel[i].x;
vec2 o = offset + materialParams.axis * materialParams.kernel[i].y;
tapReinhard(sum, totalWeight, k, uv + o);
tapReinhard(sum, totalWeight, k, uv - o);
}
sum *= 1.0 / totalWeight;
} else {
tap(sum, materialParams.kernel[0].x, uv);
vec2 offset = materialParams.axis;
for (int i = 1; i < materialParams.count; i++, offset += materialParams.axis * 2.0) {
float k = materialParams.kernel[i].x;
vec2 o = offset + materialParams.axis * materialParams.kernel[i].y;
tap(sum, k, uv + o);
tap(sum, k, uv - o);
}
}
postProcess.color.BLUR_SWIZZLE = sum.BLUR_SWIZZLE;
}

View File

@@ -1,95 +0,0 @@
material {
name : separableGaussianBlur,
parameters : [
{
type : sampler2d,
name : source,
precision: medium
},
{
type : float4,
name : resolution,
precision: high
},
{
type : float2,
name : axis
},
{
type : float,
name : level
},
{
type : int,
name : count
},
{
type : int,
name : reinhard
},
{
type : float2[32],
name : kernel
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// in the fragment shader, this is interpolated to pixel centers, but since we use
// texel-fetch, it's not what we want. Convert from screen uv to texture uv.
vec2 size = vec2(textureSize(materialParams_source, int(materialParams.level)));
postProcess.vertex.xy = (postProcess.normalizedUV - 0.5 * materialParams.resolution.zw) + 0.5 / size;
}
}
fragment {
void tap(inout highp vec3 sum, const float weight, const highp vec2 position) {
vec3 s = textureLod(materialParams_source, position, materialParams.level).rgb;
sum += s * weight;
}
void tapReinhard(inout highp vec3 sum, inout float totalWeight, const float weight, const highp vec2 position) {
vec3 s = textureLod(materialParams_source, position, materialParams.level).rgb;
float w = weight / (1.0 + max3(s));
totalWeight += w;
sum += s * w;
}
void postProcess(inout PostProcessInputs postProcess) {
highp vec2 uv = variable_vertex.xy;
// we handle the center pixel separately
highp vec3 sum = vec3(0);
if (materialParams.reinhard != 0) {
float totalWeight = 0.0;
tapReinhard(sum, totalWeight, materialParams.kernel[0].x, uv);
vec2 offset = materialParams.axis;
for (int i = 1; i < materialParams.count; i++, offset += materialParams.axis * 2.0) {
float k = materialParams.kernel[i].x;
vec2 o = offset + materialParams.axis * materialParams.kernel[i].y;
tapReinhard(sum, totalWeight, k, uv + o);
tapReinhard(sum, totalWeight, k, uv - o);
}
sum *= 1.0 / totalWeight;
} else {
tap(sum, materialParams.kernel[0].x, uv);
vec2 offset = materialParams.axis;
for (int i = 1; i < materialParams.count; i++, offset += materialParams.axis * 2.0) {
float k = materialParams.kernel[i].x;
vec2 o = offset + materialParams.axis * materialParams.kernel[i].y;
tap(sum, k, uv + o);
tap(sum, k, uv - o);
}
}
postProcess.color.rgb = sum;
}
}

View File

@@ -0,0 +1,6 @@
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
// in the fragment shader, this is interpolated to pixel centers, but since we use
// texel-fetch, it's not what we want. Convert from screen uv to texture uv.
vec2 size = vec2(textureSize(materialParams_source, int(materialParams.level)));
postProcess.vertex.xy = (postProcess.normalizedUV - 0.5 * materialParams.resolution.zw) + 0.5 / size;
}

View File

@@ -0,0 +1,54 @@
material {
name : separableGaussianBlur1,
parameters : [
{
type : sampler2d,
name : source,
precision: medium
},
{
type : float4,
name : resolution,
precision: high
},
{
type : float2,
name : axis
},
{
type : float,
name : level
},
{
type : int,
name : count
},
{
type : int,
name : reinhard
},
{
type : float2[32],
name : kernel
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
#include "separableGaussianBlur.vs"
}
fragment {
#define BLUR_TYPE vec2
#define BLUR_SWIZZLE r
#include "separableGaussianBlur.fs"
}

View File

@@ -0,0 +1,54 @@
material {
name : separableGaussianBlur2,
parameters : [
{
type : sampler2d,
name : source,
precision: medium
},
{
type : float4,
name : resolution,
precision: high
},
{
type : float2,
name : axis
},
{
type : float,
name : level
},
{
type : int,
name : count
},
{
type : int,
name : reinhard
},
{
type : float2[32],
name : kernel
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
#include "separableGaussianBlur.vs"
}
fragment {
#define BLUR_TYPE vec2
#define BLUR_SWIZZLE rg
#include "separableGaussianBlur.fs"
}

View File

@@ -0,0 +1,54 @@
material {
name : separableGaussianBlur3,
parameters : [
{
type : sampler2d,
name : source,
precision: medium
},
{
type : float4,
name : resolution,
precision: high
},
{
type : float2,
name : axis
},
{
type : float,
name : level
},
{
type : int,
name : count
},
{
type : int,
name : reinhard
},
{
type : float2[32],
name : kernel
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
#include "separableGaussianBlur.vs"
}
fragment {
#define BLUR_TYPE vec3
#define BLUR_SWIZZLE rgb
#include "separableGaussianBlur.fs"
}

View File

@@ -0,0 +1,54 @@
material {
name : separableGaussianBlur4,
parameters : [
{
type : sampler2d,
name : source,
precision: medium
},
{
type : float4,
name : resolution,
precision: high
},
{
type : float2,
name : axis
},
{
type : float,
name : level
},
{
type : int,
name : count
},
{
type : int,
name : reinhard
},
{
type : float2[32],
name : kernel
}
],
variables : [
vertex
],
domain : postprocess,
depthWrite : false,
depthCulling : false
}
vertex {
#include "separableGaussianBlur.vs"
}
fragment {
#define BLUR_TYPE vec4
#define BLUR_SWIZZLE rgba
#include "separableGaussianBlur.fs"
}

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.14.0"
spec.version = "1.14.1"
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.14.0/filament-v1.14.0-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.14.1/filament-v1.14.1-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {

View File

@@ -189,6 +189,7 @@ struct ShadowUib {
math::mat4f lightFromWorldMatrix;
math::float3 direction;
float normalBias;
float texelSizeAtOneMeter;
};
ShadowData shadows[CONFIG_MAX_SHADOW_CASTING_SPOTS];
};

View File

@@ -190,6 +190,7 @@ public:
using MaterialDomain = filament::MaterialDomain;
using RefractionMode = filament::RefractionMode;
using RefractionType = filament::RefractionType;
using VertexAttribute = filament::VertexAttribute;
using ShaderQuality = filament::ShaderQuality;
using BlendingMode = filament::BlendingMode;
@@ -285,10 +286,10 @@ public:
*
* position is always required and normal depends on the shading model.
*/
MaterialBuilder& require(filament::VertexAttribute attribute) noexcept;
MaterialBuilder& require(VertexAttribute attribute) noexcept;
//! Specify the domain that this material will operate in.
MaterialBuilder& materialDomain(MaterialDomain materialDomain) noexcept;
MaterialBuilder& materialDomain(filament::MaterialDomain materialDomain) noexcept;
/**
* Set the code content of this material.
@@ -608,7 +609,7 @@ public:
// Preview the first shader generated by the given CodeGenParams.
// This is used to run Static Code Analysis before generating a package.
const std::string peek(filament::backend::ShaderType type,
std::string peek(filament::backend::ShaderType type,
const CodeGenParams& params, const PropertyList& properties) noexcept;
// Returns true if any of the parameter samplers is of type samplerExternal
@@ -651,6 +652,9 @@ private:
const std::vector<Variant>& variants, ChunkContainer& container,
const MaterialInfo& info) const noexcept;
bool hasCustomVaryings() const noexcept;
bool needsStandardDepthProgram() const noexcept;
bool isLit() const noexcept { return mShading != filament::Shading::UNLIT; }
utils::CString mMaterialName;
@@ -680,7 +684,7 @@ private:
bool mIncludesResolved = false;
};
ShaderCode mMaterialCode;
ShaderCode mMaterialFragmentCode;
ShaderCode mMaterialVertexCode;
IncludeCallback mIncludeCallback = nullptr;

View File

@@ -17,6 +17,7 @@
#include "filamat/MaterialBuilder.h"
#include <atomic>
#include <utility>
#include <vector>
#include <utils/JobSystem.h>
@@ -141,13 +142,13 @@ MaterialBuilder& MaterialBuilder::fileName(const char* fileName) noexcept {
}
MaterialBuilder& MaterialBuilder::material(const char* code, size_t line) noexcept {
mMaterialCode.setUnresolved(CString(code));
mMaterialCode.setLineOffset(line);
mMaterialFragmentCode.setUnresolved(CString(code));
mMaterialFragmentCode.setLineOffset(line);
return *this;
}
MaterialBuilder& MaterialBuilder::includeCallback(IncludeCallback callback) noexcept {
mIncludeCallback = callback;
mIncludeCallback = std::move(callback);
return *this;
}
@@ -244,12 +245,12 @@ MaterialBuilder& MaterialBuilder::parameter(SubpassType subpassType, const char*
return parameter(subpassType, SamplerFormat::FLOAT, ParameterPrecision::DEFAULT, name);
}
MaterialBuilder& MaterialBuilder::require(filament::VertexAttribute attribute) noexcept {
MaterialBuilder& MaterialBuilder::require(VertexAttribute attribute) noexcept {
mRequiredAttributes.set(attribute);
return *this;
}
MaterialBuilder& MaterialBuilder::materialDomain(MaterialDomain materialDomain) noexcept {
MaterialBuilder& MaterialBuilder::materialDomain(filament::MaterialDomain materialDomain) noexcept {
mMaterialDomain = materialDomain;
return *this;
}
@@ -520,7 +521,7 @@ bool MaterialBuilder::findAllProperties() noexcept {
return true;
#else
GLSLToolsLite glslTools;
if (glslTools.findProperties(ShaderType::FRAGMENT, mMaterialCode.getResolved(), mProperties)) {
if (glslTools.findProperties(ShaderType::FRAGMENT, mMaterialFragmentCode.getResolved(), mProperties)) {
return glslTools.findProperties(
ShaderType::VERTEX, mMaterialVertexCode.getResolved(), mProperties);
}
@@ -587,7 +588,7 @@ bool MaterialBuilder::ShaderCode::resolveIncludes(IncludeCallback callback,
.lineNumberOffset = getLineOffset(),
.name = utils::CString("")
};
if (!::filamat::resolveIncludes(source, callback, options)) {
if (!::filamat::resolveIncludes(source, std::move(callback), options)) {
return false;
}
mCode = source.text;
@@ -635,17 +636,11 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
// End: must be protected by lock
ShaderGenerator sg(
mProperties, mVariables, mOutputs, mDefines, mMaterialCode.getResolved(),
mMaterialCode.getLineOffset(), mMaterialVertexCode.getResolved(),
mProperties, mVariables, mOutputs, mDefines, mMaterialFragmentCode.getResolved(),
mMaterialFragmentCode.getLineOffset(), mMaterialVertexCode.getResolved(),
mMaterialVertexCode.getLineOffset(), mMaterialDomain);
bool emptyVertexCode = mMaterialVertexCode.getResolved().empty();
bool customDepth = sg.hasCustomDepthShader() ||
mBlendingMode == BlendingMode::MASKED ||
((mBlendingMode == BlendingMode::TRANSPARENT ||mBlendingMode == BlendingMode::FADE) &&
mTransparentShadow) ||
!emptyVertexCode;
container.addSimpleChild<bool>(ChunkType::MaterialHasCustomDepthShader, customDepth);
container.addSimpleChild<bool>(ChunkType::MaterialHasCustomDepthShader, needsStandardDepthProgram());
std::atomic_bool cancelJobs(false);
bool firstJob = true;
@@ -748,7 +743,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
if (targetApi == TargetApi::OPENGL) {
if (targetLanguage == TargetLanguage::SPIRV) {
sg.fixupExternalSamplers(shaderModel, shader, info);
ShaderGenerator::fixupExternalSamplers(shaderModel, shader, info);
}
}
@@ -915,7 +910,7 @@ Package MaterialBuilder::build(JobSystem& jobSystem) noexcept {
}
// Resolve all the #include directives within user code.
if (!mMaterialCode.resolveIncludes(mIncludeCallback, mFileName) ||
if (!mMaterialFragmentCode.resolveIncludes(mIncludeCallback, mFileName) ||
!mMaterialVertexCode.resolveIncludes(mIncludeCallback, mFileName)) {
return Package::invalidPackage();
}
@@ -967,10 +962,30 @@ Package MaterialBuilder::build(JobSystem& jobSystem) noexcept {
return package;
}
const std::string MaterialBuilder::peek(filament::backend::ShaderType type,
bool MaterialBuilder::hasCustomVaryings() const noexcept {
for (const auto& variable : mVariables) {
if (!variable.empty()) {
return true;
}
}
return false;
}
bool MaterialBuilder::needsStandardDepthProgram() const noexcept {
const bool hasEmptyVertexCode = mMaterialVertexCode.getResolved().empty();
return !hasEmptyVertexCode ||
hasCustomVaryings() ||
mBlendingMode == BlendingMode::MASKED ||
(mTransparentShadow &&
(mBlendingMode == BlendingMode::TRANSPARENT ||
mBlendingMode == BlendingMode::FADE));
}
std::string MaterialBuilder::peek(filament::backend::ShaderType type,
const CodeGenParams& params, const PropertyList& properties) noexcept {
ShaderGenerator sg(properties, mVariables, mOutputs, mDefines, mMaterialCode.getResolved(),
mMaterialCode.getLineOffset(), mMaterialVertexCode.getResolved(),
ShaderGenerator sg(properties, mVariables, mOutputs, mDefines, mMaterialFragmentCode.getResolved(),
mMaterialFragmentCode.getLineOffset(), mMaterialVertexCode.getResolved(),
mMaterialVertexCode.getLineOffset(), mMaterialDomain);
MaterialInfo info;
@@ -987,8 +1002,6 @@ const std::string MaterialBuilder::peek(filament::backend::ShaderType type,
return sg.createFragmentProgram(ShaderModel(params.shaderModel), params.targetApi,
params.targetLanguage, info, 0, mInterpolation);
}
return std::string("");
}
void MaterialBuilder::writeCommonChunks(ChunkContainer& container, MaterialInfo& info) const noexcept {

View File

@@ -32,7 +32,7 @@ using namespace filament;
using namespace backend;
using namespace utils;
io::sstream& CodeGenerator::generateSeparator(io::sstream& out) const {
io::sstream& CodeGenerator::generateSeparator(io::sstream& out) {
out << '\n';
return out;
}
@@ -137,12 +137,12 @@ Precision CodeGenerator::getDefaultUniformPrecision() const {
}
}
io::sstream& CodeGenerator::generateEpilog(io::sstream& out) const {
io::sstream& CodeGenerator::generateEpilog(io::sstream& out) {
out << "\n"; // For line compression all shaders finish with a newline character.
return out;
}
io::sstream& CodeGenerator::generateShaderMain(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateShaderMain(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
out << SHADERS_MAIN_VS_DATA;
} else if (type == ShaderType::FRAGMENT) {
@@ -151,7 +151,7 @@ io::sstream& CodeGenerator::generateShaderMain(io::sstream& out, ShaderType type
return out;
}
io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
out << SHADERS_POST_PROCESS_VS_DATA;
} else if (type == ShaderType::FRAGMENT) {
@@ -161,7 +161,7 @@ io::sstream& CodeGenerator::generatePostProcessMain(io::sstream& out, ShaderType
}
io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderType type,
const CString& name, size_t index) const {
const CString& name, size_t index) {
if (!name.empty()) {
if (type == ShaderType::VERTEX) {
@@ -176,7 +176,7 @@ io::sstream& CodeGenerator::generateVariable(io::sstream& out, ShaderType type,
}
io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderType type,
const AttributeBitset& attributes, Interpolation interpolation) const {
const AttributeBitset& attributes, Interpolation interpolation) {
const char* shading = getInterpolationQualifier(interpolation);
out << "#define SHADING_INTERPOLATION " << shading << "\n";
@@ -242,8 +242,8 @@ io::sstream& CodeGenerator::generateShaderInputs(io::sstream& out, ShaderType ty
return out;
}
utils::io::sstream& CodeGenerator::generateOutput(utils::io::sstream& out, ShaderType type,
const utils::CString& name, size_t index,
io::sstream& CodeGenerator::generateOutput(io::sstream& out, ShaderType type,
const CString& name, size_t index,
MaterialBuilder::VariableQualifier qualifier,
MaterialBuilder::OutputType outputType) const {
if (name.empty() || type == ShaderType::VERTEX) {
@@ -285,17 +285,16 @@ utils::io::sstream& CodeGenerator::generateOutput(utils::io::sstream& out, Shade
}
io::sstream& CodeGenerator::generateDepthShaderMain(io::sstream& out, ShaderType type) const {
if (type == ShaderType::VERTEX) {
out << SHADERS_DEPTH_MAIN_VS_DATA;
} else if (type == ShaderType::FRAGMENT) {
io::sstream& CodeGenerator::generateDepthShaderMain(io::sstream& out, ShaderType type) {
assert(type != ShaderType::VERTEX);
if (type == ShaderType::FRAGMENT) {
out << SHADERS_DEPTH_MAIN_FS_DATA;
}
return out;
}
const char* CodeGenerator::getUniformPrecisionQualifier(UniformType type, Precision precision,
Precision uniformPrecision, Precision defaultPrecision) const noexcept {
Precision uniformPrecision, Precision defaultPrecision) noexcept {
if (!hasPrecision(type)) {
return "";
}
@@ -385,8 +384,8 @@ io::sstream& CodeGenerator::generateSamplers(
return out;
}
utils::io::sstream& CodeGenerator::generateSubpass(utils::io::sstream& out,
SubpassInfo subpass) const {
io::sstream& CodeGenerator::generateSubpass(io::sstream& out,
SubpassInfo subpass) {
if (!subpass.isValid) {
return out;
}
@@ -454,31 +453,31 @@ void CodeGenerator::fixupExternalSamplers(
}
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, bool value) const {
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, bool value) {
if (value) {
out << "#define " << name << "\n";
}
return out;
}
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, uint32_t value) const {
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, uint32_t value) {
out << "#define " << name << " " << value << "\n";
return out;
}
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, const char* string) const {
io::sstream& CodeGenerator::generateDefine(io::sstream& out, const char* name, const char* string) {
out << "#define " << name << " " << string << "\n";
return out;
}
io::sstream& CodeGenerator::generateIndexedDefine(io::sstream& out, const char* name,
uint32_t index, uint32_t value) const {
uint32_t index, uint32_t value) {
out << "#define " << name << index << " " << value << "\n";
return out;
}
io::sstream& CodeGenerator::generateMaterialProperty(io::sstream& out,
MaterialBuilder::Property property, bool isSet) const {
MaterialBuilder::Property property, bool isSet) {
if (isSet) {
out << "#define " << "MATERIAL_HAS_" << getConstantName(property) << "\n";
}
@@ -515,7 +514,7 @@ io::sstream& CodeGenerator::generateQualityDefine(io::sstream& out, ShaderQualit
return out;
}
io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderType type) {
out << SHADERS_COMMON_MATH_FS_DATA;
out << SHADERS_COMMON_SHADOWING_FS_DATA;
if (type == ShaderType::VERTEX) {
@@ -527,7 +526,7 @@ io::sstream& CodeGenerator::generateCommon(io::sstream& out, ShaderType type) co
return out;
}
io::sstream& CodeGenerator::generateFog(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateFog(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
} else if (type == ShaderType::FRAGMENT) {
out << SHADERS_FOG_FS_DATA;
@@ -535,7 +534,7 @@ io::sstream& CodeGenerator::generateFog(io::sstream& out, ShaderType type) const
return out;
}
io::sstream& CodeGenerator::generateCommonMaterial(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateCommonMaterial(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
out << SHADERS_MATERIAL_INPUTS_VS_DATA;
} else if (type == ShaderType::FRAGMENT) {
@@ -544,7 +543,7 @@ io::sstream& CodeGenerator::generateCommonMaterial(io::sstream& out, ShaderType
return out;
}
io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
out << SHADERS_POST_PROCESS_INPUTS_VS_DATA;
} else if (type == ShaderType::FRAGMENT) {
@@ -553,8 +552,8 @@ io::sstream& CodeGenerator::generatePostProcessInputs(io::sstream& out, ShaderTy
return out;
}
utils::io::sstream& CodeGenerator::generatePostProcessGetters(utils::io::sstream& out,
ShaderType type) const {
io::sstream& CodeGenerator::generatePostProcessGetters(io::sstream& out,
ShaderType type) {
out << SHADERS_COMMON_GETTERS_FS_DATA;
if (type == ShaderType::VERTEX) {
out << SHADERS_POST_PROCESS_GETTERS_VS_DATA;
@@ -562,7 +561,7 @@ utils::io::sstream& CodeGenerator::generatePostProcessGetters(utils::io::sstream
return out;
}
io::sstream& CodeGenerator::generateGetters(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateGetters(io::sstream& out, ShaderType type) {
out << SHADERS_COMMON_GETTERS_FS_DATA;
if (type == ShaderType::VERTEX) {
out << SHADERS_GETTERS_VS_DATA;
@@ -572,7 +571,7 @@ io::sstream& CodeGenerator::generateGetters(io::sstream& out, ShaderType type) c
return out;
}
io::sstream& CodeGenerator::generateParameters(io::sstream& out, ShaderType type) const {
io::sstream& CodeGenerator::generateParameters(io::sstream& out, ShaderType type) {
if (type == ShaderType::VERTEX) {
} else if (type == ShaderType::FRAGMENT) {
out << SHADERS_SHADING_PARAMETERS_FS_DATA;
@@ -581,7 +580,7 @@ io::sstream& CodeGenerator::generateParameters(io::sstream& out, ShaderType type
}
io::sstream& CodeGenerator::generateShaderLit(io::sstream& out, ShaderType type,
filament::Variant variant, filament::Shading shading, bool customSurfaceShading) const {
filament::Variant variant, Shading shading, bool customSurfaceShading) {
if (type == ShaderType::VERTEX) {
} else if (type == ShaderType::FRAGMENT) {
out << SHADERS_COMMON_LIGHTING_FS_DATA;
@@ -627,7 +626,7 @@ io::sstream& CodeGenerator::generateShaderLit(io::sstream& out, ShaderType type,
}
io::sstream& CodeGenerator::generateShaderUnlit(io::sstream& out, ShaderType type,
filament::Variant variant, bool hasShadowMultiplier) const {
filament::Variant variant, bool hasShadowMultiplier) {
if (type == ShaderType::VERTEX) {
} else if (type == ShaderType::FRAGMENT) {
if (hasShadowMultiplier) {

View File

@@ -56,39 +56,39 @@ public:
filament::backend::ShaderModel getShaderModel() const noexcept { return mShaderModel; }
// insert a separator (can be a new line)
utils::io::sstream& generateSeparator(utils::io::sstream& out) const;
static utils::io::sstream& generateSeparator(utils::io::sstream& out) ;
// generate prolog for the given shader
utils::io::sstream& generateProlog(utils::io::sstream& out, ShaderType type, bool hasExternalSamplers) const;
utils::io::sstream& generateEpilog(utils::io::sstream& out) const;
static utils::io::sstream& generateEpilog(utils::io::sstream& out) ;
// generate common functions for the given shader
utils::io::sstream& generateCommon(utils::io::sstream& out, ShaderType type) const;
utils::io::sstream& generateCommonMaterial(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generateCommon(utils::io::sstream& out, ShaderType type) ;
static utils::io::sstream& generateCommonMaterial(utils::io::sstream& out, ShaderType type) ;
utils::io::sstream& generateFog(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generateFog(utils::io::sstream& out, ShaderType type) ;
// generate the shader's main()
utils::io::sstream& generateShaderMain(utils::io::sstream& out, ShaderType type) const;
utils::io::sstream& generatePostProcessMain(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generateShaderMain(utils::io::sstream& out, ShaderType type) ;
static utils::io::sstream& generatePostProcessMain(utils::io::sstream& out, ShaderType type) ;
// generate the shader's code for the lit shading model
utils::io::sstream& generateShaderLit(utils::io::sstream& out, ShaderType type,
filament::Variant variant, filament::Shading shading, bool customSurfaceShading) const;
static utils::io::sstream& generateShaderLit(utils::io::sstream& out, ShaderType type,
filament::Variant variant, filament::Shading shading, bool customSurfaceShading) ;
// generate the shader's code for the unlit shading model
utils::io::sstream& generateShaderUnlit(utils::io::sstream& out, ShaderType type,
filament::Variant variant, bool hasShadowMultiplier) const;
static utils::io::sstream& generateShaderUnlit(utils::io::sstream& out, ShaderType type,
filament::Variant variant, bool hasShadowMultiplier) ;
// generate declarations for custom interpolants
utils::io::sstream& generateVariable(utils::io::sstream& out, ShaderType type,
const utils::CString& name, size_t index) const;
static utils::io::sstream& generateVariable(utils::io::sstream& out, ShaderType type,
const utils::CString& name, size_t index) ;
// generate declarations for non-custom "in" variables
utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderType type,
const filament::AttributeBitset& attributes, filament::Interpolation interpolation) const;
utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generateShaderInputs(utils::io::sstream& out, ShaderType type,
const filament::AttributeBitset& attributes, filament::Interpolation interpolation) ;
static utils::io::sstream& generatePostProcessInputs(utils::io::sstream& out, ShaderType type) ;
// generate declarations for custom output variables
utils::io::sstream& generateOutput(utils::io::sstream& out, ShaderType type,
@@ -97,7 +97,7 @@ public:
MaterialBuilder::OutputType outputType) const;
// generate no-op shader for depth prepass
utils::io::sstream& generateDepthShaderMain(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generateDepthShaderMain(utils::io::sstream& out, ShaderType type) ;
// generate uniforms
utils::io::sstream& generateUniforms(utils::io::sstream& out, ShaderType type, uint8_t binding,
@@ -108,24 +108,24 @@ public:
utils::io::sstream& out, uint8_t firstBinding, const filament::SamplerInterfaceBlock& sib) const;
// generate subpass
utils::io::sstream& generateSubpass(utils::io::sstream& out,
filament::SubpassInfo subpass) const;
static utils::io::sstream& generateSubpass(utils::io::sstream& out,
filament::SubpassInfo subpass) ;
// generate material properties getters
utils::io::sstream& generateMaterialProperty(utils::io::sstream& out,
MaterialBuilder::Property property, bool isSet) const;
static utils::io::sstream& generateMaterialProperty(utils::io::sstream& out,
MaterialBuilder::Property property, bool isSet) ;
utils::io::sstream& generateQualityDefine(utils::io::sstream& out, ShaderQuality quality) const;
utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, bool value) const;
utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, uint32_t value) const;
utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, const char* string) const;
utils::io::sstream& generateIndexedDefine(utils::io::sstream& out, const char* name,
uint32_t index, uint32_t value) const;
static utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, bool value) ;
static utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, uint32_t value) ;
static utils::io::sstream& generateDefine(utils::io::sstream& out, const char* name, const char* string) ;
static utils::io::sstream& generateIndexedDefine(utils::io::sstream& out, const char* name,
uint32_t index, uint32_t value) ;
utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderType type) const;
utils::io::sstream& generateGetters(utils::io::sstream& out, ShaderType type) const;
utils::io::sstream& generateParameters(utils::io::sstream& out, ShaderType type) const;
static utils::io::sstream& generatePostProcessGetters(utils::io::sstream& out, ShaderType type) ;
static utils::io::sstream& generateGetters(utils::io::sstream& out, ShaderType type) ;
static utils::io::sstream& generateParameters(utils::io::sstream& out, ShaderType type) ;
static void fixupExternalSamplers(
std::string& shader, filament::SamplerInterfaceBlock const& sib) noexcept;
@@ -134,10 +134,10 @@ private:
filament::backend::Precision getDefaultPrecision(ShaderType type) const;
filament::backend::Precision getDefaultUniformPrecision() const;
const char* getUniformPrecisionQualifier(filament::backend::UniformType type,
static const char* getUniformPrecisionQualifier(filament::backend::UniformType type,
filament::backend::Precision precision,
filament::backend::Precision uniformPrecision,
filament::backend::Precision defaultPrecision) const noexcept;
filament::backend::Precision defaultPrecision) noexcept;
// return type name of sampler (e.g.: "sampler2D")
char const* getSamplerTypeName(filament::backend::SamplerType type,

View File

@@ -28,26 +28,26 @@
#include "CodeGenerator.h"
#include "../UibGenerator.h"
using namespace filament;
using namespace filament::backend;
namespace filamat {
static const char* getShadingDefine(filament::Shading shading) noexcept {
using namespace filament;
using namespace filament::backend;
using namespace utils;
static const char* getShadingDefine(Shading shading) noexcept {
switch (shading) {
case filament::Shading::LIT: return "SHADING_MODEL_LIT";
case filament::Shading::UNLIT: return "SHADING_MODEL_UNLIT";
case filament::Shading::SUBSURFACE: return "SHADING_MODEL_SUBSURFACE";
case filament::Shading::CLOTH: return "SHADING_MODEL_CLOTH";
case filament::Shading::SPECULAR_GLOSSINESS: return "SHADING_MODEL_SPECULAR_GLOSSINESS";
case Shading::LIT: return "SHADING_MODEL_LIT";
case Shading::UNLIT: return "SHADING_MODEL_UNLIT";
case Shading::SUBSURFACE: return "SHADING_MODEL_SUBSURFACE";
case Shading::CLOTH: return "SHADING_MODEL_CLOTH";
case Shading::SPECULAR_GLOSSINESS: return "SHADING_MODEL_SPECULAR_GLOSSINESS";
}
}
static void generateMaterialDefines(utils::io::sstream& os, const CodeGenerator& cg,
MaterialBuilder::PropertyList const properties,
static void generateMaterialDefines(io::sstream& os, MaterialBuilder::PropertyList const properties,
const MaterialBuilder::PreprocessorDefineList& defines) noexcept {
for (size_t i = 0; i < MaterialBuilder::MATERIAL_PROPERTIES_COUNT; i++) {
cg.generateMaterialProperty(os, static_cast<MaterialBuilder::Property>(i), properties[i]);
CodeGenerator::generateMaterialProperty(os, static_cast<MaterialBuilder::Property>(i), properties[i]);
}
// synthetic defines
bool hasTBN =
@@ -55,40 +55,39 @@ static void generateMaterialDefines(utils::io::sstream& os, const CodeGenerator&
properties[static_cast<int>(MaterialBuilder::Property::NORMAL)] ||
properties[static_cast<int>(MaterialBuilder::Property::BENT_NORMAL)] ||
properties[static_cast<int>(MaterialBuilder::Property::CLEAR_COAT_NORMAL)];
cg.generateDefine(os, "MATERIAL_NEEDS_TBN", hasTBN);
CodeGenerator::generateDefine(os, "MATERIAL_NEEDS_TBN", hasTBN);
// Additional, user-provided defines.
for (const auto& define : defines) {
cg.generateDefine(os, define.name.c_str(), define.value.c_str());
CodeGenerator::generateDefine(os, define.name.c_str(), define.value.c_str());
}
}
static void generateVertexDomain(const CodeGenerator& cg, utils::io::sstream& vs,
filament::VertexDomain domain) noexcept {
static void generateVertexDomain(io::sstream& vs, VertexDomain domain) noexcept {
switch (domain) {
case VertexDomain::OBJECT:
cg.generateDefine(vs, "VERTEX_DOMAIN_OBJECT", true);
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_OBJECT", true);
break;
case VertexDomain::WORLD:
cg.generateDefine(vs, "VERTEX_DOMAIN_WORLD", true);
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_WORLD", true);
break;
case VertexDomain::VIEW:
cg.generateDefine(vs, "VERTEX_DOMAIN_VIEW", true);
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_VIEW", true);
break;
case VertexDomain::DEVICE:
cg.generateDefine(vs, "VERTEX_DOMAIN_DEVICE", true);
CodeGenerator::generateDefine(vs, "VERTEX_DOMAIN_DEVICE", true);
break;
}
}
static void generatePostProcessMaterialVariantDefines(const CodeGenerator& cg,
utils::io::sstream& shader, PostProcessVariant variant) noexcept {
static void generatePostProcessMaterialVariantDefines(io::sstream& shader,
PostProcessVariant variant) noexcept {
switch (variant) {
case PostProcessVariant::OPAQUE:
cg.generateDefine(shader, "POST_PROCESS_OPAQUE", 1u);
CodeGenerator::generateDefine(shader, "POST_PROCESS_OPAQUE", 1u);
break;
case PostProcessVariant::TRANSLUCENT:
cg.generateDefine(shader, "POST_PROCESS_OPAQUE", 0u);
CodeGenerator::generateDefine(shader, "POST_PROCESS_OPAQUE", 0u);
break;
}
}
@@ -102,7 +101,7 @@ static size_t countLines(const char* s) noexcept {
return lines;
}
static size_t countLines(const utils::CString& s) noexcept {
static size_t countLines(const CString& s) noexcept {
size_t lines = 0;
for (char i : s) {
if (i == '\n') lines++;
@@ -110,8 +109,8 @@ static size_t countLines(const utils::CString& s) noexcept {
return lines;
}
static void appendShader(utils::io::sstream& ss,
const utils::CString& shader, size_t lineOffset) noexcept {
static void appendShader(io::sstream& ss,
const CString& shader, size_t lineOffset) noexcept {
if (!shader.empty()) {
size_t lines = countLines(ss.c_str());
ss << "#line " << lineOffset + 1 << '\n';
@@ -130,50 +129,52 @@ ShaderGenerator::ShaderGenerator(
MaterialBuilder::VariableList const& variables,
MaterialBuilder::OutputList const& outputs,
MaterialBuilder::PreprocessorDefineList const& defines,
utils::CString const& materialCode, size_t lineOffset,
utils::CString const& materialVertexCode, size_t vertexLineOffset,
CString const& materialCode, size_t lineOffset,
CString const& materialVertexCode, size_t vertexLineOffset,
MaterialBuilder::MaterialDomain materialDomain) noexcept {
std::copy(std::begin(properties), std::end(properties), std::begin(mProperties));
std::copy(std::begin(variables), std::end(variables), std::begin(mVariables));
std::copy(std::begin(outputs), std::end(outputs), std::back_inserter(mOutputs));
mMaterialCode = materialCode;
mMaterialFragmentCode = materialCode;
mMaterialVertexCode = materialVertexCode;
mIsMaterialVertexShaderEmpty = materialVertexCode.empty();
mMaterialLineOffset = lineOffset;
mMaterialVertexLineOffset = vertexLineOffset;
mMaterialDomain = materialDomain;
mDefines = defines;
if (mMaterialCode.empty()) {
if (mMaterialFragmentCode.empty()) {
if (mMaterialDomain == MaterialBuilder::MaterialDomain::SURFACE) {
mMaterialCode =
utils::CString("void material(inout MaterialInputs m) {\n prepareMaterial(m);\n}\n");
mMaterialFragmentCode =
CString("void material(inout MaterialInputs m) {\n prepareMaterial(m);\n}\n");
} else if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) {
mMaterialCode =
utils::CString("void postProcess(inout PostProcessInputs p) {\n}\n");
mMaterialFragmentCode =
CString("void postProcess(inout PostProcessInputs p) {\n}\n");
}
}
if (mMaterialVertexCode.empty()) {
if (mMaterialDomain == MaterialBuilder::MaterialDomain::SURFACE) {
mMaterialVertexCode =
utils::CString("void materialVertex(inout MaterialVertexInputs m) {\n}\n");
CString("void materialVertex(inout MaterialVertexInputs m) {\n}\n");
} else if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) {
mMaterialVertexCode =
utils::CString("void postProcessVertex(inout PostProcessVertexInputs m) {\n}\n");
CString("void postProcessVertex(inout PostProcessVertexInputs m) {\n}\n");
}
}
}
std::string ShaderGenerator::createVertexProgram(filament::backend::ShaderModel shaderModel,
std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialInfo const& material, uint8_t variantKey, filament::Interpolation interpolation,
filament::VertexDomain vertexDomain) const noexcept {
MaterialInfo const& material, uint8_t variantKey, Interpolation interpolation,
VertexDomain vertexDomain) const noexcept {
if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) {
return createPostProcessVertexProgram(shaderModel, targetApi,
targetLanguage, material, variantKey, material.samplerBindings);
}
utils::io::sstream vs;
io::sstream vs;
const CodeGenerator cg(shaderModel, targetApi, targetLanguage);
const bool lit = material.isLit;
@@ -183,19 +184,35 @@ std::string ShaderGenerator::createVertexProgram(filament::backend::ShaderModel
cg.generateQualityDefine(vs, material.quality);
cg.generateDefine(vs, "MAX_SHADOW_CASTING_SPOTS", uint32_t(CONFIG_MAX_SHADOW_CASTING_SPOTS));
CodeGenerator::generateDefine(vs, "MAX_SHADOW_CASTING_SPOTS", uint32_t(CONFIG_MAX_SHADOW_CASTING_SPOTS));
cg.generateDefine(vs, "FLIP_UV_ATTRIBUTE", material.flipUV);
CodeGenerator::generateDefine(vs, "FLIP_UV_ATTRIBUTE", material.flipUV);
bool litVariants = lit || material.hasShadowMultiplier;
cg.generateDefine(vs, "HAS_DIRECTIONAL_LIGHTING", litVariants && variant.hasDirectionalLighting());
cg.generateDefine(vs, "HAS_DYNAMIC_LIGHTING", litVariants && variant.hasDynamicLighting());
cg.generateDefine(vs, "HAS_SHADOWING", litVariants && variant.hasShadowReceiver());
cg.generateDefine(vs, "HAS_SHADOW_MULTIPLIER", material.hasShadowMultiplier);
cg.generateDefine(vs, "HAS_SKINNING_OR_MORPHING", variant.hasSkinningOrMorphing());
cg.generateDefine(vs, "HAS_VSM", variant.hasVsm());
cg.generateDefine(vs, getShadingDefine(material.shading), true);
generateMaterialDefines(vs, cg, mProperties, mDefines);
const bool litVariants = lit || material.hasShadowMultiplier;
// note: even if the user vertex shader is empty, we can't use the "optimized" version if
// we're in masked mode because fragment shader needs the color varyings
const bool useOptimizedDepthVertexShader =
// must be a depth variant
filament::Variant::isValidDepthVariant(variantKey) &&
// must have an empty vertex shader
mIsMaterialVertexShaderEmpty &&
// but must not be MASKED mode
material.blendingMode != BlendingMode::MASKED &&
// and must not have transparent shadows
!(material.hasTransparentShadow &&
(material.blendingMode == BlendingMode::TRANSPARENT ||
material.blendingMode == BlendingMode::FADE));
CodeGenerator::generateDefine(vs, "USE_OPTIMIZED_DEPTH_VERTEX_SHADER", useOptimizedDepthVertexShader);
CodeGenerator::generateDefine(vs, "HAS_DIRECTIONAL_LIGHTING", litVariants && variant.hasDirectionalLighting());
CodeGenerator::generateDefine(vs, "HAS_DYNAMIC_LIGHTING", litVariants && variant.hasDynamicLighting());
CodeGenerator::generateDefine(vs, "HAS_SHADOWING", litVariants && variant.hasShadowReceiver());
CodeGenerator::generateDefine(vs, "HAS_SHADOW_MULTIPLIER", material.hasShadowMultiplier);
CodeGenerator::generateDefine(vs, "HAS_SKINNING_OR_MORPHING", variant.hasSkinningOrMorphing());
CodeGenerator::generateDefine(vs, "HAS_VSM", variant.hasVsm());
CodeGenerator::generateDefine(vs, getShadingDefine(material.shading), true);
generateMaterialDefines(vs, mProperties, mDefines);
AttributeBitset attributes = material.requiredAttributes;
if (variant.hasSkinningOrMorphing()) {
@@ -210,16 +227,16 @@ std::string ShaderGenerator::createVertexProgram(filament::backend::ShaderModel
attributes.set(VertexAttribute::MORPH_TANGENTS_2);
attributes.set(VertexAttribute::MORPH_TANGENTS_3);
}
cg.generateShaderInputs(vs, ShaderType::VERTEX, attributes, interpolation);
CodeGenerator::generateShaderInputs(vs, ShaderType::VERTEX, attributes, interpolation);
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
cg.generateVariable(vs, ShaderType::VERTEX, variable, variableIndex++);
CodeGenerator::generateVariable(vs, ShaderType::VERTEX, variable, variableIndex++);
}
// materials defines
generateVertexDomain(cg, vs, vertexDomain);
generateVertexDomain(vs, vertexDomain);
// uniforms
cg.generateUniforms(vs, ShaderType::VERTEX,
@@ -233,45 +250,27 @@ std::string ShaderGenerator::createVertexProgram(filament::backend::ShaderModel
}
cg.generateUniforms(vs, ShaderType::VERTEX,
BindingPoints::PER_MATERIAL_INSTANCE, material.uib);
cg.generateSeparator(vs);
CodeGenerator::generateSeparator(vs);
// TODO: should we generate per-view SIB in the vertex shader?
cg.generateSamplers(vs,
material.samplerBindings.getBlockOffset(BindingPoints::PER_MATERIAL_INSTANCE),
material.sib);
// shader code
cg.generateCommon(vs, ShaderType::VERTEX);
cg.generateGetters(vs, ShaderType::VERTEX);
cg.generateCommonMaterial(vs, ShaderType::VERTEX);
CodeGenerator::generateCommon(vs, ShaderType::VERTEX);
CodeGenerator::generateGetters(vs, ShaderType::VERTEX);
CodeGenerator::generateCommonMaterial(vs, ShaderType::VERTEX);
if (filament::Variant::isValidDepthVariant(variantKey) &&
material.blendingMode != BlendingMode::MASKED &&
!material.hasTransparentShadow &&
!hasCustomDepthShader()) {
// these variants are special and are treated as DEPTH variants. Filament will never
// request that variant for the color pass.
cg.generateDepthShaderMain(vs, ShaderType::VERTEX);
} else {
// main entry point
appendShader(vs, mMaterialVertexCode, mMaterialVertexLineOffset);
cg.generateShaderMain(vs, ShaderType::VERTEX);
}
// main entry point
appendShader(vs, mMaterialVertexCode, mMaterialVertexLineOffset);
CodeGenerator::generateShaderMain(vs, ShaderType::VERTEX);
cg.generateEpilog(vs);
CodeGenerator::generateEpilog(vs);
return vs.c_str();
}
bool ShaderGenerator::hasCustomDepthShader() const noexcept {
for (const auto& variable : mVariables) {
if (!variable.empty()) {
return true;
}
}
return false;
}
static bool isMobileTarget(filament::backend::ShaderModel model) {
static bool isMobileTarget(ShaderModel model) {
switch (model) {
case ShaderModel::UNKNOWN:
return false;
@@ -282,10 +281,10 @@ static bool isMobileTarget(filament::backend::ShaderModel model) {
}
}
std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderModel shaderModel,
std::string ShaderGenerator::createFragmentProgram(ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialInfo const& material, uint8_t variantKey,
filament::Interpolation interpolation) const noexcept {
Interpolation interpolation) const noexcept {
if (mMaterialDomain == MaterialBuilder::MaterialDomain::POST_PROCESS) {
return createPostProcessFragmentProgram(shaderModel, targetApi, targetLanguage, material,
variantKey, material.samplerBindings);
@@ -295,121 +294,121 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode
const bool lit = material.isLit;
const filament::Variant variant(variantKey);
utils::io::sstream fs;
io::sstream fs;
cg.generateProlog(fs, ShaderType::FRAGMENT, material.hasExternalSamplers);
cg.generateQualityDefine(fs, material.quality);
cg.generateDefine(fs, "GEOMETRIC_SPECULAR_AA", material.specularAntiAliasing && lit);
CodeGenerator::generateDefine(fs, "GEOMETRIC_SPECULAR_AA", material.specularAntiAliasing && lit);
cg.generateDefine(fs, "CLEAR_COAT_IOR_CHANGE", material.clearCoatIorChange);
CodeGenerator::generateDefine(fs, "CLEAR_COAT_IOR_CHANGE", material.clearCoatIorChange);
cg.generateDefine(fs, "MAX_SHADOW_CASTING_SPOTS", uint32_t(CONFIG_MAX_SHADOW_CASTING_SPOTS));
CodeGenerator::generateDefine(fs, "MAX_SHADOW_CASTING_SPOTS", uint32_t(CONFIG_MAX_SHADOW_CASTING_SPOTS));
auto defaultSpecularAO = isMobileTarget(shaderModel) ?
SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE;
auto specularAO = material.specularAOSet ? material.specularAO : defaultSpecularAO;
cg.generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO));
CodeGenerator::generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO));
cg.generateDefine(fs, "HAS_REFRACTION", material.refractionMode != RefractionMode::NONE);
CodeGenerator::generateDefine(fs, "HAS_REFRACTION", material.refractionMode != RefractionMode::NONE);
if (material.refractionMode != RefractionMode::NONE) {
cg.generateDefine(fs, "REFRACTION_MODE_CUBEMAP", uint32_t(RefractionMode::CUBEMAP));
cg.generateDefine(fs, "REFRACTION_MODE_SCREEN_SPACE", uint32_t(RefractionMode::SCREEN_SPACE));
CodeGenerator::generateDefine(fs, "REFRACTION_MODE_CUBEMAP", uint32_t(RefractionMode::CUBEMAP));
CodeGenerator::generateDefine(fs, "REFRACTION_MODE_SCREEN_SPACE", uint32_t(RefractionMode::SCREEN_SPACE));
switch (material.refractionMode) {
case RefractionMode::NONE:
// can't be here
break;
case RefractionMode::CUBEMAP:
cg.generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_CUBEMAP");
CodeGenerator::generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_CUBEMAP");
break;
case RefractionMode::SCREEN_SPACE:
cg.generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_SCREEN_SPACE");
CodeGenerator::generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_SCREEN_SPACE");
break;
}
cg.generateDefine(fs, "REFRACTION_TYPE_SOLID", uint32_t(RefractionType::SOLID));
cg.generateDefine(fs, "REFRACTION_TYPE_THIN", uint32_t(RefractionType::THIN));
CodeGenerator::generateDefine(fs, "REFRACTION_TYPE_SOLID", uint32_t(RefractionType::SOLID));
CodeGenerator::generateDefine(fs, "REFRACTION_TYPE_THIN", uint32_t(RefractionType::THIN));
switch (material.refractionType) {
case RefractionType::SOLID:
cg.generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_SOLID");
CodeGenerator::generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_SOLID");
break;
case RefractionType::THIN:
cg.generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_THIN");
CodeGenerator::generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_THIN");
break;
}
}
bool multiBounceAO = material.multiBounceAOSet ?
material.multiBounceAO : !isMobileTarget(shaderModel);
cg.generateDefine(fs, "MULTI_BOUNCE_AMBIENT_OCCLUSION", multiBounceAO ? 1u : 0u);
CodeGenerator::generateDefine(fs, "MULTI_BOUNCE_AMBIENT_OCCLUSION", multiBounceAO ? 1u : 0u);
// lighting variants
bool litVariants = lit || material.hasShadowMultiplier;
cg.generateDefine(fs, "HAS_DIRECTIONAL_LIGHTING", litVariants && variant.hasDirectionalLighting());
cg.generateDefine(fs, "HAS_DYNAMIC_LIGHTING", litVariants && variant.hasDynamicLighting());
cg.generateDefine(fs, "HAS_SHADOWING", litVariants && variant.hasShadowReceiver());
cg.generateDefine(fs, "HAS_FOG", variant.hasFog() && !variant.hasDepth());
cg.generateDefine(fs, "HAS_PICKING", variant.hasPicking() && variant.hasDepth());
cg.generateDefine(fs, "HAS_VSM", variant.hasVsm());
cg.generateDefine(fs, "HAS_SHADOW_MULTIPLIER", material.hasShadowMultiplier);
cg.generateDefine(fs, "HAS_TRANSPARENT_SHADOW", material.hasTransparentShadow);
CodeGenerator::generateDefine(fs, "HAS_DIRECTIONAL_LIGHTING", litVariants && variant.hasDirectionalLighting());
CodeGenerator::generateDefine(fs, "HAS_DYNAMIC_LIGHTING", litVariants && variant.hasDynamicLighting());
CodeGenerator::generateDefine(fs, "HAS_SHADOWING", litVariants && variant.hasShadowReceiver());
CodeGenerator::generateDefine(fs, "HAS_FOG", variant.hasFog() && !variant.hasDepth());
CodeGenerator::generateDefine(fs, "HAS_PICKING", variant.hasPicking() && variant.hasDepth());
CodeGenerator::generateDefine(fs, "HAS_VSM", variant.hasVsm());
CodeGenerator::generateDefine(fs, "HAS_SHADOW_MULTIPLIER", material.hasShadowMultiplier);
CodeGenerator::generateDefine(fs, "HAS_TRANSPARENT_SHADOW", material.hasTransparentShadow);
// material defines
cg.generateDefine(fs, "MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY", material.hasDoubleSidedCapability);
CodeGenerator::generateDefine(fs, "MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY", material.hasDoubleSidedCapability);
switch (material.blendingMode) {
case BlendingMode::OPAQUE:
cg.generateDefine(fs, "BLEND_MODE_OPAQUE", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_OPAQUE", true);
break;
case BlendingMode::TRANSPARENT:
cg.generateDefine(fs, "BLEND_MODE_TRANSPARENT", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_TRANSPARENT", true);
break;
case BlendingMode::ADD:
cg.generateDefine(fs, "BLEND_MODE_ADD", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_ADD", true);
break;
case BlendingMode::MASKED:
cg.generateDefine(fs, "BLEND_MODE_MASKED", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_MASKED", true);
break;
case BlendingMode::FADE:
// Fade is a special case of transparent
cg.generateDefine(fs, "BLEND_MODE_TRANSPARENT", true);
cg.generateDefine(fs, "BLEND_MODE_FADE", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_TRANSPARENT", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_FADE", true);
break;
case BlendingMode::MULTIPLY:
cg.generateDefine(fs, "BLEND_MODE_MULTIPLY", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_MULTIPLY", true);
break;
case BlendingMode::SCREEN:
cg.generateDefine(fs, "BLEND_MODE_SCREEN", true);
CodeGenerator::generateDefine(fs, "BLEND_MODE_SCREEN", true);
break;
}
switch (material.postLightingBlendingMode) {
case BlendingMode::OPAQUE:
cg.generateDefine(fs, "POST_LIGHTING_BLEND_MODE_OPAQUE", true);
CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_OPAQUE", true);
break;
case BlendingMode::TRANSPARENT:
cg.generateDefine(fs, "POST_LIGHTING_BLEND_MODE_TRANSPARENT", true);
CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_TRANSPARENT", true);
break;
case BlendingMode::ADD:
cg.generateDefine(fs, "POST_LIGHTING_BLEND_MODE_ADD", true);
CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_ADD", true);
break;
case BlendingMode::MULTIPLY:
cg.generateDefine(fs, "POST_LIGHTING_BLEND_MODE_MULTIPLY", true);
CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_MULTIPLY", true);
break;
case BlendingMode::SCREEN:
cg.generateDefine(fs, "POST_LIGHTING_BLEND_MODE_SCREEN", true);
CodeGenerator::generateDefine(fs, "POST_LIGHTING_BLEND_MODE_SCREEN", true);
break;
default:
break;
}
cg.generateDefine(fs, getShadingDefine(material.shading), true);
generateMaterialDefines(fs, cg, mProperties, mDefines);
CodeGenerator::generateDefine(fs, getShadingDefine(material.shading), true);
generateMaterialDefines(fs, mProperties, mDefines);
cg.generateDefine(fs, "MATERIAL_HAS_CUSTOM_SURFACE_SHADING", material.hasCustomSurfaceShading);
CodeGenerator::generateDefine(fs, "MATERIAL_HAS_CUSTOM_SURFACE_SHADING", material.hasCustomSurfaceShading);
cg.generateShaderInputs(fs, ShaderType::FRAGMENT, material.requiredAttributes, interpolation);
CodeGenerator::generateShaderInputs(fs, ShaderType::FRAGMENT, material.requiredAttributes, interpolation);
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
cg.generateVariable(fs, ShaderType::FRAGMENT, variable, variableIndex++);
CodeGenerator::generateVariable(fs, ShaderType::FRAGMENT, variable, variableIndex++);
}
// uniforms and samplers
@@ -427,7 +426,7 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode
BindingPoints::FROXEL_RECORDS, UibGenerator::getFroxelRecordUib());
cg.generateUniforms(fs, ShaderType::FRAGMENT,
BindingPoints::PER_MATERIAL_INSTANCE, material.uib);
cg.generateSeparator(fs);
CodeGenerator::generateSeparator(fs);
cg.generateSamplers(fs,
material.samplerBindings.getBlockOffset(BindingPoints::PER_VIEW),
SibGenerator::getPerViewSib(variantKey));
@@ -438,39 +437,41 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode
fs << "float filament_lodBias;\n";
// shading code
cg.generateCommon(fs, ShaderType::FRAGMENT);
cg.generateGetters(fs, ShaderType::FRAGMENT);
cg.generateCommonMaterial(fs, ShaderType::FRAGMENT);
cg.generateParameters(fs, ShaderType::FRAGMENT);
cg.generateFog(fs, ShaderType::FRAGMENT);
CodeGenerator::generateCommon(fs, ShaderType::FRAGMENT);
CodeGenerator::generateGetters(fs, ShaderType::FRAGMENT);
CodeGenerator::generateCommonMaterial(fs, ShaderType::FRAGMENT);
CodeGenerator::generateParameters(fs, ShaderType::FRAGMENT);
CodeGenerator::generateFog(fs, ShaderType::FRAGMENT);
// shading model
if (filament::Variant::isValidDepthVariant(variantKey)) {
// In MASKED mode or with transparent shadows, we need the alpha channel computed by
// the material (user code), so we append it here.
if (material.blendingMode == BlendingMode::MASKED || material.hasTransparentShadow) {
appendShader(fs, mMaterialCode, mMaterialLineOffset);
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
}
// these variants are special and are treated as DEPTH variants. Filament will never
// request that variant for the color pass.
cg.generateDepthShaderMain(fs, ShaderType::FRAGMENT);
CodeGenerator::generateDepthShaderMain(fs, ShaderType::FRAGMENT);
} else {
appendShader(fs, mMaterialCode, mMaterialLineOffset);
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
if (material.isLit) {
cg.generateShaderLit(fs, ShaderType::FRAGMENT, variant, material.shading,
CodeGenerator::generateShaderLit(fs, ShaderType::FRAGMENT, variant, material.shading,
material.hasCustomSurfaceShading);
} else {
cg.generateShaderUnlit(fs, ShaderType::FRAGMENT, variant, material.hasShadowMultiplier);
CodeGenerator::generateShaderUnlit(fs, ShaderType::FRAGMENT, variant, material.hasShadowMultiplier);
}
// entry point
cg.generateShaderMain(fs, ShaderType::FRAGMENT);
CodeGenerator::generateShaderMain(fs, ShaderType::FRAGMENT);
}
cg.generateEpilog(fs);
CodeGenerator::generateEpilog(fs);
return fs.c_str();
}
void ShaderGenerator::fixupExternalSamplers(filament::backend::ShaderModel sm,
std::string& shader, MaterialInfo const& material) const noexcept {
void ShaderGenerator::fixupExternalSamplers(ShaderModel sm,
std::string& shader, MaterialInfo const& material) noexcept {
// External samplers are only supported on GL ES at the moment, we must
// skip the fixup on desktop targets
if (material.hasExternalSamplers && sm == ShaderModel::GL_ES_30) {
@@ -479,28 +480,28 @@ void ShaderGenerator::fixupExternalSamplers(filament::backend::ShaderModel sm,
}
std::string ShaderGenerator::createPostProcessVertexProgram(
filament::backend::ShaderModel sm, MaterialBuilder::TargetApi targetApi,
ShaderModel sm, MaterialBuilder::TargetApi targetApi,
MaterialBuilder::TargetLanguage targetLanguage, MaterialInfo const& material,
uint8_t variant, const filament::SamplerBindingMap& samplerBindingMap) const noexcept {
uint8_t variant, const SamplerBindingMap& samplerBindingMap) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage);
utils::io::sstream vs;
io::sstream vs;
cg.generateProlog(vs, ShaderType::VERTEX, false);
cg.generateQualityDefine(vs, material.quality);
cg.generateDefine(vs, "LOCATION_POSITION", uint32_t(VertexAttribute::POSITION));
CodeGenerator::generateDefine(vs, "LOCATION_POSITION", uint32_t(VertexAttribute::POSITION));
// The UVs are at the location immediately following the custom variables.
cg.generateDefine(vs, "LOCATION_UVS", uint32_t(MaterialBuilder::MATERIAL_VARIABLES_COUNT));
CodeGenerator::generateDefine(vs, "LOCATION_UVS", uint32_t(MaterialBuilder::MATERIAL_VARIABLES_COUNT));
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
cg.generateVariable(vs, ShaderType::VERTEX, variable, variableIndex++);
CodeGenerator::generateVariable(vs, ShaderType::VERTEX, variable, variableIndex++);
}
cg.generatePostProcessInputs(vs, ShaderType::VERTEX);
generatePostProcessMaterialVariantDefines(cg, vs, PostProcessVariant(variant));
CodeGenerator::generatePostProcessInputs(vs, ShaderType::VERTEX);
generatePostProcessMaterialVariantDefines(vs, PostProcessVariant(variant));
cg.generateUniforms(vs, ShaderType::VERTEX,
BindingPoints::PER_VIEW, UibGenerator::getPerViewUib());
@@ -511,36 +512,36 @@ std::string ShaderGenerator::createPostProcessVertexProgram(
material.samplerBindings.getBlockOffset(BindingPoints::PER_MATERIAL_INSTANCE),
material.sib);
cg.generateCommon(vs, ShaderType::VERTEX);
cg.generatePostProcessGetters(vs, ShaderType::VERTEX);
CodeGenerator::generateCommon(vs, ShaderType::VERTEX);
CodeGenerator::generatePostProcessGetters(vs, ShaderType::VERTEX);
appendShader(vs, mMaterialVertexCode, mMaterialVertexLineOffset);
cg.generatePostProcessMain(vs, ShaderType::VERTEX);
CodeGenerator::generatePostProcessMain(vs, ShaderType::VERTEX);
cg.generateEpilog(vs);
CodeGenerator::generateEpilog(vs);
return vs.c_str();
}
std::string ShaderGenerator::createPostProcessFragmentProgram(
filament::backend::ShaderModel sm, MaterialBuilder::TargetApi targetApi,
ShaderModel sm, MaterialBuilder::TargetApi targetApi,
MaterialBuilder::TargetLanguage targetLanguage, MaterialInfo const& material,
uint8_t variant, const filament::SamplerBindingMap& samplerBindingMap) const noexcept {
uint8_t variant, const SamplerBindingMap& samplerBindingMap) const noexcept {
const CodeGenerator cg(sm, targetApi, targetLanguage);
utils::io::sstream fs;
io::sstream fs;
cg.generateProlog(fs, ShaderType::FRAGMENT, false);
cg.generateQualityDefine(fs, material.quality);
// The UVs are at the location immediately following the custom variables.
cg.generateDefine(fs, "LOCATION_UVS", uint32_t(MaterialBuilder::MATERIAL_VARIABLES_COUNT));
CodeGenerator::generateDefine(fs, "LOCATION_UVS", uint32_t(MaterialBuilder::MATERIAL_VARIABLES_COUNT));
generatePostProcessMaterialVariantDefines(cg, fs, PostProcessVariant(variant));
generatePostProcessMaterialVariantDefines(fs, PostProcessVariant(variant));
// custom material variables
size_t variableIndex = 0;
for (const auto& variable : mVariables) {
cg.generateVariable(fs, ShaderType::FRAGMENT, variable, variableIndex++);
CodeGenerator::generateVariable(fs, ShaderType::FRAGMENT, variable, variableIndex++);
}
cg.generateUniforms(fs, ShaderType::FRAGMENT,
@@ -553,10 +554,10 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(
material.sib);
// subpass
cg.generateSubpass(fs, material.subpass);
CodeGenerator::generateSubpass(fs, material.subpass);
cg.generateCommon(fs, ShaderType::FRAGMENT);
cg.generatePostProcessGetters(fs, ShaderType::FRAGMENT);
CodeGenerator::generateCommon(fs, ShaderType::FRAGMENT);
CodeGenerator::generatePostProcessGetters(fs, ShaderType::FRAGMENT);
// Generate post-process outputs.
for (const auto& output : mOutputs) {
@@ -565,16 +566,16 @@ std::string ShaderGenerator::createPostProcessFragmentProgram(
output.qualifier, output.type);
}
if (output.target == MaterialBuilder::OutputTarget::DEPTH) {
cg.generateDefine(fs, "FRAG_OUTPUT_DEPTH", 1u);
CodeGenerator::generateDefine(fs, "FRAG_OUTPUT_DEPTH", 1u);
}
}
cg.generatePostProcessInputs(fs, ShaderType::FRAGMENT);
CodeGenerator::generatePostProcessInputs(fs, ShaderType::FRAGMENT);
appendShader(fs, mMaterialCode, mMaterialLineOffset);
appendShader(fs, mMaterialFragmentCode, mMaterialLineOffset);
cg.generatePostProcessMain(fs, ShaderType::FRAGMENT);
cg.generateEpilog(fs);
CodeGenerator::generatePostProcessMain(fs, ShaderType::FRAGMENT);
CodeGenerator::generateEpilog(fs);
return fs.c_str();
}

View File

@@ -45,18 +45,17 @@ public:
size_t vertexLineOffset,
MaterialBuilder::MaterialDomain materialDomain) noexcept;
std::string createVertexProgram(filament::backend::ShaderModel sm,
std::string createVertexProgram(filament::backend::ShaderModel shaderModel,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialInfo const& material, uint8_t variantKey,
filament::Interpolation interpolation,
filament::VertexDomain vertexDomain) const noexcept;
std::string createFragmentProgram(filament::backend::ShaderModel sm,
MaterialBuilder::TargetApi targetApi, MaterialBuilder::TargetLanguage targetLanguage,
MaterialInfo const& material, uint8_t variantKey,
filament::Interpolation interpolation) const noexcept;
bool hasCustomDepthShader() const noexcept;
/**
* When a GLSL shader is optimized we run it through an intermediate SPIR-V
* representation. Unfortunately external samplers cannot be used with SPIR-V
@@ -64,8 +63,8 @@ public:
* fixup step can be used to turn the samplers back into external samplers after
* the optimizations have been applied.
*/
void fixupExternalSamplers(filament::backend::ShaderModel sm, std::string& shader,
MaterialInfo const& material) const noexcept;
static void fixupExternalSamplers(filament::backend::ShaderModel sm, std::string& shader,
MaterialInfo const& material) noexcept;
private:
@@ -84,10 +83,11 @@ private:
MaterialBuilder::OutputList mOutputs;
MaterialBuilder::MaterialDomain mMaterialDomain;
MaterialBuilder::PreprocessorDefineList mDefines;
utils::CString mMaterialCode;
utils::CString mMaterialFragmentCode;
utils::CString mMaterialVertexCode;
size_t mMaterialLineOffset;
size_t mMaterialVertexLineOffset;
bool mIsMaterialVertexShaderEmpty;
};
} // namespace filament

View File

@@ -17,7 +17,7 @@
#ifndef TNT_UTILS_CONDITION_H
#define TNT_UTILS_CONDITION_H
#if defined(__linux__) && !defined(__SANITIZE_THREAD__)
#if defined(__linux__)
#include <utils/linux/Condition.h>
#else
#include <utils/generic/Condition.h>

View File

@@ -17,7 +17,7 @@
#ifndef TNT_UTILS_MUTEX_H
#define TNT_UTILS_MUTEX_H
#if defined(__linux__) && !defined(__SANITIZE_THREAD__)
#if defined(__linux__)
#include <utils/linux/Mutex.h>
#else
#include <utils/generic/Mutex.h>

View File

@@ -75,8 +75,8 @@ private:
};
} // namespace details
#if defined(__SANITIZE_THREAD__)
// Unfortunately TSAN doesn't support homegrown synchronization primitives
#if UTILS_HAS_SANITIZE_THREAD
// Active spins with atomics slow down execution too much under ThreadSanitizer.
using SpinLock = Mutex;
#elif defined(__ARM_ARCH_7A__)
// We've had problems with "wfe" on some ARM-V7 devices, causing spurious SIGILL

View File

@@ -65,19 +65,21 @@
#endif
#define UTILS_NO_SANITIZE_THREAD
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# undef UTILS_NO_SANITIZE_THREAD
# define UTILS_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
# endif
#if __has_feature(thread_sanitizer)
#undef UTILS_NO_SANITIZE_THREAD
#define UTILS_NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
#endif
#define UTILS_HAS_SANITIZE_THREAD 0
#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
#undef UTILS_HAS_SANITIZE_THREAD
#define UTILS_HAS_SANITIZE_THREAD 1
#endif
#define UTILS_HAS_SANITIZE_MEMORY 0
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# undef UTILS_HAS_SANITIZE_MEMORY
# define UTILS_HAS_SANITIZE_MEMORY 1
# endif
#if __has_feature(memory_sanitizer)
#undef UTILS_HAS_SANITIZE_MEMORY
#define UTILS_HAS_SANITIZE_MEMORY 1
#endif
/*

View File

@@ -22,7 +22,6 @@ set(SHADERS
src/common_shadowing.fs
src/common_types.fs
src/depth_main.fs
src/depth_main.vs
src/fog.fs
src/getters.fs
src/getters.vs

View File

@@ -57,6 +57,18 @@ float max3(const vec3 v) {
return max(v.x, max(v.y, v.z));
}
float vmax(const vec2 v) {
return max(v.x, v.y);
}
float vmax(const vec3 v) {
return max(v.x, max(v.y, v.z));
}
float vmax(const vec4 v) {
return max(max(v.x, v.y), max(v.y, v.z));
}
/**
* Returns the minimum component of the specified vector.
*
@@ -66,6 +78,18 @@ float min3(const vec3 v) {
return min(v.x, min(v.y, v.z));
}
float vmin(const vec2 v) {
return min(v.x, v.y);
}
float vmin(const vec3 v) {
return min(v.x, min(v.y, v.z));
}
float vmin(const vec4 v) {
return min(min(v.x, v.y), min(v.y, v.z));
}
//------------------------------------------------------------------------------
// Trigonometry
//------------------------------------------------------------------------------

View File

@@ -11,34 +11,16 @@
* Normal bias is not used for VSM.
*/
#if defined(HAS_VSM)
#if defined(HAS_DIRECTIONAL_LIGHTING)
highp vec4 computeLightSpacePositionDirectional(const highp vec3 p, const highp vec3 n,
highp vec4 computeLightSpacePosition(highp vec3 p, const highp vec3 n,
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
return mulMat4x4Float3(lightFromWorldMatrix, p);
}
#endif // HAS_DIRECTIONAL_LIGHTING
#if defined(HAS_DYNAMIC_LIGHTING)
highp vec4 computeLightSpacePositionSpot(const highp vec3 p, const highp vec3 n,
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
return mulMat4x4Float3(lightFromWorldMatrix, p);
}
#endif // HAS_DYNAMIC_LIGHTING
#else // HAS_VSM
highp vec4 computeLightSpacePositionDirectional(const highp vec3 p, const highp vec3 n,
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
float NoL = saturate(dot(n, l));
#if !defined(HAS_VSM)
highp float NoL = saturate(dot(n, l));
highp float sinTheta = sqrt(1.0 - NoL * NoL);
highp vec3 offsetPosition = p + n * (sinTheta * b);
return mulMat4x4Float3(lightFromWorldMatrix, offsetPosition);
p += n * (sinTheta * b);
#endif
return mulMat4x4Float3(lightFromWorldMatrix, p);
}
#if defined(HAS_DYNAMIC_LIGHTING)
highp vec4 computeLightSpacePositionSpot(const highp vec3 p, const highp vec3 n,
const highp vec3 l, const float b, const highp mat4 lightFromWorldMatrix) {
highp vec4 positionLs = mulMat4x4Float3(lightFromWorldMatrix, p);
highp float oneOverZ = positionLs.w / positionLs.z;
return computeLightSpacePositionDirectional(p, n, l, b * oneOverZ, lightFromWorldMatrix);
}
#endif // HAS_DIRECTIONAL_LIGHTING
#endif // HAS_VSM
#endif // HAS_SHADOWING

View File

@@ -29,4 +29,5 @@ struct ShadowData {
highp mat4 lightFromWorldMatrix;
highp vec3 direction;
float normalBias;
float texelSizeAtOneMeter;
};

View File

@@ -12,10 +12,12 @@ layout(location = 0) out highp uint2 outPicking;
// note: HAS_VSM and HAS_PICKING are mutually exclusive
//------------------------------------------------------------------------------
highp vec2 computeDepthMomentsVSM(const highp float depth);
void main() {
filament_lodBias = frameUniforms.lodBias;
#if defined(BLEND_MODE_MASKED) || (defined(BLEND_MODE_TRANSPARENT) && defined(HAS_TRANSPARENT_SHADOW))
#if defined(BLEND_MODE_MASKED) || ((defined(BLEND_MODE_TRANSPARENT) || defined(BLEND_MODE_FADE)) && defined(HAS_TRANSPARENT_SHADOW))
MaterialInputs inputs;
initMaterial(inputs);
material(inputs);
@@ -37,9 +39,22 @@ void main() {
#endif
#if defined(HAS_VSM)
// interpolated depth is stored in vertex_worldPosition.w (see depth_main.vs / main.vs)
highp float depth = exp(vertex_worldPosition.w);
// interpolated depth is stored in vertex_worldPosition.w (see main.vs)
highp float depth = vertex_worldPosition.w;
depth = exp(depth);
fragColor.xy = computeDepthMomentsVSM(depth);
fragColor.zw = vec2(0.0);
// enable for full EVSM (needed for large blurs). RGBA16F needed.
//fragColor.zw = computeDepthMomentsVSM(-1.0/depth);
#elif defined(HAS_PICKING)
outPicking.x = objectUniforms.objectId;
outPicking.y = floatBitsToUint(vertex_position.z / vertex_position.w);
#else
// that's it
#endif
}
highp vec2 computeDepthMomentsVSM(const highp float depth) {
// computes the moments
// See GPU Gems 3
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-8-summed-area-variance-shadow-maps
@@ -53,11 +68,5 @@ void main() {
highp float dy = dFdy(depth);
moments.y = depth * depth + 0.25 * (dx * dx + dy * dy);
fragColor = vec4(moments, 0.0, 0.0);
#elif defined(HAS_PICKING)
outPicking.x = objectUniforms.objectId;
outPicking.y = floatBitsToUint(vertex_position.z / vertex_position.w);
#else
// that's it
#endif
return moments;
}

View File

@@ -1,57 +0,0 @@
// The sole purpose of this no-op function is to improve parity between the depth vertex shader
// and color vertex shader, thus working around a variance issue seen with NVIDIA drivers.
void materialVertex(inout MaterialVertexInputs m) { }
// NOTE: This shader is only used when the user's material does not have custom vertex code.
// There is no need to check anything related to material inputs in this file.
void main() {
// World position is used to compute gl_Position, except for vertices already in the device domain.
// Regardless of vertex domain, if VSM is turned on, then we need to compute world position to pass
// to the fragment shader.
#if !defined(VERTEX_DOMAIN_DEVICE) || defined(HAS_VSM)
// Run initMaterialVertex to compute material.worldPosition.
MaterialVertexInputs material;
initMaterialVertex(material);
materialVertex(material);
#endif
#if defined(VERTEX_DOMAIN_DEVICE)
gl_Position = getPosition();
// GL convention to inverted DX convention
gl_Position.z = gl_Position.z * -0.5 + 0.5;
#else
gl_Position = getClipFromWorldMatrix() * getWorldPosition(material);
#endif
#if defined(HAS_VSM)
// For VSM, we use the linear light-space Z coordinate as the depth metric, which works for both
// directional and spot lights and can be safely interpolated.
// The value is guaranteed to be between [-znear, -zfar] by construction of viewFromWorldMatrix,
// (see ShadowMap.cpp).
// Use vertex_worldPosition.w which is otherwise not used to store the interpolated
// light-space depth.
highp float z = (frameUniforms.viewFromWorldMatrix * vec4(material.worldPosition.xyz, 1.0)).z;
// rescale [near, far] to [0, 1]
highp float depth = -z * frameUniforms.oneOverFarMinusNear - frameUniforms.nearOverFarMinusNear;
// EVSM pre-mapping
depth = frameUniforms.vsmExponent * (depth * 2.0 - 1.0);
vertex_worldPosition.w = depth;
#endif
// this must happen before we compensate for vulkan below
vertex_position = gl_Position;
#if defined(TARGET_VULKAN_ENVIRONMENT)
// In Vulkan, clip space is Y-down. In OpenGL and Metal, clip space is Y-up.
gl_Position.y = -gl_Position.y;
#endif
#if !defined(TARGET_VULKAN_ENVIRONMENT) && !defined(TARGET_METAL_ENVIRONMENT)
// This is not needed in Vulkan or Metal because clipControl is always (1, 0)
gl_Position.z = dot(gl_Position.zw, frameUniforms.clipControl);
#endif
}

View File

@@ -100,10 +100,16 @@ highp vec3 getNormalizedViewportCoord2() {
#if defined(HAS_SHADOWING) && defined(HAS_DYNAMIC_LIGHTING)
highp vec4 getSpotLightSpacePosition(uint index) {
highp mat4 lightFromWorldMatrix = shadowUniforms.shadows[index].lightFromWorldMatrix;
highp vec3 dir = shadowUniforms.shadows[index].direction;
// for spotlights, the bias depends on z
float bias = shadowUniforms.shadows[index].normalBias;
return computeLightSpacePositionSpot(vertex_worldPosition.xyz,
vertex_worldNormal, dir, bias, shadowUniforms.shadows[index].lightFromWorldMatrix);
highp vec4 positionLs = mulMat4x4Float3(lightFromWorldMatrix, vertex_worldPosition.xyz);
highp float oneOverZ = positionLs.w / positionLs.z;
return computeLightSpacePosition(vertex_worldPosition.xyz,
vertex_worldNormal, dir, oneOverZ * bias, lightFromWorldMatrix);
}
#endif
@@ -128,13 +134,13 @@ uint getShadowCascade() {
highp vec4 getCascadeLightSpacePosition(uint cascade) {
// For the first cascade, return the interpolated light space position.
// This branch will be coherent (mostly) for neighboring fragments, and it's worth avoiding
// the matrix multiply inside computeLightSpacePositionDirectional.
// the matrix multiply inside computeLightSpacePosition.
if (cascade == 0u) {
// Note: this branch may cause issues with derivatives
return vertex_lightSpacePosition;
}
return computeLightSpacePositionDirectional(getWorldPosition(), getWorldNormalVector(),
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
frameUniforms.lightDirection, frameUniforms.shadowBias.y,
frameUniforms.lightFromWorldMatrix[cascade]);
}

View File

@@ -57,7 +57,7 @@ void evaluateDirectionalLight(const MaterialInputs material,
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
uint layer = cascade;
visibility = shadow(light_shadowMap, layer, getCascadeLightSpacePosition(cascade));
visibility = shadow(true, light_shadowMap, layer, 0u, cascade);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {

View File

@@ -211,8 +211,7 @@ void evaluatePunctualLights(const MaterialInputs material,
#if defined(HAS_SHADOWING)
if (light.NoL > 0.0) {
if (light.castsShadows) {
visibility = shadow(light_shadowMap, light.shadowLayer,
getSpotLightSpacePosition(light.shadowIndex));
visibility = shadow(false, light_shadowMap, light.shadowLayer, light.shadowIndex, 0u);
}
if (light.contactShadows && visibility > 0.0) {
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {

View File

@@ -1,5 +1,28 @@
/*
* This is the main vertex shader of surface materials. It can be invoked with
* USE_OPTIMIZED_DEPTH_VERTEX_SHADER defined, and in this case we are guaranteed that the
* DEPTH variant is active *AND* there is no custom vertex shader (i.e.: materialVertex() is
* empty).
* We can use this to remove all code that doesn't participate in the depth computation.
*/
void main() {
// Initialize the inputs to sensible default values, see material_inputs.vs
#if defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
// In USE_OPTIMIZED_DEPTH_VERTEX_SHADER mode, we can even skip this if we're already in
// VERTEX_DOMAIN_DEVICE and we don't have VSM.
#if !defined(VERTEX_DOMAIN_DEVICE) || defined(HAS_VSM)
// Run initMaterialVertex to compute material.worldPosition.
MaterialVertexInputs material;
initMaterialVertex(material);
// materialVertex() is guaranteed to be empty here, but we keep it to workaround some problem
// in NVIDA drivers related to depth invariance.
materialVertex(material);
#endif
#else // defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
MaterialVertexInputs material;
initMaterialVertex(material);
@@ -89,11 +112,14 @@ void main() {
#endif
#if defined(HAS_SHADOWING) && defined(HAS_DIRECTIONAL_LIGHTING)
vertex_lightSpacePosition = computeLightSpacePositionDirectional(
vertex_lightSpacePosition = computeLightSpacePosition(
vertex_worldPosition.xyz, vertex_worldNormal,
frameUniforms.lightDirection, frameUniforms.shadowBias.y, getLightFromWorldMatrix());
#endif
#endif // !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
#if defined(VERTEX_DOMAIN_DEVICE)
// The other vertex domains are handled in initMaterialVertex()->computeWorldPosition()
gl_Position = getPosition();
@@ -101,9 +127,11 @@ void main() {
gl_Position = getClipFromWorldMatrix() * getWorldPosition(material);
#endif
#if !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
#if defined(MATERIAL_HAS_CLIP_SPACE_TRANSFORM)
gl_Position = getClipSpaceTransform(material) * gl_Position;
#endif
#endif // !USE_OPTIMIZED_DEPTH_VERTEX_SHADER
#if defined(VERTEX_DOMAIN_DEVICE)
// GL convention to inverted DX convention (must happen after clipSpaceTransform)

View File

@@ -45,7 +45,7 @@ vec4 evaluateMaterial(const MaterialInputs material) {
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
uint layer = cascade;
visibility = shadow(light_shadowMap, layer, getCascadeLightSpacePosition(cascade));
visibility = shadow(true, light_shadowMap, layer, 0u, cascade);
}
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {

View File

@@ -1,75 +1,25 @@
//------------------------------------------------------------------------------
// Shadowing configuration
// PCF Shadow Sampling
//------------------------------------------------------------------------------
#define SHADOW_SAMPLING_ERROR_DISABLED 0
#define SHADOW_SAMPLING_ERROR_ENABLED 1
#define SHADOW_RECEIVER_PLANE_DEPTH_BIAS_DISABLED 0
#define SHADOW_RECEIVER_PLANE_DEPTH_BIAS_ENABLED 1
#define SHADOW_SAMPLING_ERROR SHADOW_SAMPLING_ERROR_DISABLED
#define SHADOW_RECEIVER_PLANE_DEPTH_BIAS SHADOW_RECEIVER_PLANE_DEPTH_BIAS_DISABLED
//------------------------------------------------------------------------------
// Shadow sampling methods
//------------------------------------------------------------------------------
vec2 computeReceiverPlaneDepthBias(const highp vec3 position) {
// see: GDC '06: Shadow Mapping: GPU-based Tips and Techniques
vec2 bias;
#if SHADOW_RECEIVER_PLANE_DEPTH_BIAS == SHADOW_RECEIVER_PLANE_DEPTH_BIAS_ENABLED
highp vec3 du = dFdx(position);
highp vec3 dv = dFdy(position);
// Chain rule we use:
// | du.x du.y |^-T | dv.y -du.y |T | dv.y -dv.x |
// D * | dv.x dv.y | = | -dv.x du.x | = | -du.y du.x |
bias = inverse(mat2(du.xy, dv.xy)) * vec2(du.z, dv.z);
#else
bias = vec2(0.0);
#endif
return bias;
}
float samplingBias(float depth, const vec2 rpdb, const highp vec2 texelSize) {
#if SHADOW_SAMPLING_ERROR == SHADOW_SAMPLING_ERROR_ENABLED
// note: if filtering is set to NEAREST, the 2.0 factor below can be changed to 1.0
float samplingError = min(2.0 * dot(texelSize, abs(rpdb)), 0.01);
depth += samplingError;
#endif
return depth;
}
float sampleDepth(const mediump sampler2DArrayShadow map, const uint layer,
const highp vec2 base, const highp vec2 dudv, float depth, vec2 rpdb) {
#if SHADOW_RECEIVER_PLANE_DEPTH_BIAS == SHADOW_RECEIVER_PLANE_DEPTH_BIAS_ENABLED
depth += dot(dudv, rpdb);
#endif
const highp vec2 uv, float depth) {
// depth must be clamped to support floating-point depth formats. This is to avoid comparing a
// value from the depth texture (which is never greater than 1.0) with a greater-than-one
// comparison value (which is possible with floating-point formats).
return texture(map, vec4(base + dudv, layer, saturate(depth)));
return texture(map, vec4(uv, layer, saturate(depth)));
}
// use hardware assisted PCF
float ShadowSample_PCF(const mediump sampler2DArrayShadow map,
const uint layer, const highp vec3 position) {
highp vec2 size = vec2(textureSize(map, 0));
highp vec2 texelSize = vec2(1.0) / size;
vec2 rpdb = computeReceiverPlaneDepthBias(position);
float depth = samplingBias(position.z, rpdb, texelSize);
// use hardware assisted PCF
return sampleDepth(map,layer, position.xy, vec2(0.0f), depth, rpdb);
return sampleDepth(map, layer, position.xy, position.z);
}
// use manual PCF
float ShadowSample_PCF(const mediump sampler2DArray shadowMap,
const uint layer, const highp vec3 position) {
highp vec2 size = vec2(textureSize(shadowMap, 0));
highp vec2 texelSize = vec2(1.0) / size;
vec2 rpdb = computeReceiverPlaneDepthBias(position);
float depth = samplingBias(position.z, rpdb, texelSize);
// use manual PCF
highp vec2 st = position.xy * size - 0.5;
vec4 d;
#if defined(FILAMENT_HAS_FEATURE_TEXTURE_GATHER)
@@ -81,7 +31,7 @@ float ShadowSample_PCF(const mediump sampler2DArray shadowMap,
d[2] = texelFetchOffset(shadowMap, tc, 0, ivec2(1, 0)).r;
d[3] = texelFetchOffset(shadowMap, tc, 0, ivec2(0, 0)).r;
#endif
vec4 pcf = step(0.0, d - vec4(depth));
vec4 pcf = step(0.0, d - position.zzzz);
highp vec2 grad = fract(st);
return mix(mix(pcf.w, pcf.z, grad.x), mix(pcf.x, pcf.y, grad.x), grad.y);
}
@@ -190,20 +140,26 @@ float chebyshevUpperBound(const highp vec2 moments, const highp float mean,
return mean <= moments.x ? 1.0 : pMax;
}
float evaluateShadowVSM(const highp vec2 moments, const highp float depth) {
highp float depthScale = frameUniforms.vsmDepthScale * depth;
highp float minVariance = depthScale * depthScale;
return chebyshevUpperBound(moments, depth, minVariance, frameUniforms.vsmLightBleedReduction);
}
float ShadowSample_VSM(const mediump sampler2DArray shadowMap,
const uint layer, const highp vec3 position) {
// Read the shadow map with all available filtering
highp vec2 moments = texture(shadowMap, vec3(position.xy, layer)).xy;
highp vec4 moments = texture(shadowMap, vec3(position.xy, layer));
highp float depth = position.z;
// EVSM depth warping
depth = depth * 2.0 - 1.0;
depth = exp(frameUniforms.vsmExponent * depth);
highp float depthScale = frameUniforms.vsmDepthScale * depth;
highp float minVariance = depthScale * depthScale;
float lightBleedReduction = frameUniforms.vsmLightBleedReduction;
return chebyshevUpperBound(moments, depth, minVariance, lightBleedReduction);
depth = exp(frameUniforms.vsmExponent * depth);
float p = evaluateShadowVSM(moments.xy, depth);
// enable for full EVSM (needed for large blurs). RGBA16F needed.
//p = min(p, evaluateShadowVSM(moments.zw, -1.0/depth));
return p;
}
//------------------------------------------------------------------------------
@@ -217,16 +173,46 @@ float ShadowSample_VSM(const mediump sampler2DArray shadowMap,
*/
// PCF sampling
float shadow(const mediump sampler2DArrayShadow shadowMap,
const uint layer, const highp vec4 shadowPosition) {
float shadow(const bool DIRECTIONAL,
const mediump sampler2DArrayShadow shadowMap,
const uint layer, const uint index, const uint cascade) {
highp vec4 shadowPosition;
// This conditional is resolved at compile time
if (DIRECTIONAL) {
#if defined(HAS_DIRECTIONAL_LIGHTING)
shadowPosition = getCascadeLightSpacePosition(cascade);
#endif
} else {
#if defined(HAS_DYNAMIC_LIGHTING)
shadowPosition = getSpotLightSpacePosition(index);
#endif
}
highp vec3 position = shadowPosition.xyz * (1.0 / shadowPosition.w);
// note: shadowPosition.z is in the [1, 0] range (reversed Z)
return ShadowSample_PCF(shadowMap, layer, position);
}
// VSM sampling
float shadow(const mediump sampler2DArray shadowMap,
const uint layer, const highp vec4 shadowPosition) {
float shadow(const bool DIRECTIONAL,
const mediump sampler2DArray shadowMap,
const uint layer, const uint index, const uint cascade) {
highp vec4 shadowPosition;
// This conditional is resolved at compile time
if (DIRECTIONAL) {
#if defined(HAS_DIRECTIONAL_LIGHTING)
shadowPosition = getCascadeLightSpacePosition(cascade);
#endif
} else {
#if defined(HAS_DYNAMIC_LIGHTING)
shadowPosition = getSpotLightSpacePosition(index);
#endif
}
// note: shadowPosition.z is in linear light-space normalized to [0, 1]
// see: ShadowMap::computeVsmLightSpaceMatrix() in ShadowMap.cpp
// see: computeLightSpacePosition() in common_shadowing.fs

View File

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