diff --git a/doc/classes/EditorSceneFormatImporter.xml b/doc/classes/EditorSceneFormatImporter.xml index b5072731173..b14810133e7 100644 --- a/doc/classes/EditorSceneFormatImporter.xml +++ b/doc/classes/EditorSceneFormatImporter.xml @@ -56,5 +56,7 @@ + + diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml index 48be28be264..1b8ae8cc591 100644 --- a/doc/classes/MeshDataTool.xml +++ b/doc/classes/MeshDataTool.xml @@ -61,6 +61,7 @@ + Adds a new surface to specified [Mesh] with edited data. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 9f64cbf6103..24b409d9410 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -2210,6 +2210,15 @@ + Returns the stride of the attribute buffer for a mesh with given [param format]. + + + + + + + + Returns the stride of the combined normals and tangents for a mesh with given [param format]. Note importantly that, while normals and tangents are in the vertex buffer with vertices, they are only interleaved with each other and so have a different stride than vertex positions. @@ -2218,6 +2227,7 @@ + Returns the offset of a given attribute by [param array_index] in the start of its respective buffer. @@ -2225,6 +2235,7 @@ + Returns the stride of the skin buffer for a mesh with given [param format]. @@ -2232,6 +2243,7 @@ + Returns the stride of the vertex positions for a mesh with given [param format]. Note importantly that vertex positions are stored consecutively and are not interleaved with the other attributes in the vertex buffer (normals and tangents). @@ -4187,6 +4199,28 @@ Flag used to mark that the array uses 8 bone weights instead of 4. + Flag used to mark that the mesh does not have a vertex array and instead will infer vertex positions in the shader using indices and other information. + + + Flag used to mark that a mesh is using compressed attributes (vertices, normals, tangents, uvs). When this form of compression is enabled, vertex positions will be packed into into an RGBA16UNORM attribute and scaled in the vertex shader. The normal and tangent will be packed into a RG16UNORM representing an axis, and an 16 bit float stored in the A-channel of the vertex. UVs will use 16-bit normalized floats instead of full 32 bit signed floats. When using this compression mode you must either use vertices, normals, and tangents or only vertices. You cannot use normals without tangents. Importers will automatically enable this compression if they can. + + + Flag used to mark the start of the bits used to store the mesh version. + + + Flag used to shift a mesh format int to bring the version into the lowest digits. + + + Flag used to record the format used by prior mesh versions before the introduction of a version. + + + Flag used to record the second iteration of the mesh version flag. The primary difference between this and [constant ARRAY_FLAG_FORMAT_VERSION_1] is that this version supports [constant ARRAY_FLAG_COMPRESS_ATTRIBUTES] and in this version vertex positions are de-interleaved from normals and tangents. + + + Flag used to record the current version that the engine expects. Currently this is the same as [constant ARRAY_FLAG_FORMAT_VERSION_2]. + + + Flag used to isolate the bits used for mesh version after using [constant ARRAY_FLAG_FORMAT_VERSION_SHIFT] to shift them into place. Primitive to draw consists of points. diff --git a/doc/classes/ResourceImporterOBJ.xml b/doc/classes/ResourceImporterOBJ.xml index 70b57b4d2d6..9cb17ed3b2c 100644 --- a/doc/classes/ResourceImporterOBJ.xml +++ b/doc/classes/ResourceImporterOBJ.xml @@ -11,6 +11,9 @@ $DOCS_URL/tutorials/assets_pipeline/importing_scenes.html + + If [code]true[/code], mesh compression will not be used. Consider enabling if you notice blocky artifacts in your mesh normals or UVs, or if you have meshes that are larger than a few thousand meters in each direction. + If [code]true[/code], generate vertex tangents using [url=http://www.mikktspace.com/]Mikktspace[/url] if the source mesh doesn't have tangent data. When possible, it's recommended to let the 3D modeling software generate tangents on export instead on relying on this option. Tangents are required for correct display of normal and height maps, along with any material/shader features that require tangents. If you don't need material features that require tangents, disabling this can reduce output file size and speed up importing if the source 3D file doesn't contain tangents. diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml index 982f6e56add..fe0a86ca218 100644 --- a/doc/classes/ResourceImporterScene.xml +++ b/doc/classes/ResourceImporterScene.xml @@ -37,6 +37,9 @@ If [code]true[/code], generate vertex tangents using [url=http://www.mikktspace.com/]Mikktspace[/url] if the input meshes don't have tangent data. When possible, it's recommended to let the 3D modeling software generate tangents on export instead on relying on this option. Tangents are required for correct display of normal and height maps, along with any material/shader features that require tangents. If you don't need material features that require tangents, disabling this can reduce output file size and speed up importing if the source 3D file doesn't contain tangents. + + If [code]true[/code], mesh compression will not be used. Consider enabling if you notice blocky artifacts in your mesh normals or UVs, or if you have meshes that are larger than a few thousand meters in each direction. + If [code]true[/code], generates lower detail variants of the mesh which will be displayed in the distance to improve rendering performance. Not all meshes benefit from LOD, especially if they are never rendered from far away. Disabling this can reduce output file size and speed up importing. See [url=$DOCS_URL/tutorials/3d/mesh_lod.html#doc-mesh-lod]Mesh level of detail (LOD)[/url] for more information. diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index fcd3af8d62c..7fce06c1333 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1383,7 +1383,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) { GLuint vertex_array_gl = 0; GLuint index_array_gl = 0; - uint32_t input_mask = 0; // 2D meshes always use the same vertex format + uint64_t input_mask = 0; // 2D meshes always use the same vertex format. if (mesh_instance.is_valid()) { mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl); } else { diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 22bb772e4f5..d359a4252f2 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2908,6 +2908,18 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, } material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, instance_variant, spec_constants); + { + GLES3::Mesh::Surface *s = reinterpret_cast(surf->surface); + if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_POSITION, s->aabb.position, shader->version, instance_variant, spec_constants); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_SIZE, s->aabb.size, shader->version, instance_variant, spec_constants); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::UV_SCALE, s->uv_scale, shader->version, instance_variant, spec_constants); + } else { + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_POSITION, Vector3(0.0, 0.0, 0.0), shader->version, instance_variant, spec_constants); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::COMPRESSED_AABB_SIZE, Vector3(1.0, 1.0, 1.0), shader->version, instance_variant, spec_constants); + material_storage->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::UV_SCALE, Vector4(0.0, 0.0, 0.0, 0.0), shader->version, instance_variant, spec_constants); + } + } // Can be index count or vertex count uint32_t count = 0; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 0c1a20caed5..c98b5f3ed7e 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -52,8 +52,8 @@ ADDITIVE_SPOT = false /* from RenderingServer: -ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) -ARRAY_NORMAL = 1, // RG16 octahedral compression +ARRAY_VERTEX = 0, // RGB32F or RGBA16 +ARRAY_NORMAL = 1, // RG16 octahedral compression or RGBA16 normal + angle ARRAY_TANGENT = 2, // RG16 octahedral compression, sign stored in sign of G ARRAY_COLOR = 3, // RGBA8 ARRAY_TEX_UV = 4, // RG32F @@ -68,16 +68,16 @@ ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights) /* INPUT ATTRIBS */ -layout(location = 0) in highp vec3 vertex_attrib; +// Always contains vertex position in XYZ, can contain tangent angle in W. +layout(location = 0) in highp vec4 vertex_angle_attrib; /* clang-format on */ #ifdef NORMAL_USED -layout(location = 1) in vec2 normal_attrib; +// Contains Normal/Axis in RG, can contain tangent in BA. +layout(location = 1) in vec4 axis_tangent_attrib; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec2 tangent_attrib; -#endif +// location 2 is unused. #if defined(COLOR_USED) layout(location = 3) in vec4 color_attrib; @@ -122,6 +122,16 @@ vec3 oct_to_vec3(vec2 e) { return normalize(v); } +void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { + float c = cos(angle); + float s = sin(angle); + vec3 omc_axis = (1.0 - c) * axis; + vec3 s_axis = s * axis; + tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); + binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); + normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); +} + #ifdef USE_INSTANCING layout(location = 12) in highp vec4 instance_xform0; layout(location = 13) in highp vec4 instance_xform1; @@ -228,10 +238,9 @@ multiview_data; #endif uniform highp mat4 world_transform; - -#ifdef USE_LIGHTMAP -uniform highp vec4 lightmap_uv_rect; -#endif +uniform highp vec3 compressed_aabb_position; +uniform highp vec3 compressed_aabb_size; +uniform highp vec4 uv_scale; /* Varyings */ @@ -248,12 +257,8 @@ out vec4 color_interp; out vec2 uv_interp; #endif -#if defined(UV2_USED) +#if defined(UV2_USED) || defined(USE_LIGHTMAP) out vec2 uv2_interp; -#else -#ifdef USE_LIGHTMAP -out vec2 uv2_interp; -#endif #endif #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) @@ -294,7 +299,7 @@ layout(std140) uniform MaterialUniforms { // ubo:3 invariant gl_Position; void main() { - highp vec3 vertex = vertex_attrib; + highp vec3 vertex = vertex_angle_attrib.xyz * compressed_aabb_size + compressed_aabb_position; highp mat4 model_matrix = world_transform; #ifdef USE_INSTANCING @@ -303,15 +308,30 @@ void main() { #endif #ifdef NORMAL_USED - vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); + vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0); #endif highp mat3 model_normal_matrix = mat3(model_matrix); -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; - vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); - float binormalf = sign(signed_tangent_attrib.y); - vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + vec3 binormal; + float binormal_sign; + vec3 tangent; + if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0; + tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + binormal = normalize(cross(normal, tangent) * binormal_sign); + } else { + // Compressed format. + float angle = vertex_angle_attrib.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = normal; + axis_angle_to_tbn(axis, angle, tangent, binormal, normal); + binormal *= binormal_sign; + } #endif #if defined(COLOR_USED) @@ -326,13 +346,18 @@ void main() { uv_interp = uv_attrib; #endif -#ifdef USE_LIGHTMAP - uv2_interp = lightmap_uv_rect.zw * uv2_attrib + lightmap_uv_rect.xy; -#else -#if defined(UV2_USED) +#if defined(UV2_USED) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; #endif + + if (uv_scale != vec4(0.0)) { // Compression enabled +#ifdef UV_USED + uv_interp = (uv_interp - 0.5) * uv_scale.xy; #endif +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = (uv2_interp - 0.5) * uv_scale.zw; +#endif + } #if defined(OVERRIDE_POSITION) highp vec4 position; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index a594813ed08..613b03e30e4 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2944,7 +2944,7 @@ void SceneShaderData::set_code(const String &p_code) { cull_mode = Cull(cull_modei); blend_mode = BlendMode(blend_modei); alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei); - vertex_input_mask = uint32_t(uses_normal); + vertex_input_mask = uint64_t(uses_normal); vertex_input_mask |= uses_tangent << 1; vertex_input_mask |= uses_color << 2; vertex_input_mask |= uses_uv << 3; diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 9c63c8847de..75127bb1981 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -316,7 +316,7 @@ struct SceneShaderData : public ShaderData { bool uses_bones; bool uses_weights; - uint32_t vertex_input_mask = 0; + uint64_t vertex_input_mask = 0; uint64_t last_pass = 0; uint32_t index = 0; diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index cc6031fa572..ae04b63cfeb 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -117,34 +117,40 @@ 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; } - } break; case RS::ARRAY_NORMAL: { stride += sizeof(uint16_t) * 2; } break; case RS::ARRAY_TANGENT: { - stride += sizeof(uint16_t) * 2; - + 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: case RS::ARRAY_CUSTOM1: @@ -183,94 +189,123 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } } +#endif + + 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 + + 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) + ")"); + +#else + + if (surface_version != uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION)) { + RS::_fix_surface_compatibility(new_surface); + surface_version = new_surface.format & (uint64_t(RS::ARRAY_FLAG_FORMAT_VERSION_MASK) << RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT); + ERR_FAIL_COND_MSG(surface_version != uint64_t(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((uint64_t(RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION) >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + + ")"); + } #endif Mesh::Surface *s = memnew(Mesh::Surface); - s->format = p_surface.format; - s->primitive = p_surface.primitive; + s->format = new_surface.format; + s->primitive = new_surface.primitive; - if (p_surface.vertex_data.size()) { + if (new_surface.vertex_data.size()) { glGenBuffers(1, &s->vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer"); - s->vertex_buffer_size = p_surface.vertex_data.size(); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->vertex_buffer, new_surface.vertex_data.size(), new_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh vertex buffer"); + s->vertex_buffer_size = new_surface.vertex_data.size(); } - if (p_surface.attribute_data.size()) { + if (new_surface.attribute_data.size()) { glGenBuffers(1, &s->attribute_buffer); glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer"); - s->attribute_buffer_size = p_surface.attribute_data.size(); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->attribute_buffer, new_surface.attribute_data.size(), new_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh attribute buffer"); + s->attribute_buffer_size = new_surface.attribute_data.size(); } - if (p_surface.skin_data.size()) { + if (new_surface.skin_data.size()) { glGenBuffers(1, &s->skin_buffer); glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, p_surface.skin_data.size(), p_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer"); - s->skin_buffer_size = p_surface.skin_data.size(); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->skin_buffer, new_surface.skin_data.size(), new_surface.skin_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh skin buffer"); + s->skin_buffer_size = new_surface.skin_data.size(); } glBindBuffer(GL_ARRAY_BUFFER, 0); - 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; glGenBuffers(1, &s->index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer"); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer, new_surface.index_data.size(), new_surface.index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer"); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - s->index_count = p_surface.index_count; - s->index_buffer_size = p_surface.index_data.size(); + s->index_count = new_surface.index_count; + s->index_buffer_size = new_surface.index_data.size(); - 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++) { + for (int i = 0; i < new_surface.lods.size(); i++) { glGenBuffers(1, &s->lods[i].index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, p_surface.lods[i].index_data.size(), p_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]"); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->lods[i].index_buffer, new_surface.lods[i].index_data.size(), new_surface.lods[i].index_data.ptr(), GL_STATIC_DRAW, "Mesh index buffer LOD[" + itos(i) + "]"); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - s->lods[i].edge_length = p_surface.lods[i].edge_length; - s->lods[i].index_count = p_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); - s->lods[i].index_buffer_size = p_surface.lods[i].index_data.size(); + s->lods[i].edge_length = new_surface.lods[i].edge_length; + s->lods[i].index_count = new_surface.lods[i].index_data.size() / (is_index_16 ? 2 : 4); + s->lods[i].index_buffer_size = new_surface.lods[i].index_data.size(); } } } - 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. - if (p_surface.skin_data.size() || mesh->blend_shape_count > 0) { + s->uv_scale = new_surface.uv_scale; + + if (new_surface.skin_data.size() || mesh->blend_shape_count > 0) { // Size must match the size of the vertex array. - int size = p_surface.vertex_data.size(); + int size = new_surface.vertex_data.size(); int vertex_size = 0; - int stride = 0; + int position_stride = 0; + int normal_tangent_stride = 0; int normal_offset = 0; int tangent_offset = 0; - if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) { - if (p_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) { + if ((new_surface.format & (1ULL << RS::ARRAY_VERTEX))) { + if (new_surface.format & RS::ARRAY_FLAG_USE_2D_VERTICES) { vertex_size = 2; + position_stride = sizeof(float) * vertex_size; } else { - vertex_size = 3; + if (new_surface.format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + vertex_size = 4; + position_stride = sizeof(uint16_t) * vertex_size; + } else { + vertex_size = 3; + position_stride = sizeof(float) * vertex_size; + } } - stride = sizeof(float) * vertex_size; } - if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) { - normal_offset = stride; - stride += sizeof(uint16_t) * 2; + if ((new_surface.format & (1ULL << RS::ARRAY_NORMAL))) { + normal_offset = position_stride * s->vertex_count; + normal_tangent_stride += sizeof(uint16_t) * 2; } - if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) { - tangent_offset = stride; - stride += sizeof(uint16_t) * 2; + if ((new_surface.format & (1ULL << RS::ARRAY_TANGENT))) { + tangent_offset = normal_offset + normal_tangent_stride; + normal_tangent_stride += sizeof(uint16_t) * 2; } if (mesh->blend_shape_count > 0) { @@ -282,54 +317,38 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) glBindVertexArray(s->blend_shapes[i].vertex_array); glGenBuffers(1, &s->blend_shapes[i].vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, p_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer"); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s->blend_shapes[i].vertex_buffer, size, new_surface.blend_shape_data.ptr() + i * size, (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW, "Mesh blend shape buffer"); - if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) { + if ((new_surface.format & (1ULL << RS::ARRAY_VERTEX))) { glEnableVertexAttribArray(RS::ARRAY_VERTEX + 3); - glVertexAttribPointer(RS::ARRAY_VERTEX + 3, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); + glVertexAttribPointer(RS::ARRAY_VERTEX + 3, vertex_size, GL_FLOAT, GL_FALSE, position_stride, CAST_INT_TO_UCHAR_PTR(0)); } - if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) { + if ((new_surface.format & (1ULL << RS::ARRAY_NORMAL))) { + // Normal and tangent are packed into the same attribute. glEnableVertexAttribArray(RS::ARRAY_NORMAL + 3); - glVertexAttribPointer(RS::ARRAY_NORMAL + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset)); + glVertexAttribPointer(RS::ARRAY_NORMAL + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, normal_tangent_stride, CAST_INT_TO_UCHAR_PTR(normal_offset)); } - if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) { + if ((p_surface.format & (1ULL << RS::ARRAY_TANGENT))) { glEnableVertexAttribArray(RS::ARRAY_TANGENT + 3); - glVertexAttribPointer(RS::ARRAY_TANGENT + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset)); + glVertexAttribPointer(RS::ARRAY_TANGENT + 3, 2, GL_UNSIGNED_SHORT, GL_TRUE, normal_tangent_stride, CAST_INT_TO_UCHAR_PTR(tangent_offset)); } } glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } - // Create a vertex array to use for skeleton/blend shapes. - glGenVertexArrays(1, &s->skeleton_vertex_array); - glBindVertexArray(s->skeleton_vertex_array); - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer); - - if ((p_surface.format & (1 << RS::ARRAY_VERTEX))) { - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, vertex_size, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); - } - if ((p_surface.format & (1 << RS::ARRAY_NORMAL))) { - glEnableVertexAttribArray(RS::ARRAY_NORMAL); - glVertexAttribPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(normal_offset)); - } - if ((p_surface.format & (1 << RS::ARRAY_TANGENT))) { - glEnableVertexAttribArray(RS::ARRAY_TANGENT); - glVertexAttribPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(tangent_offset)); - } glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); } 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; @@ -479,6 +498,8 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const { } } + sd.uv_scale = s.uv_scale; + return sd; } @@ -696,10 +717,6 @@ void MeshStorage::mesh_clear(RID p_mesh) { } memdelete_arr(s.blend_shapes); } - if (s.skeleton_vertex_array != 0) { - glDeleteVertexArrays(1, &s.skeleton_vertex_array); - s.skeleton_vertex_array = 0; - } memdelete(mesh->surfaces[i]); } @@ -720,15 +737,16 @@ void MeshStorage::mesh_clear(RID p_mesh) { } } -void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) { +void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis) { Mesh::Surface::Attrib attribs[RS::ARRAY_MAX]; + int position_stride = 0; // Vertex position only. + int normal_tangent_stride = 0; int attributes_stride = 0; - int vertex_stride = 0; int skin_stride = 0; for (int i = 0; i < RS::ARRAY_INDEX; i++) { - if (!(s->format & (1 << i))) { + if (!(s->format & (1ULL << i))) { attribs[i].enabled = false; attribs[i].integer = false; continue; @@ -739,29 +757,55 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V switch (i) { case RS::ARRAY_VERTEX: { - attribs[i].offset = vertex_stride; + attribs[i].offset = 0; + attribs[i].type = GL_FLOAT; + attribs[i].normalized = GL_FALSE; if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) { attribs[i].size = 2; + position_stride = attribs[i].size * sizeof(float); } else { - attribs[i].size = 3; + if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + attribs[i].size = 4; + position_stride = attribs[i].size * sizeof(uint16_t); + attribs[i].type = GL_UNSIGNED_SHORT; + attribs[i].normalized = GL_TRUE; + } else { + attribs[i].size = 3; + position_stride = attribs[i].size * sizeof(float); + } } - attribs[i].type = GL_FLOAT; - vertex_stride += attribs[i].size * sizeof(float); - attribs[i].normalized = GL_FALSE; } break; case RS::ARRAY_NORMAL: { - attribs[i].offset = vertex_stride; - attribs[i].size = 2; + if (!mis && (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + attribs[i].size = 2; + normal_tangent_stride += 2 * attribs[i].size; + } else { + attribs[i].size = 4; + // 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 += (mis ? sizeof(float) : sizeof(uint16_t)) * 2; + } else { + normal_tangent_stride += (mis ? sizeof(float) : sizeof(uint16_t)) * 4; + } + } + + if (mis) { + // Transform feedback has interleave all or no attributes. It can't mix interleaving. + attribs[i].offset = position_stride; + normal_tangent_stride += position_stride; + position_stride = normal_tangent_stride; + } else { + attribs[i].offset = position_stride * s->vertex_count; + } attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT); - vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1); attribs[i].normalized = GL_TRUE; } break; case RS::ARRAY_TANGENT: { - attribs[i].offset = vertex_stride; - attribs[i].size = 2; - attribs[i].type = (mis ? GL_FLOAT : GL_UNSIGNED_SHORT); - vertex_stride += sizeof(uint16_t) * 2 * (mis ? 2 : 1); - attribs[i].normalized = GL_TRUE; + // We never use the tangent attribute. It is always packed in ARRAY_NORMAL, or ARRAY_VERTEX. + attribs[i].enabled = false; + attribs[i].integer = false; } break; case RS::ARRAY_COLOR: { attribs[i].offset = attributes_stride; @@ -773,16 +817,28 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V case RS::ARRAY_TEX_UV: { attribs[i].offset = attributes_stride; attribs[i].size = 2; - attribs[i].type = GL_FLOAT; - attributes_stride += 2 * sizeof(float); - attribs[i].normalized = GL_FALSE; + if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + attribs[i].type = GL_UNSIGNED_SHORT; + attributes_stride += 2 * sizeof(uint16_t); + attribs[i].normalized = GL_TRUE; + } else { + attribs[i].type = GL_FLOAT; + attributes_stride += 2 * sizeof(float); + attribs[i].normalized = GL_FALSE; + } } break; case RS::ARRAY_TEX_UV2: { attribs[i].offset = attributes_stride; attribs[i].size = 2; - attribs[i].type = GL_FLOAT; - attributes_stride += 2 * sizeof(float); - attribs[i].normalized = GL_FALSE; + if (s->format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + attribs[i].type = GL_UNSIGNED_SHORT; + attributes_stride += 2 * sizeof(uint16_t); + attribs[i].normalized = GL_TRUE; + } else { + attribs[i].type = GL_FLOAT; + attributes_stride += 2 * sizeof(float); + attribs[i].normalized = GL_FALSE; + } } break; case RS::ARRAY_CUSTOM0: case RS::ARRAY_CUSTOM1: @@ -828,7 +884,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V continue; } if (i <= RS::ARRAY_TANGENT) { - attribs[i].stride = vertex_stride; + attribs[i].stride = (i == RS::ARRAY_VERTEX) ? position_stride : normal_tangent_stride; if (mis) { glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffer); } else { @@ -946,7 +1002,7 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3 if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) { // Cache surface properties s.format_cache = mesh->surfaces[p_surface]->format; - if ((s.format_cache & (1 << RS::ARRAY_VERTEX))) { + if ((s.format_cache & (1ULL << RS::ARRAY_VERTEX))) { if (s.format_cache & RS::ARRAY_FLAG_USE_2D_VERTICES) { s.vertex_size_cache = 2; } else { @@ -954,25 +1010,27 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3 } s.vertex_stride_cache = sizeof(float) * s.vertex_size_cache; } - if ((s.format_cache & (1 << RS::ARRAY_NORMAL))) { + if ((s.format_cache & (1ULL << RS::ARRAY_NORMAL))) { s.vertex_normal_offset_cache = s.vertex_stride_cache; s.vertex_stride_cache += sizeof(uint32_t) * 2; } - if ((s.format_cache & (1 << RS::ARRAY_TANGENT))) { + if ((s.format_cache & (1ULL << RS::ARRAY_TANGENT))) { s.vertex_tangent_offset_cache = s.vertex_stride_cache; s.vertex_stride_cache += sizeof(uint32_t) * 2; } + int buffer_size = s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count; + // Buffer to be used for rendering. Final output of skeleton and blend shapes. glGenBuffers(1, &s.vertex_buffer); glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer"); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffer, buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance vertex buffer"); if (mesh->blend_shape_count > 0) { // Ping-Pong buffers for processing blendshapes. glGenBuffers(2, s.vertex_buffers); for (uint32_t i = 0; i < 2; i++) { glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffers[i]); - GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], s.vertex_stride_cache * mesh->surfaces[p_surface]->vertex_count, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]"); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ARRAY_BUFFER, s.vertex_buffers[i], buffer_size, nullptr, GL_DYNAMIC_DRAW, "MeshInstance process buffer[" + itos(i) + "]"); } } glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind @@ -1011,19 +1069,19 @@ void MeshStorage::mesh_instance_set_canvas_item_transform(RID p_mesh_instance, c void MeshStorage::_blend_shape_bind_mesh_instance_buffer(MeshInstance *p_mi, uint32_t p_surface) { glBindBuffer(GL_ARRAY_BUFFER, p_mi->surfaces[p_surface].vertex_buffers[0]); - if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_VERTEX))) { + if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_VERTEX))) { glEnableVertexAttribArray(RS::ARRAY_VERTEX); glVertexAttribPointer(RS::ARRAY_VERTEX, p_mi->surfaces[p_surface].vertex_size_cache, GL_FLOAT, GL_FALSE, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(0)); } else { glDisableVertexAttribArray(RS::ARRAY_VERTEX); } - if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_NORMAL))) { + if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_NORMAL))) { glEnableVertexAttribArray(RS::ARRAY_NORMAL); glVertexAttribIPointer(RS::ARRAY_NORMAL, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_normal_offset_cache)); } else { glDisableVertexAttribArray(RS::ARRAY_NORMAL); } - if ((p_mi->surfaces[p_surface].format_cache & (1 << RS::ARRAY_TANGENT))) { + if ((p_mi->surfaces[p_surface].format_cache & (1ULL << RS::ARRAY_TANGENT))) { glEnableVertexAttribArray(RS::ARRAY_TANGENT); glVertexAttribIPointer(RS::ARRAY_TANGENT, 2, GL_UNSIGNED_INT, p_mi->surfaces[p_surface].vertex_stride_cache, CAST_INT_TO_UCHAR_PTR(p_mi->surfaces[p_surface].vertex_tangent_offset_cache)); } else { @@ -1091,7 +1149,7 @@ void MeshStorage::update_mesh_instances() { } for (uint32_t i = 0; i < mi->surfaces.size(); i++) { - if (mi->surfaces[i].vertex_buffer == 0 || mi->mesh->surfaces[i]->skeleton_vertex_array == 0) { + if (mi->surfaces[i].vertex_buffer == 0) { continue; } @@ -1106,10 +1164,10 @@ void MeshStorage::update_mesh_instances() { specialization |= array_is_2d ? SkeletonShaderGLES3::MODE_2D : 0; specialization |= SkeletonShaderGLES3::USE_BLEND_SHAPES; if (!array_is_2d) { - if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) { + if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_NORMAL))) { specialization |= SkeletonShaderGLES3::USE_NORMAL; } - if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) { + if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_TANGENT))) { specialization |= SkeletonShaderGLES3::USE_TANGENT; } } @@ -1123,7 +1181,12 @@ void MeshStorage::update_mesh_instances() { skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::BLEND_SHAPE_COUNT, float(mi->mesh->blend_shape_count), skeleton_shader.shader_version, variant, specialization); glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array); + GLuint vertex_array_gl = 0; + uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX. + mask = ~mask; + uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions. + mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl); + glBindVertexArray(vertex_array_gl); glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mi->surfaces[i].vertex_buffers[0]); glBeginTransformFeedback(GL_POINTS); glDrawArrays(GL_POINTS, 0, mi->mesh->surfaces[i]->vertex_count); @@ -1210,10 +1273,10 @@ void MeshStorage::update_mesh_instances() { specialization |= SkeletonShaderGLES3::FINAL_PASS; specialization |= use_8_weights ? SkeletonShaderGLES3::USE_EIGHT_WEIGHTS : 0; if (!array_is_2d) { - if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_NORMAL))) { + if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_NORMAL))) { specialization |= SkeletonShaderGLES3::USE_NORMAL; } - if ((mi->surfaces[i].format_cache & (1 << RS::ARRAY_TANGENT))) { + if ((mi->surfaces[i].format_cache & (1ULL << RS::ARRAY_TANGENT))) { specialization |= SkeletonShaderGLES3::USE_TANGENT; } } @@ -1233,7 +1296,12 @@ void MeshStorage::update_mesh_instances() { skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_Y, inverse_transform[1], skeleton_shader.shader_version, variant, specialization); skeleton_shader.shader.version_set_uniform(SkeletonShaderGLES3::INVERSE_TRANSFORM_OFFSET, inverse_transform[2], skeleton_shader.shader_version, variant, specialization); - glBindVertexArray(mi->mesh->surfaces[i]->skeleton_vertex_array); + GLuint vertex_array_gl = 0; + uint64_t mask = ((1 << 10) - 1) << 3; // Mask from ARRAY_FORMAT_COLOR to ARRAY_FORMAT_INDEX. + mask = ~mask; + uint64_t format = mi->surfaces[i].format_cache & mask; // Format should only have vertex, normal, tangent (as necessary) + compressions. + mesh_surface_get_vertex_arrays_and_format(mi->mesh->surfaces[i], format, vertex_array_gl); + glBindVertexArray(vertex_array_gl); _compute_skeleton(mi, sk, i); } } diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index 09212e4b5c6..25b15ab6a68 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -58,7 +58,7 @@ struct Mesh { uint32_t offset; }; RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS; - uint32_t format = 0; + uint64_t format = 0; GLuint vertex_buffer = 0; GLuint attribute_buffer = 0; @@ -98,6 +98,8 @@ struct Mesh { Vector bone_aabbs; + Vector4 uv_scale; + struct BlendShape { GLuint vertex_buffer = 0; GLuint vertex_array = 0; @@ -144,7 +146,7 @@ struct MeshInstance { int vertex_size_cache = 0; int vertex_normal_offset_cache = 0; int vertex_tangent_offset_cache = 0; - uint32_t format_cache = 0; + uint64_t format_cache = 0; Mesh::Surface::Version *versions = nullptr; //allocated on demand uint32_t version_count = 0; @@ -221,7 +223,7 @@ private: mutable RID_Owner mesh_owner; - void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr); + void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint64_t p_input_mask, MeshInstance::Surface *mis = nullptr); /* Mesh Instance API */ @@ -381,18 +383,18 @@ public: } // Use this to cache Vertex Array Objects so they are only generated once - _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, GLuint &r_vertex_array_gl) { + _FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint64_t p_input_mask, GLuint &r_vertex_array_gl) { Mesh::Surface *s = reinterpret_cast(p_surface); s->version_lock.lock(); - //there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way + // There will never be more than 3 or 4 versions, so iterating is the fastest way. for (uint32_t i = 0; i < s->version_count; i++) { if (s->versions[i].input_mask != p_input_mask) { continue; } - //we have this version, hooray + // We have this version, hooray. r_vertex_array_gl = s->versions[i].vertex_array; s->version_lock.unlock(); return; @@ -424,7 +426,7 @@ public: // TODO: considering hashing versions with multimesh buffer RID. // Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance. - _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, GLuint &r_vertex_array_gl) { + _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint64_t p_input_mask, GLuint &r_vertex_array_gl) { MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_NULL(mi); Mesh *mesh = mi->mesh; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index e553b2b5222..5c68149a5f4 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4499,6 +4499,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo if (atf.frequency == VERTEX_FREQUENCY_VERTEX) { // Validate size for regular drawing. uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size; + ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(), "Attachment (" + itos(i) + ") will read past the end of the buffer."); @@ -4665,7 +4666,7 @@ struct RenderingDeviceVulkanShaderBinarySpecializationConstant { }; struct RenderingDeviceVulkanShaderBinaryData { - uint32_t vertex_input_mask; + uint64_t vertex_input_mask; uint32_t fragment_output_mask; uint32_t specialization_constants_count; uint32_t is_compute; @@ -4881,7 +4882,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector &p_ push_constant.size = binary_data.push_constant_size; push_constant.vk_stages_mask = binary_data.push_constant_vk_stages_mask; - uint32_t vertex_input_mask = binary_data.vertex_input_mask; + uint64_t vertex_input_mask = binary_data.vertex_input_mask; uint32_t fragment_output_mask = binary_data.fragment_output_mask; @@ -5209,7 +5210,7 @@ RID RenderingDeviceVulkan::shader_create_placeholder() { return shader_owner.make_rid(shader); } -uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { +uint64_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) { _THREAD_SAFE_METHOD_ const Shader *shader = shader_owner.get_or_null(p_shader); @@ -6152,8 +6153,8 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma pipeline_vertex_input_state_create_info = vd.create_info; // Validate with inputs. - for (uint32_t i = 0; i < 32; i++) { - if (!(shader->vertex_input_mask & (1UL << i))) { + for (uint64_t i = 0; i < 64; i++) { + if (!(shader->vertex_input_mask & (1ULL << i))) { continue; } bool found = false; diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index fd14449ee78..7c514c11f87 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -621,7 +621,7 @@ class RenderingDeviceVulkan : public RenderingDevice { VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE; }; - uint32_t vertex_input_mask = 0; // Inputs used, this is mostly for validation. + uint64_t vertex_input_mask = 0; // Inputs used, this is mostly for validation. uint32_t fragment_output_mask = 0; struct PushConstant { @@ -1140,7 +1140,7 @@ public: virtual RID shader_create_from_bytecode(const Vector &p_shader_binary, RID p_placeholder = RID()); virtual RID shader_create_placeholder(); - virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader); + virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader); /*****************/ /**** UNIFORM ****/ diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 1e410b7272b..de9daddd380 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -919,6 +919,12 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref &p } } + uint64_t mesh_flags = 0; + + if (p_use_compression) { + mesh_flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + } + Ref surftool; surftool.instantiate(); surftool->begin(Mesh::PRIMITIVE_TRIANGLES); @@ -969,14 +975,21 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref &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 &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 &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; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index adc21aaa7b7..4379a1aae40 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -202,7 +202,7 @@ static Error _parse_material_library(const String &p_path, HashMap> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List *r_missing_deps) { +static Error _parse_obj(const String &p_path, List> &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 *r_missing_deps) { Ref 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> &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 vertices; Vector normals; @@ -287,7 +291,6 @@ static Error _parse_obj(const String &p_path, List> &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 v = l.split(" ", false); @@ -380,6 +383,9 @@ static Error _parse_obj(const String &p_path, List> &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> &r_meshes, bool p_ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap &p_options, List *r_missing_deps, Error *r_err) { List> 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, Listpush_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 &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 &p_options, List *r_platform_variants, List *r_gen_files, Variant *r_metadata) { List> 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); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 2f889287f93..7c2a26533e9 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -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, Listpush_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 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); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 7a07a5f6469..70060c3d0e6 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -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; diff --git a/gles3_builders.py b/gles3_builders.py index 0b6a3c25424..10d7e5bb4c7 100644 --- a/gles3_builders.py +++ b/gles3_builders.py @@ -364,6 +364,13 @@ def build_gles3_header( + str(defspec) + ") { _FU GLfloat vec3[3]={float(p_vec3.x),float(p_vec3.y),float(p_vec3.z)}; glUniform3fv(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),1,vec3); }\n\n" ) + fd.write( + "\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, const Vector4& p_vec4,RID p_version,ShaderVariant p_variant" + + defvariant + + ",uint64_t p_specialization=" + + str(defspec) + + ") { _FU GLfloat vec4[4]={float(p_vec4.x),float(p_vec4.y),float(p_vec4.z),float(p_vec4.w)}; glUniform4fv(version_get_uniform(p_uniform,p_version,p_variant,p_specialization),1,vec4); }\n\n" + ) fd.write( "\t_FORCE_INLINE_ void version_set_uniform(Uniforms p_uniform, float p_a, float p_b,RID p_version,ShaderVariant p_variant" + defvariant diff --git a/misc/extension_api_validation/4.1-stable.expected b/misc/extension_api_validation/4.1-stable.expected index 74d8af10175..b3b1f365736 100644 --- a/misc/extension_api_validation/4.1-stable.expected +++ b/misc/extension_api_validation/4.1-stable.expected @@ -274,3 +274,16 @@ Validate extension JSON: API was removed: classes/GraphEdit/methods/set_arrange_ Validate extension JSON: API was removed: classes/GraphEdit/properties/arrange_nodes_button_hidden Make GraphEdit toolbar more customizable + + +GH-81138 +-------- + +Validate extension JSON: Error: Field 'classes/ImporterMesh/methods/add_surface/arguments/6': meta changed value in new API, from "uint32" to "uint64". +Validate extension JSON: Error: Field 'classes/ImporterMesh/methods/get_surface_format/return_value': meta changed value in new API, from "uint32" to "uint64". +Validate extension JSON: Error: Field 'classes/MeshDataTool/methods/commit_to_surface/arguments': size changed value in new API, from 1 to 2. +Validate extension JSON: Error: Field 'classes/MeshDataTool/methods/get_format/return_value': meta changed value in new API, from "int32" to "uint64". +Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/shader_get_vertex_input_attribute_mask/return_value': meta changed value in new API, from "uint32" to "uint64". +Validate extension JSON: Error: Field 'classes/SurfaceTool/methods/commit/arguments/1': meta changed value in new API, from "uint32" to "uint64". + +Surface format was increased to 64 bits from 32 bits. Compatibility methods registered. diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index bac988630dd..595b14f260c 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -66,8 +66,10 @@ #endif // MODULE_GRIDMAP_ENABLED // FIXME: Hardcoded to avoid editor dependency. +#define GLTF_IMPORT_GENERATE_TANGENT_ARRAYS 8 #define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16 #define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32 +#define GLTF_IMPORT_FORCE_DISABLE_MESH_COMPRESSION 64 #include #include @@ -2208,7 +2210,7 @@ Error GLTFDocument::_serialize_meshes(Ref p_state) { } Array array = import_mesh->get_surface_arrays(surface_i); - uint32_t format = import_mesh->get_surface_format(surface_i); + uint64_t format = import_mesh->get_surface_format(surface_i); int32_t vertex_num = 0; Dictionary attributes; { @@ -2568,7 +2570,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { import_mesh->set_name(_gen_unique_name(p_state, vformat("%s_%s", p_state->scene_name, mesh_name))); for (int j = 0; j < primitives.size(); j++) { - uint32_t flags = 0; + uint64_t flags = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; Dictionary p = primitives[j]; Array array; @@ -2795,7 +2797,11 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { array[Mesh::ARRAY_INDEX] = indices; } - bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")); + bool generate_tangents = p_state->force_generate_tangents && (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")); + + if (p_state->force_disable_compression || !a.has("POSITION") || !a.has("NORMAL") || !(a.has("TANGENT") || generate_tangents) || p.has("targets") || (a.has("JOINTS_0") || a.has("JOINTS_1"))) { + flags &= ~RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES; + } Ref mesh_surface_tool; mesh_surface_tool.instantiate(); @@ -2935,7 +2941,7 @@ Error GLTFDocument::_parse_meshes(Ref p_state) { // Enforce blend shape mask array format for (int l = 0; l < Mesh::ARRAY_MAX; l++) { - if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1 << l))) { + if (!(Mesh::ARRAY_FORMAT_BLEND_SHAPE_MASK & (1ULL << l))) { array_copy[l] = Variant(); } } @@ -7415,6 +7421,8 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref p_state, uint ERR_FAIL_COND_V(p_state.is_null(), FAILED); p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + p_state->force_generate_tangents = p_flags & GLTF_IMPORT_GENERATE_TANGENT_ARRAYS; + p_state->force_disable_compression = p_flags & GLTF_IMPORT_FORCE_DISABLE_MESH_COMPRESSION; if (!p_state->buffers.size()) { p_state->buffers.push_back(Vector()); } @@ -7452,6 +7460,8 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa Error err = FAILED; p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + p_state->force_generate_tangents = p_flags & GLTF_IMPORT_GENERATE_TANGENT_ARRAYS; + p_state->force_disable_compression = p_flags & GLTF_IMPORT_FORCE_DISABLE_MESH_COMPRESSION; Ref file_access; file_access.instantiate(); @@ -7575,6 +7585,9 @@ Error GLTFDocument::append_from_file(String p_path, Ref p_state, uint p_state->filename = p_path.get_file().get_basename(); p_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; p_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS; + p_state->force_generate_tangents = p_flags & GLTF_IMPORT_GENERATE_TANGENT_ARRAYS; + p_state->force_disable_compression = p_flags & GLTF_IMPORT_FORCE_DISABLE_MESH_COMPRESSION; + Error err; Ref file = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index 91af8f91a4e..1ed8ce36290 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -58,7 +58,9 @@ class GLTFState : public Resource { bool use_named_skin_binds = false; bool use_khr_texture_transform = false; bool discard_meshes_and_materials = false; + bool force_generate_tangents = false; bool create_animations = true; + bool force_disable_compression = false; int handle_binary_image = HANDLE_BINARY_EXTRACT_TEXTURES; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs index bf8b2f10dc7..94788ef6804 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Compat.cs @@ -128,6 +128,16 @@ partial class GraphNode remove => DeleteRequest -= value; } } +partial class ImporterMesh +{ + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void AddSurface(Mesh.PrimitiveType primitive, Godot.Collections.Array arrays, Godot.Collections.Array blendShapes, Godot.Collections.Dictionary lods, Material material, string name, uint flags) + { + AddSurface(primitive, arrays, blendShapes, lods, material, name, (ulong)flags); + } +} + partial class MeshInstance3D { @@ -191,6 +201,13 @@ partial class SurfaceTool { AddTriangleFan(vertices, uvs, colors, uv2S, normals, new Godot.Collections.Array(tangents)); } + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public ArrayMesh Commit(ArrayMesh existing, uint flags) + { + return Commit(existing, (ulong)flags); + } } partial class TileMap diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index d24dd755dc0..1f12f96fb36 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -46,12 +46,14 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) { uint32_t surface_offsets[RS::ARRAY_MAX]; uint32_t vertex_stride; + uint32_t normal_tangent_stride; uint32_t attrib_stride; uint32_t skin_stride; - RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, attrib_stride, skin_stride); + RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, normal_tangent_stride, attrib_stride, skin_stride); buffer = surface_data.vertex_data; stride = vertex_stride; + normal_stride = normal_tangent_stride; offset_vertices = surface_offsets[RS::ARRAY_VERTEX]; offset_normal = surface_offsets[RS::ARRAY_NORMAL]; } @@ -59,6 +61,7 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) { void SoftBodyRenderingServerHandler::clear() { buffer.resize(0); stride = 0; + normal_stride = 0; offset_vertices = 0; offset_normal = 0; @@ -83,15 +86,11 @@ void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 & } void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &p_normal) { - // Store normal vector in A2B10G10R10 format. - Vector3 n = p_normal; - n *= Vector3(0.5, 0.5, 0.5); - n += Vector3(0.5, 0.5, 0.5); - Vector2 res = n.octahedron_encode(); + Vector2 res = p_normal.octahedron_encode(); uint32_t value = 0; value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535); value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16; - memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t)); + memcpy(&write_buffer[p_vertex_id * normal_stride + offset_normal], &value, sizeof(uint32_t)); } void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) { diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index 6648f956dc0..ab30f7e654f 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -44,6 +44,7 @@ class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHand int surface = 0; Vector buffer; uint32_t stride = 0; + uint32_t normal_stride = 0; uint32_t offset_vertices = 0; uint32_t offset_normal = 0; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 8250263c353..5c1b96363ea 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -234,8 +234,8 @@ void SpriteBase3D::draw_texture_rect(Ref p_texture, Rect2 p_dst_rect, float v_vertex[3] = { (float)vtx.x, (float)vtx.y, (float)vtx.z }; memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); - memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); + memcpy(&vertex_write_buffer[i * normal_tangent_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); + memcpy(&vertex_write_buffer[i * normal_tangent_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); } @@ -682,7 +682,7 @@ SpriteBase3D::SpriteBase3D() { sd.material = material; - RS::get_singleton()->mesh_surface_make_offsets_from_format(sd.format, sd.vertex_count, sd.index_count, mesh_surface_offsets, vertex_stride, attrib_stride, skin_stride); + RS::get_singleton()->mesh_surface_make_offsets_from_format(sd.format, sd.vertex_count, sd.index_count, mesh_surface_offsets, vertex_stride, normal_tangent_stride, attrib_stride, skin_stride); RS::get_singleton()->mesh_add_surface(mesh, sd); set_base(mesh); } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 1eb12119513..eeaa7e0f2d8 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -112,6 +112,7 @@ protected: PackedByteArray vertex_buffer; PackedByteArray attribute_buffer; uint32_t vertex_stride = 0; + uint32_t normal_tangent_stride = 0; uint32_t attrib_stride = 0; uint32_t skin_stride = 0; uint32_t mesh_surface_format = 0; diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index 48d609da978..dbc74d7c87a 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -149,7 +149,7 @@ void ImmediateMesh::surface_end() { ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); ERR_FAIL_COND_MSG(!vertices.size(), "No vertices were added, surface can't be created."); - uint32_t format = ARRAY_FORMAT_VERTEX; + uint64_t format = ARRAY_FORMAT_VERTEX | ARRAY_FLAG_FORMAT_CURRENT_VERSION; uint32_t vertex_stride = 0; if (active_surface_data.vertex_2d) { @@ -158,18 +158,18 @@ void ImmediateMesh::surface_end() { } else { vertex_stride = sizeof(float) * 3; } - + uint32_t normal_tangent_stride = 0; uint32_t normal_offset = 0; if (uses_normals) { format |= ARRAY_FORMAT_NORMAL; - normal_offset = vertex_stride; - vertex_stride += sizeof(uint32_t); + normal_offset = vertex_stride * vertices.size(); + normal_tangent_stride += sizeof(uint32_t); } uint32_t tangent_offset = 0; if (uses_tangents) { format |= ARRAY_FORMAT_TANGENT; - tangent_offset += vertex_stride; - vertex_stride += sizeof(uint32_t); + tangent_offset = vertex_stride * vertices.size() + normal_tangent_stride; + normal_tangent_stride += sizeof(uint32_t); } AABB aabb; @@ -192,7 +192,7 @@ void ImmediateMesh::surface_end() { } } if (uses_normals) { - uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset]; + uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * normal_tangent_stride + normal_offset]; Vector2 n = normals[i].octahedron_encode(); @@ -203,7 +203,7 @@ void ImmediateMesh::surface_end() { *normal = value; } if (uses_tangents) { - uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset]; + uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * normal_tangent_stride + tangent_offset]; Vector2 t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d); uint32_t value = 0; value |= (uint16_t)CLAMP(t.x * 65535, 0, 65535); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 092ba84aa5d..c7ee277a1b1 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -156,7 +156,7 @@ Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const { return blend_shape_mode; } -void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray &p_blend_shapes, const Dictionary &p_lods, const Ref &p_material, const String &p_name, const uint32_t p_flags) { +void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray &p_blend_shapes, const Dictionary &p_lods, const Ref &p_material, const String &p_name, const uint64_t p_flags) { ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); Surface s; @@ -240,7 +240,7 @@ float ImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const { return surfaces[p_surface].lods[p_lod].distance; } -uint32_t ImporterMesh::get_surface_format(int p_surface) const { +uint64_t ImporterMesh::get_surface_format(int p_surface) const { ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); return surfaces[p_surface].flags; } @@ -1105,7 +1105,7 @@ struct EditorSceneFormatImporterMeshLightmapSurface { Ref material; LocalVector vertices; Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX; - uint32_t format = 0; + uint64_t format = 0; String name; }; diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h index 69becc46a34..7a19aabd291 100644 --- a/scene/resources/importer_mesh.h +++ b/scene/resources/importer_mesh.h @@ -61,7 +61,7 @@ class ImporterMesh : public Resource { Vector lods; Ref material; String name; - uint32_t flags = 0; + uint64_t flags = 0; struct LODComparator { _FORCE_INLINE_ bool operator()(const LOD &l, const LOD &r) const { @@ -93,7 +93,7 @@ public: int get_blend_shape_count() const; String get_blend_shape_name(int p_blend_shape) const; - void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref &p_material = Ref(), const String &p_name = String(), const uint32_t p_flags = 0); + void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref &p_material = Ref(), const String &p_name = String(), const uint64_t p_flags = 0); int get_surface_count() const; void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); @@ -108,7 +108,7 @@ public: Vector get_surface_lod_indices(int p_surface, int p_lod) const; float get_surface_lod_size(int p_surface, int p_lod) const; Ref get_surface_material(int p_surface) const; - uint32_t get_surface_format(int p_surface) const; + uint64_t get_surface_format(int p_surface) const; void set_surface_material(int p_surface, const Ref &p_material); diff --git a/scene/resources/material.h b/scene/resources/material.h index 18fbc02a129..8cd583c709e 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -350,6 +350,8 @@ private: } }; + size_t sss = sizeof(MaterialKey); + struct ShaderData { RID shader; int users = 0; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 80927570273..971ec0e597e 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1011,12 +1011,13 @@ static Mesh::PrimitiveType _old_primitives[7] = { }; #endif // DISABLE_DEPRECATED -void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector &vertex_data, Vector &attribute_data, Vector &skin_data) { +void _fix_array_compatibility(const Vector &p_src, uint64_t p_old_format, uint64_t p_new_format, uint32_t p_elements, Vector &vertex_data, Vector &attribute_data, Vector &skin_data) { uint32_t dst_vertex_stride; + uint32_t dst_normal_tangent_stride; uint32_t dst_attribute_stride; uint32_t dst_skin_stride; uint32_t dst_offsets[Mesh::ARRAY_MAX]; - RenderingServer::get_singleton()->mesh_surface_make_offsets_from_format(p_new_format & (~RS::ARRAY_FORMAT_INDEX), p_elements, 0, dst_offsets, dst_vertex_stride, dst_attribute_stride, dst_skin_stride); + RenderingServer::get_singleton()->mesh_surface_make_offsets_from_format(p_new_format & (~RS::ARRAY_FORMAT_INDEX), p_elements, 0, dst_offsets, dst_vertex_stride, dst_normal_tangent_stride, dst_attribute_stride, dst_skin_stride); vertex_data.resize(dst_vertex_stride * p_elements); attribute_data.resize(dst_attribute_stride * p_elements); @@ -1031,7 +1032,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma uint32_t src_offset = 0; for (uint32_t j = 0; j < OLD_ARRAY_INDEX; j++) { - if (!(p_old_format & (1 << j))) { + if (!(p_old_format & (1ULL << j))) { continue; } switch (j) { @@ -1081,7 +1082,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) { for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767); dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767); @@ -1090,7 +1091,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma } else { for (uint32_t i = 0; i < p_elements; i++) { const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = src[0]; dst[1] = src[1]; @@ -1104,7 +1105,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma const Vector3 original_normal(src[0], src[1], src[2]); Vector2 res = original_normal.octahedron_encode(); - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } @@ -1115,7 +1116,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma const Vector3 original_normal(src[0], src[1], src[2]); Vector2 res = original_normal.octahedron_encode(); - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } @@ -1129,7 +1130,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM for (uint32_t i = 0; i < p_elements; i++) { const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535); @@ -1138,7 +1139,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma } else { // int16 SNORM -> uint16 UNORM for (uint32_t i = 0; i < p_elements; i++) { const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535); @@ -1152,7 +1153,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma const Vector3 original_tangent(src[0], src[1], src[2]); Vector2 res = original_tangent.octahedron_tangent_encode(src[3]); - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } @@ -1163,7 +1164,7 @@ void _fix_array_compatibility(const Vector &p_src, uint32_t p_old_forma const Vector3 original_tangent(src[0], src[1], src[2]); Vector2 res = original_tangent.octahedron_tangent_encode(src[3]); - uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_normal_tangent_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535); dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535); } @@ -1348,7 +1349,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } ERR_FAIL_COND_V(!d.has("format"), false); - uint32_t old_format = d["format"]; + uint64_t old_format = d["format"]; uint32_t primitive = d["primitive"]; @@ -1357,7 +1358,7 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!d.has("vertex_count"), false); int vertex_count = d["vertex_count"]; - uint32_t new_format = ARRAY_FORMAT_VERTEX; + uint64_t new_format = ARRAY_FORMAT_VERTEX | ARRAY_FLAG_FORMAT_CURRENT_VERSION; if (old_format & OLD_ARRAY_FORMAT_NORMAL) { new_format |= ARRAY_FORMAT_NORMAL; @@ -1494,6 +1495,7 @@ Array ArrayMesh::_get_surfaces() const { data["attribute_data"] = surface.attribute_data; } data["aabb"] = surface.aabb; + data["uv_scale"] = surface.uv_scale; if (surface.index_count) { data["index_data"] = surface.index_data; data["index_count"] = surface.index_count; @@ -1573,6 +1575,10 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { } surface.aabb = d["aabb"]; + if (d.has("uv_scale")) { + surface.uv_scale = d["uv_scale"]; + } + if (d.has("index_data")) { ERR_FAIL_COND(!d.has("index_count")); surface.index_data = d["index_data"]; @@ -1619,6 +1625,13 @@ void ArrayMesh::_set_surfaces(const Array &p_surfaces) { _2d = d["2d"]; } +#ifndef DISABLE_DEPRECATED + uint64_t surface_version = surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + if (surface_version != ARRAY_FLAG_FORMAT_CURRENT_VERSION) { + RS::_fix_surface_compatibility(surface); + } +#endif + surface_data.push_back(surface); surface_materials.push_back(material); surface_names.push_back(surf_name); @@ -1725,7 +1738,7 @@ void ArrayMesh::_recompute_aabb() { } // TODO: Need to add binding to add_surface using future MeshSurfaceData object. -void ArrayMesh::add_surface(BitField p_format, PrimitiveType p_primitive, const Vector &p_array, const Vector &p_attribute_array, const Vector &p_skin_array, int p_vertex_count, const Vector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector &p_blend_shape_data, const Vector &p_bone_aabbs, const Vector &p_lods) { +void ArrayMesh::add_surface(BitField p_format, PrimitiveType p_primitive, const Vector &p_array, const Vector &p_attribute_array, const Vector &p_skin_array, int p_vertex_count, const Vector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector &p_blend_shape_data, const Vector &p_bone_aabbs, const Vector &p_lods, const Vector4 p_uv_scale) { ERR_FAIL_COND(surfaces.size() == RS::MAX_MESH_SURFACES); _create_if_empty(); @@ -1753,6 +1766,7 @@ void ArrayMesh::add_surface(BitField p_format, PrimitiveType p_prim sd.blend_shape_data = p_blend_shape_data; sd.bone_aabbs = p_bone_aabbs; sd.lods = p_lods; + sd.uv_scale = p_uv_scale; RenderingServer::get_singleton()->mesh_add_surface(mesh, sd); @@ -1780,7 +1794,7 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & print_line("primitive: " + itos(surface.primitive)); */ - add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.bone_aabbs, surface.lods); + add_surface(surface.format, PrimitiveType(surface.primitive), surface.vertex_data, surface.attribute_data, surface.skin_data, surface.vertex_count, surface.index_data, surface.index_count, surface.aabb, surface.blend_shape_data, surface.bone_aabbs, surface.lods, surface.uv_scale); } Array ArrayMesh::surface_get_arrays(int p_surface) const { @@ -2005,7 +2019,7 @@ struct ArrayMeshLightmapSurface { Ref material; LocalVector vertices; Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX; - uint32_t format = 0; + uint64_t format = 0; }; Error ArrayMesh::lightmap_unwrap(const Transform3D &p_base_transform, float p_texel_size) { diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 435655e80aa..fd54b47b705 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -119,7 +119,7 @@ public: ARRAY_CUSTOM_MAX }; - enum ArrayFormat { + enum ArrayFormat : uint64_t { ARRAY_FORMAT_VERTEX = RS::ARRAY_FORMAT_VERTEX, ARRAY_FORMAT_NORMAL = RS::ARRAY_FORMAT_NORMAL, ARRAY_FORMAT_TANGENT = RS::ARRAY_FORMAT_TANGENT, @@ -151,6 +151,14 @@ public: ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS, ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY, + ARRAY_FLAG_COMPRESS_ATTRIBUTES = RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES, + + ARRAY_FLAG_FORMAT_VERSION_BASE = RS::ARRAY_FLAG_FORMAT_VERSION_BASE, + ARRAY_FLAG_FORMAT_VERSION_SHIFT = RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT, + ARRAY_FLAG_FORMAT_VERSION_1 = RS::ARRAY_FLAG_FORMAT_VERSION_1, + ARRAY_FLAG_FORMAT_VERSION_2 = (uint64_t)RS::ARRAY_FLAG_FORMAT_VERSION_2, + ARRAY_FLAG_FORMAT_CURRENT_VERSION = (uint64_t)RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION, + ARRAY_FLAG_FORMAT_VERSION_MASK = RS::ARRAY_FLAG_FORMAT_VERSION_MASK, }; virtual int get_surface_count() const; @@ -328,7 +336,7 @@ protected: public: void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray &p_blend_shapes = TypedArray(), const Dictionary &p_lods = Dictionary(), BitField p_flags = 0); - void add_surface(BitField p_format, PrimitiveType p_primitive, const Vector &p_array, const Vector &p_attribute_array, const Vector &p_skin_array, int p_vertex_count, const Vector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector &p_blend_shape_data = Vector(), const Vector &p_bone_aabbs = Vector(), const Vector &p_lods = Vector()); + void add_surface(BitField p_format, PrimitiveType p_primitive, const Vector &p_array, const Vector &p_attribute_array, const Vector &p_skin_array, int p_vertex_count, const Vector &p_index_array, int p_index_count, const AABB &p_aabb, const Vector &p_blend_shape_data = Vector(), const Vector &p_bone_aabbs = Vector(), const Vector &p_lods = Vector(), const Vector4 p_uv_scale = Vector4()); Array surface_get_arrays(int p_surface) const override; TypedArray surface_get_blend_shape_arrays(int p_surface) const override; diff --git a/scene/resources/mesh_data_tool.compat.inc b/scene/resources/mesh_data_tool.compat.inc new file mode 100644 index 00000000000..6299b0a2ab3 --- /dev/null +++ b/scene/resources/mesh_data_tool.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* mesh_data_tool.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +Error MeshDataTool::commit_to_surface_bind_compat_81138(const Ref &p_mesh) { + return commit_to_surface(p_mesh, 0); +} + +void MeshDataTool::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("commit_to_surface", "mesh"), &MeshDataTool::commit_to_surface_bind_compat_81138); +} + +#endif diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index 6ba236a02f0..7ec571214f8 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "mesh_data_tool.h" +#include "mesh_data_tool.compat.inc" void MeshDataTool::clear() { vertices.clear(); @@ -190,7 +191,7 @@ Error MeshDataTool::create_from_surface(const Ref &p_mesh, int p_surf return OK; } -Error MeshDataTool::commit_to_surface(const Ref &p_mesh) { +Error MeshDataTool::commit_to_surface(const Ref &p_mesh, uint64_t p_compression_flags) { ERR_FAIL_COND_V(p_mesh.is_null(), ERR_INVALID_PARAMETER); Array arr; arr.resize(Mesh::ARRAY_MAX); @@ -327,13 +328,13 @@ Error MeshDataTool::commit_to_surface(const Ref &p_mesh) { Ref ncmesh = p_mesh; int sc = ncmesh->get_surface_count(); - ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); + ncmesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, TypedArray(), Dictionary(), p_compression_flags); ncmesh->surface_set_material(sc, material); return OK; } -int MeshDataTool::get_format() const { +uint64_t MeshDataTool::get_format() const { return format; } @@ -521,7 +522,7 @@ void MeshDataTool::set_material(const Ref &p_material) { void MeshDataTool::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &MeshDataTool::clear); ClassDB::bind_method(D_METHOD("create_from_surface", "mesh", "surface"), &MeshDataTool::create_from_surface); - ClassDB::bind_method(D_METHOD("commit_to_surface", "mesh"), &MeshDataTool::commit_to_surface); + ClassDB::bind_method(D_METHOD("commit_to_surface", "mesh", "compression_flags"), &MeshDataTool::commit_to_surface, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_format"), &MeshDataTool::get_format); diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h index 2912d47416a..36311cfefc0 100644 --- a/scene/resources/mesh_data_tool.h +++ b/scene/resources/mesh_data_tool.h @@ -36,7 +36,7 @@ class MeshDataTool : public RefCounted { GDCLASS(MeshDataTool, RefCounted); - int format = 0; + uint64_t format = 0; struct Vertex { Vector3 vertex; Color color; @@ -74,12 +74,17 @@ class MeshDataTool : public RefCounted { protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + Error commit_to_surface_bind_compat_81138(const Ref &p_mesh); + static void _bind_compatibility_methods(); +#endif + public: void clear(); Error create_from_surface(const Ref &p_mesh, int p_surface); - Error commit_to_surface(const Ref &p_mesh); + Error commit_to_surface(const Ref &p_mesh, uint64_t p_compression_flags = 0); - int get_format() const; + uint64_t get_format() const; int get_vertex_count() const; int get_edge_count() const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 2523215d4dc..4560ce51cef 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -422,7 +422,7 @@ Array SurfaceTool::commit_to_arrays() { a.resize(Mesh::ARRAY_MAX); for (int i = 0; i < Mesh::ARRAY_MAX; i++) { - if (!(format & (1 << i))) { + if (!(format & (1ULL << i))) { continue; //not in format } @@ -711,7 +711,7 @@ Array SurfaceTool::commit_to_arrays() { return a; } -Ref SurfaceTool::commit(const Ref &p_existing, uint32_t p_compress_flags) { +Ref SurfaceTool::commit(const Ref &p_existing, uint64_t p_compress_flags) { Ref mesh; if (p_existing.is_valid()) { mesh = p_existing; @@ -787,7 +787,7 @@ void SurfaceTool::deindex() { index_array.clear(); } -void SurfaceTool::_create_list(const Ref &p_existing, int p_surface, LocalVector *r_vertex, LocalVector *r_index, uint32_t &lformat) { +void SurfaceTool::_create_list(const Ref &p_existing, int p_surface, LocalVector *r_vertex, LocalVector *r_index, uint64_t &lformat) { ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::_create_list() must be a valid object of type Mesh"); Array arr = p_existing->surface_get_arrays(p_surface); @@ -798,7 +798,7 @@ void SurfaceTool::_create_list(const Ref &p_existing, int p_surface, Local const uint32_t SurfaceTool::custom_mask[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0, Mesh::ARRAY_FORMAT_CUSTOM1, Mesh::ARRAY_FORMAT_CUSTOM2, Mesh::ARRAY_FORMAT_CUSTOM3 }; const uint32_t SurfaceTool::custom_shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT }; -void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector &ret, uint32_t *r_format) { +void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector &ret, uint64_t *r_format) { ret.clear(); Vector varr = p_arrays[RS::ARRAY_VERTEX]; @@ -927,7 +927,7 @@ void SurfaceTool::create_vertex_array_from_triangle_arrays(const Array &p_arrays } } -void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector *r_vertex, LocalVector *r_index, uint32_t &lformat) { +void SurfaceTool::_create_list_from_arrays(Array arr, LocalVector *r_vertex, LocalVector *r_index, uint64_t &lformat) { create_vertex_array_from_triangle_arrays(arr, *r_vertex, &lformat); ERR_FAIL_COND(r_vertex->size() == 0); @@ -1020,7 +1020,7 @@ void SurfaceTool::append_from(const Ref &p_existing, int p_surface, const format = 0; } - uint32_t nformat = 0; + uint64_t nformat = 0; LocalVector nvertices; LocalVector nindices; _create_list(p_existing, p_surface, &nvertices, &nindices, nformat); diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index eabdff19ca6..2a8ad535259 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -136,7 +136,7 @@ private: bool begun = false; bool first = false; Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_LINES; - uint32_t format = 0; + uint64_t format = 0; Ref material; //arrays LocalVector vertex_array; @@ -158,8 +158,8 @@ private: CustomFormat last_custom_format[RS::ARRAY_CUSTOM_COUNT]; - void _create_list_from_arrays(Array arr, LocalVector *r_vertex, LocalVector *r_index, uint32_t &lformat); - void _create_list(const Ref &p_existing, int p_surface, LocalVector *r_vertex, LocalVector *r_index, uint32_t &lformat); + void _create_list_from_arrays(Array arr, LocalVector *r_vertex, LocalVector *r_index, uint64_t &lformat); + void _create_list(const Ref &p_existing, int p_surface, LocalVector *r_vertex, LocalVector *r_index, uint64_t &lformat); //mikktspace callbacks static int mikktGetNumFaces(const SMikkTSpaceContext *pContext); @@ -219,12 +219,12 @@ public: LocalVector &get_vertex_array() { return vertex_array; } void create_from_triangle_arrays(const Array &p_arrays); - static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector &ret, uint32_t *r_format = nullptr); + static void create_vertex_array_from_triangle_arrays(const Array &p_arrays, LocalVector &ret, uint64_t *r_format = nullptr); Array commit_to_arrays(); void create_from(const Ref &p_existing, int p_surface); void create_from_blend_shape(const Ref &p_existing, int p_surface, const String &p_blend_shape_name); void append_from(const Ref &p_existing, int p_surface, const Transform3D &p_xform); - Ref commit(const Ref &p_existing = Ref(), uint32_t p_compress_flags = 0); + Ref commit(const Ref &p_existing = Ref(), uint64_t p_compress_flags = 0); SurfaceTool(); }; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index ece3b5597da..e65101d8568 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -728,7 +728,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i RendererRD::MaterialStorage::store_transform(inst->prev_transform, instance_data.prev_transform); #ifdef REAL_T_IS_DOUBLE - // Split the origin into two components, the float approximation and the missing precision + // Split the origin into two components, the float approximation and the missing precision. // In the shader we will combine these back together to restore the lost precision. RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]); RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]); @@ -748,6 +748,28 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; + AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)); + uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface); + Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + + if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface); + uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface); + } + + instance_data.compressed_aabb_position[0] = surface_aabb.position.x; + instance_data.compressed_aabb_position[1] = surface_aabb.position.y; + instance_data.compressed_aabb_position[2] = surface_aabb.position.z; + + instance_data.compressed_aabb_size[0] = surface_aabb.size.x; + instance_data.compressed_aabb_size[1] = surface_aabb.size.y; + instance_data.compressed_aabb_size[2] = surface_aabb.size.z; + + instance_data.uv_scale[0] = uv_scale.x; + instance_data.uv_scale[1] = uv_scale.y; + instance_data.uv_scale[2] = uv_scale.z; + instance_data.uv_scale[3] = uv_scale.w; + bool cant_repeat = instance_data.flags & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid(); if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2 && inst->mirror == prev_surface->owner->mirror && repeats < RenderElementInfo::MAX_REPEATS) { @@ -3942,7 +3964,7 @@ RenderGeometryInstance *RenderForwardClustered::geometry_instance_create(RID p_b return ginstance; } -void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) { +void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { uint64_t frame = RSG::rasterizer->get_frame_number(); if (frame != prev_transform_change_frame) { prev_transform = transform; @@ -3950,7 +3972,7 @@ void RenderForwardClustered::GeometryInstanceForwardClustered::set_transform(con prev_transform_dirty = true; } - RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabbb); + RenderGeometryInstanceBase::set_transform(p_transform, p_aabb, p_transformed_aabb); } void RenderForwardClustered::GeometryInstanceForwardClustered::set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 6955d4f6ef3..46deb30cdee 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -298,6 +298,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) uint32_t layer_mask; float lightmap_uv_scale[4]; + float compressed_aabb_position[4]; + float compressed_aabb_size[4]; + float uv_scale[4]; }; UBO ubo; @@ -479,7 +482,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void _mark_dirty() override; - virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override; + virtual void set_transform(const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; virtual void set_lightmap_capture(const Color *p_sh9) override; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 761b74defa6..0739cd9f86f 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -142,7 +142,7 @@ public: bool valid = false; RID version; - uint32_t vertex_input_mask = 0; + uint64_t vertex_input_mask = 0; PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX]; PipelineCacheRD color_pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_COLOR_PASS_FLAG_COUNT]; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 4706249142b..a032cf44b6c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -68,53 +68,40 @@ void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::For forward_id_allocators[p_type].map[p_id] = p_index; } -void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) { - // first zero out our indices +void RenderForwardMobile::fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance) { + // First zero out our indices. - p_push_constant->omni_lights[0] = 0xFFFFFFFF; - p_push_constant->omni_lights[1] = 0xFFFFFFFF; + p_instance_data->omni_lights[0] = 0xFFFFFFFF; + p_instance_data->omni_lights[1] = 0xFFFFFFFF; - p_push_constant->spot_lights[0] = 0xFFFFFFFF; - p_push_constant->spot_lights[1] = 0xFFFFFFFF; + p_instance_data->spot_lights[0] = 0xFFFFFFFF; + p_instance_data->spot_lights[1] = 0xFFFFFFFF; - p_push_constant->decals[0] = 0xFFFFFFFF; - p_push_constant->decals[1] = 0xFFFFFFFF; + p_instance_data->decals[0] = 0xFFFFFFFF; + p_instance_data->decals[1] = 0xFFFFFFFF; - p_push_constant->reflection_probes[0] = 0xFFFFFFFF; - p_push_constant->reflection_probes[1] = 0xFFFFFFFF; - - if (p_instance->omni_light_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS; - } - if (p_instance->spot_light_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS; - } - if (p_instance->reflection_probe_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES; - } - if (p_instance->decals_count == 0) { - spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS; - } + p_instance_data->reflection_probes[0] = 0xFFFFFFFF; + p_instance_data->reflection_probes[1] = 0xFFFFFFFF; for (uint32_t i = 0; i < MAX_RDL_CULL; i++) { uint32_t ofs = i < 4 ? 0 : 1; uint32_t shift = (i & 0x3) << 3; uint32_t mask = ~(0xFF << shift); if (i < p_instance->omni_light_count) { - p_push_constant->omni_lights[ofs] &= mask; - p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; + p_instance_data->omni_lights[ofs] &= mask; + p_instance_data->omni_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift; } if (i < p_instance->spot_light_count) { - p_push_constant->spot_lights[ofs] &= mask; - p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; + p_instance_data->spot_lights[ofs] &= mask; + p_instance_data->spot_lights[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift; } if (i < p_instance->decals_count) { - p_push_constant->decals[ofs] &= mask; - p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; + p_instance_data->decals[ofs] &= mask; + p_instance_data->decals[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift; } if (i < p_instance->reflection_probe_count) { - p_push_constant->reflection_probes[ofs] &= mask; - p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; + p_instance_data->reflection_probes[ofs] &= mask; + p_instance_data->reflection_probes[ofs] |= uint32_t(forward_id_storage_mobile->forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift; } } } @@ -366,6 +353,18 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ uniforms.push_back(u); } + { + RD::Uniform u; + u.binding = 1; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + RID instance_buffer = scene_state.instance_buffer[p_render_list]; + if (instance_buffer == RID()) { + instance_buffer = scene_shader.default_vec4_xform_buffer; // Any buffer will do since its not used. + } + u.append_id(instance_buffer); + uniforms.push_back(u); + } + { RID radiance_texture; if (p_radiance_texture.is_valid()) { @@ -461,15 +460,6 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ uniforms.push_back(u); } - - { - RD::Uniform u; - u.binding = 8; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - RID cb = p_cluster_buffer.is_valid() ? p_cluster_buffer : default_vec4_xform_buffer; - u.append_id(cb); - uniforms.push_back(u); - } */ { @@ -682,8 +672,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); render_list[RENDER_LIST_OPAQUE].sort_by_key(); render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); - _fill_element_info(RENDER_LIST_OPAQUE); - _fill_element_info(RENDER_LIST_ALPHA); + _fill_instance_data(RENDER_LIST_OPAQUE); + _fill_instance_data(RENDER_LIST_ALPHA); if (p_render_data->render_info) { p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size(); @@ -1290,7 +1280,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true); uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); - _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size); + _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size); { //regular forward for now @@ -1373,7 +1363,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_element_info(RENDER_LIST_SECONDARY); + _fill_instance_data(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -1418,7 +1408,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_element_info(RENDER_LIST_SECONDARY); + _fill_instance_data(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -1499,7 +1489,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_element_info(RENDER_LIST_SECONDARY); + _fill_instance_data(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -1691,6 +1681,91 @@ RID RenderForwardMobile::_render_buffers_get_velocity_texture(Ref 0) { + if (scene_state.instance_buffer[p_render_list] == RID() || scene_state.instance_buffer_size[p_render_list] < scene_state.instance_data[p_render_list].size()) { + if (scene_state.instance_buffer[p_render_list] != RID()) { + RD::get_singleton()->free(scene_state.instance_buffer[p_render_list]); + } + uint32_t new_size = nearest_power_of_2_templated(MAX(uint64_t(INSTANCE_DATA_BUFFER_MIN_SIZE), scene_state.instance_data[p_render_list].size())); + scene_state.instance_buffer[p_render_list] = RD::get_singleton()->storage_buffer_create(new_size * sizeof(SceneState::InstanceData)); + scene_state.instance_buffer_size[p_render_list] = new_size; + } + RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); + } +} + +void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { + RenderList *rl = &render_list[p_render_list]; + uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); + + scene_state.instance_data[p_render_list].resize(p_offset + element_total); + rl->element_info.resize(p_offset + element_total); + + for (uint32_t i = 0; i < element_total; i++) { + GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; + GeometryInstanceForwardMobile *inst = surface->owner; + + SceneState::InstanceData &instance_data = scene_state.instance_data[p_render_list][i + p_offset]; + + if (inst->store_transform_cache) { + RendererRD::MaterialStorage::store_transform(inst->transform, instance_data.transform); + +#ifdef REAL_T_IS_DOUBLE + // Split the origin into two components, the float approximation and the missing precision. + // In the shader we will combine these back together to restore the lost precision. + RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &instance_data.transform[12], &instance_data.transform[3]); + RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &instance_data.transform[13], &instance_data.transform[7]); + RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &instance_data.transform[14], &instance_data.transform[11]); +#endif + } else { + RendererRD::MaterialStorage::store_transform(Transform3D(), instance_data.transform); + } + + instance_data.flags = inst->flags_cache; + instance_data.gi_offset = inst->gi_offset_cache; + instance_data.layer_mask = inst->layer_mask; + instance_data.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset); + instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; + instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; + instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; + instance_data.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; + + AABB surface_aabb = AABB(Vector3(0.0, 0.0, 0.0), Vector3(1.0, 1.0, 1.0)); + uint64_t format = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_format(surface->surface); + Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + + if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + surface_aabb = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_aabb(surface->surface); + uv_scale = RendererRD::MeshStorage::get_singleton()->mesh_surface_get_uv_scale(surface->surface); + } + + fill_push_constant_instance_indices(&instance_data, inst); + + instance_data.compressed_aabb_position[0] = surface_aabb.position.x; + instance_data.compressed_aabb_position[1] = surface_aabb.position.y; + instance_data.compressed_aabb_position[2] = surface_aabb.position.z; + + instance_data.compressed_aabb_size[0] = surface_aabb.size.x; + instance_data.compressed_aabb_size[1] = surface_aabb.size.y; + instance_data.compressed_aabb_size[2] = surface_aabb.size.z; + + instance_data.uv_scale[0] = uv_scale.x; + instance_data.uv_scale[1] = uv_scale.y; + instance_data.uv_scale[2] = uv_scale.z; + instance_data.uv_scale[3] = uv_scale.w; + + RenderElementInfo &element_info = rl->element_info[p_offset + i]; + + element_info.lod_index = surface->lod_index; + element_info.uses_lightmap = surface->sort.uses_lightmap; + } + + if (p_update_buffer) { + _update_instance_data_buffer(p_render_list); + } +} + _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) { static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 }; static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 }; @@ -1911,21 +1986,6 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers, false); } -void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) { - RenderList *rl = &render_list[p_render_list]; - uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); - - rl->element_info.resize(p_offset + element_total); - - for (uint32_t i = 0; i < element_total; i++) { - GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset]; - RenderElementInfo &element_info = rl->element_info[p_offset + i]; - - element_info.lod_index = surface->lod_index; - element_info.uses_lightmap = surface->sort.uses_lightmap; - } -} - /// RENDERING /// void RenderForwardMobile::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { @@ -2011,39 +2071,17 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr uint32_t base_spec_constants = p_params->spec_constant_base_flags; - // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant; - GeometryInstanceForwardMobile::PushConstant push_constant; + SceneState::PushConstant push_constant; + push_constant.base_index = i + p_params->element_offset; - if (inst->store_transform_cache) { - RendererRD::MaterialStorage::store_transform(inst->transform, push_constant.transform); - -#ifdef REAL_T_IS_DOUBLE - // Split the origin into two components, the float approximation and the missing precision - // In the shader we will combine these back together to restore the lost precision. - RendererRD::MaterialStorage::split_double(inst->transform.origin.x, &push_constant.transform[12], &push_constant.transform[3]); - RendererRD::MaterialStorage::split_double(inst->transform.origin.y, &push_constant.transform[13], &push_constant.transform[7]); - RendererRD::MaterialStorage::split_double(inst->transform.origin.z, &push_constant.transform[14], &push_constant.transform[11]); -#endif + if constexpr (p_pass_mode == PASS_MODE_DEPTH_MATERIAL) { + push_constant.uv_offset[0] = p_params->uv_offset.x; + push_constant.uv_offset[1] = p_params->uv_offset.y; } else { - RendererRD::MaterialStorage::store_transform(Transform3D(), push_constant.transform); + push_constant.uv_offset[0] = 0.0; + push_constant.uv_offset[1] = 0.0; } - push_constant.flags = inst->flags_cache; - push_constant.gi_offset = inst->gi_offset_cache; - push_constant.layer_mask = inst->layer_mask; - push_constant.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset); - - if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) { - // abuse lightmap_uv_scale[0] here, should not be needed here - push_constant.lightmap_uv_scale[0] = p_params->uv_offset.x; - push_constant.lightmap_uv_scale[1] = p_params->uv_offset.y; - } else { - push_constant.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x; - push_constant.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y; - push_constant.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x; - push_constant.lightmap_uv_scale[3] = inst->lightmap_uv_scale.size.y; - }; - RID material_uniform_set; SceneShaderForwardMobile::ShaderData *shader; void *mesh_surface; @@ -2060,7 +2098,19 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr if (inst->use_soft_shadow) { base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS; } - forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst); + + if (inst->omni_light_count == 0) { + base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS; + } + if (inst->spot_light_count == 0) { + base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS; + } + if (inst->reflection_probe_count == 0) { + base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES; + } + if (inst->decals_count == 0) { + base_spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS; + } #ifdef DEBUG_ENABLED if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) { @@ -2184,7 +2234,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr prev_material_uniform_set = material_uniform_set; } - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant)); + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant)); uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1; if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 65723e5aa53..50bf83b6129 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -202,9 +202,9 @@ private: void _update_render_base_uniform_set(const RendererRD::MaterialStorage::Samplers &p_samplers); + void _update_instance_data_buffer(RenderListType p_render_list); + void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false); - void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1); - // void _update_instance_data_buffer(RenderListType p_render_list); void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray &p_lightmaps, const Transform3D &p_cam_transform); @@ -229,6 +229,32 @@ private: struct SceneState { LocalVector uniform_buffers; + struct PushConstant { + float uv_offset[2]; + uint32_t base_index; + uint32_t pad; + }; + + struct InstanceData { + float transform[16]; + uint32_t flags; + uint32_t instance_uniforms_ofs; // Base offset in global buffer for instance variables. + uint32_t gi_offset; // GI information when using lightmapping (VCT or lightmap index). + uint32_t layer_mask = 1; + float lightmap_uv_scale[4]; // Doubles as uv_offset when needed. + uint32_t reflection_probes[2]; // Packed reflection probes. + uint32_t omni_lights[2]; // Packed omni lights. + uint32_t spot_lights[2]; // Packed spot lights. + uint32_t decals[2]; // Packed spot lights. + float compressed_aabb_position[4]; + float compressed_aabb_size[4]; + float uv_scale[4]; + }; + + RID instance_buffer[RENDER_LIST_MAX]; + uint32_t instance_buffer_size[RENDER_LIST_MAX] = { 0, 0, 0 }; + LocalVector instance_data[RENDER_LIST_MAX]; + // !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in LightmapData lightmaps[MAX_LIGHTMAPS]; RID lightmap_ids[MAX_LIGHTMAPS]; @@ -447,27 +473,11 @@ protected: class GeometryInstanceForwardMobile : public RenderGeometryInstanceBase { public: - // this structure maps to our push constant in our shader and is populated right before our draw call - struct PushConstant { - float transform[16]; - uint32_t flags; - uint32_t instance_uniforms_ofs; //base offset in global buffer for instance variables - uint32_t gi_offset; //GI information when using lightmapping (VCT or lightmap index) - uint32_t layer_mask = 1; - float lightmap_uv_scale[4]; // doubles as uv_offset when needed - uint32_t reflection_probes[2]; // packed reflection probes - uint32_t omni_lights[2]; // packed omni lights - uint32_t spot_lights[2]; // packed spot lights - uint32_t decals[2]; // packed spot lights - }; - - // PushConstant push_constant; // we populate this from our instance data - //used during rendering RID transforms_uniform_set; bool use_projector = false; bool use_soft_shadow = false; - bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform + bool store_transform_cache = true; // If true we copy our transform into our per-draw buffer, if false we use our transforms UBO and clear our per-draw transform. uint32_t instance_count = 0; uint32_t trail_steps = 1; @@ -534,12 +544,12 @@ protected: virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override; virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override; virtual bool uses_forward_ids() const override { return true; } - - void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance); }; ForwardIDStorageMobile *forward_id_storage_mobile = nullptr; + void fill_push_constant_instance_indices(SceneState::InstanceData *p_instance_data, const GeometryInstanceForwardMobile *p_instance); + virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override { forward_id_storage_mobile = memnew(ForwardIDStorageMobile); return forward_id_storage_mobile; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index eeaff0ccb11..311ca72c754 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -620,7 +620,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; actions.global_buffer_array_variable = "global_shader_uniforms.data"; - actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs"; + actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs"; actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures. diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 0b98746d06a..5c76d892477 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -97,7 +97,7 @@ public: bool valid = false; RID version; - uint32_t vertex_input_mask = 0; + uint64_t vertex_input_mask = 0; PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; Vector texture_uniforms; diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index 52877109f7d..2f1e79b3974 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -91,7 +91,7 @@ public: return result; } - _FORCE_INLINE_ uint32_t get_vertex_input_mask() { + _FORCE_INLINE_ uint64_t get_vertex_input_mask() { if (input_mask == 0) { ERR_FAIL_COND_V(shader.is_null(), 0); input_mask = RD::get_singleton()->shader_get_vertex_input_attribute_mask(shader); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 3c23e68d724..885a00856e2 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -894,7 +894,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface); ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX); - uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask(); + uint64_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask(); RID vertex_array; RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 878b629c25b..56e466ba987 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -10,21 +10,17 @@ /* INPUT ATTRIBS */ -layout(location = 0) in vec3 vertex_attrib; +// Always contains vertex position in XYZ, can contain tangent angle in W. +layout(location = 0) in vec4 vertex_angle_attrib; //only for pure render depth when normal is not used -#ifdef NORMAL_USED -layout(location = 1) in vec2 normal_attrib; +#if defined(NORMAL_USED) || defined(TANGENT_USED) +// Contains Normal/Axis in RG, can contain tangent in BA. +layout(location = 1) in vec4 axis_tangent_attrib; #endif -#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)) -#define TANGENT_USED -#endif - -#ifdef TANGENT_USED -layout(location = 2) in vec2 tangent_attrib; -#endif +// Location 2 is unused. #if defined(COLOR_USED) layout(location = 3) in vec4 color_attrib; @@ -63,15 +59,12 @@ layout(location = 11) in vec4 weight_attrib; #endif #ifdef MOTION_VECTORS -layout(location = 12) in vec3 previous_vertex_attrib; +layout(location = 12) in vec4 previous_vertex_attrib; -#ifdef NORMAL_USED -layout(location = 13) in vec2 previous_normal_attrib; +#if defined(NORMAL_USED) || defined(TANGENT_USED) +layout(location = 13) in vec4 previous_normal_attrib; #endif -#ifdef TANGENT_USED -layout(location = 14) in vec2 previous_tangent_attrib; -#endif #endif // MOTION_VECTORS vec3 oct_to_vec3(vec2 e) { @@ -81,6 +74,16 @@ vec3 oct_to_vec3(vec2 e) { return normalize(v); } +void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { + float c = cos(angle); + float s = sin(angle); + vec3 omc_axis = (1.0 - c) * axis; + vec3 s_axis = s * axis; + tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); + binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); + normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); +} + /* Varyings */ layout(location = 0) out vec3 vertex_interp; @@ -179,10 +182,11 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec void vertex_shader(vec3 vertex_input, #ifdef NORMAL_USED - in vec2 normal_input, + in vec3 normal_input, #endif #ifdef TANGENT_USED - in vec2 tangent_input, + in vec3 tangent_input, + in vec3 binormal_input, #endif in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) { vec4 instance_custom = vec4(0.0); @@ -314,14 +318,12 @@ void vertex_shader(vec3 vertex_input, vec3 vertex = vertex_input; #ifdef NORMAL_USED - vec3 normal = oct_to_vec3(normal_input * 2.0 - 1.0); + vec3 normal = normal_input; #endif #ifdef TANGENT_USED - vec2 signed_tangent_input = tangent_input * 2.0 - 1.0; - vec3 tangent = oct_to_vec3(vec2(signed_tangent_input.x, abs(signed_tangent_input.y) * 2.0 - 1.0)); - float binormalf = sign(signed_tangent_input.y); - vec3 binormal = normalize(cross(normal, tangent) * binormalf); + vec3 tangent = tangent_input; + vec3 binormal = binormal_input; #endif #ifdef UV_USED @@ -332,6 +334,17 @@ void vertex_shader(vec3 vertex_input, uv2_interp = uv2_attrib; #endif + vec4 uv_scale = instances.data[instance_index].uv_scale; + + if (uv_scale != vec4(0.0)) { // Compression enabled +#ifdef UV_USED + uv_interp = (uv_interp - 0.5) * uv_scale.xy; +#endif +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = (uv2_interp - 0.5) * uv_scale.zw; +#endif + } + #ifdef OVERRIDE_POSITION vec4 position; #endif @@ -484,6 +497,46 @@ void vertex_shader(vec3 vertex_input, #endif } +void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec4 p_normal_in, +#ifdef NORMAL_USED + out vec3 r_normal, +#endif + out vec3 r_tangent, + out vec3 r_binormal, +#endif + out vec3 r_vertex) { + + r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position; +#ifdef NORMAL_USED + r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0); +#endif + +#if defined(NORMAL_USED) || defined(TANGENT_USED) + + float binormal_sign; + + // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1). + // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1). + if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0; + r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign); + } else { + // Compressed format. + float angle = p_vertex_in.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = r_normal; + axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal); + r_binormal *= binormal_sign; + } +#endif +} + void main() { uint instance_index = draw_call.instance_index; @@ -498,13 +551,38 @@ void main() { #ifdef MOTION_VECTORS // Previous vertex. - global_time = scene_data_block.prev_data.time; - vertex_shader(previous_vertex_attrib, + vec3 prev_vertex; #ifdef NORMAL_USED + vec3 prev_normal; +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec3 prev_tangent; + vec3 prev_binormal; +#endif + + _unpack_vertex_attributes( + previous_vertex_attrib, + instances.data[instance_index].compressed_aabb_position_pad.xyz, + instances.data[instance_index].compressed_aabb_size_pad.xyz, + +#if defined(NORMAL_USED) || defined(TANGENT_USED) previous_normal_attrib, +#ifdef NORMAL_USED + prev_normal, +#endif + prev_tangent, + prev_binormal, +#endif + prev_vertex); + + global_time = scene_data_block.prev_data.time; + vertex_shader(prev_vertex, +#ifdef NORMAL_USED + prev_normal, #endif #ifdef TANGENT_USED - previous_tangent_attrib, + prev_tangent, + prev_binormal, #endif instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position); #else @@ -512,14 +590,38 @@ void main() { vec4 screen_position; #endif + vec3 vertex; +#ifdef NORMAL_USED + vec3 normal; +#endif +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec3 tangent; + vec3 binormal; +#endif + + _unpack_vertex_attributes( + vertex_angle_attrib, + instances.data[instance_index].compressed_aabb_position_pad.xyz, + instances.data[instance_index].compressed_aabb_size_pad.xyz, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + axis_tangent_attrib, +#ifdef NORMAL_USED + normal, +#endif + tangent, + binormal, +#endif + vertex); + // Current vertex. global_time = scene_data_block.data.time; - vertex_shader(vertex_attrib, + vertex_shader(vertex, #ifdef NORMAL_USED - normal_attrib, + normal, #endif #ifdef TANGENT_USED - tangent_attrib, + tangent, + binormal, #endif instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position); } @@ -575,10 +677,6 @@ layout(location = 3) in vec2 uv_interp; layout(location = 4) in vec2 uv2_interp; #endif -#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)) -#define TANGENT_USED -#endif - #ifdef TANGENT_USED layout(location = 5) in vec3 tangent_interp; layout(location = 6) in vec3 binormal_interp; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl index 8ead363f3b8..bfd87b4ea15 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl @@ -28,6 +28,10 @@ #endif #endif +#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)) +#define TANGENT_USED +#endif + layout(push_constant, std430) uniform DrawCall { uint instance_index; uint uv_offset; @@ -211,6 +215,9 @@ struct InstanceData { uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) uint layer_mask; vec4 lightmap_uv_scale; + vec4 compressed_aabb_position_pad; // Only .xyz is used. .w is padding. + vec4 compressed_aabb_size_pad; // Only .xyz is used. .w is padding. + vec4 uv_scale; }; layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer { diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 7f6a9a50e5b..ade40cbf7a6 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -11,17 +11,17 @@ /* INPUT ATTRIBS */ -layout(location = 0) in vec3 vertex_attrib; +// Always contains vertex position in XYZ, can contain tangent angle in W. +layout(location = 0) in vec4 vertex_angle_attrib; //only for pure render depth when normal is not used #ifdef NORMAL_USED -layout(location = 1) in vec2 normal_attrib; +// Contains Normal/Axis in RG, can contain tangent in BA. +layout(location = 1) in vec4 axis_tangent_attrib; #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) -layout(location = 2) in vec2 tangent_attrib; -#endif +// Location 2 is unused. #if defined(COLOR_USED) layout(location = 3) in vec4 color_attrib; @@ -66,6 +66,16 @@ vec3 oct_to_vec3(vec2 e) { return normalize(v); } +void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { + float c = cos(angle); + float s = sin(angle); + vec3 omc_axis = (1.0 - c) * axis; + vec3 s_axis = s * axis; + tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); + binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); + normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); +} + /* Varyings */ layout(location = 0) highp out vec3 vertex_interp; @@ -162,9 +172,9 @@ void main() { color_interp = color_attrib; #endif - bool is_multimesh = bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH); + bool is_multimesh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH); - mat4 model_matrix = draw_call.transform; + mat4 model_matrix = instances.data[draw_call.instance_index].transform; mat4 inv_view_matrix = scene_data.inv_view_matrix; #ifdef USE_DOUBLE_PRECISION vec3 model_precision = vec3(model_matrix[0][3], model_matrix[1][3], model_matrix[2][3]); @@ -178,7 +188,7 @@ void main() { #endif mat3 model_normal_matrix; - if (bool(draw_call.flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_NON_UNIFORM_SCALE)) { model_normal_matrix = transpose(inverse(mat3(model_matrix))); } else { model_normal_matrix = mat3(model_matrix); @@ -191,7 +201,7 @@ void main() { //multimesh, instances are for it #ifdef USE_PARTICLE_TRAILS - uint trail_size = (draw_call.flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; + uint trail_size = (instances.data[draw_call.instance_index].flags >> INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT) & INSTANCE_FLAGS_PARTICLE_TRAIL_MASK; uint stride = 3 + 1 + 1; //particles always uses this format uint offset = trail_size * stride * gl_InstanceIndex; @@ -238,22 +248,22 @@ void main() { uint stride = 0; { //TODO implement a small lookup table for the stride - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { stride += 2; } else { stride += 3; } - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { stride += 1; } - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { stride += 1; } } uint offset = stride * gl_InstanceIndex; - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) { matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); offset += 2; } else { @@ -261,14 +271,14 @@ void main() { offset += 3; } - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_COLOR)) { #ifdef COLOR_USED color_interp *= transforms.data[offset]; #endif offset += 1; } - if (bool(draw_call.flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA)) { instance_custom = transforms.data[offset]; } @@ -287,16 +297,31 @@ void main() { model_normal_matrix = model_normal_matrix * mat3(matrix); } - vec3 vertex = vertex_attrib; + vec3 vertex = vertex_angle_attrib.xyz * instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz; #ifdef NORMAL_USED - vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0); + vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0); #endif -#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0; - vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); - float binormalf = sign(signed_tangent_attrib.y); - vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + vec3 binormal; + float binormal_sign; + vec3 tangent; + if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0; + tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + binormal = normalize(cross(normal, tangent) * binormal_sign); + } else { + // Compressed format. + float angle = vertex_angle_attrib.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = normal; + axis_angle_to_tbn(axis, angle, tangent, binormal, normal); + binormal *= binormal_sign; + } #endif #ifdef UV_USED @@ -307,6 +332,17 @@ void main() { uv2_interp = uv2_attrib; #endif + vec4 uv_scale = instances.data[draw_call.instance_index].uv_scale; + + if (uv_scale != vec4(0.0)) { // Compression enabled +#ifdef UV_USED + uv_interp = (uv_interp - 0.5) * uv_scale.xy; +#endif +#if defined(UV2_USED) || defined(USE_LIGHTMAP) + uv2_interp = (uv2_interp - 0.5) * uv_scale.zw; +#endif + } + #ifdef OVERRIDE_POSITION vec4 position; #endif @@ -441,8 +477,7 @@ void main() { #endif // MODE_RENDER_DEPTH #ifdef MODE_RENDER_MATERIAL if (scene_data.material_uv2_mode) { - vec2 uv_offset = draw_call.lightmap_uv_scale.xy; // we are abusing lightmap_uv_scale here, we shouldn't have a lightmap during a depth pass... - gl_Position.xy = (uv2_attrib.xy + uv_offset) * 2.0 - 1.0; + gl_Position.xy = (uv2_attrib.xy + draw_call.uv_offset) * 2.0 - 1.0; gl_Position.z = 0.00001; gl_Position.w = 1.0; } @@ -765,7 +800,7 @@ void main() { #endif // ALPHA_ANTIALIASING_EDGE_USED mat4 inv_view_matrix = scene_data.inv_view_matrix; - mat4 read_model_matrix = draw_call.transform; + mat4 read_model_matrix = instances.data[draw_call.instance_index].transform; #ifdef USE_DOUBLE_PRECISION read_model_matrix[0][3] = 0.0; read_model_matrix[1][3] = 0.0; @@ -890,11 +925,11 @@ void main() { if (!sc_disable_decals) { //Decals // must implement - uint decal_indices = draw_call.decals.x; + uint decal_indices = instances.data[draw_call.instance_index].decals.x; for (uint i = 0; i < 8; i++) { uint decal_index = decal_indices & 0xFF; if (i == 3) { - decal_indices = draw_call.decals.y; + decal_indices = instances.data[draw_call.instance_index].decals.y; } else { decal_indices = decal_indices >> 8; } @@ -903,7 +938,7 @@ void main() { break; } - if (!bool(decals.data[decal_index].mask & draw_call.layer_mask)) { + if (!bool(decals.data[decal_index].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked } @@ -1097,8 +1132,8 @@ void main() { #ifdef USE_LIGHTMAP //lightmap - if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture - uint index = draw_call.gi_offset; + if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE)) { //has lightmap capture + uint index = instances.data[draw_call.instance_index].gi_offset; vec3 wnormal = mat3(scene_data.inv_view_matrix) * normal; const float c1 = 0.429043; @@ -1118,12 +1153,12 @@ void main() { 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z) * scene_data.emissive_exposure_normalization; - } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap - bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); - uint ofs = draw_call.gi_offset & 0xFFFF; - uint slice = draw_call.gi_offset >> 16; + } else if (bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap + bool uses_sh = bool(instances.data[draw_call.instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); + uint ofs = instances.data[draw_call.instance_index].gi_offset & 0xFFFF; + uint slice = instances.data[draw_call.instance_index].gi_offset >> 16; vec3 uvw; - uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy; + uvw.xy = uv2 * instances.data[draw_call.instance_index].lightmap_uv_scale.zw + instances.data[draw_call.instance_index].lightmap_uv_scale.xy; uvw.z = float(slice); if (uses_sh) { @@ -1162,7 +1197,7 @@ void main() { vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - uint reflection_indices = draw_call.reflection_probes.x; + uint reflection_indices = instances.data[draw_call.instance_index].reflection_probes.x; #ifdef LIGHT_ANISOTROPY_USED // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy @@ -1179,7 +1214,7 @@ void main() { for (uint i = 0; i < 8; i++) { uint reflection_index = reflection_indices & 0xFF; if (i == 3) { - reflection_indices = draw_call.reflection_probes.y; + reflection_indices = instances.data[draw_call.instance_index].reflection_probes.y; } else { reflection_indices = reflection_indices >> 8; } @@ -1260,7 +1295,7 @@ void main() { break; } - if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { + if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked } @@ -1532,7 +1567,7 @@ void main() { break; } - if (!bool(directional_lights.data[i].mask & draw_call.layer_mask)) { + if (!bool(directional_lights.data[i].mask & instances.data[draw_call.instance_index].layer_mask)) { continue; //not masked } @@ -1601,11 +1636,11 @@ void main() { } //directional light if (!sc_disable_omni_lights) { //omni lights - uint light_indices = draw_call.omni_lights.x; + uint light_indices = instances.data[draw_call.instance_index].omni_lights.x; for (uint i = 0; i < 8; i++) { uint light_index = light_indices & 0xFF; if (i == 3) { - light_indices = draw_call.omni_lights.y; + light_indices = instances.data[draw_call.instance_index].omni_lights.y; } else { light_indices = light_indices >> 8; } @@ -1646,11 +1681,11 @@ void main() { if (!sc_disable_spot_lights) { //spot lights - uint light_indices = draw_call.spot_lights.x; + uint light_indices = instances.data[draw_call.instance_index].spot_lights.x; for (uint i = 0; i < 8; i++) { uint light_index = light_indices & 0xFF; if (i == 3) { - light_indices = draw_call.spot_lights.y; + light_indices = instances.data[draw_call.instance_index].spot_lights.y; } else { light_indices = light_indices >> 8; } diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl index d0a315858d2..3de5e769704 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl @@ -15,20 +15,11 @@ #endif #define USING_MOBILE_RENDERER -/* don't exceed 128 bytes!! */ -/* put instance data into our push content, not a array */ -layout(push_constant, std430) uniform DrawCall { - highp mat4 transform; // 64 - 64 - uint flags; // 04 - 68 - uint instance_uniforms_ofs; //base offset in global buffer for instance variables // 04 - 72 - uint gi_offset; //GI information when using lightmapping (VCT or lightmap index) // 04 - 76 - uint layer_mask; // 04 - 80 - highp vec4 lightmap_uv_scale; // 16 - 96 doubles as uv_offset when needed - uvec2 reflection_probes; // 08 - 104 - uvec2 omni_lights; // 08 - 112 - uvec2 spot_lights; // 08 - 120 - uvec2 decals; // 08 - 128 +layout(push_constant, std430) uniform DrawCall { + vec2 uv_offset; + uint instance_index; + uint pad; } draw_call; @@ -123,6 +114,29 @@ layout(set = 1, binding = 0, std140) uniform SceneDataBlock { } scene_data_block; +struct InstanceData { + highp mat4 transform; // 64 - 64 + uint flags; // 04 - 68 + uint instance_uniforms_ofs; // Base offset in global buffer for instance variables. // 04 - 72 + uint gi_offset; // GI information when using lightmapping (VCT or lightmap index). // 04 - 76 + uint layer_mask; // 04 - 80 + highp vec4 lightmap_uv_scale; // 16 - 96 Doubles as uv_offset when needed. + + uvec2 reflection_probes; // 08 - 104 + uvec2 omni_lights; // 08 - 112 + uvec2 spot_lights; // 08 - 120 + uvec2 decals; // 08 - 128 + + vec4 compressed_aabb_position_pad; // 16 - 144 // Only .xyz is used. .w is padding. + vec4 compressed_aabb_size_pad; // 16 - 160 // Only .xyz is used. .w is padding. + vec4 uv_scale; // 16 - 176 +}; + +layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer { + InstanceData data[]; +} +instances; + #ifdef USE_RADIANCE_CUBEMAP_ARRAY layout(set = 1, binding = 2) uniform mediump textureCubeArray radiance_cubemap; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index aa90ad6876a..4fb577d6979 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -71,7 +71,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix; #ifdef USING_MOBILE_RENDERER - mat4 read_model_matrix = draw_call.transform; + mat4 read_model_matrix = instances.data[draw_call.instance_index].transform; #else mat4 read_model_matrix = instances.data[instance_index_interp].transform; #endif diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl index 59c161548c5..894dee1728f 100644 --- a/servers/rendering/renderer_rd/shaders/skeleton.glsl +++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl @@ -49,7 +49,7 @@ layout(push_constant, std430) uniform Params { uint blend_shape_count; bool normalized_blend_shapes; - uint pad0; + uint normal_tangent_stride; uint pad1; vec2 skeleton_transform_x; @@ -188,15 +188,15 @@ void main() { vertex = uintBitsToFloat(uvec3(src_vertices.data[src_offset + 0], src_vertices.data[src_offset + 1], src_vertices.data[src_offset + 2])); - src_offset += 3; + uint src_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride; if (params.has_normal) { - normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]); - src_offset++; + normal = decode_uint_oct_to_norm(src_vertices.data[src_normal]); + src_normal++; } if (params.has_tangent) { - tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]); + tangent = decode_uint_oct_to_tang(src_vertices.data[src_normal]); } if (params.has_blend_shape) { @@ -208,19 +208,19 @@ void main() { for (uint i = 0; i < params.blend_shape_count; i++) { float w = blend_shape_weights.data[i]; if (abs(w) > 0.0001) { - uint base_offset = (params.vertex_count * i + index) * params.vertex_stride; + uint base_offset = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + index * params.vertex_stride; blend_vertex += uintBitsToFloat(uvec3(src_blend_shapes.data[base_offset + 0], src_blend_shapes.data[base_offset + 1], src_blend_shapes.data[base_offset + 2])) * w; - base_offset += 3; + uint base_normal = params.vertex_count * i * (params.vertex_stride + params.normal_tangent_stride) + params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride; if (params.has_normal) { - blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w; - base_offset++; + blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_normal]) * w; + base_normal++; } if (params.has_tangent) { - blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w; + blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_normal]).rgb * w; } blend_total += w; @@ -291,15 +291,15 @@ void main() { dst_vertices.data[dst_offset + 1] = uvertex.y; dst_vertices.data[dst_offset + 2] = uvertex.z; - dst_offset += 3; + uint dst_normal = params.vertex_count * params.vertex_stride + index * params.normal_tangent_stride; if (params.has_normal) { - dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal); - dst_offset++; + dst_vertices.data[dst_normal] = encode_norm_to_uint_oct(normal); + dst_normal++; } if (params.has_tangent) { - dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent); + dst_vertices.data[dst_normal] = encode_tang_to_uint_oct(tangent); } #endif diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp index cb7eb3cd59c..14605b308ee 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: @@ -336,61 +345,98 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) } } +#endif + + 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 + + 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) + ")"); + +#else + + 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 Mesh::Surface *s = memnew(Mesh::Surface); - s->format = p_surface.format; - s->primitive = p_surface.primitive; + s->format = new_surface.format; + s->primitive = new_surface.primitive; - bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0); + bool use_as_storage = (new_surface.skin_data.size() || mesh->blend_shape_count > 0); - 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 (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 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 (p_surface.attribute_data.size()) { - s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data); + 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 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 attributes; Vector buffers; + Vector 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,10 +1202,22 @@ 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; - + 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 { + 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; + } + } if (mis) { buffer = mis->vertex_buffer[p_current_buffer]; } else { @@ -1152,15 +1225,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V } } 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; - } + 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 1e1db9c47d8..f03334baac3 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 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(p_surface); + return s->aabb; + } + + _FORCE_INLINE_ uint64_t mesh_surface_get_format(void *p_surface) { + Mesh::Surface *s = reinterpret_cast(p_surface); + return s->format; + } + + _FORCE_INLINE_ Vector4 mesh_surface_get_uv_scale(void *p_surface) { + Mesh::Surface *s = reinterpret_cast(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(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; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index cb6479847a0..c2fa232eac4 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -643,7 +643,7 @@ Error RenderingDevice::_reflect_spirv(const Vector &p_spir for (uint32_t j = 0; j < iv_count; j++) { if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input. - r_reflection_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location)); + r_reflection_data.vertex_input_mask |= (1ULL << uint32_t(input_vars[j]->location)); } } } diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index b4bca054e2c..b95640acc63 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -758,7 +758,7 @@ public: virtual RID shader_create_from_bytecode(const Vector &p_shader_binary, RID p_placeholder = RID()) = 0; virtual RID shader_create_placeholder() = 0; - virtual uint32_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0; + virtual uint64_t shader_get_vertex_input_attribute_mask(RID p_shader) = 0; /******************/ /**** UNIFORMS ****/ @@ -1371,7 +1371,7 @@ protected: struct SpirvReflectionData { BitField stages_mask; - uint32_t vertex_input_mask; + uint64_t vertex_input_mask; uint32_t fragment_output_mask; bool is_compute; uint32_t compute_local_size[3]; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 9a3b7b9f3c9..94ff59f7e1c 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -322,7 +322,40 @@ RID RenderingServer::get_white_texture() { return white_texture; } -Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector &r_vertex_array, Vector &r_attrib_array, Vector &r_skin_array, int p_vertex_array_len, Vector &r_index_array, int p_index_array_len, AABB &r_aabb, Vector &r_bone_aabb) { +void _get_axis_angle(const Vector3 &p_normal, const Vector4 &p_tangent, float &r_angle, Vector3 &r_axis) { + Vector3 tangent = Vector3(p_tangent.x, p_tangent.y, p_tangent.z); + float d = p_tangent.w; + Vector3 binormal = p_normal.cross(tangent); + + r_angle = Math::acos((tangent.x + binormal.y + p_normal.z - 1.0) / 2.0); + float denom = 2.0 * Math::sin(r_angle); + r_axis.x = (p_normal.y - binormal.z) / denom; + r_axis.y = (tangent.z - p_normal.x) / denom; + r_axis.z = (binormal.x - tangent.y) / denom; + r_axis.normalize(); + + if (d < 0.0) { + r_angle = CLAMP((1.0 - r_angle / Math_PI) * 0.5, 0.0, 0.49999); + } else { + r_angle = (r_angle / Math_PI) * 0.5 + 0.5; + } +} + +// The inputs to this function should match the outputs of _get_axis_angle. I.e. p_axis is a normalized vector +// and p_angle includes the binormal direction. +void _get_tbn_from_axis_angle(const Vector3 &p_axis, float p_angle, Vector3 &r_normal, Vector4 &r_tangent) { + float binormal_sign = p_angle > 0.5 ? 1.0 : -1.0; + float angle = Math::abs(p_angle * 2.0 - 1.0) * Math_PI; + float c = cos(angle); + float s = sin(angle); + Vector3 omc_axis = (1.0 - c) * p_axis; + Vector3 s_axis = s * p_axis; + Vector3 tan = omc_axis.x * p_axis + Vector3(c, -s_axis.z, s_axis.y); + r_tangent = Vector4(tan.x, tan.y, tan.z, binormal_sign); + r_normal = omc_axis.z * p_axis + Vector3(-s_axis.y, s_axis.x, c); +} + +Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector &r_vertex_array, Vector &r_attrib_array, Vector &r_skin_array, int p_vertex_array_len, Vector &r_index_array, int p_index_array_len, AABB &r_aabb, Vector &r_bone_aabb, Vector4 &r_uv_scale) { uint8_t *vw = r_vertex_array.ptrw(); uint8_t *aw = r_attrib_array.ptrw(); uint8_t *sw = r_skin_array.ptrw(); @@ -334,8 +367,44 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint int max_bone = 0; + // Preprocess UVs if compression is enabled + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((p_format & RS::ARRAY_FORMAT_TEX_UV) || (p_format & RS::ARRAY_FORMAT_TEX_UV2))) { + const Vector2 *uv_src = nullptr; + if (p_format & RS::ARRAY_FORMAT_TEX_UV) { + Vector array = p_arrays[RS::ARRAY_TEX_UV]; + uv_src = array.ptr(); + } + + const Vector2 *uv2_src = nullptr; + if (p_format & RS::ARRAY_FORMAT_TEX_UV2) { + Vector array = p_arrays[RS::ARRAY_TEX_UV2]; + uv2_src = array.ptr(); + } + + Vector2 max_val = Vector2(0.0, 0.0); + Vector2 min_val = Vector2(0.0, 0.0); + Vector2 max_val2 = Vector2(0.0, 0.0); + Vector2 min_val2 = Vector2(0.0, 0.0); + + for (int i = 0; i < p_vertex_array_len; i++) { + if (p_format & RS::ARRAY_FORMAT_TEX_UV) { + max_val = max_val.max(uv_src[i]); + min_val = min_val.min(uv_src[i]); + } + if (p_format & RS::ARRAY_FORMAT_TEX_UV2) { + max_val2 = max_val2.max(uv2_src[i]); + min_val2 = min_val2.min(uv2_src[i]); + } + } + + max_val = max_val.abs().max(min_val.abs()); + max_val2 = max_val2.abs().max(min_val2.abs()); + + r_uv_scale = Vector4(max_val.x, max_val.y, max_val2.x, max_val2.y) * Vector4(2.0, 2.0, 2.0, 2.0); + } + for (int ai = 0; ai < RS::ARRAY_MAX; ai++) { - if (!(p_format & (1 << ai))) { // No array + if (!(p_format & (1ULL << ai))) { // No array continue; } @@ -375,7 +444,118 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint // Setting vertices means regenerating the AABB. AABB aabb; - { + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + // First we need to generate the AABB for the entire surface. + for (int i = 0; i < p_vertex_array_len; i++) { + if (i == 0) { + aabb = AABB(src[i], SMALL_VEC3); + } else { + aabb.expand_to(src[i]); + } + } + + bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); + + if (!using_normals_tangents) { + // Early out if we are only setting vertex positions. + for (int i = 0; i < p_vertex_array_len; i++) { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)0 + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + continue; + } + + // Validate normal and tangent arrays. + ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); + Variant::Type tangent_type = p_arrays[RS::ARRAY_TANGENT].get_type(); + ERR_FAIL_COND_V(tangent_type != Variant::PACKED_FLOAT32_ARRAY && tangent_type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + + Vector normal_array = p_arrays[RS::ARRAY_NORMAL]; + ERR_FAIL_COND_V(normal_array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); + const Vector3 *normal_src = normal_array.ptr(); + + // We need a different version if using double precision tangents. + if (tangent_type == Variant::PACKED_FLOAT32_ARRAY) { + Vector tangent_array = p_arrays[RS::ARRAY_TANGENT]; + ERR_FAIL_COND_V(tangent_array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const float *tangent_src = tangent_array.ptr(); + + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle = 0.0; + Vector3 axis; + Vector4 tangent = Vector4(tangent_src[i * 4 + 0], tangent_src[i * 4 + 1], tangent_src[i * 4 + 2], tangent_src[i * 4 + 3]); + _get_axis_angle(normal_src[i], tangent, angle, axis); + + // Store axis. + { + Vector2 res = axis.octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[RS::ARRAY_NORMAL] + i * p_normal_stride], vector, 4); + } + + // Store vertex position + angle. + { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)CLAMP(angle * 65535, 0, 65535) + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + } + } else { // PACKED_FLOAT64_ARRAY + Vector tangent_array = p_arrays[RS::ARRAY_TANGENT]; + ERR_FAIL_COND_V(tangent_array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const double *tangent_src = tangent_array.ptr(); + + // Set data for vertex, normal, and tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + float angle; + Vector3 axis; + Vector4 tangent = Vector4(tangent_src[i * 4 + 0], tangent_src[i * 4 + 1], tangent_src[i * 4 + 2], tangent_src[i * 4 + 3]); + _get_axis_angle(normal_src[i], tangent, angle, axis); + + // Store axis. + { + Vector2 res = axis.octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + memcpy(&vw[p_offsets[RS::ARRAY_NORMAL] + i * p_normal_stride], vector, 4); + } + + // Store vertex position + angle. + { + Vector3 pos = (src[i] - aabb.position) / aabb.size; + uint16_t vector[4] = { + (uint16_t)CLAMP(pos.x * 65535, 0, 65535), + (uint16_t)CLAMP(pos.y * 65535, 0, 65535), + (uint16_t)CLAMP(pos.z * 65535, 0, 65535), + (uint16_t)CLAMP(angle * 65535, 0, 65535) + }; + + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, sizeof(uint16_t) * 4); + } + } + } + } else { for (int i = 0; i < p_vertex_array_len; i++) { float vector[3] = { (float)src[i].x, (float)src[i].y, (float)src[i].z }; @@ -394,55 +574,61 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint } break; case RS::ARRAY_NORMAL: { - ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); + // If using compression we store normal while storing vertices. + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_VECTOR3_ARRAY, ERR_INVALID_PARAMETER); - Vector array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); + Vector array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); - const Vector3 *src = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - Vector2 res = src[i].octahedron_encode(); - uint16_t vector[2] = { - (uint16_t)CLAMP(res.x * 65535, 0, 65535), - (uint16_t)CLAMP(res.y * 65535, 0, 65535), - }; + const Vector3 *src = array.ptr(); + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 res = src[i].octahedron_encode(); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } } } break; case RS::ARRAY_TANGENT: { - Variant::Type type = p_arrays[ai].get_type(); - ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); - if (type == Variant::PACKED_FLOAT32_ARRAY) { - Vector array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const float *src_ptr = array.ptr(); + // If using compression we store tangent while storing vertices. + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Variant::Type type = p_arrays[ai].get_type(); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + if (type == Variant::PACKED_FLOAT32_ARRAY) { + Vector array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const float *src_ptr = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); - Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); - uint16_t vector[2] = { - (uint16_t)CLAMP(res.x * 65535, 0, 65535), - (uint16_t)CLAMP(res.y * 65535, 0, 65535), - }; + for (int i = 0; i < p_vertex_array_len; i++) { + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); - } - } else { // PACKED_FLOAT64_ARRAY - Vector array = p_arrays[ai]; - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - const double *src_ptr = array.ptr(); + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else { // PACKED_FLOAT64_ARRAY + Vector array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const double *src_ptr = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); - Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); - uint16_t vector[2] = { - (uint16_t)CLAMP(res.x * 65535, 0, 65535), - (uint16_t)CLAMP(res.y * 65535, 0, 65535), - }; + for (int i = 0; i < p_vertex_array_len; i++) { + const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]); + Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4); + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } } } } break; @@ -472,13 +658,20 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Vector2 *src = array.ptr(); - - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { (float)src[i].x, (float)src[i].y }; - - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 vec = src[i]; + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.x, r_uv_scale.y)) + Vector2(0.5, 0.5); + uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); + } + } else { + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { (float)src[i].x, (float)src[i].y }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + } } - } break; case RS::ARRAY_TEX_UV2: { @@ -490,9 +683,19 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint const Vector2 *src = array.ptr(); - for (int i = 0; i < p_vertex_array_len; i++) { - float uv[2] = { (float)src[i].x, (float)src[i].y }; - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + if (p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int i = 0; i < p_vertex_array_len; i++) { + Vector2 vec = src[i]; + // Normalize into 0-1 from possible range -uv_scale - uv_scale. + vec = vec / (Vector2(r_uv_scale.z, r_uv_scale.w)) + Vector2(0.5, 0.5); + uint16_t uv[2] = { (uint16_t)CLAMP(vec.x * 65535, 0, 65535), (uint16_t)CLAMP(vec.y * 65535, 0, 65535) }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 4); + } + } else { + for (int i = 0; i < p_vertex_array_len; i++) { + float uv[2] = { (float)src[i].x, (float)src[i].y }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4); + } } } break; case RS::ARRAY_CUSTOM0: @@ -707,9 +910,10 @@ uint32_t RenderingServer::mesh_surface_get_format_offset(BitField p p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return offsets[p_array_index]; } @@ -717,32 +921,48 @@ uint32_t RenderingServer::mesh_surface_get_format_vertex_stride(BitField p_format, int p_vertex_len) const { + p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; + uint32_t offsets[ARRAY_MAX]; + uint32_t vstr; + uint32_t ntstr; + uint32_t astr; + uint32_t sstr; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); + return vstr; +} + uint32_t RenderingServer::mesh_surface_get_format_attribute_stride(BitField p_format, int p_vertex_len) const { p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return astr; } uint32_t RenderingServer::mesh_surface_get_format_skin_stride(BitField p_format, int p_vertex_len) const { p_format = int64_t(p_format) & ~ARRAY_FORMAT_INDEX; uint32_t offsets[ARRAY_MAX]; uint32_t vstr; + uint32_t ntstr; uint32_t astr; uint32_t sstr; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, astr, sstr); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, 0, offsets, vstr, ntstr, astr, sstr); return sstr; } -void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { +void RenderingServer::mesh_surface_make_offsets_from_format(uint64_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_normal_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const { r_vertex_element_size = 0; + r_normal_element_size = 0; r_attrib_element_size = 0; r_skin_element_size = 0; @@ -753,13 +973,15 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (i == RS::ARRAY_VERTEX) { size_accum = &r_vertex_element_size; + } else if (i == RS::ARRAY_NORMAL) { + size_accum = &r_normal_element_size; } else if (i == RS::ARRAY_COLOR) { size_accum = &r_attrib_element_size; } else if (i == RS::ARRAY_BONES) { size_accum = &r_skin_element_size; } - if (!(p_format & (1 << i))) { // No array + if (!(p_format & (1ULL << i))) { // No array continue; } @@ -770,7 +992,7 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { elem_size = 2; } else { - elem_size = 3; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 2 : 3; } elem_size *= sizeof(float); @@ -779,22 +1001,22 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i elem_size = 4; } break; case RS::ARRAY_TANGENT: { - elem_size = 4; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 0 : 4; } break; case RS::ARRAY_COLOR: { elem_size = 4; } break; case RS::ARRAY_TEX_UV: { - elem_size = 8; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 4 : 8; } break; case RS::ARRAY_TEX_UV2: { - elem_size = 8; + elem_size = (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) ? 4 : 8; } break; case RS::ARRAY_CUSTOM0: case RS::ARRAY_CUSTOM1: case RS::ARRAY_CUSTOM2: case RS::ARRAY_CUSTOM3: { - uint32_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; + uint64_t format = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + (ARRAY_FORMAT_CUSTOM_BITS * (i - ARRAY_CUSTOM0)))) & ARRAY_FORMAT_CUSTOM_MASK; switch (format) { case ARRAY_CUSTOM_RGBA8_UNORM: { elem_size = 4; @@ -852,6 +1074,9 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i if (size_accum != nullptr) { r_offsets[i] = (*size_accum); + if (i == RS::ARRAY_NORMAL || i == RS::ARRAY_TANGENT) { + r_offsets[i] += r_vertex_element_size * p_vertex_len; + } (*size_accum) += elem_size; } else { r_offsets[i] = 0; @@ -859,11 +1084,11 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i } } -Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_compress_format) { +Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint64_t p_compress_format) { ERR_FAIL_INDEX_V(p_primitive, RS::PRIMITIVE_MAX, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_arrays.size() != RS::ARRAY_MAX, ERR_INVALID_PARAMETER); - uint32_t format = 0; + uint64_t format = 0; // Validation int index_array_len = 0; @@ -874,7 +1099,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa continue; } - format |= (1 << i); + format |= (1ULL << i); if (i == RS::ARRAY_VERTEX) { switch (p_arrays[i].get_type()) { @@ -930,7 +1155,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa for (uint32_t i = 0; i < RS::ARRAY_CUSTOM_COUNT; ++i) { // Include custom array format type. - if (format & (1 << (ARRAY_CUSTOM0 + i))) { + if (format & (1ULL << (ARRAY_CUSTOM0 + i))) { format |= (RS::ARRAY_FORMAT_CUSTOM_MASK << (RS::ARRAY_FORMAT_CUSTOM_BASE + i * RS::ARRAY_FORMAT_CUSTOM_BITS)) & p_compress_format; } } @@ -938,21 +1163,33 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa uint32_t offsets[RS::ARRAY_MAX]; uint32_t vertex_element_size; + uint32_t normal_element_size; uint32_t attrib_element_size; uint32_t skin_element_size; - mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, attrib_element_size, skin_element_size); - - uint32_t mask = (1 << ARRAY_MAX) - 1; + uint64_t mask = (1ULL << ARRAY_MAX) - 1ULL; format |= (~mask) & p_compress_format; // Make the full format. + // Force version to the current version as this function will always return a surface with the current version. + format &= ~(ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + format |= ARRAY_FLAG_FORMAT_CURRENT_VERSION & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + + mesh_surface_make_offsets_from_format(format, array_len, index_array_len, offsets, vertex_element_size, normal_element_size, attrib_element_size, skin_element_size); + if ((format & RS::ARRAY_FORMAT_VERTEX) == 0 && !(format & RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) { ERR_PRINT("Mesh created without vertex array. This mesh will not be visible with the default shader. If using an empty vertex array is intentional, create the mesh with the ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY flag to silence this error."); // Set the flag here after warning to suppress errors down the pipeline. format |= RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY; } - int vertex_array_size = vertex_element_size * array_len; + if (format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES && ((format & RS::ARRAY_FORMAT_NORMAL) || (format & RS::ARRAY_FORMAT_TANGENT))) { + // If using normals or tangents, then we need all three. + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_VERTEX), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals or tangents without vertex array."); + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_NORMAL), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using tangents without normal array."); + ERR_FAIL_COND_V_MSG(!(format & RS::ARRAY_FORMAT_TANGENT), ERR_INVALID_PARAMETER, "Can't use compression flag 'ARRAY_FLAG_COMPRESS_ATTRIBUTES' while using normals without tangent array."); + } + + int vertex_array_size = (vertex_element_size + normal_element_size) * array_len; int attrib_array_size = attrib_element_size * array_len; int skin_array_size = skin_element_size * array_len; int index_array_size = offsets[RS::ARRAY_INDEX] * index_array_len; @@ -972,7 +1209,9 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa AABB aabb; Vector bone_aabb; - Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb); + Vector4 uv_scale = Vector4(0.0, 0.0, 0.0, 0.0); + + Error err = _surface_set_data(p_arrays, format, offsets, vertex_element_size, normal_element_size, attrib_element_size, skin_element_size, vertex_array, attrib_array, skin_array, array_len, index_array, index_array_len, aabb, bone_aabb, uv_scale); ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Invalid array format for surface."); Vector blend_shape_data; @@ -987,7 +1226,8 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa Vector noskin; AABB laabb; - Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb); + Vector4 bone_uv_scale; // Not used. + Error err2 = _surface_set_data(p_blend_shapes[i], bs_format, offsets, vertex_element_size, normal_element_size, 0, 0, vertex_array_shape, noattrib, noskin, array_len, noindex, 0, laabb, bone_aabb, bone_uv_scale); aabb.merge_with(laabb); ERR_FAIL_COND_V_MSG(err2 != OK, ERR_INVALID_DATA, "Invalid blend shape array format for surface."); @@ -1048,6 +1288,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa surface_data.blend_shape_data = blend_shape_data; surface_data.bone_aabbs = bone_aabb; surface_data.lods = lods; + surface_data.uv_scale = uv_scale; return OK; } @@ -1061,13 +1302,14 @@ void RenderingServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_p mesh_add_surface(p_mesh, sd); } -Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector p_vertex_data, Vector p_attrib_data, Vector p_skin_data, int p_vertex_len, Vector p_index_data, int p_index_len) const { +Array RenderingServer::_get_array_from_surface(uint64_t p_format, Vector p_vertex_data, Vector p_attrib_data, Vector p_skin_data, int p_vertex_len, Vector p_index_data, int p_index_len, const AABB &p_aabb) const { uint32_t offsets[RS::ARRAY_MAX]; uint32_t vertex_elem_size; + uint32_t normal_elem_size; uint32_t attrib_elem_size; uint32_t skin_elem_size; - mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets, vertex_elem_size, normal_elem_size, attrib_elem_size, skin_elem_size); Array ret; ret.resize(RS::ARRAY_MAX); @@ -1077,7 +1319,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector(&r[j * vertex_elem_size + offsets[i]]); - w[j] = Vector3(v[0], v[1], v[2]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + bool using_normals_tangents = (p_format & RS::ARRAY_FORMAT_NORMAL) && (p_format & RS::ARRAY_FORMAT_TANGENT); + + // We only have vertices to read, so just read them and skip everything else. + if (!using_normals_tangents) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast(&r[j * vertex_elem_size + offsets[i]]); + Vector3 vec = Vector3(float(v[0]) / 65535.0, float(v[1]) / 65535.0, float(v[2]) / 65535.0); + w[j] = (vec * p_aabb.size) + p_aabb.position; + } + continue; + } + + Vector normals; + normals.resize(p_vertex_len); + Vector3 *normalsw = normals.ptrw(); + + Vector tangents; + tangents.resize(p_vertex_len * 4); + float *tangentsw = tangents.ptrw(); + + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t n = *(const uint32_t *)&r[j * normal_elem_size + offsets[RS::ARRAY_NORMAL]]; + Vector3 axis = Vector3::octahedron_decode(Vector2((n & 0xFFFF) / 65535.0, ((n >> 16) & 0xFFFF) / 65535.0)); + + const uint16_t *v = reinterpret_cast(&r[j * vertex_elem_size + offsets[i]]); + Vector3 vec = Vector3(float(v[0]) / 65535.0, float(v[1]) / 65535.0, float(v[2]) / 65535.0); + float angle = float(v[3]) / 65535.0; + w[j] = (vec * p_aabb.size) + p_aabb.position; + + Vector3 normal; + Vector4 tan; + _get_tbn_from_axis_angle(axis, angle, normal, tan); + + normalsw[j] = normal; + tangentsw[j * 4 + 0] = tan.x; + tangentsw[j * 4 + 1] = tan.y; + tangentsw[j * 4 + 2] = tan.z; + tangentsw[j * 4 + 3] = tan.w; + } + ret[RS::ARRAY_NORMAL] = normals; + ret[RS::ARRAY_FORMAT_TANGENT] = tangents; + + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast(&r[j * vertex_elem_size + offsets[i]]); + w[j] = Vector3(v[0], v[1], v[2]); + } } } @@ -1115,39 +1402,41 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector arr; - arr.resize(p_vertex_len); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector arr; + arr.resize(p_vertex_len); - Vector3 *w = arr.ptrw(); + Vector3 *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * normal_elem_size + offsets[i]]; - w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0)); + w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0)); + } + + ret[i] = arr; } - - ret[i] = arr; - } break; case RS::ARRAY_TANGENT: { - Vector arr; - arr.resize(p_vertex_len * 4); + if (!(p_format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES)) { + Vector arr; + arr.resize(p_vertex_len * 4); - float *w = arr.ptrw(); + float *w = arr.ptrw(); - for (int j = 0; j < p_vertex_len; j++) { - const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]]; - float tangent_sign; - Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign); - w[j * 4 + 0] = res.x; - w[j * 4 + 1] = res.y; - w[j * 4 + 2] = res.z; - w[j * 4 + 3] = tangent_sign; + for (int j = 0; j < p_vertex_len; j++) { + const uint32_t v = *(const uint32_t *)&r[j * normal_elem_size + offsets[i]]; + float tangent_sign; + Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign); + w[j * 4 + 0] = res.x; + w[j * 4 + 1] = res.y; + w[j * 4 + 2] = res.z; + w[j * 4 + 3] = tangent_sign; + } + + ret[i] = arr; } - - ret[i] = arr; - } break; case RS::ARRAY_COLOR: { Vector arr; @@ -1168,12 +1457,17 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(v[0], v[1]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + } + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(v[0], v[1]); + } } - ret[i] = arr; } break; @@ -1183,9 +1477,16 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector(&ar[j * attrib_elem_size + offsets[i]]); - w[j] = Vector2(v[0], v[1]); + if (p_format & ARRAY_FLAG_COMPRESS_ATTRIBUTES) { + for (int j = 0; j < p_vertex_len; j++) { + const uint16_t *v = reinterpret_cast(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(float(v[0]) / 65535.0, float(v[1]) / 65535.0); + } + } else { + for (int j = 0; j < p_vertex_len; j++) { + const float *v = reinterpret_cast(&ar[j * attrib_elem_size + offsets[i]]); + w[j] = Vector2(v[0], v[1]); + } } ret[i] = arr; @@ -1358,12 +1659,13 @@ TypedArray RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes uint32_t bs_offsets[RS::ARRAY_MAX]; uint32_t bs_format = (sd.format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK); uint32_t vertex_elem_size; + uint32_t normal_elem_size; uint32_t attrib_elem_size; uint32_t skin_elem_size; + //CLAY + mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, normal_elem_size, attrib_elem_size, skin_elem_size); - mesh_surface_make_offsets_from_format(bs_format, sd.vertex_count, 0, bs_offsets, vertex_elem_size, attrib_elem_size, skin_elem_size); - - int divisor = vertex_elem_size * sd.vertex_count; + int divisor = (vertex_elem_size + normal_elem_size) * sd.vertex_count; ERR_FAIL_COND_V((blend_shape_data.size() % divisor) != 0, Array()); uint32_t blend_shape_count = blend_shape_data.size() / divisor; @@ -1375,7 +1677,7 @@ TypedArray RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mes for (uint32_t i = 0; i < blend_shape_count; i++) { Vector bs_data = blend_shape_data.slice(i * divisor, (i + 1) * divisor); Vector unused; - blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0)); + blend_shape_array.set(i, _get_array_from_surface(bs_format, bs_data, unused, unused, sd.vertex_count, unused, 0, sd.aabb)); } return blend_shape_array; @@ -1395,9 +1697,9 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p Vector index_data = p_data.index_data; int index_len = p_data.index_count; - uint32_t format = p_data.format; + uint64_t format = p_data.format; - return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len); + return _get_array_from_surface(format, vertex_data, attrib_data, skin_data, vertex_len, index_data, index_len, p_data.aabb); } #if 0 Array RenderingServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surface) const { @@ -1531,7 +1833,9 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { RS::SurfaceData sd; sd.primitive = RS::PrimitiveType(int(p_dictionary["primitive"])); - sd.format = p_dictionary["format"]; + if (p_dictionary.has("uv_scale")) { + sd.format = p_dictionary["format"]; + } sd.vertex_data = p_dictionary["vertex_data"]; if (p_dictionary.has("attribute_data")) { sd.attribute_data = p_dictionary["attribute_data"]; @@ -1549,6 +1853,7 @@ static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { } sd.aabb = p_dictionary["aabb"]; + sd.uv_scale = p_dictionary["uv_scale"]; if (p_dictionary.has("lods")) { Array lods = p_dictionary["lods"]; @@ -1610,6 +1915,7 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) { d["index_count"] = sd.index_count; } d["aabb"] = sd.aabb; + d["uv_scale"] = sd.uv_scale; if (sd.lods.size()) { Array lods; @@ -1663,6 +1969,117 @@ void RenderingServer::_particles_set_trail_bind_poses(RID p_particles, const Typ particles_set_trail_bind_poses(p_particles, tbposes); } +Vector _convert_surface_version_1_to_surface_version_2(uint64_t p_format, Vector p_vertex_data, uint32_t p_vertex_count, uint32_t p_old_stride, uint32_t p_vertex_size, uint32_t p_normal_size, uint32_t p_position_stride, uint32_t p_normal_tangent_stride) { + Vector new_vertex_data; + new_vertex_data.resize(p_vertex_data.size()); + uint8_t *dst_vertex_ptr = new_vertex_data.ptrw(); + + const uint8_t *src_vertex_ptr = p_vertex_data.ptr(); + + uint32_t position_size = p_position_stride * p_vertex_count; + + for (uint32_t j = 0; j < RS::ARRAY_COLOR; j++) { + if (!(p_format & (1ULL << j))) { + continue; + } + switch (j) { + case RS::ARRAY_VERTEX: { + if (p_format & RS::ARRAY_FLAG_USE_2D_VERTICES) { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const float *src = (const float *)&src_vertex_ptr[i * p_old_stride]; + float *dst = (float *)&dst_vertex_ptr[i * p_position_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + } + } else { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const float *src = (const float *)&src_vertex_ptr[i * p_old_stride]; + float *dst = (float *)&dst_vertex_ptr[i * p_position_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + } + } break; + case RS::ARRAY_NORMAL: { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * p_old_stride + p_vertex_size]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * p_normal_tangent_stride + position_size]; + + dst[0] = src[0]; + dst[1] = src[1]; + } + } break; + case RS::ARRAY_TANGENT: { + for (uint32_t i = 0; i < p_vertex_count; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * p_old_stride + p_vertex_size + p_normal_size]; + uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * p_normal_tangent_stride + position_size + p_normal_size]; + + dst[0] = src[0]; + dst[1] = src[1]; + } + } break; + } + } + return new_vertex_data; +} + +#ifndef DISABLE_DEPRECATED +void RenderingServer::_fix_surface_compatibility(SurfaceData &p_surface) { + uint64_t surface_version = p_surface.format & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + ERR_FAIL_COND_MSG(surface_version > ARRAY_FLAG_FORMAT_CURRENT_VERSION, "Cannot convert surface with version provided (" + itos((surface_version >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ") to current version (" + itos((RS::ARRAY_FLAG_FORMAT_CURRENT_VERSION >> RS::ARRAY_FLAG_FORMAT_VERSION_SHIFT) & RS::ARRAY_FLAG_FORMAT_VERSION_MASK) + ")"); + + if (surface_version == ARRAY_FLAG_FORMAT_VERSION_1) { + // The only difference for now is that Version 1 uses interleaved vertex positions while version 2 does not. + // I.e. PNTPNTPNT -> PPPNTNTNT. + WARN_PRINT_ED("Upgrading mesh from older surface format. Once saved again (or re-imported), this mesh will be incompatible with earlier versions of Godot."); + + int vertex_size = 0; + int normal_size = 0; + int tangent_size = 0; + if (p_surface.format & ARRAY_FORMAT_VERTEX) { + if (p_surface.format & ARRAY_FLAG_USE_2D_VERTICES) { + vertex_size = sizeof(float) * 2; + } else { + vertex_size = sizeof(float) * 3; + } + } + if (p_surface.format & ARRAY_FORMAT_NORMAL) { + normal_size += sizeof(uint16_t) * 2; + } + if (p_surface.format & ARRAY_FORMAT_TANGENT) { + tangent_size = sizeof(uint16_t) * 2; + } + int stride = p_surface.vertex_data.size() / p_surface.vertex_count; + int position_stride = vertex_size; + int normal_tangent_stride = normal_size + tangent_size; + + p_surface.vertex_data = _convert_surface_version_1_to_surface_version_2(p_surface.format, p_surface.vertex_data, p_surface.vertex_count, stride, vertex_size, normal_size, position_stride, normal_tangent_stride); + + if (p_surface.blend_shape_data.size() > 0) { + // The size of one blend shape. + int divisor = (vertex_size + normal_size + tangent_size) * p_surface.vertex_count; + ERR_FAIL_COND((p_surface.blend_shape_data.size() % divisor) != 0); + + uint32_t blend_shape_count = p_surface.blend_shape_data.size() / divisor; + + Vector new_blend_shape_data; + for (uint32_t i = 0; i < blend_shape_count; i++) { + Vector bs_data = p_surface.blend_shape_data.slice(i * divisor, (i + 1) * divisor); + Vector blend_shape = _convert_surface_version_1_to_surface_version_2(p_surface.format, bs_data, p_surface.vertex_count, stride, vertex_size, normal_size, position_stride, normal_tangent_stride); + new_blend_shape_data.append_array(blend_shape); + } + + ERR_FAIL_COND(p_surface.blend_shape_data.size() != new_blend_shape_data.size()); + + p_surface.blend_shape_data = new_blend_shape_data; + } + } + p_surface.format &= ~(ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); + p_surface.format |= ARRAY_FLAG_FORMAT_CURRENT_VERSION & (ARRAY_FLAG_FORMAT_VERSION_MASK << ARRAY_FLAG_FORMAT_VERSION_SHIFT); +} +#endif + void RenderingServer::_bind_methods() { BIND_CONSTANT(NO_INDEX_ARRAY); BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); @@ -1753,6 +2170,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_normal_tangent_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_normal_tangent_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride); ClassDB::bind_method(D_METHOD("mesh_add_surface", "mesh", "surface"), &RenderingServer::_mesh_add_surface); @@ -1835,6 +2253,15 @@ void RenderingServer::_bind_methods() { BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS); BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY); + BIND_BITFIELD_FLAG(ARRAY_FLAG_COMPRESS_ATTRIBUTES); + + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_BASE); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_SHIFT); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_1); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_2); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_CURRENT_VERSION); + BIND_BITFIELD_FLAG(ARRAY_FLAG_FORMAT_VERSION_MASK); + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); BIND_ENUM_CONSTANT(PRIMITIVE_LINES); BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 6b2ba562ce9..9d186f086c5 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -52,7 +52,7 @@ class RenderingServer : public Object { int mm_policy = 0; bool render_loop_enabled = true; - Array _get_array_from_surface(uint32_t p_format, Vector p_vertex_data, Vector p_attrib_data, Vector p_skin_data, int p_vertex_len, Vector p_index_data, int p_index_len) const; + Array _get_array_from_surface(uint64_t p_format, Vector p_vertex_data, Vector p_attrib_data, Vector p_skin_data, int p_vertex_len, Vector p_index_data, int p_index_len, const AABB &p_aabb) const; const Vector2 SMALL_VEC2 = Vector2(CMP_EPSILON, CMP_EPSILON); const Vector3 SMALL_VEC3 = Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON); @@ -66,7 +66,7 @@ protected: RID white_texture; RID test_material; - Error _surface_set_data(Array p_arrays, uint32_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector &r_vertex_array, Vector &r_attrib_array, Vector &r_skin_array, int p_vertex_array_len, Vector &r_index_array, int p_index_array_len, AABB &r_aabb, Vector &r_bone_aabb); + Error _surface_set_data(Array p_arrays, uint64_t p_format, uint32_t *p_offsets, uint32_t p_vertex_stride, uint32_t p_normal_stride, uint32_t p_attrib_stride, uint32_t p_skin_stride, Vector &r_vertex_array, Vector &r_attrib_array, Vector &r_skin_array, int p_vertex_array_len, Vector &r_index_array, int p_index_array_len, AABB &r_aabb, Vector &r_bone_aabb, Vector4 &r_uv_scale); static RenderingServer *(*create_func)(); static void _bind_methods(); @@ -220,12 +220,12 @@ public: /* MESH API */ enum ArrayType { - ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) - ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored. - ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal. + ARRAY_VERTEX = 0, // RG32F (2D), RGB32F, RGBA16 (compressed) + ARRAY_NORMAL = 1, // RG16 + ARRAY_TANGENT = 2, // BA16 (with normal) or A16 (with vertex, when compressed) ARRAY_COLOR = 3, // RGBA8 - ARRAY_TEX_UV = 4, // RG32F - ARRAY_TEX_UV2 = 5, // RG32F + ARRAY_TEX_UV = 4, // RG32F or RG16 + ARRAY_TEX_UV2 = 5, // RG32F or RG16 ARRAY_CUSTOM0 = 6, // Depends on ArrayCustomFormat. ARRAY_CUSTOM1 = 7, ARRAY_CUSTOM2 = 8, @@ -252,7 +252,7 @@ public: ARRAY_CUSTOM_MAX }; - enum ArrayFormat { + enum ArrayFormat : uint64_t { /* ARRAY FORMAT FLAGS */ ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL, @@ -284,7 +284,18 @@ public: ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1), ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2), - ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = 1 << (ARRAY_INDEX + 1 + 15), + ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 3), + + ARRAY_FLAG_COMPRESS_ATTRIBUTES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 4), + // We leave enough room for up to 5 more compression flags. + + ARRAY_FLAG_FORMAT_VERSION_BASE = ARRAY_COMPRESS_FLAGS_BASE + 10, + ARRAY_FLAG_FORMAT_VERSION_SHIFT = ARRAY_FLAG_FORMAT_VERSION_BASE, + // When changes are made to the mesh format, add a new version and use it for the CURRENT_VERSION. + ARRAY_FLAG_FORMAT_VERSION_1 = 0, + ARRAY_FLAG_FORMAT_VERSION_2 = 1ULL << ARRAY_FLAG_FORMAT_VERSION_SHIFT, + ARRAY_FLAG_FORMAT_CURRENT_VERSION = ARRAY_FLAG_FORMAT_VERSION_2, + ARRAY_FLAG_FORMAT_VERSION_MASK = 0xFF, // 8 bits version }; enum PrimitiveType { @@ -299,7 +310,7 @@ public: struct SurfaceData { PrimitiveType primitive = PRIMITIVE_MAX; - uint32_t format = 0; + uint64_t format = ARRAY_FLAG_FORMAT_CURRENT_VERSION; Vector vertex_data; // Vertex, Normal, Tangent (change with skinning, blendshape). Vector attribute_data; // Color, UV, UV2, Custom0-3. Vector skin_data; // Bone index, Bone weight. @@ -317,6 +328,8 @@ public: Vector blend_shape_data; + Vector4 uv_scale; + RID material; }; @@ -327,12 +340,13 @@ public: virtual uint32_t mesh_surface_get_format_offset(BitField p_format, int p_vertex_len, int p_array_index) const; virtual uint32_t mesh_surface_get_format_vertex_stride(BitField p_format, int p_vertex_len) const; + virtual uint32_t mesh_surface_get_format_normal_tangent_stride(BitField p_format, int p_vertex_len) const; virtual uint32_t mesh_surface_get_format_attribute_stride(BitField p_format, int p_vertex_len) const; virtual uint32_t mesh_surface_get_format_skin_stride(BitField p_format, int p_vertex_len) const; /// Returns stride - virtual void mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const; - virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0); + virtual void mesh_surface_make_offsets_from_format(uint64_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets, uint32_t &r_vertex_element_size, uint32_t &r_normal_element_size, uint32_t &r_attrib_element_size, uint32_t &r_skin_element_size) const; + virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint64_t p_compress_format = 0); Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const; Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const; TypedArray mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const; @@ -1610,6 +1624,10 @@ public: RenderingServer(); virtual ~RenderingServer(); +#ifndef DISABLE_DEPRECATED + static void _fix_surface_compatibility(SurfaceData &p_surface); +#endif + private: // Binder helpers RID _texture_2d_layered_create(const TypedArray &p_layers, TextureLayeredType p_layered_type);