From 031f221b9d378a7952c72ce4596be8df0d2d0e89 Mon Sep 17 00:00:00 2001 From: clayjohn Date: Tue, 7 Nov 2023 14:24:23 +0100 Subject: [PATCH] Create tangent array if mesh created without tangents This extends our previous change to ensure that compressed meshes have tangents Now we ensure tangents are always used. This greatly simplifies our compression code at the cost of a small amount of bandwidth --- scene/resources/immediate_mesh.cpp | 13 +++++++--- servers/rendering_server.cpp | 39 ++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp index 3507df8bd88..dde556c264c 100644 --- a/scene/resources/immediate_mesh.cpp +++ b/scene/resources/immediate_mesh.cpp @@ -166,7 +166,7 @@ void ImmediateMesh::surface_end() { normal_tangent_stride += sizeof(uint32_t); } uint32_t tangent_offset = 0; - if (uses_tangents) { + if (uses_tangents || uses_normals) { format |= ARRAY_FORMAT_TANGENT; tangent_offset = vertex_stride * vertices.size() + normal_tangent_stride; normal_tangent_stride += sizeof(uint32_t); @@ -202,9 +202,16 @@ void ImmediateMesh::surface_end() { *normal = value; } - if (uses_tangents) { + if (uses_tangents || uses_normals) { 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); + Vector2 t; + if (uses_tangents) { + t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d); + } else { + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normals[i].normalized()); + t = tan.octahedron_tangent_encode(1.0); + } + uint32_t value = 0; value |= (uint16_t)CLAMP(t.x * 65535, 0, 65535); value |= (uint16_t)CLAMP(t.y * 65535, 0, 65535) << 16; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 620262f30e9..43615f0d7ea 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -635,7 +635,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint // 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); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY && type != Variant::NIL, 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); @@ -657,7 +658,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); } - } else { // PACKED_FLOAT64_ARRAY + } else if (type == Variant::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(); @@ -676,6 +677,30 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint64_t p_format, uint vector[0] = 65535; } + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); + } + } else { // No tangent array. + ERR_FAIL_COND_V(p_arrays[RS::ARRAY_NORMAL].get_type() != Variant::PACKED_VECTOR3_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(); + // Set data for tangent. + for (int i = 0; i < p_vertex_array_len; i++) { + // Generate an arbitrary vector that is tangential to normal. + Vector3 tan = Vector3(0.0, 1.0, 0.0).cross(normal_src[i].normalized()); + Vector2 res = tan.octahedron_tangent_encode(1.0); + uint16_t vector[2] = { + (uint16_t)CLAMP(res.x * 65535, 0, 65535), + (uint16_t)CLAMP(res.y * 65535, 0, 65535), + }; + + if (vector[0] == 0 && vector[1] == 65535) { + // (1, 1) and (0, 1) decode to the same value, but (0, 1) messes with our compression detection. + // So we sanitize here. + vector[0] = 65535; + } + memcpy(&vw[p_offsets[ai] + i * p_normal_stride], vector, 4); } } @@ -1172,6 +1197,11 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa } break; } ERR_FAIL_COND_V(array_len == 0, ERR_INVALID_DATA); + } else if (i == RS::ARRAY_NORMAL) { + if (p_arrays[RS::ARRAY_TANGENT].get_type() == Variant::NIL) { + // We must use tangents if using normals. + format |= (1ULL << RS::ARRAY_TANGENT); + } } else if (i == RS::ARRAY_BONES) { switch (p_arrays[i].get_type()) { case Variant::PACKED_INT32_ARRAY: { @@ -1242,11 +1272,6 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa 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."); } - if ((format & RS::ARRAY_FLAG_COMPRESS_ATTRIBUTES) && !(format & RS::ARRAY_FORMAT_TANGENT)) { - // If no tangent array provided, we will generate one. - format |= RS::ARRAY_FORMAT_TANGENT; - } - 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;