int main(int argc, const char *argv[]) try { std::vector<RigidBody> rbs; for (auto const &b : bodysizes) { auto verts = genboxverts(b); auto tris = calchull(verts, 8); rbs.push_back(RigidBody({ Shape(verts, tris) }, float3(0, 0, 0))); } rbscalemass(&rbs[0], 5.0f); // make torso heavier than limb bones rbs[0].position.z = 1.0f; // lift a meter off the ground. DXWin mywin("Joint Drive - powered rag doll model", { 800,600 }); std::vector<Mesh> meshes; for (auto &rb : rbs) { meshes.push_back(MeshSmoothish(rb.shapes[0].verts, rb.shapes[0].tris)); // 1 shape each is known rb.damping = 0.8f; //rb.gravscale = 0; } for (auto &joint : joints) { rbs[joint.b0].ignore.push_back(&rbs[joint.b1]); rbs[joint.b1].ignore.push_back(&rbs[joint.b0]); rbs[joint.b1].position = rbs[joint.b0].pose() * joint.p0 - qrot(rbs[joint.b1].orientation,joint.p1); } WingMesh ground_wm = WingMeshBox({ -5, -5, -2.0f }, { 5, 5, -1.0f }); auto ground = MeshFlatShadeTex(ground_wm.verts, WingMeshTris(ground_wm)); ground.hack = { 0.25f, 0.75f, 0.25f, 1 }; Pose camera = { { 0, -8, 0 }, normalize(float4(0.9f, 0, 0, 1)) }; // where we view the rendered scene from. float time = 0; // our global clock, used to generate the circular animation for upper limbs to follow float torquelimit = 38.0f; // how much torque we let each joint apply each frame while (mywin.WindowUp()) { time += 0.06f; std::vector<LimitAngular> angulars; std::vector<LimitLinear> linears; for (auto const &joint : joints) { Append(linears, ConstrainPositionNailed(&rbs[joint.b0], joint.p0, &rbs[joint.b1], joint.p1)); Append(angulars, ConstrainAngularDrive(&rbs[joint.b0], &rbs[joint.b1], (float4(0, joint.a*cos(time), joint.a*sin(time), sqrt(1.0f - joint.a*joint.a))), torquelimit)); } PhysicsUpdate(Addresses<RigidBody>(rbs), linears, angulars, { &ground_wm.verts }); for (unsigned int i = 0; i < rbs.size(); i++) meshes[i].pose = rbs[i].pose(); mywin.RenderScene(camera, Append(Addresses(meshes), std::vector<Mesh*>({ &ground }))); } return 0; } catch (std::exception e) { MessageBoxA(GetActiveWindow(), e.what(), "FAIL", 0); return -1; }
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,LPSTR lpszCmdLine, int nCmdShow) // int main(int argc, char *argv[]) { std::cout << "Test Physics\n"; std::vector<RigidBody*> rigidbodies; rigidbodies.push_back(new RigidBody({ AsShape(WingMeshCube(1)) }, { 1.5f, 0.0f, 1.5f })); rigidbodies.push_back(new RigidBody({ AsShape(WingMeshCube(1)) }, { -1.5f, 0.0f, 1.5f })); rigidbodies.back()->orientation = normalize(float4(0.1f, 0.01f, 0.3f, 1.0f)); auto seesaw = new RigidBody({ AsShape(WingMeshBox( { 3, 0.5f, 0.1f })) }, { 0, -2.5, 0.25f }); rigidbodies.push_back(seesaw); rigidbodies.push_back( new RigidBody({ AsShape(WingMeshCube(0.25f)) }, seesaw->position_start + float3( 2.5f, 0, 0.4f))); rigidbodies.push_back( new RigidBody({ AsShape(WingMeshCube(0.50f)) }, seesaw->position_start + float3(-2.5f, 0, 5.0f))); rbscalemass(rigidbodies.back(), 4.0f); rigidbodies.push_back(new RigidBody({ AsShape(WingMeshBox({1,0.2f,0.2f})),AsShape(WingMeshBox({0.2f,1,0.2f})),AsShape(WingMeshBox({0.2f,0.2f,1})) }, { -1.5f, 0.5f, 7.5f })); for (float z = 5.5f; z < 14.0f; z += 3.0f) rigidbodies.push_back(new RigidBody({ AsShape(WingMeshCube(0.5f)) }, { 0.0f, 0.0f, z })); for (float z = 15.0f; z < 20.0f; z += 3.0f) rigidbodies.push_back(new RigidBody({ AsShape(WingMeshDual(WingMeshCube(0.5f), 0.65f)) }, { 2.0f, -1.0f, z })); WingMesh world_slab = WingMeshBox({ -10, -10, -5 }, { 10, 10, -2 }); // world_geometry GLWin glwin("TestPhys sample"); glwin.ViewAngle = 60.0f; glwin.keyboardfunc = [&](unsigned char key, int x, int y)->void { switch (std::tolower(key)) { case ' ': g_simulate = !g_simulate; break; case 'q': case 27: // ESC exit(0); break; case 'r': for (auto &rb : rigidbodies) { rb->position = rb->position_start; //rb->orientation = rb->orientation_start; // when commented out this provides some variation rb->linear_momentum = float3(0, 0, 0); rb->angular_momentum = float3(0, 0, 0); } seesaw->orientation = { 0, 0, 0, 1 }; break; default: std::cout << "unassigned key (" << (int)key << "): '" << key << "'\n"; break; } }; InitTex(); int2 mouseprev; while (glwin.WindowUp()) { if (glwin.MouseState) // on mouse drag { g_yaw += (glwin.MouseX - mouseprev.x) * 0.3f; // poor man's trackball g_pitch += (glwin.MouseY - mouseprev.y) * 0.3f; } mouseprev = { glwin.MouseX, glwin.MouseY }; if (g_simulate) { std::vector<LimitAngular> angulars; std::vector<LimitLinear> linears; Append(linears , ConstrainPositionNailed(NULL, seesaw->position_start, seesaw, { 0, 0, 0 })); Append(angulars, ConstrainAngularRange(NULL, seesaw, { 0, 0, 0, 1 }, { 0, -20, 0 }, { 0, 20, 0 })); PhysicsUpdate(rigidbodies, linears, angulars, { &world_slab.verts }); } glPushAttrib(GL_ALL_ATTRIB_BITS); glViewport(0, 0, glwin.Width,glwin.Height); // Set up the viewport glClearColor(0.1f, 0.1f, 0.15f, 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // Set up matrices glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPerspective(glwin.ViewAngle, (double)glwin.Width/ glwin.Height, 0.01, 50); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); gluLookAt(0, -8, 5, 0, 0, 0, 0, 0, 1); glRotatef(g_pitch, 1, 0, 0); glRotatef(g_yaw, 0, 0, 1); wmdraw(world_slab); // world_geometry glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1., 1. / (float)0x10000); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_TEXTURE_2D); glColor3f(0.5f, 0.5f, 0.5f); for (auto &rb : rigidbodies) rbdraw(rb); glPopAttrib(); // Restore state glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glwin.PrintString("ESC/q quits. SPACE to simulate. r to restart", 5, 0); char buf[256]; sprintf_s(buf, "simulation %s", (g_simulate)?"ON":"OFF"); glwin.PrintString(buf, 5, 1); glwin.SwapBuffers(); } std::cout << "\n"; return 0; }
int main(int argc, const char *argv[]) try { std::vector<Joint> joints; std::vector<RigidBody> rbs; std::map<std::string,unsigned int> rbindex; auto xml = XMLParseFile("./default_hand.chr"); // replace string with whatever model you want to test. uses xml variation of John Ratcliff's easy mesh (ezm) file format. auto const &skx = xml.child("model").child("skeleton"); for (auto const &b : skx.children) { rbindex[b.attribute("name")] = rbs.size(); auto verts = ArrayImport<float3>(b.child("verts").body); auto tris = calchull(verts, verts.size()); float3 pos = StringTo<float3>(b.attribute("position")); int parent = (b.hasAttribute("parent")) ? (int)rbindex[b.attribute("parent")] : -1; rbs.push_back(RigidBody({ Shape(verts,tris) }, pos + ((parent>=0)?rbs[parent].position-rbs[parent].com:float3(0,0,0)))); if (parent>=0) joints.push_back({ parent, (int)rbs.size() - 1, pos, float3(0,0,0), StringTo<float3>(b.child("jointlimitmin").body), StringTo<float3>(b.child("jointlimitmax").body) }); } rbscalemass(&rbs[0], 3.0f); rbscalemass(&rbs[1], 5.0f); DXWin mywin("DX testing articulated rigged model", { 800,600 }); std::vector<Mesh> meshes; for (auto &rb : rbs) { meshes.push_back(MeshSmoothish(rb.shapes[0].verts, rb.shapes[0].tris)); // 1 shape each is known rb.damping = 0.8f; //rb.gravscale = 0; } for (auto &joint : joints) { rbs[joint.rbi0].ignore.push_back(&rbs[joint.rbi1]); rbs[joint.rbi1].ignore.push_back(&rbs[joint.rbi0]); joint.p0 -= rbs[joint.rbi0].com; joint.p1 -= rbs[joint.rbi1].com; } for (auto &ja : joints) for (auto &jb : joints) if (ja.rbi0 == jb.rbi0 && ja.rbi1 != jb.rbi1) // ignore siblings { rbs[ja.rbi1].ignore.push_back(&rbs[jb.rbi1]); rbs[jb.rbi1].ignore.push_back(&rbs[ja.rbi1]); } for (auto &ja : joints) for (auto &jb : joints) if (ja.rbi1 == jb.rbi0 ) // ignore grandparents { rbs[ja.rbi0].ignore.push_back(&rbs[jb.rbi1]); rbs[jb.rbi1].ignore.push_back(&rbs[ja.rbi0]); } std::vector<float3> groundpoints = { { -5.0f, -5.0f, -5.0f }, { 5.0f, -5.0f, -5.0f }, { 5.0f, 10.0f, -5.0f }, { -5.0f, 10.0f, -5.0f }, { -5.0f, -5.0f, -10.0f }, { 5.0f, -5.0f, -10.0f }, { 5.0f, 10.0f, -10.0f }, { -5.0f, 10.0f, -10.0f } }; Mesh ground = MeshSmoothish(groundpoints, { { 0, 1, 2 }, { 2, 3,0 } }); ground.hack = { 1, 1, 0 ,1}; WingMesh cube_wm = WingMeshCube(0.025f); auto mesh_cube = MeshFlatShadeTex(cube_wm.verts, WingMeshTris(cube_wm)); mesh_cube.hack = { 0, 1, 0, 1 }; Pose camera = { { 0, -10, 0 }, normalize(float4(1, 0, 0, 1)) }; RigidBody *selected = NULL; float3 spoint=camera * float3(0,0,-10); float3 rbpoint; struct Pin{ float3 w; RigidBody* rb; float3 p; }; std::vector<Pin> pins; mywin.keyboardfunc = [&](int key, int, int) { if (key == 'g') for (auto &rb : rbs) rb.gravscale = 1.0f - rb.gravscale; if (key == 'p' && selected) Append<Pin>(pins, { spoint, selected, rbpoint }); }; while (mywin.WindowUp()) { float3 ray = qrot(camera.orientation, normalize(mywin.MouseVector)); if (!selected) { for (auto &rb : rbs) { float3 v1 = camera.position + ray*100.0f; if (auto h=ConvexHitCheck(Planes(rb.shapes[0].verts, rb.shapes[0].tris),rb.pose(),camera.position,v1)) { v1 = h.impact; selected = &rb; spoint = h.impact; rbpoint = rb.pose().inverse()*h.impact; } } } spoint = camera.position + ray * length(spoint - camera.position)*powf(1.025f, (float)mywin.mousewheel); mesh_cube.pose.position = spoint; if (!mywin.MouseState) selected = NULL; std::vector<LimitAngular> angulars; std::vector<LimitLinear> linears; for (auto const &joint : joints) { Append(linears, ConstrainPositionNailed(&rbs[joint.rbi0], joint.p0, &rbs[joint.rbi1], joint.p1)); Append(angulars, ConstrainAngularRange(&rbs[joint.rbi0], &rbs[joint.rbi1], { 0, 0, 0, 1 }, joint.jointlimitmin, joint.jointlimitmax)); } if (selected) Append(linears, ConstrainPositionNailed(NULL, spoint, selected, rbpoint)); for(auto &p:pins) Append(linears, ConstrainPositionNailed(NULL, p.w,p.rb,p.p)); PhysicsUpdate(Addresses(rbs), linears, angulars, { &groundpoints }); for (unsigned int i = 0; i < rbs.size(); i++) { meshes[i].pose = rbs[i].pose(); } mywin.RenderScene(camera, Append(Addresses(meshes),std::vector<Mesh*>({ &ground, &mesh_cube }))); } } catch (std::exception e) { MessageBoxA(GetActiveWindow(), e.what(), "FAIL", 0); return -1; }