Merge remote-tracking branch 'upstream/main'

main
nonnonstop 2023-04-15 13:19:30 +00:00
commit 182551692f
No known key found for this signature in database
GPG Key ID: 86B5CF70666F1AC5
12 changed files with 273 additions and 15 deletions

View File

@ -460,6 +460,17 @@ export interface BodyData {
>
}
export interface HandData {
child: Record<
string,
{
position?: ReturnType<THREE.Vector3['toArray']>
rotation?: ReturnType<THREE.Euler['toArray']>
scale?: ReturnType<THREE.Vector3['toArray']>
}
>
}
export class BodyControlor {
body: Object3D
part: Record<ControlPartName, Object3D> = {} as any
@ -983,6 +994,68 @@ export class BodyControlor {
this.Update()
}
GetHandData(hand: 'left_hand' | 'right_hand'): HandData {
const o = this.part[hand]
const result: HandData = {
child: {},
}
o.traverse((child) => {
if (child.name && IsBone(child.name)) {
if (child.name in result.child)
console.log('Duplicate name', child.name, child)
const data: Pick<BodyData, 'position' | 'rotation' | 'scale'> =
{}
if (
this.getDistanceOf(
child.position,
new THREE.Vector3(0, 0, 0)
) != 0
) {
data.position = child.position.toArray()
}
if (
this.getDistanceOf(
child.scale,
new THREE.Vector3(1, 1, 1)
) != 0
) {
data.scale = child.scale.toArray()
}
if (
child.rotation.x !== 0 ||
child.rotation.y !== 0 ||
child.rotation.z !== 0
) {
data.rotation = child.rotation.toArray()
}
if (data) result.child[child.name] = data
}
})
return result
}
RestoreHand(hand: 'left_hand' | 'right_hand', data: HandData) {
data.child = Object.fromEntries(
Object.entries(data.child).map(([k, v]) => {
if (hand == 'left_hand') return [k.replace('_R', '_L'), v]
if (hand == 'right_hand') return [k.replace('_L', '_R'), v]
return [k, v]
})
)
this.part[hand]?.traverse((o) => {
if (o.name && o.name in data.child) {
const child = data.child[o.name]
if (child.position) o.position.fromArray(child.position)
if (child.rotation) o.rotation.fromArray(child.rotation as any)
if (child.scale) o.scale.fromArray(child.scale)
}
})
}
GetBodyData(): BodyData {
const o = this.part['torso']
const result: BodyData = {

View File

@ -79,6 +79,18 @@ const MenubarDemo: React.FC<{
>
{i18n.t('Save Scene')}
</Menubar.Item>
<Menubar.Item
className={MenubarItem}
onSelect={() => helper.LoadGesture()}
>
{i18n.t('Load Gesture')}
</Menubar.Item>
<Menubar.Item
className={MenubarItem}
onSelect={() => helper.SaveGesture()}
>
{i18n.t('Save Gesture')}
</Menubar.Item>
<Menubar.Item
className={MenubarItem}
onSelect={() => {
@ -290,6 +302,21 @@ const MenubarDemo: React.FC<{
</Menubar.ItemIndicator>
{i18n.t('Show Preview')}
</Menubar.CheckboxItem>
<Menubar.CheckboxItem
className={classNames(MenubarCheckboxItem, inset)}
checked={editor.EnableHelper}
onCheckedChange={() => {
editor.EnableHelper = !editor.EnableHelper
forceUpdate()
}}
>
<Menubar.ItemIndicator
className={MenubarItemIndicator}
>
<CheckIcon />
</Menubar.ItemIndicator>
{i18n.t('Show Grid')}
</Menubar.CheckboxItem>
</Menubar.Content>
</Menubar.Portal>
</Menubar.Menu>

View File

@ -243,6 +243,8 @@ export class BodyEditor {
effectSobel?: ShaderPass
enableComposer = false
enablePreview = true
enableHelper = true
paused = false
parentElem: ParentElement
@ -1153,11 +1155,23 @@ export class BodyEditor {
// eslint-disable-next-line @typescript-eslint/no-empty-function
return () => {}
}
changeHelper() {
const old = {
axesHelper: this.axesHelper.visible,
gridHelper: this.gridHelper.visible,
}
this.axesHelper.visible = false
this.gridHelper.visible = false
return () => {
this.axesHelper.visible = old.axesHelper
this.gridHelper.visible = old.gridHelper
}
}
MakeImages() {
this.renderer.setClearColor(0x000000)
this.axesHelper.visible = false
this.gridHelper.visible = false
const restoreHelper = this.changeHelper()
const restoreTransfromControl = this.changeTransformControl()
const restoreView = this.changeView()
@ -1173,8 +1187,7 @@ export class BodyEditor {
/// end
this.renderer.setClearColor(0x000000, 0)
this.axesHelper.visible = true
this.gridHelper.visible = true
restoreHelper()
restoreTransfromControl()
restoreView()
@ -1250,7 +1263,7 @@ export class BodyEditor {
}
getSelectedBody() {
let obj: Object3D | null = this.transformControl.object ?? null
let obj: Object3D | null = this.getSelectedPart() ?? null
obj = obj ? this.getBodyByPart(obj) : null
return obj
@ -1258,6 +1271,19 @@ export class BodyEditor {
getSelectedPart() {
return this.transformControl.object
}
getHandByPart(o: Object3D) {
if (IsHand(o?.name)) return o
const body = this.getAncestors(o).find((o) => IsHand(o?.name)) ?? null
return body
}
getSelectedHand() {
let obj: Object3D | null = this.getSelectedPart() ?? null
obj = obj ? this.getHandByPart(obj) : null
return obj
}
RemoveBody() {
const obj = this.getSelectedBody()
@ -1365,6 +1391,14 @@ export class BodyEditor {
this.setFootVisible(!this.onlyHand)
}
get EnableHelper() {
return this.enableHelper
}
set EnableHelper(value: boolean) {
this.enableHelper = value
this.gridHelper.visible = value
this.axesHelper.visible = value
}
setFootVisible(value: boolean) {
this.traverseExtremities((o) => {
if (IsFoot(o.name)) {
@ -1521,6 +1555,25 @@ void main() {
return data
}
GetGesture() {
const hand = this.getSelectedHand()
const body = this.getSelectedBody()
if (!hand || !body) return null
const data = {
header: 'Openpose Editor by Yu Zhu',
version: __APP_VERSION__,
object: {
hand: new BodyControlor(body).GetHandData(
hand.name === 'left_hand' ? 'left_hand' : 'right_hand'
),
},
setting: {},
}
return data
}
AutoSaveScene() {
try {
const rawData = localStorage.getItem('AutoSaveSceneData')
@ -1548,6 +1601,31 @@ void main() {
console.error(error)
}
}
RestoreGesture(rawData: string) {
const data = JSON.parse(rawData)
const {
version,
object: { hand: handData },
setting,
} = data
if (!handData) throw new Error('Invalid json')
const hand = this.getSelectedHand()
const body = this.getSelectedBody()
if (!hand || !body) throw new Error('!hand || !body')
new BodyControlor(body).RestoreHand(
hand.name == 'left_hand' ? 'left_hand' : 'right_hand',
handData
)
}
SaveGesture() {
const data = this.GetGesture()
if (!data) throw new Error('Failed to get gesture')
downloadJson(JSON.stringify(data), `gesture_${getCurrentTime()}.json`)
}
ClearScene() {
this.GetBodies().forEach((o) => o.removeFromParent())

View File

@ -1,5 +1,9 @@
import { getImage } from '../../utils/image'
import { CopyTextToClipboard, uploadImage } from '../../utils/transfer'
import {
CopyTextToClipboard,
uploadImage,
uploadJson,
} from '../../utils/transfer'
import { DetectPosefromImage } from '../../utils/detect'
import { BodyControlor } from '../../body'
@ -62,7 +66,13 @@ export class Helper {
} catch (error) {
loading.hide()
Oops(error)
Oops(
i18n.t(
'If you try to detect anime characters, you may get an error. Please try again with photos.'
) +
'\n' +
error
)
console.error(error)
return null
}
@ -85,6 +95,41 @@ export class Helper {
}
}
async SaveGesture() {
const hand = await this.editor.getSelectedHand()
if (!hand) {
ShowToast({ title: i18n.t('Please select a hand!!') })
return
}
try {
this.editor.SaveGesture()
} catch (error) {
Oops(error)
console.error(error)
return null
}
}
async LoadGesture() {
const hand = await this.editor.getSelectedHand()
if (!hand) {
ShowToast({ title: i18n.t('Please select a hand!!') })
return
}
const rawData = await uploadJson()
if (!rawData) return
try {
this.editor.RestoreGesture(rawData)
} catch (error) {
Oops(error)
console.error(error)
return null
}
}
async GenerateSceneURL() {
try {
const d = encodeURIComponent(

View File

@ -62,5 +62,10 @@
"Copy Keypoint Data": "Schlüsselpunktdaten kopieren",
"Copied to Clipboard": "In die Zwischenablage kopiert",
"Generate Scene URL": "Szene-URL generieren",
"Reset Scene": "Szene zurücksetzen"
"Reset Scene": "Szene zurücksetzen",
"Load Gesture": "Geste laden",
"Save Gesture": "Geste speichern",
"Please select a hand!!": "Bitte wählen Sie eine Hand aus!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "Bei dem Versuch, Anime-Charaktere zu erkennen, kann es zu einem Fehler kommen. Bitte versuchen Sie es erneut mit Fotos.",
"Show Grid": "Gitter anzeigen"
}

View File

@ -62,5 +62,10 @@
"Unlock View": "Unlock View",
"Copy Keypoint Data": "Copy Keypoint Data",
"Copied to Clipboard": "Copied to Clipboard",
"Reset Scene": "Reset Scene"
"Reset Scene": "Reset Scene",
"Load Gesture": "Load Gesture",
"Save Gesture": "Save Gesture",
"Please select a hand!!": "Please select a hand!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "If you try to detect anime characters, you may get an error. Please try again with photos.",
"Show Grid": "Show Grid"
}

View File

@ -62,5 +62,10 @@
"Unlock View": "ビューをアンロックする",
"Copy Keypoint Data": "キーポイントデータをコピーする",
"Copied to Clipboard": "クリップボードにコピーされました",
"Reset Scene": "シーンをリセットする"
"Reset Scene": "シーンをリセットする",
"Load Gesture": "ジェスチャーを読み込む",
"Save Gesture": "ジェスチャーを保存する",
"Please select a hand!!": "手を選択してください!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "アニメキャラクターを検出しようとするとエラーが発生する場合があります。写真で再度お試しください。",
"Show Grid": "グリッドを表示"
}

View File

@ -62,5 +62,10 @@
"Copy Keypoint Data": "Copiar datos del punto clave",
"Copied to Clipboard": "Copiado al portapapeles",
"Generate Scene URL": "Generar URL de escena",
"Reset Scene": "Restablecer escena"
"Reset Scene": "Restablecer escena",
"Load Gesture": "Cargar gesto",
"Save Gesture": "Guardar gesto",
"Please select a hand!!": "¡¡Por favor, seleccione una mano!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "Si intenta detectar personajes de anime, es posible que obtenga un error. Por favor, inténtelo de nuevo con fotos.",
"Show Grid": "Mostrar cuadrícula"
}

View File

@ -62,5 +62,10 @@
"Copy Keypoint Data": "复制关键点数据",
"Copied to Clipboard": "已复制到剪贴板",
"Generate Scene URL": "生成场景URL",
"Reset Scene": "重置场景"
"Reset Scene": "重置场景",
"Load Gesture": "加载手势",
"Save Gesture": "保存手势",
"Please select a hand!!": "请选择一只手!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "如果您尝试检测动漫角色,可能会出现错误。请使用照片再试一次。",
"Show Grid": "显示网格"
}

View File

@ -62,5 +62,10 @@
"Copy Keypoint Data": "複製關鍵點數據",
"Copied to Clipboard": "已複製到剪貼板",
"Generate Scene URL": "生成場景URL",
"Reset Scene": "重置場景"
"Reset Scene": "重置場景",
"Load Gesture": "載入手勢",
"Save Gesture": "儲存手勢",
"Please select a hand!!": "請選擇一隻手!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "如果您嘗試檢測動漫角色,可能會出現錯誤。請使用照片再試一次。",
"Show Grid": "顯示網格"
}

View File

@ -62,5 +62,10 @@
"Copy Keypoint Data": "複製關鍵點數據",
"Copied to Clipboard": "已複製到剪貼板",
"Generate Scene URL": "生成場景URL",
"Reset Scene": "重置場景"
"Reset Scene": "重置場景",
"Load Gesture": "載入手勢",
"Save Gesture": "儲存手勢",
"Please select a hand!!": "請選擇一隻手!!",
"If you try to detect anime characters, you may get an error. Please try again with photos.": "如果您嘗試檢測動漫角色,可能會出現錯誤。請使用照片再試一次。",
"Show Grid": "顯示網格"
}

View File

@ -110,7 +110,7 @@ const config: UserConfigFn = ({ command, mode, ssrBuild }) => {
base: mode === 'singlefile' ? './' : '/open-pose-editor/',
define: {
global: {},
__APP_VERSION__: JSON.stringify('0.1.16'),
__APP_VERSION__: JSON.stringify('0.1.18'),
__APP_BUILD_TIME__: Date.now(),
},
build: {