You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-27 15:57:02 +00:00
Fix Polygon2D skinned bounds (for culling)
The bound Rect2 was previously incorrect because bone transforms need to be applied to verts in bone space, rather than local space. This was previously resulting in skinned Polygon2Ds being incorrectly culled.
This commit is contained in:
@@ -892,10 +892,24 @@ public:
|
||||
bool antialiased;
|
||||
bool antialiasing_use_indices;
|
||||
|
||||
struct SkinningData {
|
||||
bool dirty = true;
|
||||
LocalVector<Rect2> active_bounds;
|
||||
LocalVector<uint16_t> active_bone_ids;
|
||||
Rect2 untransformed_bound;
|
||||
};
|
||||
mutable SkinningData *skinning_data = nullptr;
|
||||
|
||||
CommandPolygon() {
|
||||
type = TYPE_POLYGON;
|
||||
count = 0;
|
||||
}
|
||||
virtual ~CommandPolygon() {
|
||||
if (skinning_data) {
|
||||
memdelete(skinning_data);
|
||||
skinning_data = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CommandMesh : public Command {
|
||||
@@ -968,6 +982,12 @@ public:
|
||||
|
||||
Item *next;
|
||||
|
||||
struct SkinningData {
|
||||
Transform2D skeleton_relative_xform;
|
||||
Transform2D skeleton_relative_xform_inv;
|
||||
};
|
||||
SkinningData *skinning_data = nullptr;
|
||||
|
||||
struct CopyBackBuffer {
|
||||
Rect2 rect;
|
||||
Rect2 screen_rect;
|
||||
@@ -984,6 +1004,11 @@ public:
|
||||
|
||||
Rect2 global_rect_cache;
|
||||
|
||||
private:
|
||||
Rect2 calculate_polygon_bounds(const Item::CommandPolygon &p_polygon) const;
|
||||
void precalculate_polygon_bone_bounds(const Item::CommandPolygon &p_polygon) const;
|
||||
|
||||
public:
|
||||
const Rect2 &get_rect() const {
|
||||
if (custom_rect) {
|
||||
return rect;
|
||||
@@ -1068,61 +1093,8 @@ public:
|
||||
} break;
|
||||
case Item::Command::TYPE_POLYGON: {
|
||||
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
|
||||
int l = polygon->points.size();
|
||||
const Point2 *pp = &polygon->points[0];
|
||||
r.position = pp[0];
|
||||
for (int j = 1; j < l; j++) {
|
||||
r.expand_to(pp[j]);
|
||||
}
|
||||
|
||||
if (skeleton != RID()) {
|
||||
// calculate bone AABBs
|
||||
int bone_count = RasterizerStorage::base_singleton->skeleton_get_bone_count(skeleton);
|
||||
|
||||
Vector<Rect2> bone_aabbs;
|
||||
bone_aabbs.resize(bone_count);
|
||||
Rect2 *bptr = bone_aabbs.ptrw();
|
||||
|
||||
for (int j = 0; j < bone_count; j++) {
|
||||
bptr[j].size = Vector2(-1, -1); //negative means unused
|
||||
}
|
||||
if (l && polygon->bones.size() == l * 4 && polygon->weights.size() == polygon->bones.size()) {
|
||||
for (int j = 0; j < l; j++) {
|
||||
Point2 p = pp[j];
|
||||
for (int k = 0; k < 4; k++) {
|
||||
int idx = polygon->bones[j * 4 + k];
|
||||
float w = polygon->weights[j * 4 + k];
|
||||
if (w == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bptr[idx].size.x < 0) {
|
||||
//first
|
||||
bptr[idx] = Rect2(p, Vector2(0.00001, 0.00001));
|
||||
} else {
|
||||
bptr[idx].expand_to(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rect2 aabb;
|
||||
bool first_bone = true;
|
||||
for (int j = 0; j < bone_count; j++) {
|
||||
Transform2D mtx = RasterizerStorage::base_singleton->skeleton_bone_get_transform_2d(skeleton, j);
|
||||
Rect2 baabb = mtx.xform(bone_aabbs[j]);
|
||||
|
||||
if (first_bone) {
|
||||
aabb = baabb;
|
||||
first_bone = false;
|
||||
} else {
|
||||
aabb = aabb.merge(baabb);
|
||||
}
|
||||
}
|
||||
|
||||
r = r.merge(aabb);
|
||||
}
|
||||
}
|
||||
|
||||
DEV_ASSERT(polygon);
|
||||
r = calculate_polygon_bounds(*polygon);
|
||||
} break;
|
||||
case Item::Command::TYPE_MESH: {
|
||||
const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
|
||||
@@ -1188,6 +1160,11 @@ public:
|
||||
final_clip_owner = nullptr;
|
||||
material_owner = nullptr;
|
||||
light_masked = false;
|
||||
|
||||
if (skinning_data) {
|
||||
memdelete(skinning_data);
|
||||
skinning_data = nullptr;
|
||||
}
|
||||
}
|
||||
Item() {
|
||||
light_mask = 1;
|
||||
|
||||
Reference in New Issue
Block a user