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