fix(09): studs не растягиваются при scale-drag примитива
All checks were successful
CI / Lint (pull_request) Successful in 1m7s
CI / Build (pull_request) Successful in 1m58s
CI / Secret scan (pull_request) Successful in 2m31s
CI / PR size check (pull_request) Successful in 8s
CI / Deploy to S1 + S2 (pull_request) Has been skipped

При scale-гизмо mesh.scaling тянул faceUV → studs превращались в полосы.
Фикс: во время drag прячем studs-текстуру (плоский цвет), в dragEnd меш
пересоздаётся с правильным faceUV. _recreateMesh для studs пересоздаёт
материал заново (свежий тайлинг + восстановление текстуры).
GizmoController: + onDrag (live) колбэк для scale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
МИН 2026-05-31 13:37:44 +03:00
parent f6828aad2c
commit ea80ec3aa6
3 changed files with 41 additions and 19 deletions

View File

@ -1332,6 +1332,9 @@ export class BabylonScene {
// При окончании drag — синхронизируем
this._gizmo.setOnDragEnd(() => this._onGizmoDragEnd());
// Во время scale-drag — live-обновление тайлинга studs (кружки одного
// размера, не растягиваются пока тянешь гизмо).
this._gizmo.setOnDrag((mode) => { if (mode === 'scale') this._onGizmoScaleDrag(); });
// Привязка гизмо к выделенному
this.selection.setOnSelectionChange((sel) => this._updateGizmoForSelection(sel));
@ -3547,6 +3550,25 @@ export class BabylonScene {
* Гизмо манипулировал объектом синхронизируем через SelectionManager.
* Тип операции (move/rotate/scale) определяется по режиму гизмо.
*/
/**
* Во время scale-drag studs-примитива: текстура (faceUV) растягивается
* вместе с mesh.scaling и кружки превращаются в полосы. Чтобы не показывать
* это временно прячем diffuse/bump-текстуру (плоский цвет). В dragEnd меш
* пересоздаётся с правильным faceUV и текстура возвращается.
*/
_onGizmoScaleDrag() {
if (!this.selection) return;
const sel = this.selection.getSelection?.();
if (!sel || sel.type !== 'primitive' || sel.material !== 'studs') return;
const mat = sel.mesh?.material;
if (mat && mat.diffuseTexture && !mat._studsHidden) {
mat._studsStash = { diffuse: mat.diffuseTexture, bump: mat.bumpTexture };
mat.diffuseTexture = null;
mat.bumpTexture = null;
mat._studsHidden = true;
}
}
_onGizmoDragEnd() {
if (!this.selection || !this._gizmo) return;
const sel = this.selection.getSelection();

View File

@ -38,6 +38,7 @@ export class GizmoController {
setOnDragEnd(cb) { this._onDragEnd = cb; }
setOnDragStart(cb) { this._onDragStart = cb; }
setOnDrag(cb) { this._onDrag = cb; }
/** Главный метод — переключить режим. */
setMode(mode) {
@ -88,6 +89,13 @@ export class GizmoController {
gizmo.onDragStartObservable.add(() => {
if (this._onDragStart) this._onDragStart();
});
// onDrag (в процессе перетаскивания) — для live-обновления (напр. тайлинг
// studs, чтобы кружки не растягивались пока тянешь scale-гизмо).
if (gizmo.onDragObservable) {
gizmo.onDragObservable.add(() => {
if (this._onDrag) this._onDrag(mode);
});
}
gizmo.onDragEndObservable.add(() => {
if (this._onDragEnd) this._onDragEnd();
});

View File

@ -843,7 +843,15 @@ export class PrimitiveManager {
const newMesh = this._createMeshForType(typeDef, data.id, data.sx, data.sy, data.sz, data.material, data.studDensity);
newMesh.position = oldPos;
if (oldRot) newMesh.rotation = oldRot;
newMesh.material = oldMat;
// studs — материал пересоздаём заново (свежий faceUV/тайлинг + текстура
// могла быть временно спрятана во время scale-drag). Иначе переносим старый.
if (data.material === 'studs') {
newMesh._studsDims = { type: data.type, sx: data.sx, sy: data.sy, sz: data.sz, density: data.studDensity };
this._applyMaterial(newMesh, typeDef, data.color, data.material);
try { oldMat?.dispose(); } catch (e) { /* ignore */ }
} else {
newMesh.material = oldMat;
}
newMesh.isPickable = true;
newMesh.metadata = { ...oldMesh.metadata };
newMesh.setEnabled(data.visible);
@ -853,24 +861,8 @@ export class PrimitiveManager {
catch (e) { /* ignore */ }
data.mesh = newMesh;
newMesh._studsDims = { type: data.type, sx: data.sx, sy: data.sy, sz: data.sz, density: data.studDensity };
// studs-материал: пересчитать тайлинг под новый размер меша.
// Куб уже пересоздан с новым faceUV (тайлинг в геометрии) — uScale=1.
// Для остальных форм пересчитываем uScale/vScale по размеру.
if (data.material === 'studs' && oldMat && oldMat.diffuseTexture) {
if (data.type === 'cube' || data.type === 'trigger') {
oldMat.diffuseTexture.uScale = oldMat.diffuseTexture.vScale = 1;
if (oldMat.bumpTexture) oldMat.bumpTexture.uScale = oldMat.bumpTexture.vScale = 1;
} else {
const tile = _studsTiling(data.type, data.sx, data.sy, data.sz, data.studDensity);
oldMat.diffuseTexture.uScale = tile.u;
oldMat.diffuseTexture.vScale = tile.v;
if (oldMat.bumpTexture) {
oldMat.bumpTexture.uScale = tile.u;
oldMat.bumpTexture.vScale = tile.v;
}
}
}
// _studsDims и материал studs уже выставлены выше (через _applyMaterial
// на новом меше с правильным faceUV/тайлингом). Для не-studs ничего не надо.
}
/** Удалить инстанс. */