Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class AnimatorViewController: UIViewController {
- override func viewDidLoad() {
- super.viewDidLoad()
- /// preparing methods call are not related for the PBD part
- setupPhysics()
- }
- // MARK: - Methods
- private func setupPhysics() {
- solver = PhysicsSolver()
- setupClothVisualMesh(root: patternNode!)
- setupAvatarFromDAE(path: avatarPath)
- solver?.setupDebugNodes()
- }
- func setupClothVisualMesh(root: SCNNode) {
- var elementNodesByLayers = root.childNodes.compactMap { $0.childNodes.compactMap { $0 as? ElementNode } }
- var vertices = [SCNVector3]()
- var normals = [SCNVector3]()
- var coordinates = [SCNVector3]()
- var indices = [UInt16]()
- var elements = [UInt16]()
- elementNodesByLayers[0].forEach {
- let (_, meshVertices, meshNormals, meshTexcoords, meshElements, meshIndices) = MeshSkinning.extractArrays(node: $0)
- let offset = vertices.count > 0 ? vertices.count - 1 : 0
- indices.append(contentsOf: meshIndices.compactMap { $0 + UInt16(offset) })
- vertices.append(contentsOf: meshVertices)
- normals.append(contentsOf: meshNormals)
- coordinates.append(contentsOf: meshTexcoords)
- elements.append(contentsOf: meshElements)
- }
- print("Loaded cloth model: [\(vertices.count) VERTICES, \(indices.count / 3) FACES]" )
- print("Welding duplicate vertices...")
- let (weldedVertices, weldedTris, weldedElements) = MeshSkinning.AutoWeld(verts: vertices, elements: elements, tris: indices, threshold: 0.000000001)
- print("Removed \(vertices.count - weldedVertices.count) duplicate vertices" )
- print("Setting up cloth simualation...")
- var indicesInt: [Int] = []
- for i in weldedTris{
- indicesInt.append(Int(i))
- }
- // solver.setupCloth(vertices: vertices, indices: indicesInt, elements: elements)
- solver?.setupCloth(vertices: weldedVertices, indices: indicesInt, elements: weldedElements)
- var pairs = [ConnectionPair]()
- connections?.forEach { connection in
- let leftVertices = connection.left.points.compactMap { SCNVector3($0.x, $0.y, 0.0) }
- let rightVertices = connection.right.points.compactMap { SCNVector3($0.x, $0.y, 0.0) }
- (0...leftVertices.count - 1).forEach { pairs.append((leftVertices[$0], rightVertices[$0])) }
- }
- solver?.setSewingConstraints(vertices: vertices, pairs: pairs)
- print("Cloth simulation ready")
- print("Setting up cloth visualization...")
- let clothVisGeo = solver?.setVisualizationMesh(vertices: vertices, normals: normals, texcoords: coordinates, indices: indices, elements: elements)
- let clothVisNode = SCNNode(geometry: clothVisGeo)
- clothVisNode.name = "ClothVisualization"
- sceneView.scene?.rootNode.addChildNode(clothVisNode)
- print("Cloth visualization ready")
- }
- private func setupAvatarFromDAE(path: String) {
- let avatarScene = SCNScene(named: path)!
- avatarRootNode = avatarScene.rootNode.childNode(withName: "RootNode", recursively: false)
- avatarRootNode.isHidden = true
- sceneView.scene?.rootNode.addChildNode(avatarRootNode)
- avatarSkinNode = avatarRootNode.childNode(withName: "Genesis8Female-skinInstance", recursively: true)
- avatarAnimNode = avatarRootNode.childNode(withName: "Genesis8Female", recursively: true)
- // lisa torso with head, arms, legs
- let meshElementsToIncludeForCollisions = [0, 5, 8]
- let animKeys = avatarAnimNode.animationKeys
- avatarAnimPlayer = avatarAnimNode.animationPlayer(forKey: animKeys.first!)
- avatarAnimPlayer.speed = 0.0
- let skinner = avatarSkinNode.skinner!
- var bonesTransforms:[float4x4] = []
- var bonesInvBindTransforms:[float4x4] = []
- let baseGeometryBindTransform:float4x4 = float4x4(skinner.baseGeometryBindTransform)
- for i in 0..<skinner.bones.count{
- let worldTr = float4x4(skinner.bones[i].presentation.worldTransform)
- let bonInvBindTr = float4x4(skinner.boneInverseBindTransforms![i].scnMatrix4Value)
- bonesTransforms.append(worldTr * bonInvBindTr * baseGeometryBindTransform)
- bonesWorldTransforms.append(worldTr)
- bonesInvBindTransforms.append(bonInvBindTr)
- }
- //default: return arrays of the rest pose (untransformed, unscaled etc)
- let (skinGeo, vertices, normals, indices, boneIndices, boneWeights) = MeshSkinning.extractArrays(skinner: skinner, elementsToInclude: meshElementsToIncludeForCollisions)
- //debug: returns skinned mesh arrays of the first frame of the animation (transformed, scaled)
- // let (skinGeo, vertices, normals, indices, boneIndices, boneWeights) = MeshSkinning.bakeMesh(skinner: skinner, bonesWorldTr:bonesWorldTransforms)
- print(path + " loaded: [\(vertices.count) VERTICES, \(indices.count / 3) FACES]" )
- let avatarGeo = solver?.setDynamicGeometry(vertices: vertices, normals: normals, indices: indices, bonesIndices: boneIndices, bonesWeights: boneWeights, bonesTransforms: bonesWorldTransforms, bonesInvBinds: bonesInvBindTransforms, bonesGeoBind: baseGeometryBindTransform )
- avatarCollisionMesh = SCNNode(geometry: avatarGeo)
- avatarCollisionMesh.name = "AvatarCollisionMesh"
- // avatarCollisionMesh.isHidden = true
- sceneView.scene?.rootNode.addChildNode(avatarCollisionMesh)
- //TODO
- solver?.simParams.bonesPerVertex = Int32(skinner.boneIndices.componentsPerVector)
- solver?.simParams.vertexCount = Int32(vertices.count)
- solver?.simParams.trianglesCount = Int32(indices.count/3)
- }
- // MARK: - Actions
- @IBAction private func doneButtonPressed(_ sender: UIBarButtonItem) {
- dismiss(animated: true)
- }
- }
- extension AnimatorViewController: SCNSceneRendererDelegate {
- func renderer(_ renderer: SCNSceneRenderer, didApplyAnimationsAtTime time: TimeInterval) {
- guard solver != nil else { return }
- //allow few frames for a warm-up
- if frameCounter > 20 {
- simulatePhysics = true
- }
- if frameCounter > 50 {
- solver?.simParams.sewingStiffness += 0.01
- }
- //end sewing/layering and enter dynamics simulation
- if frameCounter > 150 {
- solver?.setRestPositionsToCurrentPositions()
- solver?.simParams.dynamicsOff = 0
- solver?.simParams.sewingStiffness = 1.0
- solver?.simParams.extraCollisionChecks = 0
- // windStrength = 100
- }
- //start character animation
- if frameCounter > 180 {
- avatarAnimPlayer.speed = avatarAnimSpeed
- avatarHighResAnimPlayer.speed = avatarAnimSpeed
- }
- if frameCounter > 400 {
- // avatarAnimPlayer.speed = 0
- // avatarHighResAnimPlayer.speed = 0
- }
- if frameCounter > 420 {
- // avatarAnimPlayer.speed = avatarAnimSpeed
- // avatarHighResAnimPlayer.speed = avatarAnimSpeed
- // windStrength = 10
- }
- //print("frame: \(frameCounter)")
- if simulatePhysics {
- let timef = Float(time);
- let windStr = cos( timef / 7000 ) * windStrength //+ 40
- let windDir = normalize (simd_float3( sin( timef / 2000 ), cos( timef / 3000 ), sin( timef / 1000 ) ) )
- solver?.simParams.windForce = windDir * windStr
- let skinner = avatarSkinNode.skinner!
- for i in 0..<skinner.bones.count{
- bonesWorldTransforms[i] = skinner.bones[i].presentation.simdWorldTransform
- }
- solver?.setBones(bonesTransforms: bonesWorldTransforms)
- solver?.preStepPhysics()
- // solver.updateUniformGrid()
- for step in 0...solverSubSteps {
- let dt = Float(0.016) / Float(solverSubSteps) //assumes 60fps, 16ms per frame
- let t = Float(step) / Float(solverSubSteps)
- solver?.stepPhysics(dt: dt, t: t, constraintsIterations: solverConstraintsIterations)
- }
- solver?.postStepPhysics()
- }
- frameCounter += 1
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement