zeux / meshoptimizer

Mesh optimization library that makes meshes smaller and faster to render

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

gltfpack: obj material color

kzhsw opened this issue · comments

commented

Motivation:
In obj material (.mtl) files, colors and other options could be defined, but output glb model does not contain these information.

Example:
obj and mtl file:
input_obj.zip

converted glb file:
glb.zip

expected: a red cube
actual: a white cube

related code:

for (unsigned int mi = 0; mi < obj->material_count; ++mi)
{
cgltf_material& gm = data->materials[mi];
fastObjMaterial& om = obj->materials[mi];
gm.has_pbr_metallic_roughness = true;
gm.pbr_metallic_roughness.base_color_factor[0] = 1.0f;
gm.pbr_metallic_roughness.base_color_factor[1] = 1.0f;
gm.pbr_metallic_roughness.base_color_factor[2] = 1.0f;
gm.pbr_metallic_roughness.base_color_factor[3] = 1.0f;
gm.pbr_metallic_roughness.metallic_factor = 0.0f;
gm.pbr_metallic_roughness.roughness_factor = 1.0f;
gm.alpha_cutoff = 0.5f;
if (om.map_Kd.name)
{
gm.pbr_metallic_roughness.base_color_texture.texture = &data->textures[textureIndex(textures, om.map_Kd.name)];
gm.pbr_metallic_roughness.base_color_texture.scale = 1.0f;
gm.alpha_mode = (om.illum == 4 || om.illum == 6 || om.illum == 7 || om.illum == 9) ? cgltf_alpha_mode_mask : cgltf_alpha_mode_opaque;
}
if (om.map_d.name)
{
gm.alpha_mode = cgltf_alpha_mode_blend;
}
}

see also this for mapping from obj material to gltf material:
https://github.com/CesiumGS/obj2gltf/blob/a1709ac1fafa5546f592d232bde0a9f64b3bbd57/lib/loadMtl.js#L119-L159

quick and incomplete patch

Note this does not contains the pbr texture conversion code here

diff --git a/gltf/parseobj.cpp b/gltf/parseobj.cpp
index 14228d0..e38a885 100644
--- a/gltf/parseobj.cpp
+++ b/gltf/parseobj.cpp
@@ -62,12 +62,33 @@ static cgltf_data* parseSceneObj(fastObjMesh* obj)
                fastObjMaterial& om = obj->materials[mi];

                gm.has_pbr_metallic_roughness = true;
-               gm.pbr_metallic_roughness.base_color_factor[0] = 1.0f;
-               gm.pbr_metallic_roughness.base_color_factor[1] = 1.0f;
-               gm.pbr_metallic_roughness.base_color_factor[2] = 1.0f;
+               // baseColorFactor = material.diffuseColor;
+               gm.pbr_metallic_roughness.base_color_factor[0] = om.Kd[0];
+               gm.pbr_metallic_roughness.base_color_factor[1] = om.Kd[1];
+               gm.pbr_metallic_roughness.base_color_factor[2] = om.Kd[2];
                gm.pbr_metallic_roughness.base_color_factor[3] = 1.0f;
-               gm.pbr_metallic_roughness.metallic_factor = 0.0f;
-               gm.pbr_metallic_roughness.roughness_factor = 1.0f;
+               // emissiveFactor = material.emissiveColor
+               gm.emissive_factor[0] = om.Ke[0];
+               gm.emissive_factor[1] = om.Ke[1];
+               gm.emissive_factor[2] = om.Ke[2];
+               // Translate the blinn-phong model to the pbr metallic-roughness model
+               // Roughness factor is a combination of specular intensity and shininess
+               // Metallic factor is 0.0
+               // Textures are not converted for now
+               float specularIntensity = om.Ks[0] * 0.2125f + om.Ks[1] * 0.7154f + om.Ks[2] * 0.0721f;
+
+               // metallicFactor = material.specularColor[0]
+               gm.pbr_metallic_roughness.metallic_factor = 0.f;
+               // roughnessFactor = material.specularShininess
+               gm.pbr_metallic_roughness.roughness_factor = std::max(0.f, std::min(1.f - (om.Ns / 1000.f), 1.f));
+               // Low specular intensity values should produce a rough material even if shininess is high.
+               if (specularIntensity < 0.1) {
+                       gm.pbr_metallic_roughness.roughness_factor *= 1.0 - specularIntensity;
+               }
+               bool transparent = false;
+               if (om.d < 1.0f) {
+                       transparent = true;
+               }

                gm.alpha_cutoff = 0.5f;

@@ -77,6 +98,10 @@ static cgltf_data* parseSceneObj(fastObjMesh* obj)
                        gm.pbr_metallic_roughness.base_color_texture.scale = 1.0f;

                        gm.alpha_mode = (om.illum == 4 || om.illum == 6 || om.illum == 7 || om.illum == 9) ? cgltf_alpha_mode_mask : cgltf_alpha_mode_opaque;
+               } else {
+                       gm.pbr_metallic_roughness.base_color_factor[3] = om.d;
+                       gm.alpha_mode = transparent ? cgltf_alpha_mode_blend : cgltf_alpha_mode_opaque;
+                       gm.double_sided = transparent;
                }

                if (om.map_d.name)

Yeah this should be pretty easy to fix, I'll do this tomorrow. Thanks for the link - this will be helpful as a reference; I believe that code is not converting to the glTF materials strictly speaking (maybe they have a richer material model internally, or this includes glTF 1.0 and some other extensions?) as some .mtl features aren't really representable with glTF 2.0 + KHR extensions - for example separate alpha texture - but definitely at least basics like color should be covered.