diff --git a/.env b/.env index cef47acb..b1765e23 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -VITE_PINATA_API_KEY=bf7ebd9ad32c11abe43c -VITE_PINATA_API_SECRET=c6fa7b8b056d0cf2e467e0ebbdc38ae889b96c59f06992ae831e2a25e52e5006 -VITE_ALCHEMY_API_KEY=OOWUrxHDTRyPmbYOSGyq7izHNQB1QYOv -VITE_ASSET_PATH=https://webaverse-studios.github.io/character-assets \ No newline at end of file +#VITE_ASSET_PATH=https://M3-org.github.io/character-assets +#download from https://github.com/M3-org/character-assets and load locally +VITE_ASSET_PATH=./character-assets + diff --git a/README.md b/README.md index ab65fdb0..ca43bb9d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ -# Webaverse Character Studio +# Character Studio + An open, collaborative and evolving 3D avatar studio for the open metaverse. # Quick Start + +> Note: Need character-assets imported to public folder for this to work! https://github.com/memelotsqui/character-assets + + ```bash # Clone the repo and change directory into it -git clone https://github.com/memelotsqui/CharacterStudio +git clone https://github.com/M3-org/CharacterStudio cd CharacterStudio # Install dependencies with legacy peer deps flag to ignore React errors @@ -15,3 +20,11 @@ npm run dev yarn install yarn run dev ``` + +--- + +## Special Thanks + +shoutout to [original repo by Webaverse](https://github.com/webaverse/characterstudio) + +Thanks m00n, memelotsqui, boomboxhead, and many others for contributing diff --git a/public/assets/portraitImages/anata.png b/public/assets/portraitImages/anata.png new file mode 100644 index 00000000..33c2d8a0 Binary files /dev/null and b/public/assets/portraitImages/anata.png differ diff --git a/src/App.jsx b/src/App.jsx index 90767d8c..a323ffe2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -51,7 +51,7 @@ const centerCameraPositionChat = new THREE.Vector3( const centerCameraPositionLengthChat = centerCameraPositionChat.length() const ndcBiasChat = 0.35 -const cameraDistanceOther = 3.2 +const cameraDistanceOther = 6 const centerCameraTargetOther = new THREE.Vector3(0, 0.8, 0) const centerCameraPositionOther = new THREE.Vector3( -2.2367993753934425, diff --git a/src/components/Selector.jsx b/src/components/Selector.jsx index 2670da8e..789e89f3 100644 --- a/src/components/Selector.jsx +++ b/src/components/Selector.jsx @@ -1,7 +1,7 @@ import React, { useContext, useEffect, useState } from "react" import * as THREE from "three" import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader" -import { VRMLoaderPlugin } from "@pixiv/three-vrm" +import { MToonMaterial, VRMLoaderPlugin } from "@pixiv/three-vrm" import cancel from "../../public/ui/selector/cancel.png" import { addModelData, disposeVRM } from "../library/utils" import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast, SAH } from 'three-mesh-bvh'; @@ -42,6 +42,7 @@ export default function Selector({confirmDialog, templateInfo, animationManager, removeOption, saveUserSelection, setIsChangingWholeAvatar, + debugMode } = useContext(SceneContext) const { playSound @@ -523,9 +524,50 @@ export default function Selector({confirmDialog, templateInfo, animationManager, // basic setup child.frustumCulled = false if (child.isMesh) { + + // XXX Setup MToonMaterial for shader + + // Set Wireframe material with random colors for each material the object has + child.origMat = child.material; + + const getRandomColor = () => { + const minRGBValue = 0.1; // Minimum RGB value to ensure colorful colors + const r = minRGBValue + Math.random() * (1 - minRGBValue); + const g = minRGBValue + Math.random() * (1 - minRGBValue); + const b = minRGBValue + Math.random() * (1 - minRGBValue); + return new THREE.Color(r, g, b); + } + + const debugMat = new THREE.MeshBasicMaterial( { + color: getRandomColor(), + wireframe: true, + wireframeLinewidth:0.2 + } ); + + const origMat = child.material; + child.setDebugMode = (debug) => { + if (debug){ + if (child.material.length){ + child.material[0] = debugMat; + child.material[1] = debugMat; + } + else{ + child.material = debugMat; + } + } + else{ + child.material = origMat; + } + } + + if (debugMode){ + child.setDebugMode(true); + } if (child.material.length){ effectManager.setCustomShader(child.material[0]); effectManager.setCustomShader(child.material[1]); + + } else{ effectManager.setCustomShader(child.material); diff --git a/src/context/SceneContext.jsx b/src/context/SceneContext.jsx index e05068af..5e9856cd 100644 --- a/src/context/SceneContext.jsx +++ b/src/context/SceneContext.jsx @@ -56,10 +56,25 @@ export const SceneProvider = (props) => { const [isChangingWholeAvatar, setIsChangingWholeAvatar] = useState(false) + const [debugMode, setDebugMode] = useState(false); + const setAvatar = (state) => { _setAvatar(state) } + const toggleDebugMNode = (isDebug) => { + if (isDebug == null) + isDebug = !debugMode; + + setDebugMode(isDebug); + scene.traverse((child) => { + if (child.isMesh) { + if (child.setDebugMode){ + child.setDebugMode(isDebug); + } + } + }); + } const loadAvatar = (avatarData) =>{ const data = getOptionsFromAvatarData(avatarData,manifest) if (data != null){ @@ -203,6 +218,9 @@ export const SceneProvider = (props) => { saveAvatarToLocalStorage, loadAvatarFromLocalStorage, + debugMode, + toggleDebugMNode, + setCurrentOptions, setSelectedOptions, getRandomCharacter, diff --git a/src/library/effectManager.js b/src/library/effectManager.js index 98d3188f..a5155697 100644 --- a/src/library/effectManager.js +++ b/src/library/effectManager.js @@ -20,6 +20,7 @@ import { transitionEffectTypeNumber, } from "./constants.js"; +import { MToonMaterial } from "@pixiv/three-vrm"; const textureLoader = new THREE.TextureLoader() diff --git a/src/pages/Appearance.jsx b/src/pages/Appearance.jsx index f125492c..8691a159 100644 --- a/src/pages/Appearance.jsx +++ b/src/pages/Appearance.jsx @@ -21,6 +21,7 @@ function Appearance({ getRandomCharacter, isChangingWholeAvatar, setIsChangingWholeAvatar, + toggleDebugMNode } = React.useContext(SceneContext) const { playSound } = React.useContext(SoundContext) @@ -30,6 +31,7 @@ function Appearance({ resetAvatar() setViewMode(ViewMode.CREATE) } + const next = () => { !isMute && playSound('backNextButton'); @@ -43,6 +45,10 @@ function Appearance({ } } + const debugMode = () =>{ + toggleDebugMNode() + } + useEffect(() => { const setIsChangingWholeAvatarFalse = () => setIsChangingWholeAvatar(false) @@ -104,6 +110,13 @@ function Appearance({ className={styles.buttonCenter} onClick={randomize} /> + )