Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gltfpack: Merge identical texture objects together #602

Merged
merged 2 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions gltf/gltfpack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ static void printImageStats(const std::vector<BufferView>& views, TextureKind ki
printf("stats: image %s: %d bytes in %d images\n", name, int(bytes), int(count));
}

static bool printReport(const char* path, cgltf_data* data, const std::vector<BufferView>& views, const std::vector<Mesh>& meshes, size_t node_count, size_t mesh_count, size_t material_count, size_t animation_count, size_t json_size, size_t bin_size)
static bool printReport(const char* path, const std::vector<BufferView>& views, const std::vector<Mesh>& meshes, size_t node_count, size_t mesh_count, size_t texture_count, size_t material_count, size_t animation_count, size_t json_size, size_t bin_size)
{
size_t bytes[BufferView::Kind_Count] = {};

Expand Down Expand Up @@ -216,7 +216,7 @@ static bool printReport(const char* path, cgltf_data* data, const std::vector<Bu
fprintf(out, "\t\t\"nodeCount\": %d,\n", int(node_count));
fprintf(out, "\t\t\"meshCount\": %d,\n", int(mesh_count));
fprintf(out, "\t\t\"materialCount\": %d,\n", int(material_count));
fprintf(out, "\t\t\"textureCount\": %d,\n", int(data->textures_count));
fprintf(out, "\t\t\"textureCount\": %d,\n", int(texture_count));
fprintf(out, "\t\t\"animationCount\": %d\n", int(animation_count));
fprintf(out, "\t},\n");
fprintf(out, "\t\"render\": {\n");
Expand Down Expand Up @@ -332,9 +332,12 @@ static void process(cgltf_data* data, const char* input_path, const char* output

// material information is required for mesh and image processing
std::vector<MaterialInfo> materials(data->materials_count);
std::vector<TextureInfo> textures(data->textures_count);
std::vector<ImageInfo> images(data->images_count);

analyzeMaterials(data, materials, images);
analyzeMaterials(data, materials, textures, images);

mergeTextures(data, textures);

optimizeMaterials(data, input_path, images);

Expand Down Expand Up @@ -442,6 +445,7 @@ static void process(cgltf_data* data, const char* input_path, const char* output
size_t accr_offset = 0;
size_t node_offset = 0;
size_t mesh_offset = 0;
size_t texture_offset = 0;
size_t material_offset = 0;

for (size_t i = 0; i < data->samplers_count; ++i)
Expand Down Expand Up @@ -491,10 +495,16 @@ static void process(cgltf_data* data, const char* input_path, const char* output
{
const cgltf_texture& texture = data->textures[i];

if (!textures[i].keep)
continue;

comma(json_textures);
append(json_textures, "{");
writeTexture(json_textures, texture, texture.image ? &images[texture.image - data->images] : NULL, data, settings);
append(json_textures, "}");

assert(textures[i].remap == int(texture_offset));
texture_offset++;
}

for (size_t i = 0; i < data->materials_count; ++i)
Expand All @@ -508,7 +518,7 @@ static void process(cgltf_data* data, const char* input_path, const char* output

comma(json_materials);
append(json_materials, "{");
writeMaterial(json_materials, data, material, settings.quantize && !settings.pos_float ? &qp : NULL, settings.quantize && !settings.tex_float ? &qt_materials[i] : NULL);
writeMaterial(json_materials, data, material, settings.quantize && !settings.pos_float ? &qp : NULL, settings.quantize && !settings.tex_float ? &qt_materials[i] : NULL, textures);
if (settings.keep_extras)
writeExtras(json_materials, material.extras);
append(json_materials, "}");
Expand Down Expand Up @@ -884,7 +894,7 @@ static void process(cgltf_data* data, const char* input_path, const char* output

if (report_path)
{
if (!printReport(report_path, data, views, meshes, node_offset, mesh_offset, material_offset, animations.size(), json.size(), bin.size()))
if (!printReport(report_path, views, meshes, node_offset, mesh_offset, texture_offset, material_offset, animations.size(), json.size(), bin.size()))
{
fprintf(stderr, "Warning: cannot save report to %s\n", report_path);
}
Expand Down
13 changes: 11 additions & 2 deletions gltf/gltfpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ struct MaterialInfo
int remap;
};

struct TextureInfo
{
bool keep;

int remap;
};

struct ImageInfo
{
TextureKind kind;
Expand Down Expand Up @@ -304,9 +311,11 @@ void filterStreams(Mesh& mesh, const MaterialInfo& mi);
void mergeMeshMaterials(cgltf_data* data, std::vector<Mesh>& meshes, const Settings& settings);
void markNeededMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, const std::vector<Mesh>& meshes, const Settings& settings);

void mergeTextures(cgltf_data* data, std::vector<TextureInfo>& textures);

bool hasValidTransform(const cgltf_texture_view& view);

void analyzeMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, std::vector<ImageInfo>& images);
void analyzeMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, std::vector<TextureInfo>& textures, std::vector<ImageInfo>& images);
void optimizeMaterials(cgltf_data* data, const char* input_path, std::vector<ImageInfo>& images);

bool readImage(const cgltf_image& image, const char* input_path, std::string& data, std::string& mime_type);
Expand Down Expand Up @@ -350,7 +359,7 @@ void appendJson(std::string& s, const char* data);
const char* attributeType(cgltf_attribute_type type);
const char* animationPath(cgltf_animation_path_type type);

void writeMaterial(std::string& json, const cgltf_data* data, const cgltf_material& material, const QuantizationPosition* qp, const QuantizationTexture* qt);
void writeMaterial(std::string& json, const cgltf_data* data, const cgltf_material& material, const QuantizationPosition* qp, const QuantizationTexture* qt, std::vector<TextureInfo>& textures);
void writeBufferView(std::string& json, BufferView::Kind kind, StreamFormat::Filter filter, size_t count, size_t stride, size_t bin_offset, size_t bin_size, BufferView::Compression compression, size_t compressed_offset, size_t compressed_size);
void writeSampler(std::string& json, const cgltf_sampler& sampler);
void writeImage(std::string& json, std::vector<BufferView>& views, const cgltf_image& image, const ImageInfo& info, size_t index, const char* input_path, const Settings& settings);
Expand Down
89 changes: 65 additions & 24 deletions gltf/material.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@

#include <string.h>

static bool areTexturesEqual(const cgltf_texture& lhs, const cgltf_texture& rhs)
{
if (lhs.image != rhs.image)
return false;

if (lhs.sampler != rhs.sampler)
return false;

return true;
}

static bool areTextureViewsEqual(const cgltf_texture_view& lhs, const cgltf_texture_view& rhs)
{
if (lhs.has_transform != rhs.has_transform)
Expand All @@ -26,7 +37,7 @@ static bool areTextureViewsEqual(const cgltf_texture_view& lhs, const cgltf_text
return false;
}

if (lhs.texture != rhs.texture)
if (lhs.texture != rhs.texture && (!lhs.texture || !rhs.texture || !areTexturesEqual(*lhs.texture, *rhs.texture)))
return false;

if (lhs.texcoord != rhs.texcoord)
Expand Down Expand Up @@ -408,10 +419,13 @@ bool hasValidTransform(const cgltf_texture_view& view)
return false;
}

static void analyzeMaterialTexture(const cgltf_texture_view& view, TextureKind kind, MaterialInfo& mi, cgltf_data* data, std::vector<ImageInfo>& images)
static void analyzeMaterialTexture(const cgltf_texture_view& view, TextureKind kind, MaterialInfo& mi, cgltf_data* data, std::vector<TextureInfo>& textures, std::vector<ImageInfo>& images)
{
mi.usesTextureTransform |= hasValidTransform(view);

if (view.texture)
textures[view.texture - data->textures].keep = true;

if (view.texture && view.texture->image)
{
ImageInfo& info = images[view.texture->image - data->images];
Expand All @@ -429,70 +443,70 @@ static void analyzeMaterialTexture(const cgltf_texture_view& view, TextureKind k
}
}

static void analyzeMaterial(const cgltf_material& material, MaterialInfo& mi, cgltf_data* data, std::vector<ImageInfo>& images)
static void analyzeMaterial(const cgltf_material& material, MaterialInfo& mi, cgltf_data* data, std::vector<TextureInfo>& textures, std::vector<ImageInfo>& images)
{
if (material.has_pbr_metallic_roughness)
{
analyzeMaterialTexture(material.pbr_metallic_roughness.base_color_texture, TextureKind_Color, mi, data, images);
analyzeMaterialTexture(material.pbr_metallic_roughness.metallic_roughness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.pbr_metallic_roughness.base_color_texture, TextureKind_Color, mi, data, textures, images);
analyzeMaterialTexture(material.pbr_metallic_roughness.metallic_roughness_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_pbr_specular_glossiness)
{
analyzeMaterialTexture(material.pbr_specular_glossiness.diffuse_texture, TextureKind_Color, mi, data, images);
analyzeMaterialTexture(material.pbr_specular_glossiness.specular_glossiness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.pbr_specular_glossiness.diffuse_texture, TextureKind_Color, mi, data, textures, images);
analyzeMaterialTexture(material.pbr_specular_glossiness.specular_glossiness_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_clearcoat)
{
analyzeMaterialTexture(material.clearcoat.clearcoat_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.clearcoat.clearcoat_roughness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.clearcoat.clearcoat_normal_texture, TextureKind_Normal, mi, data, images);
analyzeMaterialTexture(material.clearcoat.clearcoat_texture, TextureKind_Attrib, mi, data, textures, images);
analyzeMaterialTexture(material.clearcoat.clearcoat_roughness_texture, TextureKind_Attrib, mi, data, textures, images);
analyzeMaterialTexture(material.clearcoat.clearcoat_normal_texture, TextureKind_Normal, mi, data, textures, images);
}

if (material.has_transmission)
{
analyzeMaterialTexture(material.transmission.transmission_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.transmission.transmission_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_specular)
{
analyzeMaterialTexture(material.specular.specular_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.specular.specular_color_texture, TextureKind_Color, mi, data, images);
analyzeMaterialTexture(material.specular.specular_texture, TextureKind_Attrib, mi, data, textures, images);
analyzeMaterialTexture(material.specular.specular_color_texture, TextureKind_Color, mi, data, textures, images);
}

if (material.has_sheen)
{
analyzeMaterialTexture(material.sheen.sheen_color_texture, TextureKind_Color, mi, data, images);
analyzeMaterialTexture(material.sheen.sheen_roughness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.sheen.sheen_color_texture, TextureKind_Color, mi, data, textures, images);
analyzeMaterialTexture(material.sheen.sheen_roughness_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_volume)
{
analyzeMaterialTexture(material.volume.thickness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.volume.thickness_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_iridescence)
{
analyzeMaterialTexture(material.iridescence.iridescence_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.iridescence.iridescence_thickness_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.iridescence.iridescence_texture, TextureKind_Attrib, mi, data, textures, images);
analyzeMaterialTexture(material.iridescence.iridescence_thickness_texture, TextureKind_Attrib, mi, data, textures, images);
}

if (material.has_anisotropy)
{
analyzeMaterialTexture(material.anisotropy.anisotropy_texture, TextureKind_Normal, mi, data, images);
analyzeMaterialTexture(material.anisotropy.anisotropy_texture, TextureKind_Normal, mi, data, textures, images);
}

analyzeMaterialTexture(material.normal_texture, TextureKind_Normal, mi, data, images);
analyzeMaterialTexture(material.occlusion_texture, TextureKind_Attrib, mi, data, images);
analyzeMaterialTexture(material.emissive_texture, TextureKind_Color, mi, data, images);
analyzeMaterialTexture(material.normal_texture, TextureKind_Normal, mi, data, textures, images);
analyzeMaterialTexture(material.occlusion_texture, TextureKind_Attrib, mi, data, textures, images);
analyzeMaterialTexture(material.emissive_texture, TextureKind_Color, mi, data, textures, images);
}

void analyzeMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, std::vector<ImageInfo>& images)
void analyzeMaterials(cgltf_data* data, std::vector<MaterialInfo>& materials, std::vector<TextureInfo>& textures, std::vector<ImageInfo>& images)
{
for (size_t i = 0; i < data->materials_count; ++i)
{
analyzeMaterial(data->materials[i], materials[i], data, images);
analyzeMaterial(data->materials[i], materials[i], data, textures, images);
}
}

Expand Down Expand Up @@ -538,3 +552,30 @@ void optimizeMaterials(cgltf_data* data, const char* input_path, std::vector<Ima
}
}
}

void mergeTextures(cgltf_data* data, std::vector<TextureInfo>& textures)
{
size_t offset = 0;

for (size_t i = 0; i < textures.size(); ++i)
{
TextureInfo& info = textures[i];

if (!info.keep)
continue;

for (size_t j = 0; j < i; ++j)
if (textures[j].keep && areTexturesEqual(data->textures[i], data->textures[j]))
{
info.keep = false;
info.remap = textures[j].remap;
break;
}

if (info.keep)
{
info.remap = int(offset);
offset++;
}
}
}
Loading