Add a Specular Glossiness to Metallic Roughness conversion step to workflows. (#36)

* Update glTF.CPP to 1.5.19
Update driectxtex to 2018.6.1.2

* lower case Document

* Updates for future 1809 (rs5).
Add abilibty to apply Draco mesh compression.
Modify SerializeBinary to allow for BufferView's that we don't understand natively.

* Switch to use a new NuGet package for Draco consumption

* Add a Specular Glossiness to Metallic Roughness conversion step to workflows.
Refactored texture loading and packing utils into generic textures utils.
Resolved packing, resizing and compressing texture issues with sRGB and alpha channels.
Update draco build to allow for ARM.

* small fixes

* Update README with latest features.
Switch draco compression to an option; it makes loading slower.

* Tweek the mesh compression options and language.

* Found and fixed a couple of issues with mesh compression.
This commit is contained in:
Jamie Marconi 2018-08-03 12:14:49 -07:00 коммит произвёл Roberto Sonnino
Родитель 08e261e61d
Коммит 37a54981b8
47 изменённых файлов: 1385 добавлений и 499 удалений

Просмотреть файл

@ -7,9 +7,13 @@ Additionally the repository includes a command line tool that uses these steps i
[![Build status](https://ci.appveyor.com/api/projects/status/4n8m94mpc03dcuxt?svg=true)](https://ci.appveyor.com/project/robertos/gltf-toolkit)
## Features
The current release includes code for:
- Packing PBR material textures using [DirectXTex](http://github.com/Microsoft/DirectXTex) for use with the [MSFT_packing_occlusionRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_occlusionRoughnessMetallic) and [MSFT_packing_normalRoughnessMetallic](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_packing_normalRoughnessMetallic) extensions.
- Compressing textures as BC3, BC5 and BC7 and generate mip maps using [DirectXTex](http://github.com/Microsoft/DirectXTex) for use with the [MSFT_texture_dds](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds) extension.
- Compressing textures as BC3, BC5 or BC7 and generate mip maps using [DirectXTex](http://github.com/Microsoft/DirectXTex) for use with the [MSFT_texture_dds](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds) extension.
- Removing [KHR_materials_pbrSpecularGlossiness](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness) by converting material prameters to metallic-roughness.
- Mesh compression using [KHR_draco_mesh_compression](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression) extension; this can only be used on 1809 and later and should only be used for assets that are transmitted over the network as load time is increased with compression.
- Merging multiple glTF assets into a asset with multiple levels of detail using the [MSFT_lod](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_lod) extension.
- A command line tool that combines these components to create optimized glTF assets for the Windows Mixed Reality Home
- A UWP compatible Windows Runtime component to perform conversions between GLTF and GLB, as well as optimize assets for Windows Mixed Reality at runtime
@ -17,9 +21,11 @@ The current release includes code for:
## Dependencies
This project consumes the following projects through NuGet packages:
- [Microsoft.glTF.CPP](https://www.nuget.org/packages/Microsoft.glTF.CPP), licensed under the MIT license
- [DirectXTex](http://github.com/Microsoft/DirectXTex), licensed under the MIT license
- [RapidJSON](https://github.com/Tencent/rapidjson/), licensed under the MIT license
- [Draco](https://github.com/google/draco/), licensed under Apache License 2.0
## Building

Просмотреть файл

@ -15,10 +15,13 @@ const wchar_t * PARAM_SHARE_MATERIALS = L"-share-materials";
const wchar_t * PARAM_MIN_VERSION = L"-min-version";
const wchar_t * PARAM_PLATFORM = L"-platform";
const wchar_t * PARAM_REPLACE_TEXTURES = L"-replace-textures";
const wchar_t * PARAM_COMPRESS_MESHES = L"-compress-meshes";
const wchar_t * PARAM_VALUE_VERSION_1709 = L"1709";
const wchar_t * PARAM_VALUE_VERSION_1803 = L"1803";
const wchar_t * PARAM_VALUE_VERSION_1809 = L"1809";
const wchar_t * PARAM_VALUE_VERSION_RS3 = L"rs3";
const wchar_t * PARAM_VALUE_VERSION_RS4 = L"rs4";
const wchar_t * PARAM_VALUE_VERSION_RS5 = L"rs5";
const wchar_t * PARAM_VALUE_VERSION_LATEST = L"latest";
const wchar_t * PARAM_VALUE_HOLOGRAPHIC = L"holographic";
const wchar_t * PARAM_VALUE_HOLOLENS= L"hololens";
@ -60,12 +63,13 @@ void CommandLine::PrintHelp()
<< indent << "[" << std::wstring(PARAM_OUTFILE) << L" <output file path>]" << std::endl
<< indent << "[" << std::wstring(PARAM_TMPDIR) << L" <temporary folder>] - default is the system temp folder for the user" << std::endl
<< indent << "[" << std::wstring(PARAM_PLATFORM) << " <" << PARAM_VALUE_ALL << " | " << PARAM_VALUE_HOLOGRAPHIC << " | " << PARAM_VALUE_DESKTOP << ">] - defaults to " << PARAM_VALUE_DESKTOP << std::endl
<< indent << "[" << std::wstring(PARAM_MIN_VERSION) << " <" << PARAM_VALUE_VERSION_1709 << " | " << PARAM_VALUE_VERSION_1803 << " | " << PARAM_VALUE_VERSION_LATEST << ">] - defaults to " << PARAM_VALUE_VERSION_1709 << std::endl
<< indent << "[" << std::wstring(PARAM_MIN_VERSION) << " <" << PARAM_VALUE_VERSION_1709 << " | " << PARAM_VALUE_VERSION_1803 << " | " << PARAM_VALUE_VERSION_1809 << " | " << PARAM_VALUE_VERSION_LATEST << ">] - defaults to " << PARAM_VALUE_VERSION_1709 << std::endl
<< indent << "[" << std::wstring(PARAM_LOD) << " <path to each lower LOD asset in descending order of quality>]" << std::endl
<< indent << "[" << std::wstring(PARAM_SCREENCOVERAGE) << " <LOD screen coverage values>]" << std::endl
<< indent << "[" << std::wstring(PARAM_SHARE_MATERIALS) << "] - disabled if not present" << std::endl
<< indent << "[" << std::wstring(PARAM_MAXTEXTURESIZE) << " <Max texture size in pixels>] - defaults to 512" << std::endl
<< indent << "[" << std::wstring(PARAM_REPLACE_TEXTURES) << "] - disabled if not present" << std::endl
<< indent << "[" << std::wstring(PARAM_COMPRESS_MESHES) << "] - compress meshes with Draco" << std::endl
<< std::endl
<< "Example:" << std::endl
<< indent << "WindowsMRAssetConverter FileToConvert.gltf "
@ -85,7 +89,7 @@ void CommandLine::ParseCommandLineArguments(
int argc, wchar_t *argv[],
std::wstring& inputFilePath, AssetType& inputAssetType, std::wstring& outFilePath, std::wstring& tempDirectory,
std::vector<std::wstring>& lodFilePaths, std::vector<double>& screenCoveragePercentages, size_t& maxTextureSize,
bool& shareMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures)
bool& shareMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures, bool& compressMeshes)
{
CommandLineParsingState state = CommandLineParsingState::Initial;
@ -103,6 +107,7 @@ void CommandLine::ParseCommandLineArguments(
minVersion = MIN_VERSION_DEFAULT;
targetPlatforms = PLATFORM_DEFAULT;
replaceTextures = false;
compressMeshes = false;
state = CommandLineParsingState::InputRead;
@ -157,6 +162,18 @@ void CommandLine::ParseCommandLineArguments(
replaceTextures = true;
state = CommandLineParsingState::InputRead;
}
else if (param == PARAM_COMPRESS_MESHES)
{
if (minVersion >= CommandLine::Version::Version1809)
{
compressMeshes = true;
}
else
{
throw std::invalid_argument("Invalid min version specified with mesh compression; must be at least 1809.");
}
state = CommandLineParsingState::InputRead;
}
else
{
switch (state)
@ -190,6 +207,10 @@ void CommandLine::ParseCommandLineArguments(
{
minVersion = Version::Version1803;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_1809) == 0 || _wcsicmp(param.c_str(), PARAM_VALUE_VERSION_RS5) == 0)
{
minVersion = Version::Version1809;
}
else if (_wcsicmp(param.c_str(), PARAM_VALUE_VERSION_LATEST) == 0)
{
minVersion = Version::Latest;

Просмотреть файл

@ -19,7 +19,8 @@ namespace CommandLine
{
Version1709, // Fall Creators Update (RS3)
Version1803, // Spring Creators Update (RS4)
Latest = Version1803
Version1809, // Fall 2018 Update (RS5)
Latest = Version1809
};
void PrintHelp();
@ -28,6 +29,6 @@ namespace CommandLine
int argc, wchar_t *argv[],
std::wstring& inputFilePath, AssetType& inputAssetType, std::wstring& outFilePath, std::wstring& tempDirectory,
std::vector<std::wstring>& lodFilePaths, std::vector<double>& screenCoveragePercentages, size_t& maxTextureSize,
bool& sharedMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures);
bool& sharedMaterials, Version& minVersion, Platform& targetPlatforms, bool& replaceTextures, bool& compressMeshes);
};

Просмотреть файл

@ -5,13 +5,16 @@
#include <GLTFSDK/GLTF.h>
#include <GLTFSDK/Deserialize.h>
#include <GLTFSDK/IStreamFactory.h>
#include <GLTFSDK/IStreamWriter.h>
#include <GLTFSDK/GLBResourceReader.h>
#include <GLTFSDK/ExtensionsKHR.h>
#include <GLTFTexturePackingUtils.h>
#include <GLTFTextureCompressionUtils.h>
#include <GLTFSpecularGlossinessUtils.h>
#include <GLTFLODUtils.h>
#include <SerializeBinary.h>
#include <GLBtoGLTF.h>
#include <GLTFMeshCompressionUtils.h>
#include "CommandLine.h"
#include "FileSystem.h"
@ -42,53 +45,44 @@ private:
const std::wstring m_uriBase;
};
class GLBStreamFactory : public Microsoft::glTF::IStreamFactory
class GLBStreamWriter : public Microsoft::glTF::IStreamWriter
{
public:
GLBStreamFactory(const std::wstring& filename) :
m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out)),
m_tempStream(std::make_shared<std::stringstream>(std::ios_base::binary | std::ios_base::in | std::ios_base::out))
GLBStreamWriter(const std::wstring& filename) :
m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out))
{ }
std::shared_ptr<std::istream> GetInputStream(const std::string&) const override
{
throw std::logic_error("Not implemented");
}
std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const override
{
return m_stream;
}
std::shared_ptr<std::iostream> GetTemporaryStream(const std::string&) const override
{
return m_tempStream;
}
private:
std::shared_ptr<std::ofstream> m_stream;
std::shared_ptr<std::stringstream> m_tempStream;
};
GLTFDocument LoadAndConvertDocumentForWindowsMR(
Document LoadAndConvertDocumentForWindowsMR(
std::wstring& inputFilePath,
AssetType inputAssetType,
const std::wstring& tempDirectory,
size_t maxTextureSize,
TexturePacking packing,
bool processTextures = true,
bool retainOriginalImages = true)
bool processTextures,
bool retainOriginalImages,
bool meshCompression)
{
// Load the document
std::experimental::filesystem::path inputFilePathFS(inputFilePath);
std::wstring inputFileName = inputFilePathFS.filename();
std::wcout << L"Loading input document: " << inputFileName << L"..." << std::endl;
std::string tempDirectoryA(tempDirectory.begin(), tempDirectory.end());
if (inputAssetType == AssetType::GLB)
{
// Convert the GLB to GLTF in the temp directory
std::string inputFilePathA(inputFilePath.begin(), inputFilePath.end());
std::string tempDirectoryA(tempDirectory.begin(), tempDirectory.end());
// inputGltfName is the path to the converted GLTF without extension
std::wstring inputGltfName = inputFilePathFS.stem();
@ -100,18 +94,22 @@ GLTFDocument LoadAndConvertDocumentForWindowsMR(
}
auto stream = std::make_shared<std::ifstream>(inputFilePath, std::ios::in);
GLTFDocument document = DeserializeJson(*stream);
Document document = Deserialize(*stream, KHR::GetKHRExtensionDeserializer());
// Get the base path from where to read all the assets
GLTFStreamReader streamReader(FileSystem::GetBasePath(inputFilePath));
auto streamReader = std::make_shared<GLTFStreamReader>(FileSystem::GetBasePath(inputFilePath));
if (processTextures)
{
std::wcout << L"Specular Glossiness conversion..." << std::endl;
// 0. Specular Glossiness conversion
document = GLTFSpecularGlossinessUtils::ConvertMaterials(streamReader, document, tempDirectoryA);
std::wcout << L"Packing textures..." << std::endl;
// 1. Texture Packing
auto tempDirectoryA = std::string(tempDirectory.begin(), tempDirectory.end());
document = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(streamReader, document, packing, tempDirectoryA);
std::wcout << L"Compressing textures - this can take a few minutes..." << std::endl;
@ -120,6 +118,13 @@ GLTFDocument LoadAndConvertDocumentForWindowsMR(
document = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(streamReader, document, tempDirectoryA, maxTextureSize, retainOriginalImages);
}
if (meshCompression)
{
std::wcout << L"Compressing meshes - this can take a few minutes..." << std::endl;
document = GLTFMeshCompressionUtils::CompressMeshes(streamReader, document, {}, tempDirectoryA);
}
return document;
}
@ -148,10 +153,11 @@ int wmain(int argc, wchar_t *argv[])
CommandLine::Version minVersion;
CommandLine::Platform targetPlatforms;
bool replaceTextures;
bool meshCompression = false;
CommandLine::ParseCommandLineArguments(
argc, argv, inputFilePath, inputAssetType, outFilePath, tempDirectory, lodFilePaths, screenCoveragePercentages,
maxTextureSize, shareMaterials, minVersion, targetPlatforms, replaceTextures);
maxTextureSize, shareMaterials, minVersion, targetPlatforms, replaceTextures, meshCompression);
TexturePacking packing = TexturePacking::None;
@ -182,10 +188,14 @@ int wmain(int argc, wchar_t *argv[])
compatibleVersionsText += L"Desktop (version 1709+)";
}
else
else if (minVersion == CommandLine::Version::Version1803)
{
compatibleVersionsText += L"Desktop (version 1803+)";
}
else
{
compatibleVersionsText += L"Desktop (version 1809+)";
}
}
std::wcout << L"\nThis will generate an asset compatible with " << compatibleVersionsText << L"\n" << std::endl;
@ -193,14 +203,14 @@ int wmain(int argc, wchar_t *argv[])
// Load document, and perform steps:
// 1. Texture Packing
// 2. Texture Compression
auto document = LoadAndConvertDocumentForWindowsMR(inputFilePath, inputAssetType, tempDirectory, maxTextureSize, packing, true /* processTextures */, !replaceTextures);
auto document = LoadAndConvertDocumentForWindowsMR(inputFilePath, inputAssetType, tempDirectory, maxTextureSize, packing, true /* processTextures */, !replaceTextures, meshCompression);
// 3. LOD Merging
if (lodFilePaths.size() > 0)
{
std::wcout << L"Merging LODs..." << std::endl;
std::vector<GLTFDocument> lodDocuments;
std::vector<Document> lodDocuments;
std::vector<std::wstring> lodDocumentRelativePaths;
lodDocuments.push_back(document);
@ -210,7 +220,7 @@ int wmain(int argc, wchar_t *argv[])
auto lod = lodFilePaths[i];
auto subFolder = FileSystem::CreateSubFolder(tempDirectory, L"lod" + std::to_wstring(i + 1));
lodDocuments.push_back(LoadAndConvertDocumentForWindowsMR(lod, AssetTypeUtils::AssetTypeFromFilePath(lod), subFolder, maxTextureSize, packing, !shareMaterials, !replaceTextures));
lodDocuments.push_back(LoadAndConvertDocumentForWindowsMR(lod, AssetTypeUtils::AssetTypeFromFilePath(lod), subFolder, maxTextureSize, packing, !shareMaterials, !replaceTextures, meshCompression));
lodDocumentRelativePaths.push_back(FileSystem::GetRelativePathWithTrailingSeparator(FileSystem::GetBasePath(inputFilePath), FileSystem::GetBasePath(lod)));
}
@ -251,8 +261,8 @@ int wmain(int argc, wchar_t *argv[])
return accessor.componentType;
};
GLTFStreamReader streamReader(FileSystem::GetBasePath(inputFilePath));
SerializeBinary(document, streamReader, std::make_unique<GLBStreamFactory>(outFilePath), accessorConversion);
auto streamReader = std::make_shared<GLTFStreamReader>(FileSystem::GetBasePath(inputFilePath));
SerializeBinary(document, streamReader, std::make_shared<GLBStreamWriter>(outFilePath), accessorConversion);
std::wcout << L"Done!" << std::endl;
std::wcout << L"Output file: " << outFilePath << std::endl;

Просмотреть файл

@ -206,15 +206,17 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets" Condition="Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" />
<Import Project="..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets" Condition="Exists('..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets" Condition="Exists('..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets" Condition="Exists('..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="directxtex_desktop_2015" version="2018.2.9.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.3.46.0" targetFramework="native" />
<package id="directxtex_desktop_2015" version="2018.6.1.2" targetFramework="native" />
<package id="draco.CPP" version="1.3.3.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.5.19.0" targetFramework="native" />
<package id="rapidjson.temprelease" version="0.0.2.20" targetFramework="native" />
</packages>

Просмотреть файл

@ -5,7 +5,7 @@
#include <CppUnitTest.h>
#include "GLTFSDK/IStreamWriter.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Deserialize.h"
#include "GLTFSDK/GLBResourceWriter.h"
#include "GLTFSDK/GLBResourceReader.h"
@ -23,31 +23,20 @@ using namespace Microsoft::glTF::Toolkit;
namespace Microsoft::glTF::Toolkit::Test
{
class InMemoryStreamFactory : public Microsoft::glTF::IStreamFactory
class InMemoryStream : public Microsoft::glTF::IStreamWriter
{
public:
InMemoryStreamFactory(std::shared_ptr<std::stringstream> stream) :
m_stream(stream),
m_tempStream(std::make_shared<std::stringstream>(std::ios_base::app | std::ios_base::binary | std::ios_base::in | std::ios_base::out))
InMemoryStream(std::shared_ptr<std::stringstream> stream) :
m_stream(stream)
{ }
std::shared_ptr<std::istream> GetInputStream(const std::string& uri) const override
std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const
{
return uri == GLB_BUFFER_ID ? m_tempStream : m_stream;
return m_stream;
}
std::shared_ptr<std::ostream> GetOutputStream(const std::string& uri) const override
{
return uri == GLB_BUFFER_ID ? m_tempStream : m_stream;
}
std::shared_ptr<std::iostream> GetTemporaryStream(const std::string&) const override
{
return m_tempStream;
}
private:
std::shared_ptr<std::stringstream> m_stream;
std::shared_ptr<std::stringstream> m_tempStream;
};
TEST_CLASS(GLBSerializerTests)
@ -60,24 +49,24 @@ namespace Microsoft::glTF::Toolkit::Test
return json;
}
static std::shared_ptr<GLTFDocument> ImportGLB(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& glbStream)
static std::shared_ptr<Document> ImportGLB(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& glbStream)
{
GLBResourceReader resourceReader(*streamReader, glbStream);
GLBResourceReader resourceReader(streamReader, glbStream);
auto json = resourceReader.GetJson();
auto doc = DeserializeJson(json);
auto doc = Deserialize(json);
return std::make_shared<GLTFDocument>(doc);
return std::make_shared<Document>(doc);
}
static std::shared_ptr<GLTFDocument> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)
static std::shared_ptr<Document> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)
{
GLTFResourceReader resourceReader(*streamReader);
GLTFResourceReader resourceReader(streamReader);
auto json = std::string(std::istreambuf_iterator<char>(*stream), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(json);
auto doc = Deserialize(json);
return std::make_shared<GLTFDocument>(doc);
return std::make_shared<Document>(doc);
}
const char* c_waterBottleJson = "Resources\\gltf\\WaterBottle\\WaterBottle.gltf";
@ -90,17 +79,17 @@ namespace Microsoft::glTF::Toolkit::Test
{
// Deserialize input json
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson);
// Serialize GLTFDocument to GLB
TestStreamReader streamReader(TestUtils::GetAbsolutePath(c_waterBottleJson));
// Serialize Document to GLB
auto streamReader = std::make_shared<TestStreamReader>(TestUtils::GetAbsolutePath(c_waterBottleJson));
auto stream = std::make_shared<std::stringstream>(std::ios_base::app | std::ios_base::binary | std::ios_base::in | std::ios_base::out);
SerializeBinary(doc, streamReader, std::make_unique<InMemoryStreamFactory>(stream));
SerializeBinary(doc, streamReader, std::make_shared<InMemoryStream>(stream));
// Deserialize the GLB again
auto glbReader = std::make_unique<GLBResourceReader>(streamReader, stream);
auto outputJson = glbReader->GetJson();
auto outputDoc = DeserializeJson(outputJson);
auto outputDoc = Deserialize(outputJson);
// Check some structural elements
Assert::AreEqual(doc.nodes.Size(), outputDoc.nodes.Size());

Просмотреть файл

@ -5,7 +5,7 @@
#include <CppUnitTest.h>
#include <numeric>
#include <GLTFSDK/GLTFDocument.h>
#include <GLTFSDK/Document.h>
#include <GLTFSDK/Deserialize.h>
#include <GLTFSDK/Serialize.h>
#include <GLBtoGLTF.h>
@ -37,9 +37,9 @@ namespace Microsoft::glTF::Toolkit::Test
}
// Setup a GLTF document with 3 bufferviews and 2 images
GLTFDocument setupGLBDocument1()
Document setupGLBDocument1()
{
GLTFDocument glbDoc("0", {});
Document glbDoc;
Scene sc; sc.id = "0";
glbDoc.scenes.Append(std::move(sc));
Accessor acc0; acc0.bufferViewId = "0"; acc0.byteOffset = 0; acc0.id = "0";
@ -88,7 +88,7 @@ namespace Microsoft::glTF::Toolkit::Test
{
TEST_METHOD(GLBtoGLTF_NoImagesJSON)
{
GLTFDocument glbDoc("0", {});
Document glbDoc;
Scene s1; s1.id = "0";
glbDoc.scenes.Append(std::move(s1));
Accessor acc; acc.bufferViewId = "0"; acc.byteOffset = 36; acc.id = "0";
@ -112,7 +112,7 @@ namespace Microsoft::glTF::Toolkit::Test
{
glbDoc.images.Append(std::move(img));
});
GLTFDocument expectedGLTFDoc("0", {});
Document expectedGLTFDoc;
Scene s2; s2.id = "0";
expectedGLTFDoc.scenes.Append(std::move(s2));
auto actualGLTFDoc = GLBToGLTF::CreateGLTFDocument(glbDoc, "name");
@ -125,7 +125,7 @@ namespace Microsoft::glTF::Toolkit::Test
TEST_METHOD(GLBtoGLTF_ImagesWithOffsetJSON)
{
GLTFDocument glbDoc("0", {});
Document glbDoc;
Scene sc; sc.id = "0";
glbDoc.scenes.Append(std::move(sc));
Accessor acc0; acc0.bufferViewId = "0"; acc0.byteOffset = 0; acc0.id = "0";
@ -161,7 +161,7 @@ namespace Microsoft::glTF::Toolkit::Test
});
auto actualGLTFDoc = GLBToGLTF::CreateGLTFDocument(glbDoc, "test");
GLTFDocument expectedGLTFDoc("0", {});
Document expectedGLTFDoc;
Accessor exp_acc0; exp_acc0.bufferViewId = "0"; exp_acc0.byteOffset = 0; exp_acc0.id = "0";
Accessor exp_acc1; exp_acc1.bufferViewId = "1"; exp_acc1.byteOffset = 4; exp_acc1.id = "3";
expectedGLTFDoc.accessors.Append(std::move(exp_acc0));

Просмотреть файл

@ -5,12 +5,13 @@
#include <CppUnitTest.h>
#include "GLTFSDK/IStreamWriter.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Serialize.h"
#include "GLTFSDK/Deserialize.h"
#include "GLTFSDK/GLBResourceReader.h"
#include "GLTFSDK/GLTFResourceWriter.h"
#include "GLTFSDK/RapidJsonUtils.h"
#include "GLTFSDK/ExtensionsKHR.h"
#include "GLTFLODUtils.h"
@ -25,7 +26,7 @@ namespace Microsoft::glTF::Toolkit::Test
{
TEST_CLASS(GLTFLODUtilsTests)
{
static void CheckGLTFLODNodeCountAgainstOriginal(GLTFDocument& doc, GLTFDocument& docWLod, size_t lodCount)
static void CheckGLTFLODNodeCountAgainstOriginal(Document& doc, Document& docWLod, size_t lodCount)
{
// All elements in the lod'd doc should be double the original
Assert::IsTrue(doc.buffers.Size() * lodCount == docWLod.buffers.Size());
@ -48,9 +49,9 @@ namespace Microsoft::glTF::Toolkit::Test
auto readwriter = std::make_shared<StreamMock>();
try
{
GLTFResourceReader resourceReader(*readwriter);
GLTFResourceReader resourceReader(readwriter);
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());
auto lods = GLTFLODUtils::ParseDocumentNodeLODs(doc);
Assert::IsTrue(GLTFLODUtils::NumberOfNodeLODLevels(doc, lods) == expectedNumberOfLods);
@ -63,14 +64,14 @@ namespace Microsoft::glTF::Toolkit::Test
}
}
static std::shared_ptr<GLTFDocument> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)
static std::shared_ptr<Document> ImportGLTF(const std::shared_ptr<IStreamReader>& streamReader, const std::shared_ptr<std::istream>& stream)
{
GLTFResourceReader resourceReader(*streamReader);
GLTFResourceReader resourceReader(streamReader);
auto json = std::string(std::istreambuf_iterator<char>(*stream), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(json);
auto doc = Deserialize(json, KHR::GetKHRExtensionDeserializer());
return std::make_shared<GLTFDocument>(doc);
return std::make_shared<Document>(doc);
}
const char* c_cubeAsset3DJson = "Resources\\gltf\\cubeAsset3D.gltf";
@ -92,17 +93,17 @@ namespace Microsoft::glTF::Toolkit::Test
try
{
// Deserialize input json
GLTFResourceReader resourceReader(*readwriter);
GLTFResourceReader resourceReader(readwriter);
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());
std::vector<GLTFDocument> docs;
std::vector<Document> docs;
docs.push_back(doc);
docs.push_back(doc);
auto newlodgltfDoc = GLTFLODUtils::MergeDocumentsAsLODs(docs);
// Serialize GLTFDocument back to json
auto outputJson = Serialize(newlodgltfDoc);
// Serialize Document back to json
auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());
CheckGLTFLODNodeCountAgainstOriginal(doc, newlodgltfDoc, 2);
@ -146,11 +147,11 @@ namespace Microsoft::glTF::Toolkit::Test
try
{
// Deserialize input json
GLTFResourceReader resourceReader(*readwriter);
GLTFResourceReader resourceReader(readwriter);
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());
std::vector<GLTFDocument> docs;
std::vector<Document> docs;
docs.push_back(doc);
docs.push_back(doc);
docs.push_back(doc);
@ -188,8 +189,8 @@ namespace Microsoft::glTF::Toolkit::Test
Assert::IsTrue(containsLOD2RootNode);
Assert::IsTrue(containsLOD2PolyNode);
// Serialize GLTFDocument back to json
auto outputJson = Serialize(newlodgltfDoc);
// Serialize Document back to json
auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());
}
catch (std::exception ex)
{
@ -206,11 +207,11 @@ namespace Microsoft::glTF::Toolkit::Test
try
{
// Deserialize input json
GLTFResourceReader resourceReader(*readwriter);
GLTFResourceReader resourceReader(readwriter);
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());
std::vector<GLTFDocument> docs;
std::vector<Document> docs;
docs.push_back(doc);
docs.push_back(doc);
docs.push_back(doc);
@ -240,8 +241,8 @@ namespace Microsoft::glTF::Toolkit::Test
Assert::IsTrue(rootNodeContainsCoverage);
// Serialize GLTFDocument back to json
auto outputJson = Serialize(newlodgltfDoc);
// Serialize Document back to json
auto outputJson = Serialize(newlodgltfDoc, KHR::GetKHRExtensionSerializer());
}
catch (std::exception ex)
{
@ -287,13 +288,13 @@ namespace Microsoft::glTF::Toolkit::Test
try
{
// Deserialize input json
GLTFResourceReader resourceReader(*readwriter);
GLTFResourceReader resourceReader(readwriter);
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson, KHR::GetKHRExtensionDeserializer());
// Serialize GLTFDocument back to json
auto outputJson = Serialize(doc);
auto outputDoc = DeserializeJson(outputJson);
// Serialize Document back to json
auto outputJson = Serialize(doc, KHR::GetKHRExtensionSerializer());
auto outputDoc = Deserialize(outputJson, KHR::GetKHRExtensionDeserializer());
// Compare input and output GLTFDocuments
Assert::AreNotSame(doc == outputDoc, true, L"Input gltf and output gltf are not equal");

Просмотреть файл

@ -4,7 +4,7 @@
#include <CppUnitTest.h>
#include "GLTFSDK/IStreamWriter.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Serialize.h"
#include "GLTFSDK/Deserialize.h"
#include "GLTFSDK/GLBResourceReader.h"
@ -63,7 +63,7 @@ namespace Microsoft::glTF::Toolkit::Test
// This asset has all textures
TestUtils::LoadAndExecuteGLTFTest(c_waterBottleORMJson, [](auto doc, auto path)
{
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(TestStreamReader(path), doc, doc.textures.Get("0"), TextureCompression::None, "");
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get("0"), TextureCompression::None, "");
// Check that nothing changed
Assert::IsTrue(doc == compressedDoc);
@ -78,7 +78,7 @@ namespace Microsoft::glTF::Toolkit::Test
auto maxTextureSize = std::numeric_limits<size_t>::max();
auto generateMipMaps = false;
auto retainOriginalImages = true;
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(TestStreamReader(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto originalTexture = doc.textures.Get("0");
auto compressedTexture = compressedDoc.textures.Get("0");
@ -117,7 +117,7 @@ namespace Microsoft::glTF::Toolkit::Test
auto maxTextureSize = std::numeric_limits<size_t>::max();
auto generateMipMaps = false;
auto retainOriginalImages = false;
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(TestStreamReader(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto originalTexture = doc.textures.Get("0");
auto compressedTexture = compressedDoc.textures.Get("0");
@ -159,7 +159,7 @@ namespace Microsoft::glTF::Toolkit::Test
auto maxTextureSize = std::numeric_limits<size_t>::max();
auto generateMipMaps = true;
auto retainOriginalImages = true;
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(TestStreamReader(path), doc, doc.textures.Get("0"), TextureCompression::BC7, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get("0"), TextureCompression::BC7, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto originalTexture = doc.textures.Get("0");
auto compressedTexture = compressedDoc.textures.Get("0");
@ -197,7 +197,7 @@ namespace Microsoft::glTF::Toolkit::Test
{
auto maxTextureSize = std::numeric_limits<size_t>::max();
auto retainOriginalImages = true;
auto compressedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(TestStreamReader(path), doc, "", maxTextureSize, retainOriginalImages);
auto compressedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(std::make_shared<TestStreamReader>(path), doc, "", maxTextureSize, retainOriginalImages);
// Check that the materials and textures have not been replaced
// Check that the textures has not been replaced
@ -211,12 +211,12 @@ namespace Microsoft::glTF::Toolkit::Test
auto compressedMaterial = compressedDoc.materials.Get("0");
// Check that all relevant textures now have the extension
Assert::IsTrue(doc.textures.Get(originalMaterial.metallicRoughness.baseColorTextureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.metallicRoughness.baseColorTextureId).extensions.size());
Assert::IsTrue(doc.textures.Get(originalMaterial.emissiveTextureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.emissiveTextureId).extensions.size());
Assert::IsTrue(doc.textures.Get(originalMaterial.metallicRoughness.baseColorTexture.textureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.metallicRoughness.baseColorTexture.textureId).extensions.size());
Assert::IsTrue(doc.textures.Get(originalMaterial.emissiveTexture.textureId).extensions.size() + 1 == compressedDoc.textures.Get(compressedMaterial.emissiveTexture.textureId).extensions.size());
// TODO: read the WMR (MSFT_packing...) textures as well
// Check the new extension is not empty
auto ddsExtension = compressedDoc.textures.Get(compressedMaterial.emissiveTextureId).extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));
auto ddsExtension = compressedDoc.textures.Get(compressedMaterial.emissiveTexture.textureId).extensions.at(std::string(EXTENSION_MSFT_TEXTURE_DDS));
Assert::IsFalse(ddsExtension.empty());
// Check the new extension contains a DDS image
@ -241,7 +241,7 @@ namespace Microsoft::glTF::Toolkit::Test
auto maxTextureSize = std::numeric_limits<size_t>::max();
auto generateMipMaps = false;
auto retainOriginalImages = true;
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(TestStreamReader(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto compressedDoc = GLTFTextureCompressionUtils::CompressTextureAsDDS(std::make_shared<TestStreamReader>(path), doc, doc.textures.Get("0"), TextureCompression::BC3, "", maxTextureSize, generateMipMaps, retainOriginalImages);
auto originalUri = compressedDoc.images.Get("0").uri;
auto compressedUri = compressedDoc.images.Get("1").uri;

Просмотреть файл

@ -4,7 +4,7 @@
#include <CppUnitTest.h>
#include "GLTFSDK/IStreamWriter.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Serialize.h"
#include "GLTFSDK/Deserialize.h"
#include "GLTFSDK/GLBResourceReader.h"
@ -36,7 +36,7 @@ namespace Microsoft::glTF::Toolkit::Test
TestUtils::LoadAndExecuteGLTFTest(gltfRelativePath, [packing](auto doc, auto path)
{
auto material = doc.materials.Elements()[0];
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(TestStreamReader(path), doc, material, packing, "");
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, packing, "");
auto packedMaterial = packedDoc.materials.Elements()[0];
// Check that the material changed
@ -72,7 +72,7 @@ namespace Microsoft::glTF::Toolkit::Test
Assert::IsTrue(ormJson[MSFT_PACKING_ORM_RMOTEXTURE_KEY].HasMember(MSFT_PACKING_INDEX_KEY));
}
if (!material.normalTexture.id.empty())
if (!material.normalTexture.textureId.empty())
{
// Check the new extension contains a normal texture
Assert::IsTrue(ormJson[MSFT_PACKING_ORM_NORMALTEXTURE_KEY].IsObject());
@ -106,7 +106,7 @@ namespace Microsoft::glTF::Toolkit::Test
TestUtils::LoadAndExecuteGLTFTest(c_cubeAsset3DJson, [](auto doc, auto path)
{
auto material = doc.materials.Elements()[0];
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(TestStreamReader(path), doc, material, TexturePacking::OcclusionRoughnessMetallic, "");
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, TexturePacking::OcclusionRoughnessMetallic, "");
// Check that nothing changed
Assert::IsTrue(doc == packedDoc);
@ -119,7 +119,7 @@ namespace Microsoft::glTF::Toolkit::Test
TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [](auto doc, auto path)
{
auto material = doc.materials.Elements()[0];
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(TestStreamReader(path), doc, material, TexturePacking::None, "");
auto packedDoc = GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, material, TexturePacking::None, "");
// Check that nothing changed
Assert::IsTrue(doc == packedDoc);
@ -163,7 +163,7 @@ namespace Microsoft::glTF::Toolkit::Test
// This asset has no materials
TestUtils::LoadAndExecuteGLTFTest(c_cubeAsset3DJson, [](auto doc, auto path)
{
auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(TestStreamReader(path), doc, TexturePacking::OcclusionRoughnessMetallic, "");
auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::OcclusionRoughnessMetallic, "");
// Check that nothing changed
Assert::IsTrue(doc == packedDoc);
@ -175,7 +175,7 @@ namespace Microsoft::glTF::Toolkit::Test
// This asset has all textures
TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [](auto doc, auto path)
{
auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(TestStreamReader(path), doc, TexturePacking::None, "");
auto packedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::None, "");
// Check that nothing changed
Assert::IsTrue(doc == packedDoc);
@ -184,18 +184,18 @@ namespace Microsoft::glTF::Toolkit::Test
TEST_METHOD(GLTFTexturePackingUtils_PackAllWithOneMaterial)
{
std::unique_ptr<GLTFDocument> documentPackedSingleTexture;
std::unique_ptr<GLTFDocument> documentPackedAllTextures;
std::unique_ptr<Document> documentPackedSingleTexture;
std::unique_ptr<Document> documentPackedAllTextures;
// This asset has all textures
TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [&documentPackedSingleTexture](auto doc, auto path)
{
documentPackedSingleTexture = std::make_unique<GLTFDocument>(GLTFTexturePackingUtils::PackMaterialForWindowsMR(TestStreamReader(path), doc, doc.materials.Elements()[0], TexturePacking::OcclusionRoughnessMetallic, ""));
documentPackedSingleTexture = std::make_unique<Document>(GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::make_shared<TestStreamReader>(path), doc, doc.materials.Elements()[0], TexturePacking::OcclusionRoughnessMetallic, ""));
});
TestUtils::LoadAndExecuteGLTFTest(c_waterBottleJson, [&documentPackedAllTextures](auto doc, auto path)
{
documentPackedAllTextures = std::make_unique<GLTFDocument>(GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(TestStreamReader(path), doc, TexturePacking::OcclusionRoughnessMetallic, ""));
documentPackedAllTextures = std::make_unique<Document>(GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::make_shared<TestStreamReader>(path), doc, TexturePacking::OcclusionRoughnessMetallic, ""));
});
// Assert there's one material

Просмотреть файл

@ -7,7 +7,7 @@
#include <memory>
#include "GLTFSDK/IStreamWriter.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Serialize.h"
#include "GLTFSDK/Deserialize.h"
@ -114,7 +114,7 @@ namespace Microsoft::glTF::Toolkit::Test
return tempStream;
}
typedef std::function<void(const GLTFDocument& doc, const std::string& gltfAbsolutePath)> GLTFAction;
typedef std::function<void(const Document& doc, const std::string& gltfAbsolutePath)> GLTFAction;
static void LoadAndExecuteGLTFTest(const char * gltfRelativePath, GLTFAction action)
{
@ -125,7 +125,7 @@ namespace Microsoft::glTF::Toolkit::Test
{
// Deserialize input json
auto inputJson = std::string(std::istreambuf_iterator<char>(*input), std::istreambuf_iterator<char>());
auto doc = DeserializeJson(inputJson);
auto doc = Deserialize(inputJson);
action(doc, absolutePath);
}

Просмотреть файл

@ -120,5 +120,5 @@
}
],
"scene": 0,
"extensionsUsed": ["KHR_materials_PBRSpecularGlossiness"]
"extensionsUsed": ["KHR_materials_pbrSpecularGlossiness"]
}

Просмотреть файл

@ -97,5 +97,5 @@
}
],
"scene": 0,
"extensionsUsed": ["KHR_materials_PBRSpecularGlossiness"]
"extensionsUsed": ["KHR_materials_pbrSpecularGlossiness", "MSFT_lod"]
}

Просмотреть файл

@ -237,15 +237,15 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets" Condition="Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" />
<Import Project="..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets" Condition="Exists('..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets" Condition="Exists('..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="directxtex_desktop_2015" version="2018.2.9.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.3.46.0" targetFramework="native" />
<package id="directxtex_desktop_2015" version="2018.6.1.2" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.5.19.0" targetFramework="native" />
<package id="rapidjson.temprelease" version="0.0.2.20" targetFramework="native" />
</packages>

Двоичный файл не отображается.

Просмотреть файл

@ -49,19 +49,19 @@ namespace Microsoft.glTF.Toolkit.UWP.Test
// compare one of the extracted images to the source images
StorageFile sourceImageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/3DModels/WaterBottle_diffuse.png"));
StorageFile outputImageFile = await outputFolder.GetFileAsync(glbBaseName + "_image5.png");
Assert.IsTrue(await CompareFilesAsync(sourceImageFile, outputImageFile));
Assert.IsTrue(await CompareFilesAsync(sourceImageFile, outputImageFile), "images");
// compare the extracted model (.bin) to the source model (.bin) file
StorageFile sourceBinFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/3DModels/" + glbBaseName + ".bin"));
StorageFile outputBinFile = await outputFolder.GetFileAsync(glbBaseName + ".bin");
Assert.IsTrue(await CompareFilesAsync(sourceBinFile, outputBinFile));
Assert.IsTrue(await CompareFilesAsync(sourceBinFile, outputBinFile), "bins");
// Pack the gltf back into a glb file
StorageFile gltfFile = await outputFolder.GetFileAsync(glbBaseName + ".gltf");
StorageFile outputGlbFile = await GLTFSerialization.PackGLTFAsync(gltfFile, outputFolder, glbFileName);
// compare the new glb to the old glb
Assert.IsTrue(await CompareFilesAsync(sourceGlbFile, outputGlbFile));
Assert.IsTrue(await CompareFilesAsync(sourceGlbFile, outputGlbFile), "glb");
}
[TestMethod]
@ -74,7 +74,7 @@ namespace Microsoft.glTF.Toolkit.UWP.Test
StorageFolder outputFolder = await CreateTemporaryOutputFolderAsync("Out_" + glbBaseName);
var converted = await WindowsMRConversion.ConvertAssetForWindowsMR(sourceGlbFile, outputFolder, 512, TexturePacking.OcclusionRoughnessMetallic);
var converted = await WindowsMRConversion.ConvertAssetForWindowsMR(sourceGlbFile, outputFolder, 512, TexturePacking.OcclusionRoughnessMetallic, true);
Assert.IsTrue(converted.Name == "WaterBottle_converted.glb");
}

Просмотреть файл

@ -131,13 +131,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
<Version>6.0.7</Version>
<Version>6.2.0-Preview1-26502-02</Version>
</PackageReference>
<PackageReference Include="MSTest.TestAdapter">
<Version>1.2.0</Version>
<Version>1.3.2</Version>
</PackageReference>
<PackageReference Include="MSTest.TestFramework">
<Version>1.2.0</Version>
<Version>1.3.2</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(Platform)'=='x86'">

Просмотреть файл

@ -8,7 +8,7 @@
#include <GLBtoGLTF.h>
#include <SerializeBinary.h>
#include <GLTFSDK/GLTFDocument.h>
#include <GLTFSDK/Document.h>
using namespace Concurrency;
using namespace Microsoft::glTF;
@ -50,18 +50,18 @@ IAsyncOperation<StorageFile^>^ GLTFSerialization::PackGLTFAsync(StorageFile^ sou
return create_task([stream]()
{
return std::make_shared<GLTFDocument>(DeserializeJson(*stream));
return std::make_shared<Document>(Deserialize(*stream));
})
.then([sourceGltf, outputFolder, glbName](std::shared_ptr<GLTFDocument> document)
.then([sourceGltf, outputFolder, glbName](std::shared_ptr<Document> document)
{
return create_task(sourceGltf->GetParentAsync())
.then([outputFolder, glbName, document](StorageFolder^ gltfFolder)
{
GLTFStreamReader streamReader(gltfFolder);
auto streamReader = std::make_shared<GLTFStreamReader>(gltfFolder);
String^ outputGlbPath = outputFolder->Path + "\\" + glbName;
std::wstring outputGlbPathW = outputGlbPath->Data();
SerializeBinary(*document, streamReader, std::make_unique<GLBStreamFactory>(outputGlbPathW));
SerializeBinary(*document, streamReader, std::make_shared<GLBStreamWriter>(outputGlbPathW));
return outputFolder->GetFileAsync(glbName);
});

Просмотреть файл

@ -5,7 +5,7 @@
#include <filesystem>
#include <GLTFSDK/IStreamReader.h>
#include <GLTFSDK/IStreamFactory.h>
#include <GLTFSDK/IStreamWriter.h>
namespace Microsoft::glTF::Toolkit::UWP
{
@ -36,30 +36,19 @@ namespace Microsoft::glTF::Toolkit::UWP
std::experimental::filesystem::path m_uriBase;
};
class GLBStreamFactory : public Microsoft::glTF::IStreamFactory
class GLBStreamWriter : public Microsoft::glTF::IStreamWriter
{
public:
GLBStreamFactory(const std::wstring& filename) :
m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out)),
m_tempStream(std::make_shared<std::stringstream>(std::ios_base::binary | std::ios_base::in | std::ios_base::out))
GLBStreamWriter(const std::wstring& filename) :
m_stream(std::make_shared<std::ofstream>(filename, std::ios_base::binary | std::ios_base::out))
{ }
std::shared_ptr<std::istream> GetInputStream(const std::string&) const override
{
throw std::logic_error("Not implemented");
}
std::shared_ptr<std::ostream> GetOutputStream(const std::string&) const override
{
return m_stream;
}
std::shared_ptr<std::iostream> GetTemporaryStream(const std::string&) const override
{
return m_tempStream;
}
private:
std::shared_ptr<std::ofstream> m_stream;
std::shared_ptr<std::stringstream> m_tempStream;
};
}

Просмотреть файл

@ -9,12 +9,15 @@
#include <ppltasks.h>
#include <GLTFTexturePackingUtils.h>
#include <GLTFTextureCompressionUtils.h>
#include <GLTFMeshCompressionUtils.h>
#include <GLTFSpecularGlossinessUtils.h>
#include <SerializeBinary.h>
#include <GLBtoGLTF.h>
#include <GLTFSDK/GLTFDocument.h>
#include <GLTFSDK/Document.h>
#include <GLTFSDK/IStreamReader.h>
#include <GLTFSDK/IStreamFactory.h>
#include <GLTFSDK/IStreamWriter.h>
#include <GLTFSDK/ExtensionsKHR.h>
using namespace concurrency;
using namespace Platform;
@ -48,10 +51,15 @@ IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(Sto
}
IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile ^ gltfOrGlbFile, StorageFolder ^ outputFolder, size_t maxTextureSize, TexturePacking packing)
{
return ConvertAssetForWindowsMR(gltfOrGlbFile, outputFolder, maxTextureSize, packing, false);
}
IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(StorageFile ^ gltfOrGlbFile, StorageFolder ^ outputFolder, size_t maxTextureSize, TexturePacking packing, bool meshCompression)
{
auto isGlb = gltfOrGlbFile->FileType == L".glb";
return create_async([gltfOrGlbFile, maxTextureSize, outputFolder, isGlb, packing]()
return create_async([gltfOrGlbFile, maxTextureSize, outputFolder, isGlb, packing, meshCompression]()
{
return create_task([gltfOrGlbFile, isGlb]()
{
@ -64,23 +72,26 @@ IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(Sto
return task_from_result<StorageFile^>(gltfOrGlbFile);
}
})
.then([maxTextureSize, outputFolder, isGlb, packing](StorageFile^ gltfFile)
.then([maxTextureSize, outputFolder, isGlb, packing, meshCompression](StorageFile^ gltfFile)
{
auto stream = std::make_shared<std::ifstream>(gltfFile->Path->Data(), std::ios::in);
GLTFDocument document = DeserializeJson(*stream);
Document document = Deserialize(*stream, KHR::GetKHRExtensionDeserializer());
return create_task(gltfFile->GetParentAsync())
.then([document, maxTextureSize, outputFolder, gltfFile, isGlb, packing](StorageFolder^ baseFolder)
.then([document, maxTextureSize, outputFolder, gltfFile, isGlb, packing, meshCompression](StorageFolder^ baseFolder)
{
GLTFStreamReader streamReader(baseFolder);
// 1. Texture Packing
auto streamReader = std::make_shared<GLTFStreamReader>(baseFolder);
auto tempDirectory = std::wstring(ApplicationData::Current->TemporaryFolder->Path->Data());
auto tempDirectoryA = std::string(tempDirectory.begin(), tempDirectory.end());
auto convertedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(streamReader, document, static_cast<Toolkit::TexturePacking>(packing), tempDirectoryA);
// 0. Specular Glossiness conversion
auto convertedDoc = GLTFSpecularGlossinessUtils::ConvertMaterials(streamReader, document, tempDirectoryA);
// 1. Texture Packing
convertedDoc = GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(streamReader, convertedDoc, static_cast<Toolkit::TexturePacking>(packing), tempDirectoryA);
// 2. Texture Compression
convertedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(streamReader, document, tempDirectoryA, maxTextureSize, false /* retainOriginalImages */);
convertedDoc = GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(streamReader, convertedDoc, tempDirectoryA, maxTextureSize, false /* retainOriginalImages */);
// 3. Make sure there's a default scene set
if (!convertedDoc.HasDefaultScene())
@ -88,7 +99,13 @@ IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(Sto
convertedDoc.defaultSceneId = convertedDoc.scenes.Elements()[0].id;
}
// 4. GLB Export
// 4. Compress the meshes
if (meshCompression)
{
convertedDoc = GLTFMeshCompressionUtils::CompressMeshes(streamReader, convertedDoc, {}, tempDirectoryA);
}
// 5. GLB Export
// The Windows MR Fall Creators update has restrictions on the supported
// component types of accessors.
@ -125,7 +142,7 @@ IAsyncOperation<StorageFile^>^ WindowsMRConversion::ConvertAssetForWindowsMR(Sto
glbName += L".glb";
std::wstring outputGlbPathW = std::wstring(outputFolder->Path->Data()) + L"\\" + glbName;
SerializeBinary(convertedDoc, streamReader, std::make_unique<GLBStreamFactory>(outputGlbPathW), accessorConversion);
SerializeBinary(convertedDoc, streamReader, std::make_shared<GLBStreamWriter>(outputGlbPathW), accessorConversion);
return create_task(outputFolder->GetFileAsync(ref new String(glbName.c_str())));
});

Просмотреть файл

@ -22,5 +22,6 @@ namespace Microsoft::glTF::Toolkit::UWP
static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder);
static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize);
static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize, UWP::TexturePacking packing);
static Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFile^>^ ConvertAssetForWindowsMR(Windows::Storage::StorageFile^ gltfOrGlbFile, Windows::Storage::StorageFolder^ outputFolder, size_t maxTextureSize, UWP::TexturePacking packing, bool meshCompression);
};
}

Просмотреть файл

@ -284,15 +284,17 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets" Condition="Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" />
<Import Project="..\packages\directxtex_uwp.2018.2.9.1\build\native\directxtex_uwp.targets" Condition="Exists('..\packages\directxtex_uwp.2018.2.9.1\build\native\directxtex_uwp.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="..\packages\directxtex_uwp.2018.6.1.2\build\native\directxtex_uwp.targets" Condition="Exists('..\packages\directxtex_uwp.2018.6.1.2\build\native\directxtex_uwp.targets')" />
<Import Project="..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets" Condition="Exists('..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_uwp.2018.2.9.1\build\native\directxtex_uwp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_uwp.2018.2.9.1\build\native\directxtex_uwp.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('..\packages\directxtex_uwp.2018.6.1.2\build\native\directxtex_uwp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\directxtex_uwp.2018.6.1.2\build\native\directxtex_uwp.targets'))" />
<Error Condition="!Exists('..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets'))" />
</Target>
</Project>

Просмотреть файл

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="directxtex_uwp" version="2018.2.9.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.3.46.0" targetFramework="native" />
<package id="directxtex_uwp" version="2018.6.1.2" targetFramework="native" />
<package id="draco.CPP" version="1.3.3.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.5.19.0" targetFramework="native" />
<package id="rapidjson.temprelease" version="0.0.2.20" targetFramework="native" />
</packages>

Просмотреть файл

@ -141,19 +141,23 @@
<ClInclude Include="inc\DeviceResources.h" />
<ClInclude Include="inc\GLBtoGLTF.h" />
<ClInclude Include="inc\GLTFLODUtils.h" />
<ClInclude Include="inc\GLTFMeshCompressionUtils.h" />
<ClInclude Include="inc\GLTFSDK.h" />
<ClInclude Include="inc\GLTFSpecularGlossinessUtils.h" />
<ClInclude Include="inc\GLTFTextureCompressionUtils.h" />
<ClInclude Include="inc\GLTFTextureLoadingUtils.h" />
<ClInclude Include="inc\GLTFTextureUtils.h" />
<ClInclude Include="inc\GLTFTexturePackingUtils.h" />
<ClInclude Include="inc\pch.h" />
<ClInclude Include="inc\SerializeBinary.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\GLTFMeshCompressionUtils.cpp" />
<ClCompile Include="src\DeviceResources.cpp" />
<ClCompile Include="src\GLBtoGLTF.cpp" />
<ClCompile Include="src\GLTFLODUtils.cpp" />
<ClCompile Include="src\GLTFSpecularGlossinessUtils.cpp" />
<ClCompile Include="src\GLTFTextureCompressionUtils.cpp" />
<ClCompile Include="src\GLTFTextureLoadingUtils.cpp" />
<ClCompile Include="src\GLTFTextureUtils.cpp" />
<ClCompile Include="src\GLTFTexturePackingUtils.cpp" />
<ClCompile Include="src\pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
@ -163,15 +167,17 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="$(SolutionDir)packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets" Condition="Exists('$(SolutionDir)packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" />
<Import Project="$(SolutionDir)packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets" Condition="Exists('$(SolutionDir)packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" />
<Import Project="$(SolutionDir)packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('$(SolutionDir)packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="$(SolutionDir)\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets" Condition="Exists('$(SolutionDir)\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" />
<Import Project="$(SolutionDir)\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets" Condition="Exists('$(SolutionDir)\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" />
<Import Project="$(SolutionDir)\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets" Condition="Exists('$(SolutionDir)\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\rapidjson.temprelease.0.0.2.20\build\native\rapidjson.temprelease.targets'))" />
<Error Condition="!Exists('$(SolutionDir)packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\directxtex_desktop_2015.2018.2.9.1\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('$(SolutionDir)packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)packages\Microsoft.glTF.CPP.1.3.46.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\directxtex_desktop_2015.2018.6.1.2\build\native\directxtex_desktop_2015.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\Microsoft.glTF.CPP.1.5.19.0\build\native\Microsoft.glTF.CPP.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\draco.CPP.1.3.3.1\build\native\draco.CPP.targets'))" />
</Target>
</Project>
</Project>

Просмотреть файл

@ -21,9 +21,6 @@
<ClInclude Include="inc\GLTFTextureCompressionUtils.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="inc\GLTFTextureLoadingUtils.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="inc\GLTFTexturePackingUtils.h">
<Filter>inc</Filter>
</ClInclude>
@ -42,6 +39,15 @@
<ClInclude Include="inc\GLTFSDK.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="inc\GLTFMeshCompressionUtils.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="inc\GLTFSpecularGlossinessUtils.h">
<Filter>inc</Filter>
</ClInclude>
<ClInclude Include="inc\GLTFTextureUtils.h">
<Filter>inc</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\DeviceResources.cpp">
@ -53,9 +59,6 @@
<ClCompile Include="src\GLTFTextureCompressionUtils.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\GLTFTextureLoadingUtils.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\GLTFTexturePackingUtils.cpp">
<Filter>src</Filter>
</ClCompile>
@ -68,5 +71,14 @@
<ClCompile Include="src\GLBtoGLTF.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\GLTFMeshCompressionUtils.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\GLTFSpecularGlossinessUtils.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="src\GLTFTextureUtils.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
</Project>

Просмотреть файл

@ -37,7 +37,7 @@ namespace Microsoft::glTF::Toolkit
/// <returns>
/// The binary content of the buffer views as a vector.
/// </returns>
static std::vector<char> SaveBin(std::istream* in, const Microsoft::glTF::GLTFDocument& glbDoc, const size_t bufferOffset, const size_t newBufferlength);
static std::vector<char> SaveBin(std::istream* in, const Microsoft::glTF::Document& glbDoc, const size_t bufferOffset, const size_t newBufferlength);
/// <summary>
/// Loads all images in a glTF-Binary (GLB) asset into a map relating each image identifier to the contents of that image.
@ -49,7 +49,7 @@ namespace Microsoft::glTF::Toolkit
/// <returns>
/// A map relating each image identifier to the contents of that image.
/// </returns>
static std::unordered_map<std::string, std::vector<char>> GetImagesData(std::istream* in, const Microsoft::glTF::GLTFDocument& glbDoc, const std::string& name, const size_t bufferOffset);
static std::unordered_map<std::string, std::vector<char>> GetImagesData(std::istream* in, const Microsoft::glTF::Document& glbDoc, const std::string& name, const size_t bufferOffset);
/// <summary>
/// Creates the glTF manifest that represents a GLB file after unpacking.
@ -59,6 +59,6 @@ namespace Microsoft::glTF::Toolkit
/// <returns>
/// A new glTF manifest that represents the same file, but with images and resources referenced by URI instead of embedded ina GLB buffer.
/// </returns>
static Microsoft::glTF::GLTFDocument CreateGLTFDocument(const Microsoft::glTF::GLTFDocument& glbDoc, const std::string& name);
static Microsoft::glTF::Document CreateGLTFDocument(const Microsoft::glTF::Document& glbDoc, const std::string& name);
};
}

Просмотреть файл

@ -22,20 +22,20 @@ namespace Microsoft::glTF::Toolkit
/// </summary>
/// <returns>A map that relates each node ID to a vector of its levels of detail node IDs.</returns>
/// <param name="doc">The glTF document containing LODs to be parsed.</param>
static LODMap ParseDocumentNodeLODs(const GLTFDocument& doc);
static LODMap ParseDocumentNodeLODs(const Document& doc);
/// <summary>
/// Inserts each LOD GLTFDocument as a node LOD (at the root level) of the specified primary GLTF asset.
/// Inserts each LOD Document as a node LOD (at the root level) of the specified primary GLTF asset.
/// Note: Animation is not currently supported.
/// </summary>
/// <returns>The primary GLTF Document with the inserted LOD node.</returns>
/// <param name="docs">A vector of glTF documents to merge as LODs. The first element of the vector is assumed to be the primary LOD.</param>
/// <param name="relativePaths">A vector of relative path prefixes to the non-LOD0 LOD gltf documents. Used for finding resources in those LODs.
/// If not specified, all resources are assumed to be in the same directory.</param>
static GLTFDocument MergeDocumentsAsLODs(const std::vector<GLTFDocument>& docs, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);
static Document MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);
/// <summary>
/// Inserts each LOD GLTFDocument as a node LOD (at the root level) of the specified primary GLTF asset.
/// Inserts each LOD Document as a node LOD (at the root level) of the specified primary GLTF asset.
/// Note: Animation is not currently supported.
/// </summary>
/// <returns>The primary GLTF Document with the inserted LOD node.</returns>
@ -44,7 +44,7 @@ namespace Microsoft::glTF::Toolkit
/// vector is larger than the size of <see name="docs" />, lower coverage values will cause the asset to be invisible.</param>
/// <param name="relativePaths">A vector of relative path prefixes to the non-LOD0 LOD gltf documents. Used for finding resources in those LODs.
/// If not specified, all resources are assumed to be in the same directory.</param>
static GLTFDocument MergeDocumentsAsLODs(const std::vector<GLTFDocument>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);
static Document MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths = std::vector<std::wstring>(), const bool& sharedMaterials = false);
/// <summary>
/// Determines the highest number of Node LODs for a given glTF asset.
@ -52,7 +52,7 @@ namespace Microsoft::glTF::Toolkit
/// <param name="doc">The glTF asset for which to count the max number of node LODs.</param>
/// <param name="lods">A map containing the parsed node LODs in the document.</param>
/// <returns>The highest number of Node LODs in the asset.</returns>
static uint32_t NumberOfNodeLODLevels(const GLTFDocument& doc, const LODMap& lods);
static uint32_t NumberOfNodeLODLevels(const Document& doc, const LODMap& lods);
};
}

Просмотреть файл

@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#pragma once
#include "GLTFSDK.h"
#include "GLTFSDK/BufferBuilder.h"
namespace Microsoft::glTF::Toolkit
{
/// <summary>Draco compression options.</summary>
struct CompressionOptions
{
int PositionQuantizationBits = 14;
int TexCoordQuantizationBits = 12;
int NormalQuantizationBits = 10;
int ColorQuantizationBits = 8;
int GenericQuantizationBits = 12;
int Speed = 3;
};
/// <summary>
/// Utilities to compress textures in a glTF asset.
/// </summary>
class GLTFMeshCompressionUtils
{
public:
/// <summary>
/// Applies <see cref="CompressMesh" /> to every mesh in the document, following the same parameter structure as that function.
/// </summary>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the mesh will be loaded.</param>
/// <param name="options">The compression options that will be used.</param>
/// <param name="outputDirectory">The output directory to which compressed data should be saved.</param>
/// <returns>
/// A new glTF manifest that uses the KHR_draco_mesh_compression extension to point to the compressed meshes.
/// </returns>
static Document CompressMeshes(
std::shared_ptr<IStreamReader> streamReader,
const Document & doc,
CompressionOptions options,
const std::string& outputDirectory);
/// <summary>
/// Applies Draco mesh compression to the supplied mesh and creates a new set of vertex buffers for all the primitive attributes.
/// </summary>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the mesh will be loaded.</param>
/// <param name="mesh">The mesh which the mesh will be compressed.</param>
/// <param name="options">The compression options that will be used.</param>
/// <param name="builder">The output buffer builder that handles bufferId generation for the return document.</param>
/// <param name="bufferViewsToRemove">Out parameter of BufferView Ids that are no longer in use and should be removed.</param>
/// <returns>
/// A new glTF manifest that uses the KHR_draco_mesh_compression extension to point to the compressed meshes.
/// </returns>
static Document CompressMesh(
std::shared_ptr<IStreamReader> streamReader,
const Document & doc,
CompressionOptions options,
const Mesh & mesh,
BufferBuilder* builder,
std::unordered_set<std::string>& bufferViewsToRemove);
};
}

