mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
3D: world/local transform space toggle for 3D editor gizmo (#1223)
Defaults translate and rotate to world space. X key and toolbar pill toggle between world and local. Scale mode is locked to local space.
This commit is contained in:
1 parent
68f8a339af
commit
5e150db37e
4 files changed
+50
-3
No files matched your search
@@ -42,6 +42,7 @@ import {
|
||||
} from "~/signals";
|
||||
|
||||
import { outlinerState, updateObjectPanel } from "../signals";
|
||||
import { transformSpace } from "../signals/selectedMode";
|
||||
import { IGenerationOptions } from "../models/generationOptions";
|
||||
import { toEngineActions } from "../Queue/toEngineActions";
|
||||
import { SceneGenereationMetaData } from "../models/sceneGenerationMetadata";
|
||||
@@ -592,8 +593,7 @@ class Editor {
|
||||
this.cameraViewControls.enabled = true;
|
||||
|
||||
this.control = new TransformControls(this.camera, this.renderer.domElement);
|
||||
this.control.space = "local"; // Local transformation mode
|
||||
// .space = 'world'; // Global mode
|
||||
this.control.space = "world"; // Default to world space for translate mode
|
||||
this.control.setScaleSnap(0.01);
|
||||
this.control.setTranslationSnap(0.01);
|
||||
this.control.setRotationSnap(0.01);
|
||||
@@ -1538,9 +1538,18 @@ class Editor {
|
||||
return;
|
||||
}
|
||||
this.control.mode = type;
|
||||
this.control.space = type === "scale" ? "local" : transformSpace.value;
|
||||
this.transform_interaction = true;
|
||||
}
|
||||
|
||||
toggleTransformSpace() {
|
||||
if (this.control == undefined || this.control.mode === "scale") {
|
||||
return;
|
||||
}
|
||||
transformSpace.value = transformSpace.value === "world" ? "local" : "world";
|
||||
this.control.space = transformSpace.value;
|
||||
}
|
||||
|
||||
async stopPlaybackAndUploadVideo() {
|
||||
await this.videoGeneration.stopPlaybackAndUploadVideo();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
selectedMode,
|
||||
poseMode,
|
||||
showPoseControls,
|
||||
transformSpace,
|
||||
} from "../signals/selectedMode";
|
||||
import { Euler } from "three";
|
||||
|
||||
@@ -341,16 +342,25 @@ export class MouseControls {
|
||||
} else if (event.key === "t") {
|
||||
// transform
|
||||
this.control?.setMode("translate");
|
||||
if (this.control) this.control.space = transformSpace.value;
|
||||
selectedMode.value = "move";
|
||||
return;
|
||||
} else if (event.key === "x") {
|
||||
// toggle world/local space (blocked in scale mode)
|
||||
if (this.control?.mode === "scale") return;
|
||||
transformSpace.value = transformSpace.value === "world" ? "local" : "world";
|
||||
if (this.control) this.control.space = transformSpace.value;
|
||||
return;
|
||||
} else if (event.key === "r" && !event.ctrlKey) {
|
||||
// rotate
|
||||
this.control?.setMode("rotate");
|
||||
if (this.control) this.control.space = transformSpace.value;
|
||||
selectedMode.value = "rotate";
|
||||
return;
|
||||
} else if (event.key === "g") {
|
||||
// scale
|
||||
this.control?.setMode("scale");
|
||||
if (this.control) this.control.space = transformSpace.value;
|
||||
selectedMode.value = "scale";
|
||||
return;
|
||||
} else if (event.key === "k") {
|
||||
|
||||
@@ -22,7 +22,7 @@ import { useTabStore } from "~/pages/Stores/TabState";
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
// import { AssetType } from "~/enums";
|
||||
import { AssetModal } from "../AssetMenu/AssetModal";
|
||||
import { selectedMode } from "../../signals/selectedMode";
|
||||
import { selectedMode, transformSpace } from "../../signals/selectedMode";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { outlinerState } from "../../signals/outliner/outliner";
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
@@ -320,6 +320,33 @@ export const Controls3D = () => {
|
||||
onOptionChange={handleModeChange}
|
||||
selectedOption={selectedMode.value}
|
||||
/>
|
||||
{selectedMode.value === "scale" ? (
|
||||
<Tooltip
|
||||
content="Scale is always in local space"
|
||||
position="bottom"
|
||||
delay={300}
|
||||
>
|
||||
<button
|
||||
disabled
|
||||
className="h-9 rounded-[10px] px-2.5 text-[10px] font-semibold font-mono bg-white/15 uppercase tracking-wide opacity-40 cursor-not-allowed"
|
||||
>
|
||||
Local
|
||||
</button>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip
|
||||
content={`Transform space: ${transformSpace.value} (X to toggle)`}
|
||||
position="bottom"
|
||||
delay={300}
|
||||
>
|
||||
<button
|
||||
className="h-9 rounded-[10px] px-2.5 text-[10px] font-semibold font-mono bg-white/15 hover:bg-white/25 transition-colors uppercase tracking-wide"
|
||||
onClick={() => editorEngine?.toggleTransformSpace()}
|
||||
>
|
||||
{transformSpace.value === "world" ? "World" : "Local"}
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,3 +3,4 @@ import { signal } from "@preact/signals-react";
|
||||
export const selectedMode = signal("move");
|
||||
export const showPoseControls = signal(false);
|
||||
export const poseMode = signal("select");
|
||||
export const transformSpace = signal<"world" | "local">("world");
|
||||
Reference in new issue
Block a user