fix normal morph target
This commit is contained in:
@@ -63,6 +63,9 @@ using namespace gltfio;
|
||||
using namespace utils;
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace foo {
|
||||
MaterialProvider* createUbershaderLoader(filament::Engine* engine);
|
||||
}
|
||||
|
||||
namespace filament {
|
||||
class IndirectLight;
|
||||
@@ -70,7 +73,12 @@ namespace filament {
|
||||
}
|
||||
|
||||
namespace gltfio {
|
||||
MaterialProvider* createGPUMorphShaderLoader(const void* data, uint64_t size, Engine* engine);
|
||||
MaterialProvider* createGPUMorphShaderLoader(
|
||||
const void* opaqueData,
|
||||
uint64_t opaqueDataSize,
|
||||
const void* fadeData,
|
||||
uint64_t fadeDataSize,
|
||||
Engine* engine);
|
||||
void decomposeMatrix(const filament::math::mat4f& mat, filament::math::float3* translation,
|
||||
filament::math::quatf* rotation, filament::math::float3* scale);
|
||||
}
|
||||
@@ -113,12 +121,14 @@ filament::math::mat4f composeMatrix(const filament::math::float3& translation,
|
||||
|
||||
FilamentViewer::FilamentViewer(
|
||||
void* layer,
|
||||
const char* shaderPath,
|
||||
const char* opaqueShaderPath,
|
||||
const char* fadeShaderPath,
|
||||
LoadResource loadResource,
|
||||
FreeResource freeResource) : _layer(layer),
|
||||
_loadResource(loadResource),
|
||||
_freeResource(freeResource),
|
||||
materialProviderResources(nullptr, 0) {
|
||||
opaqueShaderResources(nullptr, 0),
|
||||
fadeShaderResources(nullptr, 0) {
|
||||
_engine = Engine::create(Engine::Backend::OPENGL);
|
||||
|
||||
_renderer = _engine->createRenderer();
|
||||
@@ -134,13 +144,19 @@ FilamentViewer::FilamentViewer(
|
||||
|
||||
_swapChain = _engine->createSwapChain(_layer);
|
||||
|
||||
if(shaderPath) {
|
||||
materialProviderResources = _loadResource(shaderPath);
|
||||
_materialProvider = createGPUMorphShaderLoader(materialProviderResources.data, materialProviderResources.size, _engine);
|
||||
// if(shaderPath) {
|
||||
opaqueShaderResources = _loadResource(opaqueShaderPath);
|
||||
fadeShaderResources = _loadResource(fadeShaderPath);
|
||||
_materialProvider = createGPUMorphShaderLoader(
|
||||
opaqueShaderResources.data,
|
||||
opaqueShaderResources.size,
|
||||
fadeShaderResources.data,
|
||||
fadeShaderResources.size,
|
||||
_engine);
|
||||
// _freeResource((void*)rb.data, rb.size, nullptr); <- TODO this is being freed too early, need to pass to callback?
|
||||
} else {
|
||||
_materialProvider = createUbershaderLoader(_engine);
|
||||
}
|
||||
// } else {
|
||||
// _materialProvider = foo::createUbershaderLoader(_engine);
|
||||
// }
|
||||
EntityManager& em = EntityManager::get();
|
||||
_ncm = new NameComponentManager(em);
|
||||
_assetLoader = AssetLoader::create({_engine, _materialProvider, _ncm, &em});
|
||||
@@ -191,7 +207,8 @@ void FilamentViewer::loadResources(string relativeResourcePath) {
|
||||
void FilamentViewer::releaseSourceAssets() {
|
||||
std::cout << "Releasing source data" << std::endl;
|
||||
_asset->releaseSourceData();
|
||||
_freeResource((void*)materialProviderResources.data, materialProviderResources.size, nullptr);
|
||||
_freeResource((void*)opaqueShaderResources.data, opaqueShaderResources.size, nullptr);
|
||||
_freeResource((void*)fadeShaderResources.data, fadeShaderResources.size, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +217,44 @@ void FilamentViewer::animateWeights(float* data, int numWeights, int length, flo
|
||||
morphAnimationBuffer = std::make_unique<MorphAnimationBuffer>(data, numWeights, length / numWeights, 1000 / frameRate );
|
||||
}
|
||||
|
||||
void FilamentViewer::loadGlb(const char* const uri) {
|
||||
if(_asset) {
|
||||
_resourceLoader->evictResourceData();
|
||||
_scene->removeEntities(_asset->getEntities(), _asset->getEntityCount());
|
||||
_assetLoader->destroyAsset(_asset);
|
||||
}
|
||||
_asset = nullptr;
|
||||
_animator = nullptr;
|
||||
|
||||
ResourceBuffer rbuf = _loadResource(uri);
|
||||
|
||||
// Parse the glTF file and create Filament entities.
|
||||
_asset = _assetLoader->createAssetFromJson((uint8_t*)rbuf.data, rbuf.size);
|
||||
|
||||
if (!_asset) {
|
||||
std::cerr << "Unable to parse asset" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
_resourceLoader->loadResources(_asset);
|
||||
const Entity* entities = _asset->getEntities();
|
||||
RenderableManager& rm = _engine->getRenderableManager();
|
||||
for(int i =0; i< _asset->getEntityCount(); i++) {
|
||||
Entity e = entities[i];
|
||||
auto inst = rm.getInstance(e);
|
||||
rm.setCulling(inst, false);
|
||||
}
|
||||
|
||||
_animator = _asset->getAnimator();
|
||||
|
||||
_scene->addEntities(_asset->getEntities(), _asset->getEntityCount());
|
||||
|
||||
|
||||
_freeResource((void*)rbuf.data, rbuf.size, nullptr);
|
||||
|
||||
transformToUnitCube();
|
||||
}
|
||||
|
||||
void FilamentViewer::loadGltf(const char* const uri, const char* const relativeResourcePath) {
|
||||
if(_asset) {
|
||||
_resourceLoader->evictResourceData();
|
||||
@@ -280,16 +335,23 @@ void FilamentViewer::playAnimation(int index) {
|
||||
}
|
||||
|
||||
void FilamentViewer::loadSkybox(const char* const skyboxPath, const char* const iblPath) {
|
||||
|
||||
std::cout << "Loading skybox from " << skyboxPath << std::endl;
|
||||
|
||||
ResourceBuffer skyboxBuffer = _loadResource(skyboxPath);
|
||||
|
||||
std::cout << "Loaded skybox resource buffer of size " << skyboxBuffer.size << std::endl;
|
||||
|
||||
image::KtxBundle* skyboxBundle =
|
||||
new image::KtxBundle(static_cast<const uint8_t*>(skyboxBuffer.data),
|
||||
static_cast<uint32_t>(skyboxBuffer.size));
|
||||
_skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, false);
|
||||
_skyboxTexture = image::ktx::createTexture(_engine, skyboxBundle, true);
|
||||
_skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
|
||||
_scene->setSkybox(_skybox);
|
||||
_freeResource((void*)skyboxBuffer.data, skyboxBuffer.size, nullptr);
|
||||
|
||||
std::cout << "Loading IBL from " << iblPath << std::endl;
|
||||
|
||||
// Load IBL.
|
||||
ResourceBuffer iblBuffer = _loadResource(iblPath);
|
||||
|
||||
|
||||
@@ -94,8 +94,9 @@ namespace holovox {
|
||||
|
||||
class FilamentViewer {
|
||||
public:
|
||||
FilamentViewer(void* layer, const char* shaderPath, LoadResource loadResource, FreeResource freeResource);
|
||||
FilamentViewer(void* layer, const char* opaqueShaderPath, const char* fadeShaderPath, LoadResource loadResource, FreeResource freeResource);
|
||||
~FilamentViewer();
|
||||
void loadGlb(const char* const uri);
|
||||
void loadGltf(const char* const uri, const char* relativeResourcePath);
|
||||
void loadSkybox(const char* const skyboxUri, const char* const iblUri);
|
||||
void updateViewportAndCameraProjection(int height, int width, float scaleFactor);
|
||||
@@ -127,7 +128,8 @@ namespace holovox {
|
||||
LoadResource _loadResource;
|
||||
FreeResource _freeResource;
|
||||
|
||||
ResourceBuffer materialProviderResources;
|
||||
ResourceBuffer opaqueShaderResources;
|
||||
ResourceBuffer fadeShaderResources;
|
||||
|
||||
Scene* _scene;
|
||||
View* _view;
|
||||
|
||||
@@ -35,6 +35,16 @@ using namespace filament;
|
||||
using namespace filamat;
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
|
||||
#include "upcast.h"
|
||||
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <filament/Texture.h>
|
||||
|
||||
#include <utils/compiler.h>
|
||||
|
||||
|
||||
namespace gltfio {
|
||||
|
||||
static constexpr uint8_t kUnused = 0xff;
|
||||
@@ -62,6 +72,7 @@ namespace gltfio {
|
||||
targetMesh = mesh;
|
||||
for(int i = 0; i < numPrimitives; i++) {
|
||||
int primitiveIndex = primitiveIndices[i];
|
||||
//for(int primitiveIndex = 0; primitiveIndex < targetMesh->primitives_count; primitiveIndex++) {
|
||||
std::cout << "Adding primitive at index " << primitiveIndex << " to morpher " << std::endl;
|
||||
addPrimitive(mesh, primitiveIndex);
|
||||
}
|
||||
@@ -106,7 +117,6 @@ namespace gltfio {
|
||||
auto textureSize = textureWidth * 3 * sizeof(float) * prim->numTargets;
|
||||
auto textureBuffer = (float *const) malloc(textureSize);
|
||||
|
||||
|
||||
if(!textureBuffer) {
|
||||
std::cout << "Error allocating texture buffer" << std::endl;
|
||||
exit(-1);
|
||||
@@ -117,7 +127,7 @@ namespace gltfio {
|
||||
uint32_t offset = 0;
|
||||
|
||||
// assume the primitive morph target source buffer is laid out like:
|
||||
// |target0_v0_pos * 3|target0_v0_norm * 3|target0_v1_pos * 3|target0_v1_norm * 3|...|target1_v0_pos * 3|target1_v0_norm * 3|target1_v1_pos * 3|target1_v1_norm * 3|...
|
||||
// |target0_v0_pos * 3|target0_v1_pos * 3|...|target0_v0_norm * 3|target0_v1_norm * 3|...|target1_v0_pos * 3|target1_v1_pos * 3|...|target1_v0_norm * 3|target1_v1_norm * 3|...
|
||||
// where:
|
||||
// - target0/target1/etc is the first/second/etc morph target
|
||||
// - v0/v1/etc is the first/second/etc vertex
|
||||
@@ -126,7 +136,7 @@ namespace gltfio {
|
||||
if(target.type == cgltf_attribute_type_position
|
||||
|| (numAttributes > 1 && target.type == cgltf_attribute_type_normal)
|
||||
) {
|
||||
|
||||
float attr = (float)textureBuffer[offset];
|
||||
memcpy(textureBuffer+offset, target.bufferObject, target.bufferSize);
|
||||
offset += int(target.bufferSize / sizeof(float));
|
||||
}
|
||||
@@ -137,7 +147,7 @@ namespace gltfio {
|
||||
.height(1)
|
||||
.depth(prim->numTargets)
|
||||
.sampler(Texture::Sampler::SAMPLER_2D_ARRAY)
|
||||
.format(Texture::InternalFormat::RGB32F)
|
||||
.format(backend::TextureFormat::RGB32F)
|
||||
.levels(0x01)
|
||||
.build(engine);
|
||||
|
||||
@@ -146,8 +156,8 @@ namespace gltfio {
|
||||
Texture::PixelBufferDescriptor descriptor(
|
||||
textureBuffer,
|
||||
textureSize,
|
||||
Texture::Format::RGB,
|
||||
Texture::Type::FLOAT,
|
||||
backend::PixelDataFormat::RGB,
|
||||
backend::PixelDataType::FLOAT,
|
||||
FREE_CALLBACK,
|
||||
nullptr);
|
||||
prim->texture->setImage(engine, 0, 0,0, 0, textureWidth, 1, prim->numTargets, std::move(descriptor));
|
||||
@@ -155,7 +165,8 @@ namespace gltfio {
|
||||
for(int i = 0; i < mAsset->getMaterialInstanceCount(); i++) {
|
||||
const char* name = materialInstances[i]->getName();
|
||||
if(strcmp(name, prim->materialName) == 0) {
|
||||
std::cout << "Found material instance for primitive under name : " << name << std::endl;
|
||||
const char* m = materialInstances[i]->getMaterial()->getName();
|
||||
std::cout << "Found material instance for material " << m << " and primitive under name : " << name << std::endl;
|
||||
prim->materialInstance = materialInstances[i]; //std::unique_ptr<MaterialInstance>(materialInstances[i]);
|
||||
break;
|
||||
}
|
||||
@@ -165,7 +176,7 @@ namespace gltfio {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
float dimensions[] = { (float(prim->numVertices) * float(numAttributes)), float(numAttributes), float(prim->numTargets) };
|
||||
float dimensions[] = { float(prim->numVertices), float(numAttributes), float(prim->numTargets) };
|
||||
|
||||
prim->materialInstance->setParameter("dimensions", dimensions, 3);
|
||||
// TextureSampler sampler(filament::backend::SamplerMagFilter::NEAREST, filament::TextureSampler::WrapMode::REPEAT);
|
||||
@@ -214,12 +225,7 @@ namespace gltfio {
|
||||
if (atype == cgltf_attribute_type_tangent) {
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
atype == cgltf_attribute_type_position || (numAttributes > 1 && atype == cgltf_attribute_type_normal)
|
||||
) {
|
||||
|
||||
|
||||
// All position & normal attributes must have the same data type.
|
||||
if (atype == cgltf_attribute_type_position || numAttributes > 1 && atype == cgltf_attribute_type_normal) {
|
||||
assert_invariant(
|
||||
!previous || previous->component_type == accessor->component_type);
|
||||
assert_invariant(!previous || previous->type == accessor->type);
|
||||
@@ -234,9 +240,122 @@ namespace gltfio {
|
||||
|
||||
animatedPrimitive->targets.push_back({data, size, targetIndex, atype});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
animatablePrimitives.push_back(std::move(animatedPrimitive));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// assert(
|
||||
// FTexture::validatePixelFormatAndType(
|
||||
// backend::TextureFormat::RGB32F,
|
||||
// backend::PixelDataFormat::RGB,
|
||||
// backend::PixelDataType::FLOAT));
|
||||
|
||||
// namespace filament {
|
||||
|
||||
// class FEngine;
|
||||
// class FStream;
|
||||
|
||||
// class FTexture : public Texture {
|
||||
// public:
|
||||
// FTexture(FEngine& engine, const Builder& builder);
|
||||
|
||||
// // frees driver resources, object becomes invalid
|
||||
// void terminate(FEngine& engine);
|
||||
|
||||
// backend::Handle<backend::HwTexture> getHwHandle() const noexcept { return mHandle; }
|
||||
|
||||
// size_t getWidth(size_t level = 0) const noexcept;
|
||||
// size_t getHeight(size_t level = 0) const noexcept;
|
||||
// size_t getDepth(size_t level = 0) const noexcept;
|
||||
// size_t getLevelCount() const noexcept { return mLevelCount; }
|
||||
// size_t getMaxLevelCount() const noexcept { return FTexture::maxLevelCount(mWidth, mHeight); }
|
||||
// Sampler getTarget() const noexcept { return mTarget; }
|
||||
// InternalFormat getFormat() const noexcept { return mFormat; }
|
||||
// Usage getUsage() const noexcept { return mUsage; }
|
||||
|
||||
// void setImage(FEngine& engine, size_t level,
|
||||
// uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
// PixelBufferDescriptor&& buffer) const;
|
||||
|
||||
// void setImage(FEngine& engine, size_t level,
|
||||
// uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
|
||||
// uint32_t width, uint32_t height, uint32_t depth,
|
||||
// PixelBufferDescriptor&& buffer) const;
|
||||
|
||||
// void setImage(FEngine& engine, size_t level,
|
||||
// PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets) const;
|
||||
|
||||
// void generatePrefilterMipmap(FEngine& engine,
|
||||
// PixelBufferDescriptor&& buffer, const FaceOffsets& faceOffsets,
|
||||
// PrefilterOptions const* options);
|
||||
|
||||
// void setExternalImage(FEngine& engine, void* image) noexcept;
|
||||
// void setExternalImage(FEngine& engine, void* image, size_t plane) noexcept;
|
||||
// void setExternalStream(FEngine& engine, FStream* stream) noexcept;
|
||||
|
||||
// void generateMipmaps(FEngine& engine) const noexcept;
|
||||
|
||||
// void setSampleCount(size_t sampleCount) noexcept { mSampleCount = uint8_t(sampleCount); }
|
||||
// size_t getSampleCount() const noexcept { return mSampleCount; }
|
||||
// bool isMultisample() const noexcept { return mSampleCount > 1; }
|
||||
// bool isCompressed() const noexcept { return backend::isCompressedFormat(mFormat); }
|
||||
|
||||
// bool isCubemap() const noexcept { return mTarget == Sampler::SAMPLER_CUBEMAP; }
|
||||
|
||||
// FStream const* getStream() const noexcept { return mStream; }
|
||||
|
||||
// /*
|
||||
// * Utilities
|
||||
// */
|
||||
|
||||
// // synchronous call to the backend. returns whether a backend supports a particular format.
|
||||
// static bool isTextureFormatSupported(FEngine& engine, InternalFormat format) noexcept;
|
||||
|
||||
// // synchronous call to the backend. returns whether a backend supports texture swizzling.
|
||||
// static bool isTextureSwizzleSupported(FEngine& engine) noexcept;
|
||||
|
||||
// // storage needed on the CPU side for texture data uploads
|
||||
// static size_t computeTextureDataSize(Texture::Format format, Texture::Type type,
|
||||
// size_t stride, size_t height, size_t alignment) noexcept;
|
||||
|
||||
// // Size a of a pixel in bytes for the given format
|
||||
// static size_t getFormatSize(InternalFormat format) noexcept;
|
||||
|
||||
// // Returns the with or height for a given mipmap level from the base value.
|
||||
// static inline size_t valueForLevel(uint8_t level, size_t baseLevelValue) {
|
||||
// return std::max(size_t(1), baseLevelValue >> level);
|
||||
// }
|
||||
|
||||
// // Returns the max number of levels for a texture of given max dimensions
|
||||
// static inline uint8_t maxLevelCount(uint32_t maxDimension) noexcept {
|
||||
// return std::max(1, std::ilogbf(maxDimension) + 1);
|
||||
// }
|
||||
|
||||
// // Returns the max number of levels for a texture of given dimensions
|
||||
// static inline uint8_t maxLevelCount(uint32_t width, uint32_t height) noexcept {
|
||||
// return std::max(1, std::ilogbf(std::max(width, height)) + 1);
|
||||
// }
|
||||
|
||||
// static bool validatePixelFormatAndType(backend::TextureFormat internalFormat,
|
||||
// backend::PixelDataFormat format, backend::PixelDataType type) noexcept;
|
||||
|
||||
// private:
|
||||
// friend class Texture;
|
||||
// FStream* mStream = nullptr;
|
||||
// backend::Handle<backend::HwTexture> mHandle;
|
||||
// uint32_t mWidth = 1;
|
||||
// uint32_t mHeight = 1;
|
||||
// uint32_t mDepth = 1;
|
||||
// InternalFormat mFormat = InternalFormat::RGBA8;
|
||||
// Sampler mTarget = Sampler::SAMPLER_2D;
|
||||
// uint8_t mLevelCount = 1;
|
||||
// uint8_t mSampleCount = 1;
|
||||
// Usage mUsage = Usage::DEFAULT;
|
||||
// };
|
||||
|
||||
|
||||
// } // namespace filament
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace gltfio {
|
||||
MaterialInstance* materialInstance;
|
||||
};
|
||||
|
||||
int numAttributes = 1; // just position for now - normals not working with indexing inside shader? byte offset seems not calculated correctly
|
||||
int numAttributes = 2;
|
||||
|
||||
void addPrimitive(cgltf_mesh const *mesh, int primitiveIndex);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <math/mat4.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "gltfio/resources/gltfresources_lite.h"
|
||||
|
||||
@@ -22,7 +23,12 @@ namespace {
|
||||
|
||||
class GPUMorphShaderLoader : public MaterialProvider {
|
||||
public:
|
||||
GPUMorphShaderLoader(const void* mData, uint64_t size, filament::Engine* engine);
|
||||
GPUMorphShaderLoader(
|
||||
const void* opaqueMaterial,
|
||||
uint64_t opaqueMaterialSize,
|
||||
const void* fadeMaterial,
|
||||
uint64_t fadeMaterialSize,
|
||||
filament::Engine* engine);
|
||||
~GPUMorphShaderLoader() {}
|
||||
|
||||
MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap,
|
||||
@@ -42,8 +48,10 @@ namespace {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const void* mData;
|
||||
const size_t mSize;
|
||||
const void* opaqueData;
|
||||
const size_t opaqueDataSize;
|
||||
const void* fadeData;
|
||||
const size_t fadeDataSize;
|
||||
|
||||
Material* getMaterial(const MaterialKey& config) const;
|
||||
|
||||
@@ -59,18 +67,41 @@ namespace {
|
||||
Engine* mEngine;
|
||||
};
|
||||
|
||||
GPUMorphShaderLoader::GPUMorphShaderLoader(const void* data, uint64_t size, Engine* engine) : mData(data), mSize(size), mEngine(engine) {
|
||||
|
||||
unsigned char texels[4] = {};
|
||||
mDummyTexture = Texture::Builder()
|
||||
.width(1).height(1)
|
||||
.format(Texture::InternalFormat::RGBA8)
|
||||
.build(*mEngine);
|
||||
Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE);
|
||||
mDummyTexture->setImage(*mEngine, 0, std::move(pbd));
|
||||
#define MATINDEX(shading, alpha, sheen, transmit, volume) (volume ? 11 : (transmit ? 10 : (sheen ? 9 : (int(shading) + 3 * int(alpha)))))
|
||||
|
||||
|
||||
GPUMorphShaderLoader::GPUMorphShaderLoader(const void* opaqueData,
|
||||
uint64_t opaqueDataSize,
|
||||
const void* fadeData,
|
||||
uint64_t fadeDataSize,
|
||||
Engine* engine) : opaqueData(opaqueData), opaqueDataSize(opaqueDataSize), fadeData(fadeData), fadeDataSize(fadeDataSize), mEngine(engine) {
|
||||
|
||||
// unsigned char texels[4] = {};
|
||||
// mDummyTexture = Texture::Builder()
|
||||
// .width(1)
|
||||
// .height(1)
|
||||
// .format(backend::TextureFormat::RGBA8)
|
||||
// .sampler(backend::SamplerType::SAMPLER_2D_ARRAY)
|
||||
// .build(*mEngine);
|
||||
// Texture::PixelBufferDescriptor pbd(
|
||||
// texels,
|
||||
// sizeof(texels),
|
||||
// backend::PixelDataFormat::RGBA,
|
||||
// backend::PixelDataType::UBYTE,
|
||||
// nullptr);
|
||||
// mDummyTexture->setImage(*mEngine, 0,0,0,0,0,0,0,std::move(pbd));
|
||||
unsigned char texels[4] = {};
|
||||
mDummyTexture = Texture::Builder()
|
||||
.width(1).height(1)
|
||||
.format(Texture::InternalFormat::RGBA8)
|
||||
.build(*mEngine);
|
||||
Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE);
|
||||
mDummyTexture->setImage(*mEngine, 0, std::move(pbd));
|
||||
}
|
||||
|
||||
|
||||
size_t GPUMorphShaderLoader::getMaterialsCount() const noexcept {
|
||||
return sizeof(mMaterials) / sizeof(mMaterials[0]);
|
||||
}
|
||||
@@ -90,13 +121,33 @@ namespace {
|
||||
Material* GPUMorphShaderLoader::getMaterial(const MaterialKey& config) const {
|
||||
const ShadingMode shading = config.unlit ? UNLIT :
|
||||
(config.useSpecularGlossiness ? SPECULAR_GLOSSINESS : LIT);
|
||||
const int matindex = 0;
|
||||
|
||||
const int matindex = MATINDEX(shading, config.alphaMode, config.hasSheen, config.hasTransmission, config.hasVolume);
|
||||
if (mMaterials[matindex] != nullptr) {
|
||||
return mMaterials[matindex];
|
||||
}
|
||||
switch (matindex) {
|
||||
case MATINDEX(LIT, AlphaMode::OPAQUE, false, false, false):
|
||||
{
|
||||
filamat::Package pkg = filamat::Package(opaqueData, opaqueDataSize);
|
||||
mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine);
|
||||
}
|
||||
break;
|
||||
case MATINDEX(LIT, AlphaMode::BLEND, false, false, false):
|
||||
{
|
||||
filamat::Package pkg = filamat::Package(fadeData, fadeDataSize);
|
||||
mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
filamat::Package pkg = filamat::Package(fadeData, fadeDataSize);
|
||||
mMaterials[matindex] = Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
filamat::Package pkg = filamat::Package(mData, mSize);
|
||||
return Material::Builder().package(pkg.getData(), pkg.getSize()).build(*mEngine);
|
||||
return mMaterials[matindex];
|
||||
}
|
||||
|
||||
MaterialInstance* GPUMorphShaderLoader::createMaterialInstance(MaterialKey* config, UvMap* uvmap,
|
||||
@@ -145,7 +196,9 @@ namespace {
|
||||
|
||||
mi->setDoubleSided(config->doubleSided);
|
||||
mi->setCullingMode(config->doubleSided ? CullingMode::NONE : CullingMode::BACK);
|
||||
|
||||
mi->setTransparencyMode(config->doubleSided ?
|
||||
MaterialInstance::TransparencyMode::TWO_PASSES_TWO_SIDES :
|
||||
MaterialInstance::TransparencyMode::DEFAULT);
|
||||
// Initially, assume that the clear coat texture can be honored. This is changed to false when
|
||||
// running into a sampler count limitation. TODO: check if these constraints can now be relaxed.
|
||||
bool clearCoatNeedsTexture = true;
|
||||
@@ -176,7 +229,6 @@ namespace {
|
||||
getUvIndex(config->sheenRoughnessUV, config->hasSheenRoughnessTexture));
|
||||
mi->setParameter("sheenColorUvMatrix", identity);
|
||||
mi->setParameter("sheenRoughnessUvMatrix", identity);
|
||||
|
||||
}
|
||||
if (config->hasVolume) {
|
||||
clearCoatNeedsTexture = false;
|
||||
@@ -196,6 +248,8 @@ namespace {
|
||||
mi->setParameter("normalMap", mDummyTexture, sampler);
|
||||
mi->setParameter("baseColorMap", mDummyTexture, sampler);
|
||||
mi->setParameter("metallicRoughnessMap", mDummyTexture, sampler);
|
||||
// mi->setParameter("roughnessFactor", mDummyTexture, sampler);
|
||||
|
||||
mi->setParameter("occlusionMap", mDummyTexture, sampler);
|
||||
mi->setParameter("emissiveMap", mDummyTexture, sampler);
|
||||
if (clearCoatNeedsTexture) {
|
||||
@@ -227,8 +281,18 @@ namespace {
|
||||
|
||||
namespace gltfio {
|
||||
|
||||
MaterialProvider* createGPUMorphShaderLoader(const void* data, uint64_t size, filament::Engine* engine) {
|
||||
return new GPUMorphShaderLoader(data, size,engine);
|
||||
MaterialProvider* createGPUMorphShaderLoader(
|
||||
const void* opaqueData,
|
||||
uint64_t opaqueDataSize,
|
||||
const void* fadeData,
|
||||
uint64_t fadeDataSize,
|
||||
filament::Engine* engine) {
|
||||
return new GPUMorphShaderLoader(
|
||||
opaqueData,
|
||||
opaqueDataSize,
|
||||
fadeData,
|
||||
fadeDataSize,
|
||||
engine);
|
||||
}
|
||||
|
||||
} // namespace gltfio
|
||||
|
||||
308
ios/src/morph/UbershaderLoader.cpp
Normal file
308
ios/src/morph/UbershaderLoader.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gltfio/MaterialProvider.h>
|
||||
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "gltfio/resources/gltfresources.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
namespace {
|
||||
|
||||
using CullingMode = MaterialInstance::CullingMode;
|
||||
|
||||
class UbershaderLoader : public MaterialProvider {
|
||||
public:
|
||||
UbershaderLoader(filament::Engine* engine);
|
||||
~UbershaderLoader() {}
|
||||
|
||||
MaterialInstance* createMaterialInstance(MaterialKey* config, UvMap* uvmap,
|
||||
const char* label) override;
|
||||
|
||||
size_t getMaterialsCount() const noexcept override;
|
||||
const Material* const* getMaterials() const noexcept override;
|
||||
void destroyMaterials() override;
|
||||
|
||||
bool needsDummyData(VertexAttribute attrib) const noexcept override {
|
||||
switch (attrib) {
|
||||
case VertexAttribute::UV0:
|
||||
case VertexAttribute::UV1:
|
||||
case VertexAttribute::COLOR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Material* getMaterial(const MaterialKey& config) const;
|
||||
|
||||
enum ShadingMode {
|
||||
UNLIT = 0,
|
||||
LIT = 1,
|
||||
SPECULAR_GLOSSINESS = 2,
|
||||
};
|
||||
|
||||
mutable Material* mMaterials[12] = {};
|
||||
Texture* mDummyTexture = nullptr;
|
||||
|
||||
Engine* mEngine;
|
||||
};
|
||||
|
||||
#if GLTFIO_LITE
|
||||
|
||||
#define CREATE_MATERIAL(name) Material::Builder() \
|
||||
.package(GLTFRESOURCES_LITE_ ## name ## _DATA, GLTFRESOURCES_LITE_ ## name ## _SIZE) \
|
||||
.build(*mEngine);
|
||||
|
||||
#else
|
||||
|
||||
#define CREATE_MATERIAL(name) Material::Builder() \
|
||||
.package(GLTFRESOURCES_ ## name ## _DATA, GLTFRESOURCES_ ## name ## _SIZE) \
|
||||
.build(*mEngine);
|
||||
|
||||
#endif
|
||||
|
||||
#define MATINDEX(shading, alpha, sheen, transmit, volume) (volume ? 11 : (transmit ? 10 : (sheen ? 9 : (int(shading) + 3 * int(alpha)))))
|
||||
|
||||
UbershaderLoader::UbershaderLoader(Engine* engine) : mEngine(engine) {
|
||||
unsigned char texels[4] = {};
|
||||
mDummyTexture = Texture::Builder()
|
||||
.width(1).height(1)
|
||||
.format(Texture::InternalFormat::RGBA8)
|
||||
.build(*mEngine);
|
||||
Texture::PixelBufferDescriptor pbd(texels, sizeof(texels), Texture::Format::RGBA,
|
||||
Texture::Type::UBYTE);
|
||||
mDummyTexture->setImage(*mEngine, 0, std::move(pbd));
|
||||
}
|
||||
|
||||
size_t UbershaderLoader::getMaterialsCount() const noexcept {
|
||||
return sizeof(mMaterials) / sizeof(mMaterials[0]);
|
||||
}
|
||||
|
||||
const Material* const* UbershaderLoader::getMaterials() const noexcept {
|
||||
return &mMaterials[0];
|
||||
}
|
||||
|
||||
void UbershaderLoader::destroyMaterials() {
|
||||
for (auto& material : mMaterials) {
|
||||
mEngine->destroy(material);
|
||||
material = nullptr;
|
||||
}
|
||||
mEngine->destroy(mDummyTexture);
|
||||
}
|
||||
|
||||
Material* UbershaderLoader::getMaterial(const MaterialKey& config) const {
|
||||
const ShadingMode shading = config.unlit ? UNLIT :
|
||||
(config.useSpecularGlossiness ? SPECULAR_GLOSSINESS : LIT);
|
||||
const int matindex = MATINDEX(shading, config.alphaMode, config.hasSheen, config.hasTransmission, config.hasVolume);
|
||||
if (mMaterials[matindex] != nullptr) {
|
||||
return mMaterials[matindex];
|
||||
}
|
||||
switch (matindex) {
|
||||
|
||||
case MATINDEX(LIT, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_OPAQUE); break;
|
||||
|
||||
|
||||
|
||||
case MATINDEX(LIT, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_FADE); break;
|
||||
|
||||
|
||||
|
||||
case MATINDEX(LIT, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_MASKED); break;
|
||||
case MATINDEX(UNLIT, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_OPAQUE); break;
|
||||
case MATINDEX(UNLIT, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_MASKED); break;
|
||||
case MATINDEX(UNLIT, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(UNLIT_FADE); break;
|
||||
case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::OPAQUE, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_OPAQUE); break;
|
||||
case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::MASK, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_MASKED); break;
|
||||
case MATINDEX(SPECULAR_GLOSSINESS, AlphaMode::BLEND, false, false, false): mMaterials[matindex] = CREATE_MATERIAL(SPECULARGLOSSINESS_FADE); break;
|
||||
case MATINDEX(0, 0, false, true, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_TRANSMISSION); break;
|
||||
case MATINDEX(0, 0, true, false, false): mMaterials[matindex] = CREATE_MATERIAL(LIT_SHEEN); break;
|
||||
case MATINDEX(0, 0, false, false, true): mMaterials[matindex] = CREATE_MATERIAL(LIT_VOLUME); break;
|
||||
|
||||
}
|
||||
if (mMaterials[matindex] == nullptr) {
|
||||
slog.w << "Unsupported glTF material configuration; falling back to LIT_OPAQUE." << io::endl;
|
||||
MaterialKey litOpaque = config;
|
||||
litOpaque.alphaMode = AlphaMode::OPAQUE;
|
||||
litOpaque.hasTransmission = false;
|
||||
litOpaque.hasVolume = false;
|
||||
litOpaque.hasSheen = false;
|
||||
litOpaque.useSpecularGlossiness = false;
|
||||
litOpaque.unlit = false;
|
||||
return getMaterial(litOpaque);
|
||||
}
|
||||
|
||||
return mMaterials[matindex];
|
||||
}
|
||||
|
||||
MaterialInstance* UbershaderLoader::createMaterialInstance(MaterialKey* config, UvMap* uvmap,
|
||||
const char* label) {
|
||||
// Diagnostics are not supported with LOAD_UBERSHADERS, please use GENERATE_SHADERS instead.
|
||||
if (config->enableDiagnostics) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (config->hasVolume && config->hasSheen) {
|
||||
slog.w << "Volume and sheen are not supported together in ubershader mode,"
|
||||
" removing sheen (" << label << ")." << io::endl;
|
||||
config->hasSheen = false;
|
||||
}
|
||||
|
||||
if (config->hasTransmission && config->hasSheen) {
|
||||
slog.w << "Transmission and sheen are not supported together in ubershader mode,"
|
||||
" removing sheen (" << label << ")." << io::endl;
|
||||
config->hasSheen = false;
|
||||
}
|
||||
|
||||
const bool clearCoatConflict = config->hasVolume || config->hasTransmission || config->hasSheen;
|
||||
|
||||
// Due to sampler overload, disable transmission if necessary and print a friendly warning.
|
||||
if (config->hasClearCoat && clearCoatConflict) {
|
||||
slog.w << "Volume, transmission and sheen are not supported in ubershader mode for clearcoat"
|
||||
" materials (" << label << ")." << io::endl;
|
||||
config->hasVolume = false;
|
||||
config->hasTransmission = false;
|
||||
config->hasSheen = false;
|
||||
}
|
||||
|
||||
constrainMaterial(config, uvmap);
|
||||
auto getUvIndex = [uvmap](uint8_t srcIndex, bool hasTexture) -> int {
|
||||
return hasTexture ? int(uvmap->at(srcIndex)) - 1 : -1;
|
||||
};
|
||||
Material* material = getMaterial(*config);
|
||||
MaterialInstance* mi = material->createInstance(label);
|
||||
mi->setParameter("baseColorIndex",
|
||||
getUvIndex(config->baseColorUV, config->hasBaseColorTexture));
|
||||
mi->setParameter("normalIndex", getUvIndex(config->normalUV, config->hasNormalTexture));
|
||||
mi->setParameter("metallicRoughnessIndex",
|
||||
getUvIndex(config->metallicRoughnessUV, config->hasMetallicRoughnessTexture));
|
||||
mi->setParameter("aoIndex", getUvIndex(config->aoUV, config->hasOcclusionTexture));
|
||||
mi->setParameter("emissiveIndex", getUvIndex(config->emissiveUV, config->hasEmissiveTexture));
|
||||
|
||||
mi->setDoubleSided(config->doubleSided);
|
||||
mi->setCullingMode(config->doubleSided ? CullingMode::NONE : CullingMode::BACK);
|
||||
mi->setTransparencyMode(config->doubleSided ?
|
||||
MaterialInstance::TransparencyMode::TWO_PASSES_TWO_SIDES :
|
||||
MaterialInstance::TransparencyMode::DEFAULT);
|
||||
|
||||
#if !GLTFIO_LITE
|
||||
|
||||
// Initially, assume that the clear coat texture can be honored. This is changed to false when
|
||||
// running into a sampler count limitation. TODO: check if these constraints can now be relaxed.
|
||||
bool clearCoatNeedsTexture = true;
|
||||
|
||||
mat3f identity;
|
||||
mi->setParameter("baseColorUvMatrix", identity);
|
||||
mi->setParameter("metallicRoughnessUvMatrix", identity);
|
||||
mi->setParameter("normalUvMatrix", identity);
|
||||
mi->setParameter("occlusionUvMatrix", identity);
|
||||
mi->setParameter("emissiveUvMatrix", identity);
|
||||
|
||||
if (config->hasClearCoat) {
|
||||
mi->setParameter("clearCoatIndex",
|
||||
getUvIndex(config->clearCoatUV, config->hasClearCoatTexture));
|
||||
mi->setParameter("clearCoatRoughnessIndex",
|
||||
getUvIndex(config->clearCoatRoughnessUV, config->hasClearCoatRoughnessTexture));
|
||||
mi->setParameter("clearCoatNormalIndex",
|
||||
getUvIndex(config->clearCoatNormalUV, config->hasClearCoatNormalTexture));
|
||||
mi->setParameter("clearCoatUvMatrix", identity);
|
||||
mi->setParameter("clearCoatRoughnessUvMatrix", identity);
|
||||
mi->setParameter("clearCoatNormalUvMatrix", identity);
|
||||
} else {
|
||||
if (config->hasSheen) {
|
||||
clearCoatNeedsTexture = false;
|
||||
mi->setParameter("sheenColorIndex",
|
||||
getUvIndex(config->sheenColorUV, config->hasSheenColorTexture));
|
||||
mi->setParameter("sheenRoughnessIndex",
|
||||
getUvIndex(config->sheenRoughnessUV, config->hasSheenRoughnessTexture));
|
||||
mi->setParameter("sheenColorUvMatrix", identity);
|
||||
mi->setParameter("sheenRoughnessUvMatrix", identity);
|
||||
|
||||
}
|
||||
if (config->hasVolume) {
|
||||
clearCoatNeedsTexture = false;
|
||||
mi->setParameter("volumeThicknessUvMatrix", identity);
|
||||
mi->setParameter("volumeThicknessIndex",
|
||||
getUvIndex(config->transmissionUV, config->hasVolumeThicknessTexture));
|
||||
}
|
||||
if (config->hasTransmission) {
|
||||
clearCoatNeedsTexture = false;
|
||||
mi->setParameter("transmissionUvMatrix", identity);
|
||||
mi->setParameter("transmissionIndex",
|
||||
getUvIndex(config->transmissionUV, config->hasTransmissionTexture));
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
// In the GLTFIO_LITE configuration we do not support UV matrices, clear coat, sheen, specular
|
||||
// glossiness, or transmission. For more details, see `gltflite.mat.in`. To configure a custom
|
||||
// set of features, create your own MaterialProvider class, perhaps using UbershaderLoader as a
|
||||
// starting point.
|
||||
const bool clearCoatNeedsTexture = false;
|
||||
|
||||
#endif
|
||||
|
||||
TextureSampler sampler;
|
||||
mi->setParameter("normalMap", mDummyTexture, sampler);
|
||||
mi->setParameter("baseColorMap", mDummyTexture, sampler);
|
||||
mi->setParameter("metallicRoughnessMap", mDummyTexture, sampler);
|
||||
mi->setParameter("occlusionMap", mDummyTexture, sampler);
|
||||
mi->setParameter("emissiveMap", mDummyTexture, sampler);
|
||||
if (clearCoatNeedsTexture) {
|
||||
mi->setParameter("clearCoatMap", mDummyTexture, sampler);
|
||||
mi->setParameter("clearCoatRoughnessMap", mDummyTexture, sampler);
|
||||
mi->setParameter("clearCoatNormalMap", mDummyTexture, sampler);
|
||||
}
|
||||
if (!config->hasClearCoat) {
|
||||
if (config->hasTransmission) {
|
||||
mi->setParameter("transmissionMap", mDummyTexture, sampler);
|
||||
}
|
||||
if (config->hasSheen) {
|
||||
mi->setParameter("sheenColorMap", mDummyTexture, sampler);
|
||||
mi->setParameter("sheenRoughnessMap", mDummyTexture, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
if (mi->getMaterial()->hasParameter("ior")) {
|
||||
mi->setParameter("ior", 1.5f);
|
||||
}
|
||||
if (mi->getMaterial()->hasParameter("reflectance")) {
|
||||
mi->setParameter("reflectance", 0.5f);
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace foo {
|
||||
|
||||
MaterialProvider* createUbershaderLoader(filament::Engine* engine) {
|
||||
return new UbershaderLoader(engine);
|
||||
}
|
||||
|
||||
} // namespace gltfio
|
||||
Reference in New Issue
Block a user