Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab552d3619 |
@@ -41,8 +41,6 @@ option(FILAMENT_LINUX_IS_MOBILE "Treat Linux as Mobile" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_ASAN_UBSAN "Enable Address and Undefined Behavior Sanitizers" OFF)
|
||||
|
||||
option(FILAMENT_ENABLE_FEATURE_LEVEL_0 "Enable Feature Level 0" ON)
|
||||
|
||||
set(FILAMENT_NDK_VERSION "" CACHE STRING
|
||||
"Android NDK version or version prefix to be used when building for Android."
|
||||
)
|
||||
|
||||
@@ -8,3 +8,11 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
|
||||
|
||||
## Release notes for next branch cut
|
||||
|
||||
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||
- filagui: Add support for feature level 0
|
||||
- matc: Add support for post-process materials in feature level 0
|
||||
- engine: Add `Material::getFeatureLevel()`
|
||||
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||
- engine: Support basic usage of post-processing materials on feature level 0
|
||||
|
||||
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.46.0'
|
||||
implementation 'com.google.android.filament:filament-android:1.45.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```shell
|
||||
pod 'Filament', '~> 1.46.0'
|
||||
pod 'Filament', '~> 1.45.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -7,20 +7,6 @@ A new header is inserted each time a *tag* is created.
|
||||
Instead, if you are authoring a PR for the main branch, add your release note to
|
||||
[NEW_RELEASE_NOTES.md](./NEW_RELEASE_NOTES.md).
|
||||
|
||||
## v1.46.0
|
||||
|
||||
- engine: Allow instantiating Engine at a given feature level via `Engine::Builder::featureLevel`
|
||||
- matc: Enable `GL_OES_standard_derivatives` extension in ESSL 1.0 shaders
|
||||
- matc: Fix code generation of double sided and masked materials in ESSL 1.0 shaders
|
||||
- filagui: Add support for feature level 0
|
||||
- matc: Add support for post-process materials in feature level 0
|
||||
- engine: Add `Material::getFeatureLevel()`
|
||||
- engine: Add missing `Material::getReflectionMode()` method in Java
|
||||
- engine: Support basic usage of post-processing materials on feature level 0
|
||||
- engine: Fix critical GLES 2.0 bugs
|
||||
- engine: Add `FILAMENT_ENABLE_FEATURE_LEVEL_0` build-time option optionally allow building Filament
|
||||
without FL0 support.
|
||||
|
||||
## v1.45.1
|
||||
|
||||
- engine: Added parameter for configuring JobSystem thread count
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.46.0
|
||||
VERSION_NAME=1.45.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
-58
@@ -218,6 +218,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/colorGrading/customResolveAsSubpass.mat
|
||||
src/materials/debugShadowCascades.mat
|
||||
src/materials/defaultMaterial.mat
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/dof/dof.mat
|
||||
src/materials/dof/dofCoc.mat
|
||||
src/materials/dof/dofDownsample.mat
|
||||
@@ -228,6 +229,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/dof/dofMipmap.mat
|
||||
src/materials/dof/dofMedian.mat
|
||||
src/materials/flare/flare.mat
|
||||
src/materials/blitLow.mat
|
||||
src/materials/bloom/bloomDownsample.mat
|
||||
src/materials/bloom/bloomDownsample2x.mat
|
||||
src/materials/bloom/bloomDownsample9.mat
|
||||
@@ -236,6 +238,7 @@ set(MATERIAL_SRCS
|
||||
src/materials/ssao/bilateralBlurBentNormals.mat
|
||||
src/materials/ssao/mipmapDepth.mat
|
||||
src/materials/skybox.mat
|
||||
src/materials/skybox0.mat
|
||||
src/materials/ssao/sao.mat
|
||||
src/materials/ssao/saoBentNormals.mat
|
||||
src/materials/separableGaussianBlur.mat
|
||||
@@ -244,18 +247,6 @@ set(MATERIAL_SRCS
|
||||
src/materials/vsmMipmap.mat
|
||||
)
|
||||
|
||||
set(MATERIAL_FL0_SRCS
|
||||
src/materials/defaultMaterial0.mat
|
||||
src/materials/skybox0.mat
|
||||
)
|
||||
|
||||
# TODO(exv): Replace the below duplicated materials with a command-line option
|
||||
# to matc to force disable including ESSL 1.0 code in FL0 materials.
|
||||
|
||||
set(MATERIAL_SWITCH_FL0_SRCS_HACK
|
||||
src/materials/blitLow.mat
|
||||
)
|
||||
|
||||
# Embed the binary resource blob for materials.
|
||||
get_resgen_vars(${RESOURCE_DIR} materials)
|
||||
list(APPEND PRIVATE_HDRS ${RESGEN_HEADER})
|
||||
@@ -280,11 +271,6 @@ if (NOT DFG_LUT_SIZE)
|
||||
endif()
|
||||
message(STATUS "DFG LUT size set to ${DFG_LUT_SIZE}x${DFG_LUT_SIZE}")
|
||||
|
||||
# Whether to include FL0 materials.
|
||||
if (FILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
add_definitions(-DFILAMENT_ENABLE_FEATURE_LEVEL_0)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Definitions
|
||||
# ==================================================================================================
|
||||
@@ -326,47 +312,6 @@ foreach (mat_src ${MATERIAL_SRCS})
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach()
|
||||
|
||||
|
||||
# HACK: Pick between the normal and FL0-exclusionary variants of the materials
|
||||
# based on the value of FILAMENT_ENABLE_FEATURE_LEVEL_0.
|
||||
foreach (mat_src ${MATERIAL_SWITCH_FL0_SRCS_HACK})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
if (NOT FILAMENT_ENABLE_FATURE_LEVEL_0)
|
||||
# Pick the non-FL0 variant instead.
|
||||
string(REGEX REPLACE "\\.mat$" "1.mat" fullname "${fullname}")
|
||||
string(REGEX REPLACE "\\.mat$" "1.mat" mat_src "${mat_src}")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach()
|
||||
|
||||
if (FILAMENT_ENABLE_FEATURE_LEVEL_0 AND FILAMENT_SUPPORTS_OPENGL)
|
||||
foreach (mat_src ${MATERIAL_FL0_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc -a opengl -p ${MATC_TARGET} ${MATC_OPT_FLAGS} -o ${output_path} ${fullname}
|
||||
MAIN_DEPENDENCY ${fullname}
|
||||
DEPENDS matc
|
||||
COMMENT "Compiling material ${mat_src} to ${output_path}"
|
||||
)
|
||||
list(APPEND MATERIAL_BINS ${output_path})
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
# Additional dependencies on included files for materials
|
||||
|
||||
add_custom_command(
|
||||
|
||||
@@ -356,6 +356,13 @@ enum class SamplerFormat : uint8_t {
|
||||
SHADOW = 3 //!< shadow sampler (PCF)
|
||||
};
|
||||
|
||||
//! Texture color space
|
||||
enum class SamplerTransferFunction : uint8_t {
|
||||
UNDEFINED = 0, //!< don't care
|
||||
IDENTITY = 1, //!< sampled as-is
|
||||
SRGB_TO_LINEAR = 2, //!< sampled as sRGB and converted to linear
|
||||
};
|
||||
|
||||
/**
|
||||
* Supported element types
|
||||
*/
|
||||
|
||||
@@ -172,7 +172,7 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform, const Platform::DriverConfi
|
||||
mShaderCompilerService(*this),
|
||||
mHandleAllocator("Handles", driverConfig.handleArenaSize),
|
||||
mSamplerMap(32) {
|
||||
|
||||
|
||||
std::fill(mSamplerBindings.begin(), mSamplerBindings.end(), nullptr);
|
||||
|
||||
// set a reasonable default value for our stream array
|
||||
@@ -268,9 +268,9 @@ void OpenGLDriver::useProgram(OpenGLProgram* p) noexcept {
|
||||
|
||||
if (UTILS_UNLIKELY(mContext.isES2())) {
|
||||
for (uint32_t i = 0; i < Program::UNIFORM_BINDING_COUNT; i++) {
|
||||
auto [id, buffer, age] = mUniformBindings[i];
|
||||
auto [buffer, age] = mUniformBindings[i];
|
||||
if (buffer) {
|
||||
p->updateUniforms(i, id, buffer, age);
|
||||
p->updateUniforms(i, buffer, age);
|
||||
}
|
||||
}
|
||||
// Set the output colorspace for this program (linear or rec709). This in only relevant
|
||||
@@ -479,7 +479,6 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
|
||||
|
||||
GLBufferObject* bo = construct<GLBufferObject>(boh, byteCount, bindingType, usage);
|
||||
if (UTILS_UNLIKELY(bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
bo->gl.id = ++mLastAssignedEmulatedUboId;
|
||||
bo->gl.buffer = malloc(byteCount);
|
||||
memset(bo->gl.buffer, 0, byteCount);
|
||||
} else {
|
||||
@@ -596,9 +595,8 @@ void OpenGLDriver::textureStorage(OpenGLDriver::GLTexture* t,
|
||||
}
|
||||
} else {
|
||||
glTexImage2D(t->gl.target, level, GLint(t->gl.internalFormat),
|
||||
std::max(GLsizei(1), GLsizei(width >> level)),
|
||||
std::max(GLsizei(1), GLsizei(height >> level)),
|
||||
0, format, type, nullptr);
|
||||
GLsizei(width), GLsizei(height), 0,
|
||||
format, type, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2903,11 +2901,7 @@ void OpenGLDriver::bindBufferRange(BufferObjectBinding bindingType, uint32_t ind
|
||||
assert_invariant(offset + size <= ub->byteCount);
|
||||
|
||||
if (UTILS_UNLIKELY(ub->bindingType == BufferObjectBinding::UNIFORM && gl.isES2())) {
|
||||
mUniformBindings[index] = {
|
||||
ub->gl.id,
|
||||
static_cast<uint8_t const*>(ub->gl.buffer) + offset,
|
||||
ub->age,
|
||||
};
|
||||
mUniformBindings[index] = { static_cast<uint8_t const*>(ub->gl.buffer) + offset, ub->age };
|
||||
} else {
|
||||
GLenum const target = GLUtils::getBufferBindingType(bindingType);
|
||||
|
||||
|
||||
@@ -83,9 +83,11 @@ public:
|
||||
}
|
||||
|
||||
struct {
|
||||
GLuint id;
|
||||
union {
|
||||
GLenum binding;
|
||||
struct {
|
||||
GLuint id;
|
||||
GLenum binding;
|
||||
};
|
||||
void* buffer;
|
||||
};
|
||||
} gl;
|
||||
@@ -361,8 +363,7 @@ private:
|
||||
void setScissor(Viewport const& scissor) noexcept;
|
||||
|
||||
// ES2 only. Uniform buffer emulation binding points
|
||||
GLuint mLastAssignedEmulatedUboId = 0;
|
||||
std::array<std::tuple<GLuint, void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
||||
std::array<std::pair<void const*, uint16_t>, Program::UNIFORM_BINDING_COUNT> mUniformBindings = {};
|
||||
|
||||
// sampler buffer binding points (nullptr if not used)
|
||||
std::array<GLSamplerGroup*, Program::SAMPLER_BINDING_COUNT> mSamplerBindings = {}; // 4 pointers
|
||||
|
||||
@@ -229,16 +229,15 @@ void OpenGLProgram::updateSamplers(OpenGLDriver* const gld) const noexcept {
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLProgram::updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept {
|
||||
void OpenGLProgram::updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept {
|
||||
assert_invariant(mUniformsRecords);
|
||||
assert_invariant(buffer);
|
||||
|
||||
// only update the uniforms if the UBO has changed since last time we updated
|
||||
UniformsRecord const& records = mUniformsRecords[index];
|
||||
if (records.id == id && records.age == age) {
|
||||
if (records.age == age) {
|
||||
return;
|
||||
}
|
||||
records.id = id;
|
||||
records.age = age;
|
||||
|
||||
assert_invariant(records.uniforms.size() == records.locations.size());
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
} gl; // 12 bytes
|
||||
|
||||
// For ES2 only
|
||||
void updateUniforms(uint32_t index, GLuint id, void const* buffer, uint16_t age) noexcept;
|
||||
void updateUniforms(uint32_t index, void const* buffer, uint16_t age) noexcept;
|
||||
void setRec709ColorSpace(bool rec709) const noexcept;
|
||||
|
||||
private:
|
||||
@@ -98,7 +98,6 @@ private:
|
||||
struct UniformsRecord {
|
||||
Program::UniformInfo uniforms;
|
||||
LocationInfo locations;
|
||||
mutable GLuint id = 0;
|
||||
mutable uint16_t age = std::numeric_limits<uint16_t>::max();
|
||||
};
|
||||
UniformsRecord const* mUniformsRecords = nullptr;
|
||||
|
||||
@@ -268,18 +268,13 @@ bool VulkanCommands::flush() {
|
||||
VK_NULL_HANDLE,
|
||||
VK_NULL_HANDLE,
|
||||
};
|
||||
uint32_t waitSemaphoreCount = 0;
|
||||
if (mSubmissionSignal) {
|
||||
signals[waitSemaphoreCount++] = mSubmissionSignal;
|
||||
}
|
||||
if (mInjectedSignal) {
|
||||
signals[waitSemaphoreCount++] = mInjectedSignal;
|
||||
}
|
||||
|
||||
VkCommandBuffer const cmdbuffer = currentbuf->buffer();
|
||||
|
||||
VkSubmitInfo submitInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.waitSemaphoreCount = waitSemaphoreCount,
|
||||
.pWaitSemaphores = waitSemaphoreCount > 0 ? signals : nullptr,
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitSemaphores = signals,
|
||||
.pWaitDstStageMask = waitDestStageMasks,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmdbuffer,
|
||||
@@ -287,6 +282,19 @@ bool VulkanCommands::flush() {
|
||||
.pSignalSemaphores = &renderingFinished,
|
||||
};
|
||||
|
||||
if (mSubmissionSignal) {
|
||||
signals[submitInfo.waitSemaphoreCount++] = mSubmissionSignal;
|
||||
}
|
||||
|
||||
if (mInjectedSignal) {
|
||||
signals[submitInfo.waitSemaphoreCount++] = mInjectedSignal;
|
||||
}
|
||||
|
||||
// To address a validation warning.
|
||||
if (submitInfo.waitSemaphoreCount == 0) {
|
||||
submitInfo.pWaitSemaphores = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
#if FVK_ENABLED(FVK_DEBUG_COMMAND_BUFFER)
|
||||
slog.i << "Submitting cmdbuffer=" << cmdbuffer
|
||||
<< " wait=(" << signals[0] << ", " << signals[1] << ") "
|
||||
|
||||
@@ -99,16 +99,11 @@ void VulkanSwapChain::present() {
|
||||
mColors[mCurrentSwapIndex]->transitionLayout(cmdbuf, subresources, VulkanLayout::PRESENT);
|
||||
}
|
||||
mCommands->flush();
|
||||
|
||||
// We only present if it is not headless. No-op for headless (but note that we still need the
|
||||
// flush() in the above line).
|
||||
if (!mHeadless) {
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR ||
|
||||
result == VK_ERROR_OUT_OF_DATE_KHR,
|
||||
"Cannot present in swapchain.");
|
||||
}
|
||||
VkSemaphore const finishedDrawing = mCommands->acquireFinishedSignal();
|
||||
VkResult const result = mPlatform->present(swapChain, mCurrentSwapIndex, finishedDrawing);
|
||||
ASSERT_POSTCONDITION(result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR
|
||||
|| result == VK_ERROR_OUT_OF_DATE_KHR,
|
||||
"Cannot present in swapchain.");
|
||||
|
||||
// We presented the last acquired buffer.
|
||||
mAcquired = false;
|
||||
|
||||
@@ -426,6 +426,7 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
uint8_t fieldFormat = 0;
|
||||
uint8_t fieldPrecision = 0;
|
||||
bool fieldMultisample = false;
|
||||
uint8_t fieldTransferFunction = 0;
|
||||
|
||||
if (!unflattener.read(&fieldName)) {
|
||||
return false;
|
||||
@@ -447,10 +448,15 @@ bool ChunkSamplerInterfaceBlock::unflatten(Unflattener& unflattener,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unflattener.read(&fieldTransferFunction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
builder.add({ fieldName.data(), fieldName.size() }, SamplerInterfaceBlock::Type(fieldType),
|
||||
SamplerInterfaceBlock::Format(fieldFormat),
|
||||
SamplerInterfaceBlock::Precision(fieldPrecision),
|
||||
fieldMultisample);
|
||||
fieldMultisample,
|
||||
SamplerInterfaceBlock::SamplerTransferFunction(fieldTransferFunction));
|
||||
}
|
||||
|
||||
*sib = builder.build();
|
||||
|
||||
@@ -2714,8 +2714,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::upscale(FrameGraph& fg, bool
|
||||
filament::Viewport const& vp, FrameGraphTexture::Descriptor const& outDesc,
|
||||
backend::SamplerMagFilter filter) noexcept {
|
||||
|
||||
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW &&
|
||||
mEngine.getDriverApi().getFeatureLevel() >= FeatureLevel::FEATURE_LEVEL_1)) {
|
||||
if (UTILS_LIKELY(!translucent && dsrOptions.quality == QualityLevel::LOW)) {
|
||||
return opaqueBlit(fg, input, vp, outDesc, filter);
|
||||
}
|
||||
|
||||
|
||||
@@ -108,13 +108,11 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
ShadowMapInfo const& shadowMapInfo,
|
||||
SceneInfo const& sceneInfo) noexcept {
|
||||
|
||||
// reset the visible shadow status
|
||||
mHasVisibleShadows = false;
|
||||
|
||||
FLightManager const& lcm = engine.getLightManager();
|
||||
FLightManager::Instance const li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
|
||||
// We can't use LISPSM in stable mode
|
||||
const auto direction = lightData.elementAt<FScene::SHADOW_DIRECTION>(index);
|
||||
|
||||
auto [Mv, znear, zfar, lsClippedShadowVolume, vertexCount, visibleShadows] =
|
||||
@@ -139,7 +137,6 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
*/
|
||||
|
||||
mat4f W, Wp, L;
|
||||
// We can't use LISPSM in stable mode
|
||||
const bool useLispsm = params.options.lispsm && !params.options.stable;
|
||||
if (useLispsm) {
|
||||
// Orient the shadow map in the direction of the view vector by constructing a
|
||||
|
||||
@@ -522,7 +522,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// entire camera frustum, as if we only had a single cascade.
|
||||
ShadowMap& shadowMap = cascadedShadowMaps[0];
|
||||
|
||||
const auto direction = lightData.elementAt<FScene::SHADOW_DIRECTION>(0);
|
||||
const auto direction = options.transform * lightData.elementAt<FScene::DIRECTION>(0);
|
||||
|
||||
// We compute the directional light's model matrix using the origin's as the light position.
|
||||
// The choice of the light's origin initially doesn't matter for a directional light.
|
||||
|
||||
@@ -244,10 +244,6 @@ void FEngine::init() {
|
||||
|
||||
mActiveFeatureLevel = std::min(mActiveFeatureLevel, driverApi.getFeatureLevel());
|
||||
|
||||
#ifndef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
assert_invariant(mActiveFeatureLevel > FeatureLevel::FEATURE_LEVEL_0);
|
||||
#endif
|
||||
|
||||
slog.i << "Backend feature level: " << int(driverApi.getFeatureLevel()) << io::endl;
|
||||
slog.i << "FEngine feature level: " << int(mActiveFeatureLevel) << io::endl;
|
||||
|
||||
@@ -332,15 +328,12 @@ void FEngine::init() {
|
||||
driverApi.update3DImage(mDummyZeroTexture, 0, 0, 0, 0, 1, 1, 1,
|
||||
{ zeroes, 4, Texture::Format::RGBA, Texture::Type::UBYTE });
|
||||
|
||||
#ifdef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
if (UTILS_UNLIKELY(mActiveFeatureLevel == FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
defaultMaterialBuilder.package(
|
||||
MATERIALS_DEFAULTMATERIAL0_DATA, MATERIALS_DEFAULTMATERIAL0_SIZE);
|
||||
mDefaultMaterial = downcast(defaultMaterialBuilder.build(*const_cast<FEngine*>(this)));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
mDefaultColorGrading = downcast(ColorGrading::Builder().build(*this));
|
||||
|
||||
FMaterial::DefaultMaterialBuilder defaultMaterialBuilder;
|
||||
|
||||
@@ -267,16 +267,16 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
// in the code below, we only transform directions, so the translation of the
|
||||
// world transform is irrelevant, and we don't need to use getWorldTransformAccurate()
|
||||
|
||||
mat3 const worldDirectionTransform =
|
||||
mat3::getTransformForNormals(tcm.getWorldTransformAccurate(ti).upperLeft());
|
||||
FLightManager::ShadowParams const params = lcm.getShadowParams(li);
|
||||
float3 const localDirection = worldDirectionTransform * lcm.getLocalDirection(li);
|
||||
double3 const shadowLocalDirection = params.options.transform * localDirection;
|
||||
float3 const localDirection = lcm.getLocalDirection(li);
|
||||
float3 const shadowLocalDirection = params.options.transform * localDirection;
|
||||
mat3 const worldDirectionTransform = tcm.getWorldTransformAccurate(ti).upperLeft();
|
||||
mat3 const shaderWorldTransform = worldTransform.upperLeft() * worldDirectionTransform;
|
||||
|
||||
// using mat3::getTransformForNormals handles non-uniform scaling
|
||||
// note: in the common case of the rigid-body transform, getTransformForNormals() returns
|
||||
// identity.
|
||||
mat3 const worlTransformNormals = mat3::getTransformForNormals(worldTransform.upperLeft());
|
||||
mat3 const worlTransformNormals = mat3::getTransformForNormals(shaderWorldTransform);
|
||||
double3 const d = worlTransformNormals * localDirection;
|
||||
double3 const s = worlTransformNormals * shadowLocalDirection;
|
||||
|
||||
@@ -290,8 +290,10 @@ void FScene::prepare(utils::JobSystem& js,
|
||||
// is pointing down, which is a common case for lights. See ShadowMap.cpp.
|
||||
return transpose(mat3::lookTo(direction, double3{ 1, 0, 0 }));
|
||||
};
|
||||
double3 const worldDirection =
|
||||
mat3::getTransformForNormals(worldDirectionTransform) * shadowLocalDirection;
|
||||
double3 const worldOrigin = transpose(worldTransform.upperLeft()) * worldTransform[3].xyz;
|
||||
mat3 const Mv = getMv(shadowLocalDirection);
|
||||
mat3 const Mv = getMv(worldDirection);
|
||||
double2 const lsReferencePoint = (Mv * worldOrigin).xy;
|
||||
|
||||
constexpr float inf = std::numeric_limits<float>::infinity();
|
||||
|
||||
@@ -118,12 +118,9 @@ FSkybox::FSkybox(FEngine& engine, const Builder& builder) noexcept
|
||||
|
||||
FMaterial const* FSkybox::createMaterial(FEngine& engine) {
|
||||
Material::Builder builder;
|
||||
#ifdef FILAMENT_ENABLE_FEATURE_LEVEL_0
|
||||
if (UTILS_UNLIKELY(engine.getActiveFeatureLevel() == Engine::FeatureLevel::FEATURE_LEVEL_0)) {
|
||||
builder.package(MATERIALS_SKYBOX0_DATA, MATERIALS_SKYBOX0_SIZE);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
builder.package(MATERIALS_SKYBOX_DATA, MATERIALS_SKYBOX_SIZE);
|
||||
}
|
||||
auto material = builder.build(engine);
|
||||
|
||||
@@ -82,22 +82,22 @@ uint32_t RenderPassNode::declareRenderTarget(FrameGraph& fg, FrameGraph::Builder
|
||||
RenderPassData data;
|
||||
data.name = name;
|
||||
data.descriptor = descriptor;
|
||||
FrameGraphRenderPass::Attachments const& attachments = data.descriptor.attachments;
|
||||
|
||||
// retrieve the ResourceNode of the attachments coming to us -- this will be used later
|
||||
// to compute the discard flags.
|
||||
|
||||
DependencyGraph const& dependencyGraph = fg.getGraph();
|
||||
auto incomingEdges = dependencyGraph.getIncomingEdges(this);
|
||||
auto outgoingEdges = dependencyGraph.getOutgoingEdges(this);
|
||||
|
||||
for (size_t i = 0; i < RenderPassData::ATTACHMENT_COUNT; i++) {
|
||||
FrameGraphId<FrameGraphTexture> const& handle =
|
||||
data.descriptor.attachments.array[i];
|
||||
if (handle) {
|
||||
data.attachmentInfo[i] = handle;
|
||||
if (descriptor.attachments.array[i]) {
|
||||
data.attachmentInfo[i] = attachments.array[i];
|
||||
|
||||
// TODO: this is not very efficient
|
||||
auto incomingPos = std::find_if(incomingEdges.begin(), incomingEdges.end(),
|
||||
[&dependencyGraph, handle]
|
||||
[&dependencyGraph, handle = descriptor.attachments.array[i]]
|
||||
(DependencyGraph::Edge const* edge) {
|
||||
ResourceNode const* node = static_cast<ResourceNode const*>(
|
||||
dependencyGraph.getNode(edge->from));
|
||||
@@ -111,7 +111,7 @@ uint32_t RenderPassNode::declareRenderTarget(FrameGraph& fg, FrameGraph::Builder
|
||||
}
|
||||
|
||||
// this could be either outgoing or incoming (if there are no outgoing)
|
||||
data.outgoing[i] = fg.getActiveResourceNode(handle);
|
||||
data.outgoing[i] = fg.getActiveResourceNode(descriptor.attachments.array[i]);
|
||||
if (data.outgoing[i] == data.incoming[i]) {
|
||||
data.outgoing[i] = nullptr;
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
material {
|
||||
name : blitLow,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : color,
|
||||
precision: medium
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : resolution,
|
||||
precision: high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : viewport,
|
||||
precision: high
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
vertex
|
||||
],
|
||||
depthWrite : false,
|
||||
depthCulling : false,
|
||||
domain: postprocess,
|
||||
}
|
||||
|
||||
vertex {
|
||||
void postProcessVertex(inout PostProcessVertexInputs postProcess) {
|
||||
postProcess.vertex.xy = materialParams.viewport.xy + postProcess.normalizedUV * materialParams.viewport.zw;
|
||||
postProcess.vertex.xy = uvToRenderTargetUV(postProcess.vertex.xy);
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void postProcess(inout PostProcessInputs postProcess) {
|
||||
postProcess.color = textureLod(materialParams_color, variable_vertex.xy, 0.0);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.46.0"
|
||||
spec.version = "1.45.0"
|
||||
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.46.0/filament-v1.46.0-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.45.0/filament-v1.45.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 46;
|
||||
static constexpr size_t MATERIAL_VERSION = 45;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
using Format = backend::SamplerFormat;
|
||||
using Precision = backend::Precision;
|
||||
using SamplerParams = backend::SamplerParams;
|
||||
using SamplerTransferFunction = backend::SamplerTransferFunction;
|
||||
|
||||
struct SamplerInfo { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
utils::CString name; // name of this sampler
|
||||
@@ -55,6 +56,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
class Builder {
|
||||
@@ -73,6 +75,7 @@ public:
|
||||
Format format; // format of this sampler
|
||||
Precision precision; // precision of this sampler
|
||||
bool multisample = false; // multisample capable
|
||||
SamplerTransferFunction transferFunction;
|
||||
};
|
||||
|
||||
// Give a name to this sampler interface block
|
||||
@@ -83,7 +86,8 @@ public:
|
||||
// Add a sampler
|
||||
Builder& add(std::string_view samplerName, Type type, Format format,
|
||||
Precision precision = Precision::MEDIUM,
|
||||
bool multisample = false) noexcept;
|
||||
bool multisample = false,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
// Add multiple samplers
|
||||
Builder& add(std::initializer_list<ListEntry> list) noexcept;
|
||||
|
||||
@@ -44,10 +44,10 @@ SamplerInterfaceBlock::Builder::stageFlags(backend::ShaderStageFlags stageFlags)
|
||||
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::string_view samplerName, Type type, Format format,
|
||||
Precision precision, bool multisample) noexcept {
|
||||
Precision precision, bool multisample, SamplerTransferFunction transferFunction) noexcept {
|
||||
mEntries.push_back({
|
||||
{ samplerName.data(), samplerName.size() }, { },
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample });
|
||||
uint8_t(mEntries.size()), type, format, precision, multisample, transferFunction });
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ SamplerInterfaceBlock SamplerInterfaceBlock::Builder::build() {
|
||||
SamplerInterfaceBlock::Builder& SamplerInterfaceBlock::Builder::add(
|
||||
std::initializer_list<ListEntry> list) noexcept {
|
||||
for (auto& e : list) {
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample);
|
||||
add(e.name, e.type, e.format, e.precision, e.multisample, e.transferFunction);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -35,19 +35,10 @@ set(MATERIAL_SRCS
|
||||
|
||||
file(MAKE_DIRECTORY ${MATERIAL_DIR})
|
||||
|
||||
# HACK: Pick between the normal and FL0-exclusionary variants of the materials
|
||||
# based on the value of FILAMENT_ENABLE_FEATURE_LEVEL_0.
|
||||
foreach (mat_src ${MATERIAL_SRCS})
|
||||
get_filename_component(localname "${mat_src}" NAME_WE)
|
||||
get_filename_component(fullname "${mat_src}" ABSOLUTE)
|
||||
set(output_path "${MATERIAL_DIR}/${localname}.filamat")
|
||||
|
||||
if (NOT FILAMENT_ENABLE_FATURE_LEVEL_0)
|
||||
# Pick the non-FL0 variant instead.
|
||||
string(REGEX REPLACE "\\.mat$" "1.mat" fullname "${fullname}")
|
||||
string(REGEX REPLACE "\\.mat$" "1.mat" mat_src "${mat_src}")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output_path}
|
||||
COMMAND matc ${MATC_BASE_FLAGS} -o ${output_path} ${fullname}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
material {
|
||||
name : uiBlit,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : albedo
|
||||
}
|
||||
],
|
||||
requires : [
|
||||
uv0,
|
||||
color
|
||||
],
|
||||
shadingModel : unlit,
|
||||
culling : none,
|
||||
depthCulling: false,
|
||||
blending : transparent,
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
vec2 uv = getUV0();
|
||||
uv.y = 1.0 - uv.y;
|
||||
vec4 albedo = texture(materialParams_albedo, uv);
|
||||
material.baseColor = getColor() * albedo;
|
||||
material.baseColor.rgb *= material.baseColor.a;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ using SamplerType = MaterialBuilder::SamplerType;
|
||||
using SubpassType = MaterialBuilder::SubpassType;
|
||||
using SamplerFormat = MaterialBuilder::SamplerFormat;
|
||||
using ParameterPrecision = MaterialBuilder::ParameterPrecision;
|
||||
using SamplerTransferFunction = MaterialBuilder::SamplerTransferFunction;
|
||||
using OutputTarget = MaterialBuilder::OutputTarget;
|
||||
using OutputQualifier = MaterialBuilder::VariableQualifier;
|
||||
using OutputType = MaterialBuilder::OutputType;
|
||||
@@ -75,6 +76,7 @@ private:
|
||||
static std::unordered_map<std::string, SubpassType> mStringToSubpassType;
|
||||
static std::unordered_map<std::string, SamplerFormat> mStringToSamplerFormat;
|
||||
static std::unordered_map<std::string, ParameterPrecision> mStringToSamplerPrecision;
|
||||
static std::unordered_map<std::string, SamplerTransferFunction> mStringToSamplerTransferFunction;
|
||||
static std::unordered_map<std::string, OutputTarget> mStringToOutputTarget;
|
||||
static std::unordered_map<std::string, OutputQualifier> mStringToOutputQualifier;
|
||||
static std::unordered_map<std::string, OutputType> mStringToOutputType;
|
||||
|
||||
@@ -239,6 +239,7 @@ public:
|
||||
using SubpassType = filament::backend::SubpassType;
|
||||
using SamplerFormat = filament::backend::SamplerFormat;
|
||||
using ParameterPrecision = filament::backend::Precision;
|
||||
using SamplerTransferFunction = filament::backend::SamplerTransferFunction;
|
||||
using Precision = filament::backend::Precision;
|
||||
using CullingMode = filament::backend::CullingMode;
|
||||
using FeatureLevel = filament::backend::FeatureLevel;
|
||||
@@ -307,11 +308,8 @@ public:
|
||||
*/
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format = SamplerFormat::FLOAT,
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT) noexcept;
|
||||
|
||||
/// @copydoc parameter(SamplerType, SamplerFormat, ParameterPrecision, const char*)
|
||||
MaterialBuilder& parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept;
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT,
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED) noexcept;
|
||||
|
||||
|
||||
MaterialBuilder& buffer(filament::BufferInterfaceBlock bib) noexcept;
|
||||
@@ -618,16 +616,20 @@ public:
|
||||
Parameter() noexcept: parameterType(INVALID) {}
|
||||
|
||||
// Sampler
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f), parameterType(SAMPLER) { }
|
||||
Parameter(const char* paramName, SamplerType t, SamplerFormat f, ParameterPrecision p,
|
||||
SamplerTransferFunction tf)
|
||||
: name(paramName), size(1), precision(p), samplerType(t), format(f),
|
||||
parameterType(SAMPLER), transferFunction(tf) { }
|
||||
|
||||
// Uniform
|
||||
Parameter(const char* paramName, UniformType t, size_t typeSize, ParameterPrecision p)
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p), parameterType(UNIFORM) { }
|
||||
: name(paramName), size(typeSize), uniformType(t), precision(p),
|
||||
parameterType(UNIFORM) { }
|
||||
|
||||
// Subpass
|
||||
Parameter(const char* paramName, SubpassType t, SamplerFormat f, ParameterPrecision p)
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f), parameterType(SUBPASS) { }
|
||||
: name(paramName), size(1), precision(p), subpassType(t), format(f),
|
||||
parameterType(SUBPASS) { }
|
||||
|
||||
utils::CString name;
|
||||
size_t size;
|
||||
@@ -636,6 +638,7 @@ public:
|
||||
SamplerType samplerType;
|
||||
SubpassType subpassType;
|
||||
SamplerFormat format;
|
||||
SamplerTransferFunction transferFunction;
|
||||
enum {
|
||||
INVALID,
|
||||
UNIFORM,
|
||||
|
||||
@@ -117,6 +117,17 @@ std::unordered_map<std::string, ParameterPrecision>& Enums::getMap<ParameterPrec
|
||||
return mStringToSamplerPrecision;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, SamplerTransferFunction> Enums::mStringToSamplerTransferFunction = {
|
||||
{ "undefined", SamplerTransferFunction::UNDEFINED },
|
||||
{ "identity", SamplerTransferFunction::IDENTITY },
|
||||
{ "srgbToLinear", SamplerTransferFunction::SRGB_TO_LINEAR },
|
||||
};
|
||||
|
||||
template <>
|
||||
std::unordered_map<std::string, SamplerTransferFunction>& Enums::getMap<SamplerTransferFunction>() noexcept {
|
||||
return mStringToSamplerTransferFunction;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, OutputTarget> Enums::mStringToOutputTarget = {
|
||||
{ "color", OutputTarget::COLOR },
|
||||
{ "depth", OutputTarget::DEPTH }
|
||||
|
||||
@@ -248,19 +248,14 @@ MaterialBuilder& MaterialBuilder::parameter(const char* name, UniformType type,
|
||||
return parameter(name, 1, type, precision);
|
||||
}
|
||||
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
SamplerFormat format, ParameterPrecision precision) noexcept {
|
||||
SamplerFormat format, ParameterPrecision precision,
|
||||
SamplerTransferFunction transferFunction) noexcept {
|
||||
ASSERT_POSTCONDITION(mParameterCount < MAX_PARAMETERS_COUNT, "Too many parameters");
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision };
|
||||
mParameters[mParameterCount++] = { name, samplerType, format, precision, transferFunction };
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaterialBuilder& MaterialBuilder::parameter(const char* name, SamplerType samplerType,
|
||||
ParameterPrecision precision) noexcept {
|
||||
return parameter(name, samplerType, SamplerFormat::FLOAT, precision);
|
||||
}
|
||||
|
||||
template<typename T, typename>
|
||||
MaterialBuilder& MaterialBuilder::constant(const char* name, ConstantType type, T defaultValue) {
|
||||
auto result = std::find_if(mConstants.begin(), mConstants.end(), [name](const Constant& c) {
|
||||
@@ -556,7 +551,8 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
assert_invariant(!param.isSubpass());
|
||||
if (param.isSampler()) {
|
||||
sbb.add({ param.name.data(), param.name.size() },
|
||||
param.samplerType, param.format, param.precision);
|
||||
param.samplerType, param.format, param.precision, /*multisample=*/false,
|
||||
param.transferFunction);
|
||||
} else if (param.isUniform()) {
|
||||
ibb.add({{{ param.name.data(), param.name.size() },
|
||||
uint32_t(param.size == 1u ? 0u : param.size), param.uniformType,
|
||||
|
||||
@@ -65,6 +65,7 @@ void MaterialSamplerInterfaceBlockChunk::flatten(Flattener& f) {
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.format));
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.precision));
|
||||
f.writeBool(sInfo.multisample);
|
||||
f.writeUint8(static_cast<uint8_t>(sInfo.transferFunction));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,11 +176,6 @@ if (WEBGL_PTHREADS)
|
||||
target_compile_definitions(gltfio_core PUBLIC -DFILAMENT_WASM_THREADS)
|
||||
endif()
|
||||
|
||||
set(GLTFIO_WARNINGS -Wall -Werror)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(gltfio_core PRIVATE ${GLTFIO_WARNINGS})
|
||||
endif()
|
||||
|
||||
if (NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
|
||||
# ==================================================================================================
|
||||
@@ -190,6 +185,10 @@ if (NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
target_link_libraries(${TARGET} PUBLIC filamat gltfio_core)
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
set_target_properties(${TARGET} PROPERTIES FOLDER Libs)
|
||||
|
||||
# ==================================================================================================
|
||||
# Compiler flags
|
||||
# ==================================================================================================
|
||||
if (NOT MSVC)
|
||||
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
@@ -230,7 +229,7 @@ if (TNT_DEV AND NOT WEBGL AND NOT ANDROID AND NOT IOS)
|
||||
|
||||
target_link_libraries(${TEST_TARGET} PRIVATE ${TARGET} gtest uberarchive)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(${TEST_TARGET} PRIVATE ${GLTFIO_WARNINGS})
|
||||
target_compile_options(${TEST_TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
set_target_properties(${TEST_TARGET} PROPERTIES FOLDER Tests)
|
||||
endif()
|
||||
|
||||
@@ -69,12 +69,9 @@ class UTILS_PUBLIC ResourceLoader {
|
||||
public:
|
||||
using BufferDescriptor = filament::backend::BufferDescriptor;
|
||||
|
||||
explicit ResourceLoader(const ResourceConfiguration& config);
|
||||
ResourceLoader(const ResourceConfiguration& config);
|
||||
~ResourceLoader();
|
||||
|
||||
|
||||
void setConfiguration(const ResourceConfiguration& config);
|
||||
|
||||
/**
|
||||
* Feeds the binary content of an external resource into the loader's URI cache.
|
||||
*
|
||||
@@ -157,6 +154,7 @@ public:
|
||||
private:
|
||||
bool loadResources(FFilamentAsset* asset, bool async);
|
||||
void normalizeSkinningWeights(FFilamentAsset* asset) const;
|
||||
AssetPool* mPool;
|
||||
struct Impl;
|
||||
Impl* pImpl;
|
||||
};
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/EntityManager.h>
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
#include <utils/Log.h>
|
||||
@@ -769,6 +768,7 @@ void FAssetLoader::createRenderable(const cgltf_node* node, Entity entity, const
|
||||
|
||||
void FAssetLoader::createMaterialVariants(const cgltf_mesh* mesh, Entity entity,
|
||||
FFilamentAsset* fAsset, FFilamentInstance* instance) {
|
||||
const cgltf_data* srcAsset = fAsset->mSourceAsset->hierarchy;
|
||||
UvMap uvmap {};
|
||||
for (cgltf_size prim = 0, n = mesh->primitives_count; prim < n; ++prim) {
|
||||
const cgltf_primitive& srcPrim = mesh->primitives[prim];
|
||||
@@ -1076,7 +1076,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, const char* na
|
||||
.build(mEngine);
|
||||
outPrim->targets = targets;
|
||||
fAsset->mMorphTargetBuffers.push_back(targets);
|
||||
UTILS_UNUSED_IN_RELEASE cgltf_accessor const* previous = nullptr;
|
||||
const cgltf_accessor* previous = nullptr;
|
||||
for (int tindex = 0; tindex < targetsCount; ++tindex) {
|
||||
const cgltf_morph_target& inTarget = inPrim.targets[tindex];
|
||||
for (cgltf_size aindex = 0; aindex < inTarget.attributes_count; ++aindex) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <draco/compression/decode.h>
|
||||
#endif
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#if GLTFIO_DRACO_SUPPORTED
|
||||
@@ -66,7 +65,7 @@ DracoMesh::~DracoMesh() {
|
||||
}
|
||||
|
||||
// Gets the number of components in the given cgltf vector type, or -1 for matrices.
|
||||
UTILS_UNUSED_IN_RELEASE static int getNumComponents(cgltf_type ctype) {
|
||||
static int getNumComponents(cgltf_type ctype) {
|
||||
return ((int) ctype) <= 4 ? ((int) ctype) : -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace utils {
|
||||
|
||||
namespace filament::gltfio {
|
||||
|
||||
struct Wireframe;
|
||||
class Wireframe;
|
||||
|
||||
// Encapsulates VertexBuffer::setBufferAt() or IndexBuffer::setBuffer().
|
||||
struct BufferSlot {
|
||||
|
||||
@@ -116,7 +116,7 @@ Texture* Ktx2Provider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
}
|
||||
|
||||
JobSystem* js = &mEngine->getJobSystem();
|
||||
item->job = jobs::createJob(*js, mDecoderRootJob, [item] {
|
||||
item->job = jobs::createJob(*js, mDecoderRootJob, [this, item] {
|
||||
using Result = ktxreader::Ktx2Reader::Result;
|
||||
const bool success = Result::SUCCESS == item->async->doTranscoding();
|
||||
item->transcoderState.store(success ? TranscoderState::SUCCESS : TranscoderState::ERROR);
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <geometry/Transcoder.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/JobSystem.h>
|
||||
#include <utils/Log.h>
|
||||
#include <utils/Systrace.h>
|
||||
@@ -75,15 +74,15 @@ enum class CacheResult {
|
||||
};
|
||||
|
||||
struct ResourceLoader::Impl {
|
||||
explicit Impl(const ResourceConfiguration& config) :
|
||||
Impl(const ResourceConfiguration& config) :
|
||||
mEngine(config.engine),
|
||||
mNormalizeSkinningWeights(config.normalizeSkinningWeights),
|
||||
mGltfPath(config.gltfPath ? config.gltfPath : ""),
|
||||
mUriDataCache(std::make_shared<UriDataCache>()) {}
|
||||
|
||||
Engine* const mEngine;
|
||||
bool mNormalizeSkinningWeights;
|
||||
std::string mGltfPath;
|
||||
const bool mNormalizeSkinningWeights;
|
||||
const std::string mGltfPath;
|
||||
|
||||
// User-provided resource data with URI string keys, populated with addResourceData().
|
||||
// This is used on platforms without traditional file systems, such as Android, iOS, and WebGL.
|
||||
@@ -244,7 +243,7 @@ static void decodeMeshoptCompression(cgltf_data* data) {
|
||||
void* destination = malloc(compression->count * compression->stride);
|
||||
assert_invariant(destination);
|
||||
|
||||
UTILS_UNUSED_IN_RELEASE int error = 0;
|
||||
int error = 0;
|
||||
switch (compression->mode) {
|
||||
case cgltf_meshopt_compression_mode_invalid:
|
||||
break;
|
||||
@@ -321,11 +320,6 @@ ResourceLoader::~ResourceLoader() {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
void ResourceLoader::setConfiguration(const ResourceConfiguration& config) {
|
||||
pImpl->mNormalizeSkinningWeights = config.normalizeSkinningWeights;
|
||||
pImpl->mGltfPath = config.gltfPath;
|
||||
}
|
||||
|
||||
void ResourceLoader::addResourceData(const char* uri, BufferDescriptor&& buffer) {
|
||||
pImpl->addResourceData(uri, std::move(buffer));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ Texture* StbProvider::pushTexture(const uint8_t* data, size_t byteCount,
|
||||
}
|
||||
|
||||
JobSystem* js = &mEngine->getJobSystem();
|
||||
info->decoderJob = jobs::createJob(*js, mDecoderRootJob, [info] {
|
||||
info->decoderJob = jobs::createJob(*js, mDecoderRootJob, [this, info] {
|
||||
auto& source = info->sourceBuffer;
|
||||
int width, height, comp;
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ using namespace backend;
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
constexpr uint32_t WIDTH = 64;
|
||||
constexpr uint32_t HEIGHT = 64;
|
||||
|
||||
char const* ANIMATED_MORPH_CUBE_GLB = "AnimatedMorphCube.glb";
|
||||
|
||||
static std::ifstream::pos_type getFileSize(const char* filename) {
|
||||
@@ -175,6 +178,7 @@ do { \
|
||||
TEST_F(glTFIOTest, AnimatedMorphCubeTransforms) {
|
||||
FilamentAsset const& morphCubeAsset = *mData[ANIMATED_MORPH_CUBE_GLB]->getAsset();
|
||||
auto const& transformManager = mEngine->getTransformManager();
|
||||
auto const& renderableManager = mEngine->getRenderableManager();
|
||||
Entity const* renderables = morphCubeAsset.getRenderableEntities();
|
||||
|
||||
EXPECT_EQ(morphCubeAsset.getRenderableEntityCount(), 1u);
|
||||
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
// This variable is to implement a *hanging* effect for /api/status. The call to /api/status
|
||||
// will always block until statusMaterialId is updated again. The client is expected to keep
|
||||
// calling /api/status (a constant "pull" to simulate a push).
|
||||
std::atomic<uint64_t> mCurrentStatus = 0;
|
||||
std::atomic_uint64_t mCurrentStatus = 0;
|
||||
};
|
||||
|
||||
} // filament::matdbg
|
||||
|
||||
@@ -127,19 +127,3 @@ async function statusLoop(isConnected, onStatus) {
|
||||
setTimeout(() => statusLoop(isConnected, onStatus), STATUS_LOOP_TIMEOUT)
|
||||
}
|
||||
}
|
||||
|
||||
// Use browser User-agent to guess the current backend. This is mainly for matinfo which does
|
||||
// not have a running backend.
|
||||
function guessBackend() {
|
||||
const AGENTS_TO_BACKEND = [
|
||||
['Mac OS', 'metal'],
|
||||
['Windows', 'opengl'],
|
||||
['Linux', 'vulkan'],
|
||||
];
|
||||
|
||||
const result = AGENTS_TO_BACKEND.filter((agent_backend) => {
|
||||
return window.navigator.userAgent.search(agent_backend[0]);
|
||||
}).map((agent_backend) => agent_backend[1]);
|
||||
|
||||
return result.length > 0 ? result[0] : null;
|
||||
}
|
||||
|
||||
+65
-237
@@ -25,8 +25,6 @@ const LANGUAGE_CHOICES = {
|
||||
'metal': ['msl'],
|
||||
};
|
||||
|
||||
const BACKENDS = Object.keys(LANGUAGE_CHOICES);
|
||||
|
||||
const MATERIAL_INFO_KEY_TO_STRING = {
|
||||
'model': 'shading model',
|
||||
'vertex_domain': 'vertex domain',
|
||||
@@ -56,6 +54,19 @@ const BACKGROUND_COLOR = '#5362e5';
|
||||
const HOVER_BACKGROUND_COLOR = '#b3c2ff';
|
||||
const CODE_VIEWER_BOTTOM_ROW_HEIGHT = 60;
|
||||
const REGULAR_FONT_SIZE = 12;
|
||||
const MENU_HR = `
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0px;
|
||||
border-top: 1px solid ${UNSELECTED_COLOR};
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 3px 0 8px 0;
|
||||
`;
|
||||
const MENU_SECTION_TITLE = `
|
||||
font-size: 16px;
|
||||
color: ${UNSELECTED_COLOR};
|
||||
`;
|
||||
|
||||
// Set up the Monaco editor. See also CodeViewer
|
||||
const kMonacoBaseUrl = 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.25.2/min/';
|
||||
@@ -74,14 +85,6 @@ window.MonacoEnvironment = {
|
||||
}
|
||||
};
|
||||
|
||||
const _validDict = (obj) => {
|
||||
return obj && Object.keys(obj) > 0;
|
||||
}
|
||||
|
||||
const _isMatInfoMode = (database) => {
|
||||
return Object.keys(database).length == 1;
|
||||
}
|
||||
|
||||
class Button extends LitElement {
|
||||
static get styles() {
|
||||
return css`
|
||||
@@ -219,19 +222,11 @@ class CodeViewer extends LitElement {
|
||||
scrollBeyondLastLine: false,
|
||||
readOnly: false,
|
||||
minimap: { enabled: false },
|
||||
automaticLayout: true,
|
||||
|
||||
// Workaround see https://github.com/microsoft/monaco-editor/issues/3217
|
||||
fontLigatures: '',
|
||||
automaticLayout: true
|
||||
});
|
||||
const KeyMod = monaco.KeyMod, KeyCode = monaco.KeyCode;
|
||||
this.editor.onDidChangeModelContent(this._onEdit.bind(this));
|
||||
this.editor.addCommand(KeyMod.CtrlCmd | KeyCode.KEY_S, this._rebuild.bind(this));
|
||||
|
||||
// It might be that the code is available before the editor has been created.
|
||||
if (this.code && this.code.length > 0) {
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,17 +254,13 @@ class CodeViewer extends LitElement {
|
||||
|
||||
updated(props) {
|
||||
if (props.has('code') && this.code.length > 0) {
|
||||
// Note that the prop might have been updated before the editor is available.
|
||||
if (this.editor) {
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
this.editor.setValue(this.code);
|
||||
}
|
||||
if ((props.has('expectedWidth') || props.has('expectedHeight')) &&
|
||||
(this.expectedWidth > 0 && (this.expectedHeight - CODE_VIEWER_BOTTOM_ROW_HEIGHT) > 0)) {
|
||||
const actualWidth = Math.floor(this.expectedWidth);
|
||||
const actualHeight = (Math.floor(this.expectedHeight) - CODE_VIEWER_BOTTOM_ROW_HEIGHT);
|
||||
this._editorDiv.style.width = actualWidth + 'px';
|
||||
this._editorDiv.style.height = actualHeight + 'px';
|
||||
this._editorDiv.style.width = Math.floor(this.expectedWidth) + 'px';
|
||||
this._editorDiv.style.height =
|
||||
(Math.floor(this.expectedHeight) - CODE_VIEWER_BOTTOM_ROW_HEIGHT) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,12 +311,12 @@ class CodeViewer extends LitElement {
|
||||
}
|
||||
customElements.define("code-viewer", CodeViewer);
|
||||
|
||||
class MenuSection extends LitElement {
|
||||
class MaterialInfo extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
info: {type: Object, state: true},
|
||||
showing: {type: Boolean, state: true},
|
||||
title: {type: String, attribute: 'title'},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
@@ -333,23 +324,18 @@ class MenuSection extends LitElement {
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
}
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
color: ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
cursor: pointer;
|
||||
}
|
||||
.container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.section-title {
|
||||
${unsafeCSS(MENU_SECTION_TITLE)}
|
||||
cursor: pointer;
|
||||
}
|
||||
hr {
|
||||
display: block;
|
||||
height: 1px;
|
||||
border: 0px;
|
||||
border-top: 1px solid ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
margin: 3px 0 8px 0;
|
||||
${unsafeCSS(MENU_HR)}
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
}
|
||||
.expander {
|
||||
display: flex;
|
||||
@@ -360,48 +346,9 @@ class MenuSection extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
_showClick() {
|
||||
this.showing = !this.showing;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showing = true;
|
||||
}
|
||||
|
||||
render() {
|
||||
const expandedIcon = this.showing ? '-' : '+';
|
||||
const slot = (() => html`<slot></slot>`)();
|
||||
return html`
|
||||
<div class="container">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<span>${this.title}</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
${this.showing ? slot : []}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('menu-section', MenuSection);
|
||||
|
||||
class MaterialInfo extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
info: {type: Object, state: true},
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.info = null;
|
||||
}
|
||||
|
||||
@@ -409,7 +356,12 @@ class MaterialInfo extends LitElement {
|
||||
return this.info && Object.keys(this.info).length > 0;
|
||||
}
|
||||
|
||||
_showClick() {
|
||||
this.showing = !this.showing;
|
||||
}
|
||||
|
||||
render() {
|
||||
const expandedIcon = this._hasInfo() ? (this.showing ? '-' : '+') : '';
|
||||
let infoDivs = [];
|
||||
if (this._hasInfo()) {
|
||||
if (this.info.shading && this.info.shading.material_domain === 'surface') {
|
||||
@@ -435,122 +387,22 @@ class MaterialInfo extends LitElement {
|
||||
);
|
||||
}
|
||||
}
|
||||
const shouldHide = infoDivs.length == 0;
|
||||
if (infoDivs.length > 0) {
|
||||
return html`
|
||||
<menu-section title="Material Details">
|
||||
${infoDivs}
|
||||
</menu-section>
|
||||
`;
|
||||
let divClass = 'container';
|
||||
if (infoDivs.length == 0) {
|
||||
divClass += ' hide';
|
||||
}
|
||||
return html``;
|
||||
}
|
||||
}
|
||||
customElements.define('material-info', MaterialInfo);
|
||||
|
||||
class AdvancedOptions extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
currentBackend: {type: String, attribute: 'current-backend'},
|
||||
availableBackends: {type: Array, state: true},
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
:host {
|
||||
font-size: ${unsafeCSS(REGULAR_FONT_SIZE)}px;
|
||||
}
|
||||
.option {
|
||||
border: 1px solid ${unsafeCSS(UNSELECTED_COLOR)};
|
||||
border-radius: 5px;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
}
|
||||
label {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 5px;
|
||||
}
|
||||
label input {
|
||||
margin: 0 4px 0 0;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
}
|
||||
.option-heading {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
get _backendOptionForm() {
|
||||
return this.renderRoot.querySelector('#backend-option-form');
|
||||
}
|
||||
|
||||
updated(props) {
|
||||
if (props.has('currentBackend') || props.has('availableBackends')) {
|
||||
// Clear the radio button selections. The correct option will be selected
|
||||
// in _backendOption().
|
||||
if (this._backendOptionForm) {
|
||||
this._backendOptionForm.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_backendOption() {
|
||||
if (this.availableBackends.length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onChange = (ev) => {
|
||||
const backend = ev.currentTarget.getAttribute('name');
|
||||
this.dispatchEvent(
|
||||
new CustomEvent(
|
||||
'option-backend',
|
||||
{detail: backend, bubbles: true, composed: true}));
|
||||
}
|
||||
const div = this.availableBackends.map((backend) => {
|
||||
const selected = backend == this.currentBackend;
|
||||
return html`
|
||||
<label>
|
||||
<input type="radio" name="${backend}"
|
||||
?checked=${selected} @change=${onChange}/>
|
||||
${backend}
|
||||
</label>
|
||||
`;
|
||||
});
|
||||
|
||||
return html`
|
||||
<div class="option">
|
||||
<div class="option-heading">Current Backend</div>
|
||||
<form action="" id="backend-option-form">
|
||||
${div}
|
||||
</form>
|
||||
<div class="${divClass}">
|
||||
<div class="section-title expander" @click="${this._showClick}">
|
||||
<span>Material Details</span> <span>${expandedIcon}</span>
|
||||
</div>
|
||||
<hr />
|
||||
${this.showing ? infoDivs : []}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.availableBackends = [];
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<menu-section title="Advanced Options">
|
||||
${this._backendOption() ?? nothing}
|
||||
</menu-section>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('advanced-options', AdvancedOptions);
|
||||
|
||||
customElements.define('material-info', MaterialInfo);
|
||||
|
||||
class MaterialSidePanel extends LitElement {
|
||||
// Setting the style in render() has poor performance implications. We use it simply to avoid
|
||||
@@ -572,6 +424,9 @@ class MaterialSidePanel extends LitElement {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
.material-section {
|
||||
${MENU_SECTION_TITLE}
|
||||
}
|
||||
.materials {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -603,6 +458,9 @@ class MaterialSidePanel extends LitElement {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
}
|
||||
hr {
|
||||
${MENU_HR}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -626,10 +484,6 @@ class MaterialSidePanel extends LitElement {
|
||||
return this.renderRoot.querySelector('#material-info');
|
||||
}
|
||||
|
||||
get _advancedOptions() {
|
||||
return this.renderRoot.querySelector('#advanced-options');
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.connected = false;
|
||||
@@ -674,9 +528,9 @@ class MaterialSidePanel extends LitElement {
|
||||
});
|
||||
}
|
||||
if (props.has('currentMaterial')) {
|
||||
if (this.currentBackend && this.database && this.currentMaterial) {
|
||||
if (this.currentBackend && this.database && this.activeShaders && this.currentMaterial) {
|
||||
const material = this.database[this.currentMaterial];
|
||||
const activeVariants = _validDict(this.activeShaders) ? this.activeShaders[this.currentMaterial].variants : [];
|
||||
const activeVariants = this.activeShaders[this.currentMaterial].variants;
|
||||
const materialShaders = material[this.currentBackend];
|
||||
let variants = [];
|
||||
for (const [index, shader] of materialShaders.entries()) {
|
||||
@@ -692,11 +546,6 @@ class MaterialSidePanel extends LitElement {
|
||||
if (this.currentMaterial && this.database) {
|
||||
const material = this.database[this.currentMaterial];
|
||||
this._materialInfo.info = material;
|
||||
|
||||
// The matinfo usecase
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
this._advancedOptions.availableBackends = BACKENDS.filter((backend) => !!material[backend]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -801,29 +650,23 @@ class MaterialSidePanel extends LitElement {
|
||||
${shaderDiv ?? nothing}
|
||||
`;
|
||||
});
|
||||
if (mats.length > 0) {
|
||||
return html`<menu-section title="${title}">${mats}</menu-section>`;
|
||||
}
|
||||
return null;
|
||||
return html`
|
||||
<div class="materials">
|
||||
<div class="material-section">
|
||||
${title}
|
||||
</div>
|
||||
<hr />
|
||||
${mats}
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
let advancedOptions = null;
|
||||
// Currently we only have one advanced option and it's only for when we're in matinfo
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
advancedOptions =
|
||||
(() => html`
|
||||
<advanced-options id="advanced-options"
|
||||
current-backend=${this.currentBackend}></advanced-options>
|
||||
`)();
|
||||
}
|
||||
|
||||
return html`
|
||||
<style>${this.dynamicStyle()}</style>
|
||||
<div class="container">
|
||||
<div class="title">matdbg</div>
|
||||
${sections("Surface", "surface") ?? nothing}
|
||||
${sections("Post-processing", "postpro") ?? nothing}
|
||||
${sections("Surface", "surface")}
|
||||
${sections("Post-processing", "postpro")}
|
||||
<material-info id="material-info"></material-info>
|
||||
${advancedOptions ?? nothing}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -951,12 +794,6 @@ class MatdbgViewer extends LitElement {
|
||||
}
|
||||
);
|
||||
|
||||
this.addEventListener('option-backend',
|
||||
(ev) => {
|
||||
this.currentBackend = ev.detail;
|
||||
}
|
||||
);
|
||||
|
||||
addEventListener('resize', this._onResize.bind(this));
|
||||
}
|
||||
|
||||
@@ -1038,7 +875,7 @@ class MatdbgViewer extends LitElement {
|
||||
material.active = material.active || shader.active;
|
||||
}
|
||||
}
|
||||
if (_validDict(this.activeShaders)) {
|
||||
if (this.activeShaders) {
|
||||
let backends = {};
|
||||
for (let matid in this.activeShaders) {
|
||||
const backend = this.activeShaders[matid].backend;
|
||||
@@ -1052,9 +889,6 @@ class MatdbgViewer extends LitElement {
|
||||
if (backendList.length > 0) {
|
||||
this.currentBackend = backendList[0];
|
||||
}
|
||||
} else if (!this.currentBackend) {
|
||||
// Make a guess on the backend if one wasn't from activeShaders.
|
||||
this.currentBackend = guessBackend();
|
||||
}
|
||||
|
||||
this._sidepanel.database = this.database;
|
||||
@@ -1067,12 +901,6 @@ class MatdbgViewer extends LitElement {
|
||||
this.database[matInfo.matid] = matInfo;
|
||||
this.database = this.database;
|
||||
}
|
||||
|
||||
// In the `matinfo -w` usecase, we assume the current material to be the only
|
||||
// material available in the database.
|
||||
if (_isMatInfoMode(this.database)) {
|
||||
this.currentMaterial = Object.keys(this.database)[0];
|
||||
}
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
/* compound assignment products by a scalar
|
||||
*/
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
constexpr QUATERNION<T>& operator*=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
constexpr QUATERNION<T>& operator/=(U v) {
|
||||
QUATERNION<T>& lhs = static_cast<QUATERNION<T>&>(*this);
|
||||
for (size_t i = 0; i < QUATERNION<T>::size(); i++) {
|
||||
@@ -125,25 +125,25 @@ public:
|
||||
* q.w*r.z + q.x*r.y - q.y*r.x + q.z*r.w);
|
||||
*
|
||||
*/
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(U scalar, QUATERNION<T> q) {
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator*(T scalar, QUATERNION<U> q) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q *= scalar);
|
||||
return q *= scalar;
|
||||
}
|
||||
|
||||
template<typename U, typename = std::enable_if_t<std::is_arithmetic_v<U>>>
|
||||
template<typename U>
|
||||
friend inline constexpr
|
||||
QUATERNION<arithmetic_result_t<T, U>> MATH_PURE operator/(QUATERNION<T> q, U scalar) {
|
||||
// don't pass q by reference because we need a copy anyway
|
||||
return QUATERNION<arithmetic_result_t<T, U>>(q /= scalar);
|
||||
return q /= scalar;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <math.h>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@@ -325,103 +324,3 @@ TEST_F(QuatTest, NaN) {
|
||||
EXPECT_NEAR(qs[2], 0.5, 0.1);
|
||||
EXPECT_NEAR(qs[3], 0.5, 0.1);
|
||||
}
|
||||
|
||||
TEST_F(QuatTest, Conversions) {
|
||||
quat qd;
|
||||
quatf qf;
|
||||
float3 vf;
|
||||
double3 vd;
|
||||
double d = 0.0;
|
||||
float f = 0.0f;
|
||||
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, float>, float>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<float, double>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, float>, double>::value);
|
||||
static_assert(std::is_same<details::arithmetic_result_t<double, double>, double>::value);
|
||||
|
||||
{
|
||||
auto r1 = qd * d;
|
||||
auto r2 = qd * f;
|
||||
auto r3 = qf * d;
|
||||
auto r4 = qf * f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd / d;
|
||||
auto r2 = qd / f;
|
||||
auto r3 = qf / d;
|
||||
auto r4 = qf / f;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = d * qd;
|
||||
auto r2 = f * qd;
|
||||
auto r3 = d * qf;
|
||||
auto r4 = f * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * vd;
|
||||
auto r2 = qf * vd;
|
||||
auto r3 = qd * vf;
|
||||
auto r4 = qf * vf;
|
||||
static_assert(std::is_same<decltype(r1), double3>::value);
|
||||
static_assert(std::is_same<decltype(r2), double3>::value);
|
||||
static_assert(std::is_same<decltype(r3), double3>::value);
|
||||
static_assert(std::is_same<decltype(r4), float3>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = qd * qd;
|
||||
auto r2 = qf * qd;
|
||||
auto r3 = qd * qf;
|
||||
auto r4 = qf * qf;
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = dot(qd, qd);
|
||||
auto r2 = dot(qf, qd);
|
||||
auto r3 = dot(qd, qf);
|
||||
auto r4 = dot(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), double>::value);
|
||||
static_assert(std::is_same<decltype(r2), double>::value);
|
||||
static_assert(std::is_same<decltype(r3), double>::value);
|
||||
static_assert(std::is_same<decltype(r4), float>::value);
|
||||
}
|
||||
{
|
||||
auto r1 = cross(qd, qd);
|
||||
auto r2 = cross(qf, qd);
|
||||
auto r3 = cross(qd, qf);
|
||||
auto r4 = cross(qf, qf);
|
||||
static_assert(std::is_same<decltype(r1), quat>::value);
|
||||
static_assert(std::is_same<decltype(r2), quat>::value);
|
||||
static_assert(std::is_same<decltype(r3), quat>::value);
|
||||
static_assert(std::is_same<decltype(r4), quatf>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename L, typename R, typename = void>
|
||||
struct has_divide_assign : std::false_type {};
|
||||
|
||||
template <typename L, typename R>
|
||||
struct has_divide_assign<L, R,
|
||||
decltype(std::declval<L&>() /= std::declval<R>(), void())> : std::true_type {};
|
||||
|
||||
// Static assertions to validate the availability of the /= operator for specific type
|
||||
// combinations. The first static_assert checks that the quat does not have a /= operator with Foo.
|
||||
// This ensures that quat does not provide an inappropriate overload that could be erroneously
|
||||
// selected.
|
||||
struct Foo {};
|
||||
static_assert(!has_divide_assign<quat, Foo>::value);
|
||||
static_assert(has_divide_assign<quat, float>::value);
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include <utils/Panic.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace utils {
|
||||
|
||||
// we use a non-inlined, not marked as "no return" function for aborting so that we can set
|
||||
|
||||
+28
-74
@@ -53,8 +53,6 @@
|
||||
#include <imgui.h>
|
||||
#include <filagui/ImGuiExtensions.h>
|
||||
|
||||
#include <cgltf.h>
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
@@ -487,57 +485,6 @@ static void onClick(App& app, View* view, ImVec2 pos) {
|
||||
});
|
||||
}
|
||||
|
||||
static utils::Path getPathForAsset(std::string_view string) {
|
||||
utils::Path filename{ string };
|
||||
if (!filename.exists()) {
|
||||
std::cerr << "file " << filename << " not found!" << std::endl;
|
||||
return {};
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
auto files = filename.listContents();
|
||||
for (const auto& file: files) {
|
||||
if (file.getExtension() == "gltf" || file.getExtension() == "glb") {
|
||||
filename = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
std::cerr << "no glTF file found in " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
static bool checkAsset(const utils::Path& filename) {
|
||||
// Peek at the file size to allow pre-allocation.
|
||||
long const contentSize = static_cast<long>(getFileSize(filename.c_str()));
|
||||
if (contentSize <= 0) {
|
||||
std::cerr << "Unable to open " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Consume the glTF file.
|
||||
std::ifstream in(filename.c_str(), std::ifstream::binary | std::ifstream::in);
|
||||
std::vector<uint8_t> buffer(static_cast<unsigned long>(contentSize));
|
||||
if (!in.read((char*) buffer.data(), contentSize)) {
|
||||
std::cerr << "Unable to read " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
cgltf_options options{};
|
||||
cgltf_data* sourceAsset;
|
||||
cgltf_result result = cgltf_parse(&options, buffer.data(), contentSize, &sourceAsset);
|
||||
if (result != cgltf_result_success) {
|
||||
slog.e << "Unable to parse glTF file." << io::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
App app;
|
||||
|
||||
@@ -549,10 +496,24 @@ int main(int argc, char** argv) {
|
||||
utils::Path filename;
|
||||
int const num_args = argc - optionIndex;
|
||||
if (num_args >= 1) {
|
||||
filename = getPathForAsset(argv[optionIndex]);
|
||||
if (filename.isEmpty()) {
|
||||
filename = argv[optionIndex];
|
||||
if (!filename.exists()) {
|
||||
std::cerr << "file " << filename << " not found!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
auto files = filename.listContents();
|
||||
for (const auto& file : files) {
|
||||
if (file.getExtension() == "gltf" || file.getExtension() == "glb") {
|
||||
filename = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (filename.isDirectory()) {
|
||||
std::cerr << "no glTF file found in " << filename << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto loadAsset = [&app](const utils::Path& filename) {
|
||||
@@ -573,14 +534,14 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
app.asset = app.assetLoader->createAsset(buffer.data(), buffer.size());
|
||||
app.instance = app.asset->getInstance();
|
||||
buffer.clear();
|
||||
buffer.shrink_to_fit();
|
||||
|
||||
if (!app.asset) {
|
||||
std::cerr << "Unable to parse " << filename << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
app.instance = app.asset->getInstance();
|
||||
buffer.clear();
|
||||
buffer.shrink_to_fit();
|
||||
};
|
||||
|
||||
auto loadResources = [&app] (const utils::Path& filename) {
|
||||
@@ -598,8 +559,6 @@ int main(int argc, char** argv) {
|
||||
app.resourceLoader->addTextureProvider("image/png", app.stbDecoder);
|
||||
app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder);
|
||||
app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder);
|
||||
} else {
|
||||
app.resourceLoader->setConfiguration(configuration);
|
||||
}
|
||||
|
||||
if (!app.resourceLoader->asyncBeginLoad(app.asset)) {
|
||||
@@ -1062,19 +1021,14 @@ int main(int argc, char** argv) {
|
||||
filamentApp.animate(animate);
|
||||
filamentApp.resize(resize);
|
||||
|
||||
filamentApp.setDropHandler([&](std::string_view path) {
|
||||
utils::Path const filename = getPathForAsset(path);
|
||||
if (!filename.isEmpty()) {
|
||||
if (checkAsset(filename)) {
|
||||
app.resourceLoader->asyncCancelLoad();
|
||||
app.resourceLoader->evictResourceData();
|
||||
app.viewer->removeAsset();
|
||||
app.assetLoader->destroyAsset(app.asset);
|
||||
loadAsset(filename);
|
||||
loadResources(filename);
|
||||
app.viewer->setAsset(app.asset, app.instance);
|
||||
}
|
||||
}
|
||||
filamentApp.setDropHandler([&] (std::string_view path) {
|
||||
app.resourceLoader->asyncCancelLoad();
|
||||
app.resourceLoader->evictResourceData();
|
||||
app.viewer->removeAsset();
|
||||
app.assetLoader->destroyAsset(app.asset);
|
||||
loadAsset(path);
|
||||
loadResources(path);
|
||||
app.viewer->setAsset(app.asset, app.instance);
|
||||
});
|
||||
|
||||
filamentApp.run(app.config, setup, cleanup, gui, preRender, postRender);
|
||||
|
||||
@@ -58,9 +58,9 @@ void main() {
|
||||
fragColor.zw = computeDepthMomentsVSM(-1.0 / depth); // requires at least RGBA16F
|
||||
#elif defined(VARIANT_HAS_PICKING)
|
||||
#if MATERIAL_FEATURE_LEVEL == 0
|
||||
outPicking.a = mod(float(object_uniforms_objectId / 65536), 256.0) / 255.0;
|
||||
outPicking.b = mod(float(object_uniforms_objectId / 256), 256.0) / 255.0;
|
||||
outPicking.g = mod(float(object_uniforms_objectId) , 256.0) / 255.0;
|
||||
outPicking.a = float((object_uniforms_objectId / 65536) % 256) / 255.0;
|
||||
outPicking.b = float((object_uniforms_objectId / 256) % 256) / 255.0;
|
||||
outPicking.g = float( object_uniforms_objectId % 256) / 255.0;
|
||||
outPicking.r = vertex_position.z / vertex_position.w;
|
||||
#else
|
||||
outPicking.x = intBitsToFloat(object_uniforms_objectId);
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "ParametersProcessor.h"
|
||||
|
||||
#include <GlslangToSpv.h>
|
||||
#include "glslang/Include/intermediate.h"
|
||||
|
||||
#include "sca/builtinResource.h"
|
||||
|
||||
|
||||
@@ -180,6 +180,19 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
}
|
||||
}
|
||||
|
||||
const JsonishValue* transferFunctionValue = jsonObject.getValue("transferFunction");
|
||||
if (transferFunctionValue) {
|
||||
if (transferFunctionValue->getType() != JsonishValue::STRING) {
|
||||
std::cerr << "parameters: transferFunction must be a STRING." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto transferFunctionString = formatValue->toJsonString();
|
||||
if (!Enums::isValid<SamplerTransferFunction>(transferFunctionString->getString())){
|
||||
return logEnumIssue("parameters", *transferFunctionString, Enums::map<SamplerTransferFunction>());
|
||||
}
|
||||
}
|
||||
|
||||
auto typeString = typeValue->toJsonString()->getString();
|
||||
auto nameString = nameValue->toJsonString()->getString();
|
||||
|
||||
@@ -205,22 +218,22 @@ static bool processParameter(MaterialBuilder& builder, const JsonishObject& json
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialBuilder::SamplerType type = Enums::toEnum<SamplerType>(typeString);
|
||||
if (precisionValue && formatValue) {
|
||||
auto format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
auto precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, format, precision);
|
||||
} else if (formatValue) {
|
||||
auto format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, format);
|
||||
} else if (precisionValue) {
|
||||
auto precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
builder.parameter(nameString.c_str(), type, precision);
|
||||
} else {
|
||||
builder.parameter(nameString.c_str(), type);
|
||||
SamplerType type = Enums::toEnum<SamplerType>(typeString);
|
||||
SamplerFormat format = SamplerFormat::FLOAT;
|
||||
if (formatValue) {
|
||||
format = Enums::toEnum<SamplerFormat>(formatValue->toJsonString()->getString());
|
||||
}
|
||||
ParameterPrecision precision = ParameterPrecision::DEFAULT;
|
||||
if (precisionValue) {
|
||||
precision =
|
||||
Enums::toEnum<ParameterPrecision>(precisionValue->toJsonString()->getString());
|
||||
}
|
||||
SamplerTransferFunction transferFunction = SamplerTransferFunction::UNDEFINED;
|
||||
if (transferFunctionValue) {
|
||||
transferFunction =
|
||||
Enums::toEnum<SamplerTransferFunction>(transferFunctionValue->toJsonString()->getString());
|
||||
}
|
||||
builder.parameter(nameString.c_str(), type, format, precision, transferFunction);
|
||||
} else {
|
||||
std::cerr << "parameters: the type '" << typeString
|
||||
<< "' for parameter with name '" << nameString << "' is neither a valid uniform "
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.46.0",
|
||||
"version": "1.45.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user