mirror of
https://github.com/blender/blender.git
synced 2025-07-28 04:37:09 +00:00

**Problem Description** Blender's current mesh data layout often lacks spatial coherence, causing performance bottlenecks during BVH construction for sculpting and painting operations. Each time a BVH is built, the system must recompute spatial partitioning and vertex groupings from scratch, leading to redundant calculations and suboptimal memory access patterns. **Proposed Solution** This patch implements pre-computed spatial organization of mesh data through a new `mesh_apply_spatial_organization()` function that: - Reorders vertices and faces based on spatial locality using recursive spatial partitioning. - Stores pre-computed MeshGroup hierarchies in MeshRuntime for reuse. - Enables the BVH system to bypass expensive spatial computation when pre-organized data is available. This approach separates the expensive spatial computation from more frequent BVH rebuilds, providing sustained performance improvements across multiple sculpting operations. **Limitations** - Requires manual invocation (occurs automatically only during remesh operations). - Additional memory overhead for storing MeshGroup metadata. - One-time computational cost during initial organization. - Spatial group references are not yet stored in files. **User Interface** The feature is accessible via a new "Reorder Mesh Spatially" operator in the Mesh Data Properties panel under the Geometry Data section. Users can invoke it manually when needed, or it will be applied automatically during quadriflow and voxel remesh operations. The operator provides feedback confirming successful spatial reordering. Pull Request: https://projects.blender.org/blender/blender/pulls/139536
70 lines
2.6 KiB
Python
70 lines
2.6 KiB
Python
# SPDX-FileCopyrightText: 2022 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# ./blender.bin --background --python tests/python/bl_pyapi_text.py -- --verbose
|
|
import bpy
|
|
import unittest
|
|
|
|
|
|
class TestMeshSpatialOrganization(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
bpy.ops.object.select_all(action='SELECT')
|
|
bpy.ops.object.delete(use_global=False)
|
|
if bpy.context.mode != 'OBJECT':
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
|
|
def tearDown(self):
|
|
bpy.ops.object.select_all(action='SELECT')
|
|
bpy.ops.object.delete(use_global=False)
|
|
|
|
def create_subdivided_plane(self, subdivisions):
|
|
bpy.ops.mesh.primitive_plane_add(size=2, location=(0, 0, 0))
|
|
plane = bpy.context.active_object
|
|
bpy.ops.object.mode_set(mode='EDIT')
|
|
bpy.ops.mesh.select_all(action='SELECT')
|
|
bpy.ops.mesh.subdivide(number_cuts=subdivisions, smoothness=0.0)
|
|
bpy.ops.object.mode_set(mode='OBJECT')
|
|
return plane
|
|
|
|
def get_vertex_data(self, obj):
|
|
mesh = obj.data
|
|
vertices = [(v.co.x, v.co.y, v.co.z) for v in mesh.vertices]
|
|
return {
|
|
'vertices': vertices,
|
|
'vertex_count': len(vertices)
|
|
}
|
|
|
|
def create_reference_mesh(self, source_obj):
|
|
"""Create a reference copy of the mesh for comparison"""
|
|
bpy.context.view_layer.objects.active = source_obj
|
|
source_obj.select_set(True)
|
|
bpy.ops.object.duplicate()
|
|
reference_obj = bpy.context.active_object
|
|
reference_obj.name = "reference_mesh"
|
|
return reference_obj
|
|
|
|
def test_spatial_organization_changes_vertex_order(self):
|
|
plane = self.create_subdivided_plane(subdivisions=50)
|
|
initial_data = self.get_vertex_data(plane)
|
|
bpy.ops.mesh.reorder_vertices_spatial()
|
|
final_data = self.get_vertex_data(plane)
|
|
self.assertEqual(initial_data['vertex_count'], final_data['vertex_count'])
|
|
vertices_changed = initial_data['vertices'] != final_data['vertices']
|
|
self.assertTrue(vertices_changed)
|
|
|
|
def test_spatial_organization_preserves_topology(self):
|
|
plane = self.create_subdivided_plane(subdivisions=50)
|
|
reference_plane = self.create_reference_mesh(plane)
|
|
bpy.ops.mesh.reorder_vertices_spatial()
|
|
|
|
comparison_result = plane.data.unit_test_compare(mesh=reference_plane.data)
|
|
self.assertEqual(comparison_result, "The geometries are the same up to a change of indices")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else [])
|
|
unittest.main()
|