Skip to content

Commit

Permalink
Merge pull request #602 from zeux/gltf-texmerge
Browse files Browse the repository at this point in the history
gltfpack: Merge identical texture objects together
  • Loading branch information
zeux committed Sep 25, 2023
2 parents d65dbe7 + aa89e4f commit 65cec2f
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 74 deletions.
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

0 comments on commit 65cec2f

Please sign in to comment.