Skip to content

Commit 8cfd08e

Browse files
committed
perf(physics): 优化 MeshColliderShape 顶点数据提取性能
- 直接读取 vertex buffer 数据,跳过 getPositions() 的 Vector3[] 中间层 - 紧凑布局 (stride=12, offset=0) 使用 Float32Array.set() 直接复制 - 交错布局使用单次遍历逐顶点复制 - 复用 _vertices 数组减少内存分配
1 parent 91427ad commit 8cfd08e

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

packages/core/src/physics/shape/MeshColliderShape.ts

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { IMeshColliderShape } from "@galacean/engine-design";
22
import { ignoreClone } from "../../clone/CloneManager";
33
import { Engine } from "../../Engine";
44
import { Mesh } from "../../graphic/Mesh";
5+
import { VertexAttribute } from "../../mesh/enums/VertexAttribute";
56
import { ModelMesh } from "../../mesh/ModelMesh";
67
import { ColliderShape } from "./ColliderShape";
78

@@ -123,28 +124,62 @@ export class MeshColliderShape extends ColliderShape {
123124
}
124125

125126
private _extractMeshData(mesh: ModelMesh): void {
126-
// Get positions from mesh
127-
const positions = mesh.getPositions();
128-
if (!positions || positions.length === 0) {
129-
console.warn("MeshColliderShape: Mesh has no position data or data is not accessible");
127+
// @ts-ignore: Access internal property for performance optimization
128+
const primitive = mesh._primitive;
129+
const vertexElement = primitive._vertexElementMap?.[VertexAttribute.Position];
130+
131+
if (!vertexElement) {
132+
console.warn("MeshColliderShape: Mesh has no position attribute");
133+
return;
134+
}
135+
136+
const bufferBinding = primitive.vertexBufferBindings[vertexElement.bindingIndex];
137+
const buffer = bufferBinding?.buffer;
138+
139+
if (!buffer) {
140+
console.warn("MeshColliderShape: Position buffer not found");
141+
return;
142+
}
143+
144+
if (!buffer.readable) {
145+
console.warn("MeshColliderShape: Buffer is not readable");
130146
return;
131147
}
132148

133-
// Convert Vector3[] to Float32Array
134-
const vertexCount = positions.length;
135-
this._vertices = new Float32Array(vertexCount * 3);
136-
for (let i = 0; i < vertexCount; i++) {
137-
const pos = positions[i];
138-
this._vertices[i * 3] = pos.x;
139-
this._vertices[i * 3 + 1] = pos.y;
140-
this._vertices[i * 3 + 2] = pos.z;
149+
const vertexCount = mesh.vertexCount;
150+
const byteOffset = vertexElement.offset;
151+
const byteStride = bufferBinding.stride;
152+
const bufferData = buffer.data;
153+
154+
// Reuse or create Float32Array
155+
if (!this._vertices || this._vertices.length !== vertexCount * 3) {
156+
this._vertices = new Float32Array(vertexCount * 3);
157+
}
158+
159+
// Create Float32Array view to read source data
160+
const sourceData = new Float32Array(bufferData.buffer, bufferData.byteOffset, bufferData.byteLength / 4);
161+
162+
// Choose optimal copy method based on stride
163+
if (byteStride === 12 && byteOffset === 0) {
164+
// Tightly packed: direct copy
165+
this._vertices.set(sourceData.subarray(0, vertexCount * 3));
166+
} else {
167+
// Interleaved: copy per vertex
168+
const floatStride = byteStride / 4;
169+
const floatOffset = byteOffset / 4;
170+
for (let i = 0; i < vertexCount; i++) {
171+
const srcIdx = i * floatStride + floatOffset;
172+
const dstIdx = i * 3;
173+
this._vertices[dstIdx] = sourceData[srcIdx];
174+
this._vertices[dstIdx + 1] = sourceData[srcIdx + 1];
175+
this._vertices[dstIdx + 2] = sourceData[srcIdx + 2];
176+
}
141177
}
142178

143-
// Get indices for triangle mesh
179+
// Extract indices for triangle mesh
144180
if (!this._isConvex) {
145181
const indices = mesh.getIndices();
146182
if (indices) {
147-
// Convert Uint8Array to Uint16Array if needed
148183
if (indices instanceof Uint8Array) {
149184
this._indices = new Uint16Array(indices);
150185
} else {

0 commit comments

Comments
 (0)