diff options
author | clayjohn <claynjohn@gmail.com> | 2023-08-29 21:04:32 +0200 |
---|---|---|
committer | clayjohn <claynjohn@gmail.com> | 2023-10-05 12:02:23 -0600 |
commit | 51ed3aef63c0fdfc7666c004cc6d94dd15322d81 (patch) | |
tree | de596e05a1319438fb08024f23be417d29446494 /servers/rendering/renderer_rd/storage_rd | |
parent | d31794c4a26e5e10fc30c34a1ae9722fd9f50123 (diff) | |
download | redot-engine-51ed3aef63c0fdfc7666c004cc6d94dd15322d81.tar.gz |
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.
Diffstat (limited to 'servers/rendering/renderer_rd/storage_rd')
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp | 222 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/storage_rd/mesh_storage.h | 27 |
2 files changed, 172 insertions, 77 deletions
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index cb7eb3cd59..14605b308e 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp @@ -270,10 +270,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) uint32_t skin_stride = 0; for (int i = 0; i < RS::ARRAY_WEIGHTS; i++) { - if ((p_surface.format & (1 << i))) { + if ((p_surface.format & (1ULL << i))) { switch (i) { case RS::ARRAY_VERTEX: { - if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) { + if ((p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) || (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { stride += sizeof(float) * 2; } else { stride += sizeof(float) * 3; @@ -281,22 +281,31 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } break; case RS::ARRAY_NORMAL: { - stride += sizeof(int32_t); + stride += sizeof(uint16_t) * 2; } break; case RS::ARRAY_TANGENT: { - stride += sizeof(int32_t); - + if (!(p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + stride += sizeof(uint16_t) * 2; + } } break; case RS::ARRAY_COLOR: { attrib_stride += sizeof(uint32_t); } break; case RS::ARRAY_TEX_UV: { - attrib_stride += sizeof(float) * 2; + if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + attrib_stride += sizeof(uint16_t) * 2; + } else { + attrib_stride += sizeof(float) * 2; + } } break; case RS::ARRAY_TEX_UV2: { - attrib_stride += sizeof(float) * 2; + if (p_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + attrib_stride += sizeof(uint16_t) * 2; + } else { + attrib_stride += sizeof(float) * 2; + } } break; case RS::ARRAY_CUSTOM0: @@ -338,59 +347,96 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) #endif - Mesh::Surface *s = memnew(Mesh::Surface); + uint64_t surface_version = p_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); + RS::SurfaceData new_surface = p_surface; +#ifdef DISABLE_DEPRECATED - s->format = p_surface.format; - s->primitive = p_surface.primitive; + ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Surface version provided (" + itos(int(surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT)) + ") does not match current version (" + itos(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) + ")"); - bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0); +#else - if (p_surface.vertex_data.size()) { - s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage); - s->vertex_buffer_size = p_surface.vertex_data.size(); + if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { + RS::_fix_surface_compatibility(new_surface); + surface_version = new_surface.format & (RS::ARRAY_FLAG_FORMAT_VERSION_MASK << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); + ERR_FAIL_COND_MSG(surface_version != RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, + "Surface version provided (" + + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + + ") does not match current version (" + + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + + ")"); } +#endif - if (p_surface.attribute_data.size()) { - s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data); + Mesh::Surface *s = memnew(Mesh::Surface); + + s->format = new_surface.format; + s->primitive = new_surface.primitive; + + bool use_as_storage = (new_surface.skin_data.size() || mesh->blend_shape_count > 0); + + if (new_surface.vertex_data.size()) { + // If we have an uncompressed surface that contains normals, but not tangents, we need to differentiate the array + // from a compressed array in the shader. To do so, we allow the the normal to read 4 components out of the buffer + // But only give it 2 components per normal. So essentially, each vertex reads the next normal in normal.zw. + // This allows us to avoid adding a shader permutation, and avoid passing dummy tangents. Since the stride is kept small + // this should still be a net win for bandwidth. + // If we do this, then the last normal will read past the end of the array. So we need to pad the array with dummy data. + if (!(new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (new_surface.format & RS::ARRAY_FORMAT_NORMAL) && !(new_surface.format & RS::ARRAY_FORMAT_TANGENT)) { + // Unfortunately, we need to copy the buffer, which is fine as doing a resize triggers a CoW anyway. + Vector<uint8_t> new_vertex_data; + new_vertex_data.resize_zeroed(new_surface.vertex_data.size() + sizeof(uint16_t) * 2); + memcpy(new_vertex_data.ptrw(), new_surface.vertex_data.ptr(), new_surface.vertex_data.size()); + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_vertex_data.size(), new_vertex_data, use_as_storage); + s->vertex_buffer_size = new_vertex_data.size(); + } else { + s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.vertex_data.size(), new_surface.vertex_data, use_as_storage); + s->vertex_buffer_size = new_surface.vertex_data.size(); + } + } + + if (new_surface.attribute_data.size()) { + s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.attribute_data.size(), new_surface.attribute_data); } - if (p_surface.skin_data.size()) { - s->skin_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.skin_data.size(), p_surface.skin_data, use_as_storage); - s->skin_buffer_size = p_surface.skin_data.size(); + if (new_surface.skin_data.size()) { + s->skin_buffer = RD::get_singleton()->vertex_buffer_create(new_surface.skin_data.size(), new_surface.skin_data, use_as_storage); + s->skin_buffer_size = new_surface.skin_data.size(); } - s->vertex_count = p_surface.vertex_count; + s->vertex_count = new_surface.vertex_count; - if (p_surface.format & RS::ARRAY_FORMAT_BONES) { + if (new_surface.format & RS::ARRAY_FORMAT_BONES) { mesh->has_bone_weights = true; } - if (p_surface.index_count) { - bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0; + if (new_surface.index_count) { + bool is_index_16 = new_surface.vertex_count <= 65536 && new_surface.vertex_count > 0; - s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false); - s->index_count = p_surface.index_count; + s->index_buffer = RD::get_singleton()->index_buffer_create(new_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.index_data, false); + s->index_count = new_surface.index_count; s->index_array = RD::get_singleton()->index_array_create(s->index_buffer, 0, s->index_count); - if (p_surface.lods.size()) { - s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size()); - s->lod_count = p_surface.lods.size(); + if (new_surface.lods.size()) { + s->lods = memnew_arr(Mesh::Surface::LOD, new_surface.lods.size()); + s->lod_count = new_surface.lods.size(); - for (int i = 0; i < p_surface.lods.size(); i++) { - uint32_t indices = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); - s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data); + for (int i = 0; i < new_surface.lods.size(); i++) { + uint32_t indices = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); + s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, new_surface.lods[i].index_data); s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices); - s->lods[i].edge_length = p_surface.lods[i].edge_length; + s->lods[i].edge_length = new_surface.lods[i].edge_length; s->lods[i].index_count = indices; } } } - ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both"); + ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both"); - s->aabb = p_surface.aabb; - s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them. + s->aabb = new_surface.aabb; + s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them. + + s->uv_scale = new_surface.uv_scale; if (mesh->blend_shape_count > 0) { - s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(p_surface.blend_shape_data.size(), p_surface.blend_shape_data); + s->blend_shape_buffer = RD::get_singleton()->storage_buffer_create(new_surface.blend_shape_data.size(), new_surface.blend_shape_data); } if (use_as_storage) { @@ -433,13 +479,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } if (mesh->surface_count == 0) { - mesh->aabb = p_surface.aabb; + mesh->aabb = new_surface.aabb; } else { - mesh->aabb.merge_with(p_surface.aabb); + mesh->aabb.merge_with(new_surface.aabb); } mesh->skeleton_aabb_version = 0; - s->material = p_surface.material; + s->material = new_surface.material; mesh->surfaces = (Mesh::Surface **)memrealloc(mesh->surfaces, sizeof(Mesh::Surface *) * (mesh->surface_count + 1)); mesh->surfaces[mesh->surface_count] = s; @@ -545,6 +591,11 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.format = s.format; if (s.vertex_buffer.is_valid()) { sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer); + // When using an uncompressed buffer with normals, but without tangents, we have to trim the padding. + if (!(s.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && (s.format & RS::ARRAY_FORMAT_NORMAL) && !(s.format & RS::ARRAY_FORMAT_TANGENT)) { + Vector<uint8_t> new_vertex_data; + sd.vertex_data.resize(sd.vertex_data.size() - sizeof(uint16_t) * 2); + } } if (s.attribute_buffer.is_valid()) { sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer); @@ -560,6 +611,7 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { sd.index_data = RD::get_singleton()->buffer_get_data(s.index_buffer); } sd.aabb = s.aabb; + sd.uv_scale = s.uv_scale; for (uint32_t i = 0; i < s.lod_count; i++) { RS::SurfaceData::LOD lod; lod.edge_length = s.lods[i].edge_length; @@ -1016,8 +1068,10 @@ void MeshStorage::update_mesh_instances() { push_constant.has_skeleton = sk != nullptr && sk->use_2d == array_is_2d && (mi->mesh->surfaces[i]->format & RS::ARRAY_FORMAT_BONES); push_constant.has_blend_shape = mi->mesh->blend_shape_count > 0; + push_constant.normal_tangent_stride = (push_constant.has_normal ? 1 : 0) + (push_constant.has_tangent ? 1 : 0); + push_constant.vertex_count = mi->mesh->surfaces[i]->vertex_count; - push_constant.vertex_stride = (mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; + push_constant.vertex_stride = ((mi->mesh->surfaces[i]->vertex_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4) - push_constant.normal_tangent_stride; push_constant.skin_stride = (mi->mesh->surfaces[i]->skin_buffer_size / mi->mesh->surfaces[i]->vertex_count) / 4; push_constant.skin_weight_offset = (mi->mesh->surfaces[i]->format & RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 4 : 2; @@ -1042,7 +1096,6 @@ void MeshStorage::update_mesh_instances() { push_constant.blend_shape_count = mi->mesh->blend_shape_count; push_constant.normalized_blend_shapes = mi->mesh->blend_shape_mode == RS::BLEND_SHAPE_MODE_NORMALIZED; - push_constant.pad0 = 0; push_constant.pad1 = 0; RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(SkeletonShader::PushConstant)); @@ -1061,11 +1114,13 @@ void MeshStorage::update_mesh_instances() { RD::get_singleton()->compute_list_end(); } -void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) { +void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis, uint32_t p_current_buffer, uint32_t p_previous_buffer) { Vector<RD::VertexAttribute> attributes; Vector<RID> buffers; + Vector<uint64_t> offsets; - uint32_t stride = 0; + uint32_t position_stride = 0; + uint32_t normal_tangent_stride = 0; uint32_t attribute_stride = 0; uint32_t skin_stride = 0; @@ -1073,8 +1128,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V RD::VertexAttribute vd; RID buffer; vd.location = i; + uint64_t offset = 0; - if (!(s->format & (1 << i))) { + if (!(s->format & (1ULL << i))) { // Not supplied by surface, use default value buffer = mesh_default_rd_buffers[i]; vd.stride = 0; @@ -1123,14 +1179,19 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V switch (i) { case RS::ARRAY_VERTEX: { - vd.offset = stride; + vd.offset = position_stride; if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - stride += sizeof(float) * 2; + position_stride = sizeof(float) * 2; } else { - vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; - stride += sizeof(float) * 3; + if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + position_stride = sizeof(uint16_t) * 4; + } else { + vd.format = RD::DATA_FORMAT_R32G32B32_SFLOAT; + position_stride = sizeof(float) * 3; + } } if (mis) { @@ -1141,27 +1202,33 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_NORMAL: { - vd.offset = stride; - vd.format = RD::DATA_FORMAT_R16G16_UNORM; - stride += sizeof(uint16_t) * 2; - - if (mis) { - buffer = mis->vertex_buffer[p_current_buffer]; + vd.offset = 0; + offset = position_stride * s->vertex_count; + if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + normal_tangent_stride += sizeof(uint16_t) * 2; } else { - buffer = s->vertex_buffer; + vd.format = RD::DATA_FORMAT_R16G16B16A16_UNORM; + // A small trick here: if we are uncompressed and we have normals, but no tangents. We need + // the shader to think there are 4 components to "axis_tangent_attrib". So we give a size of 4, + // but a stride based on only having 2 elements. + if (!(s->format & RS::ARRAY_FORMAT_TANGENT)) { + normal_tangent_stride += sizeof(uint16_t) * 2; + } else { + normal_tangent_stride += sizeof(uint16_t) * 4; + } } - } break; - case RS::ARRAY_TANGENT: { - vd.offset = stride; - vd.format = RD::DATA_FORMAT_R16G16_UNORM; - stride += sizeof(uint16_t) * 2; - if (mis) { buffer = mis->vertex_buffer[p_current_buffer]; } else { buffer = s->vertex_buffer; } } break; + case RS::ARRAY_TANGENT: { + buffer = mesh_default_rd_buffers[i]; + vd.stride = 0; + vd.format = RD::DATA_FORMAT_R32G32B32A32_SFLOAT; + } break; case RS::ARRAY_COLOR: { vd.offset = attribute_stride; @@ -1171,17 +1238,25 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } break; case RS::ARRAY_TEX_UV: { vd.offset = attribute_stride; - - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - attribute_stride += sizeof(float) * 2; + if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + attribute_stride += sizeof(uint16_t) * 2; + } else { + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + } buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV2: { vd.offset = attribute_stride; - - vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; - attribute_stride += sizeof(float) * 2; + if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + vd.format = RD::DATA_FORMAT_R16G16_UNORM; + attribute_stride += sizeof(uint16_t) * 2; + } else { + vd.format = RD::DATA_FORMAT_R32G32_SFLOAT; + attribute_stride += sizeof(float) * 2; + } buffer = s->attribute_buffer; } break; case RS::ARRAY_CUSTOM0: @@ -1216,12 +1291,13 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } } - if (!(p_input_mask & (1 << i))) { + if (!(p_input_mask & (1ULL << i))) { continue; // Shader does not need this, skip it (but computing stride was important anyway) } attributes.push_back(vd); buffers.push_back(buffer); + offsets.push_back(offset); if (p_input_motion_vectors) { // Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion @@ -1246,6 +1322,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V attributes.push_back(vd); buffers.push_back(buffer); + offsets.push_back(offset); } } } @@ -1256,9 +1333,10 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V continue; //default location } int loc = attributes[i].location; - - if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_VERTEX) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) { - attributes.write[i].stride = stride; + if (loc == RS::ARRAY_VERTEX || loc == ATTRIBUTE_LOCATION_PREV_VERTEX) { + attributes.write[i].stride = position_stride; + } else if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_NORMAL) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) { + attributes.write[i].stride = normal_tangent_stride; } else if (loc < RS::ARRAY_BONES) { attributes.write[i].stride = attribute_stride; } else { @@ -1271,7 +1349,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V v.previous_buffer = p_previous_buffer; v.input_motion_vectors = p_input_motion_vectors; v.vertex_format = RD::get_singleton()->vertex_format_create(attributes); - v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers); + v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers, offsets); } ////////////////// MULTIMESH diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h index 1e1db9c47d..f03334baac 100644 --- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h @@ -73,7 +73,7 @@ private: struct Mesh { struct Surface { RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS; - uint32_t format = 0; + uint64_t format = 0; RID vertex_buffer; RID attribute_buffer; @@ -90,7 +90,7 @@ private: // cache-efficient structure. struct Version { - uint32_t input_mask = 0; + uint64_t input_mask = 0; uint32_t current_buffer = 0; uint32_t previous_buffer = 0; bool input_motion_vectors = false; @@ -120,6 +120,8 @@ private: Vector<AABB> bone_aabbs; + Vector4 uv_scale; + RID blend_shape_buffer; RID material; @@ -190,7 +192,7 @@ private: weight_update_list(this), array_update_list(this) {} }; - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0); + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr, uint32_t p_current_buffer = 0, uint32_t p_previous_buffer = 0); void _mesh_instance_clear(MeshInstance *mi); void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface); @@ -265,7 +267,7 @@ private: uint32_t blend_shape_count; uint32_t normalized_blend_shapes; - uint32_t pad0; + uint32_t normal_tangent_stride; uint32_t pad1; float skeleton_transform_x[2]; float skeleton_transform_y[2]; @@ -422,6 +424,21 @@ public: return s->index_count ? s->index_count : s->vertex_count; } + _FORCE_INLINE_ AABB mesh_surface_get_aabb(void *p_surface) { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->aabb; + } + + _FORCE_INLINE_ uint64_t mesh_surface_get_format(void *p_surface) { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->format; + } + + _FORCE_INLINE_ Vector4 mesh_surface_get_uv_scale(void *p_surface) { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->uv_scale; + } + _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const { Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); @@ -484,7 +501,7 @@ public: s->version_lock.unlock(); } - _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint64_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_NULL(mi); Mesh *mesh = mi->mesh; |