Support for switching target environments
parent
875016a30d
commit
fd4eaa3c4b
|
|
@ -2,8 +2,6 @@ import * as THREE from 'three'
|
||||||
import { Object3D } from 'three'
|
import { Object3D } from 'three'
|
||||||
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils'
|
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils'
|
||||||
import type { TupleToUnion } from 'type-fest'
|
import type { TupleToUnion } from 'type-fest'
|
||||||
import handFBXFileUrl from '../models/hand.fbx?url'
|
|
||||||
import footFBXFileUrl from '../models/foot.fbx?url'
|
|
||||||
import { LoadFBXFile, LoadGLTFile, LoadObjFile } from './loader'
|
import { LoadFBXFile, LoadGLTFile, LoadObjFile } from './loader'
|
||||||
import {
|
import {
|
||||||
FindObjectItem,
|
FindObjectItem,
|
||||||
|
|
@ -11,6 +9,7 @@ import {
|
||||||
GetWorldPosition,
|
GetWorldPosition,
|
||||||
} from './three-utils'
|
} from './three-utils'
|
||||||
import { CCDIKSolver } from './CCDIKSolver'
|
import { CCDIKSolver } from './CCDIKSolver'
|
||||||
|
import assets from 'environments/assets'
|
||||||
|
|
||||||
const coco_body_keypoints_const = [
|
const coco_body_keypoints_const = [
|
||||||
'nose',
|
'nose',
|
||||||
|
|
@ -537,6 +536,7 @@ const ExtremitiesMapping: Record<
|
||||||
right_foot: footModelInfo,
|
right_foot: footModelInfo,
|
||||||
}
|
}
|
||||||
export async function LoadHand(onLoading?: (loaded: number) => void) {
|
export async function LoadHand(onLoading?: (loaded: number) => void) {
|
||||||
|
const handFBXFileUrl = assets['models/hand.fbx']
|
||||||
const fbx = await LoadFBXFile(handFBXFileUrl, onLoading)
|
const fbx = await LoadFBXFile(handFBXFileUrl, onLoading)
|
||||||
|
|
||||||
// fbx.scale.multiplyScalar(10)
|
// fbx.scale.multiplyScalar(10)
|
||||||
|
|
@ -569,6 +569,7 @@ export async function LoadHand(onLoading?: (loaded: number) => void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function LoadFoot(onLoading?: (loaded: number) => void) {
|
export async function LoadFoot(onLoading?: (loaded: number) => void) {
|
||||||
|
const footFBXFileUrl = assets['models/foot.fbx']
|
||||||
const fbx = await LoadFBXFile(footFBXFileUrl, onLoading)
|
const fbx = await LoadFBXFile(footFBXFileUrl, onLoading)
|
||||||
|
|
||||||
console.log(fbx)
|
console.log(fbx)
|
||||||
|
|
@ -1448,8 +1449,6 @@ export const PartIndexMappingOfBlazePoseModel = {
|
||||||
right_foot_index: 32,
|
right_foot_index: 32,
|
||||||
}
|
}
|
||||||
|
|
||||||
const PosesLibraryUrl = new URL('./poses/data.bin', import.meta.url).href
|
|
||||||
|
|
||||||
const PosesLibrary: [number, number, number][][] | null = []
|
const PosesLibrary: [number, number, number][][] | null = []
|
||||||
|
|
||||||
function getRandomInt(min: number, max: number) {
|
function getRandomInt(min: number, max: number) {
|
||||||
|
|
@ -1465,6 +1464,7 @@ export function GetRandomPose() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function LoadPosesLibrary() {
|
export async function LoadPosesLibrary() {
|
||||||
|
const PosesLibraryUrl = assets['src/poses/data.bin']
|
||||||
const response = await fetch(PosesLibraryUrl)
|
const response = await fetch(PosesLibraryUrl)
|
||||||
const buffer = await response.arrayBuffer()
|
const buffer = await response.arrayBuffer()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { setBackgroundImage } from 'environments/image'
|
||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
import { uploadImage } from './util'
|
import { uploadImage } from './util'
|
||||||
|
|
||||||
|
|
@ -8,8 +9,6 @@ export const options: Record<string, any> = {
|
||||||
Height: 0,
|
Height: 0,
|
||||||
async setBackground() {
|
async setBackground() {
|
||||||
const dataUrl = await uploadImage()
|
const dataUrl = await uploadImage()
|
||||||
const div = document.getElementById('background')
|
setBackgroundImage(dataUrl)
|
||||||
|
|
||||||
if (div) div.style.backgroundImage = `url(${dataUrl})`
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,11 @@ import {
|
||||||
PartIndexMappingOfBlazePoseModel,
|
PartIndexMappingOfBlazePoseModel,
|
||||||
} from './body'
|
} from './body'
|
||||||
import { options } from './config'
|
import { options } from './config'
|
||||||
import { SetScreenShot } from './image'
|
|
||||||
import {
|
import {
|
||||||
download,
|
download,
|
||||||
downloadJson,
|
downloadJson,
|
||||||
getCurrentTime,
|
getCurrentTime,
|
||||||
getImage,
|
getImage,
|
||||||
setBackgroundImage,
|
|
||||||
uploadImage,
|
uploadImage,
|
||||||
uploadJson,
|
uploadJson,
|
||||||
} from './util'
|
} from './util'
|
||||||
|
|
@ -60,6 +58,11 @@ import Swal from 'sweetalert2'
|
||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
import { FindObjectItem } from './three-utils'
|
import { FindObjectItem } from './three-utils'
|
||||||
import { DetectPosefromImage } from './detect'
|
import { DetectPosefromImage } from './detect'
|
||||||
|
import {
|
||||||
|
onMakeImages,
|
||||||
|
setBackgroundImage,
|
||||||
|
SetScreenShot,
|
||||||
|
} from 'environments/image'
|
||||||
|
|
||||||
interface BodyData {
|
interface BodyData {
|
||||||
position: ReturnType<THREE.Vector3['toArray']>
|
position: ReturnType<THREE.Vector3['toArray']>
|
||||||
|
|
@ -131,7 +134,7 @@ export class BodyEditor {
|
||||||
alight: THREE.AmbientLight
|
alight: THREE.AmbientLight
|
||||||
raycaster = new THREE.Raycaster()
|
raycaster = new THREE.Raycaster()
|
||||||
IsClick = false
|
IsClick = false
|
||||||
stats: Stats
|
stats: Stats | undefined
|
||||||
|
|
||||||
// ikSolver?: CCDIKSolver
|
// ikSolver?: CCDIKSolver
|
||||||
composer?: EffectComposer
|
composer?: EffectComposer
|
||||||
|
|
@ -139,7 +142,7 @@ export class BodyEditor {
|
||||||
enableComposer = false
|
enableComposer = false
|
||||||
enablePreview = true
|
enablePreview = true
|
||||||
|
|
||||||
constructor(canvas: HTMLCanvasElement) {
|
constructor(canvas: HTMLCanvasElement, statsElem?: Element) {
|
||||||
this.renderer = new THREE.WebGLRenderer({
|
this.renderer = new THREE.WebGLRenderer({
|
||||||
canvas,
|
canvas,
|
||||||
antialias: true,
|
antialias: true,
|
||||||
|
|
@ -228,8 +231,10 @@ export class BodyEditor {
|
||||||
// // Setup post-processing step
|
// // Setup post-processing step
|
||||||
// this.setupPost();
|
// this.setupPost();
|
||||||
|
|
||||||
this.stats = Stats()
|
if (statsElem) {
|
||||||
document.body.appendChild(this.stats.dom)
|
this.stats = Stats()
|
||||||
|
statsElem.appendChild(this.stats.dom)
|
||||||
|
}
|
||||||
this.animate()
|
this.animate()
|
||||||
this.handleResize()
|
this.handleResize()
|
||||||
this.AutoSaveScene()
|
this.AutoSaveScene()
|
||||||
|
|
@ -463,7 +468,7 @@ export class BodyEditor {
|
||||||
this.handleResize()
|
this.handleResize()
|
||||||
this.render()
|
this.render()
|
||||||
if (this.enablePreview) this.renderPreview()
|
if (this.enablePreview) this.renderPreview()
|
||||||
this.stats.update()
|
this.stats?.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
getAncestors(o: Object3D) {
|
getAncestors(o: Object3D) {
|
||||||
|
|
@ -861,6 +866,8 @@ export class BodyEditor {
|
||||||
this.renderer.setClearColor(0x000000, 0)
|
this.renderer.setClearColor(0x000000, 0)
|
||||||
this.axesHelper.visible = true
|
this.axesHelper.visible = true
|
||||||
this.gridHelper.visible = true
|
this.gridHelper.visible = true
|
||||||
|
|
||||||
|
onMakeImages()
|
||||||
}
|
}
|
||||||
|
|
||||||
CopySelectedBody() {
|
CopySelectedBody() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import handFBXFileUrl from '../../../models/hand.fbx?url'
|
||||||
|
import footFBXFileUrl from '../../../models/foot.fbx?url'
|
||||||
|
const PosesLibraryUrl = new URL('../../poses/data.bin', import.meta.url).href
|
||||||
|
|
||||||
|
export default {
|
||||||
|
'models/hand.fbx': handFBXFileUrl,
|
||||||
|
'models/foot.fbx': footFBXFileUrl,
|
||||||
|
'src/poses/data.bin': PosesLibraryUrl,
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import * as dat from 'dat.gui'
|
||||||
|
|
||||||
|
export const canvasElement =
|
||||||
|
document.querySelector<HTMLCanvasElement>('#canvas')!
|
||||||
|
export const statsElement = document.body
|
||||||
|
|
||||||
|
export function createDatGui() {
|
||||||
|
const gui = new dat.GUI()
|
||||||
|
return gui
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { download } from './util'
|
import { download } from '../../util'
|
||||||
|
|
||||||
document.querySelectorAll('.gallery img').forEach((img) =>
|
document.querySelectorAll('.gallery img').forEach((img) =>
|
||||||
img.addEventListener('click', (e) => {
|
img.addEventListener('click', (e) => {
|
||||||
|
|
@ -17,3 +17,15 @@ export function SetScreenShot(id: string, url: string, name: string) {
|
||||||
img.title = name
|
img.title = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
export function onMakeImages() {}
|
||||||
|
|
||||||
|
export function setBackgroundImage(dataUrl: string | null) {
|
||||||
|
const div = document.getElementById('background')
|
||||||
|
|
||||||
|
if (div) {
|
||||||
|
if (!dataUrl) div.style.backgroundImage = 'none'
|
||||||
|
else div.style.backgroundImage = `url(${dataUrl})`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { registerSW } from 'virtual:pwa-register'
|
import { registerSW } from 'virtual:pwa-register'
|
||||||
import Swal from 'sweetalert2'
|
import Swal from 'sweetalert2'
|
||||||
import i18n from './i18n'
|
import i18n from '../../i18n'
|
||||||
|
|
||||||
async function PWAPopup(update: (reloadPage?: boolean) => Promise<void>) {
|
async function PWAPopup(update: (reloadPage?: boolean) => Promise<void>) {
|
||||||
const result = await Swal.fire(
|
const result = await Swal.fire(
|
||||||
20
src/main.tsx
20
src/main.tsx
|
|
@ -1,16 +1,14 @@
|
||||||
import './init'
|
import 'environments/init'
|
||||||
import * as dat from 'dat.gui'
|
import 'environments/index.css'
|
||||||
import './index.css'
|
|
||||||
import { options } from './config'
|
import { options } from './config'
|
||||||
import { BodyEditor } from './editor'
|
import { BodyEditor } from './editor'
|
||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
import { CreateBodyParamsControls } from './body-params'
|
import { CreateBodyParamsControls } from './body-params'
|
||||||
import { CreateLanguageFolder } from './language'
|
import { CreateLanguageFolder } from './language'
|
||||||
|
import { canvasElement, createDatGui, statsElement } from 'environments/gui'
|
||||||
|
|
||||||
const editor = new BodyEditor(
|
const editor = new BodyEditor(canvasElement, statsElement)
|
||||||
document.querySelector<HTMLCanvasElement>('#canvas')!
|
const gui = createDatGui()
|
||||||
)
|
|
||||||
const gui = new dat.GUI()
|
|
||||||
|
|
||||||
window.addEventListener('keydown', function (event) {
|
window.addEventListener('keydown', function (event) {
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
|
|
@ -60,8 +58,10 @@ edit.add(editor, 'RemoveBody').name(i18n.t('Delete Skeleton (Del)'))
|
||||||
|
|
||||||
const setting = gui.addFolder(i18n.t('Setting'))
|
const setting = gui.addFolder(i18n.t('Setting'))
|
||||||
|
|
||||||
options['Width'] = editor.Width
|
if (options['Width'] == 0 || options['Height'] == 0) {
|
||||||
options['Height'] = editor.Height
|
options['Width'] = editor.Width
|
||||||
|
options['Height'] = editor.Height
|
||||||
|
}
|
||||||
setting
|
setting
|
||||||
.add(options, 'Width', 128, 5000)
|
.add(options, 'Width', 128, 5000)
|
||||||
.name(i18n.t('Width'))
|
.name(i18n.t('Width'))
|
||||||
|
|
@ -116,3 +116,5 @@ window.addEventListener('resize', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
editor.loadBodyData()
|
editor.loadBodyData()
|
||||||
|
|
||||||
|
export { editor }
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,6 @@ export function getImage(url: string): Promise<HTMLImageElement> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setBackgroundImage(dataUrl: string) {
|
|
||||||
const div = document.getElementById('background')
|
|
||||||
|
|
||||||
if (div) div.style.backgroundImage = `url(${dataUrl})`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getCurrentTime(format = 'YYYY_MM_DD_HH_mm_ss') {
|
export function getCurrentTime(format = 'YYYY_MM_DD_HH_mm_ss') {
|
||||||
return dayjs(new Date()).format(format)
|
return dayjs(new Date()).format(format)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,21 @@
|
||||||
|
|
||||||
declare const __APP_VERSION__: string
|
declare const __APP_VERSION__: string
|
||||||
declare const __APP_BUILD_TIME__: number
|
declare const __APP_BUILD_TIME__: number
|
||||||
|
declare module 'environments/gui' {
|
||||||
|
export const canvasElement: HTMLCanvasElement
|
||||||
|
export const statsElement: HTMLElement | undefined
|
||||||
|
export function createDatGui(): dat.GUI
|
||||||
|
}
|
||||||
|
declare module 'environments/assets' {
|
||||||
|
export = {
|
||||||
|
'models/hand.fbx': string,
|
||||||
|
'models/foot.fbx': string,
|
||||||
|
'src/poses/data.bin': string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declare module 'environments/image' {
|
||||||
|
export function SetScreenShot(id: string, url: string, name: string): void
|
||||||
|
export function onMakeImages(): void
|
||||||
|
export function setBackgroundImage(dataUrl: string | null): void
|
||||||
|
}
|
||||||
|
declare module 'environments/init' {}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,42 @@
|
||||||
import { defineConfig } from 'vite'
|
import { defineConfig, type UserConfigExport } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import { VitePWA } from 'vite-plugin-pwa'
|
import { VitePWA } from 'vite-plugin-pwa'
|
||||||
import { visualizer } from "rollup-plugin-visualizer"
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
import { resolve } from 'path'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
const config: UserConfigExport = {
|
||||||
base: '/open-pose-editor/',
|
base: '/open-pose-editor/',
|
||||||
define: {
|
define: {
|
||||||
global: {},
|
global: {},
|
||||||
__APP_VERSION__: JSON.stringify("v0.0.2"),
|
__APP_VERSION__: JSON.stringify('v0.0.2'),
|
||||||
__APP_BUILD_TIME__: Date.now()
|
__APP_BUILD_TIME__: Date.now(),
|
||||||
},
|
},
|
||||||
build: {
|
build: {},
|
||||||
},
|
resolve: {
|
||||||
plugins: [react(), VitePWA({
|
alias: {
|
||||||
workbox: {
|
'environments': resolve(__dirname, 'src/environments/online/'),
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,mp3,obj,fbx,bin}']
|
|
||||||
},
|
},
|
||||||
manifest: {
|
},
|
||||||
name: 'open pose editor',
|
plugins: [
|
||||||
short_name: 'open pose editor',
|
react(),
|
||||||
description: 'open pose editor (Yu Zhu)',
|
VitePWA({
|
||||||
theme_color: "#ffffff",
|
workbox: {
|
||||||
background_color: "#ffffff",
|
globPatterns: [
|
||||||
display: "standalone",
|
'**/*.{js,css,html,ico,png,svg,mp3,obj,fbx,bin}',
|
||||||
}
|
],
|
||||||
}), visualizer()],
|
},
|
||||||
})
|
manifest: {
|
||||||
|
name: 'open pose editor',
|
||||||
|
short_name: 'open pose editor',
|
||||||
|
description: 'open pose editor (Yu Zhu)',
|
||||||
|
theme_color: '#ffffff',
|
||||||
|
background_color: '#ffffff',
|
||||||
|
display: 'standalone',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
visualizer(),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineConfig(config)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue