diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index ee340a6088..976d2c2796 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -11,6 +11,7 @@ set(MATERIAL_SRCS materials/aiDefaultMat.mat materials/aiDefaultTrans.mat materials/depthVisualizer.mat + materials/gltf2.mat materials/groundShadow.mat materials/sandboxCloth.mat materials/sandboxLit.mat @@ -69,7 +70,7 @@ set(APP_SRCS app/IBL.cpp app/Image.cpp app/IcoSphere.cpp - app/Sphere.cpp) + app/Sphere.cpp gltf_viewer.cpp) if (APPLE) list(APPEND APP_SRCS app/NativeWindowHelperCocoa.mm) @@ -135,6 +136,7 @@ endfunction() if (NOT ANDROID) add_assimp_demo(frame_generator) + add_assimp_demo(gltf_viewer) add_assimp_demo(lightbulb) add_assimp_demo(material_sandbox) add_assimp_demo(sample_full_pbr) diff --git a/samples/app/GltfMeshAssimp.cpp b/samples/app/GltfMeshAssimp.cpp new file mode 100644 index 0000000000..87a007ec68 --- /dev/null +++ b/samples/app/GltfMeshAssimp.cpp @@ -0,0 +1,6 @@ +// +// Created by Michael Wang on 10/8/18. +// + +#include "GltfMeshAssimp.h" + diff --git a/samples/app/GltfMeshAssimp.h b/samples/app/GltfMeshAssimp.h new file mode 100644 index 0000000000..aac8616269 --- /dev/null +++ b/samples/app/GltfMeshAssimp.h @@ -0,0 +1,14 @@ +// +// Created by Michael Wang on 10/8/18. +// + +#ifndef TNT_GLTFMESHASSIMP_H +#define TNT_GLTFMESHASSIMP_H +#include "MeshAssimp.h" + +class GltfMeshAssimp : public MeshAssimp { + +}; + + +#endif //TNT_GLTFMESHASSIMP_H diff --git a/samples/app/MeshAssimp.cpp b/samples/app/MeshAssimp.cpp index c2ec7725cc..93b08b1f46 100644 --- a/samples/app/MeshAssimp.cpp +++ b/samples/app/MeshAssimp.cpp @@ -35,6 +35,9 @@ #include #include +#include + + using namespace filament; using namespace filamat; using namespace math; @@ -48,6 +51,10 @@ static constexpr uint8_t DEFAULT_TRANSPARENT_PACKAGE[] = { #include "generated/material/aiDefaultTrans.inc" }; +static constexpr uint8_t GLTF2_PACKAGE[] = { + #include "generated/material/gltf2.inc" +}; + MeshAssimp::MeshAssimp(Engine& engine) : mEngine(engine) { } @@ -56,9 +63,17 @@ MeshAssimp::~MeshAssimp() { mEngine.destroy(mIndexBuffer); mEngine.destroy(mDefaultColorMaterial); mEngine.destroy(mDefaultTransparentColorMaterial); + mEngine.destroy(mGltfMaterial); + mEngine.destroy(mDefaultNormalMap); + mEngine.destroy(mDefaultMap); for (Entity renderable : mRenderables) { mEngine.destroy(renderable); } + + for (Texture *tex : mTextures) { + mEngine.destroy(tex); + } + // destroy the Entities itself EntityManager::get().destroy(mRenderables.size(), mRenderables.data()); } @@ -75,6 +90,34 @@ struct State { T const * data() const { return state.data(); } }; +//TODO: Remove redundant method from sample_full_pbr +void loadTex(Engine* engine, const std::string& filePath, Texture** map, bool sRGB = true) { + if (!filePath.empty()) { + Path path(filePath); + if (path.exists()) { + int w, h, n; + unsigned char* data = stbi_load(path.getAbsolutePath().c_str(), &w, &h, &n, 3); + if (data != nullptr) { + *map = Texture::Builder() + .width(uint32_t(w)) + .height(uint32_t(h)) + .levels(0xff) + .format(sRGB ? driver::TextureFormat::SRGB8 : driver::TextureFormat::RGB8) + .build(*engine); + Texture::PixelBufferDescriptor buffer(data, size_t(w * h * 3), + Texture::Format::RGB, Texture::Type::UBYTE, + (driver::BufferDescriptor::Callback) &stbi_image_free); + (*map)->setImage(*engine, 0, std::move(buffer)); + (*map)->generateMipmaps(*engine); + } else { + std::cout << "The texture " << path << " could not be loaded" << std::endl; + } + } else { + std::cout << "The texture " << path << " does not exist" << std::endl; + } + } +} + void MeshAssimp::addFromFile(const Path& path, std::map& materials, bool overrideMaterial) { @@ -91,7 +134,44 @@ void MeshAssimp::addFromFile(const Path& path, // "command buffer" lifetime, we wouldn't need to have to deal with freeing the // std::vectors here. - if (!setFromFile(path, indices, positions, tangents, texCoords, meshes, parents)) { + // Make default map for all textures except Normal + int defaultTexSize = 4; + unsigned char *defaultTexData = (unsigned char *) malloc(defaultTexSize*sizeof(unsigned char*)); + for (int i=0; i < defaultTexSize; i++){ + defaultTexData[i] = static_cast(255); + } + mDefaultMap = Texture::Builder() + .width(uint32_t(1)) + .height(uint32_t(1)) + .levels(0xff) + .format(driver::TextureFormat::SRGB8) + .build(mEngine); + Texture::PixelBufferDescriptor defaultBuffer(defaultTexData, size_t(1 * 1 * 3), + Texture::Format::RGB, Texture::Type::UBYTE + ,(driver::BufferDescriptor::Callback) &free); + mDefaultMap->setImage(mEngine, 0, std::move(defaultBuffer)); + mDefaultMap->generateMipmaps(mEngine); + + //Make default Normal Map + unsigned char *defaultNormalTexData = (unsigned char *) malloc(defaultTexSize*sizeof(unsigned char*)); + defaultNormalTexData[0] = static_cast(128); + defaultNormalTexData[1] = static_cast(128); + defaultNormalTexData[2] = static_cast(255); + defaultNormalTexData[3] = static_cast(0); + + mDefaultNormalMap = Texture::Builder() + .width(uint32_t(1)) + .height(uint32_t(1)) + .levels(0xff) + .format(driver::TextureFormat::SRGB8) + .build(mEngine); + Texture::PixelBufferDescriptor defaultNormalBuffer(defaultNormalTexData, size_t(1 * 1 * 3), + Texture::Format::RGB, Texture::Type::UBYTE + ,(driver::BufferDescriptor::Callback) &free); + mDefaultNormalMap->setImage(mEngine, 0, std::move(defaultNormalBuffer)); + mDefaultNormalMap->generateMipmaps(mEngine); + + if (!setFromFile(path, indices, positions, tangents, texCoords, meshes, parents, materials)) { return; } @@ -146,6 +226,8 @@ void MeshAssimp::addFromFile(const Path& path, materials[AI_DEFAULT_MATERIAL_NAME] = mDefaultColorMaterial->createInstance(); } + + size_t startIndex = mRenderables.size(); mRenderables.resize(startIndex + meshes.size()); EntityManager::get().create(meshes.size(), mRenderables.data() + startIndex); @@ -163,11 +245,17 @@ void MeshAssimp::addFromFile(const Path& path, if (overrideMaterial) { builder.material(partIndex, materials[AI_DEFAULT_MATERIAL_NAME]); + } else { + + //TODO: add usage of gltf materials + //Load all gltf textures auto pos = materials.find(part.material); + if (pos != materials.end()) { builder.material(partIndex, pos->second); } else { + std::cout << "I don't think this should be running" << std::endl; MaterialInstance* colorMaterial; if (part.opacity < 1.0f) { colorMaterial = mDefaultTransparentColorMaterial->createInstance(); @@ -208,8 +296,9 @@ bool MeshAssimp::setFromFile(const Path& file, std::vector& outTangents, std::vector& outTexCoords, std::vector& outMeshes, - std::vector& outParents -) { + std::vector& outParents, + std::map& outMaterials + ) { Importer importer; importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT); @@ -230,6 +319,10 @@ bool MeshAssimp::setFromFile(const Path& file, // we only support triangles aiProcess_Triangulate); + if (!scene){ + std::cout << "no scene" << std::endl; + } + // we could use those, but we want to keep the graph if any, for testing // aiProcess_OptimizeGraph // aiProcess_PreTransformVertices @@ -238,10 +331,10 @@ bool MeshAssimp::setFromFile(const Path& file, countVertices = [scene, &countVertices] (aiNode const* node, size_t& totalVertexCount, size_t& totalIndexCount) { for (size_t i = 0; i < node->mNumMeshes; i++) { - aiMesh const* mesh = scene->mMeshes[node->mMeshes[i]]; + aiMesh const *mesh = scene->mMeshes[node->mMeshes[i]]; totalVertexCount += mesh->mNumVertices; - const aiFace* faces = mesh->mFaces; + const aiFace *faces = mesh->mFaces; const size_t numFaces = mesh->mNumFaces; totalIndexCount += numFaces * faces[0].mNumIndices; } @@ -255,8 +348,8 @@ bool MeshAssimp::setFromFile(const Path& file, size_t depth = 0; const std::function processNode = - [scene, &processNode, &outParents, &deep, &depth, - &outIndices, &outPositions, &outTangents, &outTexCoords, &outMeshes] + [this, file, scene, &processNode, &outParents, &deep, &depth, + &outIndices, &outPositions, &outTangents, &outTexCoords, &outMeshes, &outMaterials] (aiNode const* node, int parentIndex) { mat4f const& current = transpose(*reinterpret_cast(&node->mTransformation)); @@ -271,6 +364,10 @@ bool MeshAssimp::setFromFile(const Path& file, const float bias = 1.0f / 32767.0f; const float factor = (float) (sqrt(1.0 - (double) bias * (double) bias)); + mGltfMaterial = Material::Builder() + .package((void*) GLTF2_PACKAGE, sizeof(GLTF2_PACKAGE)) + .build(mEngine); + for (size_t i = 0; i < node->mNumMeshes; i++) { aiMesh const* mesh = scene->mMeshes[node->mMeshes[i]]; @@ -310,14 +407,142 @@ bool MeshAssimp::setFromFile(const Path& file, uint32_t materialId = mesh->mMaterialIndex; aiMaterial const* material = scene->mMaterials[materialId]; + //Get filepaths for PBR textures + + int texIndex = 0; + aiString baseColorPath; + aiString AOPath; + aiString MRPath; + aiString normalPath; + aiString emissivePath; aiString name; std::string materialName; + if (material->Get(AI_MATKEY_NAME, name) != AI_SUCCESS) { materialName = AI_DEFAULT_MATERIAL_NAME; } else { materialName = name.C_Str(); } + // TODO: Add support for non-image path values and binary gltf + + TextureSampler sampler(TextureSampler::MinFilter::LINEAR_MIPMAP_LINEAR, + TextureSampler::MagFilter::LINEAR, TextureSampler::WrapMode::REPEAT); + sampler.setAnisotropy(8.0f); + + std::string dirName = file.getParent(); + std::cout << "directory: " << dirName << std::endl; + + if (outMaterials.find(materialName) == outMaterials.end()) { + + outMaterials[materialName] = mGltfMaterial->createInstance(); + + // Load property values for gltf files + aiColor4D baseColorFactor; + sRGBColorA baseColorFactorCast{1.0f}; + aiColor3D emissiveFactor; + sRGBColor emissiveFactorCast{1.0f}; + float metallicFactor = 1.0; + float roughnessFactor = 1.0; + +// if(material->Get("$mat.gltf.occlusionTexture.strength", 0, 0, occlusionStrength) == AI_SUCCESS){ +// std::cout << "hey" << std::endl; +// } + + // Load texture images for gltf files + if (material->GetTexture(aiTextureType_DIFFUSE, 1, &baseColorPath) == AI_SUCCESS) { + Texture* baseColorMap = nullptr; + loadTex(&mEngine, dirName + baseColorPath.C_Str(), &baseColorMap); + mTextures.push_back(baseColorMap); + if (baseColorMap != nullptr) { + outMaterials[materialName]->setParameter( + "baseColorMap", baseColorMap, sampler); + } + std::cout << dirName + baseColorPath.C_Str() << std::endl; + } else { + if (mDefaultMap == nullptr){ + std::cout << "default mat is null" << std::endl; + } + outMaterials[materialName]->setParameter("baseColorMap", mDefaultMap, sampler); + } + + if (material->GetTexture(aiTextureType_UNKNOWN, 0, &MRPath) == AI_SUCCESS) { + Texture* metallicRoughnessMap = nullptr; + loadTex(&mEngine, dirName + MRPath.C_Str(), &metallicRoughnessMap, false); + mTextures.push_back(metallicRoughnessMap); + + if (metallicRoughnessMap != nullptr) { + outMaterials[materialName]->setParameter( + "metallicRoughnessMap", metallicRoughnessMap, sampler); + } + std::cout << dirName + MRPath.C_Str() << std::endl; + } else { + outMaterials[materialName]->setParameter("metallicRoughnessMap", mDefaultMap, sampler); + outMaterials[materialName]->setParameter("metallicFactor", mDefaultMetallic); + outMaterials[materialName]->setParameter("roughnessFactor", mDefaultRoughness); + } + + if (material->GetTexture(aiTextureType_LIGHTMAP, 0, &AOPath) == AI_SUCCESS) { + Texture* aoMap = nullptr; + loadTex(&mEngine, dirName + AOPath.C_Str(), &aoMap, false); + mTextures.push_back(aoMap); + + if (aoMap != nullptr) { + outMaterials[materialName]->setParameter( + "aoMap", aoMap, sampler); + } + std::cout << dirName + AOPath.C_Str() << std::endl; + } else { + outMaterials[materialName]->setParameter("aoMap", mDefaultMap, sampler); + } + + if (material->GetTexture(aiTextureType_NORMALS, 0, &normalPath) == AI_SUCCESS) { + Texture* normalMap = nullptr; + loadTex(&mEngine, dirName + normalPath.C_Str(), &normalMap, false); + mTextures.push_back(normalMap); + + if (normalMap != nullptr) { + outMaterials[materialName]->setParameter( + "normalMap", normalMap, sampler); + } + std::cout << dirName + normalPath.C_Str() << std::endl; + } else { + outMaterials[materialName]->setParameter("normalMap", mDefaultNormalMap, sampler); + } + + if (material->GetTexture(aiTextureType_EMISSIVE, 0, &emissivePath) == AI_SUCCESS) { + Texture* emissiveMap = nullptr; + loadTex(&mEngine, dirName + emissivePath.C_Str(), &emissiveMap, false); + mTextures.push_back(emissiveMap); + + if (emissiveMap != nullptr) { + outMaterials[materialName]->setParameter( + "emissiveMap", emissiveMap, sampler); + } + std::cout << dirName + emissivePath.C_Str() << std::endl; + } else { + outMaterials[materialName]->setParameter("emissiveMap", mDefaultMap, sampler); + outMaterials[materialName]->setParameter("emissiveFactor", mDefaultEmissive); + } + + //If the gltf has texture factors, override the default factor values + if(material->Get("$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0, metallicFactor) == AI_SUCCESS){ + outMaterials[materialName]->setParameter("metallicFactor", metallicFactor); + } + if (material->Get("$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0, roughnessFactor) == AI_SUCCESS){ + outMaterials[materialName]->setParameter("roughnessFactor", roughnessFactor); + } + if(material->Get(AI_MATKEY_COLOR_EMISSIVE, emissiveFactor) == AI_SUCCESS){ + emissiveFactorCast = *reinterpret_cast(&emissiveFactor); + outMaterials[materialName]->setParameter("emissiveFactor", emissiveFactorCast); + } + if(material->Get("$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0, baseColorFactor) == AI_SUCCESS){ + baseColorFactorCast = *reinterpret_cast(&baseColorFactor); + outMaterials[materialName]->setParameter("baseColorFactor", baseColorFactorCast); + } + + } + aiColor3D color; sRGBColor baseColor{1.0f}; if (material->Get(AI_MATKEY_COLOR_DIFFUSE, color) == AI_SUCCESS) { @@ -382,6 +607,9 @@ bool MeshAssimp::setFromFile(const Path& file, if (scene) { aiNode const* node = scene->mRootNode; + if(!node){ + std::cout << scene->mNumMeshes << std::endl; + } size_t totalVertexCount = 0; size_t totalIndexCount = 0; diff --git a/samples/app/MeshAssimp.h b/samples/app/MeshAssimp.h index 7aeb64a595..f8896bc23a 100644 --- a/samples/app/MeshAssimp.h +++ b/samples/app/MeshAssimp.h @@ -39,6 +39,7 @@ namespace filament { #include #include #include +#include class MeshAssimp { public: @@ -83,7 +84,10 @@ private: std::vector& outTangents, std::vector& outTexCoords, std::vector& outMeshes, - std::vector& outParents); + std::vector& outParents, + std::map& outMaterials + ); + filament::Engine& mEngine; filament::VertexBuffer* mVertexBuffer = nullptr; @@ -91,8 +95,18 @@ private: filament::Material* mDefaultColorMaterial = nullptr; filament::Material* mDefaultTransparentColorMaterial = nullptr; + filament::Material* mGltfMaterial = nullptr; + + filament::Texture* mDefaultMap = nullptr; + filament::Texture* mDefaultNormalMap = nullptr; + float mDefaultMetallic = 0.0; + float mDefaultRoughness = 0.4; + filament::sRGBColor mDefaultEmissive = filament::sRGBColor({0.0f, 0.0f, 0.0f}); + std::vector mRenderables; + + std::vector mTextures; }; #endif // TNT_FILAMENT_SAMPLE_MESH_ASSIMP_H diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp new file mode 100644 index 0000000000..791fb6599c --- /dev/null +++ b/samples/gltf_viewer.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "app/Config.h" +#include "app/FilamentApp.h" +#include "app/MeshAssimp.h" + +#include + +#include + +#include + +using namespace math; +using namespace filament; +using namespace filamat; +using namespace utils; + +static std::vector g_filenames; + +static std::map g_materialInstances; +static std::unique_ptr g_meshSet; +static const Material* g_material; +static Entity g_light; +static Texture* g_metallicMap = nullptr; +static Texture* g_roughnessMap = nullptr; +static Texture* g_aoMap = nullptr; +static Texture* g_normalMap = nullptr; +static Texture* g_baseColorMap = nullptr; + +static Config g_config; +static struct PbrConfig { + std::string materialDir; + bool clearCoat = false; + bool anisotropy = false; +} g_pbrConfig; + +static void printUsage(char* name) { + std::string exec_name(Path(name).getName()); + std::string usage( + "SAMPLE_PBR is an example of loading PBR assets with base color + packed metallic/roughness\n" + "Usage:\n" + " SAMPLE_PBR [options] \n" + "Options:\n" + " --help, -h\n" + " Prints this message\n\n" + " --ibl=, -i \n" + " Applies an IBL generated by cmgen's deploy option\n\n" + " --split-view, -v\n" + " Splits the window into 4 views\n\n" + " --scale=[number], -s [number]\n" + " Applies uniform scale\n\n" + " --material=, -m \n" + " Directory containing the textures named _*.png where * is:\n" + " - AO\n" + " - Color\n" + " - Metallic\n" + " - Normal\n" + " - Roughness\n" + "\n" + " --clear-coat, -c\n" + " Add a clear coat layer to the material\n\n" + " --anisotropy, -a\n" + " Enable anisotropy on the material\n\n" + ); + const std::string from("SAMPLE_PBR"); + for (size_t pos = usage.find(from); pos != std::string::npos; pos = usage.find(from, pos)) { + usage.replace(pos, from.length(), exec_name); + } + std::cout << usage; +} + +static int handleCommandLineArgments(int argc, char* argv[], Config* config) { + static constexpr const char* OPTSTR = "hi:vs:m:ca"; + static const struct option OPTIONS[] = { + { "help", no_argument, nullptr, 'h' }, + { "ibl", required_argument, nullptr, 'i' }, + { "split-view", no_argument, nullptr, 'v' }, + { "scale", required_argument, nullptr, 's' }, + { "material", required_argument, nullptr, 'm' }, + { "clear-coat", no_argument, nullptr, 'c' }, + { "anisotropy", no_argument, nullptr, 'a' }, + { 0, 0, 0, 0 } // termination of the option list + }; + int opt; + int option_index = 0; + while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &option_index)) >= 0) { + std::string arg(optarg ? optarg : ""); + switch (opt) { + default: + case 'h': + printUsage(argv[0]); + exit(0); + case 'i': + config->iblDirectory = arg; + break; + case 's': + try { + config->scale = std::stof(arg); + } catch (std::invalid_argument& e) { + // keep scale of 1.0 + } catch (std::out_of_range& e) { + // keep scale of 1.0 + } + break; + case 'v': + config->splitView = true; + break; + case 'm': + g_pbrConfig.materialDir = arg; + break; + case 'c': + g_pbrConfig.clearCoat = true; + break; + case 'a': + g_pbrConfig.anisotropy = true; + break; + } + } + + return optind; +} + +static void cleanup(Engine* engine, View* view, Scene* scene) { + for (auto& item : g_materialInstances) { + auto materialInstance = item.second; + engine->destroy(materialInstance); + } + g_meshSet.reset(nullptr); + engine->destroy(g_material); + engine->destroy(g_baseColorMap); + engine->destroy(g_metallicMap); + engine->destroy(g_roughnessMap); + engine->destroy(g_aoMap); + engine->destroy(g_normalMap); + + EntityManager& em = EntityManager::get(); + engine->destroy(g_light); + em.destroy(g_light); +} + +static void setup(Engine* engine, View* view, Scene* scene) { + Path path(g_pbrConfig.materialDir); + std::string name(path.getName()); + + g_meshSet = std::make_unique(*engine); + for (auto& filename : g_filenames) { + g_meshSet->addFromFile(filename, g_materialInstances, false); + } + + auto& rcm = engine->getRenderableManager(); + auto& tcm = engine->getTransformManager(); + for (auto renderable : g_meshSet->getRenderables()) { + if (rcm.hasComponent(renderable)) { + auto ti = tcm.getInstance(renderable); + tcm.setTransform(ti, mat4f{ mat3f(g_config.scale), float3(0.0f, 0.0f, -4.0f) } * + tcm.getWorldTransform(ti)); + scene->addEntity(renderable); + } + } + + g_light = EntityManager::get().create(); + LightManager::Builder(LightManager::Type::DIRECTIONAL) + .color(Color::toLinear({0.98f, 0.92f, 0.89f})) + .intensity(110000) + .direction({0.6, -1, -0.8}) + .build(*engine, g_light); + scene->addEntity(g_light); +} + +int main(int argc, char* argv[]) { + int option_index = handleCommandLineArgments(argc, argv, &g_config); + int num_args = argc - option_index; + if (num_args < 1) { + printUsage(argv[0]); + return 1; + } + + for (int i = option_index; i < argc; i++) { + utils::Path filename = argv[i]; + if (!filename.exists()) { + std::cerr << "file " << argv[option_index] << " not found!" << std::endl; + return 1; + } + g_filenames.push_back(filename); + } + + g_config.title = "gltf_viewer"; + FilamentApp& filamentApp = FilamentApp::get(); + filamentApp.run(g_config, setup, cleanup); + + return 0; +} diff --git a/samples/materials/gltf2.mat b/samples/materials/gltf2.mat new file mode 100644 index 0000000000..e3125147cf --- /dev/null +++ b/samples/materials/gltf2.mat @@ -0,0 +1,85 @@ +material { + name : Lit, + requires : [ + uv0 + ], + shadingModel : lit, + parameters : [ + { + type : sampler2d, + name : baseColorMap + }, + { + type : float4, + name : baseColorFactor + }, + { + type : sampler2d, + name : metallicRoughnessMap + }, + { + type : float, + name : metallicFactor + }, + { + type : float, + name : roughnessFactor + }, + { + type : sampler2d, + name : normalMap + }, + { + type : float, + name : normalScale + }, + { + type : sampler2d, + name : aoMap + }, + { + type : float, + name : aoStrength + }, + { + type : sampler2d, + name : emissiveMap + }, + { + type : float3, + name : emissiveFactor + } + ], +} + +fragment { +// void material(inout MaterialInputs material) { +// material.normal = texture(materialParams_normalMap, getUV0()).xyz * 2.0 - 1.0; +// prepareMaterial(material); +// material.baseColor = texture(materialParams_baseColorMap, getUV0()); +// material.roughness = texture(materialParams_metallicRoughnessMap, getUV0()).g; +// material.metallic = texture(materialParams_metallicRoughnessMap, getUV0()).b; +// material.ambientOcclusion = texture(materialParams_aoMap, getUV0()).r; +// } + +void material(inout MaterialInputs material) { + material.normal = texture(materialParams_normalMap, getUV0()).xyz * 2.0 - 1.0; + prepareMaterial(material); +// material.baseColor.rgb = float3(1.0, 0.75, 0.94); +// material.metallic = 0.0; +// material.roughness = 1.0; +// material.ambientOcclusion = 1.0; + material.baseColor = texture(materialParams_baseColorMap, getUV0()); + material.baseColor.r *= materialParams.baseColorFactor[0]; + material.baseColor.g *= materialParams.baseColorFactor[1]; + material.baseColor.b *= materialParams.baseColorFactor[2]; + material.roughness = materialParams.roughnessFactor * texture(materialParams_metallicRoughnessMap, getUV0()).g; + material.metallic = materialParams.metallicFactor * texture(materialParams_metallicRoughnessMap, getUV0()).b; + material.ambientOcclusion = texture(materialParams_aoMap, getUV0()).r; + material.emissive = texture(materialParams_emissiveMap, getUV0()); + material.emissive.r *= materialParams.emissiveFactor[0]; + material.emissive.g *= materialParams.emissiveFactor[1]; + material.emissive.b *= materialParams.emissiveFactor[2]; + +} +} \ No newline at end of file