Vertex and attribute compression to reduce the size of the vertex format.
This allows Godot to automatically compress meshes to save a lot of bandwidth. In general, this requires no interaction from the user and should result in no noticable quality loss. This scheme is not backwards compatible, so we have provided an upgrade mechanism, and a mesh versioning mechanism. Existing meshes can still be used as a result, but users can get a performance boost by reimporting assets.
This commit is contained in:
@@ -919,6 +919,12 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t mesh_flags = 0;
|
||||
|
||||
if (p_use_compression) {
|
||||
mesh_flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
|
||||
}
|
||||
|
||||
Ref<SurfaceTool> surftool;
|
||||
surftool.instantiate();
|
||||
surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
|
||||
@@ -969,14 +975,21 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p
|
||||
}
|
||||
|
||||
if (!normal_src) {
|
||||
//should always be normals
|
||||
// Should always have normals.
|
||||
surftool->generate_normals();
|
||||
}
|
||||
|
||||
if ((!binormal_src || !tangent_src) && normal_src && uv_src && force_make_tangents) {
|
||||
bool generate_tangents = (!binormal_src || !tangent_src) && uv_src && force_make_tangents;
|
||||
|
||||
if (generate_tangents) {
|
||||
surftool->generate_tangents();
|
||||
}
|
||||
|
||||
if (!binormal_src || !(tangent_src || generate_tangents) || p_mesh->get_blend_shape_count() != 0 || p_skin_controller) {
|
||||
// Can't compress if attributes missing or if using vertex weights.
|
||||
mesh_flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// FINALLY CREATE SUFRACE //
|
||||
////////////////////////////
|
||||
@@ -996,7 +1009,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p
|
||||
|
||||
// Enforce blend shape mask array format
|
||||
for (int mj = 0; mj < Mesh::ARRAY_MAX; mj++) {
|
||||
if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << mj))) {
|
||||
if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1ULL << mj))) {
|
||||
a[mj] = Variant();
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1024,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p
|
||||
}
|
||||
surface_name = material->get_name();
|
||||
}
|
||||
p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), mat, surface_name);
|
||||
p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), mat, surface_name, mesh_flags);
|
||||
}
|
||||
|
||||
/*****************/
|
||||
@@ -1773,7 +1786,7 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3
|
||||
state.use_mesh_builtin_materials = true;
|
||||
state.bake_fps = (float)p_options["animation/fps"];
|
||||
|
||||
Error err = state.load(p_path, flags, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, false);
|
||||
Error err = state.load(p_path, flags, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, !bool(p_flags & EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION));
|
||||
|
||||
if (r_err) {
|
||||
*r_err = err;
|
||||
|
||||
@@ -202,7 +202,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
|
||||
return OK;
|
||||
}
|
||||
|
||||
static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) {
|
||||
static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, bool p_disable_compression, List<String> *r_missing_deps) {
|
||||
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
|
||||
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
|
||||
|
||||
@@ -226,7 +226,11 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
bool generate_tangents = p_generate_tangents;
|
||||
Vector3 scale_mesh = p_scale_mesh;
|
||||
Vector3 offset_mesh = p_offset_mesh;
|
||||
int mesh_flags = 0;
|
||||
uint64_t mesh_flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
|
||||
|
||||
if (p_disable_compression) {
|
||||
mesh_flags = 0;
|
||||
}
|
||||
|
||||
Vector<Vector3> vertices;
|
||||
Vector<Vector3> normals;
|
||||
@@ -287,7 +291,6 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
uv.x = v[1].to_float();
|
||||
uv.y = 1.0 - v[2].to_float();
|
||||
uvs.push_back(uv);
|
||||
|
||||
} else if (l.begins_with("vn ")) {
|
||||
//normal
|
||||
Vector<String> v = l.split(" ", false);
|
||||
@@ -380,6 +383,9 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
|
||||
if (generate_tangents && uvs.size()) {
|
||||
surf_tool->generate_tangents();
|
||||
} else {
|
||||
// We need tangents in order to compress vertex data. So disable if tangents aren't generated.
|
||||
mesh_flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
|
||||
}
|
||||
|
||||
surf_tool->index();
|
||||
@@ -464,7 +470,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
|
||||
Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) {
|
||||
List<Ref<Mesh>> meshes;
|
||||
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps);
|
||||
Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), p_flags & IMPORT_FORCE_DISABLE_MESH_COMPRESSION, r_missing_deps);
|
||||
|
||||
if (err != OK) {
|
||||
if (r_err) {
|
||||
@@ -543,6 +549,7 @@ void ResourceImporterOBJ::get_import_options(const String &p_path, List<ImportOp
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "scale_mesh"), Vector3(1, 1, 1)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::VECTOR3, "offset_mesh"), Vector3(0, 0, 0)));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimize_mesh"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_disable_mesh_compression"), false));
|
||||
}
|
||||
|
||||
bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
|
||||
@@ -552,7 +559,7 @@ bool ResourceImporterOBJ::get_option_visibility(const String &p_path, const Stri
|
||||
Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
|
||||
List<Ref<Mesh>> meshes;
|
||||
|
||||
Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], nullptr);
|
||||
Error err = _parse_obj(p_source_file, meshes, true, p_options["generate_tangents"], p_options["optimize_mesh"], p_options["scale_mesh"], p_options["offset_mesh"], p_options["force_disable_mesh_compression"], nullptr);
|
||||
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
ERR_FAIL_COND_V(meshes.size() != 1, ERR_BUG);
|
||||
|
||||
@@ -112,6 +112,7 @@ void EditorSceneFormatImporter::_bind_methods() {
|
||||
BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
|
||||
BIND_CONSTANT(IMPORT_USE_NAMED_SKIN_BINDS);
|
||||
BIND_CONSTANT(IMPORT_DISCARD_MESHES_AND_MATERIALS);
|
||||
BIND_CONSTANT(IMPORT_FORCE_DISABLE_MESH_COMPRESSION);
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
@@ -1934,6 +1935,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/create_shadow_meshes"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Static (VoxelGI/SDFGI),Static Lightmaps (VoxelGI/SDFGI/LightmapGI),Dynamic (VoxelGI only)", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.2));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/force_disable_compression"), false));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
|
||||
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30));
|
||||
@@ -2428,6 +2430,11 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS;
|
||||
}
|
||||
|
||||
bool force_disable_compression = p_options["meshes/force_disable_compression"];
|
||||
if (force_disable_compression) {
|
||||
import_flags |= EditorSceneFormatImporter::IMPORT_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
}
|
||||
|
||||
Error err = OK;
|
||||
List<String> missing_deps; // for now, not much will be done with this
|
||||
Node *scene = importer->import_scene(src_path, import_flags, p_options, &missing_deps, &err);
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
IMPORT_GENERATE_TANGENT_ARRAYS = 8,
|
||||
IMPORT_USE_NAMED_SKIN_BINDS = 16,
|
||||
IMPORT_DISCARD_MESHES_AND_MATERIALS = 32, //used for optimizing animation import
|
||||
IMPORT_FORCE_DISABLE_MESH_COMPRESSION = 64,
|
||||
};
|
||||
|
||||
virtual uint32_t get_import_flags() const;
|
||||
|
||||
Reference in New Issue
Block a user