custom cam control
This commit is contained in:
@@ -0,0 +1,49 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { sceneRegistry } from "@pascal-app/core";
|
||||||
|
import { useViewer } from "@pascal-app/viewer";
|
||||||
|
import { CameraControls, CameraControlsImpl } from "@react-three/drei";
|
||||||
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
export const CustomCameraControls = () => {
|
||||||
|
const controls = useRef<CameraControlsImpl>(null!);
|
||||||
|
const currentLevelId = useViewer((state) => state.currentLevelId);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let targetY = 0;
|
||||||
|
if (currentLevelId) {
|
||||||
|
const levelMesh = sceneRegistry.nodes.get(currentLevelId);
|
||||||
|
if (levelMesh) {
|
||||||
|
targetY = levelMesh.position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const currentTarget = new Vector3();
|
||||||
|
(controls.current as CameraControlsImpl).getTarget(currentTarget);
|
||||||
|
(controls.current as CameraControlsImpl).moveTo(
|
||||||
|
currentTarget.x,
|
||||||
|
targetY,
|
||||||
|
currentTarget.z,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}, [currentLevelId]);
|
||||||
|
|
||||||
|
// Configure mouse buttons based on control mode and camera mode
|
||||||
|
const mouseButtons = useMemo(() => {
|
||||||
|
// Use ZOOM for orthographic camera, DOLLY for perspective camera
|
||||||
|
// const wheelAction =
|
||||||
|
// cameraMode === 'orthographic'
|
||||||
|
// ? CameraControlsImpl.ACTION.ZOOM
|
||||||
|
// : CameraControlsImpl.ACTION.DOLLY
|
||||||
|
const wheelAction = CameraControlsImpl.ACTION.DOLLY;
|
||||||
|
|
||||||
|
return {
|
||||||
|
left: CameraControlsImpl.ACTION.NONE,
|
||||||
|
middle: CameraControlsImpl.ACTION.SCREEN_PAN,
|
||||||
|
right: CameraControlsImpl.ACTION.ROTATE,
|
||||||
|
wheel: wheelAction,
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return <CameraControls ref={controls} mouseButtons={mouseButtons} />;
|
||||||
|
};
|
||||||
@@ -10,10 +10,10 @@ import {
|
|||||||
WallNode,
|
WallNode,
|
||||||
} from "@pascal-app/core";
|
} from "@pascal-app/core";
|
||||||
import { useGridEvents, useViewer, Viewer } from "@pascal-app/viewer";
|
import { useGridEvents, useViewer, Viewer } from "@pascal-app/viewer";
|
||||||
import { CameraControls, CameraControlsImpl, Stats } from "@react-three/drei";
|
|
||||||
import { useFrame, useThree } from "@react-three/fiber";
|
import { useFrame, useThree } from "@react-three/fiber";
|
||||||
import { useEffect, useMemo, useRef } from "react";
|
import { useEffect, useMemo, useRef } from "react";
|
||||||
import { Color, MathUtils, Mesh, Object3D } from "three";
|
import { Color, MathUtils, Mesh, Object3D, Vector3 } from "three";
|
||||||
import { outline } from "three/addons/tsl/display/OutlineNode.js";
|
import { outline } from "three/addons/tsl/display/OutlineNode.js";
|
||||||
import {
|
import {
|
||||||
color,
|
color,
|
||||||
@@ -28,10 +28,11 @@ import {
|
|||||||
uniform,
|
uniform,
|
||||||
} from "three/tsl";
|
} from "three/tsl";
|
||||||
import { MeshBasicNodeMaterial, PostProcessing } from "three/webgpu";
|
import { MeshBasicNodeMaterial, PostProcessing } from "three/webgpu";
|
||||||
import { ActionMenu } from "./ui/action-menu";
|
import { ActionMenu } from "../ui/action-menu";
|
||||||
import { ToolManager } from "./tools/tool-manager";
|
import { ToolManager } from "../tools/tool-manager";
|
||||||
import { AppSidebar } from "./ui/sidebar/app-sidebar";
|
import { AppSidebar } from "../ui/sidebar/app-sidebar";
|
||||||
import { SidebarProvider } from "./ui/primitives/sidebar";
|
import { SidebarProvider } from "../ui/primitives/sidebar";
|
||||||
|
import { CustomCameraControls } from "./custom-camera-controls";
|
||||||
|
|
||||||
const selectedObjects: Object3D[] = [];
|
const selectedObjects: Object3D[] = [];
|
||||||
|
|
||||||
@@ -40,7 +41,7 @@ useScene.getState().loadScene();
|
|||||||
|
|
||||||
export default function Editor() {
|
export default function Editor() {
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full bg-pink-50">
|
<div className="w-full h-full">
|
||||||
{/* <LevelModeSwitcher /> */}
|
{/* <LevelModeSwitcher /> */}
|
||||||
|
|
||||||
<TestUndo />
|
<TestUndo />
|
||||||
@@ -55,37 +56,11 @@ export default function Editor() {
|
|||||||
<Grid cellColor="#666" sectionColor="#999" fadeDistance={30} />
|
<Grid cellColor="#666" sectionColor="#999" fadeDistance={30} />
|
||||||
<Passes />
|
<Passes />
|
||||||
<ToolManager />
|
<ToolManager />
|
||||||
<EditorCameraManager />
|
<CustomControls />
|
||||||
</Viewer>
|
</Viewer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const EditorCameraManager = () => {
|
|
||||||
const controls = useRef<CameraControlsImpl>(null!);
|
|
||||||
const currentLevelId = useViewer((state) => state.currentLevelId);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let targetY = 0;
|
|
||||||
if (currentLevelId) {
|
|
||||||
const levelMesh = sceneRegistry.nodes.get(currentLevelId);
|
|
||||||
if (levelMesh) {
|
|
||||||
targetY = levelMesh.position.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const { position } = controls.current.camera;
|
|
||||||
controls.current.setLookAt(
|
|
||||||
position.x,
|
|
||||||
targetY + 5,
|
|
||||||
position.z,
|
|
||||||
0,
|
|
||||||
targetY,
|
|
||||||
0,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}, [currentLevelId]);
|
|
||||||
|
|
||||||
return <CameraControls ref={controls} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TestUndo = () => {
|
const TestUndo = () => {
|
||||||
const { undo, redo, futureStates, pastStates } = useScene.temporal.getState();
|
const { undo, redo, futureStates, pastStates } = useScene.temporal.getState();
|
||||||
Reference in New Issue
Block a user