Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbe7dbfa92 | ||
|
|
5697922a65 | ||
|
|
4da83df2b9 | ||
|
|
8f156d6588 | ||
|
|
cec0871c11 | ||
|
|
f690015a88 | ||
|
|
342deb5a64 | ||
|
|
fdc480ff6e | ||
|
|
378b7cd4dd | ||
|
|
f779fc7a0e | ||
|
|
fe11f495d6 | ||
|
|
265876c849 | ||
|
|
c9c52518c0 | ||
|
|
96c9ac6f8b | ||
|
|
bdeb30a847 | ||
|
|
d67210155b | ||
|
|
ae92c50cee | ||
|
|
43429dc0ec | ||
|
|
04cf92a27f | ||
|
|
57a57f50f6 | ||
|
|
5e5a75e6c5 | ||
|
|
109c86aaf7 | ||
|
|
10e7e7727a | ||
|
|
a39775050a |
29
.github/workflows/release.yml
vendored
29
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
49
filament/src/materials/separableGaussianBlur.fs
Normal file
49
filament/src/materials/separableGaussianBlur.fs
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
6
filament/src/materials/separableGaussianBlur.vs
Normal file
6
filament/src/materials/separableGaussianBlur.vs
Normal 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;
|
||||
}
|
||||
54
filament/src/materials/separableGaussianBlur1.mat
Normal file
54
filament/src/materials/separableGaussianBlur1.mat
Normal 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"
|
||||
|
||||
}
|
||||
54
filament/src/materials/separableGaussianBlur2.mat
Normal file
54
filament/src/materials/separableGaussianBlur2.mat
Normal 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"
|
||||
|
||||
}
|
||||
54
filament/src/materials/separableGaussianBlur3.mat
Normal file
54
filament/src/materials/separableGaussianBlur3.mat
Normal 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"
|
||||
|
||||
}
|
||||
54
filament/src/materials/separableGaussianBlur4.mat
Normal file
54
filament/src/materials/separableGaussianBlur4.mat
Normal 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"
|
||||
|
||||
}
|
||||
@@ -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 = {
|
||||
|
||||
@@ -189,6 +189,7 @@ struct ShadowUib {
|
||||
math::mat4f lightFromWorldMatrix;
|
||||
math::float3 direction;
|
||||
float normalBias;
|
||||
float texelSizeAtOneMeter;
|
||||
};
|
||||
ShadowData shadows[CONFIG_MAX_SHADOW_CASTING_SPOTS];
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,4 +29,5 @@ struct ShadowData {
|
||||
highp mat4 lightFromWorldMatrix;
|
||||
highp vec3 direction;
|
||||
float normalBias;
|
||||
float texelSizeAtOneMeter;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user