This commit is contained in:
quantulr
2024-01-02 09:22:09 +08:00
parent 784fe1d051
commit e54a837654
9 changed files with 1137 additions and 383 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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,
},

View File

@ -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>
</>

View File

@ -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,8 +45,8 @@ 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={[Math.PI * 1, Math.PI * 1, Math.PI * 1]}
// 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
transparent

View File

@ -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(() => "");

View File

@ -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>
);

View File

@ -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",

View File

@ -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;