mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-17 11:24:56 -04:00
arm rendering
This commit is contained in:
parent
0eec3e496c
commit
d8d7a9408b
@ -56,7 +56,7 @@ open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : Skeleta
|
|||||||
private fun createModel(properties: PlayerProperties?): SkeletalInstance? {
|
private fun createModel(properties: PlayerProperties?): SkeletalInstance? {
|
||||||
val skin = renderWindow.textureManager.skins.getSkin(entity, properties) ?: return null
|
val skin = renderWindow.textureManager.skins.getSkin(entity, properties) ?: return null
|
||||||
val skinModel = skin.model
|
val skinModel = skin.model
|
||||||
val unbaked = renderWindow.modelLoader.entities.loadUnbakedModel(if (skinModel == SkinModel.SLIM) SLIM_MODEL else NORMAL_MODEL)
|
val unbaked = renderWindow.modelLoader.entities.loadUnbakedModel(if (skinModel == SkinModel.SLIM) SLIM_MODEL else WIDE_MODEL)
|
||||||
|
|
||||||
val elements: MutableList<SkeletalElement> = mutableListOf()
|
val elements: MutableList<SkeletalElement> = mutableListOf()
|
||||||
elementLoop@ for (element in unbaked.elements) {
|
elementLoop@ for (element in unbaked.elements) {
|
||||||
@ -126,7 +126,7 @@ open class PlayerModel(renderer: EntityRenderer, player: PlayerEntity) : Skeleta
|
|||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val NORMAL_MODEL = "minecraft:entities/player/normal".toResourceLocation().bbModel()
|
private val WIDE_MODEL = "minecraft:entities/player/wide".toResourceLocation().bbModel()
|
||||||
private val SLIM_MODEL = "minecraft:entities/player/slim".toResourceLocation().bbModel()
|
private val SLIM_MODEL = "minecraft:entities/player/slim".toResourceLocation().bbModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.overlays.arm
|
package de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.overlays.arm
|
||||||
|
|
||||||
|
import de.bixilon.kotlinglm.GLM
|
||||||
import de.bixilon.kotlinglm.func.rad
|
import de.bixilon.kotlinglm.func.rad
|
||||||
import de.bixilon.kotlinglm.mat4x4.Mat4
|
import de.bixilon.kotlinglm.mat4x4.Mat4
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
@ -20,10 +21,12 @@ import de.bixilon.kutil.cast.CastUtil.nullCast
|
|||||||
import de.bixilon.kutil.cast.CastUtil.unsafeNull
|
import de.bixilon.kutil.cast.CastUtil.unsafeNull
|
||||||
import de.bixilon.minosoft.data.entities.entities.player.Arms
|
import de.bixilon.minosoft.data.entities.entities.player.Arms
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.entity.models.minecraft.player.ArmAnimator
|
import de.bixilon.minosoft.gui.rendering.camera.CameraDefinition
|
||||||
import de.bixilon.minosoft.gui.rendering.entity.models.minecraft.player.PlayerModel
|
import de.bixilon.minosoft.gui.rendering.entity.models.minecraft.player.PlayerModel
|
||||||
import de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.Overlay
|
import de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.Overlay
|
||||||
import de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.OverlayFactory
|
import de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.OverlayFactory
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel.Companion.fromBlockCoordinates
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.baked.BakedSkeletalModel.Companion.toBlockCoordinate
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
|
import de.bixilon.minosoft.gui.rendering.system.base.IntegratedBufferTypes
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities
|
import de.bixilon.minosoft.gui.rendering.system.base.RenderingCapabilities
|
||||||
import de.bixilon.minosoft.gui.rendering.system.base.texture.skin.PlayerSkin
|
import de.bixilon.minosoft.gui.rendering.system.base.texture.skin.PlayerSkin
|
||||||
@ -38,9 +41,6 @@ class ArmOverlay(private val renderWindow: RenderWindow) : Overlay {
|
|||||||
private var skin: PlayerSkin? = null
|
private var skin: PlayerSkin? = null
|
||||||
private var model: PlayerModel? = null
|
private var model: PlayerModel? = null
|
||||||
private var mesh: ArmMesh = unsafeNull()
|
private var mesh: ArmMesh = unsafeNull()
|
||||||
private var animator: ArmAnimator? = null
|
|
||||||
|
|
||||||
private var a = 0.0f
|
|
||||||
|
|
||||||
override fun postInit() {
|
override fun postInit() {
|
||||||
shader.load()
|
shader.load()
|
||||||
@ -67,7 +67,6 @@ class ArmOverlay(private val renderWindow: RenderWindow) : Overlay {
|
|||||||
}
|
}
|
||||||
val model = renderWindow.connection.player.model.nullCast<PlayerModel>()
|
val model = renderWindow.connection.player.model.nullCast<PlayerModel>()
|
||||||
this.model = model
|
this.model = model
|
||||||
this.animator = model?.let { ArmAnimator(it) }
|
|
||||||
val skin = model?.skin ?: return
|
val skin = model?.skin ?: return
|
||||||
if (this.skin == skin) {
|
if (this.skin == skin) {
|
||||||
return
|
return
|
||||||
@ -78,26 +77,21 @@ class ArmOverlay(private val renderWindow: RenderWindow) : Overlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun calculateTransform(): Mat4 {
|
private fun calculateTransform(): Mat4 {
|
||||||
val projection = renderWindow.camera.matrixHandler.projectionMatrix
|
val screen = renderWindow.window.sizef
|
||||||
|
val projection = GLM.perspective(60.0f.rad, screen.x / screen.y, CameraDefinition.NEAR_PLANE, CameraDefinition.FAR_PLANE)
|
||||||
|
|
||||||
val matrix = Mat4()
|
val model = this.model ?: return Mat4()
|
||||||
matrix.rotateAssign(45.0f.rad, Vec3(0, 0, 1))
|
val outliner = model.instance?.model?.model?.outliner?.find { it.name == if (arm == Arms.LEFT) "LEFT_ARM" else "RIGHT_ARM" } ?: return Mat4()
|
||||||
matrix.rotateAssign(-5.0f.rad, Vec3(0, 1, 0))
|
outliner.origin.z = 15.0f.toBlockCoordinate()
|
||||||
matrix.rotateAssign(130.0f.rad, Vec3(1, 0, 0))
|
|
||||||
a += 1
|
|
||||||
|
|
||||||
|
val matrix = FirstPersonArmAnimator(model).calculateTransform(outliner, 0.0f)
|
||||||
|
val screenMatrix = Mat4()
|
||||||
|
|
||||||
matrix.translateAssign(Vec3(if (arm == Arms.LEFT) 0.25f else -0.25f, 0, 0)) // move inner side of arm to 0|0|0
|
screenMatrix.translateAssign(Vec3(if (arm == Arms.LEFT) -0.2f else 0.2f, 0, 0)) // move inner side of arm to 0|0|0
|
||||||
|
|
||||||
// matrix.scaleAssign(BLOCK_RESOLUTION) // make a pixel one pixel
|
screenMatrix.translateAssign(Vec3(-18, -55, -10).fromBlockCoordinates())
|
||||||
matrix.translateAssign(-0.5f)
|
|
||||||
matrix.translateAssign(Vec3(0, 0.3, 1.0))
|
|
||||||
|
|
||||||
val a = projection * matrix
|
return projection * screenMatrix * matrix
|
||||||
|
|
||||||
|
|
||||||
// "${a * Vec4(Vec3(4, 12, -2).fromBlockCoordinates(), 1)} -> ${a * Vec4(Vec3(7, 24, 2).fromBlockCoordinates(), 1)}"
|
|
||||||
return projection * matrix
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun draw() {
|
override fun draw() {
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.gui.rendering.framebuffer.world.overlay.overlays.arm
|
||||||
|
|
||||||
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
|
import de.bixilon.minosoft.gui.rendering.entity.models.minecraft.player.PlayerModel
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.AnimationLoops
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.SkeletalAnimation
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.model.animations.animator.keyframes.KeyframeChannels
|
||||||
|
import de.bixilon.minosoft.gui.rendering.skeletal.model.outliner.SkeletalOutliner
|
||||||
|
|
||||||
|
class FirstPersonArmAnimator(private val player: PlayerModel) : SkeletalAnimation {
|
||||||
|
override val name: String = ""
|
||||||
|
override val loop = AnimationLoops.LOOP
|
||||||
|
override val length: Float = 100.0f
|
||||||
|
|
||||||
|
// TODO (swinging: move arm to front, rotate)
|
||||||
|
|
||||||
|
override fun get(channel: KeyframeChannels, outliner: SkeletalOutliner, time: Float): Vec3? {
|
||||||
|
if (channel != KeyframeChannels.ROTATION) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return Vec3(140, -20, -10)
|
||||||
|
}
|
||||||
|
}
|
@ -91,7 +91,11 @@ class BakedSkeletalModel(
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun Vec3.fromBlockCoordinates(): Vec3 {
|
fun Vec3.fromBlockCoordinates(): Vec3 {
|
||||||
return Vec3(this.x / BLOCK_RESOLUTION + 0.5f, this.y / BLOCK_RESOLUTION, this.z / BLOCK_RESOLUTION + 0.5f)
|
return Vec3(this.x.toBlockCoordinate(), this.y.toBlockCoordinate(), this.z.toBlockCoordinate())
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Float.toBlockCoordinate(): Float {
|
||||||
|
return this / BLOCK_RESOLUTION + 0.5f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import de.bixilon.kotlinglm.func.rad
|
|||||||
import de.bixilon.kotlinglm.mat4x4.Mat4
|
import de.bixilon.kotlinglm.mat4x4.Mat4
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
import de.bixilon.kutil.time.TimeUtil
|
import de.bixilon.kutil.time.TimeUtil
|
||||||
|
import de.bixilon.kutil.time.TimeUtil.millis
|
||||||
import de.bixilon.minosoft.data.entities.EntityRotation
|
import de.bixilon.minosoft.data.entities.EntityRotation
|
||||||
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
import de.bixilon.minosoft.gui.rendering.RenderWindow
|
||||||
import de.bixilon.minosoft.gui.rendering.renderer.drawable.DeltaDrawable
|
import de.bixilon.minosoft.gui.rendering.renderer.drawable.DeltaDrawable
|
||||||
@ -82,9 +83,8 @@ class SkeletalInstance(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun calculateTransforms(): List<Mat4> {
|
fun calculateTransforms(base: Mat4 = this.baseTransform): List<Mat4> {
|
||||||
val baseTransform = baseTransform
|
val time = millis()
|
||||||
val time = TimeUtil.millis
|
|
||||||
if (animations.isNotEmpty()) {
|
if (animations.isNotEmpty()) {
|
||||||
val toRemove: MutableSet<SkeletalAnimationInstance> = mutableSetOf()
|
val toRemove: MutableSet<SkeletalAnimationInstance> = mutableSetOf()
|
||||||
for (animation in animations) {
|
for (animation in animations) {
|
||||||
@ -98,7 +98,7 @@ class SkeletalInstance(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (animations.isEmpty()) {
|
if (animations.isEmpty()) {
|
||||||
if (this.transforms.isNotEmpty() && baseTransform === previousBaseTransform) {
|
if (this.transforms.isNotEmpty() && base === previousBaseTransform) {
|
||||||
return this.transforms
|
return this.transforms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,10 +112,10 @@ class SkeletalInstance(
|
|||||||
}
|
}
|
||||||
val transforms: MutableList<Mat4> = mutableListOf()
|
val transforms: MutableList<Mat4> = mutableListOf()
|
||||||
for (outliner in model.model.outliner) {
|
for (outliner in model.model.outliner) {
|
||||||
calculateTransform(baseTransform, animations, outliner, transforms)
|
calculateTransform(base, animations, outliner, transforms)
|
||||||
}
|
}
|
||||||
this.transforms = transforms
|
this.transforms = transforms
|
||||||
this.previousBaseTransform = baseTransform
|
this.previousBaseTransform = base
|
||||||
return transforms
|
return transforms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ interface SkeletalAnimation {
|
|||||||
val rotation = get(KeyframeChannels.ROTATION, outliner, tweakedTime)
|
val rotation = get(KeyframeChannels.ROTATION, outliner, tweakedTime)
|
||||||
if (rotation != null && rotation != Vec3.EMPTY_INSTANCE) {
|
if (rotation != null && rotation != Vec3.EMPTY_INSTANCE) {
|
||||||
transform.translateAssign(outliner.origin.fromBlockCoordinates())
|
transform.translateAssign(outliner.origin.fromBlockCoordinates())
|
||||||
transform.rotateAssign(-rotation.x.rad, Vec3(1, 0, 0))
|
transform.rotateAssign(rotation.x.rad, Vec3(1, 0, 0))
|
||||||
transform.rotateAssign(-rotation.y.rad, Vec3(0, 1, 0))
|
transform.rotateAssign(rotation.y.rad, Vec3(0, 1, 0))
|
||||||
transform.rotateAssign(-rotation.z.rad, Vec3(0, 0, 1))
|
transform.rotateAssign(rotation.z.rad, Vec3(0, 0, 1))
|
||||||
transform.translateAssign(-outliner.origin.fromBlockCoordinates())
|
transform.translateAssign(-outliner.origin.fromBlockCoordinates())
|
||||||
}
|
}
|
||||||
val scale = get(KeyframeChannels.SCALE, outliner, tweakedTime)
|
val scale = get(KeyframeChannels.SCALE, outliner, tweakedTime)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"meta": {
|
"meta": {
|
||||||
"__comment": "This model was created by the creators of blockbench: https://github.com/JannisX11/blockbench",
|
"__comment": "This model was created by the creators of blockbench: https://github.com/JannisX11/blockbench",
|
||||||
"format_version": "4.0",
|
"format_version": "4.0",
|
||||||
"model_format": "skin",
|
"model_format": "free",
|
||||||
"box_uv": true
|
"box_uv": true
|
||||||
},
|
},
|
||||||
"geometry_name": "steve",
|
"geometry_name": "steve",
|
||||||
@ -437,7 +437,6 @@
|
|||||||
{
|
{
|
||||||
"name": "HEAD",
|
"name": "HEAD",
|
||||||
"origin": [0, 24, 0],
|
"origin": [0, 24, 0],
|
||||||
"rotation": [-6, 5, 0],
|
|
||||||
"uuid": "6da490f7-5540-bf4a-7f0a-12a5df3f3ce0",
|
"uuid": "6da490f7-5540-bf4a-7f0a-12a5df3f3ce0",
|
||||||
"children": ["842246c7-d06c-8ec1-c4d0-3dd83fd2ddfc", "be9eb8b9-9c9e-8f03-89be-623f059ad715"]
|
"children": ["842246c7-d06c-8ec1-c4d0-3dd83fd2ddfc", "be9eb8b9-9c9e-8f03-89be-623f059ad715"]
|
||||||
}, {
|
}, {
|
||||||
@ -447,26 +446,22 @@
|
|||||||
"children": ["9e3de0ee-4f3f-f74f-3c61-d8fe865b5103", "7d5b2fb8-9d28-f485-0b15-0241ff9171af"]
|
"children": ["9e3de0ee-4f3f-f74f-3c61-d8fe865b5103", "7d5b2fb8-9d28-f485-0b15-0241ff9171af"]
|
||||||
}, {
|
}, {
|
||||||
"name": "RIGHT_ARM",
|
"name": "RIGHT_ARM",
|
||||||
"origin": [5, 22, 0],
|
"origin": [5.5, 24, 0],
|
||||||
"rotation": [-10, 0, 0],
|
|
||||||
"uuid": "aa61460e-38d0-40f0-6291-3e8521bdd98c",
|
"uuid": "aa61460e-38d0-40f0-6291-3e8521bdd98c",
|
||||||
"children": ["feeb8a9e-1099-d4ed-8e4b-53dd68b5357b", "a05a34bc-73df-2361-b8fc-e9cbeda48ea1"]
|
"children": ["feeb8a9e-1099-d4ed-8e4b-53dd68b5357b", "a05a34bc-73df-2361-b8fc-e9cbeda48ea1"]
|
||||||
}, {
|
}, {
|
||||||
"name": "LEFT_ARM",
|
"name": "LEFT_ARM",
|
||||||
"origin": [-5, 22, 0],
|
"origin": [-5.5, 24, 0],
|
||||||
"rotation": [12, 0, 0],
|
|
||||||
"uuid": "310e097e-7820-987e-7f08-9f8823e76e29",
|
"uuid": "310e097e-7820-987e-7f08-9f8823e76e29",
|
||||||
"children": ["1773dbda-88eb-b14d-2e53-f91077dcf6a6", "0bc9a70e-d062-27a1-4864-1ca1eef87225"]
|
"children": ["1773dbda-88eb-b14d-2e53-f91077dcf6a6", "0bc9a70e-d062-27a1-4864-1ca1eef87225"]
|
||||||
}, {
|
}, {
|
||||||
"name": "RIGHT_LEG",
|
"name": "RIGHT_LEG",
|
||||||
"origin": [1.9, 12, 0],
|
"origin": [1.9, 12, 0],
|
||||||
"rotation": [11, 0, 2],
|
|
||||||
"uuid": "ea6793ea-8198-47f1-cba7-a49ce5d18538",
|
"uuid": "ea6793ea-8198-47f1-cba7-a49ce5d18538",
|
||||||
"children": ["94bb1759-86c5-f896-18d3-b5ec9de29975", "2faa3e41-dfb4-7bed-5e40-58590236f620"]
|
"children": ["94bb1759-86c5-f896-18d3-b5ec9de29975", "2faa3e41-dfb4-7bed-5e40-58590236f620"]
|
||||||
}, {
|
}, {
|
||||||
"name": "LEFT_LEG",
|
"name": "LEFT_LEG",
|
||||||
"origin": [-1.9, 12, 0],
|
"origin": [-1.9, 12, 0],
|
||||||
"rotation": [-10, 0, -2],
|
|
||||||
"uuid": "75e815a2-97a3-6b0c-8529-e48852251b02",
|
"uuid": "75e815a2-97a3-6b0c-8529-e48852251b02",
|
||||||
"children": ["0cad4dc2-fc12-43ac-0610-f5692a0764b7", "478b4925-5e2b-235f-0d95-d5d028ad624d"]
|
"children": ["0cad4dc2-fc12-43ac-0610-f5692a0764b7", "478b4925-5e2b-235f-0d95-d5d028ad624d"]
|
||||||
}
|
}
|
||||||
|
@ -437,7 +437,6 @@
|
|||||||
{
|
{
|
||||||
"name": "HEAD",
|
"name": "HEAD",
|
||||||
"origin": [0, 24, 0],
|
"origin": [0, 24, 0],
|
||||||
"rotation": [-6, 5, 0],
|
|
||||||
"uuid": "6da490f7-5540-bf4a-7f0a-12a5df3f3ce0",
|
"uuid": "6da490f7-5540-bf4a-7f0a-12a5df3f3ce0",
|
||||||
"children": ["842246c7-d06c-8ec1-c4d0-3dd83fd2ddfc", "be9eb8b9-9c9e-8f03-89be-623f059ad715"]
|
"children": ["842246c7-d06c-8ec1-c4d0-3dd83fd2ddfc", "be9eb8b9-9c9e-8f03-89be-623f059ad715"]
|
||||||
}, {
|
}, {
|
||||||
@ -447,26 +446,22 @@
|
|||||||
"children": ["9e3de0ee-4f3f-f74f-3c61-d8fe865b5103", "7d5b2fb8-9d28-f485-0b15-0241ff9171af"]
|
"children": ["9e3de0ee-4f3f-f74f-3c61-d8fe865b5103", "7d5b2fb8-9d28-f485-0b15-0241ff9171af"]
|
||||||
}, {
|
}, {
|
||||||
"name": "RIGHT_ARM",
|
"name": "RIGHT_ARM",
|
||||||
"origin": [5, 22, 0],
|
"origin": [6, 24, 0],
|
||||||
"rotation": [-10, 0, 0],
|
|
||||||
"uuid": "aa61460e-38d0-40f0-6291-3e8521bdd98c",
|
"uuid": "aa61460e-38d0-40f0-6291-3e8521bdd98c",
|
||||||
"children": ["feeb8a9e-1099-d4ed-8e4b-53dd68b5357b", "a05a34bc-73df-2361-b8fc-e9cbeda48ea1"]
|
"children": ["feeb8a9e-1099-d4ed-8e4b-53dd68b5357b", "a05a34bc-73df-2361-b8fc-e9cbeda48ea1"]
|
||||||
}, {
|
}, {
|
||||||
"name": "LEFT_ARM",
|
"name": "LEFT_ARM",
|
||||||
"origin": [-5, 22, 0],
|
"origin": [-6, 24, 0],
|
||||||
"rotation": [12, 0, 0],
|
|
||||||
"uuid": "310e097e-7820-987e-7f08-9f8823e76e29",
|
"uuid": "310e097e-7820-987e-7f08-9f8823e76e29",
|
||||||
"children": ["1773dbda-88eb-b14d-2e53-f91077dcf6a6", "0bc9a70e-d062-27a1-4864-1ca1eef87225"]
|
"children": ["1773dbda-88eb-b14d-2e53-f91077dcf6a6", "0bc9a70e-d062-27a1-4864-1ca1eef87225"]
|
||||||
}, {
|
}, {
|
||||||
"name": "RIGHT_LEG",
|
"name": "RIGHT_LEG",
|
||||||
"origin": [1.9, 12, 0],
|
"origin": [1.9, 12, 0],
|
||||||
"rotation": [11, 0, 2],
|
|
||||||
"uuid": "ea6793ea-8198-47f1-cba7-a49ce5d18538",
|
"uuid": "ea6793ea-8198-47f1-cba7-a49ce5d18538",
|
||||||
"children": ["94bb1759-86c5-f896-18d3-b5ec9de29975", "2faa3e41-dfb4-7bed-5e40-58590236f620"]
|
"children": ["94bb1759-86c5-f896-18d3-b5ec9de29975", "2faa3e41-dfb4-7bed-5e40-58590236f620"]
|
||||||
}, {
|
}, {
|
||||||
"name": "LEFT_LEG",
|
"name": "LEFT_LEG",
|
||||||
"origin": [-1.9, 12, 0],
|
"origin": [-1.9, 12, 0],
|
||||||
"rotation": [-10, 0, -2],
|
|
||||||
"uuid": "75e815a2-97a3-6b0c-8529-e48852251b02",
|
"uuid": "75e815a2-97a3-6b0c-8529-e48852251b02",
|
||||||
"children": ["0cad4dc2-fc12-43ac-0610-f5692a0764b7", "478b4925-5e2b-235f-0d95-d5d028ad624d"]
|
"children": ["0cad4dc2-fc12-43ac-0610-f5692a0764b7", "478b4925-5e2b-235f-0d95-d5d028ad624d"]
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user