Skip to content

Commit

Permalink
Refactored attachables
Browse files Browse the repository at this point in the history
  • Loading branch information
Vlad Stepura committed Dec 16, 2019
1 parent 44b9d2f commit 05a0510
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 104 deletions.
6 changes: 6 additions & 0 deletions src/js/shared/IK/utils/jsUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Array.prototype.remove = function(object) {
let indexOf = this.indexOf(object)
if(indexOf !== -1) {
this.splice(indexOf, 1)
}
}
44 changes: 27 additions & 17 deletions src/js/shot-generator/Character.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ const Character = React.memo(({
largeRenderer,
deleteObjects,
updateObjects,
defaultPosePreset,
...props
}) => {
const [ready, setReady] = useState(false) // ready to load?
Expand Down Expand Up @@ -214,7 +215,11 @@ const Character = React.memo(({
useEffect(() => {
setReady(false)
setLoaded(false)
// return function cleanup () { }
return () => {
// Because when we switch models we recreate character(create new component) we need to set prev component object's id to null
if(object.current)
object.current.userData.id = null
}
}, [props.model])

useEffect(() => {
Expand Down Expand Up @@ -299,7 +304,7 @@ const Character = React.memo(({
}

return function cleanup () {
setAttachables(object.current ? object.current.attachables : null)
setAttachables(!object.current ? null : object.current.attachables ? object.current.attachables.concat([]) : null)
setModelChange(!object.current ? false : object.current.attachables ? true : false)
doCleanup()
// setLoaded(false)
Expand Down Expand Up @@ -335,17 +340,17 @@ const Character = React.memo(({
const fullyUpdateSkeleton = () => {
let skeleton = object.current.userData.skeleton
let changedSkeleton = []

let inverseMatrixWorld = object.current.getInverseMatrixWorld()
let position = new THREE.Vector3()
let scalarForBones = 1
if(props.posePresetId === defaultPosePreset.id)
scalarForBones = object.current.userData.boneLengthScale === 100 ? 100 : 1
for(let i = 0; i < skeleton.bones.length; i++) {
let bone = skeleton.bones[i]

if(bone.name.includes("leaf")) continue
let rotation = bone.rotation
bone.applyMatrix(object.current.matrixWorld)
position = bone.position.clone()
bone.applyMatrix(inverseMatrixWorld)
position.multiplyScalar( object.current.userData.boneLengthScale === 100 ? 100 : 1)

position = bone.position.clone().applyMatrix4(object.current.getInverseMatrixWorld())
position.multiplyScalar(scalarForBones)
changedSkeleton.push({
name: bone.name,
position: {
Expand All @@ -360,7 +365,7 @@ const Character = React.memo(({
}
})
}
//updateCharacterIkSkeleton({id, skeleton:changedSkeleton})
updateCharacterIkSkeleton({id, skeleton:changedSkeleton})
}

const saveAttachablesPositions = () => {
Expand All @@ -376,16 +381,17 @@ const Character = React.memo(({

const updateSkeleton = () => {
let skeleton = object.current.userData.skeleton

if (Object.values(props.skeleton).length) {
fixRootBone()

for (bone of skeleton.bones) {
let userState = props.skeleton[bone.name]
let systemState = originalSkeleton.current.getBoneByName(bone.name).clone()
let state = userState || systemState
bone.rotation.x = state.rotation.x
bone.rotation.y = state.rotation.y
bone.rotation.z = state.rotation.z

}
} else {
let skeleton = object.current.userData.skeleton
Expand Down Expand Up @@ -471,6 +477,8 @@ const Character = React.memo(({
object.current.position.z = props.y
object.current.position.y = props.z
object.current.orthoIcon.position.copy(object.current.position)
saveAttachablesPositions()

}
}, [props.model, props.x, props.y, props.z, ready])

Expand All @@ -490,7 +498,6 @@ const Character = React.memo(({
object.current.rotation.y = props.rotation
object.current.orthoIcon.icon.material.rotation = props.rotation + Math.PI
}

}
}, [props.model, props.rotation, ready])

Expand All @@ -501,18 +508,18 @@ const Character = React.memo(({
updateSkeleton()
}

const resetToStandardSkeleton = (defaultSkeleton) => {
const resetToStandardSkeleton = () => {
let skeleton = object.current.userData.skeleton
if (Object.values(props.skeleton).length) {
fixRootBone()

for (bone of skeleton.bones) {
let userState = defaultSkeleton[bone.name]
let userState = defaultPosePreset.state.skeleton[bone.name]
let systemState = originalSkeleton.current.getBoneByName(bone.name).clone()
let state = userState || systemState
bone.rotation.x = state.rotation.x
bone.rotation.y = state.rotation.y
bone.rotation.z = state.rotation.z
bone.updateMatrixWorld(true)
}
}
}
Expand Down Expand Up @@ -576,7 +583,7 @@ const Character = React.memo(({
if (!ready) return
if (!object.current) return

// console.log(type, id, 'skeleton')
//console.log(type, id, 'skeleton')
updateSkeleton()
if(props.handSkeleton && Object.keys(props.handSkeleton).length > 0)
updateSkeletonHand()
Expand All @@ -585,11 +592,14 @@ const Character = React.memo(({


useEffect(() => {
if (!ready) return
if (props.model !== object.current.userData.modelSettings.id) return
if (object.current) {
if (object.current.userData.modelSettings.height) {
let originalHeight = object.current.userData.originalHeight
let scale = props.height / originalHeight
object.current.scale.set( scale, scale, scale )
object.current.userData.height = props.height
} else {
object.current.scale.setScalar( props.height )
}
Expand Down Expand Up @@ -703,7 +713,7 @@ const Character = React.memo(({
}
}

setAttachables( null)
setAttachables(null)
}
setModelChange(false)
}
Expand Down
9 changes: 6 additions & 3 deletions src/js/shot-generator/Components.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ const CharacterPresetsEditor = connect(
let character = scene.children.filter(child => child.userData.id === sceneObject.id)[0]
let skinnedMesh = character.getObjectByProperty("type", "SkinnedMesh")
skinnedMesh.skeleton.pose()
character.resetToStandardSkeleton(defaultPosePreset.state.skeleton)
character.resetToStandardSkeleton()
character.updateWorldMatrix(true, true)
let attachables = initializeAttachables(sceneObject, preset)
if(attachables)
Expand Down Expand Up @@ -1058,13 +1058,16 @@ const CharacterPresetsEditor = connect(
if(character && character.attachables) {
let skinnedMesh = character.getObjectByProperty("type", "SkinnedMesh")
skinnedMesh.skeleton.pose()
character.resetToStandardSkeleton(defaultPosePreset.state.skeleton)
character.resetToStandardSkeleton()
character.updateWorldMatrix(true, true)
for(let i = 0; i < character.attachables.length; i++) {
character.attachables[i].saveToStore()
let attachable = character.attachables[i]
let attachableSceneObject = sceneObjects[character.attachables[i].userData.id]
let position = character.attachables[i].worldPosition()
let rotation = character.attachables[i].worldQuaternion()
let matrix = attachable.matrix.clone()
matrix.premultiply(attachable.parent.matrixWorld)
matrix.decompose(position, rotation, new THREE.Vector3())
let euler = new THREE.Euler().setFromQuaternion(rotation)
attachables.push({
x: position.x,
Expand Down
7 changes: 5 additions & 2 deletions src/js/shot-generator/SceneManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const {
updateCharacterIkSkeleton,
createPosePreset,
updateWorldEnvironment,
getDefaultPosePreset,

getSceneObjects,
getSelections,
Expand Down Expand Up @@ -68,7 +69,8 @@ const SceneManager = connect(
devices: state.devices,
meta: state.meta,
// HACK force reset skeleton pose on Board UUID change
_boardUid: state.board.uid
_boardUid: state.board.uid,
defaultPosePreset: getDefaultPosePreset()
}),
{
updateObject,
Expand All @@ -86,7 +88,7 @@ const SceneManager = connect(
undoGroupEnd
}
)(
({ world, sceneObjects, updateObject, selectObject, selectObjectToggle, remoteInput, largeCanvasRef, smallCanvasRef, selections, selectedBone, machineState, transition, animatedUpdate, selectBone, mainViewCamera, updateCharacterSkeleton, updateCharacterIkSkeleton, largeCanvasSize, activeCamera, aspectRatio, devices, meta, _boardUid, updateWorldEnvironment, attachments, undoGroupStart, undoGroupEnd, orthoCamera, camera, setCamera, selectedAttachable, updateObjects, deleteObjects }) => {
({ world, sceneObjects, updateObject, selectObject, selectObjectToggle, remoteInput, largeCanvasRef, smallCanvasRef, selections, selectedBone, machineState, transition, animatedUpdate, selectBone, mainViewCamera, updateCharacterSkeleton, updateCharacterIkSkeleton, largeCanvasSize, activeCamera, aspectRatio, devices, meta, _boardUid, updateWorldEnvironment, attachments, undoGroupStart, undoGroupEnd, orthoCamera, camera, setCamera, selectedAttachable, updateObjects, deleteObjects, defaultPosePreset }) => {
const { scene } = useContext(SceneContext)
// const modelCacheDispatch = useContext(CacheContext)

Expand Down Expand Up @@ -642,6 +644,7 @@ const SceneManager = connect(
largeRenderer,
deleteObjects,
updateObjects:updateObjects,
defaultPosePreset:defaultPosePreset,
...props
}
]
Expand Down
74 changes: 51 additions & 23 deletions src/js/shot-generator/attachables/Attachable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ window.THREE = window.THREE || THREE
const React = require('react')
const { useRef, useEffect, useState } = React
const ObjectRotationControl = require("../../shared/IK/objects/ObjectRotationControl")

require("../../shared/IK/utils/jsUtils")
// return a group which can report intersections
const groupFactory = () => {
let group = new THREE.Group()
Expand Down Expand Up @@ -55,6 +55,7 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
const characterObject = useRef()
const objectRotationControl = useRef();
const [ready, setReady] = useState(false) // ready to load?
const [needsInitialization, setInitialization] = useState(false)
const setLoaded = loaded => updateObject(id, { loaded })
const domElement = useRef()
const isBoneSelected = useRef()
Expand All @@ -72,10 +73,13 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
return function cleanup () {
setReady(false)
setLoaded(false)
container.current.parent.remove(container.current)
let indexOf = characterObject.current.attachables.indexOf(container.current)
characterObject.current.attachables.splice(indexOf, 1)
characterObject.current = null
if(container.current.parent)
container.current.parent.remove(container.current)
if( characterObject.current) {
characterObject.current.attachables.remove(container.current)
characterObject.current = null
}

objectRotationControl.current = null
container.current = null
}
Expand All @@ -87,7 +91,14 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
}, [props.model])

useEffect(() => {
if (ready) {
if (needsInitialization && !loaded) {

characterObject.current = scene.children.filter(child => child.userData.id === props.attachToId)[0]
if(!characterObject.current) {
setReady(false)
setInitialization(false)
return
}
container.current.remove(...container.current.children)
let isSkinnedMesh = false
// Traverses passed model and clones it's meshes to container
Expand All @@ -114,24 +125,27 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
deleteObjects([id])
}
// Sets up bind bone
characterObject.current = scene.children.filter(child => child.userData.id === props.attachToId)[0]
if(!characterObject.current) {
setReady(false)
return
}
let skinnedMesh = characterObject.current.getObjectByProperty("type", "SkinnedMesh")
let skeleton = skinnedMesh.skeleton
let bone = skeleton.getBoneByName(props.bindBone)
domElement.current = largeRenderer.current.domElement
container.current.userData.bindBone = props.bindBone

// Applies character scale for case when character is scaled up to 100
container.current.scale.multiplyScalar(props.size / characterObject.current.scale.x)
let scale = props.size / characterObject.current.scale.x
container.current.scale.set(scale, scale, scale)
bone.add(container.current)
container.current.updateMatrixWorld(true, true)
// Adds a container of attachable to character if it doesn't exist and adds current attachable
if(!skinnedMesh.parent.attachables) skinnedMesh.parent.attachables = []
skinnedMesh.parent.attachables.push(container.current)
if(!characterObject.current.attachables) {
characterObject.current.attachables = []
characterObject.current.attachables.push(container.current)
} else {
let isAdded = characterObject.current.attachables.some(attachable => attachable.uuid === container.current.uuid)
if(!isAdded) {
characterObject.current.attachables.push(container.current)
}
}

// Sets up object rotation control for manipulation of attachale rotation
objectRotationControl.current = new ObjectRotationControl(scene, camera, domElement.current, characterObject.current.uuid)
Expand All @@ -147,8 +161,9 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
z : euler.z,
}
} )})
setReady(true)
}
}, [ready])
}, [ready, characterObject.current, needsInitialization])


useEffect(() => {
Expand Down Expand Up @@ -225,12 +240,14 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m

useEffect(() => {
let character = scene.children.filter(child => child.userData.id === props.attachToId)[0]
if(character && modelData){
setReady(true)
if(character && modelData) {
setInitialization(true)
} else {
setReady(false)
setInitialization(false)
}
}, [modelData, scene.children.length, characterObject.current ])

}, [modelData, scene.children.length, characterObject.current, needsInitialization ])

useEffect(() => {
if(!ready) return
Expand All @@ -247,33 +264,44 @@ const Attachable = React.memo(({ scene, id, updateObject, sceneObject, loaded, m
useEffect(() => {
if(!ready) return
if(!characterObject.current) return

let scale = container.current.parent.uuid === scene.uuid ? props.size : props.size / characterObject.current.scale.x
container.current.scale.set( scale, scale, scale )
}, [props.size, characterObject.current])

const rebindAttachable = (characterScale) => {
if(!container.current) return

let prevCharacter = characterObject.current
characterObject.current = scene.children.filter(child => child.userData.id === props.attachToId)[0]

characterObject.current.updateMatrixWorld(true, true)
let skinnedMesh = characterObject.current.getObjectByProperty("type", "SkinnedMesh")
let skeleton = skinnedMesh.skeleton
let bone = skeleton.getBoneByName(props.bindBone)
domElement.current = largeRenderer.current.domElement
container.current.userData.bindBone = props.bindBone

prevCharacter.updateMatrixWorld(true)
prevCharacter.updateWorldMatrix(true, true)
let prevParent = container.current.parent
prevCharacter.attachables.remove(container.current)

prevParent.remove(container.current)
container.current.applyMatrix(prevCharacter.matrixWorld)
container.current.applyMatrix(characterObject.current.getInverseMatrixWorld())
bone.add(container.current)
container.current.scale.set( props.size, props.size, props.size )
container.current.scale.multiplyScalar(1 / characterScale)
container.current.updateWorldMatrix(true, true)

// Adds a container of attachable to character if it doesn't exist and adds current attachable
if(!skinnedMesh.parent.attachables) skinnedMesh.parent.attachables = []
skinnedMesh.parent.attachables.push(container.current)
if(!characterObject.current.attachables) {
characterObject.current.attachables = []
characterObject.current.attachables.push(container.current)
} else {
let isAdded = characterObject.current.attachables.some(attachable => attachable.uuid === container.current.uuid)
if(!isAdded) {
characterObject.current.attachables.push(container.current)
}
}
let position = container.current.worldPosition()
updateObject(id, { x: position.x, y: position.y, z: position.z})
}
Expand Down
Loading

0 comments on commit 05a0510

Please sign in to comment.