首页 > 代码库 > outdated: 40.Introduction to Physical Simulations

outdated: 40.Introduction to Physical Simulations

这一节为物理模拟绳子。在上一节中,三种物理模拟的基本运动作为这一节的基础。(直线运动, 弹性运动,万有引力下运动)

让绳子拥有弹性感,可以在每个质量节点中加入很小长度的弹簧。弹簧上力的变化可参考上节的弹性运动。

基本上所谓的重点就是绳子模拟类了,RopeSimulation类继承Simulation类(上节中)。

类中定义了,每个弹簧,万有引力, 每节绳子连接处位置和速率,还有地面对绳子的抵抗力系数,地面摩擦力系数, 地面吸引力系数,地面高度,空气摩擦力系数。先来看个构造函数,

RopeSimulation(        int numOfMasses,        float m,        float springConstant,        float springLength,        float springFrictionConstant,        Vector3D gravitation,        float airFrictionConstant,        float groundRepulsionConstant,        float groundFrictionConstant,        float groundAbsorptionConstant,        float groundHeight        ) : Simulation(numOfMasses, m) {        this->gravitation = gravitation;        this->airFrictionConstant = airFrictionConstant;        this->groundFrictionConstant = groundFrictionConstant;        this->groundRepulsionConstant = groundRepulsionConstant;        this->groundAbsorptionConstant = groundAbsorptionConstant;        this->groundHeight = groundHeight;        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->pos.x = i * springLength;            masses[i]->pos.y = 0;            masses[i]->pos.z = 0;        }        springs = new Spring*[numOfMasses - 1];        for (int i = 0; i < numOfMasses - 1; ++i) {            springs[i] = new Spring(masses[i], masses[i + 1], springConstant, springLength,                 springFrictionConstant);        }    }

下面为RopeSimulation类代码,

技术分享RopeSimulation

技术分享

下面为代码,

