ソースを参照

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
clayjohn 1 年間 前
コミット
031f221b9d
2 ファイル変更42 行追加10 行削除
  1. 10 3
      scene/resources/immediate_mesh.cpp
  2. 32 7
      servers/rendering_server.cpp

+ 10 - 3
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;

+ 32 - 7
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<float> 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<double> 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<Vector3> 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;