Cache materials in gltf as the abstract class of Material

Use the abstract material class instead of BaseMaterial3D. This allows inserting ShaderMaterials into gltf. Like in VRM.
This commit is contained in:
K. S. Ernest (iFire) Lee 2022-11-23 15:29:01 -08:00
parent e3a51e53ef
commit baab97302a
4 changed files with 207 additions and 199 deletions

View File

@ -66,7 +66,7 @@
</description> </description>
</method> </method>
<method name="get_materials"> <method name="get_materials">
<return type="BaseMaterial3D[]" /> <return type="Material[]" />
<description> <description>
</description> </description>
</method> </method>
@ -169,7 +169,7 @@
</method> </method>
<method name="set_materials"> <method name="set_materials">
<return type="void" /> <return type="void" />
<param index="0" name="materials" type="BaseMaterial3D[]" /> <param index="0" name="materials" type="Material[]" />
<description> <description>
</description> </description>
</method> </method>

View File

@ -2484,12 +2484,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
if (surface_i < instance_materials.size()) { if (surface_i < instance_materials.size()) {
v = instance_materials.get(surface_i); v = instance_materials.get(surface_i);
} }
Ref<BaseMaterial3D> mat = v; Ref<Material> mat = v;
if (!mat.is_valid()) { if (!mat.is_valid()) {
mat = import_mesh->get_surface_material(surface_i); mat = import_mesh->get_surface_material(surface_i);
} }
if (mat.is_valid()) { if (mat.is_valid()) {
HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat); HashMap<Ref<Material>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat);
if (material_cache_i && material_cache_i->value != -1) { if (material_cache_i && material_cache_i->value != -1) {
primitive["material"] = material_cache_i->value; primitive["material"] = material_cache_i->value;
} else { } else {
@ -2937,16 +2937,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
} }
} }
Ref<BaseMaterial3D> mat; Ref<Material> mat;
String mat_name; String mat_name;
if (!state->discard_meshes_and_materials) { if (!state->discard_meshes_and_materials) {
if (p.has("material")) { if (p.has("material")) {
const int material = p["material"]; const int material = p["material"];
ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
Ref<BaseMaterial3D> mat3d = state->materials[material]; Ref<Material> mat3d = state->materials[material];
ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
if (has_vertex_color) {
mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); Ref<BaseMaterial3D> base_material = mat3d;
if (has_vertex_color && base_material.is_valid()) {
base_material->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
} }
mat = mat3d; mat = mat3d;
@ -2954,7 +2956,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
Ref<StandardMaterial3D> mat3d; Ref<StandardMaterial3D> mat3d;
mat3d.instantiate(); mat3d.instantiate();
if (has_vertex_color) { if (has_vertex_color) {
mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
} }
mat = mat3d; mat = mat3d;
} }
@ -3382,8 +3384,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Array materials; Array materials;
for (int32_t i = 0; i < state->materials.size(); i++) { for (int32_t i = 0; i < state->materials.size(); i++) {
Dictionary d; Dictionary d;
Ref<Material> material = state->materials[i];
Ref<BaseMaterial3D> material = state->materials[i];
if (material.is_null()) { if (material.is_null()) {
materials.push_back(d); materials.push_back(d);
continue; continue;
@ -3391,11 +3392,12 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
if (!material->get_name().is_empty()) { if (!material->get_name().is_empty()) {
d["name"] = _gen_unique_name(state, material->get_name()); d["name"] = _gen_unique_name(state, material->get_name());
} }
{ Ref<BaseMaterial3D> base_material = material;
if (base_material.is_valid()) {
Dictionary mr; Dictionary mr;
{ {
Array arr; Array arr;
const Color c = material->get_albedo().srgb_to_linear(); const Color c = base_material->get_albedo().srgb_to_linear();
arr.push_back(c.r); arr.push_back(c.r);
arr.push_back(c.g); arr.push_back(c.g);
arr.push_back(c.b); arr.push_back(c.b);
@ -3404,12 +3406,13 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
} }
{ {
Dictionary bct; Dictionary bct;
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); if (base_material.is_valid()) {
Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
GLTFTextureIndex gltf_texture_index = -1; GLTFTextureIndex gltf_texture_index = -1;
if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
albedo_texture->set_name(material->get_name() + "_albedo"); albedo_texture->set_name(material->get_name() + "_albedo");
gltf_texture_index = _set_texture(state, albedo_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); gltf_texture_index = _set_texture(state, albedo_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
} }
if (gltf_texture_index != -1) { if (gltf_texture_index != -1) {
bct["index"] = gltf_texture_index; bct["index"] = gltf_texture_index;
@ -3421,20 +3424,21 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
mr["baseColorTexture"] = bct; mr["baseColorTexture"] = bct;
} }
} }
}
mr["metallicFactor"] = material->get_metallic(); if (base_material.is_valid()) {
mr["roughnessFactor"] = material->get_roughness(); mr["metallicFactor"] = base_material->get_metallic();
bool has_roughness = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid(); mr["roughnessFactor"] = base_material->get_roughness();
bool has_ao = material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid(); bool has_roughness = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS)->get_image().is_valid();
bool has_metalness = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid(); bool has_ao = base_material->get_feature(BaseMaterial3D::FEATURE_AMBIENT_OCCLUSION) && base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION).is_valid();
bool has_metalness = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC).is_valid() && base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC)->get_image().is_valid();
if (has_ao || has_roughness || has_metalness) { if (has_ao || has_roughness || has_metalness) {
Dictionary mrt; Dictionary mrt;
Ref<Texture2D> roughness_texture = material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS); Ref<Texture2D> roughness_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ROUGHNESS);
BaseMaterial3D::TextureChannel roughness_channel = material->get_roughness_texture_channel(); BaseMaterial3D::TextureChannel roughness_channel = base_material->get_roughness_texture_channel();
Ref<Texture2D> metallic_texture = material->get_texture(BaseMaterial3D::TEXTURE_METALLIC); Ref<Texture2D> metallic_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_METALLIC);
BaseMaterial3D::TextureChannel metalness_channel = material->get_metallic_texture_channel(); BaseMaterial3D::TextureChannel metalness_channel = base_material->get_metallic_texture_channel();
Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); Ref<Texture2D> ao_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION);
BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); BaseMaterial3D::TextureChannel ao_channel = base_material->get_ao_texture_channel();
Ref<ImageTexture> orm_texture; Ref<ImageTexture> orm_texture;
orm_texture.instantiate(); orm_texture.instantiate();
Ref<Image> orm_image; Ref<Image> orm_image;
@ -3480,7 +3484,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
metallness_image->decompress(); metallness_image->decompress();
} }
} }
Ref<Texture2D> albedo_texture = material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO); Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) { if (albedo_texture.is_valid() && albedo_texture->get_image().is_valid()) {
height = albedo_texture->get_height(); height = albedo_texture->get_height();
width = albedo_texture->get_width(); width = albedo_texture->get_width();
@ -3539,7 +3543,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex orm_texture_index = -1; GLTFTextureIndex orm_texture_index = -1;
if (has_ao || has_roughness || has_metalness) { if (has_ao || has_roughness || has_metalness) {
orm_texture->set_name(material->get_name() + "_orm"); orm_texture->set_name(material->get_name() + "_orm");
orm_texture_index = _set_texture(state, orm_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); orm_texture_index = _set_texture(state, orm_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
} }
if (has_ao) { if (has_ao) {
Dictionary occt; Dictionary occt;
@ -3556,15 +3560,15 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
mr["metallicRoughnessTexture"] = mrt; mr["metallicRoughnessTexture"] = mrt;
} }
} }
}
d["pbrMetallicRoughness"] = mr; d["pbrMetallicRoughness"] = mr;
} }
if (base_material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) {
Dictionary nt; Dictionary nt;
Ref<ImageTexture> tex; Ref<ImageTexture> tex;
tex.instantiate(); tex.instantiate();
{ {
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); Ref<Texture2D> normal_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
if (normal_texture.is_valid()) { if (normal_texture.is_valid()) {
// Code for uncompressing RG normal maps // Code for uncompressing RG normal maps
Ref<Image> img = normal_texture->get_image(); Ref<Image> img = normal_texture->get_image();
@ -3594,30 +3598,30 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
GLTFTextureIndex gltf_texture_index = -1; GLTFTextureIndex gltf_texture_index = -1;
if (tex.is_valid() && tex->get_image().is_valid()) { if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal"); tex->set_name(material->get_name() + "_normal");
gltf_texture_index = _set_texture(state, tex, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); gltf_texture_index = _set_texture(state, tex, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
} }
nt["scale"] = material->get_normal_scale(); nt["scale"] = base_material->get_normal_scale();
if (gltf_texture_index != -1) { if (gltf_texture_index != -1) {
nt["index"] = gltf_texture_index; nt["index"] = gltf_texture_index;
d["normalTexture"] = nt; d["normalTexture"] = nt;
} }
} }
if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
const Color c = material->get_emission().linear_to_srgb(); const Color c = base_material->get_emission().linear_to_srgb();
Array arr; Array arr;
arr.push_back(c.r); arr.push_back(c.r);
arr.push_back(c.g); arr.push_back(c.g);
arr.push_back(c.b); arr.push_back(c.b);
d["emissiveFactor"] = arr; d["emissiveFactor"] = arr;
} }
if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) { if (base_material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
Dictionary et; Dictionary et;
Ref<Texture2D> emission_texture = material->get_texture(BaseMaterial3D::TEXTURE_EMISSION); Ref<Texture2D> emission_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
GLTFTextureIndex gltf_texture_index = -1; GLTFTextureIndex gltf_texture_index = -1;
if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) { if (emission_texture.is_valid() && emission_texture->get_image().is_valid()) {
emission_texture->set_name(material->get_name() + "_emission"); emission_texture->set_name(material->get_name() + "_emission");
gltf_texture_index = _set_texture(state, emission_texture, material->get_texture_filter(), material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT)); gltf_texture_index = _set_texture(state, emission_texture, base_material->get_texture_filter(), base_material->get_flag(BaseMaterial3D::FLAG_USE_TEXTURE_REPEAT));
} }
if (gltf_texture_index != -1) { if (gltf_texture_index != -1) {
@ -3625,14 +3629,14 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
d["emissiveTexture"] = et; d["emissiveTexture"] = et;
} }
} }
const bool ds = material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED; const bool ds = base_material->get_cull_mode() == BaseMaterial3D::CULL_DISABLED;
if (ds) { if (ds) {
d["doubleSided"] = ds; d["doubleSided"] = ds;
} }
if (material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) { if (base_material->get_transparency() == BaseMaterial3D::TRANSPARENCY_ALPHA_SCISSOR) {
d["alphaMode"] = "MASK"; d["alphaMode"] = "MASK";
d["alphaCutoff"] = material->get_alpha_scissor_threshold(); d["alphaCutoff"] = base_material->get_alpha_scissor_threshold();
} else if (material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) { } else if (base_material->get_transparency() != BaseMaterial3D::TRANSPARENCY_DISABLED) {
d["alphaMode"] = "BLEND"; d["alphaMode"] = "BLEND";
} }
materials.push_back(d); materials.push_back(d);
@ -3838,6 +3842,7 @@ void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMater
if (d.has("extensions")) { if (d.has("extensions")) {
const Dictionary &extensions = d["extensions"]; const Dictionary &extensions = d["extensions"];
if (extensions.has("KHR_texture_transform")) { if (extensions.has("KHR_texture_transform")) {
if (material.is_valid()) {
const Dictionary &texture_transform = extensions["KHR_texture_transform"]; const Dictionary &texture_transform = extensions["KHR_texture_transform"];
const Array &offset_arr = texture_transform["offset"]; const Array &offset_arr = texture_transform["offset"];
if (offset_arr.size() == 2) { if (offset_arr.size() == 2) {
@ -3852,15 +3857,22 @@ void GLTFDocument::_set_texture_transform_uv1(const Dictionary &d, Ref<BaseMater
} }
} }
} }
}
} }
void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) { void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Ref<BaseMaterial3D> p_material) {
if (r_spec_gloss.is_null()) {
return;
}
if (r_spec_gloss->spec_gloss_img.is_null()) { if (r_spec_gloss->spec_gloss_img.is_null()) {
return; return;
} }
if (r_spec_gloss->diffuse_img.is_null()) { if (r_spec_gloss->diffuse_img.is_null()) {
return; return;
} }
if (p_material.is_null()) {
return;
}
bool has_roughness = false; bool has_roughness = false;
bool has_metal = false; bool has_metal = false;
p_material->set_roughness(1.0f); p_material->set_roughness(1.0f);
@ -6657,21 +6669,17 @@ Dictionary _serialize_texture_transform_uv(Vector2 p_offset, Vector2 p_scale) {
} }
Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) { Dictionary GLTFDocument::_serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material) {
if (p_material.is_valid()) { ERR_FAIL_NULL_V(p_material, Dictionary());
Vector3 offset = p_material->get_uv1_offset(); Vector3 offset = p_material->get_uv1_offset();
Vector3 scale = p_material->get_uv1_scale(); Vector3 scale = p_material->get_uv1_scale();
return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y));
}
return Dictionary();
} }
Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) { Dictionary GLTFDocument::_serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material) {
if (p_material.is_valid()) { ERR_FAIL_NULL_V(p_material, Dictionary());
Vector3 offset = p_material->get_uv2_offset(); Vector3 offset = p_material->get_uv2_offset();
Vector3 scale = p_material->get_uv2_scale(); Vector3 scale = p_material->get_uv2_scale();
return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y)); return _serialize_texture_transform_uv(Vector2(offset.x, offset.y), Vector2(scale.x, scale.y));
}
return Dictionary();
} }
Error GLTFDocument::_serialize_version(Ref<GLTFState> state) { Error GLTFDocument::_serialize_version(Ref<GLTFState> state) {

View File

@ -209,11 +209,11 @@ void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) {
GLTFTemplateConvert::set_from_array(meshes, p_meshes); GLTFTemplateConvert::set_from_array(meshes, p_meshes);
} }
TypedArray<BaseMaterial3D> GLTFState::get_materials() { TypedArray<Material> GLTFState::get_materials() {
return GLTFTemplateConvert::to_array(materials); return GLTFTemplateConvert::to_array(materials);
} }
void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) { void GLTFState::set_materials(TypedArray<Material> p_materials) {
GLTFTemplateConvert::set_from_array(materials, p_materials); GLTFTemplateConvert::set_from_array(materials, p_materials);
} }

View File

@ -72,8 +72,8 @@ class GLTFState : public Resource {
Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to. Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to.
Vector<AnimationPlayer *> animation_players; Vector<AnimationPlayer *> animation_players;
HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache; HashMap<Ref<Material>, GLTFMaterialIndex> material_cache;
Vector<Ref<BaseMaterial3D>> materials; Vector<Ref<Material>> materials;
String scene_name; String scene_name;
Vector<int> root_nodes; Vector<int> root_nodes;
@ -138,8 +138,8 @@ public:
TypedArray<GLTFMesh> get_meshes(); TypedArray<GLTFMesh> get_meshes();
void set_meshes(TypedArray<GLTFMesh> p_meshes); void set_meshes(TypedArray<GLTFMesh> p_meshes);
TypedArray<BaseMaterial3D> get_materials(); TypedArray<Material> get_materials();
void set_materials(TypedArray<BaseMaterial3D> p_materials); void set_materials(TypedArray<Material> p_materials);
String get_scene_name(); String get_scene_name();
void set_scene_name(String p_scene_name); void set_scene_name(String p_scene_name);