技术分享
#ifndef GL_FRAMEWORK_INCLUDED#define GL_FRAMEWORK_INCLUDED#include <windows.h>typedef struct {                                   // Structure for keyboard stuff    BOOL keyDown[256];} Keys;typedef struct {                                   // Contains information vital to applications     HMODULE hInstance;                             // Application Instance    const char* className;} Application;typedef struct {                                   // Window creation info    Application* application;    char* title;    int width;    int height;    int bitsPerPixel;    BOOL isFullScreen;} GL_WindowInit;typedef struct {                                   // Contains information vital to a window    Keys* keys;    HWND hWnd;                                     // Windows handle    HDC hDC;                                       // Device context    HGLRC hRC;                                     // Rendering context    GL_WindowInit init;    BOOL isVisible;                                // Window visiable?    DWORD lastTickCount;                           // Tick counter} GL_Window;void TerminateApplication(GL_Window* window);      // Terminate the applicationvoid ToggleFullscreen(GL_Window* window);          // Toggle fullscreen / Windowed modeBOOL Initialize(GL_Window* window, Keys* keys);void Deinitialize(void);void Update(DWORD milliseconds);void Draw(void);#endif
Previous.h
技术分享
#include <Windows.h>#include <GL\glew.h>#include <GL\glut.h>#include "Previous.h"#define WM_TOGGLEFULLSCREEN (WM_USER+1)                   // Application define message for toggling // between fulscreen / windowed modestatic BOOL g_isProgramLooping;                           // Window creation loop, for fullscreen / windowed modestatic BOOL g_createFullScreen;                           // If true, then create windowvoid TerminateApplication(GL_Window* window)              // Terminate the application{    PostMessage(window->hWnd, WM_QUIT, 0, 0);             // Send a WM_QUIT message    g_isProgramLooping = FALSE;                           // Stop looping of the program}void ToggleFullscreen(GL_Window* window)                  // Toggle fullscreen /windowed mode{    PostMessage(window->hWnd, WM_TOGGLEFULLSCREEN, 0, 0); // Send a WM_TOGGLEFULLSCREEN message}void ReshapeGL(int width, int height)                     // Reshape the window  when it‘s moved or resized{    glViewport(0, 0, (GLsizei)(width), (GLsizei)(height)); // Reset the current viewport    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    // Calcutate the aspect ratio of the window    gluPerspective(45.0f, (GLfloat)(width) / (GLfloat)(height), 1.0, 100.0f);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();}BOOL ChangeScreenResolution(int width, int height, int bitsPerPixel)     // Change the screen resolution{    DEVMODE dmScreenSettings;                              // Device mode    ZeroMemory(&dmScreenSettings, sizeof(DEVMODE));        // Make sure memory is cleared    dmScreenSettings.dmSize = sizeof(DEVMODE);             // Size of the devmode structure    dmScreenSettings.dmPelsWidth = width;    dmScreenSettings.dmPelsHeight = height;    dmScreenSettings.dmBitsPerPel = bitsPerPixel;    dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;    if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {        return FALSE;                                      // Display change failed    }    return TRUE;}BOOL CreateWindowGL(GL_Window* window){    DWORD windowStyle = WS_OVERLAPPEDWINDOW;                // Define window style    DWORD windowExtendedStyle = WS_EX_APPWINDOW;            // Define the window‘s extended style    PIXELFORMATDESCRIPTOR pdf = {        sizeof(PIXELFORMATDESCRIPTOR),                      // Size of this pixel format descriptor        1,                                                  // Version Number        PFD_DRAW_TO_WINDOW |                                // Format must support window        PFD_SUPPORT_OPENGL |                                // Format must support openGL        PFD_DOUBLEBUFFER,                                   // Must support double buffering        PFD_TYPE_RGBA,                                      // Request an RGBA format        window->init.bitsPerPixel,                          // Select color depth        0, 0, 0, 0, 0, 0,                                   // Color bits ignored        0,                                                  // No alpha buffer        0,                                                  // Shift bit ignored        0,                                                  // No accumulation buffer        0, 0, 0, 0,                                         // Accumulation bits ignored        16,                                                 // 16bits Z-buffer (depth buffer)        0,                                                  // No stencil buffer        0,                                                  // No auxiliary buffer        PFD_MAIN_PLANE,                                     // Main drawing layer        0,                                                  // Reserved        0, 0, 0                                             // Layer masks ignored    };    RECT windowRect = { 0, 0, window->init.width, window->init.height };   // Window coordiantes    GLuint PixelFormat;    if (window->init.isFullScreen == TRUE) {        if (ChangeScreenResolution(window->init.width, window->init.height, window->init.bitsPerPixel) == FALSE)        {            // Fullscreen mode failed, run in windowed mode instead            MessageBox(HWND_DESKTOP, "Mode Switch Failed.\nRuning In Windowed Mode.",                "Error", MB_OK | MB_ICONEXCLAMATION);            window->init.isFullScreen = FALSE;        }        else {            ShowCursor(FALSE);            windowStyle = WS_POPUP;                         // Popup window            windowExtendedStyle |= WS_EX_TOPMOST;        }    }    else {        // Adjust window, account for window borders        AdjustWindowRectEx(&windowRect, windowStyle, 0, windowExtendedStyle);    }    // Create Opengl window    window->hWnd = CreateWindowEx(windowExtendedStyle,      // Extended style        window->init.application->className,                // Class name        window->init.title,                                 // Window title        windowStyle,                                        // Window style        0, 0,                                               // Window X,Y position        windowRect.right - windowRect.left,                 // Window width        windowRect.bottom - windowRect.top,                 // Window height        HWND_DESKTOP,                                       // Desktop is window‘s parent        0,                                                  // No menu        window->init.application->hInstance,                // Pass the window instance        window);    if (window->hWnd == 0) {                                // Was window creation a success?        return FALSE;    }    window->hDC = GetDC(window->hWnd);    if (window->hDC == 0) {        DestroyWindow(window->hWnd);        window->hWnd = 0;        return FALSE;    }    PixelFormat = ChoosePixelFormat(window->hDC, &pdf);     // Find a compatible pixel format    if (PixelFormat == 0) {        ReleaseDC(window->hWnd, window->hDC);               // Release device context        window->hDC = 0;        DestroyWindow(window->hWnd);        window->hWnd = 0;        return FALSE;    }    if (SetPixelFormat(window->hDC, PixelFormat, &pdf) == FALSE) {   // Try to set the pixel format        ReleaseDC(window->hWnd, window->hDC);        window->hDC = 0;        DestroyWindow(window->hWnd);        window->hWnd = 0;        return FALSE;    }    window->hRC = wglCreateContext(window->hDC);            // Try to get a rendering context    if (window->hRC == 0) {        ReleaseDC(window->hWnd, window->hDC);        window->hDC = 0;        DestroyWindow(window->hWnd);        window->hWnd = 0;        return FALSE;    }    // Make the rendering context our current rendering context    if (wglMakeCurrent(window->hDC, window->hRC) == FALSE) {        wglDeleteContext(window->hRC);                      //  Delete the rendering context        window->hRC = 0;        ReleaseDC(window->hWnd, window->hDC);        window->hDC = 0;        DestroyWindow(window->hWnd);        window->hWnd = 0;        return FALSE;    }    ShowWindow(window->hWnd, SW_NORMAL);                    // Make the window visiable    window->isVisible = TRUE;    ReshapeGL(window->init.width, window->init.height);     // Reshape our GL window    ZeroMemory(window->keys, sizeof(Keys));                 // Clear all keys    window->lastTickCount = GetTickCount();    return TRUE;}BOOL DestoryWindowGL(GL_Window* window){    if (window->hWnd != 0) {        if (window->hDC != 0) {            wglMakeCurrent(window->hDC, 0);                 // Setting current active rendering context to zero            if (window->hRC != 0) {                wglDeleteContext(window->hRC);                window->hRC = 0;            }            ReleaseDC(window->hWnd, window->hDC);            window->hDC = 0;        }        DestroyWindow(window->hWnd);        window->hWnd = 0;    }    if (window->init.isFullScreen) {        ChangeDisplaySettings(NULL, 0);                     // Switch back to desktop resolution        ShowCursor(TRUE);    }    return TRUE;}// Process window message callbackLRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){    // Get the window context    GL_Window* window = (GL_Window*)(GetWindowLong(hWnd, GWL_USERDATA));    switch (uMsg) {                                         // Evaluate window message    case WM_SYSCOMMAND:                                     // Intercept system commands    {        switch (wParam) {                                   // Check system calls        case SC_SCREENSAVE:                                 // Screensaver trying to start?        case SC_MONITORPOWER:                               // Mointer trying to enter powersave?            return 0;                                           // Prevent form happening        }        break;    }    return 0;    case WM_CREATE:    {        CREATESTRUCT* creation = (CREATESTRUCT*)(lParam);   // Store window structure pointer        window = (GL_Window*)(creation->lpCreateParams);        SetWindowLong(hWnd, GWL_USERDATA, (LONG)(window));    }    return 0;    case WM_CLOSE:        TerminateApplication(window);        return 0;    case WM_SIZE:        switch (wParam) {        case SIZE_MINIMIZED:                                 // Was window minimized?            window->isVisible = FALSE;            return 0;        case SIZE_MAXIMIZED:            window->isVisible = TRUE;            ReshapeGL(LOWORD(lParam), HIWORD(lParam));            return 0;        case SIZE_RESTORED:            window->isVisible = TRUE;            ReshapeGL(LOWORD(lParam), HIWORD(lParam));            return 0;        }        break;    case WM_KEYDOWN:        if ((wParam >= 0) && (wParam <= 255)) {            window->keys->keyDown[wParam] = TRUE;            // Set the selected key(wParam) to true            return 0;        }        break;    case WM_KEYUP:        if ((wParam >= 0) && (wParam <= 255)) {            window->keys->keyDown[wParam] = FALSE;            return 0;        }        break;    case WM_TOGGLEFULLSCREEN:        g_createFullScreen = (g_createFullScreen == TRUE) ? FALSE : TRUE;        PostMessage(hWnd, WM_QUIT, 0, 0);        break;    }    return DefWindowProc(hWnd, uMsg, wParam, lParam);        // Pass unhandle message to DefWindowProc}BOOL RegisterWindowClass(Application* application){    WNDCLASSEX windowClass;    ZeroMemory(&windowClass, sizeof(WNDCLASSEX));            // Make sure memory is cleared    windowClass.cbSize = sizeof(WNDCLASSEX);                 // Size of the windowClass structure    windowClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;  // Redraws the window for any movement / resizing    windowClass.lpfnWndProc = (WNDPROC)(WindowProc);         // WindowProc handles message    windowClass.hInstance = application->hInstance;          // Set the instance    windowClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);// Class background brush color    windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);       // Load the arrow pointer    windowClass.lpszClassName = application->className;      // Sets the application className    if (RegisterClassEx(&windowClass) == 0) {        MessageBox(HWND_DESKTOP, "RegisterClassEx Failed!", "Error", MB_OK | MB_ICONEXCLAMATION);        return FALSE;    }    return TRUE;}int WINAPI WinMain(HINSTANCE hIstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){    Application application;    GL_Window window;    Keys keys;    BOOL isMessagePumpActive;    MSG msg;    DWORD tickCount;    application.className = "OpenGL";    application.hInstance = hIstance;    ZeroMemory(&window, sizeof(GL_Window));    window.keys = &keys;                                     // Window key structure    window.init.application = &application;                  // Window application    window.init.title = "Resource File";                       // Window title    window.init.width = 640;                                 // Window width    window.init.height = 480;                                // Window height    window.init.bitsPerPixel = 16;                           // Bits per pixel    window.init.isFullScreen = TRUE;                         // Fullscreen? (set to TRUE)    ZeroMemory(&keys, sizeof(Keys));    if (MessageBox(HWND_DESKTOP, "Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",        MB_YESNO | MB_ICONQUESTION) == IDNO)    {        window.init.isFullScreen = FALSE;    }    if (RegisterWindowClass(&application) == FALSE)    {        MessageBox(HWND_DESKTOP, "Error Registering Window Class!", "Error", MB_OK | MB_ICONEXCLAMATION);        return -1;    }    g_isProgramLooping = TRUE;    g_createFullScreen = window.init.isFullScreen;    while (g_isProgramLooping) {                             // Loop until WM_QUIT is received        window.init.isFullScreen = g_createFullScreen;       // Set init param of window creation to fullscreen?        if (CreateWindowGL(&window) == TRUE) {               // Was window creation successful?                                                             // At this point we should have a window that is setup to render OpenGL            if (Initialize(&window, &keys) == FALSE) {                TerminateApplication(&window);               // Close window, this will handle the shutdown            }            else {                isMessagePumpActive = TRUE;                while (isMessagePumpActive == TRUE) {                    // Success creating window. Check for window messages                    if (PeekMessage(&msg, window.hWnd, 0, 0, PM_REMOVE) != 0) {                        if (msg.message != WM_QUIT) {                            DispatchMessage(&msg);                        }                        else {                            isMessagePumpActive = FALSE;     // Terminate the message pump                        }                    }                    else {                        if (window.isVisible == FALSE) {                            WaitMessage();                   // Application is minimized wait for a message                        }                        else {                            // Process application loop                            tickCount = GetTickCount();      // Get the tick count                            Update(tickCount - window.lastTickCount); // Update the counter                            window.lastTickCount = tickCount;// Set last count to current count                            Draw();                          // Draw screen                            SwapBuffers(window.hDC);                        }                    }                }            }            // Application is finished            Deinitialize();            DestoryWindowGL(&window);        }        else {            MessageBox(HWND_DESKTOP, "Error Creating OpenGL Window", "Error", MB_OK | MB_ICONEXCLAMATION);            g_isProgramLooping = FALSE;        }    }    UnregisterClass(application.className, application.hInstance);    // UnRegister window class    return 0;}
Previous.cpp
技术分享
#include <math.h>class Vector3D {public:    float x, y, z;    Vector3D(): x(0), y(0), z(0) {}    Vector3D(float x, float y, float z)    {        this->x = x;        this->y = y;        this->z = z;    }    Vector3D& operator= (Vector3D v)    {        x = v.x;        y = v.y;        z = v.z;        return *this;    }    Vector3D operator+ (Vector3D v)    {        return Vector3D(x + v.x, y + v.y, z + v.z);    }    Vector3D operator- (Vector3D v)    {        return Vector3D(x - v.x, y - v.y, z - v.z);    }    Vector3D operator* (float value)    {        return Vector3D(x * value, y * value, z * value);    }    Vector3D operator/ (float value)    {        return Vector3D(x / value, y / value, z / value);    }    Vector3D& operator+= (Vector3D v)    {        x += v.x;        y += v.y;        z += v.z;        return *this;    }    Vector3D& operator-= (Vector3D v)    {        x -= v.x;        y -= v.y;        z -= v.z;        return *this;    }    Vector3D& operator*= (Vector3D v)    {        x *= v.x;        y *= v.y;        z *= v.z;        return *this;    }    Vector3D& operator/= (Vector3D v)    {        x /= v.x;        y /= v.y;        z /= v.z;        return *this;    }    Vector3D operator- ()    {        return Vector3D(-x, -y, -z);    }    float length()    {        return sqrtf(x*x + y*y + z*z);    }    void unitize()                            // Normalizes    {        float length = this->length();        if (length == 0) return;        x /= length;        y /= length;        z /= length;    }    Vector3D unit()                        // Normalizes return a new Vector3D    {        float length = this->length();        if (length == 0)            return *this;        return Vector3D(x / length, y / length, z / length);    }};class Mass {public:    float m;                 // The mass value    Vector3D pos;            // Position    Vector3D vel;            // Velocity    Vector3D force;          // Force    Mass(float m): m(m) {}    void applyForce(Vector3D force)    {        this->force += force;    }    void init()    {        force.x = 0;        force.y = 0;        force.z = 0;    }    void simulate(float dt)                 // New velocity and position    {        vel += (force / m) * dt;        pos += vel * dt;    }};class Simulation {public:    int    numOfMasses;    Mass** masses;    Simulation(int numOfMasses, float m)                 // Constructor    {        this->numOfMasses = numOfMasses;        masses = new Mass*[numOfMasses];        for (int i = 0; i < numOfMasses; ++i) {            masses[i] = new Mass(m);        }    }    virtual void release()                      // Delete    {        for (int i = 0; i < numOfMasses; ++i) {            delete(masses[i]);            masses[i] = NULL;        }        delete(masses);        masses = NULL;    }    Mass* getMass(int index)    {        if (index < 0 || index >= numOfMasses) {            return NULL;        }        return masses[index];    }    virtual void init()    {        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->init();        }    }    // No implementation because no forces are wanted in this basic container    // in advanced containers, this method will be overrided and some forces will act on masses    virtual void solve() {}    virtual void simulate(float dt)    {        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->simulate(dt);        }    }    virtual void operate(float dt)                     // The complete produce of simulation    {        init();        solve();        simulate(dt);    }};class ConstantVelocity : public Simulation {public:    ConstantVelocity() : Simulation(1, 1.0f)    {        masses[0]->pos = Vector3D(0.0f, 0.0f, 0.0f);        masses[0]->vel = Vector3D(1.0f, 0.0f, 0.0f);    }};class MotionUnderGravitation : public Simulation {public:    Vector3D gravitation;    MotionUnderGravitation(Vector3D gravitation) : Simulation(1, 1.0f)    {        this->gravitation = gravitation;        masses[0]->pos = Vector3D(-10.0f, 0.0f, 0.0f);        masses[0]->vel = Vector3D(10.0f, 15.0f, 0.0f);    }    virtual void solve()    {        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->applyForce(gravitation * masses[i]->m);        }    }};class MassConnectedWithSpring : public Simulation {public:    float springConstant;                      // More the springConstant, stiffer the spring force    Vector3D connectionPos;                    // The arbitrary constant point that the mass is connected    MassConnectedWithSpring(float springConstant) :Simulation(1, 1.0f)    {        this->springConstant = springConstant;        connectionPos = Vector3D(0.0f, -5.0f, 0.0f);        masses[0]->pos = connectionPos + Vector3D(10.0f, 0.0f, 0.0f);        masses[0]->vel = Vector3D(0.0f, 0.0f, 0.0f);    }    virtual void solve()    {        for (int i = 0; i < numOfMasses; ++i) {            Vector3D springVector = masses[i]->pos - connectionPos;            masses[i]->applyForce(-springVector * springConstant);        }    }};
Physics1.h
技术分享
#include "Physics1.h"// An object to represent a spring with inner friction binding two masses.// The spring has a normal length (The length that the spring does not exert any force)class Spring {public:    Mass* mass1;    Mass* mass2;    float springConstant;             // A constant to represent the stiffness of the spring    float springLength;    float frictionConstant;    // Constructor    Spring(Mass* mass1, Mass* mass2, float springConstant, float springLength, float frictionConstant) :        mass1(mass1), mass2(mass2), springConstant(springConstant), springLength(springLength),         frictionConstant(frictionConstant) {}    void solve()    {        Vector3D springVector = mass1->pos - mass2->pos;        float r = springVector.length();        Vector3D force;        if (r != 0) {            force += (springVector / r) * (r - springLength) * (-springConstant);        }        force += -(mass1->vel - mass2->vel) * frictionConstant;        mass1->applyForce(force);        mass2->applyForce(-force);    }};class RopeSimulation : public Simulation {public:    Spring** springs;    Vector3D gravitation;    Vector3D ropeConnectionPos;    Vector3D ropeConnectionVel;        // A constant to represent how much the ground shall repel the masses    float groundRepulsionConstant;    // A constant of friction applied to masses by the ground (sliding of rope)    float groundFrictionConstant;    // A constant of absorption friction alppiled to masses by the ground (vertical collisions of rope)    float groundAbsorptionConstant;    float groundHeight;    float airFrictionConstant;              // A constant of air friction-applied to masses    RopeSimulation(        int numOfMasses,        float m,        float springConstant,        float springLength,        float springFrictionConstant,        Vector3D gravitation,        float airFrictionConstant,        float groundRepulsionConstant,        float groundFrictionConstant,        float groundAbsorptionConstant,        float groundHeight        ) : Simulation(numOfMasses, m) {        this->gravitation = gravitation;        this->airFrictionConstant = airFrictionConstant;        this->groundFrictionConstant = groundFrictionConstant;        this->groundRepulsionConstant = groundRepulsionConstant;        this->groundAbsorptionConstant = groundAbsorptionConstant;        this->groundHeight = groundHeight;        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->pos.x = i * springLength;            masses[i]->pos.y = 0;            masses[i]->pos.z = 0;        }        springs = new Spring*[numOfMasses - 1];        for (int i = 0; i < numOfMasses - 1; ++i) {            springs[i] = new Spring(masses[i], masses[i + 1], springConstant, springLength,                 springFrictionConstant);        }    }    void release()    {        Simulation::release();        for (int i = 0; i < numOfMasses - 1; ++i) {            delete(springs[i]);            springs[i] = NULL;        }        delete(springs);        springs = NULL;    }    void solve()    {        for (int i = 0; i < numOfMasses - 1; ++i) {            springs[i]->solve();        }        for (int i = 0; i < numOfMasses; ++i) {            masses[i]->applyForce(gravitation * masses[i]->m);          // Gravitation            masses[i]->applyForce(-masses[i]->vel * airFrictionConstant);    // Air Friction            if (masses[i]->pos.y < groundHeight) {                Vector3D v = masses[i]->vel;             // Velocity                v.y = 0;                                 // Omit the velocity component in y direction                // The velocity in y direction is omited because we will apply a friction force to create                // a sliding effect. Sliding is parallel to the ground. Velocity in y direction will be used                // in the absorption effect.                masses[i]->applyForce(-v * groundFrictionConstant);                v = masses[i]->vel;                v.x = 0;               // Omit                v.z = 0;                if (v.y < 0) {      // Absorb energy only when a mass collides towards the ground                    masses[i]->applyForce(-v * groundAbsorptionConstant);                }                // The ground shall repel a mass like a spring.                Vector3D force = Vector3D(0, groundRepulsionConstant, 0) * (groundHeight - masses[i]->pos.y);                masses[i]->applyForce(force);            }        }    }    void simulate(float dt)              // Overriden    {        Simulation::simulate(dt);        ropeConnectionPos += ropeConnectionVel * dt;   // Iterate the positon of ropeConnectionPos        if (ropeConnectionPos.y < groundHeight) {            ropeConnectionPos.y = groundHeight;            ropeConnectionVel.y = 0;        }        masses[0]->pos = ropeConnectionPos;        masses[0]->vel = ropeConnectionVel;    }    void setRopeConnectionVel(Vector3D ropeConnectionVel)    {        this->ropeConnectionVel = ropeConnectionVel;    }};
Physics2.h
技术分享
#include <Windows.h>#include <GL/glew.h>#include <GL/glut.h>#include <GL/GLUAX.H>#include <math.h>#include <stdio.h>#include "Previous.h"#include "Physics2.h"#pragma comment(lib, "legacy_stdio_definitions.lib")#ifndef CDS_FULLSCREEN#define CDS_FULLSCREEN 4#endifGL_Window* g_window;Keys* g_keys;RopeSimulation* ropeSimulation = new RopeSimulation(    80,                 // Particles    0.05f,              // Each particle has a weight of 50 grams    1000.0f,            // SpringConstant    0.05f,              // Normal length of string in the rope    0.2f,               // Spring inner friction constant    Vector3D(0, -9.81f, 0),  // Gravitational acceleration    0.02f,              // Air friction constant    100.0f,             // Ground repel constant    0.2f,               // Ground slide friction    2.0f,               // Ground absoption constant    -1.5f);             // Height of groundBOOL Initialize(GL_Window* window, Keys* keys){    g_window = window;    g_keys = keys;    ropeSimulation->getMass(ropeSimulation->numOfMasses - 1)->vel.z = 10.0f;    glClearColor(0.0f, 0.0f, 0.0f, 0.5f);    glClearDepth(1.0f);    glShadeModel(GL_SMOOTH);    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);    return TRUE;}void Deinitialize(void){    ropeSimulation->release();    delete(ropeSimulation);    ropeSimulation = NULL;}void Update(DWORD milliseconds){    if (g_keys->keyDown[VK_ESCAPE] == TRUE)        TerminateApplication(g_window);    if (g_keys->keyDown[VK_F1] == TRUE)        ToggleFullscreen(g_window);    Vector3D ropeConnectionVel;    if (g_keys->keyDown[VK_RIGHT] == TRUE)        ropeConnectionVel.x += 3.0f;    if (g_keys->keyDown[VK_LEFT] == TRUE)        ropeConnectionVel.x -= 3.0f;    if (g_keys->keyDown[VK_UP] == TRUE)        ropeConnectionVel.z -= 3.0f;    if (g_keys->keyDown[VK_DOWN] == TRUE)        ropeConnectionVel.z += 3.0f;    if (g_keys->keyDown[VK_HOME] == TRUE)        ropeConnectionVel.y += 3.0f;    if (g_keys->keyDown[VK_END] == TRUE)        ropeConnectionVel.y -= 3.0f;    ropeSimulation->setRopeConnectionVel(ropeConnectionVel);    float dt = milliseconds / 1000.0f;    float maxPossible_dt = 0.002f;                     // Maximum possible dt is 0.002 seconds        int numOfIteration = (int)(dt / maxPossible_dt) + 1;    if (numOfIteration != 0) {        dt /= numOfIteration;    }    for (int i = 0; i < numOfIteration; ++i) {        ropeSimulation->operate(dt);    }}void Draw(void){    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    gluLookAt(0, 0, 4, 0, 0, 0, 0, 1, 0);    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    glBegin(GL_QUADS);        glColor3ub(0, 0, 255);        glVertex3f(20, ropeSimulation->groundHeight, 20);        glVertex3f(-20, ropeSimulation->groundHeight, 20);        glColor3ub(0, 0, 0);        glVertex3f(-20, ropeSimulation->groundHeight, -20);        glVertex3f(20, ropeSimulation->groundHeight, -20);    glEnd();    // Shadow of rope    glColor3ub(0, 0, 0);    for (int i = 0; i < ropeSimulation->numOfMasses - 1; ++i) {        Mass* mass1 = ropeSimulation->getMass(i);        Vector3D* pos1 = &mass1->pos;        Mass* mass2 = ropeSimulation->getMass(i + 1);        Vector3D* pos2 = &mass2->pos;        glLineWidth(2);        glBegin(GL_LINES);            glVertex3f(pos1->x, ropeSimulation->groundHeight, pos1->z);            glVertex3f(pos2->x, ropeSimulation->groundHeight, pos2->z);        glEnd();    }    glColor3ub(255, 255, 0);    for (int i = 0; i < ropeSimulation->numOfMasses - 1; ++i) {        Mass* mass1 = ropeSimulation->getMass(i);        Vector3D* pos1 = &mass1->pos;        Mass* mass2 = ropeSimulation->getMass(i + 1);        Vector3D* pos2 = &mass2->pos;        glLineWidth(4);        glBegin(GL_LINES);            glVertex3f(pos1->x, pos1->y, pos1->z);            glVertex3f(pos2->x, pos2->y, pos2->z);        glEnd();    }    glFlush();}
Main.cpp

Thanks for Nehe‘s tutorials, this is his home.

outdated: 40.Introduction to Physical Simulations