| … | … | @@ -1472,6 +1472,62 @@ static Ref<ProcGeometry> _to_godot_frame(const Ref<ProcGeometry> &p_geo, |
| 1472 | 1472 | for (int i = 0; i < mesh->normals.size(); i++) { |
| 1473 | 1473 | nor[i] = Vector3(-nor[i].x, nor[i].z, nor[i].y); |
| 1474 | 1474 | } |
| 1475 | |
| 1476 | // ⛔ AND THE WINDING. M = (-x, z, y) has determinant +1 -- it is a ROTATION, |
| 1477 | // so it does not flip anything by itself. What differs is the FRONT-FACE |
| 1478 | // convention: Blender's counter-clockwise is Godot's clockwise under the |
| 1479 | // Vulkan Y-flip, and blender-bridge has always reversed corner order when |
| 1480 | // building a Godot mesh from a Blender one for exactly that reason. |
| 1481 | // |
| 1482 | // It used to happen by accident on this path: the bridge reversed the cage's |
| 1483 | // winding while turning it into an ArrayMesh, proc-nodes inherited that, and |
| 1484 | // the result came out facing the right way. Now the cage arrives as Blender's |
| 1485 | // own mesh, in Blender's own order, so the conversion has to say it -- and |
| 1486 | // this is the function whose whole job is "a Blender-authored graph's result, |
| 1487 | // in Godot's terms". Without it the mountain renders inside out. |
| 1488 | // |
| 1489 | // Corner-domain attributes are permuted with the corners; they are indexed by |
| 1490 | // corner, so reversing one without the other silently shears them. |
| 1491 | PackedInt32Array &corners = mesh->indices; |
| 1492 | const int fc = mesh->face_count(); |
| 1493 | PackedInt32Array perm; |
| 1494 | perm.resize(corners.size()); |
| 1495 | int32_t *cw = corners.ptrw(); |
| 1496 | int32_t *pw = perm.ptrw(); |
| 1497 | for (int f = 0; f < fc; f++) { |
| 1498 | const int b = mesh->face_corner_begin(f); |
| 1499 | const int n = mesh->face_size(f); |
| 1500 | if (n < 2) { |
| 1501 | for (int k = 0; k < n; k++) { |
| 1502 | pw[b + k] = b + k; |
| 1503 | } |
| 1504 | continue; |
| 1505 | } |
| 1506 | // Keep the first corner where it is and reverse the rest, so the face |
| 1507 | // still starts at the same vertex and only its orientation changes. |
| 1508 | pw[b] = b; |
| 1509 | for (int k = 1; k < n; k++) { |
| 1510 | pw[b + k] = b + (n - k); |
| 1511 | } |
| 1512 | for (int k = 1; k < (n + 1) / 2; k++) { |
| 1513 | const int32_t tmp = cw[b + k]; |
| 1514 | cw[b + k] = cw[b + n - k]; |
| 1515 | cw[b + n - k] = tmp; |
| 1516 | } |
| 1517 | } |
| 1518 | for (const KeyValue<StringName, Ref<AttributeArray>> &kv : mesh->corner_attrs.attributes) { |
| 1519 | Ref<AttributeArray> a = kv.value; |
| 1520 | if (a.is_null() || a->size() != corners.size()) { |
| 1521 | continue; |
| 1522 | } |
| 1523 | const int esz = attr_type_size(a->type); |
| 1524 | PackedByteArray src = a->data; |
| 1525 | uint8_t *dst = a->data.ptrw(); |
| 1526 | const uint8_t *sp = src.ptr(); |
| 1527 | for (int c = 0; c < corners.size(); c++) { |
| 1528 | memcpy(dst + (int64_t)pw[c] * esz, sp + (int64_t)c * esz, esz); |
| 1529 | } |
| 1530 | } |
| 1475 | 1531 | return p_geo; |
| 1476 | 1532 | } |
| 1477 | 1533 | |