├── temp ├── code_layout_chart.jpg ├── twClothSolverTestFixture.py ├── twClothSolverIOPaperBlockoutTestFixture.py └── twClothSolverIOPaperBlockoutDepNode.py ├── ae_template ├── header_tw_cloth_solver.png └── AEverletClothSolverTemplate.mel ├── .gitignore ├── twClothSolver ├── verletClothSolver.cpp ├── verletClothSolver.h ├── vcsPositionConstraintCmd.h ├── verletClothSolverGPU.h ├── verletClothSolverVector.h ├── vcsCollisionConstraintSphereCmd.h ├── verletClothSolverCPU.h ├── verletClothSolverPlugin.h ├── cudaFunctionality.h ├── mVerletClothSolverPlugin.cpp ├── tesselationVisualization.h ├── verletClothSolverGPU.cpp ├── verletClothSolverTypes.h ├── verletClothSolverPlugin.cpp ├── verletClothSolverVector.cpp ├── vcsCollisionConstraintSphereCmd.cpp ├── mVerletClothSolver.h ├── vcsPositionConstraintCmd.cpp ├── verletClothSolverCPU.cpp ├── tesselationVisualization.cpp └── cudaFunctionality.cu ├── twClothSolverBlockout ├── twClothSolverBlockoutPlugins.py ├── twMeshInfoCmd.py ├── twClothSolverIOPaperBlockoutTestFixture.py ├── twCheckCollision.py └── twDrawBB.py ├── README.md └── uml ├── maya.xmi └── maya.uml /temp/code_layout_chart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timmwagener/tw_cloth_solver/HEAD/temp/code_layout_chart.jpg -------------------------------------------------------------------------------- /ae_template/header_tw_cloth_solver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timmwagener/tw_cloth_solver/HEAD/ae_template/header_tw_cloth_solver.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Ignore 4 | x64 5 | Debug 6 | *.sln 7 | *.suo 8 | *.sdf 9 | *.log 10 | *.htm 11 | *.db 12 | *.pyc 13 | 14 | #un-ignore 15 | twClothSolver/* 16 | !twClothSolver/*.h 17 | !twClothSolver/*.cpp 18 | !twClothSolver/*.cu 19 | 20 | twClothSolverBlockout/* 21 | !twClothSolverBlockout/*.py -------------------------------------------------------------------------------- /twClothSolver/verletClothSolver.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VerletClothSolver Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "verletClothSolver.h" 10 | 11 | 12 | //VerletClothSolver 13 | //----------------------------------------------- 14 | 15 | //Attributes 16 | 17 | 18 | //Methods 19 | VerletClothSolver::VerletClothSolver(){}; 20 | VerletClothSolver::~VerletClothSolver(){}; 21 | 22 | 23 | -------------------------------------------------------------------------------- /twClothSolver/verletClothSolver.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVER_H 4 | #define VERLETCLOTHSOLVER_H 5 | 6 | 7 | //VerletClothSolver Declaration 8 | //----------------------------------------------- 9 | 10 | 11 | //include 12 | //----------------------------------------------- 13 | #include 14 | #include 15 | #include "verletClothSolverTypes.h" 16 | 17 | 18 | 19 | 20 | //VerletClothSolver 21 | //----------------------------------------------- 22 | class VerletClothSolver 23 | { 24 | public: 25 | //Attributes 26 | //Methods 27 | VerletClothSolver(); 28 | ~VerletClothSolver(); 29 | 30 | virtual void solve(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) = 0; 31 | 32 | virtual solver_t getType(){return BASE;}; 33 | 34 | 35 | }; 36 | 37 | 38 | 39 | #endif -------------------------------------------------------------------------------- /twClothSolver/vcsPositionConstraintCmd.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VCSPOSITIONCONSTRAINTCMD_H 4 | #define VCSPOSITIONCONSTRAINTCMD_H 5 | 6 | //VcsPositionConstraintCmd Declaration 7 | //----------------------------------------------- 8 | 9 | 10 | //include 11 | //----------------------------------------------- 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | 32 | //VcsPositionConstraintCmd 33 | //----------------------------------------------- 34 | class VcsPositionConstraintCmd: public MPxCommand 35 | { 36 | public: 37 | //Attrs 38 | bool verbose; 39 | //Methods 40 | VcsPositionConstraintCmd(); 41 | ~VcsPositionConstraintCmd(); 42 | static void* create(); 43 | virtual MStatus doIt(const MArgList &args); 44 | 45 | }; 46 | 47 | 48 | 49 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverGPU.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVERGPU_CUH 4 | #define VERLETCLOTHSOLVERGPU_CUH 5 | 6 | 7 | //VerletClothSolverGPU Declaration 8 | //----------------------------------------------- 9 | 10 | 11 | //include 12 | //----------------------------------------------- 13 | #include "verletClothSolver.h" 14 | #include "cudaFunctionality.h" 15 | 16 | //constants 17 | //----------------------------------------------- 18 | 19 | 20 | //VerletClothSolverGPU 21 | //----------------------------------------------- 22 | class VerletClothSolverGPU: public VerletClothSolver 23 | { 24 | public: 25 | //Attributes 26 | //Methods 27 | VerletClothSolverGPU(); 28 | ~VerletClothSolverGPU(); 29 | 30 | void solve(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 31 | 32 | void verletIntegration(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 33 | void satisfyConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 34 | 35 | void collisionConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 36 | 37 | solver_t getType(){return GPU;}; 38 | 39 | //Cuda 40 | static int cudaAvailable(); 41 | float add_on_gpu(float, float); 42 | 43 | }; 44 | 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverVector.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVERVECTOR_H 4 | #define VERLETCLOTHSOLVERVECTOR_H 5 | 6 | 7 | //VerletClothSolverVector Declaration 8 | //----------------------------------------------- 9 | 10 | 11 | //include 12 | //----------------------------------------------- 13 | #include 14 | 15 | 16 | //VerletClothSolverVector 17 | //----------------------------------------------- 18 | class VerletClothSolverVector 19 | { 20 | public: 21 | //Attributes 22 | float x,y,z,w; 23 | //Methods 24 | VerletClothSolverVector(); 25 | VerletClothSolverVector(float aX, float aY, float aZ); 26 | ~VerletClothSolverVector(); 27 | 28 | VerletClothSolverVector operator+(VerletClothSolverVector rhsVec); 29 | VerletClothSolverVector operator-(VerletClothSolverVector rhsVec); 30 | VerletClothSolverVector operator*(const float &rhsScalar); 31 | VerletClothSolverVector operator/(const float &rhsScalar); 32 | bool operator==(VerletClothSolverVector &rhsVec); 33 | bool operator!=(VerletClothSolverVector &rhsVec); 34 | 35 | float length(); 36 | VerletClothSolverVector normal(); 37 | float angle(VerletClothSolverVector &rhsVec); 38 | float dot(VerletClothSolverVector &rhsVec); 39 | VerletClothSolverVector cross(VerletClothSolverVector &rhsVec); 40 | 41 | }; 42 | 43 | 44 | 45 | #endif -------------------------------------------------------------------------------- /twClothSolver/vcsCollisionConstraintSphereCmd.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VCSCOLLISIONCONSTRAINTSPHERECMD_H 4 | #define VCSCOLLISIONCONSTRAINTSPHERECMD_H 5 | 6 | //VcsCollisionConstraintSphereCmd Declaration 7 | //----------------------------------------------- 8 | 9 | 10 | //include 11 | //----------------------------------------------- 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | 31 | 32 | //VcsCollisionConstraintSphereCmd 33 | //----------------------------------------------- 34 | class VcsCollisionConstraintSphereCmd: public MPxCommand 35 | { 36 | public: 37 | //Attrs 38 | bool verbose; 39 | //Methods 40 | VcsCollisionConstraintSphereCmd(); 41 | ~VcsCollisionConstraintSphereCmd(); 42 | static void* create(); 43 | virtual MStatus doIt(const MArgList &args); 44 | 45 | }; 46 | 47 | 48 | 49 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverCPU.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVERCPU_H 4 | #define VERLETCLOTHSOLVERCPU_H 5 | 6 | 7 | //VerletClothSolverCPU Declaration 8 | //----------------------------------------------- 9 | 10 | 11 | //include 12 | //----------------------------------------------- 13 | #include "verletClothSolver.h" 14 | 15 | 16 | //VerletClothSolverCPU 17 | //----------------------------------------------- 18 | class VerletClothSolverCPU: public VerletClothSolver 19 | { 20 | public: 21 | //Attributes 22 | //Methods 23 | VerletClothSolverCPU(); 24 | ~VerletClothSolverCPU(); 25 | 26 | void solve(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 27 | 28 | void verletIntegration(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 29 | void satisfyConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 30 | 31 | void collisionConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 32 | void collisionConstraintGroundplane(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 33 | void collisionConstraintSpheres(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 34 | void collisionConstraintConvex(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 35 | 36 | void stickConstraint(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 37 | 38 | void positionConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData); 39 | 40 | solver_t getType(){return CPU;}; 41 | 42 | 43 | }; 44 | 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverPlugin.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVERPLUGIN_H 4 | #define VERLETCLOTHSOLVERPLUGIN_H 5 | 6 | //VerletClothSolverPlugin Declaration 7 | //----------------------------------------------- 8 | 9 | 10 | //include 11 | //----------------------------------------------- 12 | #include "verletClothSolverCPU.h" 13 | #include "verletClothSolverGPU.h" 14 | 15 | 16 | 17 | //VerletClothSolverPlugin 18 | //----------------------------------------------- 19 | class VerletClothSolverPlugin 20 | { 21 | public: 22 | //Attributes 23 | staticSolverData_t staticSolverData; 24 | staticSolverData_t staticSolverDataGPU; 25 | dynamicSolverData_t dynamicSolverData; 26 | dynamicSolverData_t dynamicSolverDataGPU; 27 | 28 | //Methods 29 | VerletClothSolverPlugin(); 30 | ~VerletClothSolverPlugin(); 31 | 32 | //VerletClothSolverPlugin 33 | void solve(solver_t solverType); 34 | void initSolver(solver_t solverType); 35 | solver_t getType(){return solver->getType();}; 36 | 37 | //staticSolverData 38 | staticSolverData_t getStaticSolverData(){return staticSolverData;}; 39 | virtual void setStaticSolverData(void* proprietaryData) = 0; 40 | void set_static_solver_data_gpu(); 41 | void set_static_solver_data_from_gpu(); 42 | bool is_static_solver_data_initialized(); 43 | virtual void printStaticSolverData() = 0; 44 | 45 | //dynamicSolverData 46 | dynamicSolverData_t getDynamicSolverData(){return dynamicSolverData;}; 47 | virtual void setDynamicSolverData(void* proprietaryData) = 0; 48 | void set_dynamic_solver_data_gpu(); 49 | virtual void printDynamicSolverData() = 0; 50 | 51 | 52 | 53 | private: 54 | //Attributes 55 | VerletClothSolver* solver; 56 | //Methods 57 | 58 | }; 59 | 60 | 61 | 62 | #endif -------------------------------------------------------------------------------- /twClothSolver/cudaFunctionality.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef CUDAFUNCTIONALITY_H 4 | #define CUDAFUNCTIONALITY_H 5 | 6 | //include 7 | //----------------------------------------------- 8 | //std 9 | #include 10 | 11 | //own 12 | #include "verletClothSolverTypes.h" 13 | 14 | 15 | //constants 16 | //----------------------------------------------- 17 | 18 | 19 | 20 | 21 | //declarations 22 | //----------------------------------------------- 23 | namespace cuda 24 | { 25 | 26 | //cudaAvailable 27 | int cudaAvailable(); 28 | //get_grid_size 29 | int get_grid_size(const staticSolverData_t&, const dynamicSolverData_t&, grid_size_t); 30 | //get_thread_count 31 | int get_thread_count(const dynamicSolverData_t&); 32 | 33 | //add_on_gpu 34 | float add_on_gpu(float, float); 35 | 36 | //set_static_solver_data_gpu 37 | void set_static_solver_data_gpu(staticSolverData_t&, const staticSolverData_t&); 38 | //set_dynamic_solver_data_gpu 39 | void set_dynamic_solver_data_gpu(dynamicSolverData_t&, const dynamicSolverData_t&, const staticSolverData_t&); 40 | //set_static_solver_data_from_gpu 41 | void set_static_solver_data_from_gpu(staticSolverData_t&, staticSolverData_t&); 42 | 43 | //verletIntegration 44 | void verletIntegration(staticSolverData_t&, dynamicSolverData_t&); 45 | //collisionConstraintGroundplane 46 | void collisionConstraintGroundplane(staticSolverData_t&, dynamicSolverData_t&); 47 | //collisionConstraintSpheres 48 | void collisionConstraintSpheres(staticSolverData_t&, dynamicSolverData_t&); 49 | //collisionConstraintConvex 50 | void collisionConstraintConvex(staticSolverData_t&, dynamicSolverData_t&); 51 | 52 | //stickConstraint 53 | void stickConstraint(staticSolverData_t&, dynamicSolverData_t&); 54 | 55 | //positionConstraints 56 | void positionConstraints(staticSolverData_t&, dynamicSolverData_t&); 57 | 58 | 59 | 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /twClothSolver/mVerletClothSolverPlugin.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //MVerletClothSolverPlugin Implementation 4 | //----------------------------------------------- 5 | /* 6 | Exported functions that maya uses to register the plugin 7 | */ 8 | 9 | //Preprocessor 10 | //----------------------------------------------- 11 | #define EXPORT __declspec(dllexport) 12 | 13 | 14 | //include 15 | //----------------------------------------------- 16 | #include 17 | //clothSolver 18 | #include "mVerletClothSolver.h" 19 | #include "vcsPositionConstraintCmd.h" 20 | #include "vcsCollisionConstraintSphereCmd.h" 21 | 22 | //test 23 | #include "tesselationVisualization.h" 24 | 25 | 26 | 27 | //initialize 28 | //----------------------------------------------- 29 | EXPORT MStatus initializePlugin(MObject obj) 30 | { 31 | MStatus status; 32 | 33 | //initialize plugin functionset 34 | MFnPlugin fnPlugin(obj, "Timm Wagener", "0.1", "2012"); 35 | 36 | //clothSolver 37 | status = fnPlugin.registerCommand("vcsPositionConstraint", VcsPositionConstraintCmd::create); 38 | status = fnPlugin.registerCommand("vcsCollisionConstraintSphere", VcsCollisionConstraintSphereCmd::create); 39 | status = fnPlugin.registerNode(MVerletClothSolver::typeName, MVerletClothSolver::id, MVerletClothSolver::create, MVerletClothSolver::initialize, MPxNode::kLocatorNode); 40 | //test 41 | status = fnPlugin.registerNode(TesselationVisualization::typeName, TesselationVisualization::id, TesselationVisualization::create, TesselationVisualization::initialize, MPxNode::kLocatorNode); 42 | 43 | return MStatus::kSuccess; 44 | } 45 | 46 | 47 | //uninitialize 48 | //----------------------------------------------- 49 | EXPORT MStatus uninitializePlugin(MObject obj) 50 | { 51 | MStatus status; 52 | 53 | //initialize plugin functionset 54 | MFnPlugin fnPlugin(obj); 55 | 56 | //clothSolver 57 | status = fnPlugin.deregisterCommand("vcsPositionConstraint"); 58 | status = fnPlugin.deregisterCommand("vcsCollisionConstraintSphere"); 59 | status = fnPlugin.deregisterNode(MVerletClothSolver::id); 60 | //test 61 | status = fnPlugin.deregisterNode(TesselationVisualization::id); 62 | 63 | return MStatus::kSuccess; 64 | } 65 | -------------------------------------------------------------------------------- /twClothSolverBlockout/twClothSolverBlockoutPlugins.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Import 4 | #------------------------------------------------------------------------------------- 5 | import maya.OpenMayaMPx as OpenMayaMPx 6 | #PlugIns 7 | import twClothSolverIOPaperBlockout 8 | import twMeshInfoCmd 9 | import twCheckCollision 10 | import twDrawBB 11 | 12 | 13 | #reload 14 | doReload = True 15 | if(doReload): reload(twClothSolverIOPaperBlockout),reload(twMeshInfoCmd), reload(twCheckCollision), reload(twDrawBB) 16 | 17 | 18 | 19 | 20 | 21 | 22 | #Plugin Registration 23 | #------------------------------------------------------------------------------------- 24 | 25 | 26 | def initializePlugin(mobject): 27 | '''Register Plugin''' 28 | 29 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 30 | try: 31 | mplugin.registerCommand('MeshInfo', twMeshInfoCmd.createTwMeshInfoCmd) 32 | mplugin.registerNode( twCheckCollision.TwCheckCollision.kPluginNodeName, twCheckCollision.TwCheckCollision.kPluginNodeId, twCheckCollision.createTwCheckCollision, twCheckCollision.initializeTwCheckCollision, OpenMayaMPx.MPxNode.kLocatorNode) 33 | mplugin.registerNode( twDrawBB.TwDrawBB.kPluginNodeName, twDrawBB.TwDrawBB.kPluginNodeId, twDrawBB.createTwDrawBB, twDrawBB.initializeTwDrawBB, OpenMayaMPx.MPxNode.kLocatorNode) 34 | mplugin.registerNode( twClothSolverIOPaperBlockout.TwClothSolverIOPaperBlockout.kPluginNodeName, twClothSolverIOPaperBlockout.TwClothSolverIOPaperBlockout.kPluginNodeId, twClothSolverIOPaperBlockout.createTwClothSolverIOPaperBlockout, twClothSolverIOPaperBlockout.initializeTwClothSolverIOPaperBlockout, OpenMayaMPx.MPxNode.kLocatorNode) 35 | except: 36 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ) 37 | raise 38 | 39 | 40 | def uninitializePlugin(mobject): 41 | '''Deregister Plugin''' 42 | 43 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 44 | try: 45 | mplugin.deregisterCommand('MeshInfo') 46 | mplugin.deregisterNode( twCheckCollision.TwCheckCollision.kPluginNodeId ) 47 | mplugin.deregisterNode( twDrawBB.TwDrawBB.kPluginNodeId ) 48 | mplugin.deregisterNode( twClothSolverIOPaperBlockout.TwClothSolverIOPaperBlockout.kPluginNodeId ) 49 | except: 50 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ) 51 | raise -------------------------------------------------------------------------------- /twClothSolver/tesselationVisualization.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef TESSELATIONVISUALIZATION_H 4 | #define TESSELATIONVISUALIZATION_H 5 | 6 | //TesselationVisualization Declaration 7 | //----------------------------------------------- 8 | 9 | 10 | //include 11 | //----------------------------------------------- 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | 35 | 36 | 37 | //drawData_t 38 | //----------------------------------------------- 39 | struct tesselationDrawData_t 40 | { 41 | //Attrs 42 | std::vector> edgeVertexPositionList; 43 | //Methods 44 | tesselationDrawData_t(){}; 45 | ~tesselationDrawData_t(){}; 46 | }; 47 | 48 | 49 | //TesselationVisualization 50 | //----------------------------------------------- 51 | class TesselationVisualization: public MPxLocatorNode 52 | { 53 | public: 54 | //Attributes 55 | static MTypeId id; 56 | static MString typeName; 57 | 58 | static MObject aVerbose; 59 | 60 | static MObject aTesselationType; 61 | 62 | static MObject aInputGeo; 63 | static MObject aOutputGeo; 64 | 65 | static MObject aCurrentFrame; 66 | 67 | //Methods 68 | TesselationVisualization(); 69 | virtual ~TesselationVisualization(); 70 | static void* create(); 71 | static MStatus initialize(); 72 | virtual MStatus compute(const MPlug &plug, MDataBlock &data); 73 | virtual void draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus); 74 | 75 | //drawData 76 | void setTesselationDrawData(MDataBlock &data); 77 | void setEdgeVertexPositionList(MDataBlock &data); 78 | void setEdgeVertexPositionListStructural(MDataBlock &data); 79 | void setEdgeVertexPositionListShear(MDataBlock &data); 80 | 81 | private: 82 | //Attributes 83 | tesselationDrawData_t drawData; 84 | 85 | //Methods 86 | }; 87 | 88 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverGPU.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VerletClothSolverGPU Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "verletClothSolverGPU.h" 10 | 11 | 12 | //VerletClothSolverGPU 13 | //----------------------------------------------- 14 | 15 | //Attributes 16 | 17 | 18 | //Methods 19 | VerletClothSolverGPU::VerletClothSolverGPU(){}; 20 | VerletClothSolverGPU::~VerletClothSolverGPU(){}; 21 | 22 | 23 | //solve 24 | void VerletClothSolverGPU::solve(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) 25 | { 26 | verletIntegration(staticSolverData, dynamicSolverData); 27 | for(int index = 1; index <= dynamicSolverData.repetitions; index++) 28 | { 29 | satisfyConstraints(staticSolverData, dynamicSolverData); 30 | }; 31 | 32 | }; 33 | 34 | //verletIntegration 35 | void VerletClothSolverGPU::verletIntegration(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) 36 | { 37 | //verletIntegration 38 | cuda::verletIntegration(staticSolverData, dynamicSolverData); 39 | 40 | //log 41 | //std::cout<<"verletIntegrationGPU"< 4 | 5 | 6 | ----------------------- 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | ----------------------- 16 | 17 | [![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/timmwagener/tw_cloth_solver) 18 | 19 | ----------------------- 20 | 21 | 22 | What is it ? 23 | ----------------------- 24 | **twClothSolver** is a **Verlet Cloth Solver** implemented as a Maya Plugin. I created this as a university test project to explore the possibilities of GPU multithreading 25 | within the context of Dependency Graph based VFX centered DCCs. It is by no means a stress-tested production ready solution. 26 | 27 | 28 | Its features include: 29 | * The deformer source code as a Python plugin blockout version 30 | * The C++ API version 31 | * CUDA and OpenMP multithreading, which can be switched during execution 32 | * OOP codebase with solver functionality completely detached from Maya interface, for easy porting to other apps 33 | * Position and convex collision constraints 34 | * OpenGL viewport feedback of solver attributes 35 | * Easy quality/speed balancing thanks to naive repetition based constraint calculation 36 | * Convenience API commands to create and connect constraints 37 | 38 | 39 | ----------------------- 40 | 41 | [**Vimeo**](https://vimeo.com/timmwagener/twclothsolver) [**More info**](http://www.timmwagener.com/gpu_cloth_solver.html) [**Author**](http://www.timmwagener.com/) 42 | 43 | ----------------------- -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverTypes.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef VERLETCLOTHSOLVERTYPES_H 4 | #define VERLETCLOTHSOLVERTYPES_H 5 | 6 | //include 7 | //----------------------------------------------- 8 | 9 | #include "verletClothSolverVector.h" 10 | 11 | 12 | //typedef for VerletClothSolverVector 13 | typedef VerletClothSolverVector vcsVector; 14 | 15 | //declarations 16 | //----------------------------------------------- 17 | 18 | //staticSolverData_t 19 | //----------------------------------------------- 20 | struct staticSolverData_t 21 | { 22 | int vertexCount; 23 | int edgeCount; 24 | vcsVector* pVertexPositionList; 25 | vcsVector* pVertexOldpositionList; 26 | vcsVector* pVertexInitialpositionList; 27 | vcsVector* pEdgeVertexIndexList; 28 | float* pEdgeRestlengthList; 29 | //Methods 30 | staticSolverData_t():pVertexPositionList(0),pVertexOldpositionList(0),pVertexInitialpositionList(0),pEdgeVertexIndexList(0),pEdgeRestlengthList(0){}; 31 | ~staticSolverData_t(){}; 32 | }; 33 | 34 | 35 | //dynamicSolverData_t 36 | //----------------------------------------------- 37 | struct dynamicSolverData_t 38 | { 39 | //Attributes 40 | float drag; 41 | int collisionGroundplaneActive; 42 | float groundplaneHeight; 43 | vcsVector* pVertexForceList; 44 | int repetitions; 45 | int positionConstraintCount; 46 | int* pPositionConstraintActiveList; 47 | int* pPositionConstraintVertexIndexList; 48 | vcsVector* pPositionConstraintCoordinateList; 49 | int collisionConstraintSpheresCount; 50 | vcsVector* pCollisionConstraintSpheresVecUpVecDownList; 51 | int collisionConstraintConvexCount; 52 | int* pCollisionConstraintConvexTriangleCountList; 53 | int collisionConstraintConvexTriangleVertexCount; 54 | vcsVector* pCollisionConstraintConvexTriangleVertexPositionList; 55 | int thread_count; 56 | int omp; 57 | float collisionConstraintConvexOffset; 58 | //Methods 59 | dynamicSolverData_t():pPositionConstraintActiveList(0), pPositionConstraintVertexIndexList(0), pPositionConstraintCoordinateList(0), pCollisionConstraintSpheresVecUpVecDownList(0), pCollisionConstraintConvexTriangleCountList(0), pCollisionConstraintConvexTriangleVertexPositionList(0){}; 60 | ~dynamicSolverData_t(){}; 61 | }; 62 | 63 | 64 | //drawData_t 65 | //----------------------------------------------- 66 | struct drawData_t 67 | { 68 | //Attrs 69 | int collisionConstraintGroundPlaneVisible; 70 | float collisionConstraintGroundplaneDispSize; 71 | float collisionConstraintGroundplaneHeight; 72 | int drawMeshlinesActive; 73 | vcsVector* pVertexColorList; 74 | //Methods 75 | drawData_t():pVertexColorList(0){}; 76 | ~drawData_t(){}; 77 | }; 78 | 79 | 80 | //solver_t 81 | //----------------------------------------------- 82 | enum solver_t 83 | { 84 | BASE = 0, 85 | CPU, 86 | GPU 87 | }; 88 | 89 | //grid_size_t 90 | //----------------------------------------------- 91 | enum grid_size_t 92 | { 93 | VERTEXCOUNT = 0, 94 | EDGECOUNT 95 | }; 96 | 97 | #endif -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverPlugin.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VerletClothSolverPlugin Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "verletClothSolverPlugin.h" 10 | 11 | 12 | //VerletClothSolverPlugin 13 | //----------------------------------------------- 14 | 15 | //Attributes 16 | 17 | //Methods 18 | VerletClothSolverPlugin::VerletClothSolverPlugin() 19 | :solver(0)//Initialisation list for member vars 20 | {}; 21 | 22 | VerletClothSolverPlugin::~VerletClothSolverPlugin(){}; 23 | 24 | //solve 25 | void VerletClothSolverPlugin::solve(solver_t solverType) 26 | { 27 | 28 | 29 | //init? 30 | //----------------------------------------------- 31 | if(!solver) 32 | { 33 | //create new solver 34 | initSolver(solverType); 35 | } 36 | else if(solverType != solver->getType()) 37 | { 38 | //delete old solver 39 | delete solver; 40 | //create new solver 41 | initSolver(solverType); 42 | } 43 | 44 | //solve 45 | //----------------------------------------------- 46 | //CPU 47 | if(solver->getType() == 1) 48 | solver->solve(staticSolverData, dynamicSolverData); 49 | //GPU 50 | else if(solver->getType() == 2) 51 | solver->solve(staticSolverDataGPU, dynamicSolverDataGPU); 52 | }; 53 | 54 | 55 | //initSolver 56 | void VerletClothSolverPlugin::initSolver(solver_t solverType) 57 | { 58 | //create solver 59 | switch(solverType) 60 | { 61 | case GPU: 62 | //If cuda available create GPU 63 | if(VerletClothSolverGPU::cudaAvailable()) 64 | { 65 | solver = new VerletClothSolverGPU(); 66 | break; 67 | } 68 | else 69 | { 70 | //if not CPU version 71 | solver = new VerletClothSolverCPU(); 72 | break; 73 | } 74 | case CPU: 75 | //if not CPU version 76 | solver = new VerletClothSolverCPU(); 77 | break; 78 | default: 79 | break; 80 | } 81 | }; 82 | 83 | 84 | //set_static_solver_data_gpu 85 | void VerletClothSolverPlugin::set_static_solver_data_gpu() 86 | { 87 | //cuda 88 | cuda::set_static_solver_data_gpu(staticSolverDataGPU, staticSolverData); 89 | }; 90 | 91 | //set_dynamic_solver_data_gpu 92 | void VerletClothSolverPlugin::set_dynamic_solver_data_gpu() 93 | { 94 | //cuda 95 | cuda::set_dynamic_solver_data_gpu(dynamicSolverDataGPU, dynamicSolverData, staticSolverData); 96 | }; 97 | 98 | //set_static_solver_data_from_gpu 99 | void VerletClothSolverPlugin::set_static_solver_data_from_gpu() 100 | { 101 | //cuda 102 | cuda::set_static_solver_data_from_gpu(staticSolverData, staticSolverDataGPU); 103 | }; 104 | 105 | //is_static_solver_data_initialized 106 | bool VerletClothSolverPlugin::is_static_solver_data_initialized() 107 | { 108 | //check pVertexPositionList 109 | if(staticSolverData.pVertexPositionList) 110 | return true; 111 | return false; 112 | }; 113 | 114 | //TMP 115 | //----------------------------------------------- -------------------------------------------------------------------------------- /temp/twClothSolverTestFixture.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Test Fixture for twClothSolver 4 | 5 | #variables 6 | sourcePath = 'H:/scripts/c++/twClothSolver/x64/maya_2012_release' 7 | sourceName = 'twClothSolver.mll' 8 | destinationPath = 'H:/scripts/temp/mayaPluginsTest' 9 | 10 | #procedure 11 | import pymel.core as pm 12 | import shutil 13 | 14 | #force restart of maya and unload plugin 15 | #---------------------------------- 16 | try: 17 | #load new scene without saving 18 | pm.mel.eval('file -f -new;') 19 | #if plugin is loaded unload it 20 | if(pm.pluginInfo( sourceName, query=True, loaded=True )):pm.unloadPlugin( sourceName ) 21 | except: 22 | print('Error unloading Plugin') 23 | 24 | 25 | #copy plugin 26 | #---------------------------------- 27 | try: 28 | shutil.copy2(sourcePath +'/' +sourceName, destinationPath) 29 | except: 30 | print('Error copying files') 31 | 32 | #reload plugin 33 | #---------------------------------- 34 | 35 | try: 36 | pm.loadPlugin( sourceName );print('Successfully reloaded plugin') 37 | except: 38 | print('Error Reloading Plugin') 39 | 40 | 41 | 42 | #create testFixture 43 | #---------------------------------- 44 | 45 | #create inputGeo 46 | #---------------------------------- 47 | #inputGeo 48 | inputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 49 | inputGeoShape = inputGeoTrans.getShape() 50 | #transformPlane 51 | inputGeoTrans.translateY.set(5) 52 | inputGeoTrans.visibility.set(0) 53 | pm.select(cl = True) 54 | 55 | 56 | #create outputGeo 57 | #---------------------------------- 58 | #outputGeo 59 | outputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 60 | outputGeoShape = outputGeoTrans.getShape() 61 | pm.select(cl = True) 62 | 63 | #create cloth solver node 64 | #---------------------------------- 65 | clothSolver = pm.createNode('verletClothSolver') 66 | clothSolver.verbose.set(1) 67 | clothSolver.repetitions.set(100) 68 | pm.select(cl = True) 69 | 70 | #set clothSolver gravity 71 | #---------------------------------- 72 | gravityPerSec = -9.8 73 | clothSolver.gravity.set(0,gravityPerSec,0) 74 | 75 | #make connections 76 | #---------------------------------- 77 | #time 78 | timeNode = pm.PyNode('time1') 79 | pm.select(cl = True) 80 | timeNode.outTime >> clothSolver.currentFrame 81 | #inputGeo 82 | inputGeoShape.outMesh >> clothSolver.inputGeo 83 | inputGeoShape.parentMatrix >> clothSolver.transformMatrix 84 | #outputGeo 85 | clothSolver.outputGeo >> outputGeoShape.inMesh 86 | 87 | 88 | #create constraints 89 | #---------------------------------- 90 | 91 | #vcsPositionConstraint1 92 | pm.select("{0}.vtx[0]".format(inputGeoTrans.name()), r = True) 93 | pm.mel.eval('vcsPositionConstraint;') 94 | pm.select(cl = True) 95 | 96 | #vcsPositionConstraint2 97 | pm.select("{0}.vtx[110]".format(inputGeoTrans.name()), r = True) 98 | pm.mel.eval('vcsPositionConstraint;') 99 | pm.select(cl = True) 100 | 101 | 102 | 103 | #adjust timeline 104 | #---------------------------------- 105 | pm.playbackOptions(ast = 1, aet = 1000, min = 1, max = 1000) 106 | 107 | #select solver 108 | #---------------------------------- 109 | pm.select(cl = True) 110 | pm.select(clothSolver, r = True) -------------------------------------------------------------------------------- /uml/maya.xmi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ArgoUML (using Netbeans XMI Writer version 1.0) 5 | 0.34(6) revised on $Date: 2010-01-11 22:20:14 +0100 (Mon, 11 Jan 2010) $ 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 19 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverVector.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VerletClothSolverVector Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "verletClothSolverVector.h" 10 | 11 | 12 | //VerletClothSolver 13 | //----------------------------------------------- 14 | 15 | //Attributes 16 | 17 | 18 | //Methods 19 | 20 | //Default constructor 21 | VerletClothSolverVector::VerletClothSolverVector() 22 | :x(0.0),y(0.0),z(0.0),w(1.0) 23 | {}; 24 | //Explicit constructor 25 | VerletClothSolverVector::VerletClothSolverVector(float aX, float aY, float aZ) 26 | :x(aX),y(aY),z(aZ),w(1.0) 27 | {}; 28 | 29 | //Destructor 30 | VerletClothSolverVector::~VerletClothSolverVector(){}; 31 | 32 | //Arithmetic Operator Overload: + 33 | VerletClothSolverVector VerletClothSolverVector::operator+(VerletClothSolverVector rhsVec) 34 | { 35 | float tempX = x + rhsVec.x; 36 | float tempY = y + rhsVec.y; 37 | float tempZ = z + rhsVec.z; 38 | return VerletClothSolverVector(tempX,tempY,tempZ); 39 | }; 40 | 41 | //Arithmetic Operator Overload: - 42 | VerletClothSolverVector VerletClothSolverVector::operator-(VerletClothSolverVector rhsVec) 43 | { 44 | float tempX = x - rhsVec.x; 45 | float tempY = y - rhsVec.y; 46 | float tempZ = z - rhsVec.z; 47 | return VerletClothSolverVector(tempX,tempY,tempZ); 48 | }; 49 | 50 | //Arithmetic Operator Overload: * 51 | VerletClothSolverVector VerletClothSolverVector::operator*(const float &rhsScalar) 52 | { 53 | float tempX = x * rhsScalar; 54 | float tempY = y * rhsScalar; 55 | float tempZ = z * rhsScalar; 56 | return VerletClothSolverVector(tempX,tempY,tempZ); 57 | }; 58 | 59 | //Arithmetic Operator Overload: / 60 | VerletClothSolverVector VerletClothSolverVector::operator/(const float &rhsScalar) 61 | { 62 | float tempX = x / rhsScalar; 63 | float tempY = y / rhsScalar; 64 | float tempZ = z / rhsScalar; 65 | return VerletClothSolverVector(tempX,tempY,tempZ); 66 | }; 67 | 68 | //Comparison Operator == 69 | bool VerletClothSolverVector::operator==(VerletClothSolverVector &rhsVec) 70 | { 71 | return (x == rhsVec.x && y == rhsVec.y && z == rhsVec.z); 72 | }; 73 | 74 | //Negative Comparison Operator 75 | bool VerletClothSolverVector::operator!=(VerletClothSolverVector &rhsVec) 76 | { 77 | return (x != rhsVec.x && y != rhsVec.y && z != rhsVec.z); 78 | }; 79 | 80 | //length 81 | float VerletClothSolverVector::length() 82 | { 83 | float length = float(sqrt((x*x) + (y*y) +(z*z))); 84 | return length; 85 | }; 86 | 87 | //normal 88 | VerletClothSolverVector VerletClothSolverVector::normal() 89 | { 90 | float length = float(sqrt((x*x) + (y*y) +(z*z))); 91 | return VerletClothSolverVector(x/length, y/length, z/length); 92 | }; 93 | 94 | //angle 95 | float VerletClothSolverVector::angle(VerletClothSolverVector &rhsVec) 96 | { 97 | //dot product 98 | float dotProduct = dot(rhsVec); 99 | 100 | //rhsVecLength 101 | float rhsVecLength = rhsVec.length(); 102 | 103 | //cosAngle 104 | float cosAngle = dotProduct / (length() * rhsVecLength); 105 | 106 | //angle 107 | float angle = acos(cosAngle) * (180.0 / 3.14159265); 108 | 109 | return angle; 110 | }; 111 | 112 | //dot 113 | float VerletClothSolverVector::dot(VerletClothSolverVector &rhsVec) 114 | { 115 | //multiply x,y,z 116 | float multipliedX = x * rhsVec.x; 117 | float multipliedY = y * rhsVec.y; 118 | float multipliedZ = z * rhsVec.z; 119 | 120 | return (multipliedX+multipliedY+multipliedZ); 121 | 122 | }; 123 | 124 | //cross 125 | VerletClothSolverVector VerletClothSolverVector::cross(VerletClothSolverVector &rhsVec) 126 | { 127 | //crossX 128 | float crossX = y*rhsVec.z - z*rhsVec.y; 129 | float crossY = z*rhsVec.x - x*rhsVec.z; 130 | float crossZ = x*rhsVec.y - y*rhsVec.x; 131 | 132 | return VerletClothSolverVector(crossX, crossY, crossZ); 133 | 134 | }; 135 | -------------------------------------------------------------------------------- /twClothSolver/vcsCollisionConstraintSphereCmd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | //VcsCollisionConstraintSphereCmd Implementation 6 | //----------------------------------------------- 7 | 8 | 9 | //include 10 | //----------------------------------------------- 11 | #include "vcsCollisionConstraintSphereCmd.h" 12 | 13 | 14 | //VcsCollisionConstraintSphereCmd 15 | //----------------------------------------------- 16 | 17 | //Attrs 18 | 19 | //Methods 20 | VcsCollisionConstraintSphereCmd::VcsCollisionConstraintSphereCmd():verbose(1){}; 21 | VcsCollisionConstraintSphereCmd::~VcsCollisionConstraintSphereCmd(){}; 22 | 23 | //create 24 | void* VcsCollisionConstraintSphereCmd::create() 25 | { 26 | return new VcsCollisionConstraintSphereCmd(); 27 | }; 28 | 29 | //doIt 30 | MStatus VcsCollisionConstraintSphereCmd::doIt(const MArgList &args) 31 | { 32 | //Get active selectionList 33 | //----------------------------------------------- 34 | 35 | //status 36 | MStatus status; 37 | 38 | //get selectionList 39 | MSelectionList selectionList; 40 | MGlobal::getActiveSelectionList(selectionList); 41 | 42 | //if !selectionList return 43 | if(!(selectionList.length() == 2)) 44 | { 45 | if(verbose){MGlobal::displayInfo("Empty SelectionList or wrong number of selected objects. Please select 1 PolySphere and 1 clothSolver.");}; 46 | return MS::kSuccess; 47 | }; 48 | 49 | 50 | 51 | //Iterate active selectionList and get objects 52 | //----------------------------------------------- 53 | 54 | //itSelectionList 55 | MItSelectionList itSelectionList(selectionList); 56 | 57 | //MObjects 58 | MObject oCollisionSphereShape; 59 | MObject oClothSolver; 60 | MObject oTest; 61 | 62 | 63 | //iterate selectionList and get sphere 64 | while(!itSelectionList.isDone()) 65 | { 66 | //get current object 67 | itSelectionList.getDependNode(oTest); 68 | 69 | //check if obj has fn of type transform 70 | //----------------------------------------------- 71 | 72 | if(oTest.hasFn(MFn::kTransform)) 73 | { 74 | //Check if object has child of type mesh 75 | 76 | //MFnDagNode 77 | MFnDagNode fnDagNodeTest(oTest); 78 | MObject oTestShape = fnDagNodeTest.child(0); 79 | 80 | if(oTestShape.hasFn(MFn::kMesh)) 81 | { 82 | //assign to oCollisionSphereShape 83 | oCollisionSphereShape = MObject(oTestShape); 84 | }; 85 | } 86 | 87 | 88 | //check if obj is of type clothSolver 89 | //----------------------------------------------- 90 | 91 | else 92 | { 93 | //Get fnDepNode for object 94 | MFnDependencyNode fnDepNodeTest(oTest); 95 | 96 | //if name == clothSolver then assign 97 | if(fnDepNodeTest.typeName() == "verletClothSolver"){oClothSolver = MObject(oTest);}; 98 | }; 99 | 100 | //advance 101 | itSelectionList.next(); 102 | }; 103 | 104 | //Check if assignments worked correctly 105 | 106 | //create fnDepNode sets 107 | MFnDependencyNode fnDepNodeCollisionSphereShape(oCollisionSphereShape); 108 | MFnDependencyNode fnDepNodeClothSolver(oClothSolver); 109 | 110 | if(fnDepNodeClothSolver.typeName() != "verletClothSolver" || fnDepNodeCollisionSphereShape.typeName() != "mesh") 111 | { 112 | if(verbose){MGlobal::displayInfo("Selection for clothSolver or PolySphere was not correct.");}; 113 | return MS::kSuccess; 114 | }; 115 | 116 | 117 | 118 | //Connect sphereShape to clothSolver 119 | //----------------------------------------------- 120 | 121 | //Get Plugs to clothSolverAttrs 122 | //----------------------------------------------- 123 | 124 | //Get plug to compound array of clothSolver 125 | MPlug pCompoundArrayAttr = fnDepNodeClothSolver.findPlug("collisionConstraint"); 126 | 127 | //lastArrayElementIndex 128 | int lastArrayElementIndex = pCompoundArrayAttr.numElements(); 129 | 130 | 131 | //plug to last array element 132 | MPlug pCompoundAttr = pCompoundArrayAttr.elementByLogicalIndex(lastArrayElementIndex); 133 | 134 | //Get Plugs to children 135 | MPlug pTargetConstraintGeoMatrix = pCompoundAttr.child(2); 136 | MPlug pTargetConstraintGeo = pCompoundAttr.child(3); 137 | 138 | 139 | 140 | //Get Plugs to collisionSphereAttrs 141 | //----------------------------------------------- 142 | 143 | //Matrix 144 | //Get plug to compound array of collisionSphere 145 | MPlug pArrayAttr = fnDepNodeCollisionSphereShape.findPlug("parentMatrix"); 146 | 147 | //GeoMatrix 148 | MPlug pSourceConstraintGeoMatrix = pArrayAttr.elementByLogicalIndex(0); 149 | 150 | //Geo 151 | MPlug pSourceConstraintGeo = fnDepNodeCollisionSphereShape.findPlug("outMesh"); 152 | 153 | 154 | 155 | 156 | //Connect source to target 157 | //----------------------------------------------- 158 | 159 | //connect position plugs 160 | MDGModifier dgModifier; 161 | dgModifier.connect(pSourceConstraintGeoMatrix, pTargetConstraintGeoMatrix); 162 | dgModifier.connect(pSourceConstraintGeo, pTargetConstraintGeo); 163 | dgModifier.doIt(); 164 | 165 | 166 | return MS::kSuccess; 167 | }; -------------------------------------------------------------------------------- /twClothSolver/mVerletClothSolver.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef MVERLETCLOTHSOLVER_H 4 | #define MVERLETCLOTHSOLVER_H 5 | 6 | //MVerletClothSolver Declaration 7 | //----------------------------------------------- 8 | 9 | 10 | //include 11 | //----------------------------------------------- 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | #include "verletClothSolverPlugin.h" 46 | 47 | 48 | 49 | //MVerletClothSolver 50 | //----------------------------------------------- 51 | class MVerletClothSolver: public MPxLocatorNode, public VerletClothSolverPlugin 52 | { 53 | public: 54 | //Attributes 55 | static MTypeId id; 56 | static MString typeName; 57 | 58 | static MObject aVerbose; 59 | static MObject aVerboseStaticSolverData; 60 | static MObject aVerboseDynamicSolverData; 61 | static MObject aVerboseDrawData; 62 | 63 | static MObject aSolverType; 64 | 65 | static MObject aInputGeo; 66 | static MObject aOutputGeo; 67 | 68 | static MObject aStartFrame; 69 | static MObject aCurrentFrame; 70 | 71 | static MObject aGravity; 72 | 73 | static MObject aTransformMatrix; 74 | 75 | static MObject aDrag; 76 | 77 | static MObject aCollisionConstraintGroundplaneActive; 78 | static MObject aCollisionConstraintGroundplaneHeight; 79 | static MObject aCollisionConstraintGroundplaneVisible; 80 | static MObject aCollisionConstraintGroundplaneDispSize; 81 | 82 | static MObject aCollisionConstraint; 83 | static MObject aCollisionConstraintActive; 84 | static MObject aCollisionConstraintType; 85 | static MObject aCollisionConstraintGeoMatrix; 86 | static MObject aCollisionConstraintGeo; 87 | 88 | static MObject aCollisionConstraintConvexOffset; 89 | 90 | static MObject aRepetitions; 91 | 92 | static MObject aPositionConstraint; 93 | static MObject aPositionConstraintActive; 94 | static MObject aPositionConstraintVertexIndex; 95 | static MObject aPositionConstraintCoordinate; 96 | 97 | static MObject aDrawMeshlinesActive; 98 | static MObject aDrawMeshlinesColorMode; 99 | 100 | static MObject aSolveTriangulated; 101 | 102 | static MObject a_thread_count; 103 | static MObject a_omp; 104 | 105 | //Methods 106 | MVerletClothSolver(); 107 | virtual ~MVerletClothSolver(); 108 | static void* create(); 109 | static MStatus initialize(); 110 | virtual MStatus compute(const MPlug &plug, MDataBlock &data); 111 | virtual void draw(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus); 112 | 113 | 114 | //staticSolverData 115 | void setStaticSolverData(void* proprietaryData); 116 | void printStaticSolverData(); 117 | void setVertexCount(MDataBlock &data); 118 | void setVertexPositionList(MDataBlock &data); 119 | void setVertexOldpositionList(MDataBlock &data); 120 | void setVertexInitialpositionList(MDataBlock &data); 121 | void setEdgeVertexIndexListAndCount(MDataBlock &data); 122 | void setEdgeRestlengthList(MDataBlock &data); 123 | 124 | //dynamicSolverData 125 | void setDynamicSolverData(void* proprietaryData); 126 | void printDynamicSolverData(); 127 | void setVertexForceList(MDataBlock &data); 128 | void setPositionConstraintCount(MDataBlock &data); 129 | void setPositionConstraintActiveList(MDataBlock &data); 130 | void setPositionConstraintVertexIndexList(MDataBlock &data); 131 | void setPositionConstraintCoordinateList(MDataBlock &data); 132 | void setCollisionConstraintSpheresCountAndVecUpVecDownList(MDataBlock &data); 133 | void setCollisionConstraintConvexCountAndTriangleCountList(MDataBlock &data); 134 | void setCollisionConstraintConvexTriangleVertexPositionList(MDataBlock &data); 135 | void setCollisionConstraintConvexOffset(MDataBlock&); 136 | void set_thread_count_and_omp(MDataBlock&); 137 | 138 | //drawData 139 | void setDrawData(MDataBlock &data); 140 | void printDrawData(); 141 | void setVertexColorList(MDataBlock &data); 142 | void setVertexColorListMono(); 143 | void setVertexColorListDistortion(); 144 | void setVertexColorListChange(); 145 | 146 | //draw 147 | void drawCollisionGroundplane(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus displayStatus); 148 | void drawMeshlines(M3dView &view, const MDagPath &path, M3dView::DisplayStyle style, M3dView::DisplayStatus displayStatus); 149 | 150 | //MVerletClothSolver 151 | float getUiFps(); 152 | void setOutputGeo(MDataBlock &data); 153 | bool attributeConnected(MString attributeName); 154 | 155 | //temp 156 | 157 | 158 | private: 159 | //Attributes 160 | float lastFrame; 161 | drawData_t drawData; 162 | 163 | //Methods 164 | 165 | 166 | }; 167 | #endif -------------------------------------------------------------------------------- /uml/maya.uml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 0.34 8 | 9 | 10 | 11 | 12 | 13 | C++ 14 | true 15 | false 16 | true 17 | false 18 | false 19 | false 20 | false 21 | true 22 | false 23 | true 24 | 1 25 | true 26 | Dialog 27 | 12 28 | 0 29 | Class Diagram 30 | 31 | 32 | 33 | 35 | 37 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | ArgoUML (using Netbeans XMI Writer version 1.0) 51 | 0.34(6) revised on $Date: 2010-01-11 22:20:14 +0100 (Mon, 11 Jan 2010) $ 52 | 53 | 54 | 55 | 58 | 59 | 60 | 61 | 62 | 65 | 68 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 96 | 97 | 98 | 99 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /twClothSolverBlockout/twMeshInfoCmd.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twMeshInfoCmd Module 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | 9 | 10 | #Setup Script 11 | #------------------------------------------------------------------------------------- 12 | 13 | ''' 14 | import pymel.core as pm 15 | 16 | 17 | #reload plugin 18 | #---------------------------------- 19 | try: 20 | #load new scene without saving 21 | pm.mel.eval('file -f -new;') 22 | #if plugin is loaded unload and reload it, else reload 23 | if(pm.pluginInfo( 'twClothSolverBlockoutPlugins.py', query=True, loaded=True )): 24 | pm.unloadPlugin( 'twClothSolverBlockoutPlugins.py' ) 25 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 26 | print('Successfully reloaded plugin') 27 | else: 28 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 29 | print('Successfully loaded plugin') 30 | except: 31 | print('Error Reloading Plugin') 32 | 33 | 34 | #MeshInfo 35 | #---------------------------------- 36 | #---------------------------------- 37 | pm.mel.eval('MeshInfo') 38 | 39 | ''' 40 | 41 | 42 | 43 | 44 | 45 | #Imports 46 | #------------------------------------------------------------------------------------- 47 | import sys, math, time, random 48 | import maya.OpenMaya as OpenMaya 49 | import maya.OpenMayaMPx as OpenMayaMPx 50 | import maya.OpenMayaAnim as OpenMayaAnim 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | #TwMeshInfoCmd class 59 | #------------------------------------------------------------------------------------- 60 | class TwMeshInfoCmd(OpenMayaMPx.MPxCommand): 61 | '''MeshInfo utility cmd to display mesh information''' 62 | 63 | def __init__(self): 64 | '''Constructor''' 65 | 66 | #Instance variables 67 | self.verbose = True 68 | self.dividerString = '-------------------------------' 69 | 70 | OpenMayaMPx.MPxCommand.__init__(self) 71 | 72 | 73 | def doIt(self, args): 74 | '''Function that is executed when cmd is executed''' 75 | 76 | #get selectionList 77 | selectionList = OpenMaya.MSelectionList() 78 | OpenMaya.MGlobal.getActiveSelectionList( selectionList ) 79 | 80 | #return if nothing is selected 81 | if(selectionList.length() == 0): 82 | if(self.verbose): OpenMaya.MGlobal.displayInfo('Nothing selected. Please select a poly object.') 83 | return OpenMaya.MStatus.kSuccess 84 | 85 | 86 | #iterate objects, if == polymesh display infos 87 | itSelectionList = OpenMaya.MItSelectionList(selectionList) 88 | 89 | #iterate 90 | while not(itSelectionList.isDone()): 91 | 92 | #get current object and create functionset 93 | currentObject = OpenMaya.MObject() 94 | itSelectionList.getDependNode(currentObject) 95 | currentObjectDagPath = OpenMaya.MDagPath() 96 | itSelectionList.getDagPath(currentObjectDagPath) 97 | fsDepNodeCurrentObject = OpenMaya.MFnDependencyNode(currentObject) 98 | 99 | 100 | #check if current object poly mesh if not continue 101 | if not(fsDepNodeCurrentObject.typeName() == 'mesh'): 102 | if(self.verbose): OpenMaya.MGlobal.displayInfo('%s is not a mesh. Its of type: %s' %(fsDepNodeCurrentObject.name(), fsDepNodeCurrentObject.typeName())) 103 | itSelectionList.next() 104 | continue 105 | 106 | #else display name 107 | OpenMaya.MGlobal.displayInfo('%s' % (fsDepNodeCurrentObject.name())) 108 | OpenMaya.MGlobal.displayInfo(self.dividerString) 109 | 110 | #create mesh functionset 111 | fsMeshCurrentObject = OpenMaya.MFnMesh(currentObjectDagPath) 112 | #create edge iterator 113 | itMeshEdges = OpenMaya.MItMeshEdge(currentObject) 114 | #iterate edges and display infos 115 | while not(itMeshEdges.isDone()): 116 | 117 | edgeIndex = itMeshEdges.index() 118 | 119 | #print edgeIndex 120 | OpenMaya.MGlobal.displayInfo('Edge Index %s' % (edgeIndex)) 121 | 122 | #print Vertex IDs for edgeIndex 123 | util = OpenMaya.MScriptUtil() 124 | util.createFromDouble(0.0) 125 | ptr = util.asInt2Ptr() 126 | fsMeshCurrentObject.getEdgeVertices(edgeIndex, ptr) 127 | 128 | vertexIndex1 = util.getInt2ArrayItem(ptr, 0,0) 129 | vertexIndex2 = util.getInt2ArrayItem(ptr, 0,1) 130 | OpenMaya.MGlobal.displayInfo('VertexIds: %s %s' %(vertexIndex1, vertexIndex2)) 131 | 132 | #print worldSpace position from vertex IDs of edge index 133 | pointIndex1 = OpenMaya.MPoint() 134 | pointIndex2 = OpenMaya.MPoint() 135 | fsMeshCurrentObject.getPoint(vertexIndex1, pointIndex1, OpenMaya.MSpace.kWorld) 136 | fsMeshCurrentObject.getPoint(vertexIndex2, pointIndex2, OpenMaya.MSpace.kWorld) 137 | 138 | OpenMaya.MGlobal.displayInfo('VertexId: %s - %.3f,%.3f,%.3f' %(vertexIndex1, pointIndex1.x, pointIndex1.y, pointIndex1.z)) 139 | OpenMaya.MGlobal.displayInfo('VertexId: %s - %.3f,%.3f,%.3f' %(vertexIndex2, pointIndex2.x, pointIndex2.y, pointIndex2.z)) 140 | 141 | itMeshEdges.next() 142 | 143 | itSelectionList.next() 144 | 145 | 146 | 147 | 148 | 149 | #Success 150 | if(self.verbose): OpenMaya.MGlobal.displayInfo('MeshInfo cmd executed successfully') 151 | return OpenMaya.MStatus.kSuccess 152 | 153 | 154 | 155 | 156 | 157 | 158 | #Initialization 159 | #------------------------------------------------------------------------------------- 160 | 161 | def createTwMeshInfoCmd(): 162 | '''Creator function for TwMeshInfoCmd. Delivers pointer to instance''' 163 | return OpenMayaMPx.asMPxPtr(TwMeshInfoCmd()) -------------------------------------------------------------------------------- /ae_template/AEverletClothSolverTemplate.mel: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | //----------------------------------------- 5 | //----------------------------------------- 6 | //twClothSolver Attribute Editor Template 7 | //----------------------------------------- 8 | //----------------------------------------- 9 | 10 | 11 | 12 | 13 | //AEverletClothSolverTemplate 14 | global proc AEverletClothSolverTemplate(string $nodeName) { 15 | 16 | 17 | 18 | //Vars 19 | //----------------------------------------- 20 | //----------------------------------------- 21 | string $node[]; 22 | tokenize $nodeName "." $node; 23 | 24 | 25 | 26 | //Header image 27 | //----------------------------------------- 28 | //----------------------------------------- 29 | 30 | //create header image 31 | editorTemplate -callCustom "verletClothSolver_create_header_image" "verletClothSolver_update_header_image" "Dummy"; 32 | 33 | 34 | 35 | //scroll layout 36 | editorTemplate -beginScrollLayout; 37 | 38 | 39 | 40 | //Debugging 41 | //----------------------------------------- 42 | //----------------------------------------- 43 | editorTemplate -beginLayout "Debugging" -collapse 0; 44 | 45 | //verbose 46 | editorTemplate -addControl "verbose"; 47 | 48 | //verboseStaticSolverData 49 | editorTemplate -addControl "verboseStaticSolverData"; 50 | 51 | //verboseDynamicSolverData 52 | editorTemplate -addControl "verboseDynamicSolverData"; 53 | 54 | //verboseDrawData 55 | editorTemplate -addControl "verboseDrawData"; 56 | 57 | //End Layout 58 | editorTemplate -endLayout; 59 | 60 | 61 | 62 | //Solver Settings 63 | //----------------------------------------- 64 | //----------------------------------------- 65 | editorTemplate -beginLayout "Solver Settings" -collapse 0; 66 | 67 | //solverType 68 | editorTemplate -addControl "solverType"; 69 | 70 | //thread_count 71 | editorTemplate -addControl "thread_count"; 72 | 73 | //omp 74 | editorTemplate -addControl "omp"; 75 | 76 | //repetitions 77 | editorTemplate -addControl "repetitions"; 78 | 79 | //solveTriangulated 80 | editorTemplate -addControl "solveTriangulated"; 81 | 82 | 83 | 84 | //Separator 85 | editorTemplate -addSeparator; 86 | 87 | //startFrame 88 | editorTemplate -addControl "startFrame"; 89 | 90 | //currentFrame 91 | editorTemplate -addControl "currentFrame"; 92 | 93 | //gravity 94 | editorTemplate -addControl "gravity"; 95 | 96 | //drag 97 | editorTemplate -addControl "drag"; 98 | 99 | //End Layout 100 | editorTemplate -endLayout; 101 | 102 | 103 | 104 | //Input Geometry 105 | //----------------------------------------- 106 | //----------------------------------------- 107 | editorTemplate -beginLayout "Input Geometry" -collapse 1; 108 | 109 | //inputGeo 110 | editorTemplate -addControl "inputGeo"; 111 | 112 | //transformMatrix 113 | editorTemplate -addControl "transformMatrix"; 114 | 115 | //outputGeo 116 | editorTemplate -addControl "outputGeo"; 117 | 118 | //End Layout 119 | editorTemplate -endLayout; 120 | 121 | 122 | 123 | //Constraints 124 | //----------------------------------------- 125 | //----------------------------------------- 126 | editorTemplate -beginLayout "Constraints" -collapse 0; 127 | 128 | 129 | 130 | //Collision 131 | //----------------------------------------- 132 | //----------------------------------------- 133 | editorTemplate -beginLayout "Collision" -collapse 0; 134 | 135 | //collisionConstraintConvexOffset 136 | editorTemplate -addControl "collisionConstraintConvexOffset"; 137 | 138 | //collisionConstraint 139 | editorTemplate -addControl "collisionConstraint"; 140 | 141 | //End Layout 142 | editorTemplate -endLayout; 143 | 144 | 145 | 146 | //Position 147 | //----------------------------------------- 148 | //----------------------------------------- 149 | editorTemplate -beginLayout "Position" -collapse 0; 150 | 151 | //positionConstraint 152 | editorTemplate -addControl "positionConstraint"; 153 | 154 | //End Layout 155 | editorTemplate -endLayout; 156 | 157 | 158 | 159 | //Ground Plane 160 | //----------------------------------------- 161 | //----------------------------------------- 162 | editorTemplate -beginLayout "Ground Plane" -collapse 0; 163 | 164 | //collisionConstraintGroundplaneActive 165 | editorTemplate -addControl "collisionConstraintGroundplaneActive"; 166 | 167 | //collisionConstraintGroundplaneVisible 168 | editorTemplate -addControl "collisionConstraintGroundplaneVisible"; 169 | 170 | //collisionConstraintGroundplaneHeight 171 | editorTemplate -addControl "collisionConstraintGroundplaneHeight"; 172 | 173 | //collisionConstraintGroundplaneDispSize 174 | editorTemplate -addControl "collisionConstraintGroundplaneDispSize"; 175 | 176 | //End Layout 177 | editorTemplate -endLayout; 178 | 179 | //End Layout 180 | editorTemplate -endLayout; 181 | 182 | 183 | 184 | //Visualization 185 | //----------------------------------------- 186 | //----------------------------------------- 187 | editorTemplate -beginLayout "Visualization" -collapse 0; 188 | 189 | //drawMeshlinesActive 190 | editorTemplate -addControl "drawMeshlinesActive"; 191 | 192 | //drawMeshlinesColorMode 193 | editorTemplate -addControl "drawMeshlinesColorMode"; 194 | 195 | //End Layout 196 | editorTemplate -endLayout; 197 | 198 | 199 | 200 | 201 | 202 | 203 | //Extra controls for unspecified attributes 204 | //----------------------------------------- 205 | //----------------------------------------- 206 | editorTemplate -addExtraControls; 207 | 208 | 209 | 210 | 211 | 212 | 213 | //end scroll layout 214 | editorTemplate -endScrollLayout; 215 | 216 | 217 | 218 | 219 | 220 | 221 | } 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | //Header image procedures 232 | //----------------------------------------- 233 | //----------------------------------------- 234 | 235 | global proc verletClothSolver_create_header_image(string $nodeName) 236 | { 237 | //Header 238 | image -w 400 -h 100 -image "header_tw_cloth_solver.png"; 239 | } 240 | 241 | 242 | global proc verletClothSolver_update_header_image(string $nodeName) 243 | {} 244 | 245 | 246 | 247 | 248 | 249 | 250 | -------------------------------------------------------------------------------- /temp/twClothSolverIOPaperBlockoutTestFixture.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twClothSolverIOPaperBlockout Test Fixture 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | import pymel.core as pm 9 | 10 | 11 | #reload plugin 12 | #---------------------------------- 13 | try: 14 | #load new scene without saving 15 | pm.mel.eval('file -f -new;') 16 | #if plugin is loaded unload and reload it, else reload 17 | if(pm.pluginInfo( 'twClothSolverBlockoutPlugins.py', query=True, loaded=True )): 18 | pm.unloadPlugin( 'twClothSolverBlockoutPlugins.py' ) 19 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 20 | print('Successfully reloaded plugin') 21 | else: 22 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 23 | print('Successfully loaded plugin') 24 | except: 25 | print('Error Reloading Plugin') 26 | 27 | 28 | 29 | 30 | #TwClothSolverIOPaperBlockout 31 | #---------------------------------- 32 | #---------------------------------- 33 | 34 | #create inputGeo 35 | #---------------------------------- 36 | #inputGeo 37 | inputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 38 | inputGeoShape = inputGeoTrans.getShape() 39 | #transformPlane 40 | inputGeoTrans.translateY.set(5) 41 | inputGeoTrans.visibility.set(0) 42 | pm.select(cl = True) 43 | #pm.select(inputGeoTrans, r = True) 44 | #pm.polyTriangulate(ch = False) 45 | #pm.select(cl = True) 46 | 47 | #create outputGeo 48 | #---------------------------------- 49 | #outputGeo 50 | outputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 51 | outputGeoShape = outputGeoTrans.getShape() 52 | pm.select(cl = True) 53 | 54 | #create cloth solver node 55 | #---------------------------------- 56 | clothSolver = pm.createNode('TwClothSolverIOPaperBlockout') 57 | clothSolver.verbose.set(0) 58 | clothSolver.repetitions.set(10) 59 | pm.select(cl = True) 60 | 61 | #create positionConstraintLocators 62 | #---------------------------------- 63 | positionConstraintLocatorIndex0Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex0') 64 | positionConstraintLocatorIndex0Shape = positionConstraintLocatorIndex0Trans.getShape() 65 | positionConstraintLocatorIndex0Trans.translate.set(-5,5,5) 66 | pm.select(cl = True) 67 | 68 | positionConstraintLocatorIndex110Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex110') 69 | positionConstraintLocatorIndex110Shape = positionConstraintLocatorIndex110Trans.getShape() 70 | positionConstraintLocatorIndex110Trans.translate.set(-5,5,-5) 71 | pm.select(cl = True) 72 | 73 | positionConstraintLocatorIndex120Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex120') 74 | positionConstraintLocatorIndex120Shape = positionConstraintLocatorIndex120Trans.getShape() 75 | positionConstraintLocatorIndex120Trans.translate.set(5,5,-5) 76 | pm.select(cl = True) 77 | 78 | positionConstraintLocatorIndex10Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex10') 79 | positionConstraintLocatorIndex10Shape = positionConstraintLocatorIndex10Trans.getShape() 80 | positionConstraintLocatorIndex10Trans.translate.set(5,5,5) 81 | pm.select(cl = True) 82 | 83 | positionConstraintLocatorIndex60Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex60') 84 | positionConstraintLocatorIndex60Shape = positionConstraintLocatorIndex60Trans.getShape() 85 | positionConstraintLocatorIndex60Trans.translate.set(0,5,0) 86 | pm.select(cl = True) 87 | 88 | #connect locators and set index attrs on clothSolver 89 | #---------------------------------- 90 | clothSolver.positionConstraint[0].positionConstraintVertexIndex.set(0) 91 | positionConstraintLocatorIndex0Shape.worldPosition >> clothSolver.positionConstraint[0].positionConstraintCoordinate 92 | pm.select(cl = True) 93 | clothSolver.positionConstraint[1].positionConstraintVertexIndex.set(110) 94 | positionConstraintLocatorIndex110Shape.worldPosition >> clothSolver.positionConstraint[1].positionConstraintCoordinate 95 | pm.select(cl = True) 96 | clothSolver.positionConstraint[2].positionConstraintVertexIndex.set(120) 97 | positionConstraintLocatorIndex120Shape.worldPosition >> clothSolver.positionConstraint[2].positionConstraintCoordinate 98 | pm.select(cl = True) 99 | clothSolver.positionConstraint[3].positionConstraintVertexIndex.set(10) 100 | positionConstraintLocatorIndex10Shape.worldPosition >> clothSolver.positionConstraint[3].positionConstraintCoordinate 101 | pm.select(cl = True) 102 | clothSolver.positionConstraint[4].positionConstraintVertexIndex.set(60) 103 | positionConstraintLocatorIndex60Shape.worldPosition >> clothSolver.positionConstraint[4].positionConstraintCoordinate 104 | pm.select(cl = True) 105 | 106 | #set clothSolver active attr 107 | #---------------------------------- 108 | clothSolver.positionConstraint[0].positionConstraintActive.set(1) 109 | clothSolver.positionConstraint[1].positionConstraintActive.set(1) 110 | 111 | #create sphere 112 | #---------------------------------- 113 | collisionSphereTrans = pm.polySphere(sx = 8,sy = 8, n = 'collisionSphere0', r = 2, ch = 0)[0] 114 | collisionSphereShape = collisionSphereTrans.getShape() 115 | collisionSphereTrans.translate.set(0,1,0) 116 | pm.select(cl = True) 117 | 118 | #connect sphere as collision object 119 | #---------------------------------- 120 | clothSolver.collisionConstraint[0].collisionConstraintActive.set(1) 121 | clothSolver.collisionConstraint[0].collisionConstraintType.set(0) 122 | collisionSphereShape.outMesh >> clothSolver.collisionConstraint[0].collisionConstraintGeo 123 | collisionSphereShape.parentMatrix >> clothSolver.collisionConstraint[0].collisionConstraintGeoMatrix 124 | pm.select(cl = True) 125 | 126 | #create cube 127 | #---------------------------------- 128 | collisionCubeTrans = pm.polyCube(sx = 1,sy = 1, sz = 1, d = 4, w = 4, h = 4, n = 'collisionCube1', ch = 0)[0] 129 | collisionCubeShape = collisionCubeTrans.getShape() 130 | collisionCubeTrans.translate.set(5,0,0) 131 | pm.select(cl = True) 132 | 133 | #connect cube as collision object 134 | #---------------------------------- 135 | clothSolver.collisionConstraint[1].collisionConstraintActive.set(1) 136 | clothSolver.collisionConstraint[1].collisionConstraintType.set(1) 137 | collisionCubeShape.outMesh >> clothSolver.collisionConstraint[1].collisionConstraintGeo 138 | collisionCubeShape.parentMatrix >> clothSolver.collisionConstraint[1].collisionConstraintGeoMatrix 139 | pm.select(cl = True) 140 | 141 | #create pyramid 142 | #---------------------------------- 143 | collisionPyramidTrans = pm.polyPyramid(ns = 5, w = 4, n = 'collisionPyramid2', ch = 0)[0] 144 | collisionPyramidShape = collisionPyramidTrans.getShape() 145 | collisionPyramidTrans.translate.set(10,0,0) 146 | pm.select(cl = True) 147 | 148 | #connect Pyramid as collision object 149 | #---------------------------------- 150 | clothSolver.collisionConstraint[2].collisionConstraintActive.set(1) 151 | clothSolver.collisionConstraint[2].collisionConstraintType.set(1) 152 | collisionPyramidShape.outMesh >> clothSolver.collisionConstraint[2].collisionConstraintGeo 153 | collisionPyramidShape.parentMatrix >> clothSolver.collisionConstraint[2].collisionConstraintGeoMatrix 154 | pm.select(cl = True) 155 | 156 | #connect time 157 | #---------------------------------- 158 | timeNode = pm.PyNode('time1') 159 | pm.select(cl = True) 160 | timeNode.outTime >> clothSolver.currentFrame 161 | 162 | #connect inputGeo 163 | #---------------------------------- 164 | inputGeoShape.outMesh >> clothSolver.inputGeo 165 | 166 | #connect inputGeo parentMatrix 167 | #---------------------------------- 168 | inputGeoShape.parentMatrix >> clothSolver.transformMatrix 169 | 170 | #connect outputGeo 171 | #---------------------------------- 172 | clothSolver.outputGeo >> outputGeoShape.inMesh 173 | 174 | #set clothSolver gravity 175 | #---------------------------------- 176 | gravityPerSec = -9.8 177 | framesPerSec = 24 178 | clothSolver.gravity.set(0,gravityPerSec/framesPerSec,0) 179 | 180 | #set time range 181 | #---------------------------------- 182 | pm.playbackOptions(ast = 1, aet = 1000, max = 1000, min = 1) 183 | 184 | #rename and select clothSolver 185 | #---------------------------------- 186 | clothSolverTrans = clothSolver.getParent() 187 | pm.rename(clothSolver, 'twClothSolverShape') 188 | pm.rename(clothSolverTrans, 'twClothSolver') 189 | pm.select(clothSolver, r = True) -------------------------------------------------------------------------------- /twClothSolverBlockout/twClothSolverIOPaperBlockoutTestFixture.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twClothSolverIOPaperBlockout Test Fixture 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | import pymel.core as pm 9 | 10 | 11 | #reload plugin 12 | #---------------------------------- 13 | try: 14 | #load new scene without saving 15 | pm.mel.eval('file -f -new;') 16 | #if plugin is loaded unload and reload it, else reload 17 | if(pm.pluginInfo( 'twClothSolverBlockoutPlugins.py', query=True, loaded=True )): 18 | pm.unloadPlugin( 'twClothSolverBlockoutPlugins.py' ) 19 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 20 | print('Successfully reloaded plugin') 21 | else: 22 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 23 | print('Successfully loaded plugin') 24 | except: 25 | print('Error Reloading Plugin') 26 | 27 | 28 | 29 | 30 | #TwClothSolverIOPaperBlockout 31 | #---------------------------------- 32 | #---------------------------------- 33 | 34 | #create inputGeo 35 | #---------------------------------- 36 | #inputGeo 37 | inputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 38 | inputGeoShape = inputGeoTrans.getShape() 39 | #transformPlane 40 | inputGeoTrans.translateY.set(5) 41 | inputGeoTrans.visibility.set(0) 42 | pm.select(cl = True) 43 | #pm.select(inputGeoTrans, r = True) 44 | #pm.polyTriangulate(ch = False) 45 | #pm.select(cl = True) 46 | 47 | #create outputGeo 48 | #---------------------------------- 49 | #outputGeo 50 | outputGeoTrans = pm.polyPlane( sx=10, sy=10, w=10, h=10, ch = False)[0] 51 | outputGeoShape = outputGeoTrans.getShape() 52 | pm.select(cl = True) 53 | 54 | #create cloth solver node 55 | #---------------------------------- 56 | clothSolver = pm.createNode('TwClothSolverIOPaperBlockout') 57 | clothSolver.verbose.set(0) 58 | clothSolver.repetitions.set(10) 59 | pm.select(cl = True) 60 | 61 | #create positionConstraintLocators 62 | #---------------------------------- 63 | positionConstraintLocatorIndex0Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex0') 64 | positionConstraintLocatorIndex0Shape = positionConstraintLocatorIndex0Trans.getShape() 65 | positionConstraintLocatorIndex0Trans.translate.set(-5,5,5) 66 | pm.select(cl = True) 67 | 68 | positionConstraintLocatorIndex110Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex110') 69 | positionConstraintLocatorIndex110Shape = positionConstraintLocatorIndex110Trans.getShape() 70 | positionConstraintLocatorIndex110Trans.translate.set(-5,5,-5) 71 | pm.select(cl = True) 72 | 73 | positionConstraintLocatorIndex120Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex120') 74 | positionConstraintLocatorIndex120Shape = positionConstraintLocatorIndex120Trans.getShape() 75 | positionConstraintLocatorIndex120Trans.translate.set(5,5,-5) 76 | pm.select(cl = True) 77 | 78 | positionConstraintLocatorIndex10Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex10') 79 | positionConstraintLocatorIndex10Shape = positionConstraintLocatorIndex10Trans.getShape() 80 | positionConstraintLocatorIndex10Trans.translate.set(5,5,5) 81 | pm.select(cl = True) 82 | 83 | positionConstraintLocatorIndex60Trans = pm.spaceLocator(n = 'positionConstraintLocatorIndex60') 84 | positionConstraintLocatorIndex60Shape = positionConstraintLocatorIndex60Trans.getShape() 85 | positionConstraintLocatorIndex60Trans.translate.set(0,5,0) 86 | pm.select(cl = True) 87 | 88 | #connect locators and set index attrs on clothSolver 89 | #---------------------------------- 90 | clothSolver.positionConstraint[0].positionConstraintVertexIndex.set(0) 91 | positionConstraintLocatorIndex0Shape.worldPosition >> clothSolver.positionConstraint[0].positionConstraintCoordinate 92 | pm.select(cl = True) 93 | clothSolver.positionConstraint[1].positionConstraintVertexIndex.set(110) 94 | positionConstraintLocatorIndex110Shape.worldPosition >> clothSolver.positionConstraint[1].positionConstraintCoordinate 95 | pm.select(cl = True) 96 | clothSolver.positionConstraint[2].positionConstraintVertexIndex.set(120) 97 | positionConstraintLocatorIndex120Shape.worldPosition >> clothSolver.positionConstraint[2].positionConstraintCoordinate 98 | pm.select(cl = True) 99 | clothSolver.positionConstraint[3].positionConstraintVertexIndex.set(10) 100 | positionConstraintLocatorIndex10Shape.worldPosition >> clothSolver.positionConstraint[3].positionConstraintCoordinate 101 | pm.select(cl = True) 102 | clothSolver.positionConstraint[4].positionConstraintVertexIndex.set(60) 103 | positionConstraintLocatorIndex60Shape.worldPosition >> clothSolver.positionConstraint[4].positionConstraintCoordinate 104 | pm.select(cl = True) 105 | 106 | #set clothSolver active attr 107 | #---------------------------------- 108 | clothSolver.positionConstraint[0].positionConstraintActive.set(1) 109 | clothSolver.positionConstraint[1].positionConstraintActive.set(1) 110 | 111 | #create sphere 112 | #---------------------------------- 113 | collisionSphereTrans = pm.polySphere(sx = 8,sy = 8, n = 'collisionSphere0', r = 2, ch = 0)[0] 114 | collisionSphereShape = collisionSphereTrans.getShape() 115 | collisionSphereTrans.translate.set(0,1,0) 116 | pm.select(cl = True) 117 | 118 | #connect sphere as collision object 119 | #---------------------------------- 120 | clothSolver.collisionConstraint[0].collisionConstraintActive.set(1) 121 | clothSolver.collisionConstraint[0].collisionConstraintType.set(0) 122 | collisionSphereShape.outMesh >> clothSolver.collisionConstraint[0].collisionConstraintGeo 123 | collisionSphereShape.parentMatrix >> clothSolver.collisionConstraint[0].collisionConstraintGeoMatrix 124 | pm.select(cl = True) 125 | 126 | #create cube 127 | #---------------------------------- 128 | collisionCubeTrans = pm.polyCube(sx = 1,sy = 1, sz = 1, d = 4, w = 4, h = 4, n = 'collisionCube1', ch = 0)[0] 129 | collisionCubeShape = collisionCubeTrans.getShape() 130 | collisionCubeTrans.translate.set(5,0,0) 131 | pm.select(cl = True) 132 | 133 | #connect cube as collision object 134 | #---------------------------------- 135 | clothSolver.collisionConstraint[1].collisionConstraintActive.set(1) 136 | clothSolver.collisionConstraint[1].collisionConstraintType.set(1) 137 | collisionCubeShape.outMesh >> clothSolver.collisionConstraint[1].collisionConstraintGeo 138 | collisionCubeShape.parentMatrix >> clothSolver.collisionConstraint[1].collisionConstraintGeoMatrix 139 | pm.select(cl = True) 140 | 141 | #create pyramid 142 | #---------------------------------- 143 | collisionPyramidTrans = pm.polyPyramid(ns = 5, w = 4, n = 'collisionPyramid2', ch = 0)[0] 144 | collisionPyramidShape = collisionPyramidTrans.getShape() 145 | collisionPyramidTrans.translate.set(10,0,0) 146 | pm.select(cl = True) 147 | 148 | #connect Pyramid as collision object 149 | #---------------------------------- 150 | clothSolver.collisionConstraint[2].collisionConstraintActive.set(1) 151 | clothSolver.collisionConstraint[2].collisionConstraintType.set(1) 152 | collisionPyramidShape.outMesh >> clothSolver.collisionConstraint[2].collisionConstraintGeo 153 | collisionPyramidShape.parentMatrix >> clothSolver.collisionConstraint[2].collisionConstraintGeoMatrix 154 | pm.select(cl = True) 155 | 156 | #connect time 157 | #---------------------------------- 158 | timeNode = pm.PyNode('time1') 159 | pm.select(cl = True) 160 | timeNode.outTime >> clothSolver.currentFrame 161 | 162 | #connect inputGeo 163 | #---------------------------------- 164 | inputGeoShape.outMesh >> clothSolver.inputGeo 165 | 166 | #connect inputGeo parentMatrix 167 | #---------------------------------- 168 | inputGeoShape.parentMatrix >> clothSolver.transformMatrix 169 | 170 | #connect outputGeo 171 | #---------------------------------- 172 | clothSolver.outputGeo >> outputGeoShape.inMesh 173 | 174 | #set clothSolver gravity 175 | #---------------------------------- 176 | gravityPerSec = -9.8 177 | framesPerSec = 24 178 | clothSolver.gravity.set(0,gravityPerSec/framesPerSec,0) 179 | 180 | #set time range 181 | #---------------------------------- 182 | pm.playbackOptions(ast = 1, aet = 1000, max = 1000, min = 1) 183 | 184 | #rename and select clothSolver 185 | #---------------------------------- 186 | clothSolverTrans = clothSolver.getParent() 187 | pm.rename(clothSolver, 'twClothSolverShape') 188 | pm.rename(clothSolverTrans, 'twClothSolver') 189 | pm.select(clothSolver, r = True) -------------------------------------------------------------------------------- /twClothSolver/vcsPositionConstraintCmd.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VcsPositionConstraintCmd Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "vcsPositionConstraintCmd.h" 10 | 11 | 12 | //VcsPositionConstraintCmd 13 | //----------------------------------------------- 14 | 15 | //Attrs 16 | 17 | //Methods 18 | VcsPositionConstraintCmd::VcsPositionConstraintCmd():verbose(1){}; 19 | VcsPositionConstraintCmd::~VcsPositionConstraintCmd(){}; 20 | 21 | //create 22 | void* VcsPositionConstraintCmd::create() 23 | { 24 | return new VcsPositionConstraintCmd(); 25 | }; 26 | 27 | //doIt 28 | MStatus VcsPositionConstraintCmd::doIt(const MArgList &args) 29 | { 30 | 31 | //Get active selectionList 32 | //----------------------------------------------- 33 | 34 | //status 35 | MStatus status; 36 | 37 | //get selectionList 38 | MSelectionList selectionList; 39 | MGlobal::getActiveSelectionList(selectionList); 40 | 41 | //if !selectionList return 42 | if(!selectionList.length()) 43 | { 44 | if(verbose){MGlobal::displayInfo("Empty SelectionList. Please select at least one vertex of an object connected to a vcsClothSolver.");}; 45 | return MS::kSuccess; 46 | }; 47 | 48 | 49 | 50 | 51 | //Iterate active selectionList 52 | //----------------------------------------------- 53 | 54 | //dagPath and component 55 | MDagPath dagPath; 56 | MObject oComponent; 57 | //itSelectionList 58 | MItSelectionList itSelectionList(selectionList); 59 | 60 | //iterate selectionList (for each selected dagNode) 61 | while(!itSelectionList.isDone()) 62 | { 63 | 64 | //Get connected ClothSolver 65 | //----------------------------------------------- 66 | 67 | //set dagPath and oComponent 68 | itSelectionList.getDagPath(dagPath, oComponent); 69 | 70 | //fnDagNode 71 | MFnDagNode fnDagNode(dagPath); 72 | //MGlobal::displayInfo(fnDagNode.typeName()); 73 | 74 | 75 | //pOutMesh 76 | MPlug pOutMesh = fnDagNode.findPlug("outMesh", true, &status); 77 | if(status == MStatus::kFailure) 78 | { 79 | if(verbose){MGlobal::displayInfo("Selected object does not have plug outMesh");}; 80 | //advance 81 | itSelectionList.next(); 82 | continue; 83 | }; 84 | 85 | //pArrayOutMesh 86 | MPlugArray pArrayOutMesh; 87 | pOutMesh.connectedTo(pArrayOutMesh, false, true); 88 | 89 | //Check if plug is connected to anything 90 | if(!pArrayOutMesh.length()) 91 | { 92 | if(verbose){MGlobal::displayInfo("Plug outMesh not connected to anything. Continuing.");}; 93 | //advance 94 | itSelectionList.next(); 95 | continue; 96 | }; 97 | 98 | //oCurrentDestination 99 | MObject oCurrentDestination; 100 | 101 | //iterate pArrayOutMesh 102 | for(int index = 0; index < pArrayOutMesh.length(); index++) 103 | { 104 | //pDestination 105 | MPlug pDestination; 106 | pDestination = pArrayOutMesh[index]; 107 | 108 | //fnDepNodeDestination 109 | MFnDependencyNode fnDepNodeDestination(pDestination.node()); 110 | 111 | //check if typename ==verletClothSolver 112 | if(fnDepNodeDestination.typeName() == "verletClothSolver"){oCurrentDestination = fnDepNodeDestination.object();break;} 113 | else{oCurrentDestination = fnDepNodeDestination.object();}; 114 | }; 115 | 116 | //fnDepNodeClothSolver 117 | MFnDependencyNode fnDepNodeClothSolver(oCurrentDestination); 118 | //Check if object really clothSolver 119 | if(!(fnDepNodeClothSolver.typeName() == "verletClothSolver")) 120 | { 121 | if(verbose){MGlobal::displayInfo(MString("Selected object is not connected to a clothSolver: ") +fnDepNodeClothSolver.name());}; 122 | //advance 123 | itSelectionList.next(); 124 | continue; 125 | }; 126 | 127 | //Display clothSolver Name and type 128 | if(verbose) 129 | { 130 | MGlobal::displayInfo(fnDepNodeClothSolver.name()); 131 | MGlobal::displayInfo(fnDepNodeClothSolver.typeName()); 132 | MGlobal::displayInfo("-----------------------------"); 133 | }; 134 | 135 | 136 | 137 | 138 | 139 | 140 | //Create posConstraintLists 141 | //----------------------------------------------- 142 | 143 | //create itVertices 144 | MItMeshVertex itVertices(dagPath, oComponent); 145 | 146 | //dataLists 147 | int verticesCount = itVertices.count(); 148 | MPoint* posConstraintPositionList = new MPoint[verticesCount]; 149 | int* posConstraintVertexIndexList = new int[verticesCount]; 150 | MObject* posConstraintObjectList = new MObject[verticesCount]; 151 | 152 | //index 153 | int runtimeVar = 0; 154 | 155 | //iterate itVertices 156 | while(!itVertices.isDone()) 157 | { 158 | //Get ws pos 159 | MPoint wsPos = itVertices.position(MSpace::kWorld); 160 | //get vertexIndex 161 | int vertexIndex = itVertices.index(); 162 | 163 | //create locator 164 | MObject oPositionConstraint; 165 | MDagModifier dagModifier; 166 | oPositionConstraint = dagModifier.createNode("locator", MObject::kNullObj ); 167 | //rename locator 168 | MString posConstraintName = MString("vcsPositionConstraint"); 169 | dagModifier.renameNode(oPositionConstraint, posConstraintName); 170 | dagModifier.doIt(); 171 | 172 | //translate locator 173 | MFnTransform fnTransformLocator(oPositionConstraint); 174 | MVector vecPos = MVector(wsPos); 175 | fnTransformLocator.setTranslation(vecPos, MSpace::kTransform); 176 | 177 | //fill in arrays 178 | posConstraintPositionList[runtimeVar] = wsPos; 179 | posConstraintVertexIndexList[runtimeVar] = vertexIndex; 180 | posConstraintObjectList[runtimeVar] = oPositionConstraint; 181 | 182 | runtimeVar++; 183 | 184 | //advance 185 | itVertices.next(); 186 | }; 187 | 188 | 189 | 190 | 191 | //Print posConstraintLists 192 | //----------------------------------------------- 193 | 194 | //iterate arrays and print info 195 | if(verbose) 196 | { 197 | for(int index = 0; index < verticesCount; index++) 198 | { 199 | //getData 200 | MPoint wsPos = posConstraintPositionList[index]; 201 | int vertexIndex = posConstraintVertexIndexList[index]; 202 | MObject oPositionConstraint = posConstraintObjectList[index]; 203 | 204 | //Header 205 | MGlobal::displayInfo(MString("PositionConstraint: ") +index); 206 | 207 | //Name 208 | MFnDependencyNode fnDepNodePosConstraint(oPositionConstraint); 209 | MString msg = MString(fnDepNodePosConstraint.name()); 210 | 211 | //wsPos 212 | MString msg1 = MString("x: ") +wsPos.x; 213 | MString msg2 = MString(" y: ") +wsPos.y; 214 | MString msg3 = MString(" z: ") +wsPos.z; 215 | 216 | //vertexIndex 217 | MString msg4 = MString("VertexIndex: ") +vertexIndex; 218 | 219 | //Print strings 220 | MGlobal::displayInfo(msg); 221 | MGlobal::displayInfo(msg1 + msg2 + msg3); 222 | MGlobal::displayInfo(msg4); 223 | MGlobal::displayInfo("-----------------------------"); 224 | 225 | }; 226 | }; 227 | 228 | 229 | //Connect posConstraintLists to solver 230 | //----------------------------------------------- 231 | for(int index = 0; index < verticesCount; index++) 232 | { 233 | //Get Plugs to clothSolverAttrs 234 | //----------------------------------------------- 235 | 236 | //Get plug to compound array of clothSolver 237 | MPlug pCompoundArrayAttr = fnDepNodeClothSolver.findPlug("positionConstraint"); 238 | MObject aCompoundArrayAttr = pCompoundArrayAttr.attribute(); 239 | 240 | //lastArrayElementIndex 241 | int lastArrayElementIndex = pCompoundArrayAttr.numElements(); 242 | 243 | 244 | //plug to last array element 245 | MPlug pCompoundAttr = pCompoundArrayAttr.elementByLogicalIndex(lastArrayElementIndex); 246 | 247 | //Get Plugs to children 248 | MPlug pTargetConstraintActive = pCompoundAttr.child(0); 249 | MPlug pTargetConstraintVertexIndex = pCompoundAttr.child(1); 250 | 251 | MPlug pTargetCompoundConstraintCoordinate = pCompoundAttr.child(2); 252 | MPlug pTargetConstraintCoordinateX = pTargetCompoundConstraintCoordinate.child(0); 253 | MPlug pTargetConstraintCoordinateY = pTargetCompoundConstraintCoordinate.child(1); 254 | MPlug pTargetConstraintCoordinateZ = pTargetCompoundConstraintCoordinate.child(2); 255 | 256 | 257 | 258 | 259 | 260 | //Get Plug to locator attrs 261 | //----------------------------------------------- 262 | 263 | //get Plug to posConstraint (locatorShape) worldPos attr 264 | //get shape of loc from transform 265 | MFnDagNode fnDagNodePosConstraint(posConstraintObjectList[index]); 266 | MObject oPosConstraintShape = fnDagNodePosConstraint.child(0); 267 | 268 | MFnDependencyNode fnDepNodePosConstraintShape(oPosConstraintShape); 269 | MPlug pSourceCompoundArrayAttr = fnDepNodePosConstraintShape.findPlug("worldPosition"); 270 | 271 | MGlobal::displayInfo(fnDepNodePosConstraintShape.name()); 272 | 273 | //plug to first array element 274 | MPlug pCompoundPositionAttr = pSourceCompoundArrayAttr.elementByLogicalIndex(0); 275 | MPlug pSourceConstraintCoordinateX = pCompoundPositionAttr.child(0); 276 | MPlug pSourceConstraintCoordinateY = pCompoundPositionAttr.child(1); 277 | MPlug pSourceConstraintCoordinateZ = pCompoundPositionAttr.child(2); 278 | 279 | 280 | //connect position plugs 281 | MDGModifier dgModifier; 282 | dgModifier.connect(pSourceConstraintCoordinateX, pTargetConstraintCoordinateX); 283 | dgModifier.connect(pSourceConstraintCoordinateY, pTargetConstraintCoordinateY); 284 | dgModifier.connect(pSourceConstraintCoordinateZ, pTargetConstraintCoordinateZ); 285 | dgModifier.doIt(); 286 | 287 | //Set vertexIndex & constraintActive 288 | pTargetConstraintActive.setBool(true); 289 | pTargetConstraintVertexIndex.setInt(posConstraintVertexIndexList[index]); 290 | 291 | }; 292 | 293 | 294 | 295 | //delete dynamic ptr 296 | delete [] posConstraintPositionList; 297 | delete [] posConstraintVertexIndexList; 298 | delete [] posConstraintObjectList; 299 | 300 | //advance 301 | itSelectionList.next(); 302 | }; 303 | 304 | return MS::kSuccess; 305 | }; -------------------------------------------------------------------------------- /twClothSolver/verletClothSolverCPU.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | //VerletClothSolverCPU Implementation 4 | //----------------------------------------------- 5 | 6 | 7 | //include 8 | //----------------------------------------------- 9 | #include "verletClothSolverCPU.h" 10 | 11 | 12 | //VerletClothSolverCPU 13 | //----------------------------------------------- 14 | 15 | //Attributes 16 | 17 | 18 | //Methods 19 | VerletClothSolverCPU::VerletClothSolverCPU(){}; 20 | VerletClothSolverCPU::~VerletClothSolverCPU(){}; 21 | 22 | 23 | //solve 24 | void VerletClothSolverCPU::solve(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) 25 | { 26 | verletIntegration(staticSolverData, dynamicSolverData); 27 | for(int index = 1; index <= dynamicSolverData.repetitions; index++) 28 | { 29 | satisfyConstraints(staticSolverData, dynamicSolverData); 30 | }; 31 | }; 32 | 33 | //verletIntegration 34 | void VerletClothSolverCPU::verletIntegration(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) 35 | { 36 | #pragma omp parallel for if(dynamicSolverData.omp) 37 | for(int index = 0; index < staticSolverData.vertexCount; index++) 38 | { 39 | //Get vars for integration 40 | vcsVector vecNew; 41 | vcsVector vecPos = staticSolverData.pVertexPositionList[index]; 42 | vcsVector vecOldpos = staticSolverData.pVertexOldpositionList[index]; 43 | vcsVector vecForce = dynamicSolverData.pVertexForceList[index]; 44 | float drag = 1.0 - dynamicSolverData.drag; 45 | 46 | //integration 47 | vecNew = (vecPos + ((vecPos - vecOldpos) * drag)) + vecForce; 48 | 49 | //update solverData 50 | staticSolverData.pVertexOldpositionList[index] = vecPos; 51 | staticSolverData.pVertexPositionList[index] = vecNew; 52 | } 53 | //std::cout<<"verletIntegrationCPU"< 0)) 183 | { 184 | //std::cout<<"No collision occured for triangle: "< 360.0 - margin && sumAngles < 360.0 + margin) 225 | { 226 | //vecOffset 227 | vcsVector vecOffset = ((vertexOldposition - vecIntersection).normal()) * dynamicSolverData.collisionConstraintConvexOffset; 228 | 229 | //set position 230 | staticSolverData.pVertexPositionList[vertexIndex] = vecIntersection + vecOffset; 231 | }; 232 | 233 | 234 | }; 235 | }; 236 | 237 | 238 | //std::cout<<"CollisionConstraintConvexCPU"<glFunctionTable();}; 126 | 127 | // Begin the drawing 128 | view.beginGL(); 129 | 130 | //Store current settings 131 | pGlFT->glPushAttrib(MGL_ALL_ATTRIB_BITS); 132 | 133 | pGlFT->glEnable(GL_POINT_SMOOTH); 134 | pGlFT->glPointSize(5.0); 135 | 136 | for(int index = 0; index < drawData.edgeVertexPositionList.size(); index++) 137 | { 138 | ////Draw Lines 139 | //pGlFT->glBegin(MGL_POINTS); 140 | // 141 | ////Color 142 | //pGlFT->glColor3f(1.0f, 1.0f,0.0f); 143 | 144 | ////positions 145 | //float posX1 = drawData.edgeVertexPositionList[index][0]; 146 | //float posY1 = drawData.edgeVertexPositionList[index][1]; 147 | //float posZ1 = drawData.edgeVertexPositionList[index][2]; 148 | 149 | //float posX2 = drawData.edgeVertexPositionList[index][3]; 150 | //float posY2 = drawData.edgeVertexPositionList[index][4]; 151 | //float posZ2 = drawData.edgeVertexPositionList[index][5]; 152 | 153 | ////draw line 154 | //pGlFT->glVertex3f( posX1, posY1, posZ1); 155 | //pGlFT->glVertex3f( posX2, posY2, posZ2); 156 | // 157 | ////End Lines 158 | //pGlFT->glEnd(); 159 | 160 | 161 | //Draw Lines 162 | pGlFT->glBegin(MGL_LINES); 163 | //Color 164 | pGlFT->glColor3f(1.0f, 1.0f,0.0f); 165 | 166 | //positions 167 | float posX1 = drawData.edgeVertexPositionList[index][0]; 168 | float posY1 = drawData.edgeVertexPositionList[index][1]; 169 | float posZ1 = drawData.edgeVertexPositionList[index][2]; 170 | 171 | float posX2 = drawData.edgeVertexPositionList[index][3]; 172 | float posY2 = drawData.edgeVertexPositionList[index][4]; 173 | float posZ2 = drawData.edgeVertexPositionList[index][5]; 174 | 175 | //draw line 176 | pGlFT->glVertex3f( posX1, posY1, posZ1); 177 | pGlFT->glVertex3f( posX2, posY2, posZ2); 178 | 179 | //End Lines 180 | pGlFT->glEnd(); 181 | } 182 | 183 | //Reset current settings 184 | pGlFT->glPopAttrib(); 185 | 186 | view.endGL(); 187 | 188 | }; 189 | 190 | //setDrawData 191 | //----------------------------------------------- 192 | void TesselationVisualization::setTesselationDrawData(MDataBlock &data) 193 | { 194 | //setEdgeVertexIndexList 195 | setEdgeVertexPositionList(data); 196 | }; 197 | 198 | 199 | 200 | //setEdgeVertexIndexList 201 | //----------------------------------------------- 202 | void TesselationVisualization::setEdgeVertexPositionList(MDataBlock &data) 203 | { 204 | 205 | //get colormode 206 | short tesselationType = data.inputValue(aTesselationType).asShort(); 207 | 208 | //switch 209 | switch(tesselationType) 210 | { 211 | case 0: 212 | setEdgeVertexPositionListStructural(data); 213 | break; 214 | case 1: 215 | setEdgeVertexPositionListShear(data); 216 | break; 217 | default: 218 | break; 219 | }; 220 | }; 221 | 222 | //setEdgeVertexIndexListStructural 223 | //----------------------------------------------- 224 | void TesselationVisualization::setEdgeVertexPositionListStructural(MDataBlock &data) 225 | { 226 | //clear edgeVertexPositionList 227 | drawData.edgeVertexPositionList.clear(); 228 | 229 | //inputGeo 230 | MObject oInputGeo = data.inputValue(aInputGeo).asMesh(); 231 | 232 | //fnMeshInputGeo 233 | MFnMesh fnMeshInputGeo(oInputGeo); 234 | 235 | //vertexPositionList 236 | MPointArray vertexPositionList; 237 | fnMeshInputGeo.getPoints(vertexPositionList); 238 | 239 | //itMeshPolyInputGeo 240 | MItMeshPolygon itMeshPolyInputGeo(oInputGeo); 241 | 242 | //for each poly 243 | while(!itMeshPolyInputGeo.isDone()) 244 | { 245 | //get edges 246 | MIntArray edgeIndexList; 247 | itMeshPolyInputGeo.getEdges(edgeIndexList); 248 | 249 | //edgeVertexIndices 250 | int2* edgeVertexIndices = new int2[4]; 251 | 252 | for(int index = 0; index < edgeIndexList.length(); index++) 253 | { 254 | fnMeshInputGeo.getEdgeVertices(edgeIndexList[index], edgeVertexIndices[index]); 255 | }; 256 | 257 | //edgeVertexIndicesNoDuplicates 258 | std::set setEdgeVertexIndicesNoDuplicates; 259 | 260 | for(int index = 0; index < edgeIndexList.length(); index++) 261 | { 262 | setEdgeVertexIndicesNoDuplicates.insert(edgeVertexIndices[index][0]); 263 | setEdgeVertexIndicesNoDuplicates.insert(edgeVertexIndices[index][1]); 264 | }; 265 | 266 | //vecEdgeVertexIndicesNoDuplicates 267 | std::vector vecEdgeVertexIndicesNoDuplicates(setEdgeVertexIndicesNoDuplicates.begin(), setEdgeVertexIndicesNoDuplicates.end()); 268 | 269 | 270 | //get faceVertexList 271 | MPointArray faceVertexPointList = MPointArray(4); 272 | 273 | for(int index = 0; index < edgeIndexList.length(); index++) 274 | { 275 | MPoint faceVertexPoint = vertexPositionList[vecEdgeVertexIndicesNoDuplicates[index]]; 276 | faceVertexPointList.set(faceVertexPoint, index); 277 | }; 278 | 279 | 280 | 281 | //edge01 282 | std::vector edge01; 283 | edge01.push_back(faceVertexPointList[0].x);edge01.push_back(faceVertexPointList[0].y);edge01.push_back(faceVertexPointList[0].z); 284 | edge01.push_back(faceVertexPointList[1].x);edge01.push_back(faceVertexPointList[1].y);edge01.push_back(faceVertexPointList[1].z); 285 | 286 | //edge13 287 | std::vector edge13; 288 | edge13.push_back(faceVertexPointList[1].x);edge13.push_back(faceVertexPointList[1].y);edge13.push_back(faceVertexPointList[1].z); 289 | edge13.push_back(faceVertexPointList[3].x);edge13.push_back(faceVertexPointList[3].y);edge13.push_back(faceVertexPointList[3].z); 290 | 291 | //edge32 292 | std::vector edge32; 293 | edge32.push_back(faceVertexPointList[3].x);edge32.push_back(faceVertexPointList[3].y);edge32.push_back(faceVertexPointList[3].z); 294 | edge32.push_back(faceVertexPointList[2].x);edge32.push_back(faceVertexPointList[2].y);edge32.push_back(faceVertexPointList[2].z); 295 | 296 | //edge20 297 | std::vector edge20; 298 | edge20.push_back(faceVertexPointList[2].x);edge20.push_back(faceVertexPointList[2].y);edge20.push_back(faceVertexPointList[2].z); 299 | edge20.push_back(faceVertexPointList[0].x);edge20.push_back(faceVertexPointList[0].y);edge20.push_back(faceVertexPointList[0].z); 300 | 301 | 302 | //add to drawData.edgeVertexPositionList 303 | drawData.edgeVertexPositionList.push_back(edge01); 304 | drawData.edgeVertexPositionList.push_back(edge13); 305 | drawData.edgeVertexPositionList.push_back(edge32); 306 | drawData.edgeVertexPositionList.push_back(edge20); 307 | 308 | //del edgeVertexIndices 309 | delete [] edgeVertexIndices; 310 | 311 | //Advance 312 | itMeshPolyInputGeo.next(); 313 | }; 314 | }; 315 | 316 | //setEdgeVertexIndexListShear 317 | //----------------------------------------------- 318 | void TesselationVisualization::setEdgeVertexPositionListShear(MDataBlock &data) 319 | { 320 | //clear edgeVertexPositionList 321 | drawData.edgeVertexPositionList.clear(); 322 | 323 | //inputGeo 324 | MObject oInputGeo = data.inputValue(aInputGeo).asMesh(); 325 | 326 | //fnMeshInputGeo 327 | MFnMesh fnMeshInputGeo(oInputGeo); 328 | 329 | //vertexPositionList 330 | MPointArray vertexPositionList; 331 | fnMeshInputGeo.getPoints(vertexPositionList); 332 | 333 | //itMeshPolyInputGeo 334 | MItMeshPolygon itMeshPolyInputGeo(oInputGeo); 335 | 336 | //for each poly 337 | while(!itMeshPolyInputGeo.isDone()) 338 | { 339 | //get edges 340 | MIntArray edgeIndexList; 341 | itMeshPolyInputGeo.getEdges(edgeIndexList); 342 | 343 | //edgeVertexIndices 344 | int2* edgeVertexIndices = new int2[4]; 345 | 346 | for(int index = 0; index < edgeIndexList.length(); index++) 347 | { 348 | fnMeshInputGeo.getEdgeVertices(edgeIndexList[index], edgeVertexIndices[index]); 349 | }; 350 | 351 | //edgeVertexIndicesNoDuplicates 352 | std::set setEdgeVertexIndicesNoDuplicates; 353 | 354 | for(int index = 0; index < edgeIndexList.length(); index++) 355 | { 356 | setEdgeVertexIndicesNoDuplicates.insert(edgeVertexIndices[index][0]); 357 | setEdgeVertexIndicesNoDuplicates.insert(edgeVertexIndices[index][1]); 358 | }; 359 | 360 | //vecEdgeVertexIndicesNoDuplicates 361 | std::vector vecEdgeVertexIndicesNoDuplicates(setEdgeVertexIndicesNoDuplicates.begin(), setEdgeVertexIndicesNoDuplicates.end()); 362 | 363 | 364 | //get faceVertexList 365 | MPointArray faceVertexPointList = MPointArray(4); 366 | 367 | for(int index = 0; index < edgeIndexList.length(); index++) 368 | { 369 | MPoint faceVertexPoint = vertexPositionList[vecEdgeVertexIndicesNoDuplicates[index]]; 370 | faceVertexPointList.set(faceVertexPoint, index); 371 | }; 372 | 373 | 374 | 375 | //edge01 376 | std::vector edge01; 377 | edge01.push_back(faceVertexPointList[0].x);edge01.push_back(faceVertexPointList[0].y);edge01.push_back(faceVertexPointList[0].z); 378 | edge01.push_back(faceVertexPointList[1].x);edge01.push_back(faceVertexPointList[1].y);edge01.push_back(faceVertexPointList[1].z); 379 | 380 | //edge13 381 | std::vector edge13; 382 | edge13.push_back(faceVertexPointList[1].x);edge13.push_back(faceVertexPointList[1].y);edge13.push_back(faceVertexPointList[1].z); 383 | edge13.push_back(faceVertexPointList[3].x);edge13.push_back(faceVertexPointList[3].y);edge13.push_back(faceVertexPointList[3].z); 384 | 385 | //edge32 386 | std::vector edge32; 387 | edge32.push_back(faceVertexPointList[3].x);edge32.push_back(faceVertexPointList[3].y);edge32.push_back(faceVertexPointList[3].z); 388 | edge32.push_back(faceVertexPointList[2].x);edge32.push_back(faceVertexPointList[2].y);edge32.push_back(faceVertexPointList[2].z); 389 | 390 | //edge20 391 | std::vector edge20; 392 | edge20.push_back(faceVertexPointList[2].x);edge20.push_back(faceVertexPointList[2].y);edge20.push_back(faceVertexPointList[2].z); 393 | edge20.push_back(faceVertexPointList[0].x);edge20.push_back(faceVertexPointList[0].y);edge20.push_back(faceVertexPointList[0].z); 394 | 395 | //edge03 396 | std::vector edge03; 397 | edge03.push_back(faceVertexPointList[0].x);edge03.push_back(faceVertexPointList[0].y);edge03.push_back(faceVertexPointList[0].z); 398 | edge03.push_back(faceVertexPointList[3].x);edge03.push_back(faceVertexPointList[3].y);edge03.push_back(faceVertexPointList[3].z); 399 | 400 | //edge12 401 | std::vector edge12; 402 | edge12.push_back(faceVertexPointList[1].x);edge12.push_back(faceVertexPointList[1].y);edge12.push_back(faceVertexPointList[1].z); 403 | edge12.push_back(faceVertexPointList[2].x);edge12.push_back(faceVertexPointList[2].y);edge12.push_back(faceVertexPointList[2].z); 404 | 405 | 406 | //add to drawData.edgeVertexPositionList 407 | drawData.edgeVertexPositionList.push_back(edge01); 408 | drawData.edgeVertexPositionList.push_back(edge13); 409 | drawData.edgeVertexPositionList.push_back(edge32); 410 | drawData.edgeVertexPositionList.push_back(edge20); 411 | drawData.edgeVertexPositionList.push_back(edge03); 412 | drawData.edgeVertexPositionList.push_back(edge12); 413 | 414 | //del edgeVertexIndices 415 | delete [] edgeVertexIndices; 416 | 417 | //Advance 418 | itMeshPolyInputGeo.next(); 419 | }; 420 | }; -------------------------------------------------------------------------------- /twClothSolverBlockout/twCheckCollision.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twCheckCollision Module 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | #Last Modified: 18.05.13 9 | #Author: Timm Wagener 10 | #Description: Simple check if points are inside a geometry 11 | 12 | 13 | 14 | #Setup Script 15 | #------------------------------------------------------------------------------------- 16 | 17 | ''' 18 | import pymel.core as pm 19 | 20 | 21 | #reload plugin 22 | #---------------------------------- 23 | try: 24 | #load new scene without saving 25 | pm.mel.eval('file -f -new;') 26 | #if plugin is loaded unload and reload it, else reload 27 | if(pm.pluginInfo( 'twClothSolverBlockoutPlugins.py', query=True, loaded=True )): 28 | pm.unloadPlugin( 'twClothSolverBlockoutPlugins.py' ) 29 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 30 | print('Successfully reloaded plugin') 31 | else: 32 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 33 | print('Successfully loaded plugin') 34 | except: 35 | print('Error Reloading Plugin') 36 | 37 | 38 | #create inputGeo 39 | #---------------------------------- 40 | #inputGeo 41 | inputGeoTrans = pm.polyCube(ch = False)[0] 42 | inputGeoShape = inputGeoTrans.getShape() 43 | inputGeoTrans.translate.set(0,5,0) 44 | pm.select(cl = True) 45 | pm.rename(inputGeoTrans, 'inputGeo') 46 | 47 | #create collisionGeo 48 | #---------------------------------- 49 | #collisionGeo 50 | collisionGeoTrans = pm.polyCube(ch = False)[0] 51 | collisionGeoShape = collisionGeoTrans.getShape() 52 | collisionGeoTrans.translate.set(0,2.5,0) 53 | pm.select(cl = True) 54 | pm.rename(collisionGeoTrans, 'collisionGeo') 55 | 56 | #create TwCheckCollision 57 | #---------------------------------- 58 | checkCollisionShape = pm.createNode('TwCheckCollision') 59 | checkCollisionShape.verbose.set(1) 60 | pm.select(cl = True) 61 | 62 | #connect TwCheckCollision 63 | #---------------------------------- 64 | inputGeoShape.outMesh >> checkCollisionShape.inputGeo 65 | inputGeoShape.parentMatrix >> checkCollisionShape.inputGeoParentMatrix 66 | collisionGeoShape.outMesh >> checkCollisionShape.collisionGeo 67 | collisionGeoShape.parentMatrix >> checkCollisionShape.collisionGeoParentMatrix 68 | pm.select(cl = True) 69 | 70 | #create outputGeo 71 | #---------------------------------- 72 | #outputGeo 73 | outputGeoTrans = pm.polyCube(ch = False)[0] 74 | outputGeoShape = outputGeoTrans.getShape() 75 | pm.select(cl = True) 76 | pm.rename(outputGeoTrans, 'outputGeo') 77 | 78 | #connect outputGeo 79 | #---------------------------------- 80 | checkCollisionShape.outputGeo >> outputGeoShape.inMesh 81 | pm.select(cl = True) 82 | 83 | #select inputGeo 84 | #---------------------------------- 85 | pm.select(inputGeoTrans, r = True) 86 | ''' 87 | 88 | 89 | 90 | #Imports 91 | #------------------------------------------------------------------------------------- 92 | import sys, math, time, random 93 | import maya.OpenMaya as OpenMaya 94 | import maya.OpenMayaMPx as OpenMayaMPx 95 | import maya.OpenMayaAnim as OpenMayaAnim 96 | import maya.OpenMayaRender as OpenMayaRender 97 | import maya.OpenMayaUI as OpenMayaUI 98 | 99 | 100 | 101 | #TwCheckCollision class 102 | #------------------------------------------------------------------------------------- 103 | 104 | class TwCheckCollision(OpenMayaMPx.MPxLocatorNode): 105 | '''TwCheckCollision utility class to perform check wether or not points are intersecting other objects''' 106 | 107 | 108 | 109 | #Class Variables 110 | #------------------------------------------------------------------------------------- 111 | 112 | kPluginNodeName = "TwCheckCollision" 113 | kPluginNodeId = OpenMaya.MTypeId(0x5800B) 114 | 115 | aVerbose = OpenMaya.MObject() 116 | 117 | aInputGeo = OpenMaya.MObject() 118 | aInputGeoParentMatrix = OpenMaya.MObject() 119 | 120 | aCollisionGeo = OpenMaya.MObject() 121 | aCollisionGeoParentMatrix = OpenMaya.MObject() 122 | 123 | aOutputGeo = OpenMaya.MObject() 124 | 125 | 126 | 127 | 128 | 129 | #Methods 130 | #------------------------------------------------------------------------------------- 131 | 132 | def __init__(self): 133 | '''TwCheckCollision __init__''' 134 | 135 | #instance variables 136 | self.verbose = False 137 | self.inputGeoVertexCollisionList = None 138 | self.inputGeoVertexPositionList = OpenMaya.MPointArray() 139 | 140 | #aGlRenderer will be initialized with Hardware renderer 141 | self.glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() 142 | 143 | #aGlFT hold reference to OpenGl fucntion table used by maya 144 | self.glFT = self.glRenderer.glFunctionTable() 145 | 146 | #Execute superclass constructor 147 | OpenMayaMPx.MPxLocatorNode.__init__(self) 148 | 149 | 150 | 151 | def compute(self, plug, data): 152 | '''Compute''' 153 | 154 | #Get all attrs to force update 155 | inputGeo = data.inputValue(self.aInputGeo).asMesh() 156 | inputGeoParentMatrix = data.inputValue(self.aInputGeoParentMatrix).asMatrix() 157 | 158 | collisionGeo = data.inputValue(self.aCollisionGeo).asMesh() 159 | collisionGeoParentMatrix = data.inputValue(self.aCollisionGeoParentMatrix).asMatrix() 160 | 161 | 162 | 163 | 164 | #Check if requested dirty plug equals output plug 165 | if(plug != self.aOutputGeo): 166 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Unknown Plug requested. Compute not executed') 167 | return OpenMaya.MStatus.kUnknownParameter 168 | 169 | else: 170 | 171 | #1-set verbose 172 | self.setVerbose(data) 173 | if(self.verbose):OpenMaya.MGlobal.displayInfo('-------------ComputationLoop-------------\nVerbose status set') 174 | 175 | 176 | #2-Check if attributes are connected 177 | #inputGeo 178 | if not(self.attrConnected('inputGeo')): 179 | if(self.verbose):OpenMaya.MGlobal.displayInfo('inputGeo not connected') 180 | return OpenMaya.MStatus.kSuccess 181 | #inputGeoParentMatrix 182 | if not(self.attrConnected('inputGeoParentMatrix')): 183 | if(self.verbose):OpenMaya.MGlobal.displayInfo('inputGeoParentMatrix not connected') 184 | return OpenMaya.MStatus.kSuccess 185 | #collisionGeo 186 | if not(self.attrConnected('collisionGeo')): 187 | if(self.verbose):OpenMaya.MGlobal.displayInfo('collisionGeo not connected') 188 | return OpenMaya.MStatus.kSuccess 189 | #collisionGeoParentMatrix 190 | if not(self.attrConnected('collisionGeoParentMatrix')): 191 | if(self.verbose):OpenMaya.MGlobal.displayInfo('collisionGeoParentMatrix not connected') 192 | return OpenMaya.MStatus.kSuccess 193 | 194 | 195 | #3-Compute collision 196 | self.computeCollision(data) 197 | 198 | 199 | 200 | #set plug clean 201 | data.setClean(plug) 202 | 203 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Compute executed') 204 | return OpenMaya.MStatus.kSuccess 205 | 206 | 207 | 208 | def draw(self, view, dagPath, displayStyle, displayStatus): 209 | '''Draws openGl to the viewport''' 210 | 211 | #check if self.inputGeoVertexCollisionList is true 212 | if not(self.inputGeoVertexCollisionList): return OpenMaya.MStatus.kSuccess 213 | 214 | #iterate vertexPositionList 215 | for index in range(self.inputGeoVertexPositionList.length()): 216 | 217 | view.beginGL() 218 | self.glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS ) 219 | 220 | self.glFT.glPointSize(5.0) 221 | self.glFT.glEnable(OpenMayaRender.MGL_POINT_SMOOTH) 222 | 223 | self.glFT.glBegin(OpenMayaRender.MGL_POINTS) 224 | 225 | #Set color 226 | self.glFT.glColor3f( 0.0, 1.0, 0.0 ) 227 | if(self.inputGeoVertexCollisionList[index]):self.glFT.glColor3f( 1.0, 0.0, 0.0 ) 228 | #draw vertices 229 | x = self.inputGeoVertexPositionList[index].x 230 | y = self.inputGeoVertexPositionList[index].y 231 | z = self.inputGeoVertexPositionList[index].z 232 | self.glFT.glVertex3f(x, y, z) 233 | 234 | 235 | self.glFT.glEnd() 236 | 237 | self.glFT.glPopAttrib() 238 | view.endGL() 239 | 240 | 241 | 242 | 243 | 244 | 245 | #Utility methods 246 | #------------------------------------------------------------------------------------- 247 | 248 | def setVerbose(self, data): 249 | '''Set instance variable verbose for output messages''' 250 | 251 | if(data.inputValue(self.aVerbose).asInt()): self.verbose = True 252 | else:self.verbose = False 253 | 254 | 255 | 256 | def attrConnected(self, attrName): 257 | '''Check if given attr of node is connected''' 258 | 259 | #Create FN for this node 260 | thisNode = self.thisMObject() 261 | fnDepNode = OpenMaya.MFnDependencyNode(thisNode) 262 | #Get MPLug for attribute name 263 | try: 264 | pAttr = fnDepNode.findPlug(attrName, True) 265 | except: 266 | if(self.verbose): OpenMaya.MGlobal.displayInfo('Error getting plug to attribute') 267 | return None 268 | 269 | return pAttr.isConnected() 270 | 271 | 272 | 273 | def computeCollision(self, data): 274 | '''Compute collision for inputGeo and collisionGeo''' 275 | 276 | #get inputGeoVertexPositionList 277 | inputGeoVertexPositionList = OpenMaya.MPointArray() 278 | oInputGeo = data.inputValue(self.aInputGeo).asMesh() 279 | fsInputGeo = OpenMaya.MFnMesh(oInputGeo) 280 | fsInputGeo.getPoints(inputGeoVertexPositionList) 281 | #get inputGeoParentMatrix 282 | inputGeoParentMatrix = data.inputValue(self.aInputGeoParentMatrix).asMatrix() 283 | #move inputGeoVertexPositionList to ws 284 | for index in range(inputGeoVertexPositionList.length()): 285 | inputGeoVertexPositionList.set(inputGeoVertexPositionList[index] * inputGeoParentMatrix ,index) 286 | 287 | 288 | #get collisionGeoVertexPositionList 289 | collisionGeoVertexPositionList = OpenMaya.MPointArray() 290 | oCollisionGeo = data.inputValue(self.aCollisionGeo).asMesh() 291 | fsCollisionGeo = OpenMaya.MFnMesh(oCollisionGeo) 292 | fsCollisionGeo.getPoints(collisionGeoVertexPositionList) 293 | #get collisionGeoParentMatrix 294 | collisionGeoParentMatrix = data.inputValue(self.aCollisionGeoParentMatrix).asMatrix() 295 | #move inputGeoVertexPositionList to ws 296 | for index in range(collisionGeoVertexPositionList.length()): 297 | collisionGeoVertexPositionList.set(collisionGeoVertexPositionList[index] * collisionGeoParentMatrix ,index) 298 | 299 | 300 | #get collisionGeoTriangleVertexIndexList 301 | collisionGeoTriangleCountList = OpenMaya.MIntArray() 302 | collisionGeoTriangleVertexIndexList = OpenMaya.MIntArray() 303 | fsCollisionGeo.getTriangles(collisionGeoTriangleCountList, collisionGeoTriangleVertexIndexList) 304 | 305 | #get triangleCount 306 | triangleCount = 0 307 | for index in range(0,collisionGeoTriangleVertexIndexList.length(),3): 308 | triangleCount+=1 309 | 310 | 311 | #if verbose print collision geo triangle stats 312 | if(self.verbose): 313 | OpenMaya.MGlobal.displayInfo('CollisionGeo triangle stats') 314 | for index in range(0,collisionGeoTriangleVertexIndexList.length(),3): 315 | OpenMaya.MGlobal.displayInfo('TriangleID: %s VertexIndices: %s-%s-%s' % (index/3, collisionGeoTriangleVertexIndexList[index], collisionGeoTriangleVertexIndexList[index+1], collisionGeoTriangleVertexIndexList[index+2])) 316 | 317 | 318 | #inputGeoVertexCollisionList 319 | self.inputGeoVertexCollisionList = [] 320 | 321 | #iterate and detect collision 322 | for index in range(inputGeoVertexPositionList.length()): 323 | collided = False 324 | collisionCounter = 0 325 | vecInputGeoPoint = OpenMaya.MVector(inputGeoVertexPositionList[index]) 326 | for triangleIndex in range(0,collisionGeoTriangleVertexIndexList.length(),3): 327 | #get vecTrianglePointA,B,C 328 | vecTrianglePointA = OpenMaya.MVector(collisionGeoVertexPositionList[collisionGeoTriangleVertexIndexList[triangleIndex]]) 329 | vecTrianglePointB = OpenMaya.MVector(collisionGeoVertexPositionList[collisionGeoTriangleVertexIndexList[triangleIndex+1]]) 330 | vecTrianglePointC = OpenMaya.MVector(collisionGeoVertexPositionList[collisionGeoTriangleVertexIndexList[triangleIndex+2]]) 331 | 332 | #get vecTriangleNormal 333 | vecTriangleNormal = ((vecTrianglePointB - vecTrianglePointA)^(vecTrianglePointC - vecTrianglePointA)).normal() 334 | 335 | #get planeDistance 336 | planeDistance = -1 * (vecTrianglePointA * vecTriangleNormal) 337 | 338 | #solve for vecInputGeoPoint 339 | collisionDecisionValue = (vecTriangleNormal*vecInputGeoPoint) + planeDistance 340 | #set collided var 341 | if(collisionDecisionValue >= 0): break 342 | else: collisionCounter += 1 343 | 344 | #Append collided value to inputGeoVertexCollisionList 345 | if(collisionCounter == triangleCount): collided = True 346 | self.inputGeoVertexCollisionList.append(collided) 347 | 348 | #set instance var for draw method 349 | self.inputGeoVertexPositionList = OpenMaya.MPointArray(inputGeoVertexPositionList) 350 | 351 | 352 | 353 | 354 | #Initialization 355 | #------------------------------------------------------------------------------------- 356 | 357 | 358 | def createTwCheckCollision(): 359 | '''Create and deliver a pointer to an instance of TwCheckCollision''' 360 | return OpenMayaMPx.asMPxPtr(TwCheckCollision()) 361 | 362 | 363 | def initializeTwCheckCollision(): 364 | '''Initializes the TwCheckCollision class factory with attributes. Is called only once when the plugin is registered.''' 365 | 366 | 367 | #Functionsets 368 | tAttr = OpenMaya.MFnTypedAttribute() 369 | eAttr = OpenMaya.MFnEnumAttribute() 370 | mAttr = OpenMaya.MFnMatrixAttribute() 371 | 372 | 373 | 374 | #aVerbose 375 | TwCheckCollision.aVerbose = eAttr.create('verbose', 'verbose') 376 | eAttr.addField('noVerbose', 0) 377 | eAttr.addField('Verbose', 1) 378 | TwCheckCollision.addAttribute(TwCheckCollision.aVerbose) 379 | 380 | 381 | #aInputGeo 382 | TwCheckCollision.aInputGeo = tAttr.create('inputGeo', 'inputGeo', OpenMaya.MFnData.kMesh) 383 | tAttr.setWritable(True) 384 | tAttr.setReadable(False) 385 | TwCheckCollision.addAttribute(TwCheckCollision.aInputGeo) 386 | #aInputGeoParentMatrix 387 | TwCheckCollision.aInputGeoParentMatrix = mAttr.create('inputGeoParentMatrix', 'inputGeoParentMatrix') 388 | mAttr.setReadable(False) 389 | mAttr.setHidden(True) 390 | TwCheckCollision.addAttribute(TwCheckCollision.aInputGeoParentMatrix) 391 | 392 | 393 | 394 | #aCollisionGeo 395 | TwCheckCollision.aCollisionGeo = tAttr.create('collisionGeo', 'collisionGeo', OpenMaya.MFnData.kMesh) 396 | tAttr.setWritable(True) 397 | tAttr.setReadable(False) 398 | TwCheckCollision.addAttribute(TwCheckCollision.aCollisionGeo) 399 | #aCollisionGeoParentMatrix 400 | TwCheckCollision.aCollisionGeoParentMatrix = mAttr.create('collisionGeoParentMatrix', 'collisionGeoParentMatrix') 401 | mAttr.setReadable(False) 402 | mAttr.setHidden(True) 403 | TwCheckCollision.addAttribute(TwCheckCollision.aCollisionGeoParentMatrix) 404 | 405 | 406 | 407 | #aOutputGeo 408 | TwCheckCollision.aOutputGeo = tAttr.create('outputGeo', 'outputGeo', OpenMaya.MFnData.kMesh) 409 | tAttr.setWritable(False) 410 | tAttr.setReadable(True) 411 | TwCheckCollision.addAttribute(TwCheckCollision.aOutputGeo) 412 | 413 | 414 | 415 | #attributeAffects 416 | TwCheckCollision.attributeAffects(TwCheckCollision.aInputGeo, TwCheckCollision.aOutputGeo) 417 | TwCheckCollision.attributeAffects(TwCheckCollision.aInputGeoParentMatrix, TwCheckCollision.aOutputGeo) 418 | 419 | TwCheckCollision.attributeAffects(TwCheckCollision.aCollisionGeo, TwCheckCollision.aOutputGeo) 420 | TwCheckCollision.attributeAffects(TwCheckCollision.aCollisionGeoParentMatrix, TwCheckCollision.aOutputGeo) -------------------------------------------------------------------------------- /twClothSolverBlockout/twDrawBB.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twDrawBB Module 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | #Last Modified: 18.05.13 9 | #Author: Timm Wagener 10 | #Description: Simple drawing of BBox 11 | 12 | 13 | 14 | #Setup Script 15 | #------------------------------------------------------------------------------------- 16 | 17 | ''' 18 | import pymel.core as pm 19 | 20 | 21 | #reload plugin 22 | #---------------------------------- 23 | try: 24 | #load new scene without saving 25 | pm.mel.eval('file -f -new;') 26 | #if plugin is loaded unload and reload it, else reload 27 | if(pm.pluginInfo( 'twClothSolverBlockoutPlugins.py', query=True, loaded=True )): 28 | pm.unloadPlugin( 'twClothSolverBlockoutPlugins.py' ) 29 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 30 | print('Successfully reloaded plugin') 31 | else: 32 | pm.loadPlugin( 'twClothSolverBlockoutPlugins.py' ) 33 | print('Successfully loaded plugin') 34 | except: 35 | print('Error Reloading Plugin') 36 | 37 | 38 | #create inputGeo 39 | #---------------------------------- 40 | #inputGeo 41 | inputGeoTrans = pm.polyHelix(c = 5, h = 12, w = 10, r = 1, cuv = 3, ch = False, n = 'BBCheckHelix')[0] 42 | inputGeoShape = inputGeoTrans.getShape() 43 | inputGeoTrans.translate.set(0,5,0) 44 | pm.select(cl = True) 45 | 46 | #create TwDrawBB 47 | #---------------------------------- 48 | drawBBShape = pm.createNode('TwDrawBB') 49 | drawBBShape.verbose.set(1) 50 | drawBBShape.bBoxType.set(1) 51 | pm.select(cl = True) 52 | 53 | #connect TwCheckCollision 54 | #---------------------------------- 55 | inputGeoShape.outMesh >> drawBBShape.inputGeo 56 | inputGeoShape.parentMatrix >> drawBBShape.inputGeoParentMatrix 57 | pm.select(cl = True) 58 | 59 | #create outputGeo 60 | #---------------------------------- 61 | #outputGeo 62 | outputGeoTrans = pm.polyCube(ch = False)[0] 63 | outputGeoShape = outputGeoTrans.getShape() 64 | pm.select(cl = True) 65 | pm.rename(outputGeoTrans, 'outputGeo') 66 | 67 | #connect outputGeo 68 | #---------------------------------- 69 | drawBBShape.outputGeo >> outputGeoShape.inMesh 70 | pm.select(cl = True) 71 | 72 | #select inputGeo 73 | #---------------------------------- 74 | pm.select(drawBBShape, r = True) 75 | ''' 76 | 77 | 78 | 79 | #Imports 80 | #------------------------------------------------------------------------------------- 81 | import sys, math, time, random 82 | import maya.OpenMaya as OpenMaya 83 | import maya.OpenMayaMPx as OpenMayaMPx 84 | import maya.OpenMayaAnim as OpenMayaAnim 85 | import maya.OpenMayaRender as OpenMayaRender 86 | import maya.OpenMayaUI as OpenMayaUI 87 | 88 | 89 | 90 | #TwDrawBB class 91 | #------------------------------------------------------------------------------------- 92 | 93 | class TwDrawBB(OpenMayaMPx.MPxLocatorNode): 94 | '''TwDrawBB utility class to calculate, test and draw different BBox methods''' 95 | 96 | 97 | 98 | #Class Variables 99 | #------------------------------------------------------------------------------------- 100 | 101 | kPluginNodeName = "TwDrawBB" 102 | kPluginNodeId = OpenMaya.MTypeId(0x5600B) 103 | 104 | aVerbose = OpenMaya.MObject() 105 | 106 | aInputGeo = OpenMaya.MObject() 107 | aInputGeoParentMatrix = OpenMaya.MObject() 108 | 109 | aBBoxType = OpenMaya.MObject() 110 | 111 | aOutputGeo = OpenMaya.MObject() 112 | 113 | 114 | 115 | 116 | 117 | #Methods 118 | #------------------------------------------------------------------------------------- 119 | 120 | def __init__(self): 121 | '''TwDrawBB __init__''' 122 | 123 | #instance variables 124 | self.verbose = False 125 | self.minBBoxPoint = [] 126 | self.maxBBoxPoint = [] 127 | self.bBoxType = 0 128 | self.inputGeoParentMatrix = None 129 | 130 | #aGlRenderer will be initialized with Hardware renderer 131 | self.glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() 132 | 133 | #aGlFT hold reference to OpenGl fucntion table used by maya 134 | self.glFT = self.glRenderer.glFunctionTable() 135 | 136 | #Execute superclass constructor 137 | OpenMayaMPx.MPxLocatorNode.__init__(self) 138 | 139 | 140 | 141 | def compute(self, plug, data): 142 | '''Compute''' 143 | 144 | #Get all attrs to force update 145 | inputGeo = data.inputValue(self.aInputGeo).asMesh() 146 | inputGeoParentMatrix = data.inputValue(self.aInputGeoParentMatrix).asMatrix() 147 | 148 | 149 | #Check if requested dirty plug equals output plug 150 | if(plug != self.aOutputGeo): 151 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Unknown Plug requested. Compute not executed') 152 | return OpenMaya.MStatus.kUnknownParameter 153 | 154 | else: 155 | 156 | #1-set verbose 157 | self.setVerbose(data) 158 | if(self.verbose):OpenMaya.MGlobal.displayInfo('-------------ComputationLoop-------------\nVerbose status set') 159 | 160 | 161 | #2-Check if attributes are connected 162 | #inputGeo 163 | if not(self.attrConnected('inputGeo')): 164 | if(self.verbose):OpenMaya.MGlobal.displayInfo('inputGeo not connected') 165 | return OpenMaya.MStatus.kSuccess 166 | #inputGeoParentMatrix 167 | if not(self.attrConnected('inputGeoParentMatrix')): 168 | if(self.verbose):OpenMaya.MGlobal.displayInfo('inputGeoParentMatrix not connected') 169 | return OpenMaya.MStatus.kSuccess 170 | 171 | 172 | #3-Compute BBox 173 | self.computeBBox(data) 174 | 175 | 176 | 177 | #set plug clean 178 | data.setClean(plug) 179 | 180 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Compute executed') 181 | return OpenMaya.MStatus.kSuccess 182 | 183 | 184 | 185 | def draw(self, view, dagPath, displayStyle, displayStatus): 186 | '''Draws openGl to the viewport''' 187 | 188 | 189 | #check if self.minBBoxPoint is true 190 | if not(self.minBBoxPoint): return OpenMaya.MStatus.kSuccess 191 | 192 | #determine drawType 193 | if(self.bBoxType == 0): self.drawBBoxAABB(view, dagPath, displayStyle, displayStatus) 194 | elif(self.bBoxType == 1): self.drawBBoxOOB(view, dagPath, displayStyle, displayStatus) 195 | 196 | return OpenMaya.MStatus.kSuccess 197 | 198 | 199 | 200 | 201 | 202 | #Utility methods 203 | #------------------------------------------------------------------------------------- 204 | 205 | def setVerbose(self, data): 206 | '''Set instance variable verbose for output messages''' 207 | 208 | if(data.inputValue(self.aVerbose).asInt()): self.verbose = True 209 | else:self.verbose = False 210 | 211 | 212 | def getBBoxType(self, data): 213 | '''Convenience method to get BBoxType Attr value''' 214 | 215 | return data.inputValue(self.aBBoxType).asInt() 216 | 217 | 218 | 219 | def attrConnected(self, attrName): 220 | '''Check if given attr of node is connected''' 221 | 222 | #Create FN for this node 223 | thisNode = self.thisMObject() 224 | fnDepNode = OpenMaya.MFnDependencyNode(thisNode) 225 | #Get MPLug for attribute name 226 | try: 227 | pAttr = fnDepNode.findPlug(attrName, True) 228 | except: 229 | if(self.verbose): OpenMaya.MGlobal.displayInfo('Error getting plug to attribute') 230 | return None 231 | 232 | return pAttr.isConnected() 233 | 234 | 235 | 236 | def computeBBox(self, data): 237 | '''Compute collision for inputGeo and collisionGeo''' 238 | 239 | #get inputGeoVertexPositionList 240 | inputGeoVertexPositionList = OpenMaya.MPointArray() 241 | oInputGeo = data.inputValue(self.aInputGeo).asMesh() 242 | fsInputGeo = OpenMaya.MFnMesh(oInputGeo) 243 | fsInputGeo.getPoints(inputGeoVertexPositionList) 244 | #get inputGeoParentMatrix 245 | inputGeoParentMatrix = data.inputValue(self.aInputGeoParentMatrix).asMatrix() 246 | #move inputGeoVertexPositionList to ws 247 | for index in range(inputGeoVertexPositionList.length()): 248 | inputGeoVertexPositionList.set(inputGeoVertexPositionList[index] * inputGeoParentMatrix ,index) 249 | 250 | 251 | #execute BBox 252 | #AABB 253 | if not(self.getBBoxType(data)): self.bBoxType = 0; self.computeBBoxAABB(inputGeoVertexPositionList) 254 | #OOB 255 | elif(self.getBBoxType(data) == 1): self.bBoxType = 1; self.computeBBoxOOB(inputGeoVertexPositionList, inputGeoParentMatrix) 256 | 257 | 258 | 259 | def computeBBoxAABB(self, inputGeoVertexPositionList): 260 | '''Compute AxisAligned BBox''' 261 | 262 | #iterate inputGeoVertexPositionList to find minPoint and maxPoint 263 | minX = self.getMin('x', inputGeoVertexPositionList) 264 | minY = self.getMin('y', inputGeoVertexPositionList) 265 | minZ = self.getMin('z', inputGeoVertexPositionList) 266 | 267 | maxX = self.getMax('x', inputGeoVertexPositionList) 268 | maxY = self.getMax('y', inputGeoVertexPositionList) 269 | maxZ = self.getMax('z', inputGeoVertexPositionList) 270 | 271 | #set instance vars 272 | self.minBBoxPoint = [minX, minY, minZ] 273 | self.maxBBoxPoint = [maxX, maxY, maxZ] 274 | 275 | 276 | 277 | def computeBBoxOOB(self, inputGeoVertexPositionList, inputGeoParentMatrix): 278 | '''Compute OOB BBox''' 279 | 280 | #move inputGeoVertexPositionList to Local Space 281 | for index in range(inputGeoVertexPositionList.length()): 282 | inputGeoVertexPositionList.set(inputGeoVertexPositionList[index] * inputGeoParentMatrix.inverse() ,index) 283 | 284 | #iterate inputGeoVertexPositionList to find minPoint and maxPoint 285 | minX = self.getMin('x', inputGeoVertexPositionList) 286 | minY = self.getMin('y', inputGeoVertexPositionList) 287 | minZ = self.getMin('z', inputGeoVertexPositionList) 288 | 289 | maxX = self.getMax('x', inputGeoVertexPositionList) 290 | maxY = self.getMax('y', inputGeoVertexPositionList) 291 | maxZ = self.getMax('z', inputGeoVertexPositionList) 292 | 293 | #create mPoints and multiply with inputGeoParentMatrix 294 | minPoint = OpenMaya.MPoint(minX, minY, minZ) 295 | maxPoint = OpenMaya.MPoint(maxX, maxY, maxZ) 296 | 297 | #set instance vars 298 | self.minBBoxPoint = [minPoint.x, minPoint.y, minPoint.z] 299 | self.maxBBoxPoint = [maxPoint.x, maxPoint.y, maxPoint.z] 300 | 301 | self.inputGeoParentMatrix = inputGeoParentMatrix 302 | 303 | 304 | 305 | def getMin(self, type, pointArray): 306 | '''Get minimum value out of mPointArray''' 307 | 308 | minValue = None 309 | for index in range(pointArray.length()): 310 | if not(index): 311 | if(type == 'x'):minValue = pointArray[index].x 312 | elif(type == 'y'):minValue = pointArray[index].y 313 | elif(type == 'z'):minValue = pointArray[index].z 314 | 315 | else: 316 | if(type == 'x'): 317 | if(minValue > pointArray[index].x): minValue = pointArray[index].x 318 | if(type == 'y'): 319 | if(minValue > pointArray[index].y): minValue = pointArray[index].y 320 | if(type == 'z'): 321 | if(minValue > pointArray[index].z): minValue = pointArray[index].z 322 | 323 | return minValue 324 | 325 | 326 | 327 | def getMax(self, type, pointArray): 328 | '''Get minimum value out of mPointArray''' 329 | 330 | maxValue = None 331 | for index in range(pointArray.length()): 332 | if not(index): 333 | if(type == 'x'):maxValue = pointArray[index].x 334 | elif(type == 'y'):maxValue = pointArray[index].y 335 | elif(type == 'z'):maxValue = pointArray[index].z 336 | 337 | else: 338 | if(type == 'x'): 339 | if(maxValue < pointArray[index].x): maxValue = pointArray[index].x 340 | if(type == 'y'): 341 | if(maxValue < pointArray[index].y): maxValue = pointArray[index].y 342 | if(type == 'z'): 343 | if(maxValue < pointArray[index].z): maxValue = pointArray[index].z 344 | 345 | return maxValue 346 | 347 | 348 | 349 | def drawBBoxAABB(self, view, dagPath, displayStyle, displayStatus): 350 | '''Draw BBox for mode AABB''' 351 | 352 | #draw BBox from minBBoxPoint and maxBBoxPoint 353 | view.beginGL() 354 | self.glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS ) 355 | 356 | 357 | #Draw Vertices 358 | #------------------------------------------------------------------------------------- 359 | self.glFT.glPointSize(5.0) 360 | self.glFT.glEnable(OpenMayaRender.MGL_POINT_SMOOTH) 361 | 362 | self.glFT.glBegin(OpenMayaRender.MGL_POINTS) 363 | 364 | #Set color 365 | self.glFT.glColor3f( 0.0, 1.0, 0.0 ) 366 | 367 | #draw vertices 368 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 369 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 370 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 371 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 372 | 373 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 374 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 375 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 376 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 377 | 378 | 379 | self.glFT.glEnd() 380 | #------------------------------------------------------------------------------------- 381 | 382 | 383 | #Draw Edges 384 | #------------------------------------------------------------------------------------- 385 | self.glFT.glBegin(OpenMayaRender.MGL_LINES) 386 | 387 | #Set color 388 | self.glFT.glColor3f( 0.0, 1.0, 0.0 ) 389 | 390 | #draw vertices 391 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 392 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 393 | 394 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 395 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 396 | 397 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 398 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 399 | 400 | 401 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 402 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 403 | 404 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 405 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 406 | 407 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 408 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 409 | 410 | 411 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 412 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 413 | 414 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 415 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 416 | 417 | 418 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 419 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 420 | 421 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 422 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 423 | 424 | 425 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) 426 | self.glFT.glVertex3f(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) 427 | 428 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) 429 | self.glFT.glVertex3f(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) 430 | 431 | 432 | self.glFT.glEnd() 433 | #------------------------------------------------------------------------------------- 434 | 435 | self.glFT.glPopAttrib() 436 | view.endGL() 437 | 438 | 439 | def drawBBoxOOB(self, view, dagPath, displayStyle, displayStatus): 440 | '''Draw BBox for type OOB''' 441 | 442 | 443 | 444 | #create points from min and maxPoints and move them to ws 445 | pointA = OpenMaya.MPoint(self.minBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) * self.inputGeoParentMatrix 446 | pointB = OpenMaya.MPoint(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.minBBoxPoint[2]) * self.inputGeoParentMatrix 447 | pointC = OpenMaya.MPoint(self.minBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) * self.inputGeoParentMatrix 448 | pointD = OpenMaya.MPoint(self.maxBBoxPoint[0], self.minBBoxPoint[1], self.maxBBoxPoint[2]) * self.inputGeoParentMatrix 449 | 450 | pointE = OpenMaya.MPoint(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) * self.inputGeoParentMatrix 451 | pointF = OpenMaya.MPoint(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.maxBBoxPoint[2]) * self.inputGeoParentMatrix 452 | pointG = OpenMaya.MPoint(self.maxBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) * self.inputGeoParentMatrix 453 | pointH = OpenMaya.MPoint(self.minBBoxPoint[0], self.maxBBoxPoint[1], self.minBBoxPoint[2]) * self.inputGeoParentMatrix 454 | 455 | 456 | #OpenGL 457 | #------------------------------------------------------------------------------------- 458 | view.beginGL() 459 | self.glFT.glPushAttrib( OpenMayaRender.MGL_ALL_ATTRIB_BITS ) 460 | 461 | 462 | #Draw Vertices 463 | #------------------------------------------------------------------------------------- 464 | self.glFT.glPointSize(5.0) 465 | self.glFT.glEnable(OpenMayaRender.MGL_POINT_SMOOTH) 466 | 467 | self.glFT.glBegin(OpenMayaRender.MGL_POINTS) 468 | 469 | #Set color 470 | self.glFT.glColor3f( 0.0, 1.0, 0.0 ) 471 | 472 | #draw vertices 473 | self.glFT.glVertex3f(pointA.x, pointA.y, pointA.z) 474 | self.glFT.glVertex3f(pointB.x, pointB.y, pointB.z) 475 | self.glFT.glVertex3f(pointC.x, pointC.y, pointC.z) 476 | self.glFT.glVertex3f(pointD.x, pointD.y, pointD.z) 477 | 478 | self.glFT.glVertex3f(pointE.x, pointE.y, pointE.z) 479 | self.glFT.glVertex3f(pointF.x, pointF.y, pointF.z) 480 | self.glFT.glVertex3f(pointG.x, pointG.y, pointG.z) 481 | self.glFT.glVertex3f(pointH.x, pointH.y, pointH.z) 482 | 483 | 484 | self.glFT.glEnd() 485 | #------------------------------------------------------------------------------------- 486 | 487 | 488 | #Draw Edges 489 | #------------------------------------------------------------------------------------- 490 | self.glFT.glBegin(OpenMayaRender.MGL_LINES) 491 | 492 | #Set color 493 | self.glFT.glColor3f( 0.0, 1.0, 0.0 ) 494 | 495 | #draw vertices 496 | self.glFT.glVertex3f(pointA.x, pointA.y, pointA.z) 497 | self.glFT.glVertex3f(pointB.x, pointB.y, pointB.z) 498 | 499 | self.glFT.glVertex3f(pointB.x, pointB.y, pointB.z) 500 | self.glFT.glVertex3f(pointD.x, pointD.y, pointD.z) 501 | 502 | self.glFT.glVertex3f(pointD.x, pointD.y, pointD.z) 503 | self.glFT.glVertex3f(pointC.x, pointC.y, pointC.z) 504 | 505 | self.glFT.glVertex3f(pointC.x, pointC.y, pointC.z) 506 | self.glFT.glVertex3f(pointA.x, pointA.y, pointA.z) 507 | 508 | 509 | self.glFT.glVertex3f(pointE.x, pointE.y, pointE.z) 510 | self.glFT.glVertex3f(pointF.x, pointF.y, pointF.z) 511 | 512 | self.glFT.glVertex3f(pointF.x, pointF.y, pointF.z) 513 | self.glFT.glVertex3f(pointH.x, pointH.y, pointH.z) 514 | 515 | self.glFT.glVertex3f(pointH.x, pointH.y, pointH.z) 516 | self.glFT.glVertex3f(pointG.x, pointG.y, pointG.z) 517 | 518 | self.glFT.glVertex3f(pointG.x, pointG.y, pointG.z) 519 | self.glFT.glVertex3f(pointE.x, pointE.y, pointE.z) 520 | 521 | 522 | self.glFT.glVertex3f(pointD.x, pointD.y, pointD.z) 523 | self.glFT.glVertex3f(pointE.x, pointE.y, pointE.z) 524 | 525 | self.glFT.glVertex3f(pointA.x, pointA.y, pointA.z) 526 | self.glFT.glVertex3f(pointH.x, pointH.y, pointH.z) 527 | 528 | self.glFT.glVertex3f(pointB.x, pointB.y, pointB.z) 529 | self.glFT.glVertex3f(pointG.x, pointG.y, pointG.z) 530 | 531 | self.glFT.glVertex3f(pointF.x, pointF.y, pointF.z) 532 | self.glFT.glVertex3f(pointC.x, pointC.y, pointC.z) 533 | 534 | 535 | self.glFT.glEnd() 536 | #------------------------------------------------------------------------------------- 537 | 538 | 539 | self.glFT.glPopAttrib() 540 | view.endGL() 541 | 542 | 543 | 544 | #Initialization 545 | #------------------------------------------------------------------------------------- 546 | 547 | 548 | def createTwDrawBB(): 549 | '''Create and deliver a pointer to an instance of TwDrawBB''' 550 | return OpenMayaMPx.asMPxPtr(TwDrawBB()) 551 | 552 | 553 | def initializeTwDrawBB(): 554 | '''Initializes the TwDrawBB class factory with attributes. Is called only once when the plugin is registered.''' 555 | 556 | 557 | #Functionsets 558 | tAttr = OpenMaya.MFnTypedAttribute() 559 | eAttr = OpenMaya.MFnEnumAttribute() 560 | mAttr = OpenMaya.MFnMatrixAttribute() 561 | 562 | 563 | 564 | #aVerbose 565 | TwDrawBB.aVerbose = eAttr.create('verbose', 'verbose') 566 | eAttr.addField('noVerbose', 0) 567 | eAttr.addField('Verbose', 1) 568 | TwDrawBB.addAttribute(TwDrawBB.aVerbose) 569 | 570 | 571 | #aInputGeo 572 | TwDrawBB.aInputGeo = tAttr.create('inputGeo', 'inputGeo', OpenMaya.MFnData.kMesh) 573 | tAttr.setWritable(True) 574 | tAttr.setReadable(False) 575 | TwDrawBB.addAttribute(TwDrawBB.aInputGeo) 576 | #aInputGeoParentMatrix 577 | TwDrawBB.aInputGeoParentMatrix = mAttr.create('inputGeoParentMatrix', 'inputGeoParentMatrix') 578 | mAttr.setReadable(False) 579 | mAttr.setHidden(True) 580 | TwDrawBB.addAttribute(TwDrawBB.aInputGeoParentMatrix) 581 | 582 | 583 | #aBBoxType 584 | TwDrawBB.aBBoxType = eAttr.create('bBoxType', 'bBoxType') 585 | eAttr.addField('AABB', 0) 586 | eAttr.addField('OOB', 1) 587 | TwDrawBB.addAttribute(TwDrawBB.aBBoxType) 588 | 589 | 590 | #aOutputGeo 591 | TwDrawBB.aOutputGeo = tAttr.create('outputGeo', 'outputGeo', OpenMaya.MFnData.kMesh) 592 | tAttr.setWritable(False) 593 | tAttr.setReadable(True) 594 | TwDrawBB.addAttribute(TwDrawBB.aOutputGeo) 595 | 596 | 597 | 598 | #attributeAffects 599 | TwDrawBB.attributeAffects(TwDrawBB.aInputGeo, TwDrawBB.aOutputGeo) 600 | TwDrawBB.attributeAffects(TwDrawBB.aInputGeoParentMatrix, TwDrawBB.aOutputGeo) 601 | TwDrawBB.attributeAffects(TwDrawBB.aBBoxType, TwDrawBB.aOutputGeo) -------------------------------------------------------------------------------- /twClothSolver/cudaFunctionality.cu: -------------------------------------------------------------------------------- 1 | 2 | 3 | //include 4 | //----------------------------------------------- 5 | //cuda 6 | #include "helper_math.h" 7 | 8 | //own 9 | #include "cudaFunctionality.h" 10 | 11 | 12 | //kernels 13 | //----------------------------------------------- 14 | 15 | namespace kernels 16 | { 17 | //add_on_gpu 18 | __global__ void add_on_gpu(float a, float b, float* p_result) 19 | { 20 | //result 21 | *p_result = a + b; 22 | } 23 | 24 | //verletIntegration 25 | __global__ void verletIntegration(staticSolverData_t staticSolverData, dynamicSolverData_t dynamicSolverData) 26 | { 27 | //thread_index 28 | int thread_index = blockIdx.x * blockDim.x + threadIdx.x; 29 | 30 | //execute if thread_index < vertexCount 31 | if(thread_index < staticSolverData.vertexCount) 32 | { 33 | 34 | //vecNew 35 | float3 vecNew = make_float3(0,0,0); //initialize to zero 36 | 37 | //vecPos 38 | float3 vecPos = make_float3(staticSolverData.pVertexPositionList[thread_index].x, 39 | staticSolverData.pVertexPositionList[thread_index].y, 40 | staticSolverData.pVertexPositionList[thread_index].z 41 | ); 42 | 43 | //vecOldpos 44 | float3 vecOldpos = make_float3(staticSolverData.pVertexOldpositionList[thread_index].x, 45 | staticSolverData.pVertexOldpositionList[thread_index].y, 46 | staticSolverData.pVertexOldpositionList[thread_index].z 47 | ); 48 | 49 | //vecForce 50 | float3 vecForce = make_float3(dynamicSolverData.pVertexForceList[thread_index].x, 51 | dynamicSolverData.pVertexForceList[thread_index].y, 52 | dynamicSolverData.pVertexForceList[thread_index].z 53 | ); 54 | 55 | //drag 56 | float drag = 1.0 - dynamicSolverData.drag; 57 | 58 | //integration 59 | vecNew = (vecPos + ((vecPos - vecOldpos) * drag)) + vecForce; 60 | 61 | 62 | //update solverData 63 | 64 | //pVertexOldpositionList 65 | staticSolverData.pVertexOldpositionList[thread_index].x = vecPos.x; 66 | staticSolverData.pVertexOldpositionList[thread_index].y = vecPos.y; 67 | staticSolverData.pVertexOldpositionList[thread_index].z = vecPos.z; 68 | 69 | //pVertexOldpositionList 70 | staticSolverData.pVertexPositionList[thread_index].x = vecNew.x; 71 | staticSolverData.pVertexPositionList[thread_index].y = vecNew.y; 72 | staticSolverData.pVertexPositionList[thread_index].z = vecNew.z; 73 | 74 | } 75 | } 76 | 77 | //collisionConstraintGroundplane 78 | __global__ void collisionConstraintGroundplane(staticSolverData_t staticSolverData, dynamicSolverData_t dynamicSolverData) 79 | { 80 | //thread_index 81 | int thread_index = blockIdx.x * blockDim.x + threadIdx.x; 82 | 83 | //execute if thread_index < vertexCount 84 | if(thread_index < staticSolverData.vertexCount) 85 | { 86 | //if point pos y is < than groundplane height set to groundplane height 87 | if(staticSolverData.pVertexPositionList[thread_index].y < dynamicSolverData.groundplaneHeight) 88 | staticSolverData.pVertexPositionList[thread_index].y = dynamicSolverData.groundplaneHeight; 89 | } 90 | } 91 | 92 | //collisionConstraintSpheres 93 | __global__ void collisionConstraintSpheres(staticSolverData_t staticSolverData, dynamicSolverData_t dynamicSolverData) 94 | { 95 | //thread_index 96 | int thread_index = blockIdx.x * blockDim.x + threadIdx.x; 97 | 98 | //execute if thread_index < vertexCount 99 | if(thread_index < staticSolverData.vertexCount) 100 | { 101 | for(int collisionSphereIndex = 0; collisionSphereIndex < dynamicSolverData.collisionConstraintSpheresCount * 2; collisionSphereIndex+=2 ) 102 | { 103 | 104 | //New 105 | //----------------------------------------------- 106 | 107 | //vecDownToUp and radiusSphere 108 | 109 | //vecUp 110 | float3 vecUp = make_float3(dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex].x, 111 | dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex].y, 112 | dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex].z 113 | ); 114 | 115 | //vecDown 116 | float3 vecDown = make_float3(dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex+1].x, 117 | dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex+1].y, 118 | dynamicSolverData.pCollisionConstraintSpheresVecUpVecDownList[collisionSphereIndex+1].z 119 | ); 120 | 121 | //vecDownToUp 122 | float3 vecDownToUp = make_float3(0,0,0); 123 | vecDownToUp = vecUp - vecDown; 124 | 125 | //vecSphereCenter 126 | float3 vecSphereCenter = make_float3(0,0,0); 127 | vecSphereCenter = vecDown + (vecDownToUp * 0.5); 128 | 129 | //radiusSphere 130 | float radiusSphere = length(vecDownToUp * 0.5); 131 | 132 | 133 | 134 | 135 | //perform collision projection 136 | 137 | //vecCurrentPoint 138 | float3 vecCurrentPoint = make_float3(staticSolverData.pVertexPositionList[thread_index].x, 139 | staticSolverData.pVertexPositionList[thread_index].y, 140 | staticSolverData.pVertexPositionList[thread_index].z 141 | ); 142 | 143 | //vecSphereCenterToCurrentPoint 144 | float3 vecSphereCenterToCurrentPoint = vecCurrentPoint - vecSphereCenter; 145 | 146 | 147 | //vecSphereCenterToCurrentPointLength 148 | float vecSphereCenterToCurrentPointLength = length(vecSphereCenterToCurrentPoint); 149 | 150 | //check if length < radius 151 | if(vecSphereCenterToCurrentPointLength < radiusSphere) 152 | { 153 | //currentPointProjected 154 | float3 currentPointProjected = make_float3(0,0,0); 155 | currentPointProjected = vecSphereCenter + ((vecSphereCenterToCurrentPoint / vecSphereCenterToCurrentPointLength) * radiusSphere); 156 | 157 | //set to solverData 158 | staticSolverData.pVertexPositionList[thread_index].x = currentPointProjected.x; 159 | staticSolverData.pVertexPositionList[thread_index].y = currentPointProjected.y; 160 | staticSolverData.pVertexPositionList[thread_index].z = currentPointProjected.z; 161 | 162 | }; 163 | 164 | } 165 | } 166 | } 167 | 168 | //stickConstraint 169 | __global__ void stickConstraint(staticSolverData_t staticSolverData, dynamicSolverData_t dynamicSolverData) 170 | { 171 | //New 172 | 173 | //iterate edges 174 | for(int index = 0; index < staticSolverData.edgeCount; index++) 175 | { 176 | //restLength 177 | float restLength = staticSolverData.pEdgeRestlengthList[index]; 178 | //vertexIndices 179 | int vertexIndex1 = int(staticSolverData.pEdgeVertexIndexList[index].x); 180 | int vertexIndex2 = int(staticSolverData.pEdgeVertexIndexList[index].y); 181 | 182 | //vec1 183 | float3 vec1 = make_float3(staticSolverData.pVertexPositionList[vertexIndex1].x, 184 | staticSolverData.pVertexPositionList[vertexIndex1].y, 185 | staticSolverData.pVertexPositionList[vertexIndex1].z 186 | ); 187 | 188 | //vec2 189 | float3 vec2 = make_float3(staticSolverData.pVertexPositionList[vertexIndex2].x, 190 | staticSolverData.pVertexPositionList[vertexIndex2].y, 191 | staticSolverData.pVertexPositionList[vertexIndex2].z 192 | ); 193 | 194 | //Compute new vector positions 195 | float3 delta = make_float3(0,0,0); 196 | delta = vec2 - vec1; 197 | float deltaLength = length(delta); 198 | float difference = (deltaLength - restLength) / deltaLength; 199 | vec1 = vec1 + delta * 0.5 * difference; 200 | vec2 = vec2 - delta * 0.5 * difference; 201 | 202 | //set vertexPositionList 203 | staticSolverData.pVertexPositionList[vertexIndex1].x = vec1.x; 204 | staticSolverData.pVertexPositionList[vertexIndex1].y = vec1.y; 205 | staticSolverData.pVertexPositionList[vertexIndex1].z = vec1.z; 206 | 207 | staticSolverData.pVertexPositionList[vertexIndex2].x = vec2.x; 208 | staticSolverData.pVertexPositionList[vertexIndex2].y = vec2.y; 209 | staticSolverData.pVertexPositionList[vertexIndex2].z = vec2.z; 210 | }; 211 | }; 212 | 213 | //positionConstraints 214 | __global__ void positionConstraints(staticSolverData_t staticSolverData, dynamicSolverData_t dynamicSolverData) 215 | { 216 | //check if posCons 217 | if(dynamicSolverData.positionConstraintCount) 218 | { 219 | //iterate posCons 220 | for(int index = 0; index < dynamicSolverData.positionConstraintCount; index++) 221 | { 222 | //check if posCon active 223 | if(dynamicSolverData.pPositionConstraintActiveList[index]) 224 | { 225 | //check if vertexIndex in vertexCount 226 | if(dynamicSolverData.pPositionConstraintVertexIndexList[index] < staticSolverData.vertexCount) 227 | { 228 | //set vertexPositionList 229 | staticSolverData.pVertexPositionList[dynamicSolverData.pPositionConstraintVertexIndexList[index]] = dynamicSolverData.pPositionConstraintCoordinateList[index]; 230 | } 231 | } 232 | } 233 | } 234 | }; 235 | } 236 | 237 | 238 | 239 | //definitions 240 | //----------------------------------------------- 241 | 242 | //cudaAvailable 243 | int cuda::cudaAvailable() 244 | { 245 | int deviceCount = 0; 246 | cudaError_t cudaErrorId; 247 | cudaErrorId = cudaGetDeviceCount(&deviceCount); 248 | return deviceCount; 249 | }; 250 | 251 | //get_grid_size 252 | int cuda::get_grid_size(const staticSolverData_t& staticSolverData, 253 | const dynamicSolverData_t& dynamicSolverData, 254 | grid_size_t grid_type = VERTEXCOUNT) 255 | { 256 | //declare grid_count 257 | int grid_count; 258 | 259 | //thread_count 260 | int thread_count = get_thread_count(dynamicSolverData); 261 | 262 | //VERTEXCOUNT 263 | if(grid_type == VERTEXCOUNT) 264 | { 265 | //grid_count 266 | grid_count = (staticSolverData.vertexCount + (thread_count - 1)) / thread_count; 267 | } 268 | //EDGECOUNT 269 | else if(grid_type == EDGECOUNT) 270 | { 271 | //grid_count 272 | grid_count = (staticSolverData.edgeCount + (thread_count - 1)) / thread_count; 273 | }; 274 | 275 | return grid_count; 276 | 277 | }; 278 | 279 | //get_thread_count 280 | int cuda::get_thread_count(const dynamicSolverData_t& dynamicSolverData) 281 | { 282 | return dynamicSolverData.thread_count; 283 | }; 284 | 285 | //add_on_gpu 286 | float cuda::add_on_gpu(float a, float b) 287 | { 288 | //size 289 | size_t size = sizeof(float); 290 | 291 | //d_p_result 292 | float* d_p_result; 293 | cudaMalloc(&d_p_result, size); 294 | 295 | //h_p_result 296 | float* h_p_result = new float[1]; 297 | 298 | //Call kernel 299 | dim3 num_blocks(1); 300 | dim3 threads_per_block(1); 301 | kernels::add_on_gpu<<>>(a, b, d_p_result); 302 | 303 | //copy 304 | cudaMemcpy(h_p_result, d_p_result, size, cudaMemcpyDeviceToHost); 305 | 306 | //free memory 307 | cudaFree(d_p_result); 308 | 309 | //return 310 | return *h_p_result; 311 | 312 | }; 313 | 314 | 315 | //set_static_solver_data_gpu 316 | void cuda::set_static_solver_data_gpu(staticSolverData_t &staticSolverDataGPU, const staticSolverData_t &staticSolverData) 317 | { 318 | 319 | //free mem if not null pointers 320 | //----------------------------------------------- 321 | //pVertexPositionList 322 | if(staticSolverDataGPU.pVertexPositionList) 323 | cudaFree(staticSolverDataGPU.pVertexPositionList); 324 | //pVertexOldpositionList 325 | if(staticSolverDataGPU.pVertexOldpositionList) 326 | cudaFree(staticSolverDataGPU.pVertexOldpositionList); 327 | //pVertexInitialpositionList 328 | if(staticSolverDataGPU.pVertexInitialpositionList) 329 | cudaFree(staticSolverDataGPU.pVertexInitialpositionList); 330 | //pEdgeVertexIndexList 331 | if(staticSolverDataGPU.pEdgeVertexIndexList) 332 | cudaFree(staticSolverDataGPU.pEdgeVertexIndexList); 333 | //pEdgeRestlengthList 334 | if(staticSolverDataGPU.pEdgeRestlengthList) 335 | cudaFree(staticSolverDataGPU.pEdgeRestlengthList); 336 | 337 | 338 | 339 | 340 | //reallocate mem for pointers and copy data 341 | //----------------------------------------------- 342 | 343 | //size_vertex_vcs_vector 344 | size_t size_vertex_vcs_vector = staticSolverData.vertexCount * sizeof(vcsVector); 345 | //size_edge_vcs_vector 346 | size_t size_edge_vcs_vector = staticSolverData.edgeCount * sizeof(vcsVector); 347 | //size_float 348 | size_t size_float = staticSolverData.edgeCount * sizeof(float); 349 | 350 | //allocate 351 | cudaMalloc(&staticSolverDataGPU.pVertexPositionList, size_vertex_vcs_vector); 352 | cudaMalloc(&staticSolverDataGPU.pVertexOldpositionList, size_vertex_vcs_vector); 353 | cudaMalloc(&staticSolverDataGPU.pVertexInitialpositionList, size_vertex_vcs_vector); 354 | cudaMalloc(&staticSolverDataGPU.pEdgeVertexIndexList, size_edge_vcs_vector); 355 | cudaMalloc(&staticSolverDataGPU.pEdgeRestlengthList, size_float); 356 | 357 | //copy 358 | //pVertexPositionList 359 | cudaMemcpy(staticSolverDataGPU.pVertexPositionList, 360 | staticSolverData.pVertexPositionList, 361 | size_vertex_vcs_vector, 362 | cudaMemcpyHostToDevice); 363 | //pVertexOldpositionList 364 | cudaMemcpy(staticSolverDataGPU.pVertexOldpositionList, 365 | staticSolverData.pVertexOldpositionList, 366 | size_vertex_vcs_vector, 367 | cudaMemcpyHostToDevice); 368 | //pVertexInitialpositionList 369 | cudaMemcpy(staticSolverDataGPU.pVertexInitialpositionList, 370 | staticSolverData.pVertexInitialpositionList, 371 | size_vertex_vcs_vector, 372 | cudaMemcpyHostToDevice); 373 | //pEdgeVertexIndexList 374 | cudaMemcpy(staticSolverDataGPU.pEdgeVertexIndexList, 375 | staticSolverData.pEdgeVertexIndexList, 376 | size_edge_vcs_vector, 377 | cudaMemcpyHostToDevice); 378 | //pEdgeRestlengthList 379 | cudaMemcpy(staticSolverDataGPU.pEdgeRestlengthList, 380 | staticSolverData.pEdgeRestlengthList, 381 | size_float, 382 | cudaMemcpyHostToDevice); 383 | 384 | 385 | //set non pointer values 386 | //----------------------------------------------- 387 | staticSolverDataGPU.edgeCount = staticSolverData.edgeCount; 388 | staticSolverDataGPU.vertexCount = staticSolverData.vertexCount; 389 | 390 | 391 | //tmp 392 | //std::cout <<"Allocated static data on the device" <>>(staticSolverData, dynamicSolverData); 575 | 576 | //log 577 | //std::cout<<"Cuda::verletIntegrationGPU"<>> (staticSolverData, dynamicSolverData); 592 | 593 | //log 594 | //std::cout<<"Cuda::collisionConstraintGroundplane"<>> (staticSolverData, dynamicSolverData); 609 | 610 | //log 611 | //std::cout<<"Cuda::collisionConstraintGroundplane"<>> (staticSolverData, dynamicSolverData); 628 | }; 629 | 630 | //positionConstraints 631 | void cuda::positionConstraints(staticSolverData_t &staticSolverData, dynamicSolverData_t &dynamicSolverData) 632 | { 633 | //kernel (serial since dependent on serial execution) 634 | kernels::positionConstraints<<<1,1>>> (staticSolverData, dynamicSolverData); 635 | }; -------------------------------------------------------------------------------- /temp/twClothSolverIOPaperBlockoutDepNode.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #twClothSolverIOPaperBlockout Module 5 | #------------------------------------------------------------------------------------- 6 | 7 | 8 | #Last Modified: 18.05.13 9 | #Author: Timm Wagener 10 | #Description: Simple cloth solver implementation 11 | 12 | 13 | 14 | #Imports 15 | #------------------------------------------------------------------------------------- 16 | import sys, math, time, random 17 | import maya.OpenMaya as OpenMaya 18 | import maya.OpenMayaMPx as OpenMayaMPx 19 | import maya.OpenMayaAnim as OpenMayaAnim 20 | 21 | 22 | 23 | #TwClothSolverIOPaperBlockout class 24 | #------------------------------------------------------------------------------------- 25 | 26 | class TwClothSolverIOPaperBlockout(OpenMayaMPx.MPxNode): 27 | '''TwClothSolverIOPaperBlockout class''' 28 | 29 | 30 | 31 | #Class Variables 32 | #------------------------------------------------------------------------------------- 33 | 34 | aInputGeo = OpenMaya.MObject() 35 | aOutputGeo = OpenMaya.MObject() 36 | 37 | aStartFrame = OpenMaya.MObject() 38 | aCurrentFrame = OpenMaya.MObject() 39 | 40 | aGravity = OpenMaya.MObject() 41 | 42 | aVertexPositionList = OpenMaya.MObject() 43 | aVertexOldpositionList = OpenMaya.MObject() 44 | aVertexInitialpositionList = OpenMaya.MObject() 45 | 46 | aEdgeVertexIndexList = OpenMaya.MObject() 47 | aEdgeRestlengthList = OpenMaya.MObject() 48 | 49 | aVertexForceList = OpenMaya.MObject() 50 | 51 | aTransformMatrix = OpenMaya.MObject() 52 | 53 | aVerbose = OpenMaya.MObject() 54 | 55 | aRepetitions = OpenMaya.MObject() 56 | 57 | aPositionConstraint = OpenMaya.MObject() 58 | aPositionConstraintActive = OpenMaya.MObject() 59 | aPositionConstraintVertexIndex = OpenMaya.MObject() 60 | aPositionConstraintCoordinate = OpenMaya.MObject() 61 | 62 | aCollisionConstraint = OpenMaya.MObject() 63 | aCollisionConstraintActive = OpenMaya.MObject() 64 | aCollisionConstraintType = OpenMaya.MObject() 65 | aCollisionConstraintGeoMatrix = OpenMaya.MObject() 66 | aCollisionConstraintGeo = OpenMaya.MObject() 67 | 68 | aCollisionConstraintGroundplaneActive = OpenMaya.MObject() 69 | aCollisionConstraintGroundplaneHeight = OpenMaya.MObject() 70 | 71 | 72 | 73 | #Methods 74 | #------------------------------------------------------------------------------------- 75 | 76 | def __init__(self): 77 | '''TwClothSolverIOPaperBlockout __init__''' 78 | 79 | #Execute superclass constructor 80 | OpenMayaMPx.MPxNode.__init__(self) 81 | 82 | #instance variables 83 | self.verbose = False 84 | 85 | 86 | def compute(self, plug, data): 87 | '''Compute new value if requested plug is outputGeo''' 88 | 89 | #Get all attrs to force update 90 | inputGeo = data.inputValue(self.aInputGeo).asMesh() 91 | 92 | startFrame = data.inputValue(self.aStartFrame).asInt() 93 | currentFrame = data.inputValue(self.aCurrentFrame).asFloat() 94 | 95 | gravity = OpenMaya.MFloatVector() 96 | gravity = data.inputValue(self.aGravity).asFloatVector() 97 | 98 | oVertexPositionList = OpenMaya.MObject() 99 | oVertexPositionList = data.inputValue(self.aVertexPositionList).data() 100 | 101 | oVertexOldpositionList = OpenMaya.MObject() 102 | oVertexOldpositionList = data.inputValue(self.aVertexOldpositionList).data() 103 | 104 | oVertexInitialpositionList = OpenMaya.MObject() 105 | oVertexInitialpositionList = data.inputValue(self.aVertexInitialpositionList).data() 106 | 107 | oEdgeVertexIndexList = OpenMaya.MObject() 108 | oEdgeVertexIndexList = data.inputValue(self.aEdgeVertexIndexList).data() 109 | 110 | 111 | #Check if requested dirty plug equals output plug 112 | if(plug != self.aOutputGeo): 113 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Unknown Plug requested. Compute not executed') 114 | return OpenMaya.MStatus.kUnknownParameter 115 | 116 | 117 | else: 118 | 119 | #1-set verbose 120 | self.setVerbose(data) 121 | if(self.verbose):OpenMaya.MGlobal.displayInfo('-------------ComputationLoop-------------\nVerbose status set') 122 | 123 | 124 | #2-Check if attributes are connected 125 | #inputGeo 126 | if not(self.attrConnected('inputGeo')): 127 | if(self.verbose):OpenMaya.MGlobal.displayInfo('inputGeo not connected') 128 | return OpenMaya.MStatus.kSuccess 129 | #transformMatrix 130 | if not(self.attrConnected('transformMatrix')): 131 | if(self.verbose):OpenMaya.MGlobal.displayInfo('transformMatrix not connected') 132 | return OpenMaya.MStatus.kSuccess 133 | 134 | 135 | #3-If currentFrame < startFrame then do nothing 136 | if(int(currentFrame) < startFrame): 137 | self.setVertexPositionListsForStartFrame(data) 138 | self.setEdgeVertexIndexListForStartFrame(data) 139 | self.setEdgeRestlengthListForStartFrame(data) 140 | self.draw(data) 141 | data.setClean(plug) 142 | if(self.verbose):OpenMaya.MGlobal.displayInfo('currentFrame < startFrame') 143 | return OpenMaya.MStatus.kSuccess 144 | 145 | 146 | #4-If currentFrame == startFrame then set vertexPositionLists and edgeVertexIndexList 147 | if(int(currentFrame) == startFrame): 148 | self.setVertexPositionListsForStartFrame(data) 149 | self.setEdgeVertexIndexListForStartFrame(data) 150 | self.setEdgeRestlengthListForStartFrame(data) 151 | self.draw(data) 152 | data.setClean(plug) 153 | if(self.verbose):OpenMaya.MGlobal.displayInfo('currentFrame == startFrame. Set vertexList attributes') 154 | return OpenMaya.MStatus.kSuccess 155 | 156 | 157 | #5-If currentFrame > startFrame then do timestep 158 | if(int(currentFrame) > startFrame): 159 | self.accumulateForces(data) 160 | self.verletIntegration(data) 161 | self.satisfyConstraints(data, self.getRepetitions(data)) 162 | self.draw(data) 163 | data.setClean(plug) 164 | if(self.verbose):OpenMaya.MGlobal.displayInfo('currentFrame > startFrame. Timestepping...') 165 | return OpenMaya.MStatus.kSuccess 166 | 167 | 168 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Compute executed') 169 | return OpenMaya.MStatus.kSuccess 170 | 171 | 172 | 173 | 174 | 175 | 176 | #Utility methods 177 | #------------------------------------------------------------------------------------- 178 | 179 | def setVerbose(self, data): 180 | '''Set instance variable verbose for output messages''' 181 | 182 | if(data.inputValue(self.aVerbose).asInt()): self.verbose = True 183 | else:self.verbose = False 184 | 185 | 186 | 187 | def attrConnected(self, attrName): 188 | '''Check if given attr of node is connected''' 189 | 190 | #Create FN for this node 191 | thisNode = self.thisMObject() 192 | fnDepNode = OpenMaya.MFnDependencyNode(thisNode) 193 | #Get MPLug for attribute name 194 | try: 195 | pAttr = fnDepNode.findPlug(attrName, True) 196 | except: 197 | if(self.verbose): OpenMaya.MGlobal.displayInfo('Error getting plug to attribute') 198 | return None 199 | 200 | return pAttr.isConnected() 201 | 202 | 203 | 204 | def setVertexPositionListsForStartFrame(self, data): 205 | '''Sets VertexPositionLists for startFrame''' 206 | 207 | 208 | #get transformMatrix 209 | transformMatrix = data.inputValue(self.aTransformMatrix).asMatrix() 210 | 211 | #get inputGeo as MObject 212 | inputGeo = data.inputValue(self.aInputGeo).asMesh() 213 | #fsMesh for inputGeo 214 | fsInputGeo = OpenMaya.MFnMesh(inputGeo) 215 | #get vertexList 216 | vertexList = OpenMaya.MPointArray() 217 | fsInputGeo.getPoints(vertexList) 218 | 219 | 220 | #set points in vertexList to worldSpace 221 | for index in range(vertexList.length()): 222 | vertexList.set(vertexList[index]*transformMatrix, index) 223 | 224 | #set attributes in datablock 225 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexList) 226 | self.setMpointArrayToDatablock(data, self.aVertexOldpositionList, vertexList) 227 | self.setMpointArrayToDatablock(data, self.aVertexInitialpositionList, vertexList) 228 | 229 | 230 | 231 | 232 | 233 | def setEdgeVertexIndexListForStartFrame(self, data): 234 | '''Set Edge-VertexIndex List for startFrame''' 235 | 236 | #get inputGeo as MObject 237 | inputGeo = data.inputValue(self.aInputGeo).asMesh() 238 | #fsMesh for inputGeo 239 | fsInputGeo = OpenMaya.MFnMesh(inputGeo) 240 | 241 | #create MItEdge 242 | itMeshEdges = OpenMaya.MItMeshEdge(inputGeo) 243 | util = OpenMaya.MScriptUtil() 244 | dummyPoint = OpenMaya.MPoint() 245 | edgeVertexIndexList = OpenMaya.MPointArray(itMeshEdges.count(), dummyPoint) 246 | 247 | while not(itMeshEdges.isDone()): 248 | 249 | #get vertex indices for edgeIndex 250 | util.createFromDouble(0.0) 251 | ptr = util.asInt2Ptr() 252 | fsInputGeo.getEdgeVertices(itMeshEdges.index(), ptr) 253 | 254 | vertexIndex1 = util.getInt2ArrayItem(ptr, 0,0) 255 | vertexIndex2 = util.getInt2ArrayItem(ptr, 0,1) 256 | 257 | #set MPoint with first two values as vertexindices and index as edgeIndex in edgeVertexIndexList 258 | pointVertexIndices = OpenMaya.MPoint(vertexIndex1, vertexIndex2, 0) 259 | edgeVertexIndexList.set(pointVertexIndices, itMeshEdges.index()) 260 | 261 | itMeshEdges.next() 262 | 263 | 264 | #set aEdgeVertexIndexList 265 | self.setMpointArrayToDatablock(data, self.aEdgeVertexIndexList, edgeVertexIndexList) 266 | 267 | 268 | 269 | def setEdgeRestlengthListForStartFrame(self, data): 270 | '''Set aEdgeRestlengthList at startFrame''' 271 | 272 | #getEdgeVertexIndexList 273 | edgeVertexIndexList = self.getMpointArrayFromDatablock(data, self.aEdgeVertexIndexList) 274 | #get vertexPositionList 275 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 276 | 277 | #edgeRestlengthList 278 | edgeRestlengthList = OpenMaya.MPointArray(edgeVertexIndexList) 279 | 280 | #fill edgeRestlengthList 281 | for index in range(edgeVertexIndexList.length()): 282 | #get vertexIndices 283 | vertexIndex1 = int(edgeVertexIndexList[index].x) 284 | vertexIndex2 = int(edgeVertexIndexList[index].y) 285 | #get vector from mpoints of indices 286 | vec1 = OpenMaya.MVector(vertexPositionList[vertexIndex1]) 287 | vec2 = OpenMaya.MVector(vertexPositionList[vertexIndex2]) 288 | #restlength 289 | restlength = (vec2 - vec1).length() 290 | 291 | #set rl in edgeRestlengthList 292 | edgeRestlengthList.set(OpenMaya.MPoint(restlength, 0, 0),index) 293 | 294 | #set aEdgeRestlengthList 295 | self.setMpointArrayToDatablock(data, self.aEdgeRestlengthList, edgeRestlengthList) 296 | 297 | 298 | 299 | def accumulateForces(self, data): 300 | '''Set vertexForceList''' 301 | 302 | #get gravity from datablock 303 | gravity = OpenMaya.MFloatVector() 304 | gravity = data.inputValue(self.aGravity).asFloatVector() 305 | 306 | #get vertexPositionList from datablock 307 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 308 | 309 | #vertexPositionList to vertexForceList 310 | vertexForceList = OpenMaya.MPointArray(vertexPositionList) 311 | 312 | #set force for each point in vertexForceList 313 | for index in range(vertexForceList.length()): 314 | vertexForceList.set(OpenMaya.MPoint(gravity.x, gravity.y, gravity.z), index) 315 | 316 | #set aVertexForceList 317 | self.setMpointArrayToDatablock(data, self.aVertexForceList, vertexForceList) 318 | 319 | 320 | 321 | def verletIntegration(self, data): 322 | '''Move points according to implicit velocity and force''' 323 | 324 | #get oldPos, Pos and forceList from datablock 325 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 326 | vertexOldpositionList = self.getMpointArrayFromDatablock(data, self.aVertexOldpositionList) 327 | vertexForceList = self.getMpointArrayFromDatablock(data, self.aVertexForceList) 328 | 329 | 330 | #verletIntegration for each point 331 | for index in range(vertexPositionList.length()): 332 | #get variables for formula 333 | vecNew = OpenMaya.MVector() 334 | vecPos = OpenMaya.MVector(vertexPositionList[index]) 335 | vecOldpos = OpenMaya.MVector(vertexOldpositionList[index]) 336 | vecForce = OpenMaya.MVector(vertexForceList[index]) 337 | #verlet integration 338 | vecNew = ((vecPos * 2) - vecOldpos) + vecForce 339 | 340 | #set new values in lists 341 | vertexOldpositionList.set(OpenMaya.MPoint(vecPos), index) 342 | vertexPositionList.set(OpenMaya.MPoint(vecNew), index) 343 | 344 | 345 | 346 | #set vertexPositionLists in datablock 347 | self.setMpointArrayToDatablock(data, self.aVertexOldpositionList, vertexOldpositionList) 348 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 349 | 350 | 351 | 352 | def satisfyConstraints(self, data, repetitions): 353 | '''Run all given constraints in a loop''' 354 | 355 | for index in range(repetitions): 356 | if(self.getCollisionConstraintGroundplaneActive(data)): self.collisionConstraintGroundplane(data) 357 | self.collisionConstraint(data) 358 | self.stickConstraint(data) 359 | self.positionConstraint(data) 360 | 361 | 362 | 363 | 364 | def collisionConstraintGroundplane(self, data): 365 | '''Simple collision with a groundplane''' 366 | 367 | #get vertexPositionList 368 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 369 | 370 | #get groundplaneHeight 371 | groundplaneHeight = data.inputValue(self.aCollisionConstraintGroundplaneHeight).asFloat() 372 | 373 | #iterate vertexPositionList and set y when value < groundplaneHeight 374 | for index in range(vertexPositionList.length()): 375 | if(vertexPositionList[index].y < groundplaneHeight): vertexPositionList.set(OpenMaya.MPoint(vertexPositionList[index].x, groundplaneHeight, vertexPositionList[index].z) ,index) 376 | 377 | #set vertexPositionList to datablock 378 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 379 | 380 | 381 | 382 | def collisionConstraint(self, data): 383 | '''Collsion constraint detects if points intersect objects and if so project them outward''' 384 | 385 | #thisNode MObject 386 | thisNode = self.thisMObject() 387 | 388 | #handle to collisionConstraint array attr 389 | haCollisionConstraintArray = data.inputArrayValue(self.aCollisionConstraint) 390 | 391 | #iterate all array elements 392 | for index in range(haCollisionConstraintArray.elementCount()): 393 | haCollisionConstraintArray.jumpToArrayElement(index) 394 | #get datahandle to active attr for current array element 395 | hCollisionConstraintArrayElement = haCollisionConstraintArray.inputValue() 396 | hCollisionConstraintActive = hCollisionConstraintArrayElement.child(self.aCollisionConstraintActive) 397 | 398 | #if current collisionConstraint is active check collisionType 399 | if(hCollisionConstraintActive.asInt()): 400 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint at index %s active' % (index)) 401 | 402 | #get plug to current collisionConstraint compund array attr 403 | pCollisionConstraintCompoundArrayAttr = OpenMaya.MPlug(thisNode, self.aCollisionConstraint) 404 | pCollisionConstraintCompoundAttr = pCollisionConstraintCompoundArrayAttr.elementByPhysicalIndex(index) 405 | 406 | #check if current collision geo matrix connected 407 | pCollisionConstraintGeoMatrixAttr = pCollisionConstraintCompoundAttr.child(2) 408 | if(pCollisionConstraintGeoMatrixAttr.isConnected()): 409 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint Geo Matrix at index %s connected' % (index)) 410 | 411 | #check if current collision geo connected 412 | pCollisionConstraintGeoAttr = pCollisionConstraintCompoundAttr.child(3) 413 | if(pCollisionConstraintGeoAttr.isConnected()): 414 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint Geo at index %s connected' % (index)) 415 | 416 | #get collision geo 417 | collisionGeo = hCollisionConstraintArrayElement.child(self.aCollisionConstraintGeo).asMesh() 418 | #get collision geo matrix 419 | collisionGeoMatrix = hCollisionConstraintArrayElement.child(self.aCollisionConstraintGeoMatrix).asMatrix() 420 | 421 | #check collisionType 422 | collisionConstraintType = hCollisionConstraintArrayElement.child(self.aCollisionConstraintType).asInt() 423 | #sphere 424 | if(collisionConstraintType == 0): self.collisionSphere(data, collisionGeo, collisionGeoMatrix) 425 | #rectangle 426 | if(collisionConstraintType == 1): self.collisionRectangle(data, collisionGeo, collisionGeoMatrix) 427 | 428 | else: 429 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint Geo at index %s not connected' % (index)) 430 | else: 431 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint Geo Matrix at index %s not connected' % (index)) 432 | else: 433 | if(self.verbose):OpenMaya.MGlobal.displayInfo('CollisionConstraint at index %s not active' % (index)) 434 | 435 | 436 | 437 | def collisionSphere(self, data, collisionGeo, collisionGeoMatrix): 438 | '''Update vertexPositionList with sphere collision''' 439 | 440 | #get vertexPositionList 441 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 442 | 443 | #get vecSphereUp,Down 444 | collisionGeoPointArray = OpenMaya.MPointArray() 445 | fsCollisionGeo = OpenMaya.MFnMesh(collisionGeo) 446 | fsCollisionGeo.getPoints(collisionGeoPointArray) 447 | vecSphereUp = OpenMaya.MVector(collisionGeoPointArray[collisionGeoPointArray.length()-1] * collisionGeoMatrix) 448 | vecSphereDown = OpenMaya.MVector(collisionGeoPointArray[collisionGeoPointArray.length()-2] * collisionGeoMatrix) 449 | 450 | #get vecSphereCenter and radiusSphere 451 | vecDownToUp = vecSphereUp - vecSphereDown 452 | vecSphereCenter = vecSphereDown + (vecDownToUp * 0.5) 453 | radiusSphere = (vecDownToUp * 0.5).length() 454 | 455 | #iterate each vertex in vertexPositionList and perfom collision projection 456 | for index in range(vertexPositionList.length()): 457 | 458 | #get vecCurrentPoint 459 | vecCurrentPoint = OpenMaya.MVector(vertexPositionList[index]) 460 | #get vecSphereCenterToCurrentPoint 461 | vecSphereCenterToCurrentPoint = vecCurrentPoint - vecSphereCenter 462 | vecSphereCenterToCurrentPointLength = vecSphereCenterToCurrentPoint.length() 463 | #check if distance < radius 464 | if(vecSphereCenterToCurrentPointLength < radiusSphere): 465 | 466 | #project vecCurrentPoint outward 467 | vecCurrentPoint = vecSphereCenter + (vecSphereCenterToCurrentPoint.normal() * radiusSphere) 468 | #set vertexPositionList 469 | vertexPositionList.set(OpenMaya.MPoint(vecCurrentPoint) ,index) 470 | 471 | 472 | #set vertexPositionList to datablock 473 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 474 | 475 | #TMP 476 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Sphere collision performed') 477 | 478 | 479 | 480 | def collisionRectangle(self, data, collisionGeo, collisionGeoMatrix): 481 | '''Update vertexPositionList with rectangle collision''' 482 | 483 | #get vertexPositionList 484 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 485 | 486 | #iterate each vertex in vertexPositionList and perfom collision projection 487 | for index in range(vertexPositionList.length()): 488 | x = vertexPositionList[index].x 489 | y = vertexPositionList[index].y 490 | z = vertexPositionList[index].z 491 | vertexPositionList.set(OpenMaya.MPoint(x, 0, z),index) 492 | 493 | #set vertexPositionList to datablock 494 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 495 | 496 | #TMP 497 | if(self.verbose):OpenMaya.MGlobal.displayInfo('Rectangle collision performed') 498 | 499 | 500 | 501 | 502 | def stickConstraint(self, data): 503 | '''Constraint to maintain length of all edges of inputGeo''' 504 | 505 | #get vertexPositionList 506 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 507 | #get edgeVertexIndexList 508 | edgeVertexIndexList = self.getMpointArrayFromDatablock(data, self.aEdgeVertexIndexList) 509 | #get edgeRestlengthList 510 | edgeRestlengthList = self.getMpointArrayFromDatablock(data, self.aEdgeRestlengthList) 511 | 512 | 513 | #iterate edges 514 | for index in range(edgeVertexIndexList.length()): 515 | #restlength 516 | restlength = edgeRestlengthList[index].x 517 | #vertexIndices 518 | vertexIndex1 = int(edgeVertexIndexList[index].x) 519 | vertexIndex2 = int(edgeVertexIndexList[index].y) 520 | #current vertex vectors 521 | vec1 = OpenMaya.MVector(vertexPositionList[vertexIndex1]) 522 | vec2 = OpenMaya.MVector(vertexPositionList[vertexIndex2]) 523 | #compute new position vectors 524 | delta = vec2 - vec1 525 | deltalength = delta.length() 526 | difference = (deltalength - restlength) / deltalength 527 | vec1 += delta*0.5*difference 528 | vec2 -= delta*0.5*difference 529 | 530 | #set positions in vertexPositionList 531 | vertexPositionList.set(OpenMaya.MPoint(vec1),vertexIndex1) 532 | vertexPositionList.set(OpenMaya.MPoint(vec2),vertexIndex2) 533 | 534 | 535 | #set vertexPositionList to datablock 536 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 537 | 538 | 539 | 540 | def positionConstraint(self, data): 541 | '''Constraint to maintain position of vertices''' 542 | 543 | #get vertexPositionList 544 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 545 | 546 | #handle to positionConstraint array attr 547 | haPositionConstraintArray = data.inputArrayValue(self.aPositionConstraint) 548 | 549 | #iterate all array elements 550 | for index in range(haPositionConstraintArray.elementCount()): 551 | haPositionConstraintArray.jumpToArrayElement(index) 552 | #get datahandle to active attr for current array element 553 | hPositionConstraintArrayElement = haPositionConstraintArray.inputValue() 554 | hPositionConstraintActive = hPositionConstraintArrayElement.child(self.aPositionConstraintActive) 555 | #if current positionConstraint is active set its position values at index in vertexPositionList 556 | if(hPositionConstraintActive.asInt()): 557 | if(self.verbose):OpenMaya.MGlobal.displayInfo('PositionConstraint at index %s active' % (index)) 558 | #get vertexIndex 559 | vertexIndex = hPositionConstraintArrayElement.child(self.aPositionConstraintVertexIndex).asInt() 560 | #check if vertexIndex in vertexPositionList 561 | if(vertexIndex >= 0 and vertexIndex < vertexPositionList.length()): 562 | #get positionConstraintCoordinate 563 | vecPositionConstraintCoordinate = hPositionConstraintArrayElement.child(self.aPositionConstraintCoordinate).asFloatVector() 564 | #set in vertexPositionList 565 | vertexPositionList.set(OpenMaya.MPoint(vecPositionConstraintCoordinate), vertexIndex) 566 | else: 567 | if(self.verbose):OpenMaya.MGlobal.displayInfo('VertexIndex: %s not in vertexPositionList' % (vertexIndex)) 568 | 569 | 570 | #set vertexPositionList to datablock 571 | self.setMpointArrayToDatablock(data, self.aVertexPositionList, vertexPositionList) 572 | 573 | 574 | 575 | 576 | 577 | def draw(self, data): 578 | '''Set the outputGeo attr''' 579 | 580 | #get Pos from datablock 581 | vertexPositionList = self.getMpointArrayFromDatablock(data, self.aVertexPositionList) 582 | 583 | 584 | #get transformMatrix from datablock 585 | transformMatrix = data.inputValue(self.aTransformMatrix).asMatrix() 586 | 587 | 588 | #move all points in vertexPositionList to ws 589 | for index in range(vertexPositionList.length()): 590 | vertexPositionList.set(vertexPositionList[index], index) 591 | 592 | 593 | #get oInputGeo 594 | oInputGeo = data.inputValue(self.aInputGeo).asMesh() 595 | #fsInputGeo 596 | fsInputGeo = OpenMaya.MFnMesh(oInputGeo) 597 | 598 | 599 | #Create MeshDataBlock 600 | mfnOutMeshData = OpenMaya.MFnMeshData() 601 | outMeshDataBlock = mfnOutMeshData.create() 602 | 603 | #Create mesh obj as child of outMeshDataBlock 604 | polyCountArray = OpenMaya.MIntArray() 605 | polyConnectArray = OpenMaya.MIntArray() 606 | fsInputGeo.getVertices(polyCountArray, polyConnectArray) 607 | 608 | #Create new geo with transformed point array 609 | mfnNewMesh = OpenMaya.MFnMesh() 610 | projectedGeo = mfnNewMesh.create(vertexPositionList.length(), polyCountArray.length(), vertexPositionList, polyCountArray, polyConnectArray, outMeshDataBlock) 611 | #Set OutPut Mesh data 612 | hOutMesh = data.outputValue(self.aOutputGeo) 613 | hOutMesh.setMObject(outMeshDataBlock) 614 | 615 | 616 | 617 | def getMpointArrayFromDatablock(self, data, aMpointArray): 618 | '''Convenience method to return MPointArray from datablock attribute''' 619 | 620 | pointArray = OpenMaya.MPointArray() 621 | oMPointArray = OpenMaya.MObject() 622 | oMPointArray = data.inputValue(aMpointArray).data() 623 | fsMPointArrayData = OpenMaya.MFnPointArrayData(oMPointArray) 624 | 625 | return fsMPointArrayData.array() 626 | 627 | 628 | 629 | def setMpointArrayToDatablock(self, data, aMpointArray, pointArray): 630 | '''Convenience method to set MPointArray to datablock attribute''' 631 | 632 | #pointArray to MObject 633 | fsPointArrayData = OpenMaya.MFnPointArrayData() 634 | oPointArray = fsPointArrayData.create(pointArray) 635 | 636 | #set aMpointArray 637 | hAMpointArray = data.outputValue(aMpointArray) 638 | hAMpointArray.setMObject(oPointArray) 639 | 640 | 641 | 642 | def getRepetitions(self, data): 643 | '''Return repetitions value from aRepetitions''' 644 | 645 | return data.inputValue(self.aRepetitions).asInt() 646 | 647 | 648 | 649 | def getCollisionConstraintGroundplaneActive(self, data): 650 | '''Return repetitions value from aRepetitions''' 651 | 652 | return data.inputValue(self.aCollisionConstraintGroundplaneActive).asInt() 653 | 654 | 655 | 656 | #Initialization 657 | #------------------------------------------------------------------------------------- 658 | 659 | 660 | def createTwClothSolverIOPaperBlockout(): 661 | '''Create and deliver a pointer to an instance of TwClothSolverIOPaperBlockout''' 662 | return OpenMayaMPx.asMPxPtr(TwClothSolverIOPaperBlockout()) 663 | 664 | 665 | def initializeTwClothSolverIOPaperBlockout(): 666 | '''Initializes the TwClothSolverIOPaperBlockout class factory with attributes. Is called only once when the plugin is registered.''' 667 | 668 | 669 | #Functionsets 670 | nAttr = OpenMaya.MFnNumericAttribute() 671 | tAttr = OpenMaya.MFnTypedAttribute() 672 | mAttr = OpenMaya.MFnMatrixAttribute() 673 | eAttr = OpenMaya.MFnEnumAttribute() 674 | cAttr = OpenMaya.MFnCompoundAttribute() 675 | 676 | 677 | 678 | 679 | #aInputGeo 680 | TwClothSolverIOPaperBlockout.aInputGeo = tAttr.create('inputGeo', 'inputGeo', OpenMaya.MFnData.kMesh) 681 | tAttr.setWritable(True) 682 | tAttr.setReadable(False) 683 | tAttr.setHidden(True) 684 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aInputGeo) 685 | 686 | 687 | #aOutputGeo 688 | TwClothSolverIOPaperBlockout.aOutputGeo = tAttr.create('outputGeo', 'outputGeo', OpenMaya.MFnData.kMesh) 689 | tAttr.setWritable(False) 690 | tAttr.setReadable(True) 691 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aOutputGeo) 692 | 693 | 694 | #aStartFrame 695 | TwClothSolverIOPaperBlockout.aStartFrame = nAttr.create('startFrame','startFrame', OpenMaya.MFnNumericData.kInt, 1) 696 | nAttr.setKeyable(True) 697 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aStartFrame) 698 | 699 | 700 | #aCurrentFrame 701 | TwClothSolverIOPaperBlockout.aCurrentFrame = nAttr.create('currentFrame','currentFrame', OpenMaya.MFnNumericData.kFloat, 1) 702 | nAttr.setKeyable(True) 703 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aCurrentFrame) 704 | 705 | 706 | #aGravity 707 | TwClothSolverIOPaperBlockout.aGravity = nAttr.createPoint('gravity','gravity') 708 | nAttr.setKeyable(True) 709 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aGravity) 710 | 711 | 712 | #aVertexPositionList 713 | TwClothSolverIOPaperBlockout.aVertexPositionList = tAttr.create('vertexPositionList','vertexPositionList', OpenMaya.MFnData.kPointArray) 714 | tAttr.setHidden(True) 715 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aVertexPositionList) 716 | 717 | 718 | #aVertexOldpositionList 719 | TwClothSolverIOPaperBlockout.aVertexOldpositionList = tAttr.create('vertexOldpositionList','vertexOldpositionList', OpenMaya.MFnData.kPointArray) 720 | tAttr.setHidden(True) 721 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aVertexOldpositionList) 722 | 723 | 724 | #aVertexInitialpositionList 725 | TwClothSolverIOPaperBlockout.aVertexInitialpositionList = tAttr.create('vertexInitialpositionList','vertexInitialpositionList', OpenMaya.MFnData.kPointArray) 726 | tAttr.setHidden(True) 727 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aVertexInitialpositionList) 728 | 729 | 730 | #aEdgeVertexIndexList 731 | TwClothSolverIOPaperBlockout.aEdgeVertexIndexList = tAttr.create('edgeVertexIndexList','edgeVertexIndexList', OpenMaya.MFnData.kPointArray) 732 | tAttr.setHidden(True) 733 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aEdgeVertexIndexList) 734 | 735 | 736 | #aEdgeRestlengthList 737 | TwClothSolverIOPaperBlockout.aEdgeRestlengthList = tAttr.create('edgeRestlengthList','edgeRestlengthList', OpenMaya.MFnData.kPointArray) 738 | tAttr.setHidden(True) 739 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aEdgeRestlengthList) 740 | 741 | 742 | #aVertexForceList 743 | TwClothSolverIOPaperBlockout.aVertexForceList = tAttr.create('vertexForceList','vertexForceList', OpenMaya.MFnData.kPointArray) 744 | tAttr.setHidden(True) 745 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aVertexForceList) 746 | 747 | 748 | #aTransformMatrix 749 | TwClothSolverIOPaperBlockout.aTransformMatrix = mAttr.create('transformMatrix', 'transformMatrix') 750 | mAttr.setReadable(False) 751 | mAttr.setHidden(True) 752 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aTransformMatrix) 753 | 754 | 755 | #aVerbose 756 | TwClothSolverIOPaperBlockout.aVerbose = eAttr.create('verbose', 'verbose') 757 | eAttr.addField('noVerbose', 0) 758 | eAttr.addField('Verbose', 1) 759 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aVerbose) 760 | 761 | 762 | #aRepetitions 763 | TwClothSolverIOPaperBlockout.aRepetitions = nAttr.create('repetitions','repetitions', OpenMaya.MFnNumericData.kInt, 1) 764 | nAttr.setKeyable(True) 765 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aRepetitions) 766 | 767 | 768 | #aPositionConstraintActive 769 | TwClothSolverIOPaperBlockout.aPositionConstraintActive = eAttr.create('positionConstraintActive', 'positionConstraintActive') 770 | eAttr.addField('Inactive', 0) 771 | eAttr.addField('Active', 1) 772 | #aPositionConstraintIndex 773 | TwClothSolverIOPaperBlockout.aPositionConstraintVertexIndex = nAttr.create('positionConstraintVertexIndex','positionConstraintVertexIndex', OpenMaya.MFnNumericData.kInt, 0) 774 | nAttr.setKeyable(True) 775 | #aPositionConstraintCoordinate 776 | TwClothSolverIOPaperBlockout.aPositionConstraintCoordinate = nAttr.createPoint('positionConstraintCoordinate','positionConstraintCoordinate') 777 | nAttr.setKeyable(True) 778 | 779 | #aPositionConstraint 780 | TwClothSolverIOPaperBlockout.aPositionConstraint = cAttr.create('positionConstraint','positionConstraint') 781 | cAttr.setArray(True) 782 | cAttr.addChild(TwClothSolverIOPaperBlockout.aPositionConstraintActive) 783 | cAttr.addChild(TwClothSolverIOPaperBlockout.aPositionConstraintVertexIndex) 784 | cAttr.addChild(TwClothSolverIOPaperBlockout.aPositionConstraintCoordinate) 785 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aPositionConstraint) 786 | 787 | 788 | #aCollisionConstraintActive 789 | TwClothSolverIOPaperBlockout.aCollisionConstraintActive = eAttr.create('collisionConstraintActive', 'collisionConstraintActive') 790 | eAttr.addField('Inactive', 0) 791 | eAttr.addField('Active', 1) 792 | #aCollisionConstraintType 793 | TwClothSolverIOPaperBlockout.aCollisionConstraintType = eAttr.create('collisionConstraintType', 'collisionConstraintType') 794 | eAttr.addField('Sphere', 0) 795 | eAttr.addField('Rectangle', 1) 796 | #aCollisionConstraintGeoMatrix 797 | TwClothSolverIOPaperBlockout.aCollisionConstraintGeoMatrix = mAttr.create('collisionConstraintGeoMatrix', 'collisionConstraintGeoMatrix') 798 | mAttr.setReadable(False) 799 | #aCollisionConstraintGeo 800 | TwClothSolverIOPaperBlockout.aCollisionConstraintGeo = tAttr.create('collisionConstraintGeo', 'collisionConstraintGeo', OpenMaya.MFnData.kMesh) 801 | tAttr.setWritable(True) 802 | tAttr.setReadable(False) 803 | 804 | #aCollisionConstraint 805 | TwClothSolverIOPaperBlockout.aCollisionConstraint = cAttr.create('collisionConstraint','collisionConstraint') 806 | cAttr.setArray(True) 807 | cAttr.addChild(TwClothSolverIOPaperBlockout.aCollisionConstraintActive) 808 | cAttr.addChild(TwClothSolverIOPaperBlockout.aCollisionConstraintType) 809 | cAttr.addChild(TwClothSolverIOPaperBlockout.aCollisionConstraintGeoMatrix) 810 | cAttr.addChild(TwClothSolverIOPaperBlockout.aCollisionConstraintGeo) 811 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aCollisionConstraint) 812 | 813 | 814 | #aCollisionConstraintGroundplaneActive 815 | TwClothSolverIOPaperBlockout.aCollisionConstraintGroundplaneActive = nAttr.create('collisionConstraintGroundplaneActive', 'collisionConstraintGroundplaneActive', OpenMaya.MFnNumericData.kBoolean, 0) 816 | nAttr.setStorable(False) 817 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aCollisionConstraintGroundplaneActive) 818 | 819 | #aCollisionConstraintGroundplaneHeight 820 | TwClothSolverIOPaperBlockout.aCollisionConstraintGroundplaneHeight = nAttr.create('collisionConstraintGroundplaneHeight','collisionConstraintGroundplaneHeight', OpenMaya.MFnNumericData.kFloat, 0) 821 | nAttr.setKeyable(True) 822 | TwClothSolverIOPaperBlockout.addAttribute(TwClothSolverIOPaperBlockout.aCollisionConstraintGroundplaneHeight) 823 | 824 | 825 | #attributeAffects 826 | TwClothSolverIOPaperBlockout.attributeAffects(TwClothSolverIOPaperBlockout.aCurrentFrame, TwClothSolverIOPaperBlockout.aOutputGeo) 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | #Plugin Registration 836 | #------------------------------------------------------------------------------------- 837 | 838 | kPluginNodeName = "TwClothSolverIOPaperBlockout" 839 | kPluginNodeId = OpenMaya.MTypeId(0x5700B) 840 | 841 | 842 | def initializePlugin(mobject): 843 | '''Register Plugin''' 844 | 845 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 846 | try: 847 | mplugin.registerNode( kPluginNodeName, kPluginNodeId, createTwClothSolverIOPaperBlockout, initializeTwClothSolverIOPaperBlockout, OpenMayaMPx.MPxNode.kDependNode) 848 | except: 849 | sys.stderr.write( "Failed to register node: %s" % kPluginNodeName ) 850 | raise 851 | 852 | 853 | def uninitializePlugin(mobject): 854 | '''Deregister Plugin''' 855 | 856 | mplugin = OpenMayaMPx.MFnPlugin(mobject) 857 | try: 858 | mplugin.deregisterNode( kPluginNodeId ) 859 | except: 860 | sys.stderr.write( "Failed to deregister node: %s" % kPluginNodeName ) 861 | raise --------------------------------------------------------------------------------