bugfix
This commit is contained in:
19
package.json
19
package.json
@ -13,15 +13,16 @@
|
||||
"dependencies": {
|
||||
"@chakra-ui/icons": "^2.1.1",
|
||||
"@chakra-ui/react": "^2.8.2",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/react": "^11.11.3",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@react-three/drei": "^9.92.1",
|
||||
"@react-three/drei": "^9.92.7",
|
||||
"@react-three/fiber": "^8.15.12",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"ahooks": "^3.7.8",
|
||||
"fabric": "^5.3.0",
|
||||
"framer-motion": "^10.16.16",
|
||||
"leva": "^0.9.35",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@ -32,23 +33,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fabric": "^5.3.6",
|
||||
"@types/node": "^20.10.4",
|
||||
"@types/node": "^20.10.5",
|
||||
"@types/react": "^18.2.45",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/three": "^0.159.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
||||
"@typescript-eslint/parser": "^6.14.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.16.0",
|
||||
"@typescript-eslint/parser": "^6.16.0",
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"postcss": "^8.4.32",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-tailwindcss": "^0.5.9",
|
||||
"sass": "^1.69.5",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vite": "^5.0.8"
|
||||
"vite": "^5.0.10"
|
||||
}
|
||||
}
|
||||
|
1375
pnpm-lock.yaml
generated
1375
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -65,7 +65,7 @@ const LogoPanel = () => {
|
||||
{
|
||||
id,
|
||||
url: URL.createObjectURL(files[0]),
|
||||
postion: new Vector3(0, 0, 0),
|
||||
position: new Vector3(0, 0, 0),
|
||||
type: StickerType.logo,
|
||||
scale: activeModel ? 1.5 : 0.05,
|
||||
},
|
||||
|
@ -4,18 +4,57 @@ import useModelStore from "@/store/useModelStore.ts";
|
||||
import TextureSelectorPanel from "./TextureSelectorPanel";
|
||||
import LogoPanel from "./LogoPanel";
|
||||
import TextLabelPanel from "./TextLabelPanel";
|
||||
import { useState } from "react";
|
||||
|
||||
const RightPanel = () => {
|
||||
const activeModel = useModelStore((state) => state.activeModel);
|
||||
const setActiveModel = useModelStore((state) => state.setActiveModel);
|
||||
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
return (
|
||||
<>
|
||||
<Tabs variant={"soft-rounded"}>
|
||||
<Tabs variant={"enclosed"} index={activeTab}>
|
||||
<TabList>
|
||||
<Tab>版型</Tab>
|
||||
<Tab>纹理</Tab>
|
||||
<Tab>文字</Tab>
|
||||
<Tab>LOGO</Tab>
|
||||
<Tab
|
||||
className={`${
|
||||
activeTab === 0 ? "!rounded-none bg-white shadow-lg" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveTab(() => 0);
|
||||
}}
|
||||
>
|
||||
版型
|
||||
</Tab>
|
||||
<Tab
|
||||
className={`${
|
||||
activeTab === 1 ? "!rounded-none bg-white shadow-lg" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveTab(() => 1);
|
||||
}}
|
||||
>
|
||||
纹理
|
||||
</Tab>
|
||||
<Tab
|
||||
className={`${
|
||||
activeTab === 2 ? "!rounded-none bg-white shadow-lg" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveTab(() => 2);
|
||||
}}
|
||||
>
|
||||
文字
|
||||
</Tab>
|
||||
<Tab
|
||||
className={`${
|
||||
activeTab === 3 ? "!rounded-none bg-white shadow-lg" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setActiveTab(() => 3);
|
||||
}}
|
||||
>
|
||||
LOGO
|
||||
</Tab>
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
<TabPanel>
|
||||
@ -33,6 +72,7 @@ const RightPanel = () => {
|
||||
<img
|
||||
className="h-full w-full object-cover"
|
||||
src={models[index].icon}
|
||||
alt={""}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
@ -41,12 +81,15 @@ const RightPanel = () => {
|
||||
<TabPanel>
|
||||
<TextureSelectorPanel />
|
||||
</TabPanel>
|
||||
;
|
||||
<TabPanel>
|
||||
<TextLabelPanel />
|
||||
</TabPanel>
|
||||
;
|
||||
<TabPanel>
|
||||
<LogoPanel />
|
||||
</TabPanel>
|
||||
;
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import useModelStore, { DecalSticker } from "@/store/useModelStore";
|
||||
import { Decal, useTexture } from "@react-three/drei";
|
||||
// import { Euler } from "three";
|
||||
|
||||
/**
|
||||
* logo 和文字标签
|
||||
@ -16,8 +17,8 @@ const Sticker = ({ decal }: { decal: DecalSticker }) => {
|
||||
// }, 10)
|
||||
return (
|
||||
<Decal
|
||||
// debug={true}
|
||||
position={decal.postion}
|
||||
debug={true}
|
||||
position={decal.position}
|
||||
scale={decal.scale}
|
||||
onPointerDown={(ev) => {
|
||||
ev.stopPropagation();
|
||||
@ -28,9 +29,6 @@ const Sticker = ({ decal }: { decal: DecalSticker }) => {
|
||||
ev.stopPropagation();
|
||||
setDecalDragging(false);
|
||||
}}
|
||||
onPointerEnter={(_ev) => {
|
||||
// ev.ctrlKey
|
||||
}}
|
||||
onWheel={(ev) => {
|
||||
ev.stopPropagation();
|
||||
// setDecalDragging(true);
|
||||
@ -47,7 +45,7 @@ const Sticker = ({ decal }: { decal: DecalSticker }) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
rotation={Math.PI}
|
||||
// rotation={new Euler(Math.PI / 2, 0, 0)}
|
||||
// rotation={new Euler(Math.PI * euler.x, Math.PI * euler.y, Math.PI * euler.z)}
|
||||
// rotation={[Math.PI * 1, Math.PI * 1, Math.PI * 1]}
|
||||
>
|
||||
<meshPhysicalMaterial
|
||||
|
@ -67,11 +67,11 @@ const TextLabelPanel = () => {
|
||||
...decals,
|
||||
{
|
||||
id,
|
||||
postion: new Vector3(0, 0, 0),
|
||||
position: new Vector3(0, 0, 0),
|
||||
text,
|
||||
url: fabricCanvas.toDataURL(),
|
||||
type: StickerType.text,
|
||||
scale: activeModel ? 1.5 : 0.05,
|
||||
scale: activeModel ? 1.5 : 0.5,
|
||||
},
|
||||
]);
|
||||
setText(() => "");
|
||||
|
@ -6,25 +6,30 @@ import { models } from "@/constant/models.ts";
|
||||
import { useGLTF } from "@react-three/drei/core/useGLTF";
|
||||
import { textures } from "@/constant/textures.ts";
|
||||
import Sticker from "./Sticker";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
const CapModel = () => {
|
||||
const activeModel = useModelStore((state) => state.activeModel);
|
||||
const activeTextures = useModelStore((state) => state.activeTextures);
|
||||
const decalDragging = useModelStore((state) => state.decalDragging);
|
||||
const activeDecal = useModelStore((state) => state.activeDecal);
|
||||
const setDecalPositon = useModelStore((state) => state.setDecalPositon);
|
||||
|
||||
const setDecalPosition = useModelStore((state) => state.setDecalPosition);
|
||||
const [isAltDown, setIsAltDown] = useState(false);
|
||||
const ctrlRef = useRef(null);
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-expect-error
|
||||
ctrlRef.current?.reset();
|
||||
}, [activeModel]);
|
||||
|
||||
useEffect(() => {
|
||||
function handleKeyDown(event: any) {
|
||||
function handleKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === "Alt") {
|
||||
setIsAltDown(true);
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyUp(event: any) {
|
||||
function handleKeyUp(event: KeyboardEvent) {
|
||||
if (event.key === "Alt") {
|
||||
setIsAltDown(false);
|
||||
}
|
||||
@ -42,10 +47,19 @@ const CapModel = () => {
|
||||
}, []);
|
||||
|
||||
const { nodes } = useGLTF(models[activeModel].path);
|
||||
// const [ry, setRy] = useState(0);
|
||||
return (
|
||||
<>
|
||||
<group
|
||||
scale={models[activeModel].scale}
|
||||
onClick={(ev) => {
|
||||
console.log(ev.face?.normal);
|
||||
const angle = ev.face?.normal.angleTo(new Vector3(0, 1, 0));
|
||||
// if (angle && angle < Math.PI) {
|
||||
// angle = 2 * Math.PI - angle;
|
||||
// }
|
||||
console.log(angle ?? 0 / Math.PI);
|
||||
}}
|
||||
onPointerMove={(ev) => {
|
||||
ev.stopPropagation();
|
||||
if (!decalDragging) return;
|
||||
@ -56,7 +70,7 @@ const CapModel = () => {
|
||||
y / models[activeModel].scale,
|
||||
z / models[activeModel].scale,
|
||||
);
|
||||
setDecalPositon(activeDecal, pos);
|
||||
setDecalPosition(activeDecal, pos);
|
||||
}
|
||||
}}
|
||||
>
|
||||
@ -82,15 +96,17 @@ const CapModel = () => {
|
||||
const normal = ev.face?.normal;
|
||||
// normal?.transformDirection(ev.intersections[0].object.matrixWorld)
|
||||
// normal?.applyQuaternion(ev.object.quaternion)
|
||||
normal?.normalize();
|
||||
// normal?.normalize();
|
||||
console.log(normal);
|
||||
console.log(normal?.angleTo(new Vector3(0, 1, 0)));
|
||||
// const _ry = y + 0.5;
|
||||
// setRy(_ry);
|
||||
// console.log(normal?.angleTo(new Vector3(0, 1, 0)));
|
||||
|
||||
// const y_a = normal?.angleTo(new Vector3(0, 1, 0))
|
||||
// const x_a = normal?.angleTo(new Vector3(1, 0, 0))
|
||||
// const z_a = normal?.angleTo(new Vector3(0, 0, 1))
|
||||
// console.log(x_a, y_a, z_a);
|
||||
setDecalPositon(activeDecal, pos);
|
||||
setDecalPosition(activeDecal, pos);
|
||||
}
|
||||
}}
|
||||
castShadow
|
||||
@ -117,7 +133,13 @@ const CapModel = () => {
|
||||
}
|
||||
})}
|
||||
</group>
|
||||
<OrbitControls enabled={!decalDragging} enableZoom={!isAltDown} />
|
||||
<OrbitControls
|
||||
ref={ctrlRef}
|
||||
makeDefault={true}
|
||||
enabled={!decalDragging}
|
||||
enableZoom={!isAltDown}
|
||||
/>
|
||||
;
|
||||
</>
|
||||
);
|
||||
};
|
||||
@ -141,7 +163,7 @@ const ThreeScene = () => {
|
||||
<pointLight position={[10, 10, 10]}></pointLight>
|
||||
<perspectiveCamera />
|
||||
<CapModel />
|
||||
{/* <axesHelper /> */}
|
||||
<axesHelper />
|
||||
<Environment files={"/venice_sunset_1k.hdr"} background={false} />
|
||||
</Canvas>
|
||||
);
|
||||
|
@ -51,7 +51,7 @@ export const models = [
|
||||
name: "版型2",
|
||||
icon: "/icon/model2.jpg",
|
||||
path: "/models/baseball_cap.glb",
|
||||
scale: 0.02,
|
||||
scale: 0.4,
|
||||
mesh: [
|
||||
{
|
||||
name: "baseballCap_1",
|
||||
|
@ -2,6 +2,7 @@ import { create } from "zustand";
|
||||
import { models } from "@/constant/models.ts";
|
||||
import { Vector3 } from "three";
|
||||
import { devtools } from "zustand/middleware";
|
||||
|
||||
// import { v4 as uuidv4 } from "uuid";
|
||||
export enum StickerType {
|
||||
text,
|
||||
@ -10,7 +11,7 @@ export enum StickerType {
|
||||
|
||||
export interface DecalSticker {
|
||||
id: string;
|
||||
postion: Vector3;
|
||||
position: Vector3;
|
||||
text?: string;
|
||||
url: string;
|
||||
scale: number;
|
||||
@ -38,7 +39,7 @@ interface ModelState {
|
||||
|
||||
decals: DecalSticker[];
|
||||
activeDecal?: string;
|
||||
setDecalPositon: (id: string, postion: Vector3) => void;
|
||||
setDecalPosition: (id: string, position: Vector3) => void;
|
||||
setDecals: (decals: DecalSticker[]) => void;
|
||||
setDecalScale: (id: string, scale: number) => void;
|
||||
setActiveDecal: (decalId: string) => void;
|
||||
@ -93,13 +94,13 @@ const useModelStore = create<ModelState>()(
|
||||
|
||||
decals: [],
|
||||
activeDecal: undefined,
|
||||
setDecalPositon: (id: string, postion: Vector3) =>
|
||||
setDecalPosition: (id: string, position: Vector3) =>
|
||||
set((state) => {
|
||||
const _decals = state.decals.map((el) => {
|
||||
if (el.id === id) {
|
||||
return {
|
||||
...el,
|
||||
postion,
|
||||
position,
|
||||
};
|
||||
} else {
|
||||
return el;
|
||||
|
Reference in New Issue
Block a user