Просмотреть файл

@ -7,16 +7,15 @@
#pragma warning(disable : 4634)
#pragma warning(disable : 4996)
#include <GLTFSDK/GLTFDocument.h>
#include <GLTFSDK/Document.h>
#include <GLTFSDK/Deserialize.h>
#include <GLTFSDK/Serialize.h>
#include <GLTFSDK/GLTFResourceWriter.h>
#include <GLTFSDK/GLBResourceReader.h>
#include <GLTFSDK/GLTFResourceReader.h>
#include <GLTFSDK/IStreamReader.h>
#include <GLTFSDK/IStreamFactory.h>
#include <GLTFSDK/RapidJsonUtils.h>
#include <GLTFSDK/GLTF.h>
#include <GLTFSDK/GLTFConstants.h>
#include <GLTFSDK/Constants.h>
#pragma warning(pop)

Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#pragma once
#include "GLTFSDK.h"
namespace Microsoft::glTF::Toolkit
{
/// <summary>
/// Utilities to remove Specular Glossiness from a glTF asset.
/// </summary>
class GLTFSpecularGlossinessUtils
{
public:
/// <summary>
/// Applies <see cref="ConvertMaterial" /> to every material in the document, following the same parameter structure as that function.
/// </summary>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the mesh will be loaded.</param>
/// <param name="outputDirectory">The output directory to which compressed data should be saved.</param>
/// <returns>
/// A new glTF manifest without the KHR_materials_pbrSpecularGlossiness extension.
/// </returns>
static Document ConvertMaterials(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory);
/// <summary>
/// Removes the KHR_materials_pbrSpecularGlossiness extension by converting the parameters to Metal Roughness.
/// </summary>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the mesh will be loaded.</param>
/// <param name="material">The material to be converted.</param>
/// <param name="outputDirectory">The output directory to which compressed data should be saved.</param>
/// <returns>
/// A new glTF manifest without the KHR_materials_pbrSpecularGlossiness extension.
/// </returns>
static Document ConvertMaterial(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, const std::string& outputDirectory);
};
}

