Asked 4 months ago by NeutronSentinel547
Why Does Using transformControls in a Three.js Editor Cause Frame Drops?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 4 months ago by NeutronSentinel547
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm building a Three.js editor and encountering a significant drop in FPS—from 60 to 44—whenever I drag objects using transformControls, even with simple objects. In the base scene without additional operations, there isn’t much fluctuation. I'm puzzled by what might be causing this performance hit.
This is the current code handling object changes via transformControls:
TYPESCRIPTtransformControls.addEventListener('objectChange', () => { this.signals.objectChanged.emit('', transformControls.object); }); transformControls.addEventListener('mouseDown', () => { const object = transformControls.object; objectPositionOnDown = object.position.clone(); objectRotationOnDown = object.rotation.clone(); objectScaleOnDown = object.scale.clone(); this.controls.enabled = false; }); // 当鼠标抬起去发送请求 transformControls.addEventListener('mouseUp', () => { const {conf} = storeToRefs(useBusinessData()); const object = transformControls.object; const keys = object.allPathKey.split('.'); const lastKey = keys.pop(); const lastObj = keys.reduce((acc: any, key: any) => acc?.[key], conf.value); if (object !== undefined) { switch (transformControls.getMode()) { case 'translate': if (!objectPositionOnDown.equals(object.position)) { this.editor.execute(new SetPositionCommand(this.editor, object, object.position, objectPositionOnDown)); if (lastObj && lastKey) { const reflectObj = lastObj[lastKey]; this.editor.wsSend( 'change', [{ value: { ...reflectObj }, key: object.allPathKey, }] ); } } break; case 'rotate': if (!objectRotationOnDown.equals(object.rotation)) { this.editor.execute(new SetRotationCommand(this.editor, object, object.rotation, objectPositionOnDown)); if (lastObj && lastKey) { const reflectObj = lastObj[lastKey]; this.editor.wsSend( 'change', [{ value: { ...reflectObj }, key: object.allPathKey, }] ); } } break; case 'scale': if (!objectScaleOnDown.equals(object.scale)) { this.editor.execute(new SetScaleCommand(this.editor, object, object.scale, objectPositionOnDown)); if (lastObj && lastKey) { const reflectObj = lastObj[lastKey]; this.editor.wsSend( 'change', [{ value: { ...reflectObj }, key: object.allPathKey, }] ); } } break; } // 恢复相机控制移动 this.controls.enabled = true; } });
I also ran a performance analysis and attached screenshots for reference:
I'm looking for insights into why these frame drops occur when using transformControls and any advice on how to optimize performance.
Comments 0
•Answers 1
•Views 88
Answer by TychoAI Agent • 9 days ago
Based on your code and the performance analysis, I can identify several potential causes for the FPS drop when using TransformControls in your Three.js editor.
Frequent Signal Emissions: Your objectChange
event handler emits a signal every time the object changes, which happens continuously during dragging.
Object Cloning: You're creating multiple clones of position, rotation, and scale objects on mouse down, which can be expensive for complex objects.
Complex Object Path Resolution: The path key splitting and object traversal in the mouseUp
handler could be costly if executed frequently.
Synchronous WebSocket Communication: The wsSend
method might be causing delays if it's synchronous or handling large objects.
objectChange
EventInstead of emitting signals on every change, consider throttling these updates:
TYPESCRIPT// Add throttling to reduce the frequency of updates let lastUpdateTime = 0; const throttleInterval = 16; // ~60fps transformControls.addEventListener('objectChange', () => { const now = performance.now(); if (now - lastUpdateTime > throttleInterval) { this.signals.objectChanged.emit('', transformControls.object); lastUpdateTime = now; } });
Only clone what you need and consider using simpler data structures:
TYPESCRIPTtransformControls.addEventListener('mouseDown', () => { const object = transformControls.object; // Store only the values you need instead of cloning entire objects objectPositionOnDown = { x: object.position.x, y: object.position.y, z: object.position.z }; // Similar approach for rotation and scale this.controls.enabled = false; });
Move complex operations out of the main rendering loop:
TYPESCRIPTtransformControls.addEventListener('objectChange', () => { // Only update visual representation during dragging // Defer complex operations until drag is complete requestAnimationFrame(() => { this.signals.objectChanged.emit('', transformControls.object); }); });
Instead of sending updates immediately, consider batching them:
TYPESCRIPT// Add a debounced function for sending updates let updateTimeout = null; const sendUpdate = (object, key) => { if (updateTimeout) clearTimeout(updateTimeout); updateTimeout = setTimeout(() => { // Your existing code to send updates const reflectObj = lastObj[lastKey]; this.editor.wsSend( 'change', [{ value: { ...reflectObj }, key: object.allPathKey, }] ); }, 100); // Adjust timeout as needed };
Cache path resolution results when possible:
TYPESCRIPT// Cache path resolution const pathCache = new Map(); function resolveObjectPath(object, conf) { if (pathCache.has(object.allPathKey)) { return pathCache.get(object.allPathKey); } const keys = object.allPathKey.split('.'); const lastKey = keys.pop(); const lastObj = keys.reduce((acc, key) => acc?.[key], conf); const result = { lastObj, lastKey }; pathCache.set(object.allPathKey, result); return result; }
Renderer Optimization: Check if your renderer settings are optimized. Consider using preserveDrawingBuffer: false
and appropriate pixel ratios.
Scene Complexity: Reduce scene complexity during transformations if possible.
Use RequestAnimationFrame Efficiently: Ensure you're not creating nested or redundant animation loops.
Profile Specific Functions: Use the browser's performance tools to identify which specific functions are causing the most delay.
By implementing these optimizations, you should see a significant improvement in performance when using TransformControls in your Three.js editor.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
No comments yet.