Просмотреть файл

@ -43,7 +43,7 @@ namespace Microsoft::glTF::Toolkit
/// <param name="generateMipMaps">If true, also generates mip maps when compressing.</param>
/// <param name="retainOriginalImage">If true, retains the original image on the resulting glTF. If false,
/// replaces that image (making the glTF incompatible with most core glTF 2.0 viewers).</param>
/// <returns>Returns a new GLTFDocument that contains a new reference to the compressed dds file added as part
/// <returns>Returns a new Document that contains a new reference to the compressed dds file added as part
/// of the MSFT_texture_dds extension.</returns>
/// <example>
/// Example Input:
@ -84,7 +84,7 @@ namespace Microsoft::glTF::Toolkit
/// </code>
/// </example>
/// </summary>
static GLTFDocument CompressTextureAsDDS(const IStreamReader& streamReader, const GLTFDocument & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool generateMipMaps = true, bool retainOriginalImage = true);
static Document CompressTextureAsDDS(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool generateMipMaps = true, bool retainOriginalImage = true);
/// <summary>
/// Applies <see cref="CompressTextureAsDDS" /> to all textures in the document that are accessible via materials according to the
@ -97,10 +97,10 @@ namespace Microsoft::glTF::Toolkit
/// <param name="generateMipMaps">If true, also generates mip maps when compressing.</param>
/// <param name="retainOriginalImage">If true, retains the original image on the resulting glTF. If false,
/// replaces that image (making the glTF incompatible with most core glTF 2.0 viewers).</param>
/// <returns>Returns a new GLTFDocument that contains alternate textures for all applicable materials following the requirements of the Windows
/// <returns>Returns a new Document that contains alternate textures for all applicable materials following the requirements of the Windows
/// Mixed Reality home using the MSFT_texture_dds extension.</returns>
/// </summary>
static GLTFDocument CompressAllTexturesForWindowsMR(const IStreamReader& streamReader, const GLTFDocument & doc, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool retainOriginalImages = true);
static Document CompressAllTexturesForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory, size_t maxTextureSize = std::numeric_limits<size_t>::max(), bool retainOriginalImages = true);
/// <summary>
/// Compresses a DirectX::ScratchImage in place using the specified compression.

Просмотреть файл

@ -1,25 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.#pragma once
#include "GLTFSDK.h"
#include <DirectXTex.h>
namespace Microsoft::glTF::Toolkit
{
/// <summary>
/// Utilities to load textures from glTF assets.
/// </summary>
class GLTFTextureLoadingUtils
{
public:
/// <summary>
/// Loads a texture into a scratch image in the DXGI_FORMAT_R32G32B32A32_FLOAT format for in-memory processing.
/// </summary>
/// <returns>A scratch image containing the loaded texture in the DXGI_FORMAT_R32G32B32A32_FLOAT format.</returns>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the texture will be loaded.</param>
/// <param name="textureId">The identifier of the texture to be loaded.</param>
static DirectX::ScratchImage LoadTexture(const IStreamReader& streamReader, const GLTFDocument& doc, const std::string& textureId);
};
}

Просмотреть файл

@ -42,7 +42,7 @@ namespace Microsoft::glTF::Toolkit
/// <returns>
/// A new glTF manifest that uses the MSFT_packing_occlusionRoughnessMetallic extension to point to the packed textures.
/// </returns>
static GLTFDocument PackMaterialForWindowsMR(const IStreamReader& streamReader, const GLTFDocument & doc, const Material & material, TexturePacking packing, const std::string& outputDirectory);
static Document PackMaterialForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, TexturePacking packing, const std::string& outputDirectory);
/// <summary>
/// Applies <see cref="PackMaterialForWindowsMR" /> to every material in the document, following the same parameter structure as that function.
@ -54,7 +54,7 @@ namespace Microsoft::glTF::Toolkit
/// <returns>
/// A new glTF manifest that uses the MSFT_packing_occlusionRoughnessMetallic extension to point to the packed textures.
/// </returns>
static GLTFDocument PackAllMaterialsForWindowsMR(const IStreamReader& streamReader, const GLTFDocument & doc, TexturePacking packing, const std::string& outputDirectory);
static Document PackAllMaterialsForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, TexturePacking packing, const std::string& outputDirectory);
};
}

Просмотреть файл

@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.#pragma once
#include "GLTFSDK.h"
#include <DirectXTex.h>
namespace Microsoft::glTF::Toolkit
{
enum Channel
{
Red = 0,
Green = 4,
Blue = 8,
Alpha = 12
};
/// <summary>
/// Utilities to load textures from glTF assets.
/// </summary>
class GLTFTextureUtils
{
public:
/// <summary>
/// Loads a texture into a scratch image in the DXGI_FORMAT_R32G32B32A32_FLOAT format for in-memory processing.
/// </summary>
/// <returns>A scratch image containing the loaded texture in the DXGI_FORMAT_R32G32B32A32_FLOAT format.</returns>
/// <param name="streamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="doc">The document from which the texture will be loaded.</param>
/// <param name="textureId">The identifier of the texture to be loaded.</param>
static DirectX::ScratchImage LoadTexture(std::shared_ptr<const IStreamReader> streamReader, const Document& doc, const std::string& textureId, bool treatAsLinear = true);
/// <summary>
/// Gets the value of channel `channel` in pixel index `offset` in image `imageData`
/// assumed to be formatted as DXGI_FORMAT_R32G32B32A32_FLOAT
/// </summary>
static float* GetChannelValue(uint8_t * imageData, size_t offset, Channel channel);
static std::string SaveAsPng(DirectX::ScratchImage* image, const std::string& fileName, const std::string& directory, const GUID* targetFormat = &GUID_WICPixelFormat24bppBGR);
static std::string AddImageToDocument(Document& doc, const std::string& imageUri);
static void ResizeToLargest(std::unique_ptr<DirectX::ScratchImage>& image1, std::unique_ptr<DirectX::ScratchImage>& image2);
static void ResizeIfNeeded(const std::unique_ptr<DirectX::ScratchImage>& image, size_t resizedWidth, size_t resizedHeight);
};
}

Просмотреть файл

@ -20,18 +20,18 @@ namespace Microsoft::glTF::Toolkit
/// <summary>
/// Serializes a glTF asset as a glTF binary (GLB) file.
/// </summary>
/// <param name="gltfDocument">The glTF asset manifest to be serialized.</param>
/// <param name="Document">The glTF asset manifest to be serialized.</param>
/// <param name="inputStreamReader">A stream reader that is capable of accessing the resources used in the glTF asset by URI.</param>
/// <param name="outputStreamFactory">A stream factory that is capable of creating an output stream where the GLB will be saved, and a temporary stream for
/// use during the serialization process.</param>
void SerializeBinary(const GLTFDocument& gltfDocument, const IStreamReader& inputStreamReader, std::unique_ptr<const IStreamFactory>&& outputStreamFactory, const AccessorConversionStrategy& accessorConversion = nullptr);
void SerializeBinary(const Document& document, std::shared_ptr<const IStreamReader> inputStreamReader, std::shared_ptr<const IStreamWriter> outputStreamWriter, const AccessorConversionStrategy& accessorConversion = nullptr);
/// <summary>
/// Serializes a glTF asset as a glTF binary (GLB) file.
/// </summary>
/// <param name="gltfDocument">The glTF asset manifest to be serialized.</param>
/// <param name="Document">The glTF asset manifest to be serialized.</param>
/// <param name="resourceReader">A resource reader that is capable of accessing the resources used in the document.</param>
/// <param name="outputStreamFactory">A stream factory that is capable of creating an output stream where the GLB will be saved, and a temporary stream for
/// use during the serialization process.</param>
void SerializeBinary(const GLTFDocument& gltfDocument, const GLTFResourceReader& resourceReader, std::unique_ptr<const IStreamFactory>&& outputStreamFactory, const AccessorConversionStrategy& accessorConversion = nullptr);
void SerializeBinary(const Document& document, const GLTFResourceReader& resourceReader, std::shared_ptr<const IStreamWriter> outputStreamWriter, const AccessorConversionStrategy& accessorConversion = nullptr);
}

Просмотреть файл

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="directxtex_desktop_2015" version="2018.2.9.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.3.46.0" targetFramework="native" />
<package id="directxtex_desktop_2015" version="2018.6.1.2" targetFramework="native" />
<package id="draco.CPP" version="1.3.3.1" targetFramework="native" />
<package id="Microsoft.glTF.CPP" version="1.5.19.0" targetFramework="native" />
<package id="rapidjson.temprelease" version="0.0.2.20" targetFramework="native" />
</packages>

Просмотреть файл

@ -41,7 +41,7 @@ namespace
}
}
std::vector<char> GLBToGLTF::SaveBin(std::istream* input, const GLTFDocument& glbDoc, const size_t bufferOffset, const size_t newBufferlength)
std::vector<char> GLBToGLTF::SaveBin(std::istream* input, const Document& glbDoc, const size_t bufferOffset, const size_t newBufferlength)
{
if (newBufferlength == 0)
{
@ -110,7 +110,7 @@ std::vector<char> GLBToGLTF::SaveBin(std::istream* input, const GLTFDocument& gl
return result;
}
std::unordered_map<std::string, std::vector<char>> GLBToGLTF::GetImagesData(std::istream* input, const GLTFDocument& glbDoc, const std::string& name, const size_t bufferOffset)
std::unordered_map<std::string, std::vector<char>> GLBToGLTF::GetImagesData(std::istream* input, const Document& glbDoc, const std::string& name, const size_t bufferOffset)
{
input->seekg(0, std::ios::beg);
std::unordered_map<std::string, int> imageIDs;
@ -179,9 +179,9 @@ std::unordered_map<std::string, std::vector<char>> GLBToGLTF::GetImagesData(std:
// Create modified gltf from original by removing image buffer segments and updating
// images, bufferViews and accessors fields accordingly
GLTFDocument GLBToGLTF::CreateGLTFDocument(const GLTFDocument& glbDoc, const std::string& name)
Document GLBToGLTF::CreateGLTFDocument(const Document& glbDoc, const std::string& name)
{
GLTFDocument gltfDoc(glbDoc);
Document gltfDoc(glbDoc);
gltfDoc.images.Clear();
gltfDoc.buffers.Clear();
@ -291,12 +291,12 @@ void GLBToGLTF::UnpackGLB(const std::string& glbPath, const std::string& outDire
{
// read glb file into json
auto glbStream = std::make_shared<std::ifstream>(glbPath, std::ios::binary);
auto streamReader = std::make_unique<StreamMock>();
GLBResourceReader reader(*streamReader, glbStream);
auto streamReader = std::make_shared<StreamMock>();
GLBResourceReader reader(streamReader, glbStream);
// get original json
auto json = reader.GetJson();
auto doc = DeserializeJson(json);
auto doc = Deserialize(json);
// create new modified json
auto gltfDoc = GLBToGLTF::CreateGLTFDocument(doc, gltfName);

Просмотреть файл

@ -8,10 +8,10 @@
#include "GLTFLODUtils.h"
#include "GLTFSDK/GLTF.h"
#include "GLTFSDK/GLTFConstants.h"
#include "GLTFSDK/Constants.h"
#include "GLTFSDK/Deserialize.h"
#include "GLTFSDK/RapidJsonUtils.h"
#include "GLTFSDK/Schema.h"
#include "GLTFSDK/ExtensionsKHR.h"
#include <algorithm>
#include <iostream>
@ -33,6 +33,16 @@ namespace
id = (id.empty()) ? "" : std::to_string(std::stoi(id) + offset);
}
inline void AddIndexOffset(MeshPrimitive& primitive, const char* attributeName, size_t offset)
{
// an empty id string indicates that the id is not inuse and therefore should not be updated
auto attributeItr = primitive.attributes.find(attributeName);
if (attributeItr != primitive.attributes.end())
{
attributeItr->second = std::to_string(std::stoi(attributeItr->second) + offset);
}
}
inline void AddIndexOffsetPacked(rapidjson::Value& json, const char* textureId, size_t offset)
{
if (json.HasMember(textureId))
@ -68,7 +78,7 @@ namespace
}
template <typename T>
std::string SerializeExtensionMSFTLod(const T&, const std::vector<std::string>& lods, const GLTFDocument& gltfDocument)
std::string SerializeExtensionMSFTLod(const T&, const std::vector<std::string>& lods, const Document& document)
{
// Omit MSFT_lod entirely if no LODs are available
if (lods.empty())
@ -86,14 +96,14 @@ namespace
{
for (const auto& lodId : lods)
{
lodIndices.push_back(ToKnownSizeType(gltfDocument.materials.GetIndex(lodId)));
lodIndices.push_back(ToKnownSizeType(document.materials.GetIndex(lodId)));
}
}
else if (std::is_same<T, Node>())
{
for (const auto& lodId : lods)
{
lodIndices.push_back(ToKnownSizeType(gltfDocument.nodes.GetIndex(lodId)));
lodIndices.push_back(ToKnownSizeType(document.nodes.GetIndex(lodId)));
}
}
else
@ -110,9 +120,9 @@ namespace
return stringBuffer.GetString();
}
GLTFDocument AddGLTFNodeLOD(const GLTFDocument& primary, LODMap& primaryLods, const GLTFDocument& lod, const std::wstring& relativePath = L"", bool sharedMaterials = false)
Document AddGLTFNodeLOD(const Document& primary, LODMap& primaryLods, const Document& lod, const std::wstring& relativePath = L"", bool sharedMaterials = false)
{
Microsoft::glTF::GLTFDocument gltfLod(primary);
Microsoft::glTF::Document gltfLod(primary);
auto primaryScenes = primary.scenes.Elements();
auto lodScenes = lod.scenes.Elements();
@ -274,15 +284,18 @@ namespace
material.name += nodeLodLabel;
AddIndexOffset(material.id, materialOffset);
AddIndexOffset(material.normalTexture.id, texturesOffset);
AddIndexOffset(material.occlusionTexture.id, texturesOffset);
AddIndexOffset(material.emissiveTextureId, texturesOffset);
AddIndexOffset(material.normalTexture.textureId, texturesOffset);
AddIndexOffset(material.occlusionTexture.textureId, texturesOffset);
AddIndexOffset(material.emissiveTexture.textureId, texturesOffset);
AddIndexOffset(material.metallicRoughness.baseColorTextureId, texturesOffset);
AddIndexOffset(material.metallicRoughness.metallicRoughnessTextureId, texturesOffset);
AddIndexOffset(material.metallicRoughness.baseColorTexture.textureId, texturesOffset);
AddIndexOffset(material.metallicRoughness.metallicRoughnessTexture.textureId, texturesOffset);
AddIndexOffset(material.specularGlossiness.diffuseTextureId, texturesOffset);
AddIndexOffset(material.specularGlossiness.specularGlossinessTextureId, texturesOffset);
if (material.HasExtension<KHR::Materials::PBRSpecularGlossiness>())
{
AddIndexOffset(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseTexture.textureId, texturesOffset);
AddIndexOffset(material.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularGlossinessTexture.textureId, texturesOffset);
}
// MSFT_packing_occlusionRoughnessMetallic packed textures
auto ormExtensionIt = material.extensions.find(EXTENSION_MSFT_PACKING_ORM);
@ -333,15 +346,15 @@ namespace
for (auto &primitive : mesh.primitives)
{
AddIndexOffset(primitive.positionsAccessorId, accessorOffset);
AddIndexOffset(primitive.normalsAccessorId, accessorOffset);
AddIndexOffset(primitive.indicesAccessorId, accessorOffset);
AddIndexOffset(primitive.uv0AccessorId, accessorOffset);
AddIndexOffset(primitive.uv1AccessorId, accessorOffset);
AddIndexOffset(primitive.color0AccessorId, accessorOffset);
AddIndexOffset(primitive.tangentsAccessorId, accessorOffset);
AddIndexOffset(primitive.joints0AccessorId, accessorOffset);
AddIndexOffset(primitive.weights0AccessorId, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_POSITION, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_NORMAL, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_TEXCOORD_0, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_TEXCOORD_1, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_COLOR_0, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_TANGENT, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_JOINTS_0, accessorOffset);
AddIndexOffset(primitive, ACCESSOR_WEIGHTS_0, accessorOffset);
if (sharedMaterials)
{
@ -363,9 +376,12 @@ namespace
localMaterial.metallicRoughness.baseColorFactor == globalMaterial.metallicRoughness.baseColorFactor &&
localMaterial.metallicRoughness.metallicFactor == globalMaterial.metallicRoughness.metallicFactor &&
localMaterial.occlusionTexture.strength == globalMaterial.occlusionTexture.strength &&
localMaterial.specularGlossiness.diffuseFactor == globalMaterial.specularGlossiness.diffuseFactor &&
localMaterial.specularGlossiness.glossinessFactor == globalMaterial.specularGlossiness.glossinessFactor &&
localMaterial.specularGlossiness.specularFactor == globalMaterial.specularGlossiness.specularFactor;
localMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() == globalMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() &&
(!localMaterial.HasExtension<KHR::Materials::PBRSpecularGlossiness>() ||
(localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().diffuseFactor &&
localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().glossinessFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().glossinessFactor &&
localMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularFactor == globalMaterial.GetExtension<KHR::Materials::PBRSpecularGlossiness>().specularFactor)
);
}
);
@ -454,10 +470,8 @@ namespace
newAnimation.samplers.Append(std::move(newSampler));
}
size_t channelsOffset = baseAnimation.channels.size();
for (auto channel : lodAnimation.channels)
{
AddIndexOffset(channel.id, channelsOffset);
AddIndexOffset(channel.target.nodeId, nodeOffset);
AddIndexOffset(channel.samplerId, samplerOffset);
@ -485,7 +499,7 @@ namespace
}
}
LODMap GLTFLODUtils::ParseDocumentNodeLODs(const GLTFDocument& doc)
LODMap GLTFLODUtils::ParseDocumentNodeLODs(const Document& doc)
{
LODMap lodMap;
@ -497,14 +511,14 @@ LODMap GLTFLODUtils::ParseDocumentNodeLODs(const GLTFDocument& doc)
return lodMap;
}
GLTFDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<GLTFDocument>& docs, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)
Document GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)
{
if (docs.empty())
{
throw std::invalid_argument("MergeDocumentsAsLODs passed empty vector");
}
GLTFDocument gltfPrimary(docs[0]);
Document gltfPrimary(docs[0]);
LODMap lods = ParseDocumentNodeLODs(gltfPrimary);
for (size_t i = 1; i < docs.size(); i++)
@ -532,9 +546,9 @@ GLTFDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<GLTFDocument>&
return gltfPrimary;
}
GLTFDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<GLTFDocument>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)
Document GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<Document>& docs, const std::vector<double>& screenCoveragePercentages, const std::vector<std::wstring>& relativePaths, const bool& sharedMaterials)
{
GLTFDocument merged = MergeDocumentsAsLODs(docs, relativePaths, sharedMaterials);
Document merged = MergeDocumentsAsLODs(docs, relativePaths, sharedMaterials);
if (screenCoveragePercentages.size() == 0)
{
@ -571,7 +585,7 @@ GLTFDocument GLTFLODUtils::MergeDocumentsAsLODs(const std::vector<GLTFDocument>&
return merged;
}
uint32_t GLTFLODUtils::NumberOfNodeLODLevels(const GLTFDocument& doc, const LODMap& lods)
uint32_t GLTFLODUtils::NumberOfNodeLODLevels(const Document& doc, const LODMap& lods)
{
size_t maxLODLevel = 0;
for (auto node : doc.nodes.Elements())

Просмотреть файл

@ -0,0 +1,290 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "pch.h"
#include "AccessorUtils.h"
#include "GLTFMeshCompressionUtils.h"
#include "GLTFSDK/MeshPrimitiveUtils.h"
#include "GLTFSDK/ExtensionsKHR.h"
#include "GLTFSDK/BufferBuilder.h"
#pragma warning(push)
#pragma warning(disable: 4018 4081 4244 4267 4389)
#include "draco/compression/encode.h"
#include "draco/core/cycle_timer.h"
#include "draco/io/mesh_io.h"
#include "draco/io/point_cloud_io.h"
#pragma warning(pop)
// Usings for glTF
using namespace Microsoft::glTF;
using namespace Microsoft::glTF::Toolkit;
std::wstring PathConcat(const std::wstring& part1, const std::wstring& part2)
{
wchar_t uriAbsoluteRaw[MAX_PATH];
// Note: PathCchCombine will return the last argument if it's an absolute path
if (FAILED(::PathCchCombine(uriAbsoluteRaw, ARRAYSIZE(uriAbsoluteRaw), part1.c_str(), part2.c_str())))
{
auto msg = L"Could not combine the path names: " + part1 + L" and " + part2;
throw std::invalid_argument(std::string(msg.begin(), msg.end()));
}
return uriAbsoluteRaw;
}
std::string PathConcat(const std::string& part1, const std::string& part2)
{
std::wstring part1W = std::wstring(part1.begin(), part1.end());
std::wstring part2W = std::wstring(part2.begin(), part2.end());
auto pathW = PathConcat(part1W, part2W);
return std::string(pathW.begin(), pathW.end());
}
class FilepathStreamWriter : public IStreamWriter
{
public:
FilepathStreamWriter(std::string uriBase) : m_uriBase(uriBase) {}
virtual ~FilepathStreamWriter() override {}
virtual std::shared_ptr<std::ostream> GetOutputStream(const std::string& filename) const override
{
return std::make_shared<std::ofstream>(PathConcat(m_uriBase, filename), std::ios::binary);
}
private:
const std::string m_uriBase;
};
draco::GeometryAttribute::Type GetTypeFromAttributeName(const std::string& name)
{
if (name == ACCESSOR_POSITION)
{
return draco::GeometryAttribute::Type::POSITION;
}
if (name == ACCESSOR_NORMAL)
{
return draco::GeometryAttribute::Type::NORMAL;
}
if (name == ACCESSOR_TEXCOORD_0)
{
return draco::GeometryAttribute::Type::TEX_COORD;
}
if (name == ACCESSOR_TEXCOORD_1)
{
return draco::GeometryAttribute::Type::TEX_COORD;
}
if (name == ACCESSOR_COLOR_0)
{
return draco::GeometryAttribute::Type::COLOR;
}
if (name == ACCESSOR_JOINTS_0)
{
return draco::GeometryAttribute::Type::GENERIC;
}
if (name == ACCESSOR_WEIGHTS_0)
{
return draco::GeometryAttribute::Type::GENERIC;
}
if (name == ACCESSOR_TANGENT)
{
return draco::GeometryAttribute::Type::GENERIC;
}
return draco::GeometryAttribute::Type::GENERIC;
}
draco::DataType GetDataType(const Accessor& accessor)
{
switch (accessor.componentType)
{
case COMPONENT_BYTE: return draco::DataType::DT_INT8;
case COMPONENT_UNSIGNED_BYTE: return draco::DataType::DT_UINT8;
case COMPONENT_SHORT: return draco::DataType::DT_INT16;
case COMPONENT_UNSIGNED_SHORT: return draco::DataType::DT_UINT16;
case COMPONENT_UNSIGNED_INT: return draco::DataType::DT_UINT32;
case COMPONENT_FLOAT: return draco::DataType::DT_FLOAT32;
}
return draco::DataType::DT_INVALID;
}
template<typename T>
int InitializePointAttribute(draco::Mesh& dracoMesh, const std::string& attributeName, const Document& doc, GLTFResourceReader& reader, Accessor& accessor)
{
auto stride = sizeof(T) * Accessor::GetTypeCount(accessor.type);
auto numComponents = Accessor::GetTypeCount(accessor.type);
draco::PointAttribute pointAttr;
pointAttr.Init(GetTypeFromAttributeName(attributeName), nullptr, numComponents, GetDataType(accessor), accessor.normalized, stride, 0);
int attId = dracoMesh.AddAttribute(pointAttr, true, static_cast<unsigned int>(accessor.count));
auto attrActual = dracoMesh.attribute(attId);
std::vector<T> values = reader.ReadBinaryData<T>(doc, accessor);
if ((accessor.min.empty() || accessor.max.empty()) && !values.empty())
{
auto minmax = AccessorUtils::CalculateMinMax(accessor, values);
accessor.min = minmax.first;
accessor.max = minmax.second;
}
for (draco::PointIndex i(0); i < static_cast<uint32_t>(accessor.count); ++i)
{
attrActual->SetAttributeValue(attrActual->mapped_index(i), &values[i.value() * numComponents]);
}
if (dracoMesh.num_points() == 0)
{
dracoMesh.set_num_points(static_cast<unsigned int>(accessor.count));
}
else if (dracoMesh.num_points() != accessor.count)
{
throw GLTFException("Inconsistent points count.");
}
return attId;
}
void SetEncoderOptions(draco::Encoder& encoder, const CompressionOptions& options)
{
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, options.PositionQuantizationBits);
encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, options.TexCoordQuantizationBits);
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, options.NormalQuantizationBits);
encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, options.ColorQuantizationBits);
encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, options.GenericQuantizationBits);
encoder.SetSpeedOptions(options.Speed, options.Speed);
encoder.SetTrackEncodedProperties(true);
}
Document GLTFMeshCompressionUtils::CompressMesh(
std::shared_ptr<IStreamReader> streamReader,
const Document & doc,
CompressionOptions options,
const Mesh & mesh,
BufferBuilder* builder,
std::unordered_set<std::string>& bufferViewsToRemove)
{
GLTFResourceReader reader(streamReader);
Document resultDocument(doc);
draco::Encoder encoder;
SetEncoderOptions(encoder, options);
Mesh resultMesh(mesh);
resultMesh.primitives.clear();
for (const auto& primitive : mesh.primitives)
{
if (primitive.HasExtension<KHR::MeshPrimitives::DracoMeshCompression>())
{
continue;
}
auto dracoExtension = std::make_unique<KHR::MeshPrimitives::DracoMeshCompression>();
draco::Mesh dracoMesh;
auto indices = MeshPrimitiveUtils::GetIndices32(doc, reader, primitive);
size_t numFaces = indices.size() / 3;
dracoMesh.SetNumFaces(numFaces);
for (uint32_t i = 0; i < numFaces; i++)
{
draco::Mesh::Face face;
face[0] = indices[(i * 3) + 0];
face[1] = indices[(i * 3) + 1];
face[2] = indices[(i * 3) + 2];
dracoMesh.SetFace(draco::FaceIndex(i), face);
}
Accessor indiciesAccessor(doc.accessors[primitive.indicesAccessorId]);
bufferViewsToRemove.emplace(indiciesAccessor.bufferViewId);
indiciesAccessor.bufferViewId = "";
indiciesAccessor.byteOffset = 0;
resultDocument.accessors.Replace(indiciesAccessor);
for (const auto& attribute : primitive.attributes)
{
const auto& accessor = doc.accessors[attribute.second];
Accessor attributeAccessor(accessor);
int attId;
switch (accessor.componentType)
{
case COMPONENT_BYTE: attId = InitializePointAttribute<int8_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
case COMPONENT_UNSIGNED_BYTE: attId = InitializePointAttribute<uint8_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
case COMPONENT_SHORT: attId = InitializePointAttribute<int16_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
case COMPONENT_UNSIGNED_SHORT: attId = InitializePointAttribute<uint16_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
case COMPONENT_UNSIGNED_INT: attId = InitializePointAttribute<uint32_t>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
case COMPONENT_FLOAT: attId = InitializePointAttribute<float>(dracoMesh, attribute.first, doc, reader, attributeAccessor); break;
default: throw GLTFException("Unknown component type.");
}
bufferViewsToRemove.emplace(accessor.bufferViewId);
attributeAccessor.bufferViewId = "";
attributeAccessor.byteOffset = 0;
resultDocument.accessors.Replace(attributeAccessor);
dracoExtension->attributes.emplace(attribute.first, dracoMesh.attribute(attId)->unique_id());
}
if (primitive.targets.size() > 0)
{
// Set sequential encoding to preserve order of vertices.
encoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING);
}
dracoMesh.DeduplicateAttributeValues();
dracoMesh.DeduplicatePointIds();
draco::EncoderBuffer buffer;
const draco::Status status = encoder.EncodeMeshToBuffer(dracoMesh, &buffer);
if (!status.ok()) {
throw GLTFException(std::string("Failed to encode the mesh: ") + status.error_msg());
}
// We must update the original accessors to the encoding out values.
Accessor encodedIndexAccessor(resultDocument.accessors[primitive.indicesAccessorId]);
encodedIndexAccessor.count = encoder.num_encoded_faces() * 3;
resultDocument.accessors.Replace(encodedIndexAccessor);
for (const auto& dracoAttribute : dracoExtension->attributes)
{
auto accessorId = primitive.attributes.at(dracoAttribute.first);
Accessor encodedAccessor(resultDocument.accessors[accessorId]);
encodedAccessor.count = encoder.num_encoded_points();
resultDocument.accessors.Replace(encodedAccessor);
}
// Finally put the encoded data in place.
auto bufferView = builder->AddBufferView(buffer.data(), buffer.size());
dracoExtension->bufferViewId = bufferView.id;
MeshPrimitive resultPrim(primitive);
resultPrim.SetExtension(std::move(dracoExtension));
resultMesh.primitives.emplace_back(resultPrim);
}
resultDocument.meshes.Replace(resultMesh);
return resultDocument;
}
Document GLTFMeshCompressionUtils::CompressMeshes(std::shared_ptr<IStreamReader> streamReader, const Document & doc, CompressionOptions options, const std::string& outputDirectory)
{
Document resultDocument(doc);
auto writerStream = std::make_shared<FilepathStreamWriter>(outputDirectory);
auto writer = std::make_unique<GLTFResourceWriter>(writerStream);
writer->SetUriPrefix(PathConcat(outputDirectory, "MeshCompression"));
std::unique_ptr<BufferBuilder> builder = std::make_unique<BufferBuilder>(std::move(writer),
[&doc](const BufferBuilder& builder) { return std::to_string(doc.buffers.Size() + builder.GetBufferCount()); },
[&doc](const BufferBuilder& builder) { return std::to_string(doc.bufferViews.Size() + builder.GetBufferViewCount()); },
[&doc](const BufferBuilder& builder) { return std::to_string(doc.accessors.Size() + builder.GetAccessorCount()); });
auto buffer = builder->AddBuffer();
std::unordered_set<std::string> bufferViewsToRemove;
for (const auto& mesh : doc.meshes.Elements())
{
resultDocument = CompressMesh(streamReader, resultDocument, options, mesh, builder.get(), bufferViewsToRemove);
}
for (const auto& bufferViewId : bufferViewsToRemove)
{
if (resultDocument.bufferViews.Has(bufferViewId))
{
resultDocument.bufferViews.Remove(bufferViewId);
}
}
builder->Output(resultDocument);
resultDocument.extensionsUsed.emplace(KHR::MeshPrimitives::DRACOMESHCOMPRESSION_NAME);
resultDocument.extensionsRequired.emplace(KHR::MeshPrimitives::DRACOMESHCOMPRESSION_NAME);
return resultDocument;
}

Просмотреть файл

@ -0,0 +1,264 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "pch.h"
#include "GLTFTextureUtils.h"
#include "GLTFSDK/ExtensionsKHR.h"
#include "GLTFSDK/PBRUtils.h"
#include "GLTFSpecularGlossinessUtils.h"
// Usings for glTF
using namespace Microsoft::glTF;
using namespace Toolkit;
using namespace DirectX;
float SolveMetallic(float diffusePerceivedBrightness, float specularPerceivedBrightness, float oneMinusSpecularStrength)
{
if (specularPerceivedBrightness < DIELECTRIC_SPECULAR.r)
{
return 0.0f;
}
const float a = DIELECTRIC_SPECULAR.r;
const float b = diffusePerceivedBrightness * oneMinusSpecularStrength / (1.0f - a) + specularPerceivedBrightness - 2.0f * a;
const float c = a - specularPerceivedBrightness;
const float d = std::max(0.0f, b * b - 4.0f * a * c);
return std::clamp((-b + std::sqrt(d)) / (2.0f * a), 0.0f, 1.0f);
}
void ConvertEntrySpecularGlossinessToMetallicRoughness(
const XMVECTORF32& diffuseColor,
const XMVECTORF32& specGloss,
XMVECTORF32& diffuseOut,
float& metallicOut,
float& roughnessOut)
{
const Color3 gltfDiffuse(diffuseColor[0], diffuseColor[1], diffuseColor[2]);
const Color3 gltfSpecular(specGloss[0], specGloss[1], specGloss[2]);
// roughness
roughnessOut = 1.0f - specGloss[3];
// metalness
const float oneMinusSpecularStrength = 1.0f - gltfSpecular.GetMaxComponent();
metallicOut = SolveMetallic(gltfDiffuse.GetPerceivedBrightness(), gltfSpecular.GetPerceivedBrightness(), oneMinusSpecularStrength);
// diffuse color
const Color3 baseColorFromDiffuse = gltfDiffuse.Scale(oneMinusSpecularStrength / (1.0f - DIELECTRIC_SPECULAR.r) / std::max(1e-4f, 1.0f - metallicOut));
const Color3 baseColorFromSpecular = gltfSpecular.Subtract(DIELECTRIC_SPECULAR.Scale(1.0f - metallicOut).Scale(1.0f / std::max(1e-4f, metallicOut)));
Color3 baseColor = Color3::Lerp(baseColorFromDiffuse, baseColorFromSpecular, metallicOut * metallicOut);
baseColor.Clamp(0.0f, 1.0f);
diffuseOut = { baseColor.r, baseColor.g, baseColor.b, diffuseColor[3] };
}
void ConvertTextureSpecularGlossinessToMetallicRoughness(
ScratchImage& out_metallicRoughnessTexture,
ScratchImage& out_modulatedDiffuseTexture,
const std::unique_ptr<ScratchImage>& diffuseTexture,
const XMVECTORF32& diffuseFactor,
const std::unique_ptr<ScratchImage>& specularGlossinessTexture,
const XMVECTORF32& specularFactor)
{
size_t targetWidth = 4;
size_t targetHeight = 4;
uint8_t* diffusePixels = nullptr;
if (diffuseTexture != nullptr)
{
targetWidth = diffuseTexture->GetMetadata().width;
targetHeight = diffuseTexture->GetMetadata().height;
diffusePixels = diffuseTexture->GetPixels();
}
else if (specularGlossinessTexture != nullptr)
{
targetWidth = specularGlossinessTexture->GetMetadata().width;
targetHeight = specularGlossinessTexture->GetMetadata().height;
}
uint8_t* specGlossPixels = nullptr;
if (specularGlossinessTexture)
{
GLTFTextureUtils::ResizeIfNeeded(specularGlossinessTexture, targetWidth, targetHeight);
specGlossPixels = specularGlossinessTexture->GetPixels();
}
out_modulatedDiffuseTexture.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, targetWidth, targetHeight, 1, 1);
out_metallicRoughnessTexture.Initialize2D(DXGI_FORMAT_R32G32B32A32_FLOAT, targetWidth, targetHeight, 1, 1);
auto diffuseOutPixels = out_modulatedDiffuseTexture.GetPixels();
auto metalRoughPixels = out_metallicRoughnessTexture.GetPixels();
for (uint32_t i = 0; i < targetHeight * targetWidth; ++i)
{
XMVECTORF32 diffuseColor { 1.0f, 1.0f, 1.0f, 1.0f };
if (diffusePixels != nullptr)
{
memcpy_s(&diffuseColor, 16, GLTFTextureUtils::GetChannelValue(diffusePixels, i, Red), 16);
}
diffuseColor.v = diffuseColor * diffuseFactor;
XMVECTORF32 specGloss { 1.0f, 1.0f, 1.0f, 1.0f };
if (specularGlossinessTexture != nullptr)
{
memcpy_s(&specGloss, 16, GLTFTextureUtils::GetChannelValue(specGlossPixels, i, Red), 16);
}
specGloss.v = specGloss * specularFactor;
float metallic;
float roughness;
XMVECTORF32 diffuseColorOut;
ConvertEntrySpecularGlossinessToMetallicRoughness(diffuseColor, specGloss, diffuseColorOut, metallic, roughness);
*GLTFTextureUtils::GetChannelValue(metalRoughPixels, i, Green) = roughness;
*GLTFTextureUtils::GetChannelValue(metalRoughPixels, i, Blue) = metallic;
auto diffuseOutPtr = GLTFTextureUtils::GetChannelValue(diffuseOutPixels, i, Red);
memcpy_s(diffuseOutPtr, 16, diffuseColorOut, 16);
}
}
Document GLTFSpecularGlossinessUtils::ConvertMaterial(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Material & material, const std::string& outputDirectory)
{
if (!material.HasExtension<KHR::Materials::PBRSpecularGlossiness>())
{
return doc;
}
Document resultDoc(doc);
Material resultMaterial(material);
resultMaterial.RemoveExtension<KHR::Materials::PBRSpecularGlossiness>();
const auto& specularGlossiness = material.GetExtension<KHR::Materials::PBRSpecularGlossiness>();
XMVECTORF32 diffuseFactorIn = {
specularGlossiness.diffuseFactor.r,
specularGlossiness.diffuseFactor.g,
specularGlossiness.diffuseFactor.b,
specularGlossiness.diffuseFactor.a
};
XMVECTORF32 specularFactor = {
specularGlossiness.specularFactor.r,
specularGlossiness.specularFactor.g,
specularGlossiness.specularFactor.b,
specularGlossiness.glossinessFactor
};
// First, we check if there actually is a diffuse or specular glossiness texture to convert.
// If not, we only perform the conversion on the materials parameters and early out.
if (specularGlossiness.diffuseTexture.textureId.empty() &&
specularGlossiness.specularGlossinessTexture.textureId.empty())
{
XMVECTORF32 diffuseFactor;
float metallicFactor;
float roughnessFactor;
ConvertEntrySpecularGlossinessToMetallicRoughness(diffuseFactorIn, specularFactor, diffuseFactor, metallicFactor, roughnessFactor);
resultMaterial.metallicRoughness.baseColorFactor.r = diffuseFactor.f[0];
resultMaterial.metallicRoughness.baseColorFactor.g = diffuseFactor.f[1];
resultMaterial.metallicRoughness.baseColorFactor.b = diffuseFactor.f[2];
resultMaterial.metallicRoughness.baseColorFactor.a = diffuseFactor.f[3];
resultMaterial.metallicRoughness.metallicFactor = metallicFactor;
resultMaterial.metallicRoughness.roughnessFactor = roughnessFactor;
resultDoc.materials.Replace(resultMaterial);
}
std::string samplerId;
// Diffuse texture
std::unique_ptr<ScratchImage> diffuseTexture;
if (!specularGlossiness.diffuseTexture.textureId.empty())
{
try
{
diffuseTexture = std::make_unique<ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, specularGlossiness.diffuseTexture.textureId, false));
samplerId = doc.textures[specularGlossiness.diffuseTexture.textureId].samplerId;
}
catch (GLTFException)
{
throw GLTFException("Failed to load diffuse texture.");
}
}
// SpecularGlossiness texture
std::unique_ptr<ScratchImage> specularGlossinessTexture;
if (!specularGlossiness.specularGlossinessTexture.textureId.empty())
{
try
{
specularGlossinessTexture = std::make_unique<ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, specularGlossiness.specularGlossinessTexture.textureId, false));
samplerId = samplerId.empty() ? doc.textures[specularGlossiness.specularGlossinessTexture.textureId].samplerId : samplerId;
}
catch (GLTFException)
{
throw GLTFException("Failed to load specular glossiness texture.");
}
}
ScratchImage metallicRoughnessTexture;
ScratchImage modulatedDiffuseTexture;
ConvertTextureSpecularGlossinessToMetallicRoughness(
metallicRoughnessTexture,
modulatedDiffuseTexture,
diffuseTexture,
diffuseFactorIn, // will be baked into texture
specularGlossinessTexture,
specularFactor);
Material::PBRMetallicRoughness gltfPBRMetallicRoughness;
{
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*metallicRoughnessTexture.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for processing.");
}
auto metallicRoughnessPath = GLTFTextureUtils::SaveAsPng(&converted, "metallicRoughness_" + material.id + ".png", outputDirectory);
auto metallicRoughnessImageId = GLTFTextureUtils::AddImageToDocument(resultDoc, metallicRoughnessPath);
Texture mrTexture;
mrTexture.samplerId = samplerId;
mrTexture.imageId = metallicRoughnessImageId;
gltfPBRMetallicRoughness.metallicRoughnessTexture.textureId = resultDoc.textures.Append(mrTexture, AppendIdPolicy::GenerateOnEmpty).id;
}
{
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*modulatedDiffuseTexture.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DirectX::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_B8G8R8A8_UNORM_SRGB for processing.");
}
auto diffusePath = GLTFTextureUtils::SaveAsPng(&converted, "diffuse_" + material.id + ".png", outputDirectory, &GUID_WICPixelFormat32bppBGRA);
auto diffuseImageId = GLTFTextureUtils::AddImageToDocument(resultDoc, diffusePath);
Texture diffusGltfTexture;
diffusGltfTexture.samplerId = samplerId;
diffusGltfTexture.imageId = diffuseImageId;
gltfPBRMetallicRoughness.baseColorTexture.textureId = resultDoc.textures.Append(diffusGltfTexture, AppendIdPolicy::GenerateOnEmpty).id;
}
resultMaterial.metallicRoughness = gltfPBRMetallicRoughness;
resultDoc.materials.Replace(resultMaterial);
return resultDoc;
}
Document GLTFSpecularGlossinessUtils::ConvertMaterials(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string & outputDirectory)
{
Document resultDocument(doc);
for (const auto& material : doc.materials.Elements())
{
resultDocument = ConvertMaterial(streamReader, resultDocument, material, outputDirectory);
}
resultDocument.extensionsUsed.erase(KHR::Materials::PBRSPECULARGLOSSINESS_NAME);
resultDocument.extensionsRequired.erase(KHR::Materials::PBRSPECULARGLOSSINESS_NAME);
return resultDocument;
}

Просмотреть файл

@ -3,7 +3,7 @@
#include "pch.h"
#include "GLTFTextureLoadingUtils.h"
#include "GLTFTextureUtils.h"
#include "GLTFTexturePackingUtils.h"
#include "GLTFTextureCompressionUtils.h"
#include "DeviceResources.h"
@ -20,9 +20,9 @@ using namespace Microsoft::glTF::Toolkit;
const char* Microsoft::glTF::Toolkit::EXTENSION_MSFT_TEXTURE_DDS = "MSFT_texture_dds";
GLTFDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(const IStreamReader& streamReader, const GLTFDocument & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize, bool generateMipMaps, bool retainOriginalImage)
Document GLTFTextureCompressionUtils::CompressTextureAsDDS(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const Texture & texture, TextureCompression compression, const std::string& outputDirectory, size_t maxTextureSize, bool generateMipMaps, bool retainOriginalImage)
{
GLTFDocument outputDoc(doc);
Document outputDoc(doc);
// Early return cases:
// - No compression requested
@ -36,7 +36,7 @@ GLTFDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(const IStreamRead
return outputDoc;
}
auto image = std::make_unique<DirectX::ScratchImage>(GLTFTextureLoadingUtils::LoadTexture(streamReader, doc, texture.id));
auto image = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, texture.id, compression == TextureCompression::BC7_SRGB ? false : true));
// Resize up to a multiple of 4
auto metadata = image->GetMetadata();
@ -65,7 +65,7 @@ GLTFDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(const IStreamRead
if (resizedWidth != metadata.width || resizedHeight != metadata.height)
{
auto resized = std::make_unique<DirectX::ScratchImage>();
if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), image->GetMetadata(), resizedWidth, resizedHeight, DirectX::TEX_FILTER_DEFAULT, *resized)))
if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), image->GetMetadata(), resizedWidth, resizedHeight, DirectX::TEX_FILTER_SEPARATE_ALPHA, *resized)))
{
throw GLTFException("Failed to resize image.");
}
@ -76,7 +76,7 @@ GLTFDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(const IStreamRead
if (generateMipMaps)
{
auto mipChain = std::make_unique<DirectX::ScratchImage>();
if (FAILED(DirectX::GenerateMipMaps(image->GetImages(), image->GetImageCount(), image->GetMetadata(), DirectX::TEX_FILTER_DEFAULT, 0, *mipChain)))
if (FAILED(DirectX::GenerateMipMaps(image->GetImages(), image->GetImageCount(), image->GetMetadata(), DirectX::TEX_FILTER_SEPARATE_ALPHA, 0, *mipChain)))
{
throw GLTFException("Failed to generate mip maps.");
}
@ -176,9 +176,9 @@ GLTFDocument GLTFTextureCompressionUtils::CompressTextureAsDDS(const IStreamRead
return outputDoc;
}
GLTFDocument GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(const IStreamReader& streamReader, const GLTFDocument & doc, const std::string& outputDirectory, size_t maxTextureSize, bool retainOriginalImages)
Document GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, const std::string& outputDirectory, size_t maxTextureSize, bool retainOriginalImages)
{
GLTFDocument outputDoc(doc);
Document outputDoc(doc);
for (auto material : doc.materials.Elements())
{
@ -191,8 +191,8 @@ GLTFDocument GLTFTextureCompressionUtils::CompressAllTexturesForWindowsMR(const
};
// Compress base and emissive texture as BC7
compressIfNotEmpty(material.metallicRoughness.baseColorTextureId, TextureCompression::BC7_SRGB);
compressIfNotEmpty(material.emissiveTextureId, TextureCompression::BC7_SRGB);
compressIfNotEmpty(material.metallicRoughness.baseColorTexture.textureId, TextureCompression::BC7_SRGB);
compressIfNotEmpty(material.emissiveTexture.textureId, TextureCompression::BC7_SRGB);
// Get textures from the MSFT_packing_occlusionRoughnessMetallic extension
if (material.extensions.find(EXTENSION_MSFT_PACKING_ORM) != material.extensions.end())
@ -246,7 +246,6 @@ void GLTFTextureCompressionUtils::CompressImage(DirectX::ScratchImage& image, Te
return;
}
DWORD compressionFlags = DirectX::TEX_COMPRESS_DEFAULT;
DXGI_FORMAT compressionFormat = DXGI_FORMAT_BC7_UNORM;
switch (compression)
{
@ -261,7 +260,6 @@ void GLTFTextureCompressionUtils::CompressImage(DirectX::ScratchImage& image, Te
break;
case TextureCompression::BC7_SRGB:
compressionFormat = DXGI_FORMAT_BC7_UNORM_SRGB;
compressionFlags |= DirectX::TEX_COMPRESS_SRGB_IN;
break;
default:
throw std::invalid_argument("Invalid compression specified.");
@ -279,7 +277,7 @@ void GLTFTextureCompressionUtils::CompressImage(DirectX::ScratchImage& image, Te
if (device != nullptr)
{
if (SUCCEEDED(DirectX::Compress(device.Get(), image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, compressionFlags, 0, compressedImage)))
if (SUCCEEDED(DirectX::Compress(device.Get(), image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, DirectX::TEX_COMPRESS_DEFAULT, 1, compressedImage)))
{
gpuCompressionSuccessful = true;
}
@ -293,7 +291,7 @@ void GLTFTextureCompressionUtils::CompressImage(DirectX::ScratchImage& image, Te
if (!gpuCompressionSuccessful)
{
// Try software compression
if (FAILED(DirectX::Compress(image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, compressionFlags | DirectX::TEX_COMPRESS_PARALLEL, 0, compressedImage)))
if (FAILED(DirectX::Compress(image.GetImages(), image.GetImageCount(), image.GetMetadata(), compressionFormat, DirectX::TEX_COMPRESS_PARALLEL, 1, compressedImage)))
{
throw GLTFException("Failed to compress data using software compression");
}

Просмотреть файл

@ -1,56 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "pch.h"
#include "GLTFTextureLoadingUtils.h"
using namespace Microsoft::glTF;
using namespace Microsoft::glTF::Toolkit;
namespace
{
}
DirectX::ScratchImage GLTFTextureLoadingUtils::LoadTexture(const IStreamReader& streamReader, const GLTFDocument& doc, const std::string& textureId)
{
DirectX::ScratchImage output;
const Texture& texture = doc.textures.Get(textureId);
GLTFResourceReader gltfResourceReader(streamReader);
const Image& image = doc.images.Get(texture.imageId);
std::vector<uint8_t> imageData = gltfResourceReader.ReadBinaryData(doc, image);
auto data = std::make_unique<uint8_t[]>(imageData.size());
memcpy_s(data.get(), imageData.size(), imageData.data(), imageData.size());
DirectX::TexMetadata info;
if (FAILED(DirectX::LoadFromDDSMemory(data.get(), imageData.size(), DirectX::DDS_FLAGS_NONE, &info, output)))
{
// DDS failed, try WIC
// Note: try DDS first since WIC can load some DDS (but not all), so we wouldn't want to get
// a partial or invalid DDS loaded from WIC.
if (FAILED(DirectX::LoadFromWICMemory(data.get(), imageData.size(), DirectX::WIC_FLAGS_IGNORE_SRGB, &info, output)))
{
throw GLTFException("Failed to load image - Image could not be loaded as DDS or read by WIC.");
}
}
if (info.format == DXGI_FORMAT_R32G32B32A32_FLOAT)
{
return output;
}
else
{
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*output.GetImage(0, 0, 0), DXGI_FORMAT_R32G32B32A32_FLOAT, DirectX::TEX_FILTER_DEFAULT, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_R32G32B32A32_FLOAT for processing.");
}
return converted;
}
}

Просмотреть файл

@ -5,7 +5,7 @@
#include <DirectXTex.h>
#include "GLTFTextureLoadingUtils.h"
#include "GLTFTextureUtils.h"
#include "GLTFTexturePackingUtils.h"
using namespace Microsoft::glTF;
@ -21,57 +21,7 @@ const char* Microsoft::glTF::Toolkit::MSFT_PACKING_NRM_KEY = "normalRoughnessMet
namespace
{
enum Channel
{
Red = 0,
Green = 4,
Blue = 8,
Alpha = 12
};
// Constants for the format DXGI_FORMAT_R32G32B32A32_FLOAT
const size_t DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE = 16;
// Gets the value of channel `channel` in pixel index `offset` in image `imageData`
// assumed to be formatted as DXGI_FORMAT_R32G32B32A32_FLOAT
float* GetChannelValue(uint8_t * imageData, size_t offset, Channel channel)
{
return reinterpret_cast<float*>(imageData + offset * DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE + channel);
}
std::string SaveAsPng(std::unique_ptr<DirectX::ScratchImage>& image, const std::string& fileName, const std::string& directory, const GUID* targetFormat = &GUID_WICPixelFormat24bppBGR)
{
wchar_t outputImageFullPath[MAX_PATH];
auto fileNameW = std::wstring(fileName.begin(), fileName.end());
auto directoryW = std::wstring(directory.begin(), directory.end());
if (FAILED(::PathCchCombine(outputImageFullPath, ARRAYSIZE(outputImageFullPath), directoryW.c_str(), fileNameW.c_str())))
{
throw GLTFException("Failed to compose output file path.");
}
const DirectX::Image* img = image->GetImage(0, 0, 0);
if (FAILED(SaveToWICFile(*img, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, GUID_ContainerFormatPng, outputImageFullPath, targetFormat)))
{
throw GLTFException("Failed to save file.");
}
std::wstring outputImageFullPathStr(outputImageFullPath);
return std::string(outputImageFullPathStr.begin(), outputImageFullPathStr.end());
}
std::string AddImageToDocument(GLTFDocument& doc, const std::string& imageUri)
{
Image image;
auto imageId = std::to_string(doc.images.Size());
image.id = imageId;
image.uri = imageUri;
doc.images.Append(std::move(image));
return imageId;
}
void AddTextureToExtension(const std::string& imageId, TexturePacking packing, GLTFDocument& doc, rapidjson::Value& packedExtensionJson, rapidjson::MemoryPoolAllocator<>& a)
void AddTextureToExtension(const std::string& imageId, TexturePacking packing, Document& doc, rapidjson::Value& packedExtensionJson, rapidjson::MemoryPoolAllocator<>& a)
{
Texture packedTexture;
auto textureId = std::to_string(doc.textures.Size());
@ -98,40 +48,11 @@ namespace
throw GLTFException("Invalid packing.");
}
}
void ResizeIfNeeded(std::unique_ptr<DirectX::ScratchImage>& image, size_t resizedWidth, size_t resizedHeight)
{
auto metadata = image->GetMetadata();
if (resizedWidth != metadata.width || resizedHeight != metadata.height)
{
auto resized = std::make_unique<DirectX::ScratchImage>();
if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), metadata, resizedWidth, resizedHeight, DirectX::TEX_FILTER_DEFAULT, *resized)))
{
throw GLTFException("Failed to resize image while packing.");
}
image = std::move(resized);
}
}
void ResizeToLargest(std::unique_ptr<DirectX::ScratchImage>& image1, std::unique_ptr<DirectX::ScratchImage>& image2)
{
auto metadata1 = image1->GetMetadata();
auto metadata2 = image2->GetMetadata();
if (metadata1.height != metadata2.height || metadata1.width != metadata2.width)
{
auto resizedWidth = std::max(metadata1.width, metadata2.width);
auto resizedHeight = std::max(metadata1.height, metadata2.height);
ResizeIfNeeded(image1, resizedWidth, resizedHeight);
ResizeIfNeeded(image2, resizedWidth, resizedHeight);
}
}
}
GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamReader& streamReader, const GLTFDocument& doc, const Material& material, TexturePacking packing, const std::string& outputDirectory)
Document GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document& doc, const Material& material, TexturePacking packing, const std::string& outputDirectory)
{
GLTFDocument outputDoc(doc);
Document outputDoc(doc);
// No packing requested, return copy of document
if (packing == TexturePacking::None)
@ -140,9 +61,9 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
}
// Read images from material
auto metallicRoughness = material.metallicRoughness.metallicRoughnessTextureId;
auto normal = material.normalTexture.id;
auto occlusion = material.occlusionTexture.id;
auto metallicRoughness = material.metallicRoughness.metallicRoughnessTexture.textureId;
auto normal = material.normalTexture.textureId;
auto occlusion = material.occlusionTexture.textureId;
bool hasMR = !metallicRoughness.empty();
bool hasNormal = !normal.empty();
@ -174,7 +95,7 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
{
try
{
metallicRoughnessImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureLoadingUtils::LoadTexture(streamReader, doc, metallicRoughness));
metallicRoughnessImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, metallicRoughness));
}
catch (GLTFException)
{
@ -189,7 +110,7 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
{
try
{
occlusionImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureLoadingUtils::LoadTexture(streamReader, doc, occlusion));
occlusionImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, occlusion));
}
catch (GLTFException)
{
@ -199,7 +120,7 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
if (hasMR && hasOcclusion && packingIncludesOrm)
{
ResizeToLargest(metallicRoughnessImage, occlusionImage);
GLTFTextureUtils::ResizeToLargest(metallicRoughnessImage, occlusionImage);
}
bool packingIncludesNrm = (packing & TexturePacking::NormalRoughnessMetallic) > 0;
@ -209,7 +130,7 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
{
try
{
normalImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureLoadingUtils::LoadTexture(streamReader, doc, normal));
normalImage = std::make_unique<DirectX::ScratchImage>(GLTFTextureUtils::LoadTexture(streamReader, doc, normal));
}
catch (GLTFException)
{
@ -219,7 +140,7 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
if (hasMR && hasNormal && packingIncludesNrm)
{
ResizeToLargest(metallicRoughnessImage, normalImage);
GLTFTextureUtils::ResizeToLargest(metallicRoughnessImage, normalImage);
}
uint8_t *mrPixels = metallicRoughnessImage != nullptr ? metallicRoughnessImage->GetPixels() : nullptr;
@ -241,30 +162,37 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
}
else
{
auto orm = std::make_unique<DirectX::ScratchImage>();
DirectX::ScratchImage orm;
auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *occlusionImage->GetImage(0, 0, 0);
if (FAILED(orm->Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
if (FAILED(orm.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
{
throw GLTFException("Failed to initialize from texture.");
}
auto ormPixels = orm->GetPixels();
auto metadata = orm->GetMetadata();
auto ormPixels = orm.GetPixels();
auto metadata = orm.GetMetadata();
for (size_t i = 0; i < metadata.width * metadata.height; i += 1)
{
// Occlusion: Occ [R] -> ORM [R]
*GetChannelValue(ormPixels, i, Channel::Red) = hasOcclusion ? *GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;
*GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Red) = hasOcclusion ? *GLTFTextureUtils::GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;
// Roughness: MR [G] -> ORM [G]
*GetChannelValue(ormPixels, i, Channel::Green) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
*GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Green) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
// Metalness: MR [B] -> ORM [B]
*GetChannelValue(ormPixels, i, Channel::Blue) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
*GLTFTextureUtils::GetChannelValue(ormPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
}
auto imagePath = SaveAsPng(orm, "packing_orm_" + material.id + ".png", outputDirectory);
// Convert with assumed sRGB because PNG defaults to that color space.
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*orm.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for storage.");
}
ormImageId = AddImageToDocument(outputDoc, imagePath);
auto imagePath = GLTFTextureUtils::SaveAsPng(&converted, "packing_orm_" + material.id + ".png", outputDirectory);
ormImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);
}
AddTextureToExtension(ormImageId, TexturePacking::OcclusionRoughnessMetallic, outputDoc, ormExtensionJson, ormAllocator);
@ -272,63 +200,71 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
if (packing & TexturePacking::RoughnessMetallicOcclusion && (hasMR || hasOcclusion))
{
auto rmo = std::make_unique<DirectX::ScratchImage>();
DirectX::ScratchImage rmo;
auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *occlusionImage->GetImage(0, 0, 0);
if (FAILED(rmo->Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
if (FAILED(rmo.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
{
throw GLTFException("Failed to initialize from texture.");
}
auto rmoPixels = rmo->GetPixels();
auto metadata = rmo->GetMetadata();
auto rmoPixels = rmo.GetPixels();
auto metadata = rmo.GetMetadata();
for (size_t i = 0; i < metadata.width * metadata.height; i += 1)
{
// Roughness: MR [G] -> RMO [R]
*GetChannelValue(rmoPixels, i, Channel::Red) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
*GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Red) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
// Metalness: MR [B] -> RMO [G]
*GetChannelValue(rmoPixels, i, Channel::Green) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
*GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Green) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
// Occlusion: Occ [R] -> RMO [B]
*GetChannelValue(rmoPixels, i, Channel::Blue) = hasOcclusion ? *GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;
*GLTFTextureUtils::GetChannelValue(rmoPixels, i, Channel::Blue) = hasOcclusion ? *GLTFTextureUtils::GetChannelValue(occlusionPixels, i, Channel::Red) : 255.0f;
}
auto imagePath = SaveAsPng(rmo, "packing_rmo_" + material.id + ".png", outputDirectory);
// Convert with assumed sRGB because PNG defaults to that color space.
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*rmo.GetImage(0, 0, 0), DXGI_FORMAT_B8G8R8X8_UNORM, DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_B8G8R8X8_UNORM for storage.");
}
auto imagePath = GLTFTextureUtils::SaveAsPng(&converted, "packing_rmo_" + material.id + ".png", outputDirectory);
// Add back to GLTF
auto rmoImageId = AddImageToDocument(outputDoc, imagePath);
auto rmoImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);
AddTextureToExtension(rmoImageId, TexturePacking::RoughnessMetallicOcclusion, outputDoc, ormExtensionJson, ormAllocator);
}
if (packingIncludesNrm && (hasMR || hasNormal))
{
auto nrm = std::make_unique<DirectX::ScratchImage>();
DirectX::ScratchImage nrm;
auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage(0, 0, 0) : *normalImage->GetImage(0, 0, 0);
if (FAILED(nrm->Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
if (FAILED(nrm.Initialize2D(sourceImage.format, sourceImage.width, sourceImage.height, 1, 1)))
{
throw GLTFException("Failed to initialize from texture.");
}
auto nrmPixels = nrm->GetPixels();
auto metadata = nrm->GetMetadata();
auto nrmPixels = nrm.GetPixels();
auto metadata = nrm.GetMetadata();
for (size_t i = 0; i < metadata.width * metadata.height; i += 1)
{
// Normal: N [RG] -> NRM [RG]
*GetChannelValue(nrmPixels, i, Channel::Red) = hasNormal ? *GetChannelValue(normalPixels, i, Channel::Red) : 255.0f;
*GetChannelValue(nrmPixels, i, Channel::Green) = hasNormal ? *GetChannelValue(normalPixels, i, Channel::Green) : 255.0f;
*GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Red) = hasNormal ? *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Red) : 255.0f;
*GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Green) = hasNormal ? *GLTFTextureUtils::GetChannelValue(normalPixels, i, Channel::Green) : 255.0f;
// Roughness: MR [G] -> NRM [B]
*GetChannelValue(nrmPixels, i, Channel::Blue) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
*GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Green) : 255.0f;
// Metalness: MR [B] -> NRM [A]
*GetChannelValue(nrmPixels, i, Channel::Alpha) = hasMR ? *GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
*GLTFTextureUtils::GetChannelValue(nrmPixels, i, Channel::Alpha) = hasMR ? *GLTFTextureUtils::GetChannelValue(mrPixels, i, Channel::Blue) : 255.0f;
}
auto imagePath = SaveAsPng(nrm, "packing_nrm_" + material.id + ".png", outputDirectory, &GUID_WICPixelFormat32bppBGRA);
// sRGB conversion not needed for PNG in BGRA
auto imagePath = GLTFTextureUtils::SaveAsPng(&nrm, "packing_nrm_" + material.id + ".png", outputDirectory, &GUID_WICPixelFormat32bppBGRA);
// Add back to GLTF
auto nrmImageId = AddImageToDocument(outputDoc, imagePath);
auto nrmImageId = GLTFTextureUtils::AddImageToDocument(outputDoc, imagePath);
AddTextureToExtension(nrmImageId, TexturePacking::NormalRoughnessMetallic, outputDoc, nrmExtensionJson, nrmAllocator);
}
@ -369,9 +305,9 @@ GLTFDocument GLTFTexturePackingUtils::PackMaterialForWindowsMR(const IStreamRead
return outputDoc;
}
GLTFDocument GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(const IStreamReader& streamReader, const GLTFDocument & doc, TexturePacking packing, const std::string& outputDirectory)
Document GLTFTexturePackingUtils::PackAllMaterialsForWindowsMR(std::shared_ptr<IStreamReader> streamReader, const Document & doc, TexturePacking packing, const std::string& outputDirectory)
{
GLTFDocument outputDoc(doc);
Document outputDoc(doc);
// No packing requested, return copy of document
if (packing == TexturePacking::None)

Просмотреть файл

@ -0,0 +1,118 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
#include "pch.h"
#include "GLTFTextureUtils.h"
using namespace Microsoft::glTF;
using namespace Microsoft::glTF::Toolkit;
DirectX::ScratchImage GLTFTextureUtils::LoadTexture(std::shared_ptr<const IStreamReader> streamReader, const Document& doc, const std::string& textureId, bool treatAsLinear)
{
DirectX::ScratchImage output;
const Texture& texture = doc.textures.Get(textureId);
GLTFResourceReader gltfResourceReader(streamReader);
const Image& image = doc.images.Get(texture.imageId);
std::vector<uint8_t> imageData = gltfResourceReader.ReadBinaryData(doc, image);
DirectX::TexMetadata info;
if (FAILED(DirectX::LoadFromDDSMemory(imageData.data(), imageData.size(), DirectX::DDS_FLAGS_NONE, &info, output)))
{
// DDS failed, try WIC
// Note: try DDS first since WIC can load some DDS (but not all), so we wouldn't want to get
// a partial or invalid DDS loaded from WIC.
if (FAILED(DirectX::LoadFromWICMemory(imageData.data(), imageData.size(), treatAsLinear ? DirectX::WIC_FLAGS_IGNORE_SRGB : DirectX::WIC_FLAGS_NONE, &info, output)))
{
throw GLTFException("Failed to load image - Image could not be loaded as DDS or read by WIC.");
}
}
if (info.format == DXGI_FORMAT_R32G32B32A32_FLOAT && treatAsLinear)
{
return output;
}
else
{
DirectX::ScratchImage converted;
if (FAILED(DirectX::Convert(*output.GetImage(0, 0, 0), DXGI_FORMAT_R32G32B32A32_FLOAT, treatAsLinear ? DirectX::TEX_FILTER_DEFAULT : DirectX::TEX_FILTER_SRGB_IN, DirectX::TEX_THRESHOLD_DEFAULT, converted)))
{
throw GLTFException("Failed to convert texture to DXGI_FORMAT_R32G32B32A32_FLOAT for processing.");
}
return converted;
}
}
// Constants for the format DXGI_FORMAT_R32G32B32A32_FLOAT
constexpr size_t DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE = 16;
float* GLTFTextureUtils::GetChannelValue(uint8_t * imageData, size_t offset, Channel channel)
{
return reinterpret_cast<float*>(imageData + offset * DXGI_FORMAT_R32G32B32A32_FLOAT_STRIDE + channel);
}
std::string GLTFTextureUtils::SaveAsPng(DirectX::ScratchImage* image, const std::string& fileName, const std::string& directory, const GUID* targetFormat)
{
wchar_t outputImageFullPath[MAX_PATH];
auto fileNameW = std::wstring(fileName.begin(), fileName.end());
auto directoryW = std::wstring(directory.begin(), directory.end());
if (FAILED(::PathCchCombine(outputImageFullPath, ARRAYSIZE(outputImageFullPath), directoryW.c_str(), fileNameW.c_str())))
{
throw GLTFException("Failed to compose output file path.");
}
const DirectX::Image* img = image->GetImage(0, 0, 0);
if (FAILED(SaveToWICFile(*img, DirectX::WIC_FLAGS::WIC_FLAGS_NONE, GUID_ContainerFormatPng, outputImageFullPath, targetFormat)))
{
throw GLTFException("Failed to save file.");
}
std::wstring outputImageFullPathStr(outputImageFullPath);
return std::string(outputImageFullPathStr.begin(), outputImageFullPathStr.end());
}
std::string GLTFTextureUtils::AddImageToDocument(Document& doc, const std::string& imageUri)
{
Image image;
auto imageId = std::to_string(doc.images.Size());
image.id = imageId;
image.uri = imageUri;
doc.images.Append(std::move(image));
return imageId;
}
void GLTFTextureUtils::ResizeIfNeeded(const std::unique_ptr<DirectX::ScratchImage>& image, size_t resizedWidth, size_t resizedHeight)
{
auto metadata = image->GetMetadata();
if (resizedWidth != metadata.width || resizedHeight != metadata.height)
{
DirectX::ScratchImage resized;
if (FAILED(DirectX::Resize(image->GetImages(), image->GetImageCount(), metadata, resizedWidth, resizedHeight, DirectX::TEX_FILTER_DEFAULT, resized)))
{
throw GLTFException("Failed to resize image while packing.");
}
*image = std::move(resized);
}
}
void GLTFTextureUtils::ResizeToLargest(std::unique_ptr<DirectX::ScratchImage>& image1, std::unique_ptr<DirectX::ScratchImage>& image2)
{
auto metadata1 = image1->GetMetadata();
auto metadata2 = image2->GetMetadata();
if (metadata1.height != metadata2.height || metadata1.width != metadata2.width)
{
auto resizedWidth = std::max(metadata1.width, metadata2.width);
auto resizedHeight = std::max(metadata1.height, metadata2.height);
ResizeIfNeeded(image1, resizedWidth, resizedHeight);
ResizeIfNeeded(image2, resizedWidth, resizedHeight);
}
}

Просмотреть файл

@ -7,11 +7,12 @@
#include "SerializeBinary.h"
#include "GLTFSDK/GLTF.h"
#include "GLTFSDK/GLTFDocument.h"
#include "GLTFSDK/Document.h"
#include "GLTFSDK/GLBResourceReader.h"
#include "GLTFSDK/GLBResourceWriter2.h"
#include "GLTFSDK/GLBResourceWriter.h"
#include "GLTFSDK/Serialize.h"
#include "GLTFSDK/BufferBuilder.h"
#include "GLTFSDK/ExtensionsKHR.h"
using namespace Microsoft::glTF;
using namespace Microsoft::glTF::Toolkit;
@ -23,9 +24,9 @@ namespace
auto extension = uri.substr(uri.rfind('.') + 1, 3);
std::transform(extension.begin(), extension.end(), extension.begin(), [](char c) { return static_cast<char>(::tolower(static_cast<int>(c))); });
if (extension == FILE_EXT_DDS)
if (extension == "dds")
{
return MIMETYPE_DDS;
return "image/vnd-ms.dds";
}
if (extension == FILE_EXT_JPEG)
@ -99,7 +100,7 @@ namespace
}
template <typename T>
void SerializeAccessor(const Accessor& accessor, const GLTFDocument& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)
void SerializeAccessor(const Accessor& accessor, const Document& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)
{
builder.AddBufferView(doc.bufferViews.Get(accessor.bufferViewId).target);
const std::vector<T>& accessorContents = reader.ReadBinaryData<T>(doc, accessor);
@ -121,7 +122,7 @@ namespace
}
}
void SerializeAccessor(const Accessor& accessor, const GLTFDocument& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)
void SerializeAccessor(const Accessor& accessor, const Document& doc, const GLTFResourceReader& reader, BufferBuilder& builder, const AccessorConversionStrategy& accessorConversion)
{
switch (accessor.componentType)
{
@ -149,41 +150,100 @@ namespace
}
}
void Microsoft::glTF::Toolkit::SerializeBinary(const GLTFDocument& gltfDocument,
void Microsoft::glTF::Toolkit::SerializeBinary(const Document& document,
const GLTFResourceReader& resourceReader,
std::unique_ptr<const IStreamFactory>&& outputStreamFactory,
std::shared_ptr<const IStreamWriter> outputStreamWriter,
const AccessorConversionStrategy& accessorConversion)
{
auto writer = std::make_unique<GLBResourceWriter2>(std::move(outputStreamFactory), std::string());
auto writer = std::make_unique<GLBResourceWriter>(std::move(outputStreamWriter));
GLTFDocument outputDoc(gltfDocument);
Document outputDoc(document);
outputDoc.buffers.Clear();
outputDoc.bufferViews.Clear();
outputDoc.accessors.Clear();
std::unique_ptr<BufferBuilder> builder = std::make_unique<BufferBuilder>(std::move(writer));
// Get the collection of bufferViews we won't move around
IndexedContainer<const BufferView> staticBufferViews = document.bufferViews;
for (const auto& accessor : document.accessors.Elements())
{
if (!accessor.bufferViewId.empty() && staticBufferViews.Has(accessor.bufferViewId))
{
staticBufferViews.Remove(accessor.bufferViewId);
}
}
for (const auto& image : outputDoc.images.Elements())
{
if (!image.bufferViewId.empty() && staticBufferViews.Has(image.bufferViewId))
{
staticBufferViews.Remove(image.bufferViewId);
}
}
size_t currentAccessorId = 0;
std::string currentAccessorIdStr = std::to_string(currentAccessorId);
size_t currentBufferViewId = 0;
std::string currentBufferViewIdStr = std::to_string(currentBufferViewId);
auto AdvanceAccessorId = [&currentAccessorId, &currentAccessorIdStr]()
{
currentAccessorId++;
currentAccessorIdStr = std::to_string(currentAccessorId);
};
auto AdvanceBufferViewId = [&currentBufferViewId, &currentBufferViewIdStr, &staticBufferViews]()
{
do
{
currentBufferViewId++;
currentBufferViewIdStr = std::to_string(currentBufferViewId);
} while (staticBufferViews.Has(currentBufferViewIdStr));
};
std::unique_ptr<BufferBuilder> builder = std::make_unique<BufferBuilder>(std::move(writer),
[](const BufferBuilder&) { return GLB_BUFFER_ID; },
[&currentBufferViewIdStr](const BufferBuilder&) { return currentBufferViewIdStr; },
[&currentAccessorIdStr](const BufferBuilder&) { return currentAccessorIdStr; });
// GLB buffer
builder->AddBuffer(GLB_BUFFER_ID);
// Serialize accessors
for (auto accessor : gltfDocument.accessors.Elements())
// Add those bufferView to the builder.
for (const auto& bufferView : staticBufferViews.Elements())
{
if (accessor.count > 0)
currentBufferViewIdStr = bufferView.id;
auto data = resourceReader.ReadBinaryData<uint8_t>(document, bufferView);
builder->AddBufferView(data);
}
// Return value to tracked state
currentBufferViewIdStr = std::to_string(currentBufferViewId);
if (staticBufferViews.Has(currentBufferViewIdStr))
{
AdvanceBufferViewId();
}
// Serialize accessors
for (const auto& accessor : document.accessors.Elements())
{
if (!accessor.bufferViewId.empty() && accessor.count > 0)
{
SerializeAccessor(accessor, gltfDocument, resourceReader, *builder, accessorConversion);
SerializeAccessor(accessor, document, resourceReader, *builder, accessorConversion);
AdvanceBufferViewId();
}
else
{
outputDoc.accessors.Append(accessor);
}
AdvanceAccessorId();
}
// Serialize images
for (auto image : outputDoc.images.Elements())
for (const auto& image : outputDoc.images.Elements())
{
Image newImage(image);
auto data = resourceReader.ReadBinaryData(gltfDocument, image);
auto data = resourceReader.ReadBinaryData(document, image);
auto imageBufferView = builder->AddBufferView(data);
AdvanceBufferViewId();
newImage.bufferViewId = imageBufferView.id;
if (image.mimeType.empty())
@ -196,10 +256,79 @@ void Microsoft::glTF::Toolkit::SerializeBinary(const GLTFDocument& gltfDocument,
outputDoc.images.Replace(newImage);
}
// Collect anything in extensions that looks like it should to be packed for the GLB.
for (auto& extension : outputDoc.extensions)
{
rapidjson::Document extensionJson;
extensionJson.Parse(extension.second.c_str());
if (!extensionJson.IsObject())
{
continue;
}
for (auto& member : extensionJson.GetObject())
{
if (!member.value.IsArray())
{
continue;
}
for (auto& possibleBuffer : member.value.GetArray())
{
if (!possibleBuffer.IsObject())
{
continue;
}
// Build an Image to object to use to load the data from.
Image tmpImg;
if (possibleBuffer.HasMember("uri"))
{
tmpImg.uri = possibleBuffer["uri"].GetString();
}
else
{
continue;
}
try
{
auto data = resourceReader.ReadBinaryData(document, tmpImg);
auto bufferView = builder->AddBufferView(data);
AdvanceBufferViewId();
possibleBuffer.RemoveMember("uri");
possibleBuffer.RemoveMember("bufferView");
possibleBuffer.AddMember("bufferView", rapidjson::Value(std::stoi(bufferView.id)), extensionJson.GetAllocator());
}
catch (...)
{
// Didn't work out.
continue;
}
}
}
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> jsonWriter(buffer);
extensionJson.Accept(jsonWriter);
extension.second = buffer.GetString();
}
// Fill in any gaps in the bufferViewList.
for (const auto& bufferView : staticBufferViews.Elements())
{
auto bufferViewId = std::stoul(bufferView.id);
while (bufferViewId > currentBufferViewId)
{
std::vector<uint8_t> data;
data.resize(4);
builder->AddBufferView(data);
AdvanceBufferViewId();
}
}
builder->Output(outputDoc);
// Add extensions and extras to bufferViews, if any
for (auto bufferView : gltfDocument.bufferViews.Elements())
for (auto bufferView : document.bufferViews.Elements())
{
auto fixedBufferView = outputDoc.bufferViews.Get(bufferView.id);
fixedBufferView.extensions = bufferView.extensions;
@ -208,18 +337,26 @@ void Microsoft::glTF::Toolkit::SerializeBinary(const GLTFDocument& gltfDocument,
outputDoc.bufferViews.Replace(fixedBufferView);
}
auto manifest = Serialize(outputDoc);
// We may have put the bufferViews in the IndexedContainer out of order sort them now.
auto finalBufferViewList = outputDoc.bufferViews;
outputDoc.bufferViews.Clear();
for (size_t i = 0; i < finalBufferViewList.Size(); i++)
{
outputDoc.bufferViews.Append(finalBufferViewList[std::to_string(i)]);
}
auto outputWriter = dynamic_cast<GLBResourceWriter2 *>(&builder->GetResourceWriter());
auto manifest = Serialize(outputDoc, KHR::GetKHRExtensionSerializer());
auto outputWriter = dynamic_cast<GLBResourceWriter*>(&builder->GetResourceWriter());
if (outputWriter != nullptr)
{
outputWriter->Flush(manifest, std::string());
}
}
void Microsoft::glTF::Toolkit::SerializeBinary(const GLTFDocument& gltfDocument, const IStreamReader& inputStreamReader,
std::unique_ptr<const IStreamFactory>&& outputStreamFactory,
void Microsoft::glTF::Toolkit::SerializeBinary(const Document& document, std::shared_ptr<const IStreamReader> inputStreamReader,
std::shared_ptr<const IStreamWriter> outputStreamWriter,
const AccessorConversionStrategy& accessorConversion)
{
SerializeBinary(gltfDocument, GLTFResourceReader{inputStreamReader}, std::move(outputStreamFactory), accessorConversion);
SerializeBinary(document, GLTFResourceReader{inputStreamReader}, std::move(outputStreamWriter), accessorConversion